- 17
- Posts
- 4
- Years
- Seen Jan 4, 2025
[BATTLE MECHANICS A]
Ever grown tired of the same few weather effects? Wish some from Mystery Dungeon were implemented?
Feeling devilish to bring back Gen 4 fog?
Fortunately I've managed to figure how to add more weathers for battle effects. Special thanks to Ghoulslash for helping me with the Various ptrs
So we'll begin with a relatively simple weather effect: Cloudy
here's the gist of the effect;
And visual
*Note for people using Battle Expansion: the AI has been rehauled massively. I'll make a new post for it later
*Also this doesn't cover adding Castform forms. Believe me, I tried
Now for code...
For defining it:
We can now move on to actually implementing the weather, animation for it, the AI in response to it, and text strings
For anim scripts:
We can move on to how the AI reacts to the changed weather
AI (note, current Battle Expansion is all in a C file, so see next post for AI mechanics)
In data/battle_ai_scripts.s, where the Badmove checks are in place
Along with
And in AI_CheckViability
Finally near weather effects (this is a doozy given this weakens most types)
*Note: Smooth Rock is from earlier Battle Engine Commits. You can ignore it
Then in src/data/battle_ai_script_commands.c in Cmd_get_weather[/COLOR
Vanilla:
Battle Expansion:
Now for text edits
In src/battle_message.c, with the other static consts
Then with STRING_IDs in the gBattleStringsTable
And gMoveWeatherChangeStringIds
And finally if you implement Overworld weather, you can associate it. I used WEATHER_SHADE
We finally get to the meat of weather mechanics
in src/battle_main.c change this
To this
then for Weather Ball for Battle Expansion
For this weather since it's about nerfing attacks we're "done" for battle_main, but say you want to increase/decrease speed of a mon, like how Mystery Dungeon does for Ice types in Snow?
Fear not, scroll back up to here and add your effects
Vanilla:
(Note, this is if you have a Snow weather set)
For Battle Expansion:
With that done, head to src/battle_script_commands.c, and in Cmd_playanimation and Cmd_playanimation_var(Vanilla) Cmd_playanimation2(Battle Expansion) where the other weather anims are defined
Finally (well for Battle Expansion, Vanilla needs 1 more file tweaked), in various
And for Vanilla, weather ball tweaks, in static void Cmd_setweatherballtype
If you're curious, weather effects for accuracy (like Thunder/Blizzard) are here in battle_script_commands.c
And in the last file, in src/battle_util.c, in the enum after GetImprisonedMovesCount
In DoFieldEndTurnEffects, add a case before ENDTURN_FIELD_COUNT
Vanilla:
Battle Expansion:
If Battle Expansion and Item Expansion are used, in static const u32 sWeatherFlagsInfo[][3] for the rocks
Then in the u8 AbilityBattleEffects Cases for the weather, to link to Overworld weather
From this point, Battle Expansion and Vanilla have parted ways
For Vanilla, go to src/pokemon.c
in if(WEATHER_HAS_EFFECT2), add the following
Then for Solarbeam, you can simply add the weather
For Battle Expansion, where move effects and weather weakening are in battle_util.c still
With other move effect cases
With other type move weakening
And there you have it. If you want to make it into a move like Rain Dance, or weather ability, you can simply copy what Vanilla/Battle Expansion does for the original weather types (we already established EFFECT_CLOUDY, so go nuts in src/data/battle_moves.h)
Otherwise, you can view the effect in battle like so:
Where despite the major level difference, Mud Slap doesn't cut a third of health due to being weakened
Ever grown tired of the same few weather effects? Wish some from Mystery Dungeon were implemented?
Feeling devilish to bring back Gen 4 fog?
Fortunately I've managed to figure how to add more weathers for battle effects. Special thanks to Ghoulslash for helping me with the Various ptrs
So we'll begin with a relatively simple weather effect: Cloudy
here's the gist of the effect;
All moves that aren't Normal or Dark type will be weakened
And visual
![[PokeCommunity.com] [TUTORIAL] Adding New Weather [PokeCommunity.com] [TUTORIAL] Adding New Weather](https://cdn.discordapp.com/attachments/419213926245335041/904116206221525044/se.gif)
*Note for people using Battle Expansion: the AI has been rehauled massively. I'll make a new post for it later
*Also this doesn't cover adding Castform forms. Believe me, I tried
Now for code...
For defining it:
Spoiler:
In asm/macros/battle_script.inc, near where the other [various] commands are, add the following
You're probably wondering why this isn't near the other setweather macros. There's unfortunately no more room, so we're placing it in various. Battle Expansion uses Various macros due to this
Speaking of no more room, in include/battle.h, change
to
Since we made a new [various] command, we need to define it. Go to include/constants/battle_script_commands.h
And for the effect, in include/constants/battle_move_effects.h
Our flags are expanded, so in include/constants/battle.h, where the other Weather flags are set
Vanilla:
Note that WEATHER_ANY needs to be expanded as well
For Battle Expansion:
Note that WEATHER_ANY needs to be expanded as well
As well as adding the weather to Enums if you're using the Battle Expansion
Similarly for the AI, in include/constants/battle_ai.h
Setting an anim tag will help. In include/contants/battle_anim.h
As well as the general weather tag
the weathers have 3 parts (starting, continuing, and ending). We did starting, so in include/battle_scripts.h
Then head over to data/battle_scripts_1.s and insert this block (preferably near other weather effects)
Now we need to define text strings for changing weather
In include/constants/battle_string_ids.h
Along with
Code:
[COLOR="Green"].macro setcloudy ptr:req
various BS_ATTACKER, VARIOUS_SETCLOUDY
.4byte \ptr
.endm[/COLOR]
Speaking of no more room, in include/battle.h, change
Code:
[COLOR="DarkRed"]-extern u16 gBattleWeather;[/COLOR]
Code:
[COLOR="Green"]extern u32 gBattleWeather;[/COLOR]
Code:
#define VARIOUS_PALACE_TRY_ESCAPE_STATUS 24
#define VARIOUS_SET_TELEPORT_OUTCOME 25
#define VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC 26
[COLOR="Green"]#define VARIOUS_SETCLOUDY 27[/COLOR]
Code:
#define EFFECT_CALM_MIND 211
#define EFFECT_DRAGON_DANCE 212
#define EFFECT_CAMOUFLAGE 213
[COLOR="Green"]#define EFFECT_CLOUDY 214[/COLOR]
[COLOR="DarkRed"]-#define NUM_BATTLE_MOVE_EFFECTS 214[/COLOR]
[COLOR="Green"]#define NUM_BATTLE_MOVE_EFFECTS 215[/COLOR]
Vanilla:
Code:
#define B_WEATHER_HAIL_TEMPORARY (1 << 7)
#define B_WEATHER_HAIL_PERMANENT (1 << 8)
#define B_WEATHER_HAIL (B_WEATHER_HAIL_TEMPORARY | B_WEATHER_HAIL_PERMANENT)
[COLOR="Green"]#define B_WEATHER_CLOUDY_TEMPORARY (1 << 9)
#define B_WEATHER_CLOUDY_PERMANENT (1 << 10
#define B_WEATHER_CLOUDY (B_WEATHER_CLOUDY_TEMPORARY | B_WEATHER_CLOUDY_PERMANENT)[/COLOR]
Code:
#define WEATHER_ANY (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_SUN | B_WEATHER_HAIL [COLOR="Green"]| B_WEATHER_CLOUDY[/COLOR])
For Battle Expansion:
Code:
#define WEATHER_HAIL_TEMPORARY (1 << 7)
#define WEATHER_HAIL_PERMANENT (1 << 8)
#define WEATHER_HAIL (WEATHER_HAIL_TEMPORARY | WEATHER_HAIL_PERMANENT)
[COLOR="Green"]#define WEATHER_CLOUDY_TEMPORARY (1 << 9)
#define WEATHER_CLOUDY_PERMANENT (1 << 10
#define WEATHER_CLOUDY_ANY (WEATHER_CLOUDY_TEMPORARY | WEATHER_CLOUDY_PERMANENT)[/COLOR]
Code:
#define WEATHER_ANY (WEATHER_RAIN_ANY | WEATHER_SANDSTORM_ANY | WEATHER_SUN_ANY | WEATHER_HAIL_ANY [COLOR="Green"]| WEATHER_CLOUDY_ANY[/COLOR])
Code:
#define ENUM_WEATHER_SANDSTORM 3
#define ENUM_WEATHER_HAIL 4
[COLOR="Green"]#define ENUM_WEATHER_CLOUDY 5[/COLOR]
Code:
#define AI_WEATHER_RAIN 1
#define AI_WEATHER_SANDSTORM 2
#define AI_WEATHER_HAIL 3
[COLOR="Green"]#define AI_WEATHER_CLOUDY 4[/COLOR]
Setting an anim tag will help. In include/contants/battle_anim.h
Code:
#define B_ANIM_RAIN_CONTINUES 10
#define B_ANIM_SUN_CONTINUES 11
#define B_ANIM_SANDSTORM_CONTINUES 12
#define B_ANIM_HAIL_CONTINUES 13
#define B_ANIM_LEECH_SEED_DRAIN 14
#define B_ANIM_MON_HIT 15
#define B_ANIM_ITEM_STEAL 16
#define B_ANIM_SNATCH_MOVE 17
#define B_ANIM_FUTURE_SIGHT_HIT 18
#define B_ANIM_DOOM_DESIRE_HIT 19
#define B_ANIM_FOCUS_PUNCH_SETUP 20
#define B_ANIM_INGRAIN_HEAL 21
#define B_ANIM_WISH_HEAL 22
[COLOR="Green"]#define B_ANIM_CLOUDY_CONTINUES 23[/COLOR]
Code:
#define ANIM_WEATHER_RAIN 2
#define ANIM_WEATHER_SANDSTORM 3
#define ANIM_WEATHER_HAIL 4
[COLOR="Green"]#define ANIM_WEATHER_CLOUDY 5[/COLOR]
the weathers have 3 parts (starting, continuing, and ending). We did starting, so in include/battle_scripts.h
Code:
extern const u8 BattleScript_ActionWatchesCarefully[];
extern const u8 BattleScript_ActionGetNear[];
extern const u8 BattleScript_ActionThrowPokeblock[];
[COLOR="Green"]extern const u8 BattleScript_CloudyContinues[];
extern const u8 BattleScript_CloudyEnd[];[/COLOR]
Then head over to data/battle_scripts_1.s and insert this block (preferably near other weather effects)
Code:
[COLOR="Green"]BattleScript_EffectCloudy::
attackcanceler
attackstring
ppreduce
setwind BattleScript_ButItFailed
goto BattleScript_MoveWeatherChange[/COLOR]
Now we need to define text strings for changing weather
In include/constants/battle_string_ids.h
Code:
#define STRINGID_PKMNBOXLANETTESPCFULL 378
#define STRINGID_TRAINER1WINTEXT 379
#define STRINGID_TRAINER2WINTEXT 380
[COLOR="Green"]#define STRINGID_STARTEDCLOUDY 381
#define STRINGID_CLOUDYCONTINUES 382
#define STRINGID_CLOUDYSTOPPED 383[/COLOR]
Along with
Code:
#define B_MSG_WEATHER_FAILED 2
#define B_MSG_STARTED_SANDSTORM 3
#define B_MSG_STARTED_SUNLIGHT 4
#define B_MSG_STARTED_HAIL 5
[COLOR="Green"]#define B_MSG_STARTED_CLOUDY 6[/COLOR]
We can now move on to actually implementing the weather, animation for it, the AI in response to it, and text strings
For anim scripts:
Spoiler:
Weathers are done the same way moves are. The main difference is that having weather be battler position dependent typically causes it to look wonky
Here for Cloudy we'll simply dim the screen
in data/battle_anim_scripts.s, define a new general battle anim in gBattleAnims_General
Scrolling down to where other weather effects are, insert this
Basically this dims the field, lasts for 65 frames (around 1 second), then fade back
Typically that's enough, but Weather Ball exists. So tweak it
Admittedly you can make it snazzier, but it's functionally well suited. If you're adding other weather, remember weather ball
For linking the anim to the weather
in src/battle_anim_effects_3.c, where the AnimTask for getting weather is
Then in src/battle_gfx_sfx_util.c for the Substitute switch case
Here for Cloudy we'll simply dim the screen
in data/battle_anim_scripts.s, define a new general battle anim in gBattleAnims_General
Code:
.4byte General_DoomDesireHit @ B_ANIM_DOOM_DESIRE_HIT
.4byte General_FocusPunchSetUp @ B_ANIM_FOCUS_PUNCH_SETUP
.4byte General_IngrainHeal @ B_ANIM_INGRAIN_HEAL
.4byte General_WishHeal @ B_ANIM_WISH_HEAL
[COLOR="Green"].4byte General_Encloud @B_ANIM_CLOUDY[/COLOR]
Scrolling down to where other weather effects are, insert this
Code:
[COLOR="Green"]General_Encloud::
createvisualtask AnimTask_HardwarePaletteFade, 2, 248, 3, 0, 10, 0
waitforvisualfinish
playsewithpan SE_M_FAINT_ATTACK, SOUND_PAN_ATTACKER
waitsound
delay 65
createvisualtask AnimTask_HardwarePaletteFade, 2, 248, 3, 10, 0, 1
waitforvisualfinish
end[/COLOR]
Basically this dims the field, lasts for 65 frames (around 1 second), then fade back
Typically that's enough, but Weather Ball exists. So tweak it
Code:
jumpreteq ANIM_WEATHER_NONE, WeatherBallNormal
jumpreteq ANIM_WEATHER_SUN, WeatherBallFire
jumpreteq ANIM_WEATHER_RAIN, WeatherBallWater
jumpreteq ANIM_WEATHER_SANDSTORM, WeatherBallSandstorm
jumpreteq ANIM_WEATHER_HAIL, WeatherBallIce
[COLOR="Green"] jumpreteq ANIM_WEATHER_CLOUDY, WeatherBallNormal[/COLOR]
Admittedly you can make it snazzier, but it's functionally well suited. If you're adding other weather, remember weather ball
For linking the anim to the weather
in src/battle_anim_effects_3.c, where the AnimTask for getting weather is
Code:
else if (gWeatherMoveAnim & WEATHER_SANDSTORM_ANY)
gBattleAnimArgs[ARG_RET_ID] = ANIM_WEATHER_SANDSTORM;
else if (gWeatherMoveAnim & WEATHER_HAIL_ANY)
gBattleAnimArgs[ARG_RET_ID] = ANIM_WEATHER_HAIL;
[COLOR="Green"]else if (gWeatherMoveAnim & WEATHER_CLOUDY_ANY)
gBattleAnimArgs[ARG_RET_ID] = ANIM_WEATHER_CLOUDY;[/COLOR]
Then in src/battle_gfx_sfx_util.c for the Substitute switch case
Code:
switch (animId)
{
case B_ANIM_SUBSTITUTE_FADE:
case B_ANIM_RAIN_CONTINUES:
case B_ANIM_SUN_CONTINUES:
case B_ANIM_SANDSTORM_CONTINUES:
case B_ANIM_HAIL_CONTINUES:
[COLOR="Green"] case B_ANIM_CLOUDY_CONTINUES:[/COLOR]
case B_ANIM_SNATCH_MOVE:
return TRUE;
default:
return FALSE;
}
We can move on to how the AI reacts to the changed weather
AI (note, current Battle Expansion is all in a C file, so see next post for AI mechanics)
Spoiler:
In data/battle_ai_scripts.s, where the Badmove checks are in place
Code:
if_effect EFFECT_WATER_SPORT, AI_CBM_WaterSport
if_effect EFFECT_CALM_MIND, AI_CBM_CalmMind
if_effect EFFECT_DRAGON_DANCE, AI_CBM_DragonDance
[COLOR="Green"]if_effect EFFECT_CLOUDY, AI_CBM_Cloudy
if_effect EFFECT_CLOUDY, AI_CBM_Cloudy[/COLOR]
end
Along with
Code:
[COLOR="Green"]AI_CBM_Cloudy: @ 82DC661
get_weather
if_equal AI_WEATHER_CLOUDY, Score_Minus8
end[/COLOR]
And in AI_CheckViability
Code:
if_effect EFFECT_WATER_SPORT, AI_CV_WaterSport
if_effect EFFECT_CALM_MIND, AI_CV_SpDefUp
if_effect EFFECT_DRAGON_DANCE, AI_CV_DragonDance
[COLOR="Green"]if_effect EFFECT_CLOUDY, AI_CV_Cloudy[/COLOR]
Finally near weather effects (this is a doozy given this weakens most types)
*Note: Smooth Rock is from earlier Battle Engine Commits. You can ignore it
Code:
[COLOR="Green"]AI_CV_Cloudy:
get_weather
if_equal AI_WEATHER_CLOUDY, AI_CV_Cloudy_End
if_user_faster AI_CV_Cloudy2
AI_CV_Cloudy2:
if_hp_less_than AI_USER, 40, AI_CV_Cloudy_ScoreDown1
get_weather
if_equal AI_WEATHER_HAIL, AI_CV_Cloudy3
if_equal AI_WEATHER_SUN, AI_CV_Cloudy3
if_equal AI_WEATHER_SANDSTORM, AI_CV_Cloudy3
if_equal AI_WEATHER_WIND, AI_CV_Cloudy3
if_equal AI_WEATHER_FOG, AI_CV_Cloudy3
if_equal AI_WEATHER_SNOW, AI_CV_Cloudy3
AI_CV_Cloudy3:
score +1
goto AI_CV_Cloudy_Rock
AI_CV_Cloudy_ScoreDown1:
score -1
AI_CV_Cloudy_Rock:
get_hold_effect AI_USER
if_not_equal HOLD_EFFECT_SMOOTH_ROCK, AI_CV_Cloudy_Opponent
score +2
AI_CV_Cloudy_Opponent:
if_has_move_with_type AI_TARGET, TYPE_ELECTRIC, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_ELECTRIC, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_ICE, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_ICE, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_ROCK, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_ROCK, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_FIGHTING, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_FIGHTING, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_PSYCHIC, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_PSYCHIC, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_DARK, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_DARK, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_FLYING, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_FLYING, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_BUG, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_BUG, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_STEEL, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_STEEL, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_GHOST, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_GHOST, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_DRAGON, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_DRAGON, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_POISON, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_POISON, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_GROUND, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_GROUND, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_GRASS, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_GRASS, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_WATER, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_WATER, AI_CV_Cloudy_End
if_has_move_with_type AI_TARGET, TYPE_FIRE, AI_CV_Cloudy_OpponentPlus
if_no_type AI_TARGET, TYPE_FIRE, AI_CV_Cloudy_End
AI_CV_Cloudy_OpponentPlus:
score +1
AI_CV_Cloudy_End:
end[/COLOR]
Then in src/data/battle_ai_script_commands.c in Cmd_get_weather[/COLOR
Vanilla:
Code:
if (gBattleWeather & B_WEATHER_SUN)
AI_THINKING_STRUCT->funcResult = AI_WEATHER_SUN;
if (gBattleWeather & B_WEATHER_HAIL)
AI_THINKING_STRUCT->funcResult = AI_WEATHER_HAIL;
if (gBattleWeather & B_WEATHER_CLOUDY)
AI_THINKING_STRUCT->funcResult = AI_WEATHER_CLOUDY;
[COLOR="Green"]if (gBattleWeather & WEATHER_CLOUDY_ANY)
AI_THINKING_STRUCT->funcResult = AI_WEATHER_CLOUDY;[/COLOR]
gAIScriptPtr += 1;
}
Battle Expansion:
Code:
else if (gBattleWeather & WEATHER_SUN_ANY)
AI_THINKING_STRUCT->funcResult = AI_WEATHER_SUN;
else if (gBattleWeather & WEATHER_HAIL_ANY)
AI_THINKING_STRUCT->funcResult = AI_WEATHER_HAIL;
[COLOR="Green"] else if (gBattleWeather & WEATHER_CLOUDY_ANY)
AI_THINKING_STRUCT->funcResult = AI_WEATHER_CLOUDY;[/COLOR]
else
AI_THINKING_STRUCT->funcResult = AI_WEATHER_NONE;
gAIScriptPtr += 1;
}
Now for text edits
Spoiler:
In src/battle_message.c, with the other static consts
Code:
static const u8 sText_SpDef2[] = _("SP. DEF");
static const u8 sText_Accuracy[] = _("accuracy");
static const u8 sText_Evasiveness[] = _("evasiveness");
[COLOR="Green"]static const u8 sText_StartedCloudy[] = _("The sky grows dim with clouds");
static const u8 sText_CloudyContinues[] = _("The clouds still block the sun.");
static const u8 sText_CloudyStopped[] = _("The clouds clear out.");[/COLOR]
Then with STRING_IDs in the gBattleStringsTable
Code:
[STRINGID_TRAINER1WINTEXT - 12] = sText_Trainer1WinText,
[STRINGID_TRAINER2WINTEXT - 12] = sText_Trainer2WinText,
[COLOR="Green"][STRINGID_STARTEDCLOUDY - 12] = sText_StartedCloudy,
[STRINGID_CLOUDYCONTINUES - 12] = sText_CloudyContinues,
[STRINGID_CLOUDYSTOPPED - 12] = sText_CloudyStopped,[/COLOR]
And gMoveWeatherChangeStringIds
Code:
[B_MSG_STARTED_SANDSTORM] = STRINGID_SANDSTORMBREWED,
[B_MSG_STARTED_SUNLIGHT] = STRINGID_SUNLIGHTGOTBRIGHT,
[B_MSG_STARTED_HAIL] = STRINGID_STARTEDHAIL,
[COLOR="Green"][B_MSG_STARTED_CLOUDY] = STRINGID_STARTEDCLOUDY,[/COLOR]
};
And finally if you implement Overworld weather, you can associate it. I used WEATHER_SHADE
Code:
const u16 gWeatherStartsStringIds[] =
{
[WEATHER_NONE] = STRINGID_ITISRAINING,
[WEATHER_SUNNY_CLOUDS] = STRINGID_ITISRAINING,
[WEATHER_SUNNY] = STRINGID_ITISRAINING,
[WEATHER_RAIN] = STRINGID_ITISRAINING,
[WEATHER_SNOW] = STRINGID_ITISRAINING,
[WEATHER_RAIN_THUNDERSTORM] = STRINGID_ITISRAINING,
[WEATHER_FOG_HORIZONTAL] = STRINGID_ITISRAINING,
[WEATHER_VOLCANIC_ASH] = STRINGID_ITISRAINING,
[WEATHER_SANDSTORM] = STRINGID_SANDSTORMISRAGING,
[WEATHER_FOG_DIAGONAL] = STRINGID_ITISRAINING,
[WEATHER_UNDERWATER] = STRINGID_ITISRAINING,
[COLOR="DarkRed"]- [WEATHER_SHADE] = STRINGID_ITISRAINING,[/COLOR]
[COLOR="Green"][WEATHER_SHADE] = STRINGID_STARTEDCLOUDY,[/COLOR]
[WEATHER_DROUGHT] = STRINGID_SUNLIGHTSTRONG,
[WEATHER_DOWNPOUR] = STRINGID_ITISRAINING,
[WEATHER_UNDERWATER_BUBBLES] = STRINGID_ITISRAINING,
[WEATHER_ABNORMAL] = STRINGID_ITISRAINING
};
We finally get to the meat of weather mechanics
Spoiler:
in src/battle_main.c change this
Code:
[COLOR="DarkRed"]-EWRAM_DATA u16 gBattleWeather = 0;[/COLOR]
To this
Code:
[COLOR="Green"]EWRAM_DATA u32 gBattleWeather = 0;[/COLOR]
then for Weather Ball for Battle Expansion
Code:
if (gBattleMoves[move].effect == EFFECT_WEATHER_BALL)
{
if (WEATHER_HAS_EFFECT)
{
if (gBattleWeather & WEATHER_RAIN_ANY)
gBattleStruct->dynamicMoveType = TYPE_WATER | 0x80;
else if (gBattleWeather & WEATHER_SANDSTORM_ANY)
gBattleStruct->dynamicMoveType = TYPE_ROCK | 0x80;
else if (gBattleWeather & WEATHER_SUN_ANY)
gBattleStruct->dynamicMoveType = TYPE_FIRE | 0x80;
else if (gBattleWeather & WEATHER_HAIL_ANY)
gBattleStruct->dynamicMoveType = TYPE_ICE | 0x80;
[COLOR="Green"]else if (gBattleWeather & WEATHER_CLOUDY_ANY)
gBattleStruct->dynamicMoveType = TYPE_DARK | 0x80;[/COLOR]
else
gBattleStruct->dynamicMoveType = TYPE_NORMAL | 0x80;
}
}
For this weather since it's about nerfing attacks we're "done" for battle_main, but say you want to increase/decrease speed of a mon, like how Mystery Dungeon does for Ice types in Snow?
Fear not, scroll back up to here and add your effects
Vanilla:
(Note, this is if you have a Snow weather set)
Code:
if (WEATHER_HAS_EFFECT)
{
if ((gBattleMons[battler1].ability == ABILITY_SWIFT_SWIM && gBattleWeather & B_WEATHER_RAIN)
|| (gBattleMons[battler1].ability == ABILITY_CHLOROPHYLL && gBattleWeather & B_WEATHER_SUN)
[COLOR="Green"]|| (IS_BATTLER_OF_TYPE(battlerId, TYPE_ICE) && gBattleWeather & B_WEATHER_SNOW)[/COLOR])
speedMultiplierBattler1 = 2;
else
speedMultiplierBattler1 = 1;
if ((gBattleMons[battler2].ability == ABILITY_SWIFT_SWIM && gBattleWeather & B_WEATHER_RAIN)
|| (gBattleMons[battler2].ability == ABILITY_CHLOROPHYLL && gBattleWeather & B_WEATHER_SUN)
[COLOR="Green"]|| (IS_BATTLER_OF_TYPE(battlerId, TYPE_ICE) && gBattleWeather & B_WEATHER_SNOW)[/COLOR])
speedMultiplierBattler2 = 2;
else
speedMultiplierBattler2 = 1;
}
For Battle Expansion:
Code:
// weather abilities
if (WEATHER_HAS_EFFECT)
{
if (ability == ABILITY_SWIFT_SWIM && gBattleWeather & WEATHER_RAIN_ANY)
speed *= 2;
else if (ability == ABILITY_CHLOROPHYLL && gBattleWeather & WEATHER_SUN_ANY)
speed *= 2;
else if (ability == ABILITY_SAND_RUSH && gBattleWeather & WEATHER_SANDSTORM_ANY)
speed *= 2;
else if (ability == ABILITY_SLUSH_RUSH && gBattleWeather & WEATHER_HAIL_ANY)
speed *= 2;
[COLOR="Green"]else if ((IS_BATTLER_OF_TYPE(battlerId, TYPE_WATER) || IS_BATTLER_OF_TYPE(battlerId, TYPE_DRAGON)) && !IS_BATTLER_OF_TYPE(battlerId, TYPE_ICE) && gBattleWeather & WEATHER_SNOW_ANY)
speed = (speed * 75) / 100;
else if (IS_BATTLER_OF_TYPE(battlerId, TYPE_ICE) && gBattleWeather & WEATHER_SNOW_ANY)
speed = (speed * 185) / 100;[/COLOR]
}
With that done, head to src/battle_script_commands.c, and in Cmd_playanimation and Cmd_playanimation_var(Vanilla) Cmd_playanimation2(Battle Expansion) where the other weather anims are defined
Code:
|| gBattlescriptCurrInstr[2] == B_ANIM_SANDSTORM_CONTINUES
|| gBattlescriptCurrInstr[2] == B_ANIM_HAIL_CONTINUES
[COLOR="Green"]|| gBattlescriptCurrInstr[2] == B_ANIM_CLOUDY_CONTINUES[/COLOR]
Code:
|| *animationIdPtr == B_ANIM_SANDSTORM_CONTINUES
|| *animationIdPtr == B_ANIM_HAIL_CONTINUES
[COLOR="Green"]|| *animationIdPtr == B_ANIM_CLOUDY_CONTINUES[/COLOR]
Finally (well for Battle Expansion, Vanilla needs 1 more file tweaked), in various
Code:
case VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC:
BtlController_EmitPlayFanfareOrBGM(BUFFER_A, MUS_VICTORY_TRAINER, TRUE);
MarkBattlerForControllerExec(gActiveBattler);
break;
[COLOR="Green"]case VARIOUS_SETCLOUDY:
if (!TryChangeBattleWeather(gBattlerAttacker, ENUM_WEATHER_CLOUDY, FALSE))
{
gMoveResultFlags |= MOVE_RESULT_MISSED;
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
gBattlescriptCurrInstr += 7;
}
else
{
gBattleCommunication[MULTISTRING_CHOOSER] = 7;
gBattlescriptCurrInstr += 7;
}
return;[/COLOR]
}
And for Vanilla, weather ball tweaks, in static void Cmd_setweatherballtype
Code:
else if (gBattleWeather & B_WEATHER_SUN)
*(&gBattleStruct->dynamicMoveType) = TYPE_FIRE | F_DYNAMIC_TYPE_2;
else if (gBattleWeather & B_WEATHER_HAIL)
*(&gBattleStruct->dynamicMoveType) = TYPE_ICE | F_DYNAMIC_TYPE_2;
[COLOR="Green"]else if (gBattleWeather & B_WEATHER_CLOUDY)
*(&gBattleStruct->dynamicMoveType) = TYPE_DARK | F_DYNAMIC_TYPE_2;[/COLOR]
else
*(&gBattleStruct->dynamicMoveType) = TYPE_NORMAL | F_DYNAMIC_TYPE_2;
}
If you're curious, weather effects for accuracy (like Thunder/Blizzard) are here in battle_script_commands.c
And in the last file, in src/battle_util.c, in the enum after GetImprisonedMovesCount
Code:
ENDTURN_SANDSTORM,
ENDTURN_SUN,
ENDTURN_HAIL,
[COLOR="Green"]ENDTURN_CLOUDY,[/COLOR]
ENDTURN_FIELD_COUNT,
In DoFieldEndTurnEffects, add a case before ENDTURN_FIELD_COUNT
Vanilla:
Code:
[COLOR="Green"]case ENDTURN_CLOUDY:
if (gBattleWeather & B_WEATHER_CLOUDY)
{
if (!(gBattleWeather & B_WEATHER_CLOUDY_PERMANENT) && --gWishFutureKnock.weatherDuration == 0)
{
gBattleWeather &= ~B_WEATHER_CLOUDY_TEMPORARY;
gBattlescriptCurrInstr = BattleScript_CloudyEnd;
}
else
{
gBattlescriptCurrInstr = BattleScript_CloudyContinues;
}
BattleScriptExecute(gBattlescriptCurrInstr);
effect++;
}
gBattleStruct->turnCountersTracker++;
break;[/COLOR]
Battle Expansion:
Code:
[COLOR="Green"]case ENDTURN_CLOUDY:
if (gBattleWeather & WEATHER_CLOUDY_ANY)
{
if (!(gBattleWeather & WEATHER_CLOUDY_PERMANENT) && --gWishFutureKnock.weatherDuration == 0)
{
gBattleWeather &= ~WEATHER_CLOUDY_TEMPORARY;
gBattlescriptCurrInstr = BattleScript_CloudyEnd;
}
else
{
gBattlescriptCurrInstr = BattleScript_CloudyContinues;
}
BattleScriptExecute(gBattlescriptCurrInstr);
effect++;
}
gBattleStruct->turnCountersTracker++;
break;[/COLOR]
If Battle Expansion and Item Expansion are used, in static const u32 sWeatherFlagsInfo[][3] for the rocks
Code:
[ENUM_WEATHER_SANDSTORM] = {WEATHER_SANDSTORM_TEMPORARY, WEATHER_SANDSTORM_PERMANENT, HOLD_EFFECT_SMOOTH_ROCK},
[ENUM_WEATHER_HAIL] = {WEATHER_HAIL_TEMPORARY, WEATHER_HAIL_PERMANENT, HOLD_EFFECT_ICY_ROCK},
[COLOR="Green"][ENUM_WEATHER_CLOUDY] = {WEATHER_CLOUDY_TEMPORARY, WEATHER_CLOUDY_PERMANENT, HOLD_EFFECT_SMOOTH_ROCK},[/COLOR]
Then in the u8 AbilityBattleEffects Cases for the weather, to link to Overworld weather
Code:
[COLOR="Green"]case WEATHER_SHADE:
if (!(gBattleWeather & WEATHER_CLOUDY_ANY))
{
gBattleWeather = (WEATHER_CLOUDY_PERMANENT | WEATHER_CLOUDY_TEMPORARY);
gBattleScripting.animArg1 = B_ANIM_CLOUDY_CONTINUES;
effect++;
}[/COLOR]
From this point, Battle Expansion and Vanilla have parted ways
For Vanilla, go to src/pokemon.c
in if(WEATHER_HAS_EFFECT2), add the following
Code:
[COLOR="GREEN"]if (gBattleWeather & B_WEATHER_CLOUDY_TEMPORARY)
{
if (gBattleMoves[gCurrentMove].type != TYPE_NORMAL && gBattleMoves[gCurrentMove].type != TYPE_DARK)
damage /= 2;
}[/COLOR]
Then for Solarbeam, you can simply add the weather
Code:
// Any weather except sun weakens solar beam
if ((gBattleWeather & (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_HAIL [COLOR="Green"]| B_WEATHER_CLOUDY[/COLOR])) && gCurrentMove == MOVE_SOLAR_BEAM)
damage /= 2;
For Battle Expansion, where move effects and weather weakening are in battle_util.c still
With other move effect cases
Code:
case EFFECT_SOLARBEAM:
if (WEATHER_HAS_EFFECT && gBattleWeather & (WEATHER_HAIL_ANY | WEATHER_SANDSTORM_ANY | WEATHER_RAIN_ANY [COLOR="Green"]| WEATHER_CLOUDY_ANY[/COLOR]))
MulModifier(&modifier, UQ_4_12(0.5));
With other type move weakening
Code:
[COLOR="Green"]else if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_CLOUDY_ANY)
{
if (moveType != TYPE_NORMAL && moveType != TYPE_DARK)
dmg = ApplyModifier(UQ_4_12(0.5), dmg);
}[/COLOR]
And there you have it. If you want to make it into a move like Rain Dance, or weather ability, you can simply copy what Vanilla/Battle Expansion does for the original weather types (we already established EFFECT_CLOUDY, so go nuts in src/data/battle_moves.h)
Otherwise, you can view the effect in battle like so:
![[PokeCommunity.com] [TUTORIAL] Adding New Weather [PokeCommunity.com] [TUTORIAL] Adding New Weather](https://cdn.discordapp.com/attachments/419213926245335041/904116206359945266/so.gif)
Where despite the major level difference, Mud Slap doesn't cut a third of health due to being weakened
Last edited: