diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 78fb914063..bfc81fbb6c 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1346,6 +1346,10 @@ callnative BS_ItemRestorePP .endm + .macro setsnow + callnative BS_SetSnow + .endm + @ various command changed to more readable macros .macro cancelmultiturnmoves battler:req various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index dcfdac88ed..a0b035704d 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -947,6 +947,7 @@ gBattleAnims_General:: .4byte General_ShellTrapSetUp @ B_ANIM_SHELL_TRAP_SETUP .4byte General_ZMoveActivate @ B_ANIM_ZMOVE_ACTIVATE .4byte General_AffectionHangedOn @ B_ANIM_AFFECTION_HANGED_ON + .4byte General_Snow @ B_ANIM_SNOW_CONTINUES .align 2 gBattleAnims_Special:: @@ -14385,6 +14386,18 @@ Move_SILK_TRAP:: clearmonbg ANIM_ATK_PARTNER end +@ Also used by Snow weather. Currently identical with Move_HAIL +Move_SNOWSCAPE:: + loadspritegfx ANIM_TAG_HAIL + loadspritegfx ANIM_TAG_ICE_CRYSTALS + createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_BG, 3, 0, 6, RGB_BLACK + waitforvisualfinish + createvisualtask AnimTask_Hail, 5 + loopsewithpan SE_M_HAIL, 0, 8, 10 + waitforvisualfinish + createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_BG, 3, 6, 0, RGB_BLACK + end + Move_WICKED_BLOW:: Move_SURGING_STRIKES:: Move_THUNDER_CAGE:: @@ -14448,7 +14461,6 @@ Move_ELECTRO_DRIFT:: Move_SHED_TAIL:: Move_CHILLY_RECEPTION:: Move_TIDY_UP:: -Move_SNOWSCAPE:: Move_POUNCE:: Move_TRAILBLAZE:: Move_CHILLING_WATER:: @@ -23924,6 +23936,7 @@ Move_WEATHER_BALL: jumpreteq ANIM_WEATHER_RAIN, WeatherBallWater jumpreteq ANIM_WEATHER_SANDSTORM, WeatherBallSandstorm jumpreteq ANIM_WEATHER_HAIL, WeatherBallIce + jumpreteq ANIM_WEATHER_SNOW, WeatherBallIce WeatherBallNormal: loadspritegfx ANIM_TAG_IMPACT createsprite gWeatherBallNormalDownSpriteTemplate, ANIM_TARGET, 2, -30, -100, 25, 1, 0, 0 @@ -24679,6 +24692,9 @@ General_Sandstorm: General_Hail: goto Move_HAIL +General_Snow: + goto Move_SNOWSCAPE + General_LeechSeedDrain: createvisualtask AnimTask_GetBattlersFromArg, 5 delay 0 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index ace2f707ba..fdc7c8a3fd 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -429,6 +429,7 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectBarbBarrage @ EFFECT_BARB_BARRAGE .4byte BattleScript_EffectRevivalBlessing @ EFFECT_REVIVAL_BLESSING .4byte BattleScript_EffectFrostbiteHit @ EFFECT_FROSTBITE_HIT + .4byte BattleScript_EffectSnow @ EFFECT_SNOWSCAPE BattleScript_EffectRevivalBlessing:: attackcanceler @@ -6850,7 +6851,7 @@ BattleScript_RainContinuesOrEndsEnd:: end2 BattleScript_DamagingWeatherContinues:: - printfromtable gSandStormHailContinuesStringIds + printfromtable gSandStormHailSnowContinuesStringIds waitmessage B_WAIT_TIME_LONG playanimation_var BS_ATTACKER, sB_ANIM_ARG1 setbyte gBattleCommunication, 0 @@ -6882,8 +6883,8 @@ BattleScript_DamagingWeatherContinuesEnd:: bicword gHitMarker, HITMARKER_SKIP_DMG_TRACK | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE | HITMARKER_GRUDGE end2 -BattleScript_SandStormHailEnds:: - printfromtable gSandStormHailEndStringIds +BattleScript_SandStormHailSnowEnds:: + printfromtable gSandStormHailSnowEndStringIds waitmessage B_WAIT_TIME_LONG end2 @@ -8865,7 +8866,7 @@ BattleScript_MimicryActivates_End3:: waitmessage B_WAIT_TIME_SHORT end3 -BattleScript_SnowWarningActivates:: +BattleScript_SnowWarningActivatesHail:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp printstring STRINGID_SNOWWARNINGHAIL @@ -8874,6 +8875,15 @@ BattleScript_SnowWarningActivates:: call BattleScript_ActivateWeatherAbilities end3 +BattleScript_SnowWarningActivatesSnow:: + pause B_WAIT_TIME_SHORT + call BattleScript_AbilityPopUp + printstring STRINGID_SNOWWARNINGSNOW + waitstate + playanimation BS_BATTLER_0, B_ANIM_SNOW_CONTINUES + call BattleScript_ActivateWeatherAbilities + end3 + BattleScript_ActivateTerrainEffects: savetarget setbyte gBattlerTarget, 0 @@ -10478,3 +10488,13 @@ BattleScript_BerserkGeneRet_OwnTempoPrevents: BattleScript_BerserkGeneRet_End: removeitem BS_SCRIPTING end3 + +BattleScript_EffectSnow:: + attackcanceler + attackstring + ppreduce + jumpifhalfword CMP_COMMON_BITS, gBattleWeather, B_WEATHER_SUN_PRIMAL, BattleScript_ExtremelyHarshSunlightWasNotLessened + jumpifhalfword CMP_COMMON_BITS, gBattleWeather, B_WEATHER_RAIN_PRIMAL, BattleScript_NoReliefFromHeavyRain + jumpifhalfword CMP_COMMON_BITS, gBattleWeather, B_WEATHER_STRONG_WINDS, BattleScript_MysteriousAirCurrentBlowsOn + setsnow + goto BattleScript_MoveWeatherChange diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 1a0fbc2645..37c9e9c19c 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -112,6 +112,7 @@ bool32 IsEncoreEncouragedEffect(u16 moveEffect); void ProtectChecks(u8 battlerAtk, u8 battlerDef, u16 move, u16 predictedMove, s16 *score); bool32 ShouldSetSandstorm(u8 battler, u16 ability, u16 holdEffect); bool32 ShouldSetHail(u8 battler, u16 ability, u16 holdEffect); +bool32 ShouldSetSnow(u8 battler, u16 ability, u16 holdEffect); bool32 ShouldSetRain(u8 battlerAtk, u16 ability, u16 holdEffect); bool32 ShouldSetSun(u8 battlerAtk, u16 atkAbility, u16 holdEffect); bool32 HasSleepMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef); diff --git a/include/battle_scripts.h b/include/battle_scripts.h index d387fd1551..94625566dd 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -45,8 +45,9 @@ extern const u8 BattleScript_ActionSwitch[]; extern const u8 BattleScript_Pausex20[]; extern const u8 BattleScript_LevelUp[]; extern const u8 BattleScript_RainContinuesOrEnds[]; +extern const u8 BattleScript_SnowContinuesOrEnds[]; extern const u8 BattleScript_DamagingWeatherContinues[]; -extern const u8 BattleScript_SandStormHailEnds[]; +extern const u8 BattleScript_SandStormHailSnowEnds[]; extern const u8 BattleScript_SunlightContinues[]; extern const u8 BattleScript_SunlightFaded[]; extern const u8 BattleScript_OverworldWeatherStarts[]; @@ -274,7 +275,8 @@ extern const u8 BattleScript_CursedBodyActivates[]; extern const u8 BattleScript_MummyActivates[]; extern const u8 BattleScript_WeakArmorActivates[]; extern const u8 BattleScript_FellStingerRaisesStat[]; -extern const u8 BattleScript_SnowWarningActivates[]; +extern const u8 BattleScript_SnowWarningActivatesHail[]; +extern const u8 BattleScript_SnowWarningActivatesSnow[]; extern const u8 BattleScript_HarvestActivates[]; extern const u8 BattleScript_ImposterActivates[]; extern const u8 BattleScript_SelectingNotAllowedMoveAssaultVest[]; diff --git a/include/config/battle.h b/include/config/battle.h index 6a6a829d65..6475f6664c 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -121,6 +121,7 @@ #define B_CHECK_IF_CHARGED_UP TRUE // If set to TRUE, certain abilities such as Electromorphosis WILL check if the STATUS3_CHARGED_UP status flag is applied. #define B_ABSORBING_ABILITY_STRING GEN_LATEST // In Gen5+, the abilities that absorb moves of a certain type use a generic string for stat increases and decreases. #define B_LEAF_GUARD_PREVENTS_REST GEN_LATEST // In Gen5+, Leaf Guard prevents the use of Rest in harsh sunlight. +#define B_SNOW_WARNING GEN_LATEST // In Gen9+, Snow Warning will summon snow instead of hail. // Item settings #define B_HP_BERRIES GEN_LATEST // In Gen4+, berries which restore hp activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn. diff --git a/include/constants/battle.h b/include/constants/battle.h index 950d98484f..814d1bfa57 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -288,8 +288,11 @@ #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) +#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_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) +#define B_WEATHER_SNOW (B_WEATHER_SNOW_TEMPORARY | B_WEATHER_SNOW_PERMANENT) // Battle Weather as enum #define ENUM_WEATHER_NONE 0 @@ -300,6 +303,7 @@ #define ENUM_WEATHER_SUN_PRIMAL 5 #define ENUM_WEATHER_RAIN_PRIMAL 6 #define ENUM_WEATHER_STRONG_WINDS 7 +#define ENUM_WEATHER_SNOW 8 // Move Effects #define MOVE_EFFECT_SLEEP 1 diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 1316054cd1..81dbdad163 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -30,6 +30,7 @@ #define AI_WEATHER_RAIN 2 #define AI_WEATHER_SANDSTORM 3 #define AI_WEATHER_HAIL 4 +#define AI_WEATHER_SNOW 5 // get_how_powerful_move_is #define MOVE_POWER_OTHER 0 diff --git a/include/constants/battle_anim.h b/include/constants/battle_anim.h index 46e229a319..4b772022e5 100644 --- a/include/constants/battle_anim.h +++ b/include/constants/battle_anim.h @@ -544,6 +544,7 @@ #define B_ANIM_SHELL_TRAP_SETUP 34 #define B_ANIM_ZMOVE_ACTIVATE 35 // Using Z Moves #define B_ANIM_AFFECTION_HANGED_ON 36 +#define B_ANIM_SNOW_CONTINUES 37 // special animations table (gBattleAnims_Special) #define B_ANIM_LVL_UP 0 @@ -591,6 +592,7 @@ #define ANIM_WEATHER_RAIN 2 #define ANIM_WEATHER_SANDSTORM 3 #define ANIM_WEATHER_HAIL 4 +#define ANIM_WEATHER_SNOW 5 // mon pal blend #define ANIM_PAL_BG 0x1 diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 5df12b4496..4d8330498d 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -406,7 +406,8 @@ #define EFFECT_BARB_BARRAGE 400 #define EFFECT_REVIVAL_BLESSING 401 #define EFFECT_FROSTBITE_HIT 402 +#define EFFECT_SNOWSCAPE 403 -#define NUM_BATTLE_MOVE_EFFECTS 403 +#define NUM_BATTLE_MOVE_EFFECTS 404 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 9ce49894ee..174c611e2f 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -660,8 +660,12 @@ #define STRINGID_PKMNFROSTBITEHEALED2 658 #define STRINGID_PKMNFROSTBITEHEALEDBY 659 #define STRINGID_MIRRORHERBCOPIED 660 +#define STRINGID_STARTEDSNOW 661 +#define STRINGID_SNOWCONTINUES 662 +#define STRINGID_SNOWSTOPPED 663 +#define STRINGID_SNOWWARNINGSNOW 664 -#define BATTLESTRINGS_COUNT 661 +#define BATTLESTRINGS_COUNT 665 // This is the string id that gBattleStringsTable starts with. // String ids before this (e.g. STRINGID_INTROMSG) are not in the table, @@ -727,15 +731,17 @@ #define B_MSG_STARTED_SANDSTORM 3 #define B_MSG_STARTED_SUNLIGHT 4 #define B_MSG_STARTED_HAIL 5 +#define B_MSG_STARTED_SNOW 6 // gRainContinuesStringIds #define B_MSG_RAIN_CONTINUES 0 #define B_MSG_DOWNPOUR_CONTINUES 1 #define B_MSG_RAIN_STOPPED 2 -// gSandStormHailContinuesStringIds / gSandStormHailDmgStringIds/ gSandStormHailEndStringIds +// gSandStormHailSnowContinuesStringIds / gSandStormHailDmgStringIds/ gSandStormHailSnowEndStringIds #define B_MSG_SANDSTORM 0 #define B_MSG_HAIL 1 +#define B_MSG_SNOW 2 // gReflectLightScreenSafeguardStringIds #define B_MSG_SIDE_STATUS_FAILED 0 diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 7dc33dd3b2..76bf2261e6 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -280,7 +280,7 @@ void Ai_InitPartyStruct(void) { if (GetMonData(&gPlayerParty[i], MON_DATA_HP) == 0) AI_PARTY->mons[B_SIDE_PLAYER][i].isFainted = TRUE; - + if (isOmniscient) { u32 j; @@ -1372,7 +1372,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_AURORA_VEIL: if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_AURORA_VEIL || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove) - || !(gBattleWeather & B_WEATHER_HAIL)) + || !(gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW))) score -= 10; break; case EFFECT_OHKO: @@ -1581,6 +1581,15 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_PRIMAL_ANY) || PartnerMoveEffectIsWeather(BATTLE_PARTNER(battlerAtk), AI_DATA->partnerMove)) score -= 8; + else if (gBattleWeather & B_WEATHER_SNOW) + score -= 2; // mainly to prevent looping between hail and snow + break; + case EFFECT_SNOWSCAPE: + if (gBattleWeather & (B_WEATHER_SNOW | B_WEATHER_PRIMAL_ANY) + || PartnerMoveEffectIsWeather(BATTLE_PARTNER(battlerAtk), AI_DATA->partnerMove)) + score -= 8; + else if (gBattleWeather & B_WEATHER_HAIL) + score -= 2; // mainly to prevent looping between hail and snow break; case EFFECT_ATTRACT: if (!AI_CanBeInfatuated(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], @@ -2803,6 +2812,13 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) RETURN_SCORE_PLUS(2); // our partner benefits from hail } break; + case EFFECT_SNOWSCAPE: + if (IsBattlerAlive(battlerAtkPartner) + && ShouldSetSnow(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect)) + { + RETURN_SCORE_PLUS(2); // our partner benefits from snow + } + break; } // global move effect check @@ -3965,6 +3981,22 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 2; } break; + case EFFECT_SNOWSCAPE: + if (ShouldSetSnow(battlerAtk, AI_DATA->abilities[battlerAtk], AI_DATA->holdEffects[battlerAtk])) + { + if ((HasMoveEffect(battlerAtk, EFFECT_AURORA_VEIL) || HasMoveEffect(BATTLE_PARTNER(battlerAtk), EFFECT_AURORA_VEIL)) + && ShouldSetScreen(battlerAtk, battlerDef, EFFECT_AURORA_VEIL)) + score += 3; + + score++; + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_ICY_ROCK) + score++; + if (HasMoveEffect(battlerDef, EFFECT_MORNING_SUN) + || HasMoveEffect(battlerDef, EFFECT_SYNTHESIS) + || HasMoveEffect(battlerDef, EFFECT_MOONLIGHT)) + score += 2; + } + break; case EFFECT_RAIN_DANCE: if (ShouldSetRain(battlerAtk, AI_DATA->abilities[battlerAtk], AI_DATA->holdEffects[battlerAtk])) { @@ -4948,6 +4980,7 @@ static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_SUNNY_DAY: case EFFECT_SANDSTORM: case EFFECT_HAIL: + case EFFECT_SNOWSCAPE: case EFFECT_GEOMANCY: case EFFECT_VICTORY_DANCE: case EFFECT_HIT_SET_ENTRY_HAZARD: @@ -5174,6 +5207,7 @@ static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_SUNNY_DAY: case EFFECT_SANDSTORM: case EFFECT_HAIL: + case EFFECT_SNOWSCAPE: case EFFECT_RAIN_DANCE: score -= 2; break; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index e187a06a98..13d70f28f2 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -331,6 +331,7 @@ static const u16 sEncouragedEncoreEffects[] = EFFECT_SPIT_UP, EFFECT_SWALLOW, EFFECT_HAIL, + EFFECT_SNOWSCAPE, EFFECT_TORMENT, EFFECT_WILL_O_WISP, EFFECT_FOLLOW_ME, @@ -1504,7 +1505,7 @@ bool32 IsMoveEncouragedToHit(u8 battlerAtk, u8 battlerDef, u16 move) // increased accuracy but don't always hit if ((AI_WeatherHasEffect() && (((gBattleWeather & B_WEATHER_RAIN) && (gBattleMoves[move].effect == EFFECT_THUNDER || gBattleMoves[move].effect == EFFECT_HURRICANE)) - || (((gBattleWeather & B_WEATHER_HAIL) && move == MOVE_BLIZZARD)))) + || (((gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && move == MOVE_BLIZZARD)))) || (gBattleMoves[move].effect == EFFECT_VITAL_THROW) #if B_MINIMIZE_DMG_ACC >= GEN_6 || ((gStatuses3[battlerDef] & STATUS3_MINIMIZED) && (gBattleMoves[move].flags & FLAG_DMG_MINIMIZE)) @@ -1579,7 +1580,7 @@ bool32 ShouldSetHail(u8 battler, u16 ability, u16 holdEffect) { if (!AI_WeatherHasEffect()) return FALSE; - else if (gBattleWeather & B_WEATHER_HAIL) + else if (gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) return FALSE; if (ability == ABILITY_SNOW_CLOAK @@ -1649,6 +1650,26 @@ bool32 ShouldSetSun(u8 battlerAtk, u16 atkAbility, u16 holdEffect) return FALSE; } +bool32 ShouldSetSnow(u8 battler, u16 ability, u16 holdEffect) +{ + if (!AI_WeatherHasEffect()) + return FALSE; + else if (gBattleWeather & (B_WEATHER_SNOW | B_WEATHER_HAIL)) + return FALSE; + + if (ability == ABILITY_SNOW_CLOAK + || ability == ABILITY_ICE_BODY + || ability == ABILITY_FORECAST + || ability == ABILITY_SLUSH_RUSH + || IS_BATTLER_OF_TYPE(battler, TYPE_ICE) + || HasMove(battler, MOVE_BLIZZARD) + || HasMoveEffect(battler, EFFECT_AURORA_VEIL) + || HasMoveEffect(battler, EFFECT_WEATHER_BALL)) + { + return TRUE; + } + return FALSE; +} void ProtectChecks(u8 battlerAtk, u8 battlerDef, u16 move, u16 predictedMove, s16 *score) { @@ -3137,7 +3158,7 @@ bool32 ShouldSetScreen(u8 battlerAtk, u8 battlerDef, u16 moveEffect) { case EFFECT_AURORA_VEIL: // Use only in Hail and only if AI doesn't already have Reflect, Light Screen or Aurora Veil itself active. - if (gBattleWeather & B_WEATHER_HAIL + if ((gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && !(gSideStatuses[atkSide] & (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL))) return TRUE; break; @@ -3242,7 +3263,8 @@ bool32 PartnerMoveEffectIsWeather(u8 battlerAtkPartner, u16 partnerMove) && (gBattleMoves[partnerMove].effect == EFFECT_SUNNY_DAY || gBattleMoves[partnerMove].effect == EFFECT_RAIN_DANCE || gBattleMoves[partnerMove].effect == EFFECT_SANDSTORM - || gBattleMoves[partnerMove].effect == EFFECT_HAIL)) + || gBattleMoves[partnerMove].effect == EFFECT_HAIL + || gBattleMoves[partnerMove].effect == EFFECT_SNOWSCAPE)) return TRUE; return FALSE; diff --git a/src/battle_anim_effects_3.c b/src/battle_anim_effects_3.c index 7d449c767e..4e510c59c7 100755 --- a/src/battle_anim_effects_3.c +++ b/src/battle_anim_effects_3.c @@ -5603,6 +5603,8 @@ void AnimTask_GetWeather(u8 taskId) gBattleAnimArgs[ARG_RET_ID] = ANIM_WEATHER_SANDSTORM; else if (gWeatherMoveAnim & B_WEATHER_HAIL) gBattleAnimArgs[ARG_RET_ID] = ANIM_WEATHER_HAIL; + else if (gWeatherMoveAnim & B_WEATHER_SNOW) + gBattleAnimArgs[ARG_RET_ID] = ANIM_WEATHER_SNOW; DestroyAnimVisualTask(taskId); } diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index c06a7795a5..b1187b59e7 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -492,6 +492,7 @@ static bool8 ShouldAnimBeDoneRegardlessOfSubstitute(u8 animId) case B_ANIM_SUN_CONTINUES: case B_ANIM_SANDSTORM_CONTINUES: case B_ANIM_HAIL_CONTINUES: + case B_ANIM_SNOW_CONTINUES: case B_ANIM_SNATCH_MOVE: return TRUE; default: diff --git a/src/battle_main.c b/src/battle_main.c index 91d5c3aa50..7270e0f369 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4642,7 +4642,7 @@ u32 GetBattlerTotalSpeedStat(u8 battlerId) speed *= 2; else if (ability == ABILITY_SAND_RUSH && gBattleWeather & B_WEATHER_SANDSTORM) speed *= 2; - else if (ability == ABILITY_SLUSH_RUSH && gBattleWeather & B_WEATHER_HAIL) + else if (ability == ABILITY_SLUSH_RUSH && (gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW))) speed *= 2; } @@ -5590,7 +5590,7 @@ void SetTypeBeforeUsingMove(u16 move, u8 battlerAtk) gBattleStruct->dynamicMoveType = TYPE_ROCK | F_DYNAMIC_TYPE_2; else if (gBattleWeather & B_WEATHER_SUN && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA) gBattleStruct->dynamicMoveType = TYPE_FIRE | F_DYNAMIC_TYPE_2; - else if (gBattleWeather & B_WEATHER_HAIL) + else if (gBattleWeather & (B_WEATHER_HAIL |B_WEATHER_SNOW)) gBattleStruct->dynamicMoveType = TYPE_ICE | F_DYNAMIC_TYPE_2; else gBattleStruct->dynamicMoveType = TYPE_NORMAL | F_DYNAMIC_TYPE_2; diff --git a/src/battle_message.c b/src/battle_message.c index be3442d6c3..94dc0d6707 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -365,6 +365,9 @@ static const u8 sText_SunlightFaded[] = _("The sunlight faded."); static const u8 sText_StartedHail[] = _("It started to hail!"); static const u8 sText_HailContinues[] = _("Hail continues to fall."); static const u8 sText_HailStopped[] = _("The hail stopped."); +static const u8 sText_StartedSnow[] = _("It started to snow!"); +static const u8 sText_SnowContinues[] = _("Snow continues to fall."); +static const u8 sText_SnowStopped[] = _("The snow stopped."); static const u8 sText_FailedToSpitUp[] = _("But it failed to spit up\na thing!"); static const u8 sText_FailedToSwallow[] = _("But it failed to swallow\na thing!"); static const u8 sText_WindBecameHeatWave[] = _("The wind turned into a\nHEAT WAVE!"); @@ -614,6 +617,7 @@ static const u8 sText_AnticipationActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFI static const u8 sText_ForewarnActivates[] = _("{B_SCR_ACTIVE_ABILITY} alerted {B_SCR_ACTIVE_NAME_WITH_PREFIX}\nto the {B_DEF_NAME_WITH_PREFIX}'s {B_BUFF1}!"); static const u8 sText_IceBodyHpGain[] = _("{B_ATK_NAME_WITH_PREFIX}'s {B_ATK_ABILITY}\nhealed it a little bit!"); static const u8 sText_SnowWarningHail[] = _("It started to hail!"); +static const u8 sText_SnowWarningSnow[] = _("It started to snow!"); static const u8 sText_FriskActivates[] = _("{B_ATK_NAME_WITH_PREFIX} frisked {B_DEF_NAME_WITH_PREFIX} and\nfound its {B_LAST_ITEM}!"); static const u8 sText_UnnerveEnters[] = _("The opposing team is too nervous\nto eat Berries!"); static const u8 sText_HarvestBerry[] = _("{B_ATK_NAME_WITH_PREFIX} harvested\nits {B_LAST_ITEM}!"); @@ -1143,6 +1147,9 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_STARTEDHAIL - BATTLESTRINGS_TABLE_START] = sText_StartedHail, [STRINGID_HAILCONTINUES - BATTLESTRINGS_TABLE_START] = sText_HailContinues, [STRINGID_HAILSTOPPED - BATTLESTRINGS_TABLE_START] = sText_HailStopped, + [STRINGID_STARTEDSNOW - BATTLESTRINGS_TABLE_START] = sText_StartedSnow, + [STRINGID_SNOWCONTINUES -BATTLESTRINGS_TABLE_START] = sText_SnowContinues, + [STRINGID_SNOWSTOPPED - BATTLESTRINGS_TABLE_START] = sText_SnowStopped, [STRINGID_FAILEDTOSPITUP - BATTLESTRINGS_TABLE_START] = sText_FailedToSpitUp, [STRINGID_FAILEDTOSWALLOW - BATTLESTRINGS_TABLE_START] = sText_FailedToSwallow, [STRINGID_WINDBECAMEHEATWAVE - BATTLESTRINGS_TABLE_START] = sText_WindBecameHeatWave, @@ -1363,6 +1370,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_FOREWARNACTIVATES - BATTLESTRINGS_TABLE_START] = sText_ForewarnActivates, [STRINGID_ICEBODYHPGAIN - BATTLESTRINGS_TABLE_START] = sText_IceBodyHpGain, [STRINGID_SNOWWARNINGHAIL - BATTLESTRINGS_TABLE_START] = sText_SnowWarningHail, + [STRINGID_SNOWWARNINGSNOW - BATTLESTRINGS_TABLE_START] = sText_SnowWarningSnow, [STRINGID_FRISKACTIVATES - BATTLESTRINGS_TABLE_START] = sText_FriskActivates, [STRINGID_UNNERVEENTERS - BATTLESTRINGS_TABLE_START] = sText_UnnerveEnters, [STRINGID_HARVESTBERRY - BATTLESTRINGS_TABLE_START] = sText_HarvestBerry, @@ -1559,12 +1567,14 @@ const u16 gMoveWeatherChangeStringIds[] = [B_MSG_STARTED_SANDSTORM] = STRINGID_SANDSTORMBREWED, [B_MSG_STARTED_SUNLIGHT] = STRINGID_SUNLIGHTGOTBRIGHT, [B_MSG_STARTED_HAIL] = STRINGID_STARTEDHAIL, + [B_MSG_STARTED_SNOW] = STRINGID_STARTEDSNOW, }; -const u16 gSandStormHailContinuesStringIds[] = +const u16 gSandStormHailSnowContinuesStringIds[] = { [B_MSG_SANDSTORM] = STRINGID_SANDSTORMRAGES, - [B_MSG_HAIL] = STRINGID_HAILCONTINUES + [B_MSG_HAIL] = STRINGID_HAILCONTINUES, + [B_MSG_SNOW] = STRINGID_SNOWCONTINUES, }; const u16 gSandStormHailDmgStringIds[] = @@ -1573,10 +1583,11 @@ const u16 gSandStormHailDmgStringIds[] = [B_MSG_HAIL] = STRINGID_PKMNPELTEDBYHAIL }; -const u16 gSandStormHailEndStringIds[] = +const u16 gSandStormHailSnowEndStringIds[] = { [B_MSG_SANDSTORM] = STRINGID_SANDSTORMSUBSIDED, - [B_MSG_HAIL] = STRINGID_HAILSTOPPED + [B_MSG_HAIL] = STRINGID_HAILSTOPPED, + [B_MSG_SNOW] = STRINGID_SNOWSTOPPED, }; const u16 gRainContinuesStringIds[] = diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 0842884311..955970539c 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1812,7 +1812,7 @@ static bool32 AccuracyCalcHelper(u16 move) return TRUE; } #if B_BLIZZARD_HAIL >= GEN_4 - else if ((gBattleWeather & B_WEATHER_HAIL) && move == MOVE_BLIZZARD) + else if ((gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && move == MOVE_BLIZZARD) { // thunder/hurricane ignore acc checks in rain unless target is holding utility umbrella JumpIfMoveFailed(7, move); @@ -1892,7 +1892,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u if (defAbility == ABILITY_SAND_VEIL && WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SANDSTORM) calc = (calc * 80) / 100; // 1.2 sand veil loss - else if (defAbility == ABILITY_SNOW_CLOAK && WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_HAIL) + else if (defAbility == ABILITY_SNOW_CLOAK && WEATHER_HAS_EFFECT && (gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW))) calc = (calc * 80) / 100; // 1.2 snow cloak loss else if (defAbility == ABILITY_TANGLED_FEET && gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) calc = (calc * 50) / 100; // 1.5 tangled feet loss @@ -5190,7 +5190,8 @@ static void Cmd_playanimation(void) else if (animId == B_ANIM_RAIN_CONTINUES || animId == B_ANIM_SUN_CONTINUES || animId == B_ANIM_SANDSTORM_CONTINUES - || animId == B_ANIM_HAIL_CONTINUES) + || animId == B_ANIM_HAIL_CONTINUES + || animId == B_ANIM_SNOW_CONTINUES) { BtlController_EmitBattleAnimation(BUFFER_A, animId, *argPtr); MarkBattlerForControllerExec(gActiveBattler); @@ -5239,7 +5240,8 @@ static void Cmd_playanimation_var(void) else if (*animIdPtr == B_ANIM_RAIN_CONTINUES || *animIdPtr == B_ANIM_SUN_CONTINUES || *animIdPtr == B_ANIM_SANDSTORM_CONTINUES - || *animIdPtr == B_ANIM_HAIL_CONTINUES) + || *animIdPtr == B_ANIM_HAIL_CONTINUES + || *animIdPtr == B_ANIM_SNOW_CONTINUES) { BtlController_EmitBattleAnimation(BUFFER_A, *animIdPtr, *argPtr); MarkBattlerForControllerExec(gActiveBattler); @@ -10250,7 +10252,7 @@ static void Cmd_various(void) { VARIOUS_ARGS(); if (gSideStatuses[GET_BATTLER_SIDE(gActiveBattler)] & SIDE_STATUS_AURORA_VEIL - || !(WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_HAIL)) + || !(WEATHER_HAS_EFFECT && gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW))) { gMoveResultFlags |= MOVE_RESULT_MISSED; gBattleCommunication[MULTISTRING_CHOOSER] = 0; @@ -12781,6 +12783,20 @@ static void Cmd_weatherdamage(void) gBattleMoveDamage = 1; } } + if (gBattleWeather & B_WEATHER_SNOW) + { + if (ability == ABILITY_ICE_BODY + && !(gStatuses3[gBattlerAttacker] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) + && !BATTLER_MAX_HP(gBattlerAttacker) + && !(gStatuses3[gBattlerAttacker] & STATUS3_HEAL_BLOCK)) + { + gBattlerAbility = gBattlerAttacker; + gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 16; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + } + } } gBattlescriptCurrInstr = cmd->nextInstr; @@ -16577,3 +16593,20 @@ void BS_ItemRestorePP(void) { PREPARE_SPECIES_BUFFER(gBattleTextBuff1, GetMonData(mon, MON_DATA_SPECIES)); gBattlescriptCurrInstr = cmd->nextInstr; } + +void BS_SetSnow(void) +{ + NATIVE_ARGS(); + + if (!TryChangeBattleWeather(gBattlerAttacker, ENUM_WEATHER_SNOW, FALSE)) + { + gMoveResultFlags |= MOVE_RESULT_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_FAILED; + + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_SNOW; + } + gBattlescriptCurrInstr = cmd->nextInstr; +} diff --git a/src/battle_tv.c b/src/battle_tv.c index f5c9f43c4e..7379b72e4b 100644 --- a/src/battle_tv.c +++ b/src/battle_tv.c @@ -251,6 +251,7 @@ static const u16 sPoints_MoveEffect[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_SWALLOW] = 3, // [EFFECT_UNUSED_A3] = 1, [EFFECT_HAIL] = 4, + [EFFECT_SNOWSCAPE] = 4, [EFFECT_TORMENT] = 7, [EFFECT_FLATTER] = 7, [EFFECT_WILL_O_WISP] = 5, @@ -1770,6 +1771,6 @@ static void AddPointsBasedOnWeather(u16 weatherFlags, u16 moveId, u8 moveSlot) AddMovePoints(PTS_SUN, moveId, moveSlot, 0); else if (weatherFlags & B_WEATHER_SANDSTORM) AddMovePoints(PTS_SANDSTORM, moveId, moveSlot, 0); - else if (weatherFlags & B_WEATHER_HAIL) + else if (weatherFlags & (B_WEATHER_HAIL | B_WEATHER_SNOW)) AddMovePoints(PTS_HAIL, moveId, moveSlot, 0); } diff --git a/src/battle_util.c b/src/battle_util.c index abdeed7569..cd65d58093 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2032,6 +2032,7 @@ enum ENDTURN_SANDSTORM, ENDTURN_SUN, ENDTURN_HAIL, + ENDTURN_SNOW, ENDTURN_GRAVITY, ENDTURN_WATER_SPORT, ENDTURN_MUD_SPORT, @@ -2340,7 +2341,7 @@ u8 DoFieldEndTurnEffects(void) if (!(gBattleWeather & B_WEATHER_SANDSTORM_PERMANENT) && --gWishFutureKnock.weatherDuration == 0) { gBattleWeather &= ~B_WEATHER_SANDSTORM_TEMPORARY; - gBattlescriptCurrInstr = BattleScript_SandStormHailEnds; + gBattlescriptCurrInstr = BattleScript_SandStormHailSnowEnds; } else { @@ -2380,7 +2381,7 @@ u8 DoFieldEndTurnEffects(void) if (!(gBattleWeather & B_WEATHER_HAIL_PERMANENT) && --gWishFutureKnock.weatherDuration == 0) { gBattleWeather &= ~B_WEATHER_HAIL_TEMPORARY; - gBattlescriptCurrInstr = BattleScript_SandStormHailEnds; + gBattlescriptCurrInstr = BattleScript_SandStormHailSnowEnds; } else { @@ -2394,6 +2395,26 @@ u8 DoFieldEndTurnEffects(void) } gBattleStruct->turnCountersTracker++; break; + case ENDTURN_SNOW: + if (gBattleWeather & B_WEATHER_SNOW) + { + if (!(gBattleWeather & B_WEATHER_SNOW_PERMANENT) && --gWishFutureKnock.weatherDuration == 0) + { + gBattleWeather &= ~B_WEATHER_SNOW_TEMPORARY; + gBattlescriptCurrInstr = BattleScript_SandStormHailSnowEnds; + } + else + { + gBattlescriptCurrInstr = BattleScript_DamagingWeatherContinues; + } + + gBattleScripting.animArg1 = B_ANIM_SNOW_CONTINUES; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SNOW; + BattleScriptExecute(gBattlescriptCurrInstr); + effect++; + } + gBattleStruct->turnCountersTracker++; + break; case ENDTURN_TRICK_ROOM: if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && --gFieldTimers.trickRoomTimer == 0) { @@ -4032,7 +4053,7 @@ u8 TryWeatherFormChange(u8 battler) } } #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))) + else if (holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA || (!(gBattleWeather & (B_WEATHER_RAIN | B_WEATHER_SUN | B_WEATHER_HAIL | B_WEATHER_SNOW)) && !IS_BATTLER_OF_TYPE(battler, TYPE_NORMAL))) { SET_BATTLER_TYPE(battler, TYPE_NORMAL); ret = CASTFORM_NORMAL + 1; @@ -4047,7 +4068,7 @@ u8 TryWeatherFormChange(u8 battler) SET_BATTLER_TYPE(battler, TYPE_WATER); ret = CASTFORM_WATER + 1; } - else if (gBattleWeather & B_WEATHER_HAIL && !IS_BATTLER_OF_TYPE(battler, TYPE_ICE)) + else if (gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW) && !IS_BATTLER_OF_TYPE(battler, TYPE_ICE)) { SET_BATTLER_TYPE(battler, TYPE_ICE); ret = CASTFORM_ICE + 1; @@ -4083,6 +4104,7 @@ static const u16 sWeatherFlagsInfo[][3] = [ENUM_WEATHER_SANDSTORM] = {B_WEATHER_SANDSTORM_TEMPORARY, B_WEATHER_SANDSTORM_PERMANENT, HOLD_EFFECT_SMOOTH_ROCK}, [ENUM_WEATHER_HAIL] = {B_WEATHER_HAIL_TEMPORARY, B_WEATHER_HAIL_PERMANENT, HOLD_EFFECT_ICY_ROCK}, [ENUM_WEATHER_STRONG_WINDS] = {B_WEATHER_STRONG_WINDS, B_WEATHER_STRONG_WINDS, HOLD_EFFECT_NONE}, + [ENUM_WEATHER_SNOW] = {B_WEATHER_SNOW_TEMPORARY, B_WEATHER_SNOW_PERMANENT, HOLD_EFFECT_ICY_ROCK}, }; static void ShouldChangeFormInWeather(u8 battler) @@ -4103,7 +4125,6 @@ static void ShouldChangeFormInWeather(u8 battler) bool32 TryChangeBattleWeather(u8 battler, u32 weatherEnumId, bool32 viaAbility) { u16 battlerAbility = GetBattlerAbility(battler); - if (gBattleWeather & B_WEATHER_PRIMAL_ANY && battlerAbility != ABILITY_DESOLATE_LAND && battlerAbility != ABILITY_PRIMORDIAL_SEA @@ -4129,7 +4150,6 @@ bool32 TryChangeBattleWeather(u8 battler, u32 weatherEnumId, bool32 viaAbility) ShouldChangeFormInWeather(battler); return TRUE; } - return FALSE; } @@ -4634,11 +4654,19 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move } break; case ABILITY_SNOW_WARNING: - if (TryChangeBattleWeather(battler, ENUM_WEATHER_HAIL, TRUE)) + #if B_SNOW_WARNING >= GEN_9 + if (TryChangeBattleWeather(battler, ENUM_WEATHER_SNOW, TRUE)) { - BattleScriptPushCursorAndCallback(BattleScript_SnowWarningActivates); + BattleScriptPushCursorAndCallback(BattleScript_SnowWarningActivatesSnow); effect++; } + #else + if (TryChangeBattleWeather(battler, ENUM_WEATHER_HAIL, TRUE)) + { + BattleScriptPushCursorAndCallback(BattleScript_SnowWarningActivatesHail); + effect++; + } + #endif else if (gBattleWeather & B_WEATHER_PRIMAL_ANY && WEATHER_HAS_EFFECT && !gSpecialStatuses[battler].switchInAbilityDone) { gSpecialStatuses[battler].switchInAbilityDone = TRUE; @@ -6111,7 +6139,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move } break; case ABILITY_ICE_FACE: - if (IsBattlerWeatherAffected(battler, B_WEATHER_HAIL) + if (IsBattlerWeatherAffected(battler, B_WEATHER_HAIL | B_WEATHER_SNOW) && gBattleMons[battler].species == SPECIES_EISCUE_NOICE_FACE && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && gBattleStruct->allowedToChangeFormInWeather[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)]) @@ -9125,7 +9153,7 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe MulModifier(&modifier, UQ_4_12(2.0)); break; case EFFECT_SOLAR_BEAM: - if (IsBattlerWeatherAffected(battlerAtk, (B_WEATHER_HAIL | B_WEATHER_SANDSTORM | B_WEATHER_RAIN))) + if (IsBattlerWeatherAffected(battlerAtk, (B_WEATHER_HAIL | B_WEATHER_SANDSTORM | B_WEATHER_RAIN | B_WEATHER_SNOW))) MulModifier(&modifier, UQ_4_12(0.5)); break; case EFFECT_STOMPING_TANTRUM: @@ -9530,6 +9558,9 @@ static u32 CalcDefenseStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, // sandstorm sp.def boost for rock types if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_ROCK) && gBattleWeather & B_WEATHER_SANDSTORM && WEATHER_HAS_EFFECT && !usesDefStat) MulModifier(&modifier, UQ_4_12(1.5)); + // snow def boost for ice types + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_ICE) && gBattleWeather & B_WEATHER_SNOW && WEATHER_HAS_EFFECT && usesDefStat) + MulModifier(&modifier, UQ_4_12(1.5)); // The defensive stats of a Player's Pokémon are boosted by x1.1 (+10%) if they have the 5th badge and 7th badges. // Having the 5th badge boosts physical defense while having the 7th badge boosts special defense. diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 4d04c743fd..b30f62a684 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -13356,7 +13356,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = [MOVE_SNOWSCAPE] = { - .effect = EFFECT_HAIL, + .effect = EFFECT_SNOWSCAPE, .power = 0, .type = TYPE_ICE, .accuracy = 0, diff --git a/src/data/text/abilities.h b/src/data/text/abilities.h index 96407c3409..a3bad09b1b 100644 --- a/src/data/text/abilities.h +++ b/src/data/text/abilities.h @@ -79,7 +79,7 @@ static const u8 sTangledFeetDescription[] = _("Ups evasion if confused."); static const u8 sMotorDriveDescription[] = _("Electricity raises Speed."); static const u8 sRivalryDescription[] = _("Powers up against rivals."); static const u8 sSteadfastDescription[] = _("Flinching raises Speed."); -static const u8 sSnowCloakDescription[] = _("Ups evasion in Hail."); +static const u8 sSnowCloakDescription[] = _("Ups evasion in Hail or Snow."); static const u8 sGluttonyDescription[] = _("Eats Berries early."); static const u8 sAngerPointDescription[] = _("Critical hits raise Attack."); static const u8 sUnburdenDescription[] = _("Using a hold item ups Speed."); @@ -113,8 +113,12 @@ static const u8 sFilterDescription[] = _("Weakens “supereffective”."); static const u8 sSlowStartDescription[] = _("Takes a while to get going."); static const u8 sScrappyDescription[] = _("Hits Ghost-type Pokémon."); static const u8 sStormDrainDescription[] = _("Draws in Water moves."); -static const u8 sIceBodyDescription[] = _("Slight HP recovery in Hail."); -static const u8 sSnowWarningDescription[] = _("Summons a hailstorm."); +static const u8 sIceBodyDescription[] = _("HP recovery in Hail or Snow."); +#if B_SNOW_WARNING < GEN_9 +static const u8 sSnowWarningDescription[] = _("Summons a Hailstorm."); +#elif B_SNOW_WARNING >= GEN_9 +static const u8 sSnowWarningDescription[] = _("Summons a Snowstorm."); +#endif static const u8 sHoneyGatherDescription[] = _("May gather Honey."); static const u8 sFriskDescription[] = _("Checks a foe's item."); static const u8 sRecklessDescription[] = _("Boosts moves with recoil."); @@ -192,7 +196,7 @@ static const u8 sStakeoutDescription[] = _("Stronger as foes switch in."); static const u8 sWaterBubbleDescription[] = _("Guards from fire and burns."); static const u8 sSteelworkerDescription[] = _("Powers up Steel moves."); static const u8 sBerserkDescription[] = _("Boosts Sp. Atk at low HP."); -static const u8 sSlushRushDescription[] = _("Raises Speed in hail."); +static const u8 sSlushRushDescription[] = _("Raises Speed in Hail or Snow."); static const u8 sLongReachDescription[] = _("Never makes contact."); static const u8 sLiquidVoiceDescription[] = _("Makes sound moves Water."); static const u8 sTriageDescription[] = _("Healing moves go first."); @@ -234,7 +238,7 @@ static const u8 sPunkRockDescription[] = _("Ups and resists sound."); static const u8 sSandSpitDescription[] = _("Creates a sandstorm if hit."); static const u8 sIceScalesDescription[] = _("Halves special damage."); static const u8 sRipenDescription[] = _("Doubles effect of Berries."); -static const u8 sIceFaceDescription[] = _("Take a free hit. Hail renews."); +static const u8 sIceFaceDescription[] = _("Hail or Snow renew free hit."); static const u8 sPowerSpotDescription[] = _("Powers up ally moves."); static const u8 sMimicryDescription[] = _("Changes type on terrain."); static const u8 sScreenCleanerDescription[] = _("Removes walls of light."); diff --git a/test/ability_snow_warning.c b/test/ability_snow_warning.c new file mode 100644 index 0000000000..200a14acaf --- /dev/null +++ b/test/ability_snow_warning.c @@ -0,0 +1,24 @@ +#include "global.h" +#include "test_battle.h" + +#if B_SNOW_WARNING < GEN_9 +SINGLE_BATTLE_TEST("Snow Warning summons hail") +#elif B_SNOW_WARNING >= GEN_9 +SINGLE_BATTLE_TEST("Snow Warning summons snow") +#endif +{ + GIVEN { + PLAYER(SPECIES_ABOMASNOW) { Ability(ABILITY_SNOW_WARNING); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN {} + } SCENE { + #if B_SNOW_WARNING < GEN_9 + MESSAGE("It started to hail!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HAIL_CONTINUES); + #elif B_SNOW_WARNING >= GEN_9 + MESSAGE("It started to snow!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_SNOW_CONTINUES); + #endif + } +} diff --git a/test/weather_snow.c b/test/weather_snow.c new file mode 100644 index 0000000000..d313c921bb --- /dev/null +++ b/test/weather_snow.c @@ -0,0 +1,157 @@ +#include "global.h" +#include "test_battle.h" + +#define TEST_HP 1 +#define MAX_HP 400 + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_SNOWSCAPE].effect == EFFECT_SNOWSCAPE); + ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_ICE && gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_ICE); + ASSUME(gSpeciesInfo[SPECIES_GLALIE].types[0] == TYPE_ICE || gSpeciesInfo[SPECIES_GLALIE].types[1] == TYPE_ICE); +} + +SINGLE_BATTLE_TEST("Snow increases the defense of Ice types by 50 %", s16 damage) +{ + u16 move; + PARAMETRIZE{ move = MOVE_SNOWSCAPE; } + PARAMETRIZE{ move = MOVE_CELEBRATE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GLALIE); + } WHEN { + TURN { MOVE(opponent, move); } + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + 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("Snow turns Weather Ball to an Ice-type move and doubles its power", s16 damage) +{ + u16 move; + PARAMETRIZE{ move = MOVE_CELEBRATE; } + PARAMETRIZE{ move = MOVE_SNOWSCAPE; } + GIVEN { + ASSUME(gBattleMoves[MOVE_WEATHER_BALL].effect == EFFECT_WEATHER_BALL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_DRAGONAIR); + } WHEN { + TURN { MOVE(player, move); } + TURN { MOVE(player, MOVE_WEATHER_BALL); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(4.0), results[1].damage); // double base power + type effectiveness. + } +} + +SINGLE_BATTLE_TEST("Snow allows Blizzard to bypass accuracy checks") +{ + PASSES_RANDOMLY(100, 100); + GIVEN { + ASSUME(gBattleMoves[MOVE_BLIZZARD].accuracy == 70); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SNOWSCAPE); MOVE(player, MOVE_BLIZZARD); } + } SCENE { + NONE_OF { MESSAGE("Wobbuffet's attack missed!"); } + } +} + +SINGLE_BATTLE_TEST("Snow halves the power of Solar Beam", s16 damage) +{ + u16 move; + PARAMETRIZE{ move = MOVE_CELEBRATE; } + PARAMETRIZE{ move = MOVE_SNOWSCAPE; } + GIVEN { + ASSUME(gBattleMoves[MOVE_SOLAR_BEAM].effect == EFFECT_SOLAR_BEAM); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BEAM); } + TURN { SKIP_TURN(player); } + } SCENE { + 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("Snow halves the power of Solar Blade", s16 damage) +{ + u16 move; + KNOWN_FAILING; // fails bc the bp of solar blade gets rounded up which leads to slightly incorrect calcs down the line + PARAMETRIZE{ move = MOVE_CELEBRATE; } + PARAMETRIZE{ move = MOVE_SNOWSCAPE; } + GIVEN { + ASSUME(gBattleMoves[MOVE_SOLAR_BLADE].effect == EFFECT_SOLAR_BEAM); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BLADE); } + TURN { SKIP_TURN(player); } + } SCENE { + 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("Snow causes Moonlight to recover 1/4 of the user's max HP") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_MOONLIGHT].effect == EFFECT_MOONLIGHT); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SNOWSCAPE); MOVE(player, MOVE_MOONLIGHT); } + } SCENE { + HP_BAR(player, hp: TEST_HP + (MAX_HP/4)); + } +} + +SINGLE_BATTLE_TEST("Snow causes Moonlight to recover 1/4 of the user's max HP") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_MOONLIGHT].effect == EFFECT_MOONLIGHT); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SNOWSCAPE); MOVE(player, MOVE_MOONLIGHT); } + } SCENE { + HP_BAR(player, hp: TEST_HP + (MAX_HP/4)); + } +} + +SINGLE_BATTLE_TEST("Snow causes Synthesis to recover 1/4 of the user's max HP") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_SYNTHESIS].effect == EFFECT_SYNTHESIS); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SNOWSCAPE); MOVE(player, MOVE_SYNTHESIS); } + } SCENE { + HP_BAR(player, hp: TEST_HP + (MAX_HP/4)); + } +} + +SINGLE_BATTLE_TEST("Snow causes Morning Sun to recover 1/4 of the user's max HP") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_MORNING_SUN].effect == EFFECT_MORNING_SUN); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SNOWSCAPE); MOVE(player, MOVE_MORNING_SUN); } + } SCENE { + HP_BAR(player, hp: TEST_HP + (MAX_HP/4)); + } +} + +#undef MAX_HP +#undef TEST_HP