From d58e6517f85eb5717649acfc2739890571b522c6 Mon Sep 17 00:00:00 2001 From: kittenchilly Date: Sat, 27 Apr 2024 12:52:31 -0500 Subject: [PATCH] Add abilities Tera Shift, Tera Shell, and Teraform Zero (#4418) * Add abilities Tera Shift, Tera Shell, and Teraform Zero * Address reviews * Tests and misc cleanup * Fix alignments * Update battle_script_commands.c * New tests and fix behavior * Address more reviews * Update battle_util.c --- asm/macros/battle_script.inc | 4 ++ data/battle_scripts_1.s | 49 +++++++++++++ include/battle.h | 1 + include/battle_script_commands.h | 1 + include/battle_scripts.h | 5 ++ include/constants/battle.h | 2 +- include/constants/battle_string_ids.h | 13 +++- include/constants/form_change_types.h | 2 +- src/battle_message.c | 13 ++++ src/battle_script_commands.c | 55 ++++++++++++++- src/battle_util.c | 30 +++++++- src/data/pokemon/form_change_tables.h | 2 +- test/battle/ability/gastro_acid.c | 2 +- test/battle/ability/tera_shell.c | 99 +++++++++++++++++++++++++++ test/battle/ability/tera_shift.c | 35 ++++++++++ test/battle/ability/zero_to_hero.c | 2 +- 16 files changed, 307 insertions(+), 8 deletions(-) create mode 100644 test/battle/ability/tera_shell.c create mode 100644 test/battle/ability/tera_shift.c diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 4edc76841c..34f29950bd 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1638,6 +1638,10 @@ .4byte \failInstr .endm + .macro removeweather + callnative BS_RemoveWeather + .endm + @ various command changed to more readable macros .macro cancelmultiturnmoves battler:req various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index c5023db393..24ce3405eb 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -7078,6 +7078,29 @@ BattleScript_AttackerFormChangeEnd3NoPopup:: call BattleScript_AttackerFormChangeNoPopup end3 +BattleScript_AttackerFormChangeWithString:: + pause 5 + copybyte gBattlerAbility, gBattlerAttacker + call BattleScript_AbilityPopUp + flushtextbox +BattleScript_AttackerFormChangeWithStringNoPopup:: + handleformchange BS_ATTACKER, 0 + handleformchange BS_ATTACKER, 1 + playanimation BS_ATTACKER, B_ANIM_FORM_CHANGE + waitanimation + handleformchange BS_ATTACKER, 2 + printstring STRINGID_PKMNTRANSFORMED + waitmessage B_WAIT_TIME_LONG + return + +BattleScript_AttackerFormChangeWithStringEnd3:: + call BattleScript_AttackerFormChangeWithString + end3 + +BattleScript_AttackerFormChangeWithStringEnd3NoPopup:: + call BattleScript_AttackerFormChangeWithStringNoPopup + end3 + BattleScript_AttackerFormChangeMoveEffect:: waitmessage 1 handleformchange BS_ATTACKER, 0 @@ -8356,6 +8379,13 @@ BattleScript_ProteanActivates:: waitmessage B_WAIT_TIME_LONG return +BattleScript_TeraShellDistortingTypeMatchups:: + pause B_WAIT_TIME_SHORTEST + call BattleScript_AbilityPopUp + printstring STRINGID_PKMNMADESHELLGLEAM + waitmessage B_WAIT_TIME_LONG + return + BattleScript_CursedBodyActivates:: call BattleScript_AbilityPopUp printstring STRINGID_CUSEDBODYDISABLED @@ -9261,6 +9291,25 @@ BattleScript_AnnounceAirLockCloudNine:: call BattleScript_ActivateWeatherAbilities end3 +BattleScript_ActivateTeraformZero:: + call BattleScript_AbilityPopUp + waitmessage B_WAIT_TIME_LONG + jumpifhalfword CMP_COMMON_BITS, gBattleWeather, B_WEATHER_ANY, BattleScript_ActivateTeraformZero_RemoveWeather + jumpifhalfword CMP_COMMON_BITS, gFieldStatuses, STATUS_FIELD_TERRAIN_ANY, BattleScript_ActivateTeraformZero_RemoveTerrain + goto BattleScript_ActivateTeraformZero_End +BattleScript_ActivateTeraformZero_RemoveWeather: + removeweather + printfromtable gWeatherEndsStringIds + waitmessage B_WAIT_TIME_LONG + jumpifhalfword CMP_NO_COMMON_BITS, gFieldStatuses, STATUS_FIELD_TERRAIN_ANY, BattleScript_ActivateTeraformZero_End +BattleScript_ActivateTeraformZero_RemoveTerrain: + removeterrain + playanimation BS_ATTACKER, B_ANIM_RESTORE_BG + printfromtable gTerrainStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_ActivateTeraformZero_End: + end3 + BattleScript_QuickClawActivation:: flushtextbox playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT diff --git a/include/battle.h b/include/battle.h index c5d08bb584..cdcb1b1742 100644 --- a/include/battle.h +++ b/include/battle.h @@ -816,6 +816,7 @@ struct BattleStruct u8 quickClawRandom[MAX_BATTLERS_COUNT]; u8 quickDrawRandom[MAX_BATTLERS_COUNT]; u8 boosterEnergyActivates; + u8 distortedTypeMatchups; }; // The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider, diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 540390bb53..fcf69e53dc 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -52,6 +52,7 @@ void StealTargetItem(u8 battlerStealer, u8 battlerItem); u8 GetCatchingBattler(void); u32 GetHighestStatId(u32 battlerId); bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType); +bool32 ShouldTeraShellDistortTypeMatchups(u32 move, u32 battlerDef); bool32 IsMoveNotAllowedInSkyBattles(u32 move); bool32 DoSwitchInAbilities(u32 battlerId); u8 GetFirstFaintedPartyIndex(u8 battlerId); diff --git a/include/battle_scripts.h b/include/battle_scripts.h index e4e9ca4307..7ab27aa117 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -364,6 +364,8 @@ extern const u8 BattleScript_DancerActivates[]; extern const u8 BattleScript_AftermathDmg[]; extern const u8 BattleScript_AttackerFormChange[]; extern const u8 BattleScript_AttackerFormChangeEnd3[]; +extern const u8 BattleScript_AttackerFormChangeWithString[]; +extern const u8 BattleScript_AttackerFormChangeWithStringEnd3[]; extern const u8 BattleScript_TargetFormChange[]; extern const u8 BattleScript_AnticipationActivates[]; extern const u8 BattleScript_SlowStartEnds[]; @@ -382,6 +384,7 @@ extern const u8 BattleScript_CheekPouchActivates[]; extern const u8 BattleScript_TotemVar[]; extern const u8 BattleScript_TotemFlaredToLife[]; extern const u8 BattleScript_AnnounceAirLockCloudNine[]; +extern const u8 BattleScript_ActivateTeraformZero[]; extern const u8 BattleScript_BattlerAbilityStatRaiseOnSwitchIn[]; extern const u8 BattleScript_CottonDownActivates[]; extern const u8 BattleScript_BallFetch[]; @@ -436,6 +439,7 @@ extern const u8 BattleScript_PastelVeilActivates[]; extern const u8 BattleScript_MimicryActivatesEnd3[]; extern const u8 BattleScript_ApplyMimicry[]; extern const u8 BattleScript_AttackerFormChangeEnd3NoPopup[]; +extern const u8 BattleScript_AttackerFormChangeWithStringEnd3NoPopup[]; extern const u8 BattleScript_AttackerFormChangeMoveEffect[]; extern const u8 BattleScript_BothCanNoLongerEscape[]; extern const u8 BattleScript_OctolockEndTurn[]; @@ -502,6 +506,7 @@ extern const u8 BattleScript_AromaVeilProtectsRet[]; extern const u8 BattleScript_LowerAtkSpAtk[]; extern const u8 BattleScript_Terastallization[]; extern const u8 BattleScript_BoosterEnergyEnd2[]; +extern const u8 BattleScript_TeraShellDistortingTypeMatchups[]; // zmoves extern const u8 BattleScript_ZMoveActivateDamaging[]; diff --git a/include/constants/battle.h b/include/constants/battle.h index 30f304144f..4ca7eabdca 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -299,7 +299,7 @@ #define B_WEATHER_HAIL_PERMANENT (1 << 10) #define B_WEATHER_HAIL (B_WEATHER_HAIL_TEMPORARY | B_WEATHER_HAIL_PERMANENT) #define B_WEATHER_STRONG_WINDS (1 << 11) -#define B_WEATHER_ANY (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_SUN | B_WEATHER_HAIL | B_WEATHER_STRONG_WINDS | B_WEATHER_SNOW) +#define B_WEATHER_ANY (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_SUN | B_WEATHER_HAIL | B_WEATHER_STRONG_WINDS | B_WEATHER_SNOW | B_WEATHER_FOG) #define B_WEATHER_PRIMAL_ANY (B_WEATHER_RAIN_PRIMAL | B_WEATHER_SUN_PRIMAL | B_WEATHER_STRONG_WINDS) #define B_WEATHER_SNOW_TEMPORARY (1 << 12) #define B_WEATHER_SNOW_PERMANENT (1 << 13) diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index dfb5c5e2d4..4167522f18 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -712,8 +712,9 @@ #define STRINGID_FOGCREPTUP 710 #define STRINGID_FOGISDEEP 711 #define STRINGID_FOGLIFTED 712 +#define STRINGID_PKMNMADESHELLGLEAM 713 -#define BATTLESTRINGS_COUNT 713 +#define BATTLESTRINGS_COUNT 714 // This is the string id that gBattleStringsTable starts with. // String ids before this (e.g. STRINGID_INTROMSG) are not in the table, @@ -767,6 +768,16 @@ #define B_MSG_STARTED_SNOW 6 #define B_MSG_STARTED_FOG 7 +// gWeatherEndsStringIds +#define B_MSG_WEATHER_END_RAIN 0 +#define B_MSG_WEATHER_END_SANDSTORM 1 +#define B_MSG_WEATHER_END_SUN 2 +#define B_MSG_WEATHER_END_HAIL 3 +#define B_MSG_WEATHER_END_STRONG_WINDS 4 +#define B_MSG_WEATHER_END_SNOW 5 +#define B_MSG_WEATHER_END_FOG 6 +#define B_MSG_WEATHER_END_COUNT 7 + // gRainContinuesStringIds #define B_MSG_RAIN_CONTINUES 0 #define B_MSG_DOWNPOUR_CONTINUES 1 diff --git a/include/constants/form_change_types.h b/include/constants/form_change_types.h index 51325baf25..d23dc0d2bd 100644 --- a/include/constants/form_change_types.h +++ b/include/constants/form_change_types.h @@ -61,7 +61,7 @@ #define FORM_CHANGE_END_BATTLE_TERRAIN 8 // Form change that activates when the Pokémon is switched out in battle. -// - No parameters. +// param1: ability to check, optional #define FORM_CHANGE_BATTLE_SWITCH 9 // Form change that activates when the Pokémon's HP % passes a certain threshold. diff --git a/src/battle_message.c b/src/battle_message.c index b713d846ad..d630520953 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -724,6 +724,7 @@ static const u8 sText_ASandstormKickedUp[] = _("A sandstorm kicked up!"); static const u8 sText_PkmnsWillPerishIn3Turns[] = _("Both Pokémon will perish\nin three turns!"); static const u8 sText_AbilityRaisedStatDrastically[] = _("{B_DEF_ABILITY} raised {B_DEF_NAME_WITH_PREFIX}'s\n{B_BUFF1} drastically!"); static const u8 sText_AsOneEnters[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} has two Abilities!"); +static const u8 sText_PkmnMadeShellGleam[] = _("{B_DEF_NAME_WITH_PREFIX} made its shell gleam!\nIt's distorting type matchups!"); static const u8 sText_CuriousMedicineEnters[] = _("{B_EFF_NAME_WITH_PREFIX}'s\nstat changes were reset!"); static const u8 sText_CanActFaster[] = _("{B_ATK_NAME_WITH_PREFIX} can act faster,\nthanks to {B_BUFF1}!"); static const u8 sText_MicleBerryActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} boosted the accuracy of its\nnext move using {B_LAST_ITEM}!"); @@ -964,6 +965,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_CANACTFASTERTHANKSTO - BATTLESTRINGS_TABLE_START] = sText_CanActFaster, [STRINGID_CURIOUSMEDICINEENTERS - BATTLESTRINGS_TABLE_START] = sText_CuriousMedicineEnters, [STRINGID_ASONEENTERS - BATTLESTRINGS_TABLE_START] = sText_AsOneEnters, + [STRINGID_PKMNMADESHELLGLEAM - BATTLESTRINGS_TABLE_START] = sText_PkmnMadeShellGleam, [STRINGID_ABILITYRAISEDSTATDRASTICALLY - BATTLESTRINGS_TABLE_START] = sText_AbilityRaisedStatDrastically, [STRINGID_PKMNSWILLPERISHIN3TURNS - BATTLESTRINGS_TABLE_START] = sText_PkmnsWillPerishIn3Turns, [STRINGID_ASANDSTORMKICKEDUP - BATTLESTRINGS_TABLE_START] = sText_ASandstormKickedUp, @@ -1684,6 +1686,17 @@ const u16 gMoveWeatherChangeStringIds[] = [B_MSG_STARTED_FOG] = STRINGID_FOGCREPTUP, // Unused, can use for custom moves that set fog }; +const u16 gWeatherEndsStringIds[B_MSG_WEATHER_END_COUNT] = +{ + [B_MSG_WEATHER_END_RAIN] = STRINGID_RAINSTOPPED, + [B_MSG_WEATHER_END_SANDSTORM] = STRINGID_SANDSTORMSUBSIDED, + [B_MSG_WEATHER_END_SUN] = STRINGID_SUNLIGHTFADED, + [B_MSG_WEATHER_END_HAIL] = STRINGID_HAILSTOPPED, + [B_MSG_WEATHER_END_STRONG_WINDS] = STRINGID_STRONGWINDSDISSIPATED, + [B_MSG_WEATHER_END_SNOW] = STRINGID_SNOWSTOPPED, + [B_MSG_WEATHER_END_FOG] = STRINGID_FOGLIFTED, +}; + const u16 gSandStormHailSnowContinuesStringIds[] = { [B_MSG_SANDSTORM] = STRINGID_SANDSTORMRAGES, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index bfbb2b3ca0..405deafaf3 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -330,6 +330,7 @@ static bool8 IsFinalStrikeEffect(u16 move); static void TryUpdateRoundTurnOrder(void); static bool32 ChangeOrderTargetAfterAttacker(void); void ApplyExperienceMultipliers(s32 *expAmount, u8 expGetterMonId, u8 faintedBattler); +static void RemoveAllWeather(void); static void RemoveAllTerrains(void); static bool8 CanAbilityPreventStatLoss(u16 abilityDef, bool8 isIntimidate); static bool8 CanBurnHitThaw(u16 move); @@ -1233,6 +1234,19 @@ bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType) return FALSE; } +bool32 ShouldTeraShellDistortTypeMatchups(u32 move, u32 battlerDef) +{ + if (!(gBattleStruct->distortedTypeMatchups & gBitTable[battlerDef]) + && GetBattlerAbility(battlerDef) == ABILITY_TERA_SHELL + && gBattleMons[battlerDef].species == SPECIES_TERAPAGOS_TERASTAL + && !IS_MOVE_STATUS(move) + && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattleMons[battlerDef].hp == gBattleMons[battlerDef].maxHP) + return TRUE; + + return FALSE; +} + bool32 IsMoveNotAllowedInSkyBattles(u32 move) { return ((gBattleStruct->isSkyBattle) && (gMovesInfo[gCurrentMove].skyBattleBanned)); @@ -1859,6 +1873,14 @@ static void Cmd_ppreduce(void) gHitMarker &= ~HITMARKER_NO_PPDEDUCT; gBattlescriptCurrInstr = cmd->nextInstr; + + if (ShouldTeraShellDistortTypeMatchups(gCurrentMove, gBattlerTarget)) + { + gBattleStruct->distortedTypeMatchups |= gBitTable[gBattlerTarget]; + gBattlerAbility = gBattlerTarget; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_TeraShellDistortingTypeMatchups; + } } // The chance is 1/N for each stage. @@ -6326,6 +6348,7 @@ static void Cmd_moveend(void) gBattleStruct->enduredDamage = 0; gBattleStruct->additionalEffectsCounter = 0; gBattleStruct->poisonPuppeteerConfusion = FALSE; + gBattleStruct->distortedTypeMatchups = 0; gBattleScripting.moveendState++; break; case MOVEEND_COUNT: @@ -8397,6 +8420,30 @@ bool32 CanUseLastResort(u8 battler) return (knownMovesCount >= 2 && usedMovesCount >= knownMovesCount - 1); } +static void RemoveAllWeather(void) +{ + gWishFutureKnock.weatherDuration = 0; + + if (gBattleWeather & B_WEATHER_RAIN) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_RAIN; + else if(gBattleWeather & B_WEATHER_SANDSTORM) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_SANDSTORM; + else if(gBattleWeather & B_WEATHER_SUN) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_SUN; + else if(gBattleWeather & B_WEATHER_HAIL) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_HAIL; + else if(gBattleWeather & B_WEATHER_STRONG_WINDS) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_STRONG_WINDS; + else if(gBattleWeather & B_WEATHER_SNOW) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_SNOW; + else if(gBattleWeather & B_WEATHER_FOG) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_FOG; + else + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_COUNT; // failsafe + + gBattleWeather = 0; // remove the weather +} + static void RemoveAllTerrains(void) { gFieldTimers.terrainTimer = 0; @@ -16825,7 +16872,6 @@ void BS_TryGulpMissile(void) gBattlescriptCurrInstr = cmd->nextInstr; } - void BS_TryQuash(void) { NATIVE_ARGS(const u8 *failInstr); @@ -16857,3 +16903,10 @@ void BS_TryQuash(void) } gBattlescriptCurrInstr = cmd->nextInstr; } + +void BS_RemoveWeather(void) +{ + NATIVE_ARGS(); + RemoveAllWeather(); + gBattlescriptCurrInstr = cmd->nextInstr; +} diff --git a/src/battle_util.c b/src/battle_util.c index 6d6ce38a7c..6a3f43f9d7 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4619,6 +4619,14 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 effect++; } break; + case ABILITY_TERAFORM_ZERO: + if (!gSpecialStatuses[battler].switchInAbilityDone + && gBattleMons[battler].species == SPECIES_TERAPAGOS_STELLAR) + { + gSpecialStatuses[battler].switchInAbilityDone = TRUE; + BattleScriptPushCursorAndCallback(BattleScript_ActivateTeraformZero); + effect++; + } case ABILITY_SCHOOLING: if (gBattleMons[battler].level < 20) break; @@ -4805,6 +4813,18 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 effect++; } break; + case ABILITY_TERA_SHIFT: + if (!gSpecialStatuses[battler].switchInAbilityDone + && gBattleMons[battler].species == SPECIES_TERAPAGOS_NORMAL + && TryBattleFormChange(battler, FORM_CHANGE_BATTLE_SWITCH)) + { + gBattlerAttacker = battler; + gBattleScripting.abilityPopupOverwrite = gLastUsedAbility = ABILITY_TERA_SHIFT; + gSpecialStatuses[battler].switchInAbilityDone = TRUE; + BattleScriptPushCursorAndCallback(BattleScript_AttackerFormChangeWithStringEnd3); + effect++; + } + break; } break; case ABILITYEFFECT_ENDTURN: // 1 @@ -10110,6 +10130,13 @@ static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 move mod = UQ_4_12(1.0); } + if (gBattleStruct->distortedTypeMatchups & gBitTable[battlerDef]) + { + mod = UQ_4_12(0.5); + if (recordAbilities) + RecordAbilityBattle(battlerDef, GetBattlerAbility(battlerDef)); + } + *modifier = uq4_12_multiply(*modifier, mod); } @@ -10537,7 +10564,8 @@ u16 GetBattleFormChangeTargetSpecies(u32 battler, u16 method) targetSpecies = formChanges[i].targetSpecies; break; case FORM_CHANGE_BATTLE_SWITCH: - targetSpecies = formChanges[i].targetSpecies; + if (formChanges[i].param1 == GetBattlerAbility(battler) || formChanges[i].param1 == ABILITY_NONE) + targetSpecies = formChanges[i].targetSpecies; break; case FORM_CHANGE_BATTLE_HP_PERCENT: if (formChanges[i].param1 == GetBattlerAbility(battler)) diff --git a/src/data/pokemon/form_change_tables.h b/src/data/pokemon/form_change_tables.h index 5edd6f42b5..f8edc496de 100644 --- a/src/data/pokemon/form_change_tables.h +++ b/src/data/pokemon/form_change_tables.h @@ -1268,7 +1268,7 @@ static const struct FormChange sOgerponFormChangeTable[] = { #if P_FAMILY_TERAPAGOS static const struct FormChange sTerapagosFormChangeTable[] = { - {FORM_CHANGE_BEGIN_BATTLE, SPECIES_TERAPAGOS_TERASTAL}, //needs to be tied to the ability + {FORM_CHANGE_BATTLE_SWITCH, SPECIES_TERAPAGOS_TERASTAL, ABILITY_TERA_SHIFT}, #if P_TERA_FORMS //{FORM_CHANGE_TERASTALLIZATION, SPECIES_TERAPAGOS_STELLAR}, #endif diff --git a/test/battle/ability/gastro_acid.c b/test/battle/ability/gastro_acid.c index a9fba14f89..2f5b04dab9 100644 --- a/test/battle/ability/gastro_acid.c +++ b/test/battle/ability/gastro_acid.c @@ -23,7 +23,7 @@ SINGLE_BATTLE_TEST("Gastro Acid fails if target has a banned ability") PARAMETRIZE { species = SPECIES_CRAMORANT; ability = ABILITY_GULP_MISSILE; } PARAMETRIZE { species = SPECIES_PALAFIN_ZERO; ability = ABILITY_ZERO_TO_HERO; } PARAMETRIZE { species = SPECIES_TATSUGIRI; ability = ABILITY_COMMANDER; } - // Needs confirmation since those abilities can be surpressed by Neutralizing Gas + // Needs confirmation since those abilities can be suppressed by Neutralizing Gas // PARAMETRIZE { species = SPECIES_IRON_MOTH; ability = ABILITY_QUARK_DRIVE; } // PARAMETRIZE { species = SPECIES_WALKING_WAKE; ability = ABILITY_PROTOSYNTHESIS; } PARAMETRIZE { species = SPECIES_CALYREX_SHADOW_RIDER; ability = ABILITY_AS_ONE_SHADOW_RIDER; } diff --git a/test/battle/ability/tera_shell.c b/test/battle/ability/tera_shell.c new file mode 100644 index 0000000000..138a56f9b4 --- /dev/null +++ b/test/battle/ability/tera_shell.c @@ -0,0 +1,99 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Tera Shell makes all moves against Terapagos not very effective when at full HP") +{ + u16 hp; + PARAMETRIZE { hp = 100; } + PARAMETRIZE { hp = 99; } + GIVEN { + PLAYER(SPECIES_TERAPAGOS_TERASTAL) { Ability(ABILITY_TERA_SHELL); HP(hp); MaxHP(100);} + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + if (hp == 100) { + MESSAGE("Foe Wobbuffet used Tackle!"); + ABILITY_POPUP(player, ABILITY_TERA_SHELL); + MESSAGE("Terapagos made its shell gleam! It's distorting type matchups!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player); + MESSAGE("It's not very effective…"); + } + else { + NONE_OF { + ABILITY_POPUP(player, ABILITY_TERA_SHELL); + MESSAGE("Terapagos made its shell gleam! It's distorting type matchups!"); + MESSAGE("It's not very effective…"); + } + } + } +} + +SINGLE_BATTLE_TEST("Tera Shell makes all hits of multi-hit moves against Terapagos not very effective") +{ + s16 firstHit; + s16 secondHit; + GIVEN { + PLAYER(SPECIES_TERAPAGOS_TERASTAL) { Ability(ABILITY_TERA_SHELL); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_DOUBLE_HIT); } + } SCENE { + MESSAGE("Foe Wobbuffet used Double Hit!"); + ABILITY_POPUP(player, ABILITY_TERA_SHELL); + MESSAGE("Terapagos made its shell gleam! It's distorting type matchups!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_HIT, opponent); + HP_BAR(player, captureDamage: &firstHit); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_HIT, opponent); + HP_BAR(player, captureDamage: &secondHit); + MESSAGE("It's not very effective…"); + } THEN { + EXPECT_EQ(firstHit, secondHit); + } +} + +DOUBLE_BATTLE_TEST("Tera Shell only makes the first hit of a double battle turn not very effective") +{ + s16 firstHit; + s16 secondHit; + GIVEN { + PLAYER(SPECIES_TERAPAGOS_TERASTAL) { Ability(ABILITY_TERA_SHELL); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_TACKLE, target: playerLeft); MOVE(opponentRight, MOVE_TACKLE, target: playerLeft); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_TERA_SHELL); + MESSAGE("Terapagos made its shell gleam! It's distorting type matchups!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentLeft); + HP_BAR(playerLeft, captureDamage: &firstHit); + MESSAGE("It's not very effective…"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentRight); + HP_BAR(playerLeft, captureDamage: &secondHit); + NOT MESSAGE("It's not very effective…"); + } THEN { + EXPECT_MUL_EQ(firstHit, Q_4_12(2.0), secondHit); + } +} + +DOUBLE_BATTLE_TEST("Tera Shell only makes the first hit against Terapagos from a multi-target move not very effective") +{ + GIVEN { + PLAYER(SPECIES_TERAPAGOS_TERASTAL) { Ability(ABILITY_TERA_SHELL); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_BLIZZARD); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_TERA_SHELL); + MESSAGE("Terapagos made its shell gleam! It's distorting type matchups!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BLIZZARD, opponentLeft); + HP_BAR(playerLeft); + MESSAGE("It's not very effective…"); + HP_BAR(playerRight); + NOT MESSAGE("It's not very effective…"); + } +} diff --git a/test/battle/ability/tera_shift.c b/test/battle/ability/tera_shift.c new file mode 100644 index 0000000000..9149160cd1 --- /dev/null +++ b/test/battle/ability/tera_shift.c @@ -0,0 +1,35 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Tera Shift transforms Terapagos into its Terastal form on switch in") +{ + GIVEN { + PLAYER(SPECIES_TERAPAGOS_NORMAL) { Ability(ABILITY_TERA_SHIFT); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { ; } + } SCENE { + ABILITY_POPUP(player, ABILITY_TERA_SHIFT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Terapagos transformed!"); + } THEN { + EXPECT_EQ(player->species, SPECIES_TERAPAGOS_TERASTAL); + } +} + +SINGLE_BATTLE_TEST("Tera Shift can't be suppressed by Neutralizing Gas") +{ + GIVEN { + PLAYER(SPECIES_TERAPAGOS_NORMAL) { Ability(ABILITY_TERA_SHIFT); } + OPPONENT(SPECIES_KOFFING) { Ability(ABILITY_NEUTRALIZING_GAS); } + } WHEN { + TURN { ; } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_NEUTRALIZING_GAS); + ABILITY_POPUP(player, ABILITY_TERA_SHIFT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Terapagos transformed!"); + } THEN { + EXPECT_EQ(player->species, SPECIES_TERAPAGOS_TERASTAL); + } +} diff --git a/test/battle/ability/zero_to_hero.c b/test/battle/ability/zero_to_hero.c index 4a186661a6..4f8cfc8a65 100644 --- a/test/battle/ability/zero_to_hero.c +++ b/test/battle/ability/zero_to_hero.c @@ -20,7 +20,7 @@ SINGLE_BATTLE_TEST("Zero to Hero transforms Palafin when it switches out") } THEN { EXPECT_EQ(player->species, SPECIES_PALAFIN_HERO); } } -SINGLE_BATTLE_TEST("Zero to Hero can't be surpressed by Neutralizing Gas") +SINGLE_BATTLE_TEST("Zero to Hero can't be suppressed by Neutralizing Gas") { GIVEN { PLAYER(SPECIES_PALAFIN_ZERO) { Ability(ABILITY_ZERO_TO_HERO); }