Merge branch 'RHH/master' into RHH/upcoming

# Conflicts:
#	src/battle_util.c
This commit is contained in:
Eduardo Quezada 2023-07-19 23:22:07 -04:00
commit 47cea526ec
21 changed files with 797 additions and 77 deletions

View File

@ -23,8 +23,9 @@ body:
label: Version
description: What version of pokeemerald-expansion are you using as a base?
options:
- 1.5.0 (Default)
- 1.5.1 (Default)
- upcoming (Edge)
- 1.5.0
- 1.4.3
- 1.4.2
- 1.4.1

View File

@ -23,8 +23,9 @@ body:
label: Version
description: What version of pokeemerald-expansion are you using as a base?
options:
- 1.5.0 (Default)
- 1.5.1 (Default)
- upcoming (Edge)
- 1.5.0
- 1.4.3
- 1.4.2
- 1.4.1

View File

@ -23,8 +23,9 @@ body:
label: Version
description: What version of pokeemerald-expansion are you using as a base?
options:
- 1.5.0 (Default)
- 1.5.1 (Default)
- upcoming (Edge)
- 1.5.0
- 1.4.3
- 1.4.2
- 1.4.1

View File

@ -6634,9 +6634,6 @@ BattleScript_DoSwitchOut::
hidepartystatussummary BS_ATTACKER
switchinanim BS_ATTACKER, FALSE
waitstate
jumpifcantreverttoprimal BattleScript_DoSwitchOut2
call BattleScript_PrimalReversionRet
BattleScript_DoSwitchOut2:
switchineffects BS_ATTACKER
moveendcase MOVEEND_STATUS_IMMUNITY_ABILITIES
moveendcase MOVEEND_MIRROR_MOVE
@ -7791,17 +7788,12 @@ BattleScript_WishMegaEvolution::
goto BattleScript_MegaEvolutionAfterString
BattleScript_PrimalReversion::
printstring STRINGID_EMPTYSTRING3
waitmessage 1
setbyte gIsCriticalHit, 0
handleprimalreversion BS_ATTACKER, 0
handleprimalreversion BS_ATTACKER, 1
playanimation BS_ATTACKER, B_ANIM_PRIMAL_REVERSION
waitanimation
handleprimalreversion BS_ATTACKER, 2
printstring STRINGID_PKMNREVERTEDTOPRIMAL
waitmessage B_WAIT_TIME_LONG
switchinabilities BS_ATTACKER
call BattleScript_PrimalReversionRet
end2
BattleScript_PrimalReversionRestoreAttacker::
call BattleScript_PrimalReversionRet
copybyte gBattlerAttacker, sSAVED_BATTLER
end2
BattleScript_PrimalReversionRet::
@ -7815,6 +7807,7 @@ BattleScript_PrimalReversionRet::
handleprimalreversion BS_ATTACKER, 2
printstring STRINGID_PKMNREVERTEDTOPRIMAL
waitmessage B_WAIT_TIME_LONG
switchinabilities BS_ATTACKER
return
BattleScript_AttackerFormChange::

View File

@ -634,7 +634,7 @@ struct BattleStruct
bool8 friskedAbility; // If identifies two mons, show the ability pop-up only once.
u8 sameMoveTurns[MAX_BATTLERS_COUNT]; // For Metronome, number of times the same moves has been SUCCESFULLY used.
u16 moveEffect2; // For Knock Off
u16 changedSpecies[PARTY_SIZE]; // For Zygarde or future forms when multiple mons can change into the same pokemon.
u16 changedSpecies[NUM_BATTLE_SIDES][PARTY_SIZE]; // For forms when multiple mons can change into the same pokemon.
u8 quickClawBattlerId;
struct LostItem itemLost[PARTY_SIZE]; // Player's team that had items consumed or stolen (two bytes per party member)
u8 blunderPolicy:1; // should blunder policy activate

View File

@ -418,6 +418,7 @@ extern const u8 BattleScript_AttackWeakenedByStrongWinds[];
extern const u8 BattleScript_BlockedByPrimalWeatherEnd3[];
extern const u8 BattleScript_BlockedByPrimalWeatherRet[];
extern const u8 BattleScript_PrimalReversion[];
extern const u8 BattleScript_PrimalReversionRestoreAttacker[];
extern const u8 BattleScript_HyperspaceFuryRemoveProtect[];
extern const u8 BattleScript_SelectingNotAllowedMoveGorillaTactics[];
extern const u8 BattleScript_SelectingNotAllowedMoveGorillaTacticsInPalace[];

View File

@ -142,6 +142,7 @@ u8 AtkCanceller_UnableToUseMove2(void);
bool8 HasNoMonsToSwitch(u8 battlerId, u8 r1, u8 r2);
bool32 TryChangeBattleWeather(u8 battler, u32 weatherEnumId, bool32 viaAbility);
u8 AbilityBattleEffects(u8 caseID, u8 battlerId, u16 ability, u8 special, u16 moveArg);
bool32 TryPrimalReversion(u8 battlerId);
bool32 IsNeutralizingGasOnField(void);
u32 GetBattlerAbility(u8 battlerId);
u32 IsAbilityOnSide(u32 battlerId, u32 ability);
@ -208,6 +209,7 @@ void BufferStatChange(u8 battlerId, u8 statId, u8 stringId);
bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef, bool32 checkTarget);
u16 GetUsedHeldItem(u8 battler);
bool32 IsBattlerWeatherAffected(u8 battlerId, u32 weatherFlags);
u32 ApplyWeatherDamageMultiplier(u8 battlerAtk, u16 move, u8 moveType, u32 dmg, u16 holdEffectAtk, u16 holdEffectDef);
u32 GetBattlerMoveTargetType(u8 battlerId, u16 move);
bool32 CanTargetBattler(u8 battlerAtk, u8 battlerDef, u16 move);
bool8 IsMoveAffectedByParentalBond(u16 move, u8 battlerId);

View File

@ -10,6 +10,7 @@
#define I_VITAMIN_EV_CAP GEN_LATEST // In Gen8+, the Vitamins no longer have a cap of 100 EV per stat.
#define I_BERRY_EV_JUMP GEN_LATEST // In Gen4 only, EV-lowering Berries lower a stat's EV to 100 if it is above 100.
#define I_GRISEOUS_ORB_FORM_CHANGE GEN_LATEST // In Gen9+, the Griseous Orb no longer changes Giratina's form when held.
#define I_GEM_BOOST_POWER GEN_LATEST // In Gen5+, the Gem boost power was reduced from 50% to 30%.
#define I_USE_EVO_HELD_ITEMS_FROM_BAG FALSE // If TRUE, items such as Razor Claw or Electirizer will be usable from the bag to evolve a Pokémon just like in LA.
// TM config

View File

@ -3875,14 +3875,9 @@ static void TryDoEventsBeforeFirstTurn(void)
while (gBattleStruct->switchInAbilitiesCounter < gBattlersCount)
{
gBattlerAttacker = gBattlerByTurnOrder[gBattleStruct->switchInAbilitiesCounter++];
// Primal Reversion
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_PRIMAL_ORB
&& GetBattleFormChangeTargetSpecies(gBattlerAttacker, FORM_CHANGE_BATTLE_PRIMAL_REVERSION) != SPECIES_NONE)
{
BattleScriptExecute(BattleScript_PrimalReversion);
if (TryPrimalReversion(gBattlerAttacker))
return;
}
if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gBattlerAttacker, 0, 0, 0) != 0)
return;
}
@ -5454,7 +5449,8 @@ static void HandleEndTurn_FinishBattle(void)
changedForm = TryFormChange(i, B_SIDE_PLAYER, FORM_CHANGE_END_BATTLE);
// Clear original species field
gBattleStruct->changedSpecies[i] = SPECIES_NONE;
gBattleStruct->changedSpecies[B_SIDE_PLAYER][i] = SPECIES_NONE;
gBattleStruct->changedSpecies[B_SIDE_OPPONENT][i] = SPECIES_NONE;
#if B_RECALCULATE_STATS >= GEN_5
// Recalculate the stats of every party member before the end

View File

@ -6826,7 +6826,8 @@ static void SetDmgHazardsBattlescript(u8 battlerId, u8 multistringId)
bool32 DoSwitchInAbilitiesItems(u32 battlerId)
{
return (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, battlerId, 0, 0, 0)
return (TryPrimalReversion(battlerId)
|| AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, battlerId, 0, 0, 0)
|| (gBattleWeather & B_WEATHER_ANY && WEATHER_HAS_EFFECT && AbilityBattleEffects(ABILITYEFFECT_ON_WEATHER, battlerId, 0, 0, 0))
|| (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY && AbilityBattleEffects(ABILITYEFFECT_ON_TERRAIN, battlerId, 0, 0, 0))
|| ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, battlerId, FALSE)
@ -10434,7 +10435,7 @@ static void Cmd_various(void)
{
gBattleStruct->battleBondTransformed[GET_BATTLER_SIDE2(gBattlerAttacker)] |= gBitTable[gBattlerPartyIndexes[gBattlerAttacker]];
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].species);
gBattleStruct->changedSpecies[gBattlerPartyIndexes[gBattlerAttacker]] = gBattleMons[gBattlerAttacker].species;
gBattleStruct->changedSpecies[GET_BATTLER_SIDE2(gBattlerAttacker)][gBattlerPartyIndexes[gBattlerAttacker]] = gBattleMons[gBattlerAttacker].species;
gBattleMons[gBattlerAttacker].species = SPECIES_GRENINJA_ASH;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_BattleBondActivatesOnMoveEndAttacker;

View File

@ -6040,6 +6040,27 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
return effect;
}
bool32 TryPrimalReversion(u8 battlerId)
{
if (GetBattlerHoldEffect(battlerId, FALSE) == HOLD_EFFECT_PRIMAL_ORB
&& GetBattleFormChangeTargetSpecies(battlerId, FORM_CHANGE_BATTLE_PRIMAL_REVERSION) != SPECIES_NONE)
{
if (gBattlerAttacker == battlerId)
{
BattleScriptExecute(BattleScript_PrimalReversion);
}
else
{
// edge case for scenarios like a switch-in after activated eject button
gBattleScripting.savedBattler = gBattlerAttacker;
gBattlerAttacker = battlerId;
BattleScriptExecute(BattleScript_PrimalReversionRestoreAttacker);
}
return TRUE;
}
return FALSE;
}
bool32 IsNeutralizingGasBannedAbility(u32 ability)
{
switch (ability)
@ -8784,14 +8805,16 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe
case ABILITY_PROTOSYNTHESIS:
{
u8 atkHighestStat = GetHighestStatId(battlerAtk);
if (gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT && (atkHighestStat == STAT_ATK || atkHighestStat == STAT_SPATK))
if (gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT
&& ((IS_MOVE_PHYSICAL(move) && atkHighestStat == STAT_ATK) || (IS_MOVE_SPECIAL(move) && atkHighestStat == STAT_SPATK)))
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
}
break;
case ABILITY_QUARK_DRIVE:
{
u8 atkHighestStat = GetHighestStatId(battlerAtk);
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && (atkHighestStat == STAT_ATK || atkHighestStat == STAT_SPATK))
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN
&& ((IS_MOVE_PHYSICAL(move) && atkHighestStat == STAT_ATK) || (IS_MOVE_SPECIAL(move) && atkHighestStat == STAT_SPATK)))
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
}
break;
@ -8882,14 +8905,16 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe
case ABILITY_PROTOSYNTHESIS:
{
u8 defHighestStat = GetHighestStatId(battlerDef);
if (gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT && (defHighestStat == STAT_DEF || defHighestStat == STAT_SPDEF))
if (gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT
&& ((IS_MOVE_PHYSICAL(move) && defHighestStat == STAT_DEF) || (IS_MOVE_SPECIAL(move) && defHighestStat == STAT_SPDEF)))
modifier = uq4_12_multiply(modifier, UQ_4_12(0.7));
}
break;
case ABILITY_QUARK_DRIVE:
{
u8 defHighestStat = GetHighestStatId(battlerDef);
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && (defHighestStat == STAT_DEF || defHighestStat == STAT_SPDEF))
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN
&& ((IS_MOVE_PHYSICAL(move) && defHighestStat == STAT_DEF) || (IS_MOVE_SPECIAL(move) && defHighestStat == STAT_SPDEF)))
modifier = uq4_12_multiply(modifier, UQ_4_12(0.7));
}
break;
@ -8933,10 +8958,6 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe
#endif
modifier = uq4_12_multiply(modifier, holdEffectModifier);
break;
case HOLD_EFFECT_GEMS:
if (gSpecialStatuses[battlerAtk].gemBoost && gBattleMons[battlerAtk].item)
modifier = uq4_12_multiply(modifier, UQ_4_12(1.0) + sPercentToModifier[gSpecialStatuses[battlerAtk].gemParam]);
break;
case HOLD_EFFECT_BUG_POWER:
case HOLD_EFFECT_STEEL_POWER:
case HOLD_EFFECT_GROUND_POWER:
@ -9027,6 +9048,8 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe
// various effects
if (gProtectStructs[battlerAtk].helpingHand)
modifier = uq4_12_multiply(modifier, UQ_4_12(1.5));
if (gSpecialStatuses[battlerAtk].gemBoost)
modifier = uq4_12_multiply(modifier, UQ_4_12(1.0) + sPercentToModifier[gSpecialStatuses[battlerAtk].gemParam]);
if (gStatuses3[battlerAtk] & STATUS3_CHARGED_UP && moveType == TYPE_ELECTRIC)
modifier = uq4_12_multiply(modifier, UQ_4_12(2.0));
if (gStatuses3[battlerAtk] & STATUS3_ME_FIRST)
@ -9423,6 +9446,8 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move
u32 defSide = GET_BATTLER_SIDE(battlerDef);
uq4_12_t finalModifier = UQ_4_12(1.0);
u16 itemDef = gBattleMons[battlerDef].item;
u16 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE);
u16 holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE);
// check multiple targets in double battle
if (GetMoveTargetCount(move, battlerAtk, battlerDef) >= 2)
@ -9452,28 +9477,15 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move
dmg = ApplyModifier(UQ_4_12(0.5), dmg);
// check frostbite
if (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE && !IS_MOVE_PHYSICAL(move)
if (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE && IS_MOVE_SPECIAL(move)
#if B_BURN_FACADE_DMG >= GEN_6
&& gBattleMoves[move].effect != EFFECT_FACADE
#endif
&& abilityAtk != ABILITY_GUTS)
dmg = ApplyModifier(UQ_4_12(0.5), dmg);
// check sunny/rain weather
if (IsBattlerWeatherAffected(battlerAtk, B_WEATHER_RAIN))
{
if (moveType == TYPE_FIRE)
dmg = ApplyModifier(UQ_4_12(0.5), dmg);
else if (moveType == TYPE_WATER)
dmg = ApplyModifier(UQ_4_12(1.5), dmg);
}
else if (IsBattlerWeatherAffected(battlerAtk, B_WEATHER_SUN))
{
if (moveType == TYPE_FIRE || gBattleMoves[move].effect == EFFECT_HYDRO_STEAM)
dmg = ApplyModifier(UQ_4_12(1.5), dmg);
else if (moveType == TYPE_WATER)
dmg = ApplyModifier(UQ_4_12(0.5), dmg);
}
// check weather
dmg = ApplyWeatherDamageMultiplier(battlerAtk, move, moveType, dmg, holdEffectAtk, holdEffectDef);
// check stab
if (IS_BATTLER_OF_TYPE(battlerAtk, moveType) && move != MOVE_STRUGGLE && move != MOVE_NONE)
@ -9562,7 +9574,7 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move
}
// attacker's hold effect
switch (GetBattlerHoldEffect(battlerAtk, TRUE))
switch (holdEffectAtk)
{
case HOLD_EFFECT_METRONOME:
percentBoost = min((gBattleStruct->sameMoveTurns[battlerAtk] * GetBattlerHoldEffectParam(battlerAtk)), 100);
@ -9578,7 +9590,7 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move
}
// target's hold effect
switch (GetBattlerHoldEffect(battlerDef, TRUE))
switch (holdEffectDef)
{
// berries reducing dmg
case HOLD_EFFECT_RESIST_BERRY:
@ -10152,8 +10164,8 @@ bool32 TryBattleFormChange(u8 battlerId, u16 method)
if (targetSpecies != SPECIES_NONE)
{
// Saves the original species on the first form change for the player.
if (side == B_SIDE_PLAYER && gBattleStruct->changedSpecies[monId] == SPECIES_NONE)
gBattleStruct->changedSpecies[monId] = gBattleMons[battlerId].species;
if (gBattleStruct->changedSpecies[side][monId] == SPECIES_NONE)
gBattleStruct->changedSpecies[side][monId] = gBattleMons[battlerId].species;
TryToSetBattleFormChangeMoves(&party[monId], method);
SetMonData(&party[monId], MON_DATA_SPECIES, &targetSpecies);
@ -10161,7 +10173,7 @@ bool32 TryBattleFormChange(u8 battlerId, u16 method)
RecalcBattlerStats(battlerId, &party[monId]);
return TRUE;
}
else if (gBattleStruct->changedSpecies[monId] != SPECIES_NONE)
else if (gBattleStruct->changedSpecies[side][monId] != SPECIES_NONE)
{
bool8 restoreSpecies = FALSE;
@ -10177,7 +10189,7 @@ bool32 TryBattleFormChange(u8 battlerId, u16 method)
{
// Reverts the original species
TryToSetBattleFormChangeMoves(&party[monId], method);
SetMonData(&party[monId], MON_DATA_SPECIES, &gBattleStruct->changedSpecies[monId]);
SetMonData(&party[monId], MON_DATA_SPECIES, &gBattleStruct->changedSpecies[side][monId]);
RecalcBattlerStats(battlerId, &party[monId]);
return TRUE;
}
@ -10765,6 +10777,34 @@ bool32 IsBattlerWeatherAffected(u8 battlerId, u32 weatherFlags)
return FALSE;
}
// Utility Umbrella holders take normal damage from what would be rain- and sun-weakened attacks.
u32 ApplyWeatherDamageMultiplier(u8 battlerAtk, u16 move, u8 moveType, u32 dmg, u16 holdEffectAtk, u16 holdEffectDef)
{
if (WEATHER_HAS_EFFECT)
{
if (gBattleMoves[move].effect == EFFECT_HYDRO_STEAM && (gBattleWeather & B_WEATHER_SUN) && holdEffectAtk != HOLD_EFFECT_UTILITY_UMBRELLA)
dmg = ApplyModifier(UQ_4_12(1.5), dmg);
else if (holdEffectDef != HOLD_EFFECT_UTILITY_UMBRELLA)
{
if (gBattleWeather & B_WEATHER_RAIN)
{
if (moveType == TYPE_FIRE)
dmg = ApplyModifier(UQ_4_12(0.5), dmg);
else if (moveType == TYPE_WATER)
dmg = ApplyModifier(UQ_4_12(1.5), dmg);
}
else if (gBattleWeather & B_WEATHER_SUN)
{
if (moveType == TYPE_FIRE)
dmg = ApplyModifier(UQ_4_12(1.5), dmg);
else if (moveType == TYPE_WATER)
dmg = ApplyModifier(UQ_4_12(0.5), dmg);
}
}
}
return dmg;
}
// Gets move target before redirection effects etc. are applied
// Possible return values are defined in battle.h following MOVE_TARGET_SELECTED
u32 GetBattlerMoveTargetType(u8 battlerId, u16 move)

View File

@ -6,6 +6,12 @@
#define EVO_HELD_ITEM_FIELD_FUNC ItemUseOutOfBattle_CannotUse
#endif
#if I_GEM_BOOST_POWER >= GEN_5
#define GEM_BOOST_PARAM 30
#else
#define GEM_BOOST_PARAM 50
#endif
const struct Item gItems[] =
{
[ITEM_NONE] =
@ -4416,7 +4422,7 @@ const struct Item gItems[] =
.itemId = ITEM_NORMAL_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sNormalGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4430,7 +4436,7 @@ const struct Item gItems[] =
.itemId = ITEM_FIRE_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sFireGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4444,7 +4450,7 @@ const struct Item gItems[] =
.itemId = ITEM_WATER_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sWaterGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4458,7 +4464,7 @@ const struct Item gItems[] =
.itemId = ITEM_ELECTRIC_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sElectricGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4472,7 +4478,7 @@ const struct Item gItems[] =
.itemId = ITEM_GRASS_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sGrassGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4486,7 +4492,7 @@ const struct Item gItems[] =
.itemId = ITEM_ICE_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sIceGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4500,7 +4506,7 @@ const struct Item gItems[] =
.itemId = ITEM_FIGHTING_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sFightingGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4514,7 +4520,7 @@ const struct Item gItems[] =
.itemId = ITEM_POISON_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sPoisonGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4528,7 +4534,7 @@ const struct Item gItems[] =
.itemId = ITEM_GROUND_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sGroundGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4542,7 +4548,7 @@ const struct Item gItems[] =
.itemId = ITEM_FLYING_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sFlyingGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4556,7 +4562,7 @@ const struct Item gItems[] =
.itemId = ITEM_PSYCHIC_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sPsychicGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4570,7 +4576,7 @@ const struct Item gItems[] =
.itemId = ITEM_BUG_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sBugGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4584,7 +4590,7 @@ const struct Item gItems[] =
.itemId = ITEM_ROCK_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sRockGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4598,7 +4604,7 @@ const struct Item gItems[] =
.itemId = ITEM_GHOST_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sGhostGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4612,7 +4618,7 @@ const struct Item gItems[] =
.itemId = ITEM_DRAGON_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sDragonGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4626,7 +4632,7 @@ const struct Item gItems[] =
.itemId = ITEM_DARK_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sDarkGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4640,7 +4646,7 @@ const struct Item gItems[] =
.itemId = ITEM_STEEL_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sSteelGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4654,7 +4660,7 @@ const struct Item gItems[] =
.itemId = ITEM_FAIRY_GEM,
.price = 4000,
.holdEffect = HOLD_EFFECT_GEMS,
.holdEffectParam = 30,
.holdEffectParam = GEM_BOOST_PARAM,
.description = sFairyGemDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,

View File

@ -8549,7 +8549,7 @@ bool32 TryFormChange(u32 monId, u32 side, u16 method)
targetSpecies = GetFormChangeTargetSpecies(&party[monId], method, 0);
if (targetSpecies == SPECIES_NONE && gBattleStruct != NULL)
targetSpecies = gBattleStruct->changedSpecies[monId];
targetSpecies = gBattleStruct->changedSpecies[side][monId];
if (targetSpecies != SPECIES_NONE)
{

View File

@ -0,0 +1,87 @@
#include "global.h"
#include "test_battle.h"
ASSUMPTIONS
{
ASSUME(gBattleMoves[MOVE_TACKLE].split == SPLIT_PHYSICAL);
ASSUME(gBattleMoves[MOVE_ROUND].split == SPLIT_SPECIAL);
}
SINGLE_BATTLE_TEST("Protosynthesis boosts the highest stat")
{
GIVEN {
PLAYER(SPECIES_ABRA) { Ability(ABILITY_PROTOSYNTHESIS); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_SUNNY_DAY); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, player);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
MESSAGE("The harsh sunlight activated Abra's Protosynthesis!");
MESSAGE("Abra's Sp. Atk was heightened!");
}
}
SINGLE_BATTLE_TEST("Protosynthesis boosts either Attack or Special Attack, not both")
{
u16 species;
u32 move;
u16 damage[2];
PARAMETRIZE { species = SPECIES_BELLSPROUT; move = MOVE_TACKLE; }
PARAMETRIZE { species = SPECIES_BELLSPROUT; move = MOVE_ROUND; }
PARAMETRIZE { species = SPECIES_ABRA; move = MOVE_TACKLE; }
PARAMETRIZE { species = SPECIES_ABRA; move = MOVE_ROUND; }
GIVEN {
PLAYER(species) { Ability(ABILITY_PROTOSYNTHESIS); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, move); }
TURN { MOVE(opponent, MOVE_SUNNY_DAY); MOVE(player, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, player);
HP_BAR(opponent, captureDamage: &damage[0]);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent);
ANIMATION(ANIM_TYPE_MOVE, move, player);
HP_BAR(opponent, captureDamage: &damage[1]);
} THEN {
if ((move == MOVE_TACKLE && species == SPECIES_BELLSPROUT) || (move == MOVE_ROUND && species == SPECIES_ABRA))
EXPECT_MUL_EQ(damage[0], Q_4_12(1.3), damage[1]);
else
EXPECT_EQ(damage[0], damage[1]);
}
}
SINGLE_BATTLE_TEST("Protosynthesis either boosts Defense or Special Defense, not both")
{
u16 species;
u32 move;
u16 damage[2];
PARAMETRIZE { species = SPECIES_ONIX; move = MOVE_TACKLE; }
PARAMETRIZE { species = SPECIES_ONIX; move = MOVE_ROUND; }
PARAMETRIZE { species = SPECIES_BLASTOISE; move = MOVE_TACKLE; }
PARAMETRIZE { species = SPECIES_BLASTOISE; move = MOVE_ROUND; }
GIVEN {
PLAYER(species) { Ability(ABILITY_PROTOSYNTHESIS); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, move); }
TURN { MOVE(player, MOVE_SUNNY_DAY); MOVE(opponent, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
HP_BAR(player, captureDamage: &damage[0]);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, player);
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
HP_BAR(player, captureDamage: &damage[1]);
} THEN {
if ((move == MOVE_TACKLE && species == SPECIES_ONIX) || (move == MOVE_ROUND && species == SPECIES_BLASTOISE))
EXPECT_MUL_EQ(damage[0], Q_4_12(0.7), damage[1]);
else
EXPECT_EQ(damage[0], damage[1]);
}
}

View File

@ -0,0 +1,87 @@
#include "global.h"
#include "test_battle.h"
ASSUMPTIONS
{
ASSUME(gBattleMoves[MOVE_TACKLE].split == SPLIT_PHYSICAL);
ASSUME(gBattleMoves[MOVE_ROUND].split == SPLIT_SPECIAL);
}
SINGLE_BATTLE_TEST("Quark Drive boosts the highest stat")
{
GIVEN {
PLAYER(SPECIES_ABRA) { Ability(ABILITY_QUARK_DRIVE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, player);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
MESSAGE("The Electric Terrain activated Abra's Quark Drive!");
MESSAGE("Abra's Sp. Atk was heightened!");
}
}
SINGLE_BATTLE_TEST("Quark Drive boosts either Attack or Special Attack, not both")
{
u16 species;
u32 move;
u16 damage[2];
PARAMETRIZE { species = SPECIES_BELLSPROUT; move = MOVE_TACKLE; }
PARAMETRIZE { species = SPECIES_BELLSPROUT; move = MOVE_ROUND; }
PARAMETRIZE { species = SPECIES_ABRA; move = MOVE_TACKLE; }
PARAMETRIZE { species = SPECIES_ABRA; move = MOVE_ROUND; }
GIVEN {
PLAYER(species) { Ability(ABILITY_QUARK_DRIVE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, move); }
TURN { MOVE(opponent, MOVE_ELECTRIC_TERRAIN); MOVE(player, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, player);
HP_BAR(opponent, captureDamage: &damage[0]);
ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, opponent);
ANIMATION(ANIM_TYPE_MOVE, move, player);
HP_BAR(opponent, captureDamage: &damage[1]);
} THEN {
if ((move == MOVE_TACKLE && species == SPECIES_BELLSPROUT) || (move == MOVE_ROUND && species == SPECIES_ABRA))
EXPECT_MUL_EQ(damage[0], Q_4_12(1.3), damage[1]);
else
EXPECT_EQ(damage[0], damage[1]);
}
}
SINGLE_BATTLE_TEST("Quark Drive either boosts Defense or Special Defense, not both")
{
u16 species;
u32 move;
u16 damage[2];
PARAMETRIZE { species = SPECIES_ONIX; move = MOVE_TACKLE; }
PARAMETRIZE { species = SPECIES_ONIX; move = MOVE_ROUND; }
PARAMETRIZE { species = SPECIES_BLASTOISE; move = MOVE_TACKLE; }
PARAMETRIZE { species = SPECIES_BLASTOISE; move = MOVE_ROUND; }
GIVEN {
PLAYER(species) { Ability(ABILITY_QUARK_DRIVE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, move); }
TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); MOVE(opponent, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
HP_BAR(player, captureDamage: &damage[0]);
ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, player);
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
HP_BAR(player, captureDamage: &damage[1]);
} THEN {
if ((move == MOVE_TACKLE && species == SPECIES_ONIX) || (move == MOVE_ROUND && species == SPECIES_BLASTOISE))
EXPECT_MUL_EQ(damage[0], Q_4_12(0.7), damage[1]);
else
EXPECT_EQ(damage[0], damage[1]);
}
}

89
test/hold_effect_gems.c Normal file
View File

@ -0,0 +1,89 @@
#include "global.h"
#include "test_battle.h"
ASSUMPTIONS
{
ASSUME(gItems[ITEM_NORMAL_GEM].holdEffect == HOLD_EFFECT_GEMS);
}
SINGLE_BATTLE_TEST("Gem is consumed when it corresponds to the type of a move")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMAL_GEM); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_EMBER); }
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Fire Gem strengthened Wobbuffet's power!");
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Normal Gem strengthened Wobbuffet's power!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
}
}
SINGLE_BATTLE_TEST("Gem boost is only applied once")
{
s16 boostedHit;
s16 normalHit;
GIVEN {
ASSUME(I_GEM_BOOST_POWER >= GEN_5);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMAL_GEM); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Normal Gem strengthened Wobbuffet's power!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
HP_BAR(opponent, captureDamage: &boostedHit);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
HP_BAR(opponent, captureDamage: &normalHit);
} THEN {
EXPECT_MUL_EQ(normalHit, Q_4_12(1.3), boostedHit);
}
}
SINGLE_BATTLE_TEST("Gem modifier is used for all hits of Multi Hit Moves")
{
s16 firstHit;
s16 secondHit;
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMAL_GEM); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN {
MOVE(player, MOVE_DOUBLE_HIT);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_HIT, player);
HP_BAR(opponent, captureDamage: &firstHit);
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_HIT, player);
HP_BAR(opponent, captureDamage: &secondHit);
} THEN {
EXPECT_EQ(firstHit, secondHit);
}
}
SINGLE_BATTLE_TEST("Gem is consumed if the move type is changed")
{
GIVEN {
PLAYER(SPECIES_DELCATTY) { Ability(ABILITY_NORMALIZE); Item(ITEM_NORMAL_GEM); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN {
MOVE(player, MOVE_FEINT_ATTACK);
}
} SCENE {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Normal Gem strengthened Delcatty's power!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_FEINT_ATTACK, player);
}
}

View File

@ -0,0 +1,54 @@
#include "global.h"
#include "test_battle.h"
// Please add Utility Umbrella interactions with move, item and ability effects on their respective files.
ASSUMPTIONS
{
ASSUME(gItems[ITEM_UTILITY_UMBRELLA].holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA);
ASSUME(gBattleMoves[MOVE_EMBER].type == TYPE_FIRE);
ASSUME(gBattleMoves[MOVE_WATER_GUN].type == TYPE_WATER);
}
SINGLE_BATTLE_TEST("Utility Umbrella blocks Sun damage modifiers", s16 damage)
{
u16 setupMove, attackingMove, heldItem;
PARAMETRIZE { setupMove = MOVE_SUNNY_DAY; attackingMove = MOVE_EMBER; heldItem = ITEM_UTILITY_UMBRELLA; }
PARAMETRIZE { setupMove = MOVE_SUNNY_DAY; attackingMove = MOVE_EMBER; heldItem = ITEM_NONE; }
PARAMETRIZE { setupMove = MOVE_SUNNY_DAY; attackingMove = MOVE_WATER_GUN; heldItem = ITEM_UTILITY_UMBRELLA; }
PARAMETRIZE { setupMove = MOVE_SUNNY_DAY; attackingMove = MOVE_WATER_GUN; heldItem = ITEM_NONE; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(heldItem); };
} WHEN {
TURN { MOVE(opponent, setupMove); }
TURN { MOVE(player, attackingMove); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, attackingMove, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
EXPECT_MUL_EQ(results[2].damage, Q_4_12(0.5), results[3].damage);
}
}
SINGLE_BATTLE_TEST("Utility Umbrella blocks Rain damage modifiers", s16 damage)
{
u16 setupMove, attackingMove, heldItem;
PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; attackingMove = MOVE_EMBER; heldItem = ITEM_UTILITY_UMBRELLA; }
PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; attackingMove = MOVE_EMBER; heldItem = ITEM_NONE; }
PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; attackingMove = MOVE_WATER_GUN; heldItem = ITEM_UTILITY_UMBRELLA; }
PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; attackingMove = MOVE_WATER_GUN; heldItem = ITEM_NONE; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(heldItem); };
} WHEN {
TURN { MOVE(opponent, setupMove); }
TURN { MOVE(player, attackingMove); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, attackingMove, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage);
EXPECT_MUL_EQ(results[2].damage, Q_4_12(1.5), results[3].damage);
}
}

View File

@ -0,0 +1,50 @@
#include "global.h"
#include "test_battle.h"
ASSUMPTIONS
{
ASSUME(gBattleMoves[MOVE_HYDRO_STEAM].effect == EFFECT_HYDRO_STEAM);
}
SINGLE_BATTLE_TEST("Hydro Steam deals 1.5x damage under both Sunlight and Rain", s16 damage)
{
u16 setupMove;
PARAMETRIZE { setupMove = MOVE_CELEBRATE; }
PARAMETRIZE { setupMove = MOVE_SUNNY_DAY; }
PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, setupMove); }
TURN { MOVE(player, MOVE_HYDRO_STEAM); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYDRO_STEAM, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[2].damage);
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
}
}
SINGLE_BATTLE_TEST("Hydro Steam is affected by Utility Umbrella", s16 damage)
{
u32 itemPlayer;
u32 itemOpponent;
PARAMETRIZE { itemPlayer = ITEM_UTILITY_UMBRELLA; itemOpponent = ITEM_NONE; }
PARAMETRIZE { itemPlayer = ITEM_NONE; itemOpponent = ITEM_UTILITY_UMBRELLA; }
PARAMETRIZE { itemPlayer = ITEM_UTILITY_UMBRELLA; itemOpponent = ITEM_UTILITY_UMBRELLA; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(itemPlayer); };
OPPONENT(SPECIES_WOBBUFFET) {Item(itemOpponent); };
} WHEN {
TURN { MOVE(player, MOVE_SUNNY_DAY); }
TURN { MOVE(player, MOVE_HYDRO_STEAM); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYDRO_STEAM, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[2].damage, Q_4_12(1.5), results[1].damage);
EXPECT_MUL_EQ(results[2].damage, Q_4_12(0.5), results[0].damage);
}
}

216
test/primal_reversion.c Normal file
View File

@ -0,0 +1,216 @@
#include "global.h"
#include "test_battle.h"
SINGLE_BATTLE_TEST("Primal reversion happens for Groudon only when holding Red Orb")
{
u16 heldItem;
PARAMETRIZE { heldItem = ITEM_NONE;}
PARAMETRIZE { heldItem = ITEM_RED_ORB;}
PARAMETRIZE { heldItem = ITEM_BLUE_ORB;}
GIVEN {
PLAYER(SPECIES_GROUDON) { Item(heldItem); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_CELEBRATE); }
} SCENE {
if (heldItem == ITEM_RED_ORB) {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player);
MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!");
}
else {
NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player);
MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!");
}
}
} THEN {
if (heldItem == ITEM_RED_ORB) {
EXPECT_EQ(player->species, SPECIES_GROUDON_PRIMAL);
}
else {
EXPECT_EQ(player->species, SPECIES_GROUDON);
}
}
}
SINGLE_BATTLE_TEST("Primal reversion happens for Kyogre only when holding Blue Orb")
{
u16 heldItem;
PARAMETRIZE { heldItem = ITEM_NONE;}
PARAMETRIZE { heldItem = ITEM_RED_ORB;}
PARAMETRIZE { heldItem = ITEM_BLUE_ORB;}
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_KYOGRE) { Item(heldItem); }
} WHEN {
TURN { MOVE(opponent, MOVE_CELEBRATE); }
} SCENE {
if (heldItem == ITEM_BLUE_ORB) {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, opponent);
MESSAGE("Foe Kyogre's Primal Reversion! It reverted to its primal form!");
}
else {
NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, opponent);
MESSAGE("Foe Kyogre's Primal Reversion! It reverted to its primal form!");
}
}
} THEN {
if (heldItem == ITEM_BLUE_ORB) {
EXPECT_EQ(opponent->species, SPECIES_KYOGRE_PRIMAL);
}
else {
EXPECT_EQ(opponent->species, SPECIES_KYOGRE);
}
}
}
DOUBLE_BATTLE_TEST("Primal reversion's order is determined by Speed - opponent faster")
{
GIVEN {
PLAYER(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); Speed(5); };
PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); Speed(15); };
OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); Speed(10); }
OPPONENT(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); Speed(20); }
} WHEN {
TURN { MOVE(opponentLeft, MOVE_CELEBRATE); }
} SCENE {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, opponentRight);
MESSAGE("Foe Kyogre's Primal Reversion! It reverted to its primal form!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, playerRight);
MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, opponentLeft);
MESSAGE("Foe Groudon's Primal Reversion! It reverted to its primal form!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, playerLeft);
MESSAGE("Kyogre's Primal Reversion! It reverted to its primal form!");
} THEN {
EXPECT_EQ(playerLeft->species, SPECIES_KYOGRE_PRIMAL);
EXPECT_EQ(opponentLeft->species, SPECIES_GROUDON_PRIMAL);
EXPECT_EQ(opponentRight->species, SPECIES_KYOGRE_PRIMAL);
EXPECT_EQ(playerRight->species, SPECIES_GROUDON_PRIMAL);
}
}
DOUBLE_BATTLE_TEST("Primal reversion's order is determined by Speed - player faster")
{
GIVEN {
PLAYER(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); Speed(20); };
PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); Speed(30); };
OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); Speed(10); }
OPPONENT(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); Speed(2); }
} WHEN {
TURN { MOVE(opponentLeft, MOVE_CELEBRATE); }
} SCENE {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, playerRight);
MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, playerLeft);
MESSAGE("Kyogre's Primal Reversion! It reverted to its primal form!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, opponentLeft);
MESSAGE("Foe Groudon's Primal Reversion! It reverted to its primal form!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, opponentRight);
MESSAGE("Foe Kyogre's Primal Reversion! It reverted to its primal form!");
} THEN {
EXPECT_EQ(playerLeft->species, SPECIES_KYOGRE_PRIMAL);
EXPECT_EQ(opponentLeft->species, SPECIES_GROUDON_PRIMAL);
EXPECT_EQ(opponentRight->species, SPECIES_KYOGRE_PRIMAL);
EXPECT_EQ(playerRight->species, SPECIES_GROUDON_PRIMAL);
}
}
SINGLE_BATTLE_TEST("Primal reversion happens after a mon is sent out after a mon is fainted")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_TACKLE].power != 0);
PLAYER(SPECIES_WOBBUFFET) {HP(1); }
PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); }
TURN { MOVE(opponent, MOVE_TACKLE); }
} SCENE {
MESSAGE("Wobbuffet fainted!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player);
MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!");
} THEN {
EXPECT_EQ(player->species, SPECIES_GROUDON_PRIMAL);
}
}
SINGLE_BATTLE_TEST("Primal reversion happens after a mon is switched in")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { SWITCH(player, 1); MOVE(opponent, MOVE_CELEBRATE); }
TURN { MOVE(opponent, MOVE_CELEBRATE); }
} SCENE {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player);
MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!");
} THEN {
EXPECT_EQ(player->species, SPECIES_GROUDON_PRIMAL);
}
}
SINGLE_BATTLE_TEST("Primal reversion happens after a switch-in caused by Eject Button")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_TACKLE].power != 0);
ASSUME(gItems[ITEM_EJECT_BUTTON].holdEffect == HOLD_EFFECT_EJECT_BUTTON);
PLAYER(SPECIES_WOBBUFFET) {Item(ITEM_EJECT_BUTTON); }
PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); }
TURN { MOVE(opponent, MOVE_TACKLE); }
} SCENE {
MESSAGE("Wobbuffet is switched out with the Eject Button!");
MESSAGE("Go! Groudon!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player);
MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!");
} THEN {
EXPECT_EQ(player->species, SPECIES_GROUDON_PRIMAL);
}
}
SINGLE_BATTLE_TEST("Primal reversion happens after a switch-in caused by Red Card")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_TACKLE].power != 0);
ASSUME(gItems[ITEM_RED_CARD].holdEffect == HOLD_EFFECT_RED_CARD);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); }
OPPONENT(SPECIES_WOBBUFFET) {Item(ITEM_RED_CARD); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
MESSAGE("Foe Wobbuffet held up its Red Card against Wobbuffet!");
MESSAGE("Groudon was dragged out!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player);
MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!");
} THEN {
EXPECT_EQ(player->species, SPECIES_GROUDON_PRIMAL);
}
}
SINGLE_BATTLE_TEST("Primal reversion happens after the entry hazards damage")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_SPIKES].effect == EFFECT_SPIKES);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_SPIKES); }
TURN { MOVE(opponent, MOVE_SPIKES); SWITCH(player, 1);}
} SCENE {
MESSAGE("Go! Groudon!");
HP_BAR(player);
MESSAGE("Groudon is hurt by spikes!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player);
MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!");
} THEN {
EXPECT_EQ(player->species, SPECIES_GROUDON_PRIMAL);
}
}

47
test/weather_rain.c Normal file
View File

@ -0,0 +1,47 @@
#include "global.h"
#include "test_battle.h"
// Please add Rain interactions with move, item and ability effects on their respective files.
ASSUMPTIONS
{
ASSUME(gBattleMoves[MOVE_EMBER].type == TYPE_FIRE);
ASSUME(gBattleMoves[MOVE_WATER_GUN].type == TYPE_WATER);
}
SINGLE_BATTLE_TEST("Rain multiplies the power of Fire-type moves by 0.5x", s16 damage)
{
u32 setupMove;
PARAMETRIZE { setupMove = MOVE_CELEBRATE; }
PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, setupMove); }
TURN { MOVE(player, MOVE_EMBER); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage);
}
}
SINGLE_BATTLE_TEST("Rain multiplies the power of Water-type moves by 1.5x", s16 damage)
{
u32 setupMove;
PARAMETRIZE { setupMove = MOVE_CELEBRATE; }
PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, setupMove); }
TURN { MOVE(player, MOVE_WATER_GUN); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
}
}

47
test/weather_sunlight.c Normal file
View File

@ -0,0 +1,47 @@
#include "global.h"
#include "test_battle.h"
// Please add Sunlight interactions with move, item and ability effects on their respective files.
ASSUMPTIONS
{
ASSUME(gBattleMoves[MOVE_EMBER].type == TYPE_FIRE);
ASSUME(gBattleMoves[MOVE_WATER_GUN].type == TYPE_WATER);
}
SINGLE_BATTLE_TEST("Sunlight multiplies the power of Fire-type moves by 1.5x", s16 damage)
{
u32 setupMove;
PARAMETRIZE { setupMove = MOVE_CELEBRATE; }
PARAMETRIZE { setupMove = MOVE_SUNNY_DAY; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, setupMove); }
TURN { MOVE(player, MOVE_EMBER); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
}
}
SINGLE_BATTLE_TEST("Sunlight multiplies the power of Water-type moves by 0.5x", s16 damage)
{
u32 setupMove;
PARAMETRIZE { setupMove = MOVE_CELEBRATE; }
PARAMETRIZE { setupMove = MOVE_SUNNY_DAY; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, setupMove); }
TURN { MOVE(player, MOVE_WATER_GUN); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage);
}
}