Updated Add Physical Special Split (markdown)

Kurausukun 2019-12-19 23:14:12 -05:00
parent da74a8437a
commit 4066c1c43d
1 changed files with 55 additions and 1 deletions

@ -5,6 +5,7 @@ This tutorial is for adding the per-move physical/special split that was impleme
2. [Modifying the physicality check macro](#2-modifying-the-physicality-check-macro) 2. [Modifying the physicality check macro](#2-modifying-the-physicality-check-macro)
3. [Modifying the damage calculation logic](#3-modifying-the-damage-calculation-logic) 3. [Modifying the damage calculation logic](#3-modifying-the-damage-calculation-logic)
4. [Adding the physicality byte to moves](#4-adding-the-physicality-byte-to-moves) 4. [Adding the physicality byte to moves](#4-adding-the-physicality-byte-to-moves)
5. [A Note on AI Scripts](#5-a-note-on-ai-scripts)
## 1. Adding a byte to the move struct ## 1. Adding a byte to the move struct
The struct that defines the properties of a move are located in **include/pokemon.h**, so we will be modifying that file to include a byte that determines whether the move is physical or special. We will also be adding some macros to make the values more descriptive. Before editing, the struct looks like this: The struct that defines the properties of a move are located in **include/pokemon.h**, so we will be modifying that file to include a byte that determines whether the move is physical or special. We will also be adding some macros to make the values more descriptive. Before editing, the struct looks like this:
@ -81,6 +82,51 @@ for (i = 0; i < ARRAY_COUNT(sHoldEffectToType); i++)
} }
} }
``` ```
### Weather
We also need to make a similar change to the boosts that weather provides. In Gen 3, all types that can be boosted by weather are special types, so the code only checks for the boost if a special move is being used. All of the weather checks are conveniently bunched together, so we can just copy and paste this entire section outside of the special check:
```c
if (WEATHER_HAS_EFFECT2)
{
if (gBattleWeather & WEATHER_RAIN_TEMPORARY)
{
switch (type)
{
case TYPE_FIRE:
damage /= 2;
break;
case TYPE_WATER:
damage = (15 * damage) / 10;
break;
}
}
// any weather except sun weakens solar beam
if ((gBattleWeather & (WEATHER_RAIN_ANY | WEATHER_SANDSTORM_ANY | WEATHER_HAIL_ANY)) && gCurrentMove == MOVE_SOLAR_BEAM)
damage /= 2;
// sunny
if (gBattleWeather & WEATHER_SUN_ANY)
{
switch (type)
{
case TYPE_FIRE:
damage = (15 * damage) / 10;
break;
case TYPE_WATER:
damage /= 2;
break;
}
}
```
### Flash Fire
Just like weather, since Flash Fire only affects Fire-type moves, which are all special in Gen 3, the check for Flash Fire only occurs in the special block. It's actually located right after the weather checks, so you can copy and paste this check outside of the block along with them:
```c
if ((gBattleResources->flags->flags[battlerIdAtk] & RESOURCE_FLAG_FLASH_FIRE) && type == TYPE_FIRE)
damage = (15 * damage) / 10;
```
The next thing we need to do is change the arguments passed to IS_TYPE_PHYSICAL and IS_TYPE_SPECIAL. Originally, they were passed a type argument, but now we want to pass a move argument. There is one instance of each of these functions in **src/pokemon.c**, and there are three more in **src/battle_script_commands.c**. The ones in **pokemon.c** should be changed from IS_TYPE_PHYSICAL(type) and IS_TYPE_SPECIAL(type) to IS_TYPE_PHYSICAL(gBattleMoves[move]) and IS_TYPE_SPECIAL(gBattleMoves[move]). The first one in **battle_script_commands.c** can also be changed like this, but the argument names are different for the second and third one. The second one looks like this originally: The next thing we need to do is change the arguments passed to IS_TYPE_PHYSICAL and IS_TYPE_SPECIAL. Originally, they were passed a type argument, but now we want to pass a move argument. There is one instance of each of these functions in **src/pokemon.c**, and there are three more in **src/battle_script_commands.c**. The ones in **pokemon.c** should be changed from IS_TYPE_PHYSICAL(type) and IS_TYPE_SPECIAL(type) to IS_TYPE_PHYSICAL(gBattleMoves[move]) and IS_TYPE_SPECIAL(gBattleMoves[move]). The first one in **battle_script_commands.c** can also be changed like this, but the argument names are different for the second and third one. The second one looks like this originally:
```c ```c
IS_TYPE_PHYSICAL(moveType) IS_TYPE_PHYSICAL(moveType)
@ -141,4 +187,12 @@ The last step is definitely the most tedious, but it is very simple. We need to
.flags = FLAG_PROTECT_AFFECTED | FLAG_MAGICCOAT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED, .flags = FLAG_PROTECT_AFFECTED | FLAG_MAGICCOAT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED,
.physicality = MOVE_PHYSICALITY_OTHER, .physicality = MOVE_PHYSICALITY_OTHER,
}, },
``` ```
## 5. A Note on AI Scripts
The last thing that should be noted is how AI Scripts relating to physical/special moves work in these games. The file **data/battle_ai_scripts.s** contains the code for the battle AI and how it chooses which moves to use. The way it does this is not by calling the macro that the damage calculation code uses; instead, it has multiple internal tables used to keep track of which types are physical and which are special. Note that this does not affect any actual damage calculation, and its effect on the AI is limited in the first place. The three things affected are:
1. The likelihood of the AI using an attack-lowering vs. a special attack-lowering move
2. The likelihood of the AI using Reflect vs. Light Screen
3. The likelihood of the AI using Counter vs. Mirror Coat
An important note is that these decisions are all made based on the types of the opposing Pokemon itself rather than the moves it has, so the original check is pretty bad to begin with--in fact, it's arguable whether you would even notice the difference. Correcting the AI to check for the physicality of moves instead of the types of Pokemon is beyond the scope of this tutorial and is more suited to a general AI overhaul tutorial, but I wanted to mention it here to be totally clear about what's happening with these calculations.