Merge pull request #80 from rh-hideout/master

sync update
This commit is contained in:
RoamerX 2025-12-20 17:59:54 +08:00 committed by GitHub
commit 961d858027
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 372 additions and 385 deletions

View File

@ -23,7 +23,7 @@ The best bug reports have enough information that we won't have to contact you f
- A maintainer will [label](https://github.com/rh-hideout/pokeemerald-expansion/labels) the bug report.
- A maintainer will try to reproduce the bug with your provided steps.
- If there are no reproduction steps or no obvious way to reproduce the issue, somebody will ask you for those steps. Until the bug can be reproduced, the bug will retain the `bug:unconfirmed` label. Unconfirmed bugs are less likely get fixed.
- If there are no reproduction steps or no obvious way to reproduce the issue, somebody will ask you for those steps. Until the bug can be reproduced, the bug will retain the `bug:unconfirmed` label. Unconfirmed bugs are less likely to get fixed.
- If the team is able to reproduce the bug, it will be labeled `bug:confirmed`, and the bug will be left to be [fixed by someone](#Pull-Requests).
- If the issue is particularly game-breaking, a maintainer will add it to a future version's [milestone](), meaning that version will not be released until the problem is solved.

View File

@ -497,10 +497,10 @@ Causes the test to fail if the `SCENE` command succeeds before the following com
```
Causes the test to fail unless one of the `SCENE` commands succeeds.
```
ONE_OF {
MESSAGE("Wobbuffet used Celebrate!");
MESSAGE("Wobbuffet couldn't move because it's paralyzed!");
}
ONE_OF {
MESSAGE("Wobbuffet used Celebrate!");
MESSAGE("Wobbuffet couldn't move because it's paralyzed!");
}
```
### `NONE_OF`
@ -511,12 +511,12 @@ Causes the test to fail unless one of the `SCENE` commands succeeds.
```
Causes the test to fail if one of the `SCENE` commands succeeds before the command after the `NONE_OF` succeeds.
```
// Our Wobbuffet does not move before the foe's.
NONE_OF {
MESSAGE("Wobbuffet used Celebrate!");
MESSAGE("Wobbuffet couldn't move because it's paralyzed!");
}
MESSAGE("The opposing Wobbuffet used Celebrate!");
// Our Wobbuffet does not move before the foe's.
NONE_OF {
MESSAGE("Wobbuffet used Celebrate!");
MESSAGE("Wobbuffet couldn't move because it's paralyzed!");
}
MESSAGE("The opposing Wobbuffet used Celebrate!");
```
### `PLAYER_PARTY`

View File

@ -343,7 +343,7 @@ bool32 IsPartnerMonFromSameTrainer(u32 battler);
enum DamageCategory GetCategoryBasedOnStats(u32 battler);
void SetShellSideArmCategory(void);
bool32 MoveIsAffectedBySheerForce(u32 move);
bool32 TestIfSheerForceAffected(u32 battler, u16 move);
bool32 IsSheerForceAffected(u16 move, enum Ability ability);
void TryRestoreHeldItems(void);
bool32 CanStealItem(u32 battlerStealing, u32 battlerItem, u16 item);
void TrySaveExchangedItem(u32 battler, u16 stolenItem);

View File

@ -24,7 +24,7 @@
F(MAX_LEVEL_EV_GAINS, maxLevelEvGains, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(RECALCULATE_STATS, recalculateStats, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
/* Damage settings */ \
F(BURN_DAMAGE, burnDamage, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(BURN_DAMAGE, burnDamage, (u32, GEN_COUNT - 1)) \
F(BURN_FACADE_DMG, burnFacadeDmg, (u32, GEN_COUNT - 1)) \
F(BINDING_DAMAGE, bindingDamage, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(PSYWAVE_DMG, psywaveDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
@ -51,7 +51,7 @@
F(UPROAR_TURNS, uproarTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(UPROAR_IGNORE_SOUNDPROOF, uproarIgnoreSoundproof, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(DISABLE_TURNS, disableTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(TAILWIND_TURNS, tailwindTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(TAILWIND_TURNS, tailwindTurns, (u32, GEN_COUNT - 1)) \
F(SLEEP_TURNS, sleepTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(TAUNT_TURNS, tauntTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SPORT_TURNS, sportTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
@ -64,9 +64,9 @@
F(UPDATED_MOVE_FLAGS, updatedMoveFlags, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(PHYSICAL_SPECIAL_SPLIT, physicalSpecialSplit, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(RECOIL_IF_MISS_DMG, recoilIfMissDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(KLUTZ_FLING_INTERACTION, klutzFlingInteraction, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(KLUTZ_FLING_INTERACTION, klutzFlingInteraction, (u32, GEN_COUNT - 1)) \
F(UPDATED_CONVERSION, updatedConversion, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(UPDATED_CONVERSION_2, updatedConversion2, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(UPDATED_CONVERSION_2, updatedConversion2, (u32, GEN_COUNT - 1)) \
F(PP_REDUCED_BY_SPITE, ppReducedBySpite, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(EXTRAPOLATED_MOVE_FLAGS, extrapolatedMoveFlags, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
/* Ability data settings */ \
@ -129,15 +129,15 @@
F(SHADOW_TAG_ESCAPE, shadowTagEscape, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(MOODY_ACC_EVASION, moodyAccEvasion, (u32, GEN_COUNT - 1)) \
F(FLASH_FIRE_FROZEN, flashFireFrozen, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SYNCHRONIZE_TOXIC, synchronizeToxic, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SYNCHRONIZE_TOXIC, synchronizeToxic, (u32, GEN_COUNT - 1)) \
F(UPDATED_INTIMIDATE, updatedIntimidate, (u32, GEN_COUNT - 1)) \
F(OBLIVIOUS_TAUNT, obliviousTaunt, (u32, GEN_COUNT - 1)) \
F(STURDY, sturdy, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(STURDY, sturdy, (u32, GEN_COUNT - 1)) \
F(PLUS_MINUS_INTERACTION, plusMinusInteraction, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(WEATHER_FORMS, weatherForms, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SYMBIOSIS_GEMS, symbiosisGems, (u32, GEN_COUNT - 1)) \
F(ABSORBING_ABILITY_STRING, absorbingAbilityString, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(REDIRECT_ABILITY_IMMUNITY, redirectAbilityImmunity, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(REDIRECT_ABILITY_IMMUNITY, redirectAbilityImmunity, (u32, GEN_COUNT - 1)) \
F(REDIRECT_ABILITY_ALLIES, redirectAbilityAllies, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(LEAF_GUARD_PREVENTS_REST, leafGuardPreventsRest, (u32, GEN_COUNT - 1)) \
F(TRANSISTOR_BOOST, transistorBoost, (u32, GEN_COUNT - 1)) \
@ -176,7 +176,7 @@
F(SAFARI_BALL_MODIFIER, safariBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(FRIEND_BALL_MODIFIER, friendBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SERENE_GRACE_BOOST, sereneGraceBoost, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(IRON_BALL, ironBall, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(IRON_BALL, ironBall, (u32, GEN_COUNT - 1)) \
/* Weather settings */ \
F(ABILITY_WEATHER, abilityWeather, (u32, GEN_COUNT - 1)) \
F(SANDSTORM_SPDEF_BOOST, sandstormSpDefBoost, (u32, GEN_COUNT - 1)) \

View File

@ -723,7 +723,6 @@ void CreateBattleTowerMon_HandleLevel(struct Pokemon *mon, struct BattleTowerPok
void CreateApprenticeMon(struct Pokemon *mon, const struct Apprentice *src, u8 monId);
void CreateMonWithEVSpreadNatureOTID(struct Pokemon *mon, u16 species, u8 level, u8 nature, u8 fixedIV, u8 evSpread, u32 otId);
void ConvertPokemonToBattleTowerPokemon(struct Pokemon *mon, struct BattleTowerPokemon *dest);
bool8 ShouldIgnoreDeoxysForm(u8 caseId, u8 battler);
u16 GetUnionRoomTrainerPic(void);
enum TrainerClassID GetUnionRoomTrainerClass(void);
void CreateEnemyEventMon(void);

View File

@ -3398,7 +3398,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case ABILITY_VOLT_ABSORB:
if (moveType == TYPE_ELECTRIC)
{
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5 && atkPartnerAbility == ABILITY_LIGHTNING_ROD)
if (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) < GEN_5 && atkPartnerAbility == ABILITY_LIGHTNING_ROD)
{
RETURN_SCORE_MINUS(10);
}
@ -3444,7 +3444,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case ABILITY_STORM_DRAIN:
if (moveType == TYPE_WATER)
{
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5 && atkPartnerAbility == ABILITY_STORM_DRAIN)
if (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) < GEN_5 && atkPartnerAbility == ABILITY_STORM_DRAIN)
{
RETURN_SCORE_MINUS(10);
}
@ -5397,7 +5397,7 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru
case EFFECT_ION_DELUGE:
if ((aiData->abilities[battlerAtk] == ABILITY_VOLT_ABSORB
|| aiData->abilities[battlerAtk] == ABILITY_MOTOR_DRIVE
|| (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD))
|| (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD))
&& predictedType == TYPE_NORMAL)
ADJUST_SCORE(DECENT_EFFECT);
break;
@ -5457,7 +5457,7 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru
if (predictedMove != MOVE_NONE
&& (aiData->abilities[battlerAtk] == ABILITY_VOLT_ABSORB
|| aiData->abilities[battlerAtk] == ABILITY_MOTOR_DRIVE
|| (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD)))
|| (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD)))
{
ADJUST_SCORE(DECENT_EFFECT);
}
@ -5697,17 +5697,14 @@ static s32 AI_CalcAdditionalEffectScore(u32 battlerAtk, u32 battlerDef, u32 move
u32 i;
u32 additionalEffectCount = GetMoveAdditionalEffectCount(move);
if (IsSheerForceAffected(move, aiData->abilities[battlerAtk]))
return score;
// check move additional effects that are likely to happen
for (i = 0; i < additionalEffectCount; i++)
{
const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i);
if (aiData->abilities[battlerAtk] == ABILITY_SHEER_FORCE)
{
if ((additionalEffect->chance > 0) != additionalEffect->sheerForceOverride)
continue;
}
// Only consider effects with a guaranteed chance to happen
if (!MoveEffectIsGuaranteed(battlerAtk, aiData->abilities[battlerAtk], additionalEffect))
continue;

View File

@ -298,7 +298,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
// Check if mon gets one shot
if (maxDamageTaken > gBattleMons[battler].hp
&& !(gItemsInfo[gBattleMons[battler].item].holdEffect == HOLD_EFFECT_FOCUS_SASH || (!IsMoldBreakerTypeAbility(opposingBattler, gAiLogicData->abilities[opposingBattler]) && B_STURDY >= GEN_5 && aiAbility == ABILITY_STURDY)))
&& !(gItemsInfo[gBattleMons[battler].item].holdEffect == HOLD_EFFECT_FOCUS_SASH || (!IsMoldBreakerTypeAbility(opposingBattler, gAiLogicData->abilities[opposingBattler]) && GetConfig(CONFIG_STURDY) >= GEN_5 && aiAbility == ABILITY_STURDY)))
{
getsOneShot = TRUE;
}
@ -534,14 +534,14 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
{
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_WATER_ABSORB;
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_DRY_SKIN;
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5)
if (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) >= GEN_5)
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_STORM_DRAIN;
}
else if (incomingType == TYPE_ELECTRIC || (isOpposingBattlerChargingOrInvulnerable && incomingType == TYPE_ELECTRIC))
{
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_VOLT_ABSORB;
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_MOTOR_DRIVE;
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5)
if (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) >= GEN_5)
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_LIGHTNING_ROD;
}
else if (incomingType == TYPE_GRASS || (isOpposingBattlerChargingOrInvulnerable && incomingType == TYPE_GRASS))
@ -1757,7 +1757,7 @@ static u32 GetSwitchinStatusDamage(u32 battler)
{
if (status & STATUS1_BURN)
{
if (B_BURN_DAMAGE >= GEN_7)
if (GetConfig(CONFIG_BURN_DAMAGE) >= GEN_7)
statusDamage = maxHP / 16;
else
statusDamage = maxHP / 8;
@ -1768,7 +1768,7 @@ static u32 GetSwitchinStatusDamage(u32 battler)
}
else if (status & STATUS1_FROSTBITE)
{
if (B_BURN_DAMAGE >= GEN_7)
if (GetConfig(CONFIG_BURN_DAMAGE) >= GEN_7)
statusDamage = maxHP / 16;
else
statusDamage = maxHP / 8;
@ -1852,7 +1852,7 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler)
currentHP = currentHP - damageTaken;
// One shot prevention effects
if (damageTaken >= maxHP && startingHP == maxHP && (heldItemEffect == HOLD_EFFECT_FOCUS_SASH || (!opponentCanBreakMold && B_STURDY >= GEN_5 && ability == ABILITY_STURDY)) && hitsToKO < 1)
if (damageTaken >= maxHP && startingHP == maxHP && (heldItemEffect == HOLD_EFFECT_FOCUS_SASH || (!opponentCanBreakMold && GetConfig(CONFIG_STURDY) >= GEN_5 && ability == ABILITY_STURDY)) && hitsToKO < 1)
currentHP = 1;
// If mon is still alive, apply weather impact first, as it might KO the mon before it can heal with its item (order is weather -> item -> status)

View File

@ -1030,6 +1030,9 @@ 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))
return FALSE;
switch (GetMoveEffect(move))
{
case EFFECT_HIT_ESCAPE:
@ -1469,7 +1472,7 @@ bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move)
if (!DoesBattlerIgnoreAbilityChecks(battler, gAiLogicData->abilities[battler], move))
{
if (B_STURDY >= GEN_5 && gAiLogicData->abilities[battlerTarget] == ABILITY_STURDY)
if (GetConfig(CONFIG_STURDY) >= GEN_5 && gAiLogicData->abilities[battlerTarget] == ABILITY_STURDY)
return TRUE;
if (IsMimikyuDisguised(battlerTarget))
return TRUE;
@ -3351,7 +3354,7 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, enum Ability defAbility
if (!IsBattleMoveStatus(move) && ((gAiLogicData->shouldSwitch & (1u << battlerAtk))
|| (AI_BattlerAtMaxHp(battlerDef) && (gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH
|| (B_STURDY >= GEN_5 && defAbility == ABILITY_STURDY)
|| (GetConfig(CONFIG_STURDY) >= GEN_5 && defAbility == ABILITY_STURDY)
|| defAbility == ABILITY_MULTISCALE
|| defAbility == ABILITY_SHADOW_SHIELD))))
return SHOULD_PIVOT; // pivot to break sash/sturdy/multiscale
@ -3359,7 +3362,7 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, enum Ability defAbility
else if (!hasStatBoost)
{
if (!IsBattleMoveStatus(move) && (AI_BattlerAtMaxHp(battlerDef) && (gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH
|| (B_STURDY >= GEN_5 && defAbility == ABILITY_STURDY)
|| (GetConfig(CONFIG_STURDY) >= GEN_5 && defAbility == ABILITY_STURDY)
|| defAbility == ABILITY_MULTISCALE
|| defAbility == ABILITY_SHADOW_SHIELD)))
return SHOULD_PIVOT; // pivot to break sash/sturdy/multiscale
@ -5241,6 +5244,9 @@ bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove)
return FALSE;
}
if (GetMoveEffect(chosenMove) == EFFECT_LAST_RESORT && !CanUseLastResort(battlerAtk))
return TRUE;
uq4_12_t effectiveness;
struct SimulatedDamage dmg;
@ -5766,7 +5772,7 @@ bool32 ShouldTriggerAbility(u32 battlerAtk, u32 battlerDef, enum Ability ability
{
case ABILITY_LIGHTNING_ROD:
case ABILITY_STORM_DRAIN:
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5)
if (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) < GEN_5)
return FALSE;
else
return (BattlerStatCanRise(battlerDef, ability, STAT_SPATK) && HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL));

View File

@ -531,7 +531,7 @@ static bool32 HandleEndTurnBurn(u32 battler)
&& IsBattlerAlive(battler)
&& !IsAbilityAndRecord(battler, ability, ABILITY_MAGIC_GUARD))
{
s32 burnDamage = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8);
s32 burnDamage = GetNonDynamaxMaxHP(battler) / (GetConfig(CONFIG_BURN_DAMAGE) >= GEN_7 ? 16 : 8);
if (ability == ABILITY_HEATPROOF)
{
if (burnDamage > (burnDamage / 2) + 1) // Record ability if the burn takes less damage than it normally would.
@ -556,7 +556,7 @@ static bool32 HandleEndTurnFrostbite(u32 battler)
&& IsBattlerAlive(battler)
&& !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD))
{
SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8));
SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / (GetConfig(CONFIG_BURN_DAMAGE) >= GEN_7 ? 16 : 8));
BattleScriptExecute(BattleScript_FrostbiteTurnDmg);
effect = TRUE;
}

View File

@ -1929,7 +1929,7 @@ static void Cmd_adjustdamage(void)
gLastUsedItem = gBattleMons[battlerDef].item;
gBattleStruct->moveResultFlags[battlerDef] |= MOVE_RESULT_FOE_HUNG_ON;
}
else if (B_STURDY >= GEN_5 && GetBattlerAbility(battlerDef) == ABILITY_STURDY && IsBattlerAtMaxHp(battlerDef))
else if (GetConfig(CONFIG_STURDY) >= GEN_5 && GetBattlerAbility(battlerDef) == ABILITY_STURDY && IsBattlerAtMaxHp(battlerDef))
{
enduredHit |= 1u << battlerDef;
RecordAbilityBattle(battlerDef, ABILITY_STURDY);
@ -3049,7 +3049,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
if (!primary && !affectsUser && IsMoveEffectBlockedByTarget(battlerAbility))
moveEffect = MOVE_EFFECT_NONE;
else if (!primary
&& TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)
&& IsSheerForceAffected(gCurrentMove, GetBattlerAbility(battler))
&& !(GetMoveEffect(gCurrentMove) == EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE))
moveEffect = MOVE_EFFECT_NONE;
else if (!IsBattlerAlive(gEffectBattler) && !activateAfterFaint)
@ -6400,7 +6400,7 @@ static void Cmd_moveend(void)
&& gBattlerTarget != gBattlerAttacker
&& !IsBattlerAlly(gBattlerTarget, gBattlerAttacker)
&& gProtectStructs[gBattlerTarget].physicalBattlerId == gBattlerAttacker
&& !TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove))
&& !IsSheerForceAffected(gCurrentMove, GetBattlerAbility(gBattlerAttacker)))
{
gProtectStructs[gBattlerTarget].shellTrap = TRUE;
// Change move order in double battles, so the hit mon with shell trap moves immediately after being hit.
@ -6660,7 +6660,7 @@ static void Cmd_moveend(void)
gBattleScripting.moveendState++;
break;
case MOVEEND_SHEER_FORCE:
if (TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove))
if (IsSheerForceAffected(gCurrentMove, GetBattlerAbility(gBattlerAttacker)))
gBattleScripting.moveendState = MOVEEND_EJECT_PACK;
else
gBattleScripting.moveendState++;
@ -9525,7 +9525,7 @@ static bool32 IsElectricAbilityAffected(u32 battler, enum Ability ability)
moveType = GetMoveType(gCurrentMove);
if (moveType == TYPE_ELECTRIC
&& (ability != ABILITY_LIGHTNING_ROD || B_REDIRECT_ABILITY_IMMUNITY >= GEN_5)
&& (ability != ABILITY_LIGHTNING_ROD || GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) >= GEN_5)
&& GetBattlerAbility(battler) == ability)
return TRUE;
else
@ -11526,120 +11526,75 @@ static void Cmd_settypetorandomresistance(void)
// Before Gen 5 Conversion 2 only worked on a move the attacker was actually hit by.
// This changed later to the last move used by the selected target.
if (B_UPDATED_CONVERSION_2 < GEN_5)
u32 moveToCheck;
u32 typeToCheck;
if (GetConfig(CONFIG_UPDATED_CONVERSION_2) < GEN_5)
{
if (gLastLandedMoves[gBattlerAttacker] == MOVE_NONE
|| gLastLandedMoves[gBattlerAttacker] == MOVE_UNAVAILABLE)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gBattleMoveEffects[GetMoveEffect(gLastLandedMoves[gBattlerAttacker])].twoTurnEffect
&& gBattleMons[gLastHitBy[gBattlerAttacker]].volatiles.multipleTurns)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_TERA)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gLastHitByType[gBattlerAttacker] == TYPE_STELLAR || gLastHitByType[gBattlerAttacker] == TYPE_MYSTERY)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
moveToCheck = gLastLandedMoves[gBattlerAttacker];
if (GetMoveEffect(moveToCheck) == EFFECT_STRUGGLE)
typeToCheck = TYPE_NORMAL;
else
{
u32 i, resistTypes = 0;
u32 hitByType = gLastHitByType[gBattlerAttacker];
for (i = 0; i < NUMBER_OF_MON_TYPES; i++) // Find all types that resist.
{
switch (GetTypeModifier(hitByType, i))
{
case UQ_4_12(0):
case UQ_4_12(0.5):
resistTypes |= 1u << i;
break;
}
}
while (resistTypes != 0)
{
i = Random() % NUMBER_OF_MON_TYPES;
if (resistTypes & 1u << i)
{
if (IS_BATTLER_OF_TYPE(gBattlerAttacker, i))
{
resistTypes &= ~(1u << i); // Type resists, but the user is already of this type.
}
else
{
SET_BATTLER_TYPE(gBattlerAttacker, i);
PREPARE_TYPE_BUFFER(gBattleTextBuff1, i);
gBattlescriptCurrInstr = cmd->nextInstr;
return;
}
}
}
gBattlescriptCurrInstr = cmd->failInstr;
}
typeToCheck = gLastHitByType[gBattlerAttacker];
}
else
{
if (gLastResultingMoves[gBattlerTarget] == MOVE_NONE
|| gLastResultingMoves[gBattlerTarget] == MOVE_UNAVAILABLE
|| gLastResultingMoves[gBattlerTarget] == MOVE_STRUGGLE)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (!BreaksThroughSemiInvulnerablity(gBattlerTarget, gCurrentMove))
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gLastUsedMoveType[gBattlerTarget] == TYPE_NONE || gLastUsedMoveType[gBattlerTarget] == TYPE_STELLAR || gLastUsedMoveType[gBattlerTarget] == TYPE_MYSTERY)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_TERA)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else
{
u32 i, resistTypes = 0;
moveToCheck = gLastResultingMoves[gBattlerTarget];
typeToCheck = gLastUsedMoveType[gBattlerTarget];
}
for (i = 0; i < NUMBER_OF_MON_TYPES; i++) // Find all types that resist.
if (moveToCheck == MOVE_NONE
|| moveToCheck == MOVE_UNAVAILABLE)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (!BreaksThroughSemiInvulnerablity(gBattlerTarget, moveToCheck))
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_TERA)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (typeToCheck == TYPE_NONE || typeToCheck == TYPE_STELLAR || typeToCheck == TYPE_MYSTERY)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else
{
u32 i, resistTypes = 0;
for (i = 0; i < NUMBER_OF_MON_TYPES; i++) // Find all types that resist.
{
switch (GetTypeModifier(typeToCheck, i))
{
switch (GetTypeModifier(gLastUsedMoveType[gBattlerTarget], i))
case UQ_4_12(0):
case UQ_4_12(0.5):
resistTypes |= 1u << i;
break;
}
}
while (resistTypes != 0)
{
i = Random() % NUMBER_OF_MON_TYPES;
if (resistTypes & 1u << i)
{
if (IS_BATTLER_OF_TYPE(gBattlerAttacker, i))
{
case UQ_4_12(0):
case UQ_4_12(0.5):
resistTypes |= 1u << i;
break;
resistTypes &= ~(1u << i); // Type resists, but the user is already of this type.
}
else
{
SET_BATTLER_TYPE(gBattlerAttacker, i);
PREPARE_TYPE_BUFFER(gBattleTextBuff1, i);
gBattlescriptCurrInstr = cmd->nextInstr;
return;
}
}
while (resistTypes != 0)
{
i = Random() % NUMBER_OF_MON_TYPES;
if (resistTypes & 1u << i)
{
if (IS_BATTLER_OF_TYPE(gBattlerAttacker, i))
{
resistTypes &= ~(1u << i); // Type resists, but the user is already of this type.
}
else
{
SET_BATTLER_TYPE(gBattlerAttacker, i);
PREPARE_TYPE_BUFFER(gBattleTextBuff1, i);
gBattlescriptCurrInstr = cmd->nextInstr;
return;
}
}
}
gBattlescriptCurrInstr = cmd->failInstr;
}
gBattlescriptCurrInstr = cmd->failInstr;
}
}
@ -11739,7 +11694,7 @@ static void Cmd_settailwind(void)
if (!(gSideStatuses[side] & SIDE_STATUS_TAILWIND))
{
gSideStatuses[side] |= SIDE_STATUS_TAILWIND;
gSideTimers[side].tailwindTimer = (B_TAILWIND_TURNS >= GEN_5 ? 4 : 3);
gSideTimers[side].tailwindTimer = (GetConfig(CONFIG_TAILWIND_TURNS) >= GEN_5 ? 4 : 3);
gBattlescriptCurrInstr = cmd->nextInstr;
}
else

View File

@ -3552,14 +3552,14 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, enum Ability ability
}
break;
case ABILITY_LIGHTNING_ROD:
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && moveType == TYPE_ELECTRIC && GetBattlerMoveTargetType(battlerAtk, move) != MOVE_TARGET_ALL_BATTLERS)
if (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && moveType == TYPE_ELECTRIC && GetBattlerMoveTargetType(battlerAtk, move) != MOVE_TARGET_ALL_BATTLERS)
{
effect = MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY;
statId = STAT_SPATK;
}
break;
case ABILITY_STORM_DRAIN:
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && moveType == TYPE_WATER)
if (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && moveType == TYPE_WATER)
{
effect = MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY;
statId = STAT_SPATK;
@ -5500,7 +5500,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
gBattleScripting.battler = gBattlerAbility = gBattlerTarget;
RecordAbilityBattle(gBattlerTarget, ABILITY_SYNCHRONIZE);
if (B_SYNCHRONIZE_TOXIC < GEN_5 && gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
if (GetConfig(CONFIG_SYNCHRONIZE_TOXIC) < GEN_5 && gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON;
if (CanSetNonVolatileStatus(
@ -5530,7 +5530,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
gBattleScripting.battler = gBattlerAbility = gBattlerAttacker;
RecordAbilityBattle(gBattlerAttacker, ABILITY_SYNCHRONIZE);
if (B_SYNCHRONIZE_TOXIC < GEN_5 && gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
if (GetConfig(CONFIG_SYNCHRONIZE_TOXIC) < GEN_5 && gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON;
if (CanSetNonVolatileStatus(
@ -8798,7 +8798,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageCont
}
// Iron Ball ignores type modifiers for flying-type mons if it is the only source of grounding
if (B_IRON_BALL >= GEN_5
if (GetConfig(CONFIG_IRON_BALL) >= GEN_5
&& ctx->moveType == TYPE_GROUND
&& ctx->holdEffectDef == HOLD_EFFECT_IRON_BALL
&& IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_FLYING)
@ -9743,7 +9743,7 @@ bool32 CanFling(u32 battler)
u16 item = gBattleMons[battler].item;
if (item == ITEM_NONE
|| (B_KLUTZ_FLING_INTERACTION >= GEN_5 && GetBattlerAbility(battler) == ABILITY_KLUTZ)
|| (GetConfig(CONFIG_KLUTZ_FLING_INTERACTION) >= GEN_5 && GetBattlerAbility(battler) == ABILITY_KLUTZ)
|| gFieldStatuses & STATUS_FIELD_MAGIC_ROOM
|| gBattleMons[battler].volatiles.embargo
|| GetFlingPowerFromItemId(item) == 0
@ -9892,9 +9892,9 @@ bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes)
return ret;
}
bool32 TestIfSheerForceAffected(u32 battler, u16 move)
bool32 IsSheerForceAffected(u16 move, enum Ability ability)
{
return GetBattlerAbility(battler) == ABILITY_SHEER_FORCE && MoveIsAffectedBySheerForce(move);
return ability == ABILITY_SHEER_FORCE && MoveIsAffectedBySheerForce(move);
}
// This function is the body of "jumpifstat", but can be used dynamically in a function

View File

@ -1554,63 +1554,6 @@ static void CreateEventMon(struct Pokemon *mon, u16 species, u8 level, u8 fixedI
SetMonData(mon, MON_DATA_MODERN_FATEFUL_ENCOUNTER, &isModernFatefulEncounter);
}
// If FALSE, should load this game's Deoxys form. If TRUE, should load normal Deoxys form
bool8 ShouldIgnoreDeoxysForm(u8 caseId, u8 battler)
{
switch (caseId)
{
case 0:
default:
return FALSE;
case 1: // Player's side in battle
if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI))
return FALSE;
if (!gMain.inBattle)
return FALSE;
if (gLinkPlayers[GetMultiplayerId()].id == battler)
return FALSE;
break;
case 2:
break;
case 3: // Summary Screen
if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI))
return FALSE;
if (!gMain.inBattle)
return FALSE;
if (battler == 1 || battler == 4 || battler == 5)
return TRUE;
return FALSE;
case 4:
break;
case 5: // In move animation, e.g. in Role Play or Snatch
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
if (!gMain.inBattle)
return FALSE;
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
{
if (gLinkPlayers[GetMultiplayerId()].id == battler)
return FALSE;
}
else
{
if (IsOnPlayerSide(battler))
return FALSE;
}
}
else
{
if (!gMain.inBattle)
return FALSE;
if (IsOnPlayerSide(battler))
return FALSE;
}
break;
}
return TRUE;
}
u16 GetUnionRoomTrainerPic(void)
{
u8 linkId;

View File

@ -167,6 +167,10 @@ static u32 PickMonFromPool(const struct Trainer *trainer, u8 *poolIndexArray, u3
// If no mon has been found yet continue looking
if (monIndex == POOL_SLOT_DISABLED)
monIndex = pickFunctions.OtherFunction(trainer, poolIndexArray, partyIndex, monsCount, battleTypeFlags, rules);
// If a mon still hasn't been found, return POOL_SLOT_DISABLED which makes party generation default to regular party generation
if (monIndex == POOL_SLOT_DISABLED)
return monIndex;
u32 chosenTags = trainer->party[monIndex].tags;
u16 chosenSpecies = trainer->party[monIndex].species;
u16 chosenItem = trainer->party[monIndex].heldItem;

View File

@ -1,16 +1,20 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Lightning Rod absorbs Electric-type moves and increases the Sp. Attack [Gen5+]")
SINGLE_BATTLE_TEST("Lightning Rod absorbs Electric-type moves and increases the Sp. Attack (Gen5+)")
{
u32 config;
PARAMETRIZE { config = GEN_4; }
PARAMETRIZE { config = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, config);
ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); }
} WHEN {
TURN { MOVE(player, MOVE_THUNDERBOLT); MOVE(opponent, MOVE_CELEBRATE); }
} SCENE {
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) {
if (config >= GEN_5) {
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDERBOLT, player);
HP_BAR(opponent);
@ -29,13 +33,21 @@ SINGLE_BATTLE_TEST("Lightning Rod absorbs Electric-type moves and increases the
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent);
} THEN {
EXPECT_EQ(gBattleHistory->abilities[1], ABILITY_LIGHTNING_ROD); // Check if the correct ability has been recorded
if (config >= GEN_5) {
EXPECT_EQ(gBattleHistory->abilities[1], ABILITY_LIGHTNING_ROD); // Check if the correct ability has been recorded
} else {
EXPECT_EQ(gBattleHistory->abilities[1], ABILITY_NONE);
}
}
}
DOUBLE_BATTLE_TEST("Lightning Rod forces single-target Electric-type moves to target the Pokémon with this Ability.")
{
u32 config;
PARAMETRIZE { config = GEN_4; }
PARAMETRIZE { config = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, config);
ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
@ -49,7 +61,7 @@ DOUBLE_BATTLE_TEST("Lightning Rod forces single-target Electric-type moves to ta
MOVE(opponentRight, MOVE_CELEBRATE);
}
} SCENE {
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) {
if (config >= GEN_5) {
NONE_OF {
HP_BAR(opponentLeft);
HP_BAR(opponentRight);
@ -86,7 +98,7 @@ DOUBLE_BATTLE_TEST("Lightning Rod redirects an ally's attack")
TURN { MOVE(opponentRight, MOVE_THUNDERBOLT, target: playerLeft); }
} SCENE {
MESSAGE("The opposing Wobbuffet used Thunderbolt!");
if (B_REDIRECT_ABILITY_ALLIES >= GEN_5)
if (B_REDIRECT_ABILITY_ALLIES >= GEN_4)
{
NOT HP_BAR(playerLeft);
ABILITY_POPUP(opponentLeft, ABILITY_LIGHTNING_ROD);
@ -100,9 +112,10 @@ DOUBLE_BATTLE_TEST("Lightning Rod redirects an ally's attack")
}
}
DOUBLE_BATTLE_TEST("Lightning Rod absorbs moves that targets all battlers but does not redirect")
DOUBLE_BATTLE_TEST("Lightning Rod absorbs moves that targets all battlers but does not redirect (Gen6+)")
{
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
ASSUME(GetMoveType(MOVE_DISCHARGE) == TYPE_ELECTRIC);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);

View File

@ -109,8 +109,9 @@ SINGLE_BATTLE_TEST("Parental Bond-converted moves only hit once on Lightning Rod
enum Type type;
enum Ability ability;
PARAMETRIZE { move = MOVE_THUNDERBOLT; ability = ABILITY_LIGHTNING_ROD; species = SPECIES_RAICHU; type = TYPE_ELECTRIC; }
PARAMETRIZE { move = MOVE_SURF; ability = ABILITY_STORM_DRAIN; species = SPECIES_LILEEP; type = TYPE_WATER; }
PARAMETRIZE { move = MOVE_SURF; ability = ABILITY_STORM_DRAIN; species = SPECIES_LILEEP; type = TYPE_WATER; }
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
ASSUME(GetMoveStrikeCount(move) < 2);
ASSUME(GetMoveType(move) == type);
PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); }

View File

@ -21,10 +21,13 @@ DOUBLE_BATTLE_TEST("Stalwart ignores redirection from Follow-Me")
DOUBLE_BATTLE_TEST("Stalwart stops Lightning Rod and Storm Drain from redirecting moves")
{
enum Ability ability;
u32 species;
PARAMETRIZE { ability = ABILITY_STORM_DRAIN; species = SPECIES_LUMINEON; }
PARAMETRIZE { ability = ABILITY_LIGHTNING_ROD; species = SPECIES_RAICHU; }
u32 species, config;
PARAMETRIZE { ability = ABILITY_STORM_DRAIN; species = SPECIES_LUMINEON; config = GEN_4; }
PARAMETRIZE { ability = ABILITY_STORM_DRAIN; species = SPECIES_LUMINEON; config = GEN_5; }
PARAMETRIZE { ability = ABILITY_LIGHTNING_ROD; species = SPECIES_RAICHU; config = GEN_4; }
PARAMETRIZE { ability = ABILITY_LIGHTNING_ROD; species = SPECIES_RAICHU; config = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, config);
ASSUME(GetMoveType(MOVE_SPARK) == TYPE_ELECTRIC);
ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER);
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_STALWART); }
@ -39,15 +42,14 @@ DOUBLE_BATTLE_TEST("Stalwart stops Lightning Rod and Storm Drain from redirectin
MOVE(playerLeft, MOVE_WATER_GUN, target: opponentRight);
}
} SCENE {
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) {
HP_BAR(opponentRight);
HP_BAR(opponentRight);
if (config >= GEN_5) {
NONE_OF {
ABILITY_POPUP(opponentLeft, ability);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
MESSAGE("The opposing Raichu's Sp. Atk rose!");
}
} else {
HP_BAR(opponentRight);
NONE_OF {
HP_BAR(opponentLeft);
}

View File

@ -1,16 +1,20 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Storm Drain absorbs Water-type moves and increases the Sp. Attack [Gen5+]")
SINGLE_BATTLE_TEST("Storm Drain absorbs Water-type moves and increases the Sp. Attack (Gen5+)")
{
u32 config;
PARAMETRIZE { config = GEN_4; }
PARAMETRIZE { config = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, config);
ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GASTRODON_EAST) { Ability(ABILITY_STORM_DRAIN); }
} WHEN {
TURN { MOVE(player, MOVE_WATER_GUN); MOVE(opponent, MOVE_CELEBRATE); }
} SCENE {
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) {
if (config >= GEN_5) {
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, player);
HP_BAR(opponent);
@ -33,7 +37,11 @@ SINGLE_BATTLE_TEST("Storm Drain absorbs Water-type moves and increases the Sp. A
DOUBLE_BATTLE_TEST("Storm Drain forces single-target Water-type moves to target the Pokémon with this Ability.")
{
u32 config;
PARAMETRIZE { config = GEN_4; }
PARAMETRIZE { config = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, config);
ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
@ -47,7 +55,7 @@ DOUBLE_BATTLE_TEST("Storm Drain forces single-target Water-type moves to target
MOVE(opponentRight, MOVE_CELEBRATE);
}
} SCENE {
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) {
if (config >= GEN_5) {
NONE_OF {
HP_BAR(opponentLeft);
HP_BAR(opponentRight);

View File

@ -18,18 +18,37 @@ SINGLE_BATTLE_TEST("Sturdy prevents OHKO moves")
}
}
SINGLE_BATTLE_TEST("Sturdy prevents OHKOs")
SINGLE_BATTLE_TEST("Sturdy prevents OHKOs (Gen5+)")
{
u32 config;
PARAMETRIZE { config = GEN_4; }
PARAMETRIZE { config = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_STURDY, config);
PLAYER(SPECIES_GEODUDE) { Ability(ABILITY_STURDY); MaxHP(100); HP(100); }
PLAYER(SPECIES_GEODUDE);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_SEISMIC_TOSS); }
TURN {
MOVE(opponent, MOVE_SEISMIC_TOSS);
if (config < GEN_5) {
SEND_OUT(player, 1);
}
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SEISMIC_TOSS, opponent);
HP_BAR(player, hp: 1);
ABILITY_POPUP(player, ABILITY_STURDY);
MESSAGE("Geodude endured the hit using Sturdy!");
if (config >= GEN_5) {
HP_BAR(player, hp: 1);
ABILITY_POPUP(player, ABILITY_STURDY);
MESSAGE("Geodude endured the hit using Sturdy!");
} else {
HP_BAR(player, hp: 0);
NONE_OF {
ABILITY_POPUP(player, ABILITY_STURDY);
MESSAGE("Geodude endured the hit using Sturdy!");
}
SEND_IN_MESSAGE("Geodude");
}
}
}

View File

@ -3,11 +3,13 @@
SINGLE_BATTLE_TEST("Synchronize will mirror back non volatile status back at opposing mon")
{
u32 config;
PARAMETRIZE { config = GEN_4; }
PARAMETRIZE { config = GEN_5; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_NON_VOLATILE_STATUS);
ASSUME(GetMoveNonVolatileStatus(MOVE_TOXIC) == MOVE_EFFECT_TOXIC);
ASSUME(GetMoveNonVolatileStatus(MOVE_TOXIC) == MOVE_EFFECT_TOXIC);
WITH_CONFIG(CONFIG_SYNCHRONIZE_TOXIC, config);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ABRA) { Ability(ABILITY_SYNCHRONIZE); }
} WHEN {
@ -18,7 +20,10 @@ SINGLE_BATTLE_TEST("Synchronize will mirror back non volatile status back at opp
STATUS_ICON(opponent, badPoison: TRUE);
ABILITY_POPUP(opponent, ABILITY_SYNCHRONIZE);
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player);
STATUS_ICON(player, badPoison: TRUE);
if (config >= GEN_5)
STATUS_ICON(player, badPoison: TRUE);
else
STATUS_ICON(player, poison: TRUE);
}
}

View File

@ -846,6 +846,7 @@ AI_DOUBLE_BATTLE_TEST("AI sees opposing drain ability")
ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC);
ASSUME(GetMoveType(MOVE_RAZOR_LEAF) != TYPE_ELECTRIC);
ASSUME(GetMoveType(MOVE_METAL_CLAW) != TYPE_ELECTRIC);
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
PLAYER(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); Moves(MOVE_CELEBRATE); }
PLAYER(SPECIES_KRABBY) { Ability(ABILITY_VOLT_ABSORB); Moves(MOVE_CELEBRATE); }

View File

@ -133,3 +133,16 @@ AI_SINGLE_BATTLE_TEST("HasMoveThatChangesKOThreshold - AI should not see self-ta
TURN { MOVE(player, MOVE_HAMMER_ARM); EXPECT_MOVE(opponent, move == MOVE_EARTHQUAKE ? MOVE_NASTY_PLOT : MOVE_AURA_SPHERE); }
}
}
AI_SINGLE_BATTLE_TEST("AI_IsMoveEffectInPlus - AI should not see secondary effect of Sheer Force boosted moves as beneficial")
{
GIVEN {
ASSUME(GetMovePower(MOVE_PSYCHIC) == 90);
ASSUME(MoveHasAdditionalEffect(MOVE_PSYCHIC, MOVE_EFFECT_SP_DEF_MINUS_1) == TRUE);
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 | AI_FLAG_OMNISCIENT);
PLAYER(SPECIES_STEELIX) { Level(100); Nature(NATURE_SASSY); Item(ITEM_STEELIXITE); Ability(ABILITY_STURDY); Speed(58); Moves(MOVE_GYRO_BALL); }
OPPONENT(SPECIES_BRAVIARY_HISUI) { Level(100); Nature(NATURE_TIMID); Ability(ABILITY_SHEER_FORCE); Speed(251); Moves(MOVE_PSYCHIC, MOVE_NIGHT_SHADE); }
} WHEN {
TURN { MOVE(player, MOVE_GYRO_BALL); SCORE_EQ_VAL(opponent, MOVE_PSYCHIC, 101); SCORE_EQ_VAL(opponent, MOVE_NIGHT_SHADE, 101); }
}
}

View File

@ -542,54 +542,28 @@ AI_DOUBLE_BATTLE_TEST("AI sees corresponding absorbing abilities on partners")
}
}
AI_DOUBLE_BATTLE_TEST("AI treats an ally's redirection ability appropriately (gen 4)")
AI_DOUBLE_BATTLE_TEST("AI treats an ally's redirection ability appropriately")
{
KNOWN_FAILING;
ASSUME(GetMoveTarget(MOVE_DISCHARGE) == MOVE_TARGET_FOES_AND_ALLY);
ASSUME(GetMoveType(MOVE_DISCHARGE) == TYPE_ELECTRIC);
ASSUME(GetMoveTarget(MOVE_SURF) == MOVE_TARGET_FOES_AND_ALLY);
ASSUME(GetMoveType(MOVE_SURF) == TYPE_WATER);
u32 ability, move, species, config, expectedMove;
enum Ability ability;
u32 move, species;
PARAMETRIZE { species = SPECIES_SEAKING; ability = ABILITY_LIGHTNING_ROD; move = MOVE_DISCHARGE; }
PARAMETRIZE { species = SPECIES_SHELLOS; ability = ABILITY_STORM_DRAIN; move = MOVE_SURF; }
PARAMETRIZE { species = SPECIES_SEAKING; ability = ABILITY_LIGHTNING_ROD; move = MOVE_DISCHARGE; config = GEN_4; expectedMove = MOVE_HEADBUTT; }
PARAMETRIZE { species = SPECIES_SHELLOS; ability = ABILITY_STORM_DRAIN; move = MOVE_SURF; config = GEN_4; expectedMove = MOVE_HEADBUTT; }
PARAMETRIZE { species = SPECIES_SEAKING; ability = ABILITY_LIGHTNING_ROD; move = MOVE_DISCHARGE; config = GEN_5; expectedMove = MOVE_DISCHARGE; }
PARAMETRIZE { species = SPECIES_SHELLOS; ability = ABILITY_STORM_DRAIN; move = MOVE_SURF; config = GEN_5; expectedMove = MOVE_SURF; }
GIVEN {
ASSUME(GetMoveTarget(MOVE_DISCHARGE) == MOVE_TARGET_FOES_AND_ALLY);
ASSUME(GetMoveType(MOVE_DISCHARGE) == TYPE_ELECTRIC);
ASSUME(GetMoveTarget(MOVE_SURF) == MOVE_TARGET_FOES_AND_ALLY);
ASSUME(GetMoveType(MOVE_SURF) == TYPE_WATER);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_HP_AWARE);
WITH_CONFIG(B_REDIRECT_ABILITY_IMMUNITY, GEN_4);
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, config);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Moves(move, MOVE_HEADBUTT); }
OPPONENT(species) { HP(1); Ability(ability); Moves(MOVE_ROUND); }
} WHEN {
TURN { EXPECT_MOVE(opponentLeft, MOVE_HEADBUTT); }
}
}
AI_DOUBLE_BATTLE_TEST("AI treats an ally's redirection ability appropriately (gen 5+)")
{
ASSUME(GetMoveTarget(MOVE_DISCHARGE) == MOVE_TARGET_FOES_AND_ALLY);
ASSUME(GetMoveType(MOVE_DISCHARGE) == TYPE_ELECTRIC);
ASSUME(GetMoveTarget(MOVE_SURF) == MOVE_TARGET_FOES_AND_ALLY);
ASSUME(GetMoveType(MOVE_SURF) == TYPE_WATER);
enum Ability ability;
u32 move, species;
PARAMETRIZE { species = SPECIES_SEAKING; ability = ABILITY_LIGHTNING_ROD; move = MOVE_DISCHARGE; }
PARAMETRIZE { species = SPECIES_SHELLOS; ability = ABILITY_STORM_DRAIN; move = MOVE_SURF; }
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_HP_AWARE);
WITH_CONFIG(B_REDIRECT_ABILITY_IMMUNITY, GEN_5);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Moves(move, MOVE_HEADBUTT); }
OPPONENT(species) { HP(1); Ability(ability); Moves(MOVE_ROUND); }
} WHEN {
TURN { EXPECT_MOVE(opponentLeft, move); }
TURN { EXPECT_MOVE(opponentLeft, expectedMove); }
}
}

View File

@ -1109,7 +1109,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has an
PARAMETRIZE { aiMon = SPECIES_CHESNAUGHT; absorbingAbility = ABILITY_BULLETPROOF; move = MOVE_SLUDGE_BOMB;}
PARAMETRIZE { aiMon = SPECIES_BRAMBLEGHAST; absorbingAbility = ABILITY_WIND_RIDER; move = MOVE_HURRICANE;}
GIVEN {
ASSUME(B_REDIRECT_ABILITY_IMMUNITY >= GEN_5);
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
PLAYER(SPECIES_ZIGZAGOON) { Moves(move); }
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_SCRATCH); }
@ -1662,7 +1662,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will consider Hidden Power wh
{
PASSES_RANDOMLY(SHOULD_SWITCH_ABSORBS_HIDDEN_POWER_PERCENTAGE, 100, RNG_AI_SWITCH_ABSORBING_HIDDEN_POWER);
GIVEN {
ASSUME(B_REDIRECT_ABILITY_IMMUNITY >= GEN_5);
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
PLAYER(SPECIES_ZIGZAGOON) { Moves(MOVE_HIDDEN_POWER); HPIV(31); AttackIV(30); DefenseIV(31); SpAttackIV(30); SpDefenseIV(31); SpeedIV(30); }
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_SCRATCH); }

View File

@ -47,6 +47,18 @@ AI_SINGLE_BATTLE_TEST("AI uses Z-Moves -- Extreme Evoboost")
}
}
AI_SINGLE_BATTLE_TEST("AI uses Z-Moves to bypass move limitations")
{
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT );
ASSUME(GetMoveType(MOVE_QUICK_ATTACK) == TYPE_NORMAL);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); Moves(MOVE_POUND, MOVE_LAST_RESORT); }
} WHEN {
TURN { EXPECT_MOVE(opponent, MOVE_LAST_RESORT, gimmick: GIMMICK_Z_MOVE); }
}
}
AI_SINGLE_BATTLE_TEST("AI uses Z-Moves -- 10,000,000 Volt Thunderbolt")
{
GIVEN {

View File

@ -1611,16 +1611,16 @@ SINGLE_BATTLE_TEST("Dynamax: Max Moves don't bypass absorbing abilities")
{
u32 move, species;
enum Ability ability;
PARAMETRIZE { move = MOVE_SPARK; ability = ABILITY_VOLT_ABSORB; species = SPECIES_LANTURN; }
PARAMETRIZE { move = MOVE_WATER_GUN; ability = ABILITY_WATER_ABSORB; species = SPECIES_LANTURN; }
PARAMETRIZE { move = MOVE_EMBER; ability = ABILITY_FLASH_FIRE; species = SPECIES_HEATRAN; }
PARAMETRIZE { move = MOVE_SPARK; ability = ABILITY_LIGHTNING_ROD; species = SPECIES_PIKACHU; }
PARAMETRIZE { move = MOVE_WATER_GUN; ability = ABILITY_STORM_DRAIN; species = SPECIES_GASTRODON; }
PARAMETRIZE { move = MOVE_EMBER; ability = ABILITY_WELL_BAKED_BODY; species = SPECIES_DACHSBUN; }
PARAMETRIZE { move = MOVE_SPARK; ability = ABILITY_MOTOR_DRIVE; species = SPECIES_ELECTIVIRE; }
PARAMETRIZE { move = MOVE_WATER_GUN; ability = ABILITY_DRY_SKIN; species = SPECIES_PARASECT; }
PARAMETRIZE { move = MOVE_MUD_BOMB; ability = ABILITY_EARTH_EATER; species = SPECIES_ORTHWORM; }
PARAMETRIZE { move = MOVE_VINE_WHIP; ability = ABILITY_SAP_SIPPER; species = SPECIES_MILTANK; }
PARAMETRIZE { move = MOVE_SPARK; ability = ABILITY_VOLT_ABSORB; species = SPECIES_LANTURN; }
PARAMETRIZE { move = MOVE_WATER_GUN; ability = ABILITY_WATER_ABSORB; species = SPECIES_LANTURN; }
PARAMETRIZE { move = MOVE_EMBER; ability = ABILITY_FLASH_FIRE; species = SPECIES_HEATRAN; }
PARAMETRIZE { move = MOVE_SPARK; ability = ABILITY_LIGHTNING_ROD; species = SPECIES_PIKACHU; }
PARAMETRIZE { move = MOVE_WATER_GUN; ability = ABILITY_STORM_DRAIN; species = SPECIES_GASTRODON; }
PARAMETRIZE { move = MOVE_EMBER; ability = ABILITY_WELL_BAKED_BODY; species = SPECIES_DACHSBUN; }
PARAMETRIZE { move = MOVE_SPARK; ability = ABILITY_MOTOR_DRIVE; species = SPECIES_ELECTIVIRE; }
PARAMETRIZE { move = MOVE_WATER_GUN; ability = ABILITY_DRY_SKIN; species = SPECIES_PARASECT; }
PARAMETRIZE { move = MOVE_MUD_BOMB; ability = ABILITY_EARTH_EATER; species = SPECIES_ORTHWORM; }
PARAMETRIZE { move = MOVE_VINE_WHIP; ability = ABILITY_SAP_SIPPER; species = SPECIES_MILTANK; }
GIVEN {
ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER);
@ -1628,6 +1628,7 @@ SINGLE_BATTLE_TEST("Dynamax: Max Moves don't bypass absorbing abilities")
ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE);
ASSUME(GetMoveType(MOVE_MUD_BOMB) == TYPE_GROUND);
ASSUME(GetMoveType(MOVE_VINE_WHIP) == TYPE_GRASS);
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(species) { Ability(ability); }
} WHEN {

View File

@ -327,33 +327,6 @@ SINGLE_BATTLE_TEST("(TERA) Reflect Type fails if used by a Terastallized Pokemon
}
}
SINGLE_BATTLE_TEST("(TERA) Conversion fails if used by a Terastallized Pokemon")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_PSYCHIC); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_CONVERSION, gimmick: GIMMICK_TERA); }
} SCENE {
MESSAGE("Wobbuffet used Conversion!");
MESSAGE("But it failed!");
}
}
SINGLE_BATTLE_TEST("(TERA) Conversion2 fails if used by a Terastallized Pokemon")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_PSYCHIC); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_SCRATCH); }
TURN { MOVE(player, MOVE_CONVERSION_2, gimmick: GIMMICK_TERA); }
} SCENE {
MESSAGE("Wobbuffet used Conversion 2!");
MESSAGE("But it failed!");
}
}
SINGLE_BATTLE_TEST("(TERA) Reflect Type copies a Terastallized Pokemon's Tera Type")
{
GIVEN {
@ -506,26 +479,6 @@ SINGLE_BATTLE_TEST("(TERA) Revelation Dance uses a Stellar-type Pokemon's base t
}
}
#if B_UPDATED_CONVERSION_2 < GEN_5
SINGLE_BATTLE_TEST("(TERA) Conversion2 fails if last hit by a Stellar-type move")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TERA_BLAST, gimmick: GIMMICK_TERA); }
TURN { MOVE(opponent, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Wobbuffet used Tera Blast!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player);
// turn 2
MESSAGE("The opposing Wobbuffet used Conversion 2!");
MESSAGE("But it failed!");
}
}
#endif
SINGLE_BATTLE_TEST("(TERA) Roost does not remove Flying-type ground immunity when Terastallized into the Stellar type")
{
GIVEN {

View File

@ -5,17 +5,24 @@ ASSUMPTIONS{
ASSUME(gItemsInfo[ITEM_IRON_BALL].holdEffect == HOLD_EFFECT_IRON_BALL);
}
SINGLE_BATTLE_TEST("Ground-type moves do neutral damage to non-grounded Flying types holding Iron Ball regardless of other typings") //gen5+ only
SINGLE_BATTLE_TEST("Ground-type moves do neutral damage to non-grounded Flying types holding Iron Ball regardless of other typings (Gen5+)")
{
ASSUME(B_IRON_BALL >= GEN_5);
u32 config;
PARAMETRIZE { config = GEN_4; }
PARAMETRIZE { config = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_IRON_BALL, config);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SKARMORY) { Item(ITEM_IRON_BALL); };
} WHEN {
TURN { MOVE(player, MOVE_EARTHQUAKE); };
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, player);
NONE_OF {
if (config >= GEN_5) {
NONE_OF {
MESSAGE("It's super effective!");
}
} else {
MESSAGE("It's super effective!");
}
}

View File

@ -110,6 +110,7 @@ SINGLE_BATTLE_TEST("Life Orb does not activate if on a confusion hit")
SINGLE_BATTLE_TEST("Life Orb does not activate if move was absorbed by target")
{
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); }
OPPONENT(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); }
} WHEN {

View File

@ -8,3 +8,16 @@ TO_DO_BATTLE_TEST("Conversion fails if all the user's moves share types with the
TO_DO_BATTLE_TEST("Conversion changes the user's types to the one in the user's first slot (Gen 6+)");
TO_DO_BATTLE_TEST("Conversion can read the user's first move slot even if that move cannot be selected (Gen 6+)"); //Eg. Disable
TO_DO_BATTLE_TEST("Conversion can change the user's types to Conversion's type");
SINGLE_BATTLE_TEST("(TERA) Conversion fails if used by a Terastallized Pokemon")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_PSYCHIC); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_CONVERSION, gimmick: GIMMICK_TERA); }
} SCENE {
MESSAGE("Wobbuffet used Conversion!");
MESSAGE("But it failed!");
}
}

View File

@ -3,10 +3,10 @@
TO_DO_BATTLE_TEST("Conversion 2's type change considers Inverse Battles");
#if B_UPDATED_CONVERSION_2 < GEN_5
SINGLE_BATTLE_TEST("Conversion 2 randomly changes the type of the user to a type that resists the last move that hit the user (Gen 3-4)")
SINGLE_BATTLE_TEST("Conversion 2 randomly changes the type of the user to a type that resists the last move that hit the user (Gen 1-4)")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_CONVERSION_2, GEN_4);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -16,15 +16,16 @@ SINGLE_BATTLE_TEST("Conversion 2 randomly changes the type of the user to a type
MESSAGE("Wobbuffet used Ominous Wind!");
// turn 1
ONE_OF {
MESSAGE("The opposing Wobbuffet transformed into the Normal type!");
MESSAGE("The opposing Wobbuffet transformed into the Dark type!");
MESSAGE("The opposing Wobbuffet transformed into the Normal type!");
MESSAGE("The opposing Wobbuffet transformed into the Dark type!");
}
}
}
SINGLE_BATTLE_TEST("Conversion 2's type change considers Struggle to be Normal type (Gen 3-4)")
SINGLE_BATTLE_TEST("Conversion 2's type change considers Struggle to be Normal type (Gen 1-4)")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_CONVERSION_2, GEN_4);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -35,18 +36,17 @@ SINGLE_BATTLE_TEST("Conversion 2's type change considers Struggle to be Normal t
MESSAGE("The opposing Wobbuffet used Struggle!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Steel type!");
MESSAGE("Wobbuffet transformed into the Rock type!");
MESSAGE("Wobbuffet transformed into the Ghost type!");
MESSAGE("Wobbuffet transformed into the Steel type!");
MESSAGE("Wobbuffet transformed into the Rock type!");
MESSAGE("Wobbuffet transformed into the Ghost type!");
}
}
}
#endif
#if B_UPDATED_CONVERSION_2 >= GEN_5
SINGLE_BATTLE_TEST("Conversion 2 randomly changes the type of the user to a type that resists the last used target's move (Gen 5+)")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_CONVERSION_2, GEN_5);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -56,8 +56,8 @@ SINGLE_BATTLE_TEST("Conversion 2 randomly changes the type of the user to a type
MESSAGE("Wobbuffet used Ominous Wind!");
// turn 1
ONE_OF {
MESSAGE("The opposing Wobbuffet transformed into the Normal type!");
MESSAGE("The opposing Wobbuffet transformed into the Dark type!");
MESSAGE("The opposing Wobbuffet transformed into the Normal type!");
MESSAGE("The opposing Wobbuffet transformed into the Dark type!");
}
}
}
@ -65,6 +65,7 @@ SINGLE_BATTLE_TEST("Conversion 2 randomly changes the type of the user to a type
SINGLE_BATTLE_TEST("Conversion 2's type change considers status moves (Gen 5+)")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_CONVERSION_2, GEN_5);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -75,8 +76,8 @@ SINGLE_BATTLE_TEST("Conversion 2's type change considers status moves (Gen 5+)")
MESSAGE("The opposing Wobbuffet used Curse!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Normal type!");
MESSAGE("Wobbuffet transformed into the Dark type!");
MESSAGE("Wobbuffet transformed into the Normal type!");
MESSAGE("Wobbuffet transformed into the Dark type!");
}
}
}
@ -84,6 +85,7 @@ SINGLE_BATTLE_TEST("Conversion 2's type change considers status moves (Gen 5+)")
SINGLE_BATTLE_TEST("Conversion 2's type change considers the type of moves called by other moves")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_CONVERSION_2, GEN_5);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -94,8 +96,8 @@ SINGLE_BATTLE_TEST("Conversion 2's type change considers the type of moves calle
MESSAGE("The opposing Wobbuffet used Mirror Move!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Normal type!");
MESSAGE("Wobbuffet transformed into the Dark type!");
MESSAGE("Wobbuffet transformed into the Normal type!");
MESSAGE("Wobbuffet transformed into the Dark type!");
}
}
}
@ -103,6 +105,7 @@ SINGLE_BATTLE_TEST("Conversion 2's type change considers the type of moves calle
SINGLE_BATTLE_TEST("Conversion 2's type change considers dynamic type moves")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_CONVERSION_2, GEN_5);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -113,10 +116,10 @@ SINGLE_BATTLE_TEST("Conversion 2's type change considers dynamic type moves")
MESSAGE("The opposing Wobbuffet used Weather Ball!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Steel type!");
MESSAGE("Wobbuffet transformed into the Fire type!");
MESSAGE("Wobbuffet transformed into the Water type!");
MESSAGE("Wobbuffet transformed into the Ice type!");
MESSAGE("Wobbuffet transformed into the Steel type!");
MESSAGE("Wobbuffet transformed into the Fire type!");
MESSAGE("Wobbuffet transformed into the Water type!");
MESSAGE("Wobbuffet transformed into the Ice type!");
}
}
}
@ -124,6 +127,7 @@ SINGLE_BATTLE_TEST("Conversion 2's type change considers dynamic type moves")
SINGLE_BATTLE_TEST("Conversion 2's type change considers move types changed by Normalize and Electrify")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_CONVERSION_2, GEN_5);
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_NORMALIZE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -136,17 +140,17 @@ SINGLE_BATTLE_TEST("Conversion 2's type change considers move types changed by N
MESSAGE("The opposing Wobbuffet used Pound!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Ground type!");
MESSAGE("Wobbuffet transformed into the Dragon type!");
MESSAGE("Wobbuffet transformed into the Grass type!");
MESSAGE("Wobbuffet transformed into the Electric type!");
MESSAGE("Wobbuffet transformed into the Ground type!");
MESSAGE("Wobbuffet transformed into the Dragon type!");
MESSAGE("Wobbuffet transformed into the Grass type!");
MESSAGE("Wobbuffet transformed into the Electric type!");
}
// turn 3
MESSAGE("Wobbuffet used Water Gun!");
ONE_OF {
MESSAGE("The opposing Wobbuffet transformed into the Steel type!");
MESSAGE("The opposing Wobbuffet transformed into the Rock type!");
MESSAGE("The opposing Wobbuffet transformed into the Ghost type!");
MESSAGE("The opposing Wobbuffet transformed into the Steel type!");
MESSAGE("The opposing Wobbuffet transformed into the Rock type!");
MESSAGE("The opposing Wobbuffet transformed into the Ghost type!");
}
}
}
@ -154,6 +158,7 @@ SINGLE_BATTLE_TEST("Conversion 2's type change considers move types changed by N
SINGLE_BATTLE_TEST("Conversion 2's type change fails targeting Struggle (Gen 5+)")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_CONVERSION_2, GEN_5);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -171,6 +176,7 @@ SINGLE_BATTLE_TEST("Conversion 2's type change fails targeting Struggle (Gen 5+)
SINGLE_BATTLE_TEST("Conversion 2 fails if the move used is of typeless damage (Gen 5+)")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_CONVERSION_2, GEN_5);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ENTEI);
} WHEN {
@ -187,7 +193,6 @@ SINGLE_BATTLE_TEST("Conversion 2 fails if the move used is of typeless damage (G
MESSAGE("But it failed!");
}
}
#endif
SINGLE_BATTLE_TEST("Conversion 2 fails if the targeted move is Stellar Type")
{
@ -205,3 +210,35 @@ SINGLE_BATTLE_TEST("Conversion 2 fails if the targeted move is Stellar Type")
MESSAGE("But it failed!");
}
}
SINGLE_BATTLE_TEST("Conversion 2 fails if used by a Terastallized Pokemon")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_PSYCHIC); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
TURN { MOVE(player, MOVE_CONVERSION_2, gimmick: GIMMICK_TERA); }
} SCENE {
MESSAGE("Wobbuffet used Conversion 2!");
MESSAGE("But it failed!");
}
}
SINGLE_BATTLE_TEST("Conversion 2 fails if last hit by a Stellar-type move (Gen 1-4)")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_CONVERSION_2, GEN_4);
PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TERA_BLAST, gimmick: GIMMICK_TERA); MOVE(opponent, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Wobbuffet used Tera Blast!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player);
// turn 2
MESSAGE("The opposing Wobbuffet used Conversion 2!");
MESSAGE("But it failed!");
}
}

View File

@ -81,6 +81,7 @@ DOUBLE_BATTLE_TEST("Court Change swaps entry hazards used by the player")
DOUBLE_BATTLE_TEST("Court Change used by the player swaps Mist, Safeguard, Aurora Veil, Reflect, Light Screen, Tailwind")
{
GIVEN {
WITH_CONFIG(CONFIG_TAILWIND_TURNS, GEN_5);
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_WYNAUT);
@ -119,6 +120,7 @@ DOUBLE_BATTLE_TEST("Court Change used by the player swaps Mist, Safeguard, Auror
DOUBLE_BATTLE_TEST("Court Change used by the opponent swaps Mist, Safeguard, Aurora Veil, Reflect, Light Screen, Tailwind")
{
GIVEN {
WITH_CONFIG(CONFIG_TAILWIND_TURNS, GEN_5);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
@ -248,4 +250,3 @@ AI_SINGLE_BATTLE_TEST("AI uses Court Change")
TURN { MOVE(player, MOVE_CELEBRATE); EXPECT_MOVE(opponent, MOVE_COURT_CHANGE); }
}
}

View File

@ -56,22 +56,24 @@ SINGLE_BATTLE_TEST("Fling fails if Pokémon is under the effects of Embargo or M
}
}
SINGLE_BATTLE_TEST("Fling fails for Pokémon with Klutz ability")
SINGLE_BATTLE_TEST("Fling fails for Pokémon with Klutz ability (Gen5+)")
{
enum Ability ability;
u32 config;
PARAMETRIZE {ability = ABILITY_KLUTZ; }
PARAMETRIZE {ability = ABILITY_RUN_AWAY; }
PARAMETRIZE { ability = ABILITY_RUN_AWAY; config = GEN_4; }
PARAMETRIZE { ability = ABILITY_KLUTZ; config = GEN_4; }
PARAMETRIZE { ability = ABILITY_KLUTZ; config = GEN_5; }
GIVEN {
ASSUME(B_KLUTZ_FLING_INTERACTION >= GEN_5);
WITH_CONFIG(CONFIG_KLUTZ_FLING_INTERACTION, config);
PLAYER(SPECIES_BUNEARY) { Item(ITEM_RAZOR_CLAW); Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_FLING); }
} SCENE {
MESSAGE("Buneary used Fling!");
if (ability != ABILITY_KLUTZ) {
if (ability != ABILITY_KLUTZ || config == GEN_4) {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player);
HP_BAR(opponent);
} else {

View File

@ -239,6 +239,7 @@ DOUBLE_BATTLE_TEST("Instructed move will be redirected and absorbed by Lightning
PARAMETRIZE { moveTarget = opponentLeft; }
PARAMETRIZE { moveTarget = opponentRight; }
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_PIKACHU) { Ability(ABILITY_LIGHTNING_ROD); }

View File

@ -910,6 +910,7 @@ DOUBLE_BATTLE_TEST("Pledge move combo doesn't trigger on opponent's Pledge move
DOUBLE_BATTLE_TEST("Pledge move combo doesn't trigger on opponent's Pledge move - Storm Drain")
{
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
PLAYER(SPECIES_GASTRODON) { Ability(ABILITY_STORM_DRAIN); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);

View File

@ -113,6 +113,7 @@ DOUBLE_BATTLE_TEST("Sleep Talk calls move and that move may be redirected by Lig
{
PASSES_RANDOMLY(1, 2, RNG_RANDOM_TARGET);
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
ASSUME(GetMoveType(MOVE_SPARK) == TYPE_ELECTRIC);
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); Moves(MOVE_SLEEP_TALK, MOVE_SPARK, MOVE_FLY, MOVE_DIG); }
PLAYER(SPECIES_WOBBUFFET);
@ -132,6 +133,7 @@ DOUBLE_BATTLE_TEST("Sleep Talk calls move and that move may be redirected by Sto
{
PASSES_RANDOMLY(1, 2, RNG_RANDOM_TARGET);
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER);
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); Moves(MOVE_SLEEP_TALK, MOVE_WATER_GUN, MOVE_FLY, MOVE_DIG); }
PLAYER(SPECIES_WOBBUFFET);

View File

@ -6,10 +6,13 @@ ASSUMPTIONS
ASSUME(GetMoveEffect(MOVE_TAILWIND) == EFFECT_TAILWIND);
}
SINGLE_BATTLE_TEST("Tailwind applies for 4 turns")
SINGLE_BATTLE_TEST("Tailwind applies for 3 turns (Gen4) or 4 turns (Gen5+)")
{
u32 config;
PARAMETRIZE { config = GEN_4; }
PARAMETRIZE { config = GEN_5; }
GIVEN {
ASSUME(B_TAILWIND_TURNS >= GEN_5);
WITH_CONFIG(CONFIG_TAILWIND_TURNS, config);
PLAYER(SPECIES_WOBBUFFET) { Speed(10); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(15); }
} WHEN {
@ -28,8 +31,10 @@ SINGLE_BATTLE_TEST("Tailwind applies for 4 turns")
MESSAGE("Wobbuffet used Celebrate!");
MESSAGE("The opposing Wobbuffet used Celebrate!");
MESSAGE("Wobbuffet used Celebrate!");
MESSAGE("The opposing Wobbuffet used Celebrate!");
if (config >= GEN_5) {
MESSAGE("Wobbuffet used Celebrate!");
MESSAGE("The opposing Wobbuffet used Celebrate!");
}
MESSAGE("The opposing Wobbuffet used Celebrate!");
MESSAGE("Wobbuffet used Celebrate!");

View File

@ -205,6 +205,7 @@ SINGLE_BATTLE_TEST("Teatime triggers Lightning Rod if it has been affected by El
PARAMETRIZE { move = MOVE_PLASMA_FISTS; item = ITEM_NONE; }
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
PLAYER(SPECIES_PIKACHU) { Ability(ABILITY_LIGHTNING_ROD); Item(item); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LIECHI_BERRY); }
} WHEN {

View File

@ -172,6 +172,7 @@ DOUBLE_BATTLE_TEST("Spread Moves: A spread move attack will be weakened by stron
DOUBLE_BATTLE_TEST("Spread Moves: AOE move vs Disguise, Volt Absorb (right) and Lightning Rod (left)")
{
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
ASSUME(GetMoveTarget(MOVE_DISCHARGE) == MOVE_TARGET_FOES_AND_ALLY);
ASSUME(GetMoveType(MOVE_DISCHARGE) == TYPE_ELECTRIC);
PLAYER(SPECIES_WOBBUFFET);
@ -191,6 +192,7 @@ DOUBLE_BATTLE_TEST("Spread Moves: AOE move vs Disguise, Volt Absorb (right) and
DOUBLE_BATTLE_TEST("Spread Moves: AOE move vs Disguise, Volt Absorb (left) and Lightning Rod (right)")
{
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
ASSUME(GetMoveTarget(MOVE_DISCHARGE) == MOVE_TARGET_FOES_AND_ALLY);
ASSUME(GetMoveType(MOVE_DISCHARGE) == TYPE_ELECTRIC);
PLAYER(SPECIES_WOBBUFFET);

View File

@ -7,10 +7,13 @@ ASSUMPTIONS
ASSUME(GetMoveNonVolatileStatus(MOVE_WILL_O_WISP) == MOVE_EFFECT_BURN);
}
SINGLE_BATTLE_TEST("Burn deals 1/16th (Gen7+) or 1/8th damage per turn")
SINGLE_BATTLE_TEST("Burn deals 1/8th damage (Gen1-6) or 1/16th (Gen7+) per turn")
{
u32 j;
u32 j, config, value;
PARAMETRIZE { config = GEN_7; value = 16; }
PARAMETRIZE { config = GEN_6; value = 8; }
GIVEN {
WITH_CONFIG(CONFIG_BURN_DAMAGE, config);
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_BURN); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -19,7 +22,7 @@ SINGLE_BATTLE_TEST("Burn deals 1/16th (Gen7+) or 1/8th damage per turn")
} SCENE {
s32 maxHP = GetMonData(&PLAYER_PARTY[0], MON_DATA_MAX_HP);
for (j = 0; j < 4; j++)
HP_BAR(player, damage: maxHP / ((B_BURN_DAMAGE >= GEN_7) ? 16 : 8));
HP_BAR(player, damage: maxHP / value);
}
}

View File

@ -23,11 +23,14 @@ SINGLE_BATTLE_TEST("Frostbite reduces the special attack by 50 percent")
} THEN { EXPECT_EQ(reducedDamage * 2, normaleDamage); }
}
SINGLE_BATTLE_TEST("Frostbite deals 1/16th (Gen7+) or 1/8th damage to affected Pokémon")
SINGLE_BATTLE_TEST("Frostbite deals 1/8th damage (Gen1-6) or 1/16th (Gen7+) per turn")
{
s16 frostbiteDamage;
u32 config, value;
PARAMETRIZE { config = GEN_7; value = 16; }
PARAMETRIZE { config = GEN_6; value = 8; }
GIVEN {
WITH_CONFIG(CONFIG_BURN_DAMAGE, config);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_FROSTBITE); }
} WHEN {
@ -36,7 +39,9 @@ SINGLE_BATTLE_TEST("Frostbite deals 1/16th (Gen7+) or 1/8th damage to affected P
MESSAGE("The opposing Wobbuffet was hurt by its frostbite!");
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRB, opponent);
HP_BAR(opponent, captureDamage: &frostbiteDamage);
} THEN { EXPECT_EQ(frostbiteDamage, opponent->maxHP / ((B_BURN_DAMAGE >= GEN_7) ? 16 : 8)); }
} THEN {
EXPECT_EQ(frostbiteDamage, opponent->maxHP / value);
}
}
SINGLE_BATTLE_TEST("Frostbite is healed if hit with a thawing move")