From a5f28afe427f51d6f50c11ee879a271b505f5204 Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Thu, 4 May 2023 17:01:03 -0700 Subject: [PATCH 1/6] fixed Forecast and Flower Gift --- asm/macros/battle_script.inc | 4 + data/battle_scripts_1.s | 35 ++- include/battle_scripts.h | 1 + include/battle_util.h | 1 - include/config/battle.h | 1 + src/battle_script_commands.c | 27 ++- src/battle_util.c | 98 +-------- src/data/pokemon/form_change_table_pointers.h | 2 + test/ability_flower_gift.c | 86 ++++++++ test/ability_forecast.c | 201 ++++++++++++++++++ 10 files changed, 351 insertions(+), 105 deletions(-) create mode 100644 test/ability_flower_gift.c create mode 100644 test/ability_forecast.c diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 78fb91406..dec096e6e 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1346,6 +1346,10 @@ callnative BS_ItemRestorePP .endm + .macro trytorevertweatherform + callnative BS_TryRevertWeatherForm + .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 23a7632bd..26f30ef3f 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1580,6 +1580,7 @@ BattleScript_MoveEffectCoreEnforcer:: printstring STRINGID_PKMNSABILITYSUPPRESSED waitmessage B_WAIT_TIME_LONG trytoclearprimalweather + trytorevertweatherform printstring STRINGID_EMPTYSTRING3 waitmessage 1 BattleScript_CoreEnforcerRet: @@ -2728,6 +2729,7 @@ BattleScript_EffectSimpleBeam: printstring STRINGID_PKMNACQUIREDSIMPLE waitmessage B_WAIT_TIME_LONG trytoclearprimalweather + trytorevertweatherform printstring STRINGID_EMPTYSTRING3 waitmessage 1 tryendneutralizinggas BS_TARGET @@ -2827,6 +2829,7 @@ BattleScript_EffectWorrySeed: printstring STRINGID_PKMNACQUIREDABILITY waitmessage B_WAIT_TIME_LONG trytoclearprimalweather + trytorevertweatherform printstring STRINGID_EMPTYSTRING3 waitmessage 1 goto BattleScript_MoveEnd @@ -2958,6 +2961,7 @@ BattleScript_EffectGastroAcid: printstring STRINGID_PKMNSABILITYSUPPRESSED waitmessage B_WAIT_TIME_LONG trytoclearprimalweather + trytorevertweatherform printstring STRINGID_EMPTYSTRING3 waitmessage 1 tryendneutralizinggas BS_TARGET @@ -6847,6 +6851,7 @@ BattleScript_RainContinuesOrEnds:: jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_RAIN_STOPPED, BattleScript_RainContinuesOrEndsEnd playanimation BS_ATTACKER, B_ANIM_RAIN_CONTINUES BattleScript_RainContinuesOrEndsEnd:: + call BattleScript_ActivateWeatherAbilities end2 BattleScript_DamagingWeatherContinues:: @@ -6880,22 +6885,26 @@ BattleScript_DamagingWeatherLoopIncrement:: jumpifbytenotequal gBattleCommunication, gBattlersCount, BattleScript_DamagingWeatherLoop BattleScript_DamagingWeatherContinuesEnd:: bicword gHitMarker, HITMARKER_SKIP_DMG_TRACK | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE | HITMARKER_GRUDGE + call BattleScript_ActivateWeatherAbilities end2 BattleScript_SandStormHailEnds:: printfromtable gSandStormHailEndStringIds waitmessage B_WAIT_TIME_LONG + call BattleScript_ActivateWeatherAbilities end2 BattleScript_SunlightContinues:: printstring STRINGID_SUNLIGHTSTRONG waitmessage B_WAIT_TIME_LONG playanimation BS_ATTACKER, B_ANIM_SUN_CONTINUES + call BattleScript_ActivateWeatherAbilities end2 BattleScript_SunlightFaded:: printstring STRINGID_SUNLIGHTFADED waitmessage B_WAIT_TIME_LONG + call BattleScript_ActivateWeatherAbilities end2 BattleScript_OverworldWeatherStarts:: @@ -8020,6 +8029,19 @@ BattleScript_TargetFormChangeWithString:: waitmessage B_WAIT_TIME_LONG return +BattleScript_TargetFormChangeWithStringNoPopupEnd3:: + pause 5 + printstring STRINGID_EMPTYSTRING3 + waitmessage 1 + handleformchange BS_TARGET, 0 + handleformchange BS_TARGET, 1 + playanimation BS_TARGET, B_ANIM_FORM_CHANGE, NULL + waitanimation + handleformchange BS_TARGET, 2 + printstring STRINGID_PKMNTRANSFORMED + waitmessage B_WAIT_TIME_LONG + end3 + BattleScript_BattlerFormChangeWithStringEnd3:: pause 5 call BattleScript_AbilityPopUp @@ -8663,14 +8685,15 @@ BattleScript_ShedSkinActivates:: end3 BattleScript_ActivateWeatherAbilities: - copybyte sBATTLER, gBattlerAttacker - setbyte gBattlerAttacker, 0 + savetarget + setbyte gBattlerTarget, 0 BattleScript_ActivateWeatherAbilities_Loop: - activateweatherchangeabilities BS_ATTACKER + copybyte sBATTLER, gBattlerTarget + activateweatherchangeabilities BS_TARGET BattleScript_ActivateWeatherAbilities_Increment: - addbyte gBattlerAttacker, 1 - jumpifbytenotequal gBattlerAttacker, gBattlersCount, BattleScript_ActivateWeatherAbilities_Loop - copybyte gBattlerAttacker, sBATTLER + addbyte gBattlerTarget, 1 + jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_ActivateWeatherAbilities_Loop + restoretarget return BattleScript_TryAdrenalineOrb: diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 8cd8606a5..4a0057275 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -465,6 +465,7 @@ extern const u8 BattleScript_MoveEffectStockpileWoreOff[]; extern const u8 BattleScript_StealthRockActivates[]; extern const u8 BattleScript_SpikesActivates[]; extern const u8 BattleScript_BerserkGeneRet[]; +extern const u8 BattleScript_TargetFormChangeWithStringNoPopupEnd3[]; // zmoves extern const u8 BattleScript_ZMoveActivateDamaging[]; diff --git a/include/battle_util.h b/include/battle_util.h index e28e41aad..0337dacba 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -139,7 +139,6 @@ void TryClearRageAndFuryCutter(void); u8 AtkCanceller_UnableToUseMove(void); u8 AtkCanceller_UnableToUseMove2(void); bool8 HasNoMonsToSwitch(u8 battlerId, u8 r1, u8 r2); -u8 TryWeatherFormChange(u8 battlerId); bool32 TryChangeBattleWeather(u8 battler, u32 weatherEnumId, bool32 viaAbility); u8 AbilityBattleEffects(u8 caseID, u8 battlerId, u16 ability, u8 special, u16 moveArg); bool32 IsNeutralizingGasOnField(void); diff --git a/include/config/battle.h b/include/config/battle.h index 6a6a829d6..73ae9a7a7 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -101,6 +101,7 @@ #define B_STOCKPILE_RAISES_DEFS GEN_LATEST // In Gen4+, Stockpile also raises Defense and Sp. Defense stats. Once Spit Up / Swallow is used, these stat changes are lost. #define B_TRANSFORM_SHINY GEN_LATEST // In Gen4+, Transform will copy the shiny state of the opponent instead of maintaining its own shiny state. #define B_TRANSFORM_FORM_CHANGES GEN_LATEST // In Gen5+, Transformed Pokemon cannot change forms. +#define B_WEATHER_FORM_SUPPRESS GEN_LATEST // In Gen5+, Cherrim and Castform revert to their normal forms upon losing their ability. // Ability settings #define B_EXPANDED_ABILITY_NAMES TRUE // If TRUE, ability names are increased from 12 characters to 16 characters. diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 1784f9682..b21197a67 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -16414,7 +16414,8 @@ u8 GetFirstFaintedPartyIndex(u8 battlerId) return PARTY_SIZE; } -void BS_ItemRestoreHP(void) { +void BS_ItemRestoreHP(void) +{ NATIVE_ARGS(); u16 healAmount; u32 battlerId = MAX_BATTLERS_COUNT; @@ -16476,7 +16477,8 @@ void BS_ItemRestoreHP(void) { gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_ItemCureStatus(void) { +void BS_ItemCureStatus(void) +{ NATIVE_ARGS(); struct Pokemon *party = GetBattlerParty(gBattlerAttacker); @@ -16504,7 +16506,8 @@ void BS_ItemCureStatus(void) { gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_ItemIncreaseStat(void) { +void BS_ItemIncreaseStat(void) +{ NATIVE_ARGS(); u16 statId = GetItemEffect(gLastUsedItem)[1]; u16 stages = ItemId_GetHoldEffectParam(gLastUsedItem); @@ -16512,7 +16515,8 @@ void BS_ItemIncreaseStat(void) { gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_ItemRestorePP(void) { +void BS_ItemRestorePP(void) +{ NATIVE_ARGS(); const u8 *effect = GetItemEffect(gLastUsedItem); u32 i, pp, maxPP, moveId; @@ -16559,3 +16563,18 @@ void BS_ItemRestorePP(void) { PREPARE_SPECIES_BUFFER(gBattleTextBuff1, GetMonData(mon, MON_DATA_SPECIES)); gBattlescriptCurrInstr = cmd->nextInstr; } + +void BS_TryRevertWeatherForm(void) +{ + NATIVE_ARGS(); + u16 ability = gBattleMons[gBattlerTarget].ability; + if (B_WEATHER_FORM_SUPPRESS >= GEN_5 + && (ability == ABILITY_FORECAST || ability == ABILITY_FLOWER_GIFT) + && TryBattleFormChange(gBattlerTarget, FORM_CHANGE_BATTLE_SWITCH)) // revert form + { + gBattleScripting.battler = gBattlerTarget; + BattleScriptPushCursorAndCallback(BattleScript_TargetFormChangeWithStringNoPopupEnd3); + return; + } + gBattlescriptCurrInstr = cmd->nextInstr; +} diff --git a/src/battle_util.c b/src/battle_util.c index 831e65829..67270469e 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -3984,96 +3984,6 @@ bool8 HasNoMonsToSwitch(u8 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2) } } -u8 TryWeatherFormChange(u8 battler) -{ - u8 ret = 0; - bool32 weatherEffect = WEATHER_HAS_EFFECT; - u16 holdEffect = GetBattlerHoldEffect(battler, TRUE); - - switch (gBattleMons[battler].species) - { - case SPECIES_CASTFORM: -/* Placeholder - case SPECIES_CASTFORM_RAINY: - case SPECIES_CASTFORM_SNOWY: - case SPECIES_CASTFORM_SUNNY:*/ -#if B_WEATHER_FORMS >= GEN_5 - if (gBattleMons[battler].hp == 0) - { - ret = 0; // No change - } - else if (GetBattlerAbility(battler) != ABILITY_FORECAST || !weatherEffect) - { - if (!IS_BATTLER_OF_TYPE(battler, TYPE_NORMAL)) - { - SET_BATTLER_TYPE(battler, TYPE_NORMAL); - ret = CASTFORM_NORMAL + 1; - } - else - { - ret = 0; // No change - } - } -#else - if (GetBattlerAbility(battler) != ABILITY_FORECAST || gBattleMons[battler].hp == 0) - { - ret = 0; // No change - } - else if (!weatherEffect) - { - if (!IS_BATTLER_OF_TYPE(battler, TYPE_NORMAL)) - { - SET_BATTLER_TYPE(battler, TYPE_NORMAL); - ret = CASTFORM_NORMAL + 1; - } - else - { - ret = 0; // No change - } - } -#endif - else if (holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA || (!(gBattleWeather & (B_WEATHER_RAIN | B_WEATHER_SUN | B_WEATHER_HAIL)) && !IS_BATTLER_OF_TYPE(battler, TYPE_NORMAL))) - { - SET_BATTLER_TYPE(battler, TYPE_NORMAL); - ret = CASTFORM_NORMAL + 1; - } - else if (gBattleWeather & B_WEATHER_SUN && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA && !IS_BATTLER_OF_TYPE(battler, TYPE_FIRE)) - { - SET_BATTLER_TYPE(battler, TYPE_FIRE); - ret = CASTFORM_FIRE + 1; - } - else if (gBattleWeather & B_WEATHER_RAIN && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA && !IS_BATTLER_OF_TYPE(battler, TYPE_WATER)) - { - SET_BATTLER_TYPE(battler, TYPE_WATER); - ret = CASTFORM_WATER + 1; - } - else if (gBattleWeather & B_WEATHER_HAIL && !IS_BATTLER_OF_TYPE(battler, TYPE_ICE)) - { - SET_BATTLER_TYPE(battler, TYPE_ICE); - ret = CASTFORM_ICE + 1; - } - break; - case SPECIES_CHERRIM: -// case SPECIES_CHERRIM_SUNSHINE: - if (gBattleMons[battler].hp == 0) - ret = 0; // No change -#if B_WEATHER_FORMS >= GEN_5 - if (GetBattlerAbility(battler) != ABILITY_FLOWER_GIFT) - if (gBattleMonForms[battler] != 0) - ret = CHERRIM_OVERCAST + 1; - else - ret = 0; // No change -#endif - else if (gBattleMonForms[battler] == 0 && weatherEffect && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA && gBattleWeather & B_WEATHER_SUN) - ret = CHERRIM_SUNSHINE + 1; - else if (gBattleMonForms[battler] != 0 && (!weatherEffect || holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA || !(gBattleWeather & B_WEATHER_SUN))) - ret = CHERRIM_OVERCAST + 1; - break; - } - - return ret; -} - static const u16 sWeatherFlagsInfo[][3] = { [ENUM_WEATHER_RAIN] = {B_WEATHER_RAIN_TEMPORARY, B_WEATHER_RAIN_PERMANENT, HOLD_EFFECT_DAMP_ROCK}, @@ -9273,7 +9183,7 @@ static u32 CalcAttackStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, b break; #endif case ABILITY_FLOWER_GIFT: - if (gBattleMons[battlerAtk].species == SPECIES_CHERRIM && IsBattlerWeatherAffected(battlerAtk, B_WEATHER_SUN) && IS_MOVE_PHYSICAL(move)) + if (gBattleMons[battlerAtk].species == SPECIES_CHERRIM_SUNSHINE && IsBattlerWeatherAffected(battlerAtk, B_WEATHER_SUN) && IS_MOVE_PHYSICAL(move)) MulModifier(&modifier, UQ_4_12(1.5)); break; case ABILITY_HUSTLE: @@ -9313,7 +9223,7 @@ static u32 CalcAttackStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, b switch (GetBattlerAbility(BATTLE_PARTNER(battlerAtk))) { case ABILITY_FLOWER_GIFT: - if (gBattleMons[BATTLE_PARTNER(battlerAtk)].species == SPECIES_CHERRIM && IsBattlerWeatherAffected(BATTLE_PARTNER(battlerAtk), B_WEATHER_SUN) && IS_MOVE_PHYSICAL(move)) + if (gBattleMons[BATTLE_PARTNER(battlerAtk)].species == SPECIES_CHERRIM_SUNSHINE && IsBattlerWeatherAffected(BATTLE_PARTNER(battlerAtk), B_WEATHER_SUN) && IS_MOVE_PHYSICAL(move)) MulModifier(&modifier, UQ_4_12(1.5)); break; } @@ -9447,7 +9357,7 @@ static u32 CalcDefenseStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, } break; case ABILITY_FLOWER_GIFT: - if (gBattleMons[battlerDef].species == SPECIES_CHERRIM && IsBattlerWeatherAffected(battlerDef, B_WEATHER_SUN) && !usesDefStat) + if (gBattleMons[battlerDef].species == SPECIES_CHERRIM_SUNSHINE && IsBattlerWeatherAffected(battlerDef, B_WEATHER_SUN) && !usesDefStat) MulModifier(&modifier, UQ_4_12(1.5)); break; case ABILITY_PUNK_ROCK: @@ -9466,7 +9376,7 @@ static u32 CalcDefenseStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, switch (GetBattlerAbility(BATTLE_PARTNER(battlerDef))) { case ABILITY_FLOWER_GIFT: - if (gBattleMons[BATTLE_PARTNER(battlerDef)].species == SPECIES_CHERRIM && IsBattlerWeatherAffected(BATTLE_PARTNER(battlerDef), B_WEATHER_SUN) && !usesDefStat) + if (gBattleMons[BATTLE_PARTNER(battlerDef)].species == SPECIES_CHERRIM_SUNSHINE && IsBattlerWeatherAffected(BATTLE_PARTNER(battlerDef), B_WEATHER_SUN) && !usesDefStat) MulModifier(&modifier, UQ_4_12(1.5)); break; } diff --git a/src/data/pokemon/form_change_table_pointers.h b/src/data/pokemon/form_change_table_pointers.h index daeaa9cbb..8453ed480 100644 --- a/src/data/pokemon/form_change_table_pointers.h +++ b/src/data/pokemon/form_change_table_pointers.h @@ -92,6 +92,8 @@ const struct FormChange *const gFormChangeTablePointers[NUM_SPECIES] = [SPECIES_BURMY] = sBurmyFormChangeTable, [SPECIES_BURMY_SANDY_CLOAK] = sBurmyFormChangeTable, [SPECIES_BURMY_TRASH_CLOAK] = sBurmyFormChangeTable, + [SPECIES_CHERRIM] = sCherrimFormChangeTable, + [SPECIES_CHERRIM_SUNSHINE] = sCherrimFormChangeTable, [SPECIES_LOPUNNY] = sLopunnyFormChangeTable, [SPECIES_LOPUNNY_MEGA] = sLopunnyFormChangeTable, [SPECIES_GARCHOMP] = sGarchompFormChangeTable, diff --git a/test/ability_flower_gift.c b/test/ability_flower_gift.c new file mode 100644 index 000000000..2f2b98d1e --- /dev/null +++ b/test/ability_flower_gift.c @@ -0,0 +1,86 @@ +#include "global.h" +#include "test_battle.h" + +SINGLE_BATTLE_TEST("Flower Gift transforms Cherrim in harsh sunlight") +{ + GIVEN { + PLAYER(SPECIES_CHERRIM) { Ability(ABILITY_FLOWER_GIFT); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUNNY_DAY); } + } SCENE { + ABILITY_POPUP(player, ABILITY_FLOWER_GIFT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Cherrim transformed!"); + } +} + +SINGLE_BATTLE_TEST("Flower Gift transforms Cherrim back to normal when weather changes") +{ + GIVEN { + PLAYER(SPECIES_CHERRIM) { Ability(ABILITY_FLOWER_GIFT); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUNNY_DAY); } + TURN { MOVE(opponent, MOVE_RAIN_DANCE); } + } SCENE { + // transforms in sun + ABILITY_POPUP(player, ABILITY_FLOWER_GIFT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Cherrim transformed!"); + // back to normal + ABILITY_POPUP(player, ABILITY_FLOWER_GIFT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Cherrim transformed!"); + } +} + +SINGLE_BATTLE_TEST("Flower Gift transforms Cherrim back to normal when its ability is suppressed") +{ + GIVEN { + PLAYER(SPECIES_CHERRIM) { Ability(ABILITY_FLOWER_GIFT); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUNNY_DAY); } + TURN { MOVE(opponent, MOVE_GASTRO_ACID); } + } SCENE { + // transforms in sun + ABILITY_POPUP(player, ABILITY_FLOWER_GIFT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Cherrim transformed!"); + // back to normal + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Cherrim transformed!"); + } +} + +DOUBLE_BATTLE_TEST("Flower Gift increases the attack of Cherrim's ally by 1.5x", s16 damage) +{ + bool32 sunny; + PARAMETRIZE { sunny = FALSE; } + PARAMETRIZE { sunny = TRUE; } + GIVEN { + PLAYER(SPECIES_CHERRIM) { Ability(ABILITY_FLOWER_GIFT); }; + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (sunny) + TURN { MOVE(playerLeft, MOVE_SUNNY_DAY); } + TURN { MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); } + } SCENE { + // Sun activates + if (sunny) { + ABILITY_POPUP(playerLeft, ABILITY_FLOWER_GIFT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, playerLeft); + MESSAGE("Cherrim transformed!"); + } + // Partner uses Tackle + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight); + HP_BAR(opponentLeft, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, UQ_4_12(1.5), results[1].damage); + } +} + +TO_DO_BATTLE_TEST("Flower Gift does not transform Cherrim back to normal when suppressed if Cherrim is Dynamaxed"); diff --git a/test/ability_forecast.c b/test/ability_forecast.c new file mode 100644 index 000000000..dba09992d --- /dev/null +++ b/test/ability_forecast.c @@ -0,0 +1,201 @@ +#include "global.h" +#include "test_battle.h" + +SINGLE_BATTLE_TEST("Forecast transforms Castform in weather from an opponent's move") +{ + u32 move; + PARAMETRIZE { move = MOVE_SUNNY_DAY; } + PARAMETRIZE { move = MOVE_RAIN_DANCE; } + PARAMETRIZE { move = MOVE_HAIL; } + GIVEN { + PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); } + } SCENE { + ABILITY_POPUP(player, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + } +} + +SINGLE_BATTLE_TEST("Forecast transforms Castform in weather from its own move") +{ + u32 move; + PARAMETRIZE { move = MOVE_SUNNY_DAY; } + PARAMETRIZE { move = MOVE_RAIN_DANCE; } + PARAMETRIZE { move = MOVE_HAIL; } + GIVEN { + PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ABILITY_POPUP(player, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + } +} + +DOUBLE_BATTLE_TEST("Forecast transforms Castform in weather from a partner's move") +{ + u32 move; + PARAMETRIZE { move = MOVE_SUNNY_DAY; } + PARAMETRIZE { move = MOVE_RAIN_DANCE; } + PARAMETRIZE { move = MOVE_HAIL; } + GIVEN { + PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerRight, move); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, playerLeft); + MESSAGE("Castform transformed!"); + } +} + +DOUBLE_BATTLE_TEST("Forecast transforms all Castforms present in weather") +{ + u32 move; + PARAMETRIZE { move = MOVE_SUNNY_DAY; } + PARAMETRIZE { move = MOVE_RAIN_DANCE; } + PARAMETRIZE { move = MOVE_HAIL; } + GIVEN { + PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + OPPONENT(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + OPPONENT(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + } WHEN { + TURN { MOVE(playerRight, move); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, playerLeft); + MESSAGE("Castform transformed!"); + ABILITY_POPUP(opponentLeft, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, opponentLeft); + MESSAGE("Foe Castform transformed!"); + ABILITY_POPUP(playerRight, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, playerRight); + MESSAGE("Castform transformed!"); + ABILITY_POPUP(opponentRight, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, opponentRight); + MESSAGE("Foe Castform transformed!"); + } +} + +SINGLE_BATTLE_TEST("Forecast transforms Castform in weather from an ability") +{ + GIVEN { + PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_KYOGRE) { Ability(ABILITY_DRIZZLE); }; + } WHEN { + TURN { SWITCH(opponent, 1); } + } SCENE { + ABILITY_POPUP(player, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + } +} + +SINGLE_BATTLE_TEST("Forecast transforms Castform in primal weather") +{ + GIVEN { + PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_KYOGRE) { Ability(ABILITY_DRIZZLE); Item(ITEM_BLUE_ORB); }; + } WHEN { + TURN { SWITCH(opponent, 1); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_PRIMORDIAL_SEA); + ABILITY_POPUP(player, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + } +} + +SINGLE_BATTLE_TEST("Forecast transforms Castform back to normal when weather expires") +{ + GIVEN { + PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RAIN_DANCE); } + TURN { } + TURN { } + TURN { } + TURN { } + TURN { } + } SCENE { + // transforms + ABILITY_POPUP(player, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + // back to normal + ABILITY_POPUP(player, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + } +} + +SINGLE_BATTLE_TEST("Forecast transforms Castform back to normal when Sandstorm is active") +{ + GIVEN { + PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RAIN_DANCE); } + TURN { MOVE(player, MOVE_SANDSTORM); } + } SCENE { + // transforms + ABILITY_POPUP(player, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + // back to normal + ABILITY_POPUP(player, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + } +} + +SINGLE_BATTLE_TEST("Forecast transforms Castform on switch-in") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RAIN_DANCE); } + TURN { SWITCH(player, 1); } + } SCENE { + // turn 1 + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAIN_DANCE, player); + // turn 2 + ABILITY_POPUP(player, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + } +} + +SINGLE_BATTLE_TEST("Forecast transforms Castform when weather changes") +{ + GIVEN { + PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RAIN_DANCE); } + TURN { MOVE(player, MOVE_SUNNY_DAY); } + } SCENE { + // transforms + ABILITY_POPUP(player, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + // transforms again + ABILITY_POPUP(player, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + } +} From 0c182345bf015aa7e659e68b6598955d992aece0 Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Tue, 16 May 2023 16:24:25 -0700 Subject: [PATCH 2/6] reworked weather form reversion + added more tests --- asm/macros/battle_script.inc | 2 +- data/battle_scripts_1.s | 39 +++++++----------- include/battle_scripts.h | 2 +- include/constants/form_change_types.h | 1 + src/battle_script_commands.c | 7 ++-- src/battle_util.c | 27 ++++++++++-- src/data/pokemon/form_change_tables.h | 16 ++++---- test/ability_flower_gift.c | 48 +++++++++++++++++++--- test/ability_forecast.c | 59 +++++++++++++++++++++++++-- 9 files changed, 150 insertions(+), 51 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index dec096e6e..4b0b341dd 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1346,7 +1346,7 @@ callnative BS_ItemRestorePP .endm - .macro trytorevertweatherform + .macro tryrevertweatherform callnative BS_TryRevertWeatherForm .endm diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 26f30ef3f..89e69b50c 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1580,7 +1580,7 @@ BattleScript_MoveEffectCoreEnforcer:: printstring STRINGID_PKMNSABILITYSUPPRESSED waitmessage B_WAIT_TIME_LONG trytoclearprimalweather - trytorevertweatherform + tryrevertweatherform printstring STRINGID_EMPTYSTRING3 waitmessage 1 BattleScript_CoreEnforcerRet: @@ -2729,7 +2729,7 @@ BattleScript_EffectSimpleBeam: printstring STRINGID_PKMNACQUIREDSIMPLE waitmessage B_WAIT_TIME_LONG trytoclearprimalweather - trytorevertweatherform + tryrevertweatherform printstring STRINGID_EMPTYSTRING3 waitmessage 1 tryendneutralizinggas BS_TARGET @@ -2829,7 +2829,7 @@ BattleScript_EffectWorrySeed: printstring STRINGID_PKMNACQUIREDABILITY waitmessage B_WAIT_TIME_LONG trytoclearprimalweather - trytorevertweatherform + tryrevertweatherform printstring STRINGID_EMPTYSTRING3 waitmessage 1 goto BattleScript_MoveEnd @@ -2961,7 +2961,7 @@ BattleScript_EffectGastroAcid: printstring STRINGID_PKMNSABILITYSUPPRESSED waitmessage B_WAIT_TIME_LONG trytoclearprimalweather - trytorevertweatherform + tryrevertweatherform printstring STRINGID_EMPTYSTRING3 waitmessage 1 tryendneutralizinggas BS_TARGET @@ -8003,9 +8003,7 @@ BattleScript_CudChewActivates:: setbyte sBERRY_OVERRIDE, 0 end3 -BattleScript_TargetFormChange:: - pause 5 - call BattleScript_AbilityPopUpTarget +BattleScript_TargetFormChangeNoPopup: printstring STRINGID_EMPTYSTRING3 waitmessage 1 handleformchange BS_TARGET, 0 @@ -8015,32 +8013,25 @@ BattleScript_TargetFormChange:: handleformchange BS_TARGET, 2 return +BattleScript_TargetFormChange:: + pause 5 + call BattleScript_AbilityPopUpTarget + call BattleScript_TargetFormChangeNoPopup + return + BattleScript_TargetFormChangeWithString:: pause 5 call BattleScript_AbilityPopUpTarget - printstring STRINGID_EMPTYSTRING3 - waitmessage 1 - handleformchange BS_TARGET, 0 - handleformchange BS_TARGET, 1 - playanimation BS_TARGET, B_ANIM_FORM_CHANGE, NULL - waitanimation - handleformchange BS_TARGET, 2 + call BattleScript_TargetFormChangeNoPopup printstring STRINGID_PKMNTRANSFORMED waitmessage B_WAIT_TIME_LONG return -BattleScript_TargetFormChangeWithStringNoPopupEnd3:: - pause 5 - printstring STRINGID_EMPTYSTRING3 - waitmessage 1 - handleformchange BS_TARGET, 0 - handleformchange BS_TARGET, 1 - playanimation BS_TARGET, B_ANIM_FORM_CHANGE, NULL - waitanimation - handleformchange BS_TARGET, 2 +BattleScript_TargetFormChangeWithStringNoPopup:: + call BattleScript_TargetFormChangeNoPopup printstring STRINGID_PKMNTRANSFORMED waitmessage B_WAIT_TIME_LONG - end3 + return BattleScript_BattlerFormChangeWithStringEnd3:: pause 5 diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 4a0057275..c5b844b99 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -465,7 +465,7 @@ extern const u8 BattleScript_MoveEffectStockpileWoreOff[]; extern const u8 BattleScript_StealthRockActivates[]; extern const u8 BattleScript_SpikesActivates[]; extern const u8 BattleScript_BerserkGeneRet[]; -extern const u8 BattleScript_TargetFormChangeWithStringNoPopupEnd3[]; +extern const u8 BattleScript_TargetFormChangeWithStringNoPopup[]; // zmoves extern const u8 BattleScript_ZMoveActivateDamaging[]; diff --git a/include/constants/form_change_types.h b/include/constants/form_change_types.h index 651bcf788..81d1b045b 100644 --- a/include/constants/form_change_types.h +++ b/include/constants/form_change_types.h @@ -89,6 +89,7 @@ // Form change that activates when a specific weather is set during battle. // param1: weather to check +// param2: (optional) revert if specified ability is lost #define FORM_CHANGE_BATTLE_WEATHER 14 // Form change that activates automatically when the turn ends. diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index b21197a67..dd198f512 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -16567,13 +16567,12 @@ void BS_ItemRestorePP(void) void BS_TryRevertWeatherForm(void) { NATIVE_ARGS(); - u16 ability = gBattleMons[gBattlerTarget].ability; if (B_WEATHER_FORM_SUPPRESS >= GEN_5 - && (ability == ABILITY_FORECAST || ability == ABILITY_FLOWER_GIFT) - && TryBattleFormChange(gBattlerTarget, FORM_CHANGE_BATTLE_SWITCH)) // revert form + && TryBattleFormChange(gBattlerTarget, FORM_CHANGE_BATTLE_WEATHER)) { gBattleScripting.battler = gBattlerTarget; - BattleScriptPushCursorAndCallback(BattleScript_TargetFormChangeWithStringNoPopupEnd3); + BattleScriptPush(cmd->nextInstr); + gBattlescriptCurrInstr = BattleScript_TargetFormChangeWithStringNoPopup; return; } gBattlescriptCurrInstr = cmd->nextInstr; diff --git a/src/battle_util.c b/src/battle_util.c index 67270469e..602dd5c74 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6013,8 +6013,10 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move #else TRY_WEATHER_FORM: #endif - if ((IsBattlerWeatherAffected(battler, gBattleWeather) || gBattleWeather == B_WEATHER_NONE) - && TryBattleFormChange(battler, FORM_CHANGE_BATTLE_WEATHER)) + if ((IsBattlerWeatherAffected(battler, gBattleWeather) + || gBattleWeather == B_WEATHER_NONE + || !WEATHER_HAS_EFFECT) // Air Lock active + && TryBattleFormChange(battler, FORM_CHANGE_BATTLE_WEATHER)) { BattleScriptPushCursorAndCallback(BattleScript_BattlerFormChangeWithStringEnd3); effect++; @@ -10101,9 +10103,26 @@ u16 GetBattleFormChangeTargetSpecies(u8 battlerId, u16 method) } break; case FORM_CHANGE_BATTLE_WEATHER: - if (gBattleWeather & formChanges[i].param1 - || (gBattleWeather == B_WEATHER_NONE && formChanges[i].param1 == B_WEATHER_NONE)) + // Check if there is a required ability and if the battler's ability does not match it + // or is suppressed. If so, revert to the no weather form. + if (formChanges[i].param2 + && (gBattleMons[battlerId].ability != formChanges[i].param2 + || (gStatuses3[gBattlerTarget] & STATUS3_GASTRO_ACID)) + && formChanges[i].param1 == B_WEATHER_NONE) + { targetSpecies = formChanges[i].targetSpecies; + } + // We need to revert the weather form if the field is under Air Lock, too. + if (!WEATHER_HAS_EFFECT && formChanges[i].param1 == B_WEATHER_NONE) + { + targetSpecies = formChanges[i].targetSpecies; + } + // Otherwise, just check for a match between the weather and the form change table. + else if (gBattleWeather & formChanges[i].param1 + || (gBattleWeather == B_WEATHER_NONE && formChanges[i].param1 == B_WEATHER_NONE)) + { + targetSpecies = formChanges[i].targetSpecies; + } break; case FORM_CHANGE_BATTLE_TURN_END: if (formChanges[i].param1 == GetBattlerAbility(battlerId)) diff --git a/src/data/pokemon/form_change_tables.h b/src/data/pokemon/form_change_tables.h index c4ade7b9a..4137c9ba3 100644 --- a/src/data/pokemon/form_change_tables.h +++ b/src/data/pokemon/form_change_tables.h @@ -156,11 +156,11 @@ static const struct FormChange sAbsolFormChangeTable[] = { }; static const struct FormChange sCastformFormChangeTable[] = { - {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_SUNNY, B_WEATHER_SUN}, - {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_RAINY, B_WEATHER_RAIN}, - {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_SNOWY, B_WEATHER_HAIL}, - {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM, ~(B_WEATHER_SUN | B_WEATHER_RAIN | B_WEATHER_HAIL)}, - {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM, B_WEATHER_NONE}, + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_SUNNY, B_WEATHER_SUN, ABILITY_FORECAST}, + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_RAINY, B_WEATHER_RAIN, ABILITY_FORECAST}, + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_SNOWY, B_WEATHER_HAIL, ABILITY_FORECAST}, + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM, ~(B_WEATHER_SUN | B_WEATHER_RAIN | B_WEATHER_HAIL), ABILITY_FORECAST}, + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM, B_WEATHER_NONE, ABILITY_FORECAST}, {FORM_CHANGE_BATTLE_SWITCH, SPECIES_CASTFORM}, {FORM_CHANGE_FAINT, SPECIES_CASTFORM}, {FORM_CHANGE_END_BATTLE, SPECIES_CASTFORM}, @@ -231,9 +231,9 @@ static const struct FormChange sBurmyFormChangeTable[] = { }; static const struct FormChange sCherrimFormChangeTable[] = { - {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CHERRIM_SUNSHINE, B_WEATHER_SUN}, - {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CHERRIM, ~B_WEATHER_SUN}, - {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CHERRIM, B_WEATHER_NONE}, + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CHERRIM_SUNSHINE, B_WEATHER_SUN, ABILITY_FLOWER_GIFT}, + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CHERRIM, ~B_WEATHER_SUN, ABILITY_FLOWER_GIFT}, + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CHERRIM, B_WEATHER_NONE, ABILITY_FLOWER_GIFT}, {FORM_CHANGE_BATTLE_SWITCH, SPECIES_CHERRIM}, {FORM_CHANGE_FAINT, SPECIES_CHERRIM}, {FORM_CHANGE_END_BATTLE, SPECIES_CHERRIM}, diff --git a/test/ability_flower_gift.c b/test/ability_flower_gift.c index 2f2b98d1e..1967b874d 100644 --- a/test/ability_flower_gift.c +++ b/test/ability_flower_gift.c @@ -54,7 +54,7 @@ SINGLE_BATTLE_TEST("Flower Gift transforms Cherrim back to normal when its abili } } -DOUBLE_BATTLE_TEST("Flower Gift increases the attack of Cherrim's ally by 1.5x", s16 damage) +DOUBLE_BATTLE_TEST("Flower Gift increases the attack of Cherrim and its allies by 1.5x", s16 damageL, s16 damageR) { bool32 sunny; PARAMETRIZE { sunny = FALSE; } @@ -67,19 +67,55 @@ DOUBLE_BATTLE_TEST("Flower Gift increases the attack of Cherrim's ally by 1.5x", } WHEN { if (sunny) TURN { MOVE(playerLeft, MOVE_SUNNY_DAY); } - TURN { MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); } + TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); + MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); } } SCENE { - // Sun activates + // sun activates if (sunny) { ABILITY_POPUP(playerLeft, ABILITY_FLOWER_GIFT); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, playerLeft); MESSAGE("Cherrim transformed!"); } - // Partner uses Tackle + // player uses Tackle + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &results[i].damageL); + // partner uses Tackle ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight); - HP_BAR(opponentLeft, captureDamage: &results[i].damage); + HP_BAR(opponentLeft, captureDamage: &results[i].damageR); } FINALLY { - EXPECT_MUL_EQ(results[0].damage, UQ_4_12(1.5), results[1].damage); + EXPECT_MUL_EQ(results[0].damageL, UQ_4_12(1.5), results[1].damageL); + EXPECT_MUL_EQ(results[0].damageR, UQ_4_12(1.5), results[1].damageR); + } +} + +DOUBLE_BATTLE_TEST("Flower Gift increases the Sp. Def of Cherrim and its allies by 1.5x", s16 damageL, s16 damageR) +{ + bool32 sunny; + PARAMETRIZE { sunny = FALSE; } + PARAMETRIZE { sunny = TRUE; } + GIVEN { + PLAYER(SPECIES_CHERRIM) { Ability(ABILITY_FLOWER_GIFT); }; + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (sunny) + TURN { MOVE(playerLeft, MOVE_SUNNY_DAY); } + TURN { MOVE(opponentLeft, MOVE_HYPER_VOICE, target: playerLeft); } + } SCENE { + // sun activates + if (sunny) { + ABILITY_POPUP(playerLeft, ABILITY_FLOWER_GIFT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, playerLeft); + MESSAGE("Cherrim transformed!"); + } + // opponentLeft uses Hyper Voice + ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, opponentLeft); + HP_BAR(playerLeft, captureDamage: &results[i].damageL); + HP_BAR(playerRight, captureDamage: &results[i].damageR); + } FINALLY { + EXPECT_MUL_EQ(results[1].damageL, UQ_4_12(1.5), results[0].damageL); + EXPECT_MUL_EQ(results[1].damageR, UQ_4_12(1.5), results[0].damageR); } } diff --git a/test/ability_forecast.c b/test/ability_forecast.c index dba09992d..826ba0e99 100644 --- a/test/ability_forecast.c +++ b/test/ability_forecast.c @@ -7,6 +7,7 @@ SINGLE_BATTLE_TEST("Forecast transforms Castform in weather from an opponent's m PARAMETRIZE { move = MOVE_SUNNY_DAY; } PARAMETRIZE { move = MOVE_RAIN_DANCE; } PARAMETRIZE { move = MOVE_HAIL; } + PARAMETRIZE { move = MOVE_SNOWSCAPE; } GIVEN { PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; OPPONENT(SPECIES_WOBBUFFET); @@ -25,6 +26,7 @@ SINGLE_BATTLE_TEST("Forecast transforms Castform in weather from its own move") PARAMETRIZE { move = MOVE_SUNNY_DAY; } PARAMETRIZE { move = MOVE_RAIN_DANCE; } PARAMETRIZE { move = MOVE_HAIL; } + PARAMETRIZE { move = MOVE_SNOWSCAPE; } GIVEN { PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; OPPONENT(SPECIES_WOBBUFFET); @@ -43,6 +45,7 @@ DOUBLE_BATTLE_TEST("Forecast transforms Castform in weather from a partner's mov PARAMETRIZE { move = MOVE_SUNNY_DAY; } PARAMETRIZE { move = MOVE_RAIN_DANCE; } PARAMETRIZE { move = MOVE_HAIL; } + PARAMETRIZE { move = MOVE_SNOWSCAPE; } GIVEN { PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; PLAYER(SPECIES_WOBBUFFET); @@ -63,6 +66,7 @@ DOUBLE_BATTLE_TEST("Forecast transforms all Castforms present in weather") PARAMETRIZE { move = MOVE_SUNNY_DAY; } PARAMETRIZE { move = MOVE_RAIN_DANCE; } PARAMETRIZE { move = MOVE_HAIL; } + PARAMETRIZE { move = MOVE_SNOWSCAPE; } GIVEN { PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; @@ -88,10 +92,14 @@ DOUBLE_BATTLE_TEST("Forecast transforms all Castforms present in weather") SINGLE_BATTLE_TEST("Forecast transforms Castform in weather from an ability") { + u32 species, ability; + PARAMETRIZE { species = SPECIES_KYOGRE; ability = ABILITY_DRIZZLE; } + PARAMETRIZE { species = SPECIES_GROUDON; ability = ABILITY_DROUGHT; } + PARAMETRIZE { species = SPECIES_ABOMASNOW; ability = ABILITY_SNOW_WARNING; } GIVEN { PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_KYOGRE) { Ability(ABILITY_DRIZZLE); }; + OPPONENT(species) { Ability(ability); }; } WHEN { TURN { SWITCH(opponent, 1); } } SCENE { @@ -103,14 +111,17 @@ SINGLE_BATTLE_TEST("Forecast transforms Castform in weather from an ability") SINGLE_BATTLE_TEST("Forecast transforms Castform in primal weather") { + u32 species, item, ability; + PARAMETRIZE { species = SPECIES_KYOGRE; ability = ABILITY_PRIMORDIAL_SEA; item = ITEM_BLUE_ORB; } + PARAMETRIZE { species = SPECIES_GROUDON; ability = ABILITY_DESOLATE_LAND; item = ITEM_RED_ORB; } GIVEN { PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_KYOGRE) { Ability(ABILITY_DRIZZLE); Item(ITEM_BLUE_ORB); }; + OPPONENT(species) { Item(item); }; } WHEN { TURN { SWITCH(opponent, 1); } } SCENE { - ABILITY_POPUP(opponent, ABILITY_PRIMORDIAL_SEA); + ABILITY_POPUP(opponent, ability); ABILITY_POPUP(player, ABILITY_FORECAST); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); MESSAGE("Castform transformed!"); @@ -161,6 +172,29 @@ SINGLE_BATTLE_TEST("Forecast transforms Castform back to normal when Sandstorm i } } +SINGLE_BATTLE_TEST("Forecast transforms Castform back to normal under Air Lock") +{ + GIVEN { + PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_RAYQUAZA); + } WHEN { + TURN { MOVE(player, MOVE_RAIN_DANCE); } + TURN { SWITCH(opponent, 1); } + TURN { MOVE(opponent, MOVE_CELEBRATE, megaEvolve: TRUE); } + } SCENE { + // transforms + ABILITY_POPUP(player, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + // back to normal + ABILITY_POPUP(opponent, ABILITY_AIR_LOCK); + ABILITY_POPUP(player, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + } +} + SINGLE_BATTLE_TEST("Forecast transforms Castform on switch-in") { GIVEN { @@ -199,3 +233,22 @@ SINGLE_BATTLE_TEST("Forecast transforms Castform when weather changes") MESSAGE("Castform transformed!"); } } + +SINGLE_BATTLE_TEST("Forecast transforms Castform back to normal when its ability is suppressed") +{ + GIVEN { + PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUNNY_DAY); } + TURN { MOVE(opponent, MOVE_GASTRO_ACID); } + } SCENE { + // transforms in sun + ABILITY_POPUP(player, ABILITY_FORECAST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + // back to normal + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Castform transformed!"); + } +} From b269cc69060afda3e027eed2265f3fb5967232fc Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Tue, 16 May 2023 16:37:18 -0700 Subject: [PATCH 3/6] changed gastro acid check to properly use GetBattlerAbility --- src/battle_util.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/battle_util.c b/src/battle_util.c index 5fa5a2759..3f0e101f0 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -10161,8 +10161,7 @@ u16 GetBattleFormChangeTargetSpecies(u8 battlerId, u16 method) // Check if there is a required ability and if the battler's ability does not match it // or is suppressed. If so, revert to the no weather form. if (formChanges[i].param2 - && (gBattleMons[battlerId].ability != formChanges[i].param2 - || (gStatuses3[gBattlerTarget] & STATUS3_GASTRO_ACID)) + && GetBattlerAbility(battlerId) != formChanges[i].param2 && formChanges[i].param1 == B_WEATHER_NONE) { targetSpecies = formChanges[i].targetSpecies; From 7b087137072c220e06a5f11ffe59b3f3c6bfe5fd Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Tue, 16 May 2023 20:34:16 -0700 Subject: [PATCH 4/6] changed B_WEATHER_FORM_SUPPRESS config to preproc --- src/battle_script_commands.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index cfb8c5965..c85446a34 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -16605,14 +16605,15 @@ void BS_ItemRestorePP(void) void BS_TryRevertWeatherForm(void) { NATIVE_ARGS(); - if (B_WEATHER_FORM_SUPPRESS >= GEN_5 - && TryBattleFormChange(gBattlerTarget, FORM_CHANGE_BATTLE_WEATHER)) +#if B_WEATHER_FORM_SUPPRESS >= GEN_5 + if (TryBattleFormChange(gBattlerTarget, FORM_CHANGE_BATTLE_WEATHER)) { gBattleScripting.battler = gBattlerTarget; BattleScriptPush(cmd->nextInstr); gBattlescriptCurrInstr = BattleScript_TargetFormChangeWithStringNoPopup; return; } +#endif gBattlescriptCurrInstr = cmd->nextInstr; } From d4c7e5e5595d85f25f4ab078d64dd3a02dce49e1 Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Tue, 23 May 2023 14:03:38 -0700 Subject: [PATCH 5/6] changed B_WEATHER_FORM preproc to affect tables instead of function --- include/config/battle.h | 1 - src/battle_script_commands.c | 2 -- src/battle_util.c | 2 +- src/data/pokemon/form_change_tables.h | 8 ++++++++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/config/battle.h b/include/config/battle.h index d0b5366ec..4a1bbdc2f 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -101,7 +101,6 @@ #define B_STOCKPILE_RAISES_DEFS GEN_LATEST // In Gen4+, Stockpile also raises Defense and Sp. Defense stats. Once Spit Up / Swallow is used, these stat changes are lost. #define B_TRANSFORM_SHINY GEN_LATEST // In Gen4+, Transform will copy the shiny state of the opponent instead of maintaining its own shiny state. #define B_TRANSFORM_FORM_CHANGES GEN_LATEST // In Gen5+, Transformed Pokemon cannot change forms. -#define B_WEATHER_FORM_SUPPRESS GEN_LATEST // In Gen5+, Cherrim and Castform revert to their normal forms upon losing their ability. // Ability settings #define B_EXPANDED_ABILITY_NAMES TRUE // If TRUE, ability names are increased from 12 characters to 16 characters. diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index c85446a34..47a98ac9e 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -16605,7 +16605,6 @@ void BS_ItemRestorePP(void) void BS_TryRevertWeatherForm(void) { NATIVE_ARGS(); -#if B_WEATHER_FORM_SUPPRESS >= GEN_5 if (TryBattleFormChange(gBattlerTarget, FORM_CHANGE_BATTLE_WEATHER)) { gBattleScripting.battler = gBattlerTarget; @@ -16613,7 +16612,6 @@ void BS_TryRevertWeatherForm(void) gBattlescriptCurrInstr = BattleScript_TargetFormChangeWithStringNoPopup; return; } -#endif gBattlescriptCurrInstr = cmd->nextInstr; } diff --git a/src/battle_util.c b/src/battle_util.c index 3f0e101f0..7c0d3f8cc 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -10167,7 +10167,7 @@ u16 GetBattleFormChangeTargetSpecies(u8 battlerId, u16 method) targetSpecies = formChanges[i].targetSpecies; } // We need to revert the weather form if the field is under Air Lock, too. - if (!WEATHER_HAS_EFFECT && formChanges[i].param1 == B_WEATHER_NONE) + else if (!WEATHER_HAS_EFFECT && formChanges[i].param1 == B_WEATHER_NONE) { targetSpecies = formChanges[i].targetSpecies; } diff --git a/src/data/pokemon/form_change_tables.h b/src/data/pokemon/form_change_tables.h index 6919ca05d..ca2006157 100644 --- a/src/data/pokemon/form_change_tables.h +++ b/src/data/pokemon/form_change_tables.h @@ -156,11 +156,19 @@ static const struct FormChange sAbsolFormChangeTable[] = { }; static const struct FormChange sCastformFormChangeTable[] = { +#ifdef B_WEATHER_FORMS >= GEN_5 {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_SUNNY, B_WEATHER_SUN, ABILITY_FORECAST}, {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_RAINY, B_WEATHER_RAIN, ABILITY_FORECAST}, {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_SNOWY, B_WEATHER_HAIL | B_WEATHER_SNOW, ABILITY_FORECAST}, {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM, ~(B_WEATHER_SUN | B_WEATHER_RAIN | B_WEATHER_HAIL | B_WEATHER_SNOW), ABILITY_FORECAST}, {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM, B_WEATHER_NONE, ABILITY_FORECAST}, +#else + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_SUNNY, B_WEATHER_SUN}, + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_RAINY, B_WEATHER_RAIN}, + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_SNOWY, B_WEATHER_HAIL | B_WEATHER_SNOW}, + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM, ~(B_WEATHER_SUN | B_WEATHER_RAIN | B_WEATHER_HAIL | B_WEATHER_SNOW)}, + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM, B_WEATHER_NONE}, +#endif {FORM_CHANGE_BATTLE_SWITCH, SPECIES_CASTFORM}, {FORM_CHANGE_FAINT, SPECIES_CASTFORM}, {FORM_CHANGE_END_BATTLE, SPECIES_CASTFORM}, From 6a92caa9fbfa3bf08c385000cb2d0187a6b7bef6 Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Tue, 23 May 2023 16:10:26 -0700 Subject: [PATCH 6/6] removed old B_WEATHER_FORMS use, tests now have assumptions for config --- src/battle_util.c | 10 ---------- src/data/pokemon/form_change_tables.h | 8 +++++++- test/ability_flower_gift.c | 1 + test/ability_forecast.c | 1 + 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/battle_util.c b/src/battle_util.c index 7c0d3f8cc..fec8d013d 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4759,12 +4759,6 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move effect++; } break; -#if B_WEATHER_FORMS < GEN_5 - default: - if (gBattleMons[battler].species == SPECIES_CHERRIM) - goto TRY_WEATHER_FORM; - break; -#endif } break; case ABILITYEFFECT_ENDTURN: // 1 @@ -6037,11 +6031,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move switch (gLastUsedAbility) { case ABILITY_FORECAST: -#if B_WEATHER_FORMS >= GEN_5 case ABILITY_FLOWER_GIFT: -#else - TRY_WEATHER_FORM: -#endif if ((IsBattlerWeatherAffected(battler, gBattleWeather) || gBattleWeather == B_WEATHER_NONE || !WEATHER_HAS_EFFECT) // Air Lock active diff --git a/src/data/pokemon/form_change_tables.h b/src/data/pokemon/form_change_tables.h index ca2006157..1d9b0e8dc 100644 --- a/src/data/pokemon/form_change_tables.h +++ b/src/data/pokemon/form_change_tables.h @@ -156,7 +156,7 @@ static const struct FormChange sAbsolFormChangeTable[] = { }; static const struct FormChange sCastformFormChangeTable[] = { -#ifdef B_WEATHER_FORMS >= GEN_5 +#if B_WEATHER_FORMS >= GEN_5 {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_SUNNY, B_WEATHER_SUN, ABILITY_FORECAST}, {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_RAINY, B_WEATHER_RAIN, ABILITY_FORECAST}, {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_SNOWY, B_WEATHER_HAIL | B_WEATHER_SNOW, ABILITY_FORECAST}, @@ -239,9 +239,15 @@ static const struct FormChange sBurmyFormChangeTable[] = { }; static const struct FormChange sCherrimFormChangeTable[] = { +#if B_WEATHER_FORMS >= GEN_5 {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CHERRIM_SUNSHINE, B_WEATHER_SUN, ABILITY_FLOWER_GIFT}, {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CHERRIM, ~B_WEATHER_SUN, ABILITY_FLOWER_GIFT}, {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CHERRIM, B_WEATHER_NONE, ABILITY_FLOWER_GIFT}, +#else + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CHERRIM_SUNSHINE, B_WEATHER_SUN}, + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CHERRIM, ~B_WEATHER_SUN}, + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_CHERRIM, B_WEATHER_NONE}, +#endif {FORM_CHANGE_BATTLE_SWITCH, SPECIES_CHERRIM}, {FORM_CHANGE_FAINT, SPECIES_CHERRIM}, {FORM_CHANGE_END_BATTLE, SPECIES_CHERRIM}, diff --git a/test/ability_flower_gift.c b/test/ability_flower_gift.c index 1967b874d..dd01736a2 100644 --- a/test/ability_flower_gift.c +++ b/test/ability_flower_gift.c @@ -38,6 +38,7 @@ SINGLE_BATTLE_TEST("Flower Gift transforms Cherrim back to normal when weather c SINGLE_BATTLE_TEST("Flower Gift transforms Cherrim back to normal when its ability is suppressed") { GIVEN { + ASSUME(B_WEATHER_FORMS >= GEN_5); PLAYER(SPECIES_CHERRIM) { Ability(ABILITY_FLOWER_GIFT); }; OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/ability_forecast.c b/test/ability_forecast.c index 826ba0e99..96559706a 100644 --- a/test/ability_forecast.c +++ b/test/ability_forecast.c @@ -237,6 +237,7 @@ SINGLE_BATTLE_TEST("Forecast transforms Castform when weather changes") SINGLE_BATTLE_TEST("Forecast transforms Castform back to normal when its ability is suppressed") { GIVEN { + ASSUME(B_WEATHER_FORMS >= GEN_5); PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); }; OPPONENT(SPECIES_WOBBUFFET); } WHEN {