Skip to content

Commit

Permalink
How to docs and fixes to be added to the mdbook documentation site (#…
Browse files Browse the repository at this point in the history
…5070)

* Added most of the documentation from the wiki to the mdbook site directory and fixed some errors

* Removed the infinite repel documentation file

* Update docs/SUMMARY.md

---------

Co-authored-by: Eduardo Quezada <[email protected]>
  • Loading branch information
anrichtait and AsparagusEduardo authored Aug 5, 2024
1 parent 41a79e3 commit fd3cb6f
Show file tree
Hide file tree
Showing 10 changed files with 6,143 additions and 0 deletions.
11 changes: 11 additions & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@
- [Installation](./INSTALL.md)
- [Setting up WSL1 (Legacy Portion)](./legacy_WSL1_INSTALL.md)
- [AI Flags](./ai_flags.md)
- [Tutorials]()
- [How to add new AI Flags](./ai_logic.md)
- [How to add new battle script commands/macros](./how_to_battle_script_command_macro.md)
- [How to add a new move](./how_to_new_move.md)
- [How to add a new trainer class](./how_to_trainer_class.md)
- [How to add a new Pokémon]()
- [v1.9.0](./how_to_new_pokemon_1_9_0.md)
- [v1.8.0](./how_to_new_pokemon_1_8_0.md)
- [v1.7.0](./how_to_new_pokemon_1_7_0.md)
- [v1.6.0](./how_to_new_pokemon_1_6_0.md)
- [How to use the Testing System](./how_to_testing_system.md)
- [Changelog](./CHANGELOG.md)
- [1.9.x]()
- [Version 1.9.0](changelogs/1.9.x/1.9.0.md)
Expand Down
31 changes: 31 additions & 0 deletions docs/ai_logic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# How to add new AI Flags

The battle engine upgrade has rewritten the AI battle scripts to C functions to easily add new logic. This tutorial explains how to add a new AI logic flag.

## 1. Define your flag

Open `include/constants/battle_ai.h`. We have many unused flags, but you can add a new one after `AI_FLAG_SMART_SWITCHING` like so:

`#define AI_FLAG_SUPPORT (1 << 16)`

## 2. Make your new function

Open `src/battle_ai_main.c`. Search for the array `static s16 (*const sBattleAiFuncTable[])(u8, u8, u16, s16)`. We want to add our new function to this table. Since we have defined our flag as `(1 << 16)`, find the 16th entry in the table (identifiable by the initializer, `[16]`), and replace it with:

`[16] = AI_Support, // AI_FLAG_SUPPORT`

Define your function above the table as `static s16 AI_Support(u8 battlerAtk, u8 battlerDef, u16 move, s16 score);`

## Make your function do something

at the bottom of the file, add:
```c
static s16 AI_Support(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
{
// Add your logic here!
}
```
## Give your trainer the correct AI flag!
And that's it!
51 changes: 51 additions & 0 deletions docs/how_to_battle_script_command_macro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
## How to add new Battle Script Commands/Macros

To preface this tutorial, the battle engine upgrade has exhausted all battle script command IDs, and instead uses the `various` command to effectively add new commands. This is preferential to creating a secondary battle script command table like is done in the CFRU.

In general, `gBattlescriptCurrInstr` tracks the current battle script position as a ROM address. Fortunately, we don't need to worry about ROM addresses when using the decomps, but it is important to understand because of how the `various` command is set up.

```
.macro various battler:req, param1:req
.byte 0x76
.byte \battler
.byte \param1
.endm
```

`various` is 3 bytes in size, so if we wanted to advance to the next battle script command, we would write `gBattlescriptCurrInstr += 3`. Coincidentally, this is found at the end of `Cmd_Various` in `src/battle_script_commands.c`.

Now, how might we add a custom various command case? Here are the steps. We will use `VARIOUS_SET_SIMPLE_BEAM` as an example.
### 1. Add a definition to `include/constants/battle_script_commands.h`.

For example, `#define VARIOUS_SET_SIMPLE_BEAM 39`

### 2. Create a macro in `asm/macros/battle_script.inc`. For example:
```c
.macro setabilitysimple battler:req, ptr:req
various \battler VARIOUS_SET_SIMPLE_BEAM
.4byte \ptr
.endm
```

### 3. Add your new various command ID to `Cmd_Various`. For example:
```c
case VARIOUS_SET_SIMPLE_BEAM:
if (IsEntrainmentTargetOrSimpleBeamBannedAbility(gBattleMons[gBattlerTarget].ability)
|| gBattleMons[gBattlerTarget].ability == ABILITY_SIMPLE)
{
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
}
else
{
gBattleMons[gBattlerTarget].ability = ABILITY_SIMPLE;
RecordAbilityBattle(gActiveBattler, ABILITY_SIMPLE);
gBattlescriptCurrInstr += 7;
}
return;
```
The macros' `battler` argument is the battler who will be affected/considered by your command. In our case, which battler we will try to give `ABILITY_SIMPLE`. Note that `gActiveBattler` is always set to this battler at the beginning of `Cmd_Various`.
The `ptr` argument is an extra argument that, in this case, provides a battle script to jump to in the event that we fail to set `ABILITY_SIMPLE`. We must add the `.4byte \ptr` inside our macro. So now when we want to advance to the next battle script command in our script, we must increment `gBattlescriptCurrInstr` by `7` because our overall macro is 3 bytes for the various command, and 4 bytes for the pointer. *IMPORTANT* the `return` at the end of the switch case is required because remember that `various` always defaults to `gBattlescriptCurrInstr += 3` at the very end of the function, so if we included `gBattlescriptCurrInstr += 7` with a `break`, we would end up effectively doing `gBattlescriptCurrInstr += 10`.
This behavior can be found under the `else` statement in the example above, corresponding to `ABILITY_SIMPLE` being correctly applied. If we are unable to set `ABILITY_SIMPLE`, however, notice the following `gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);`. This means we are jumping to the battle script provided by the pointer 3 bytes after our various command (which is the `ptr` argument described previously). We still must `return` or else we would actually jump to 3 bytes after the `ptr` battle script begins.
197 changes: 197 additions & 0 deletions docs/how_to_new_move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
*Full credits and thank you to CancerFairy for writing this guide!*

### Note: This guide was written for version 1.8.0. Most stuff still applies to 1.7.x versions and earlier, with the following exceptions:
- Battle and Contest move data are separated in `src/data/battle_moves.h` and `src/data/contest_moves.h`
- `additionalEffects` doesn't exist, instead being handled by a combination of `secondaryEffectChance` and unique `EFFECT_xxx`s.
- There's no `include/constants/battle_move_effects.h`, so data specific to certain effects is handled in other places.
- Move names are handled in `gMoveNames`.

# Adding/editing moves
This guide is here to give you a breakdown of how moves work, how to edit existing ones, and how to add your own.

## Contents:
1. [Key files and definitions](#key-files-and-definitions)
- [Header files](#header-files)
- [C files](#c-files)
- [Script files](#script-files)
2. [Editing a move](#editing-a-move)
3. [Adding a new move](#adding-a-new-move)

## Key files and definitions
Before beginning the process, it's important to familiarise yourself with the important files that control moves. There are three categories of files - header(.h) files, which contain static information about a move, .c files which contains functions in C that determine how the move behaves, and script files (.s or .inc) that actually "run" the move - i.e. determine the sequence of events you see on screen when you execute the move.

## Header files
### src/data/moves_info.h
This is the place where the bulk of move information is stored, including name, base power, typing, PP, contest information etc.

Let's look at an example:
```c
[MOVE_THUNDER_SHOCK] =
{
.name = HANDLE_EXPANDED_MOVE_NAME("ThunderShock", "Thunder Shock"),
.description = COMPOUND_STRING(
"An electrical attack that\n"
"may paralyze the foe."),
.effect = EFFECT_HIT,
.power = 40,
.type = TYPE_ELECTRIC,
.accuracy = 100,
.pp = 30,
.target = MOVE_TARGET_SELECTED,
.priority = 0,
.category = DAMAGE_CATEGORY_SPECIAL,
.sheerForceBoost = TRUE,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_PARALYSIS,
.chance = 10,
}),
.contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING,
.contestCategory = CONTEST_CATEGORY_COOL,
.contestComboStarterId = 0,
.contestComboMoves = {COMBO_STARTER_CHARGE},
},
```
The `HANDLE_EXPANDED_MOVE_NAME` allows the usage of a name of extended character length, so long as the `B_EXPANDED_MOVE_NAMES` is set to `TRUE`, whereas by default it's limited in Gen 3 to 12 characters. Most of the fields here are obvious, but the two important ones for determining what a move actually *does* are `effect` and `additionalEffects`.

The `effect` represents how the move actually works when called in battle - it can be a two turn move, or a move that only works if the target is holding an item, for example. How each effect works is pretty much unique, but the way a move of a particular effect is executed is defined by a script [`data/battle_scripts_1.s`](#databattle_scripts_1s), and any *variable* characteristics such as typing or power are defined in either [`src/battle_script_commands.c`](#srcbattle_script_commandsc) or [`src/battle_util.c`](#srcbattle_utilc), depending on the effect. The vast majority of non-status moves are simply `EFFECT_HIT`, in that they deal damage and apply `additionalEffects` (if defined).

The `additionalEffects` field represents effects that are applied at the `setadditionaleffects` stage of the move script (for most moves, see `BattleScript_Hit_RetFromAtkAnimation`). These are effects that can be encapsulated by any of the `MOVE_EFFECT_X` defined in [`include/constants/battle.h`](#includeconstantsbattleh) and encoded under `SetMoveEffect` in [`src/battle_script_commands.c`](#srcbattle_script_commandsc). These can vary from applying a status, such as `MOVE_EFFECT_PARALYSIS`, or lowering/raising stats etc. The move effect could target the user by setting `self = TRUE`, such as Overheat lowering the user's own Sp. Atk. What's more, definining a `chance`, such as for Thunder Shock, not only limits the effect to applying only `chance`% of the time, but it also turns it into a *secondary effect.* This difference is important because secondary effects are nullified by Sheer Force (which in turn will boost the move's power) and they are blocked by Shield Dust. These two limitations do not apply to *primary effects* which do not a chance field defined and by definition will *always* happen when the move is executed.

### src/data/battle_move_effects.h
Effects are listed here along with the `battleScript` that governs each one. Said scripts are defined in [`data/battle_scripts_1.s`](#databattle_scripts_1s). The indices/names of the effects (e.g. `EFFECT_FIRST_TURN_ONLY`) are enums defined in [`include/constants/battle_move_effects.h`](#includeconstantsbattle_move_effectsh).

### include/battle_scripts.h
Contains references to scripts [`data/battle_scripts_1.s`](#databattle_scripts_1s), allowing them to be referenced in C. Any new scripts must be added here.

### include/constants/battle_move_effects.h
Simply an enum list of possible effects for moves. Any new effects would be added here, with a definition for them (including defining a script) would then also be added to [`src/data/battle_move_effects.h`](#srcdatabattle_move_effectsh).

### include/constants/battle_string_ids.h
All strings that can be printed in battle have an id that is defined here. The actual message itself would then be defined and assigned to this id in [`src/data/battle_message.c`](#srcbattle_messagec).

### include/constants/battle.h
A whole range of constants defining battle variables, such as statuses, weather, and move effects.

### include/constants/moves.h
Where moves are defined (and nothing else).

**Note:** When adding custom moves, you should add them between the moves from the latest generation and the z moves, then adjust `MOVES_COUNT` accordingly. Adding a move after `MOVES_COUNT` that is neither a Max Move or a Z Move will result in that move's name not being printed when it is used, instead a generic message will be printed.

## C files
### src/battle_script_commands.c
This is where a lot of the commands referred to in scripts are defined. For example, the `jumpifnotfirstturn` command above is defined by the function `Cmd_jumpifnotfirstturn` and you can see how it works in C. It's possible that any move editing or updating you have in mind can be done with existing commands, but if you wanted to add a new function that could be called in a script above, this is where you would define it.

### src/battle_util.c
This contains a lot of the "utility" functions used to determine things like a move's dynamic typing or power. It's also where damage calculation takes place, and a lot of that will naturally take a move's effect into account. For example, a move with the effect `EFFECT_SOLAR_BEAM` would have its damage halved in sandstorm. If you wanted to add a move with an effect which gave it variable BP or typing, this is the file you would encode that effect.

### src/battle_message.c
Contains string defines and functions that print messages during the battle. If you wish to add or edit a move's string, then this is where you would do so.

### src/battle_main.c
Contains more fundamental functions that control the flow of the battle. Functions here determine move order, dynamic typing, animations, priority, speed calculations and more.

## Script files
### data/battle_scripts_1.s
Each move's effect is governed by a script defined here. For a simple example, let's look at the script for Fake Out/First Impression:

```
BattleScript_EffectFirstTurnOnly::
attackcanceler
jumpifnotfirstturn BattleScript_FailedFromAtkString
goto BattleScript_EffectHit
```

`attackcanceler` is a command that covers all the cases that could cause a move to fail before it's even attempted (e.g. paralysis). And as we can tell from the commands, if it's not the first turn, we go to `BattleScript_FailedFromAtkString` which evidently causes us to print the `attackstring` ("POKEMON used MOVE") then fail ("But it failed!"). Otherwise, we go to the generic "hit" effect which is the same script for moves that just deal damage and nothing else.

This is the most advanced part of the ROM. There are dozens upon dozens of commands and hundreds of scripts so this guide would go on forever if I were to go into more detail. To learn how these scripts work, it's best to look at a few examples of moves you know.

### asm/macros/battle_script.inc
The "link" between [`data/battle_scripts_1.s`](#databattle_scripts_1s) and [`src/battle_script_commands.c`](#srcbattle_script_commandsc). Each command is represented by a hex byte which represents its index in the `gBattleScriptingCommandsTable` array at the top of [`src/battle_script_commands.c`](#srcbattle_script_commandsc). However, this file also contains macros which perform combinations of other commands, or just calculations in assembly. In addition to commands, it is also possible to call functions in [`src/battle_script_commands.c`](#srcbattle_script_commandsc) using the `various` (now gradually being deprecated) and the `callnative` functionality. The `various` macros will point to a case under the `Cmd_various` function in [`src/battle_script_commands.c`](#srcbattle_script_commandsc), whereas `callnative` will let you directly call a function in [`src/battle_script_commands.c`](#srcbattle_script_commandsc) by name.

### data/battle_anim_scripts.s
This is the place where move animations are defined. The array at the top, `gBattleAnims_Moves`, is in move index order and determines which animation goes with which move.

## Editing a move
### Basic information
To edit a move's basic information, you need only edit the relevant fields in [`src/data/battle_moves.h`](#srcdatamoves_infoh). This will let you change a move's:
- name
- description
- power
- accuracy
- type
- category
- target
- pp
- recoil percentage
- flags
- Z-move effect (for status moves) or overwritting its calculated power (for damaging moves)

### Changing a move's main effect
To change the main effect of a move to an existing effect, you need only change its `effect` field to one of the options in [`src/data/battle_move_effects.h`](#srcdatabattle_move_effectsh). If you wish to keep the effect but simply modify how it works, you can modify how it plays out on screen by editing its entry in [`data/battle_scripts_1.s`](#databattle_scripts_1s) and any relevant functions in [`src/battle_script_commands.c`](#srcbattle_script_commandsc). To change how a move's dynamic power, accuracy and are calculated, then you need to modify the following functions:

- For power: `CalcMoveBasePowerAfterModifiers` in [`src/battle_util.c`](#srcbattle_utilc)
- For accuracy: `AccuracyCalcHelper` in [`src/battle_script_commands.c`](#srcbattle_script_commandsc)
- For type: `SetTypeBeforeUsingMove` in [`src/battle_main.c`](#srcbattle_mainc)

Note: A generic function for calculating category does not currently exist - Photon Geyser's script in [`data/battle_scripts_1.s`](#databattle_scripts_1s) uses a special `callnative` function `BS_SetPhotonGeyserCategory`.

### Changing a move's additional effects
If you look at the example [here](#srcdatamoves_infoh), you can see that Thunder Shock has an additional effects array that contains a single move effect `MOVE_EFFECT_PARALYSIS` with a 10% chance of applying. Thanks to this field, you can add and remove primary and secondary effects (so long as they are defined by a `MOVE_EFFECT`) to a move without having to change its effect or script. You can also make an effect apply to the attacker rather than the target (for, say, a stat boost) with `.self = TRUE` and you can set the probability to whatever you want with the `chance` field.

All additional effects with a defined chance (even 100%) are treated as "secondary effects". This means that they are nullified by Sheer Force, blocked by Shield Dust or the Covert Cloak, and have their chance modified by Serene Grace. Additional effects without a chance field (effectively setting it to 0) are treated as "primary effects", which means that they cannot be blocked by the aforementioned items and abilities and their chance to occur cannot be modified; they will *always* happen.

Each move can have up to 15 additional effects, allowing you to construct monstrosities like this:
```
[MOVE_POUND] =
{
.name = COMPOUND_STRING("Pound"),
.description = COMPOUND_STRING(
"Pounds the foe with\n"
"forelegs or tail."),
.effect = EFFECT_HIT,
.power = 40,
.type = TYPE_NORMAL,
.accuracy = 100,
.pp = 35,
.target = MOVE_TARGET_SELECTED,
.priority = 0,
.category = DAMAGE_CATEGORY_PHYSICAL,
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_PARALYSIS,
.chance = 10,
},{
.moveEffect = MOVE_EFFECT_CONFUSION,
.chance = 100,
},{
.moveEffect = MOVE_EFFECT_FLINCH,
.chance = 30,
},{
.moveEffect = MOVE_EFFECT_ALL_STATS_UP,
.chance = 40,
.self = TRUE,
},{
.moveEffect = MOVE_EFFECT_RAPID_SPIN,
},{
.moveEffect = MOVE_EFFECT_DEF_MINUS_2,
.chance = 50,
}),
.makesContact = TRUE,
.ignoresKingsRock = B_UPDATED_MOVE_FLAGS == GEN_4,
.contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING,
.contestCategory = CONTEST_CATEGORY_TOUGH,
.contestComboStarterId = COMBO_STARTER_POUND,
.contestComboMoves = {0}
},
```

**Note: at the moment, additional effects can only be used by damaging moves, not by status moves.**

## Adding a new move
To add a new move, you need to create an entry in three locations:

- a define in [`include/constants/moves.h`](#includeconstantsmovesh)
- an info entry in [`src/data/battle_moves.h`](#srcdatamoves_infoh)
- an animation entry in [data/battle_anim_scripts.s](#databattle_anim_scriptss)

And that's it! You can use an existing animation or effect for your move - or you can add your own, but I'll leave figuring that out to you.

Loading

0 comments on commit fd3cb6f

Please sign in to comment.