From fd3cb6f96b1d9deaac4805e1d8bf767321198575 Mon Sep 17 00:00:00 2001 From: toon <123473450+anrichtait@users.noreply.github.com> Date: Mon, 5 Aug 2024 15:26:14 +0200 Subject: [PATCH] How to docs and fixes to be added to the mdbook documentation site (#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 --- docs/SUMMARY.md | 11 + docs/ai_logic.md | 31 + docs/how_to_battle_script_command_macro.md | 51 + docs/how_to_new_move.md | 197 +++ docs/how_to_new_pokemon_1_6_0.md | 1860 ++++++++++++++++++++ docs/how_to_new_pokemon_1_7_0.md | 1049 +++++++++++ docs/how_to_new_pokemon_1_8_0.md | 1049 +++++++++++ docs/how_to_new_pokemon_1_9_0.md | 1139 ++++++++++++ docs/how_to_testing_system.md | 578 ++++++ docs/how_to_trainer_class.md | 178 ++ 10 files changed, 6143 insertions(+) create mode 100644 docs/ai_logic.md create mode 100644 docs/how_to_battle_script_command_macro.md create mode 100644 docs/how_to_new_move.md create mode 100644 docs/how_to_new_pokemon_1_6_0.md create mode 100644 docs/how_to_new_pokemon_1_7_0.md create mode 100644 docs/how_to_new_pokemon_1_8_0.md create mode 100644 docs/how_to_new_pokemon_1_9_0.md create mode 100644 docs/how_to_testing_system.md create mode 100644 docs/how_to_trainer_class.md diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 3ff95a251c..fce328d858 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -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) diff --git a/docs/ai_logic.md b/docs/ai_logic.md new file mode 100644 index 0000000000..b910d46946 --- /dev/null +++ b/docs/ai_logic.md @@ -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! diff --git a/docs/how_to_battle_script_command_macro.md b/docs/how_to_battle_script_command_macro.md new file mode 100644 index 0000000000..042a87601d --- /dev/null +++ b/docs/how_to_battle_script_command_macro.md @@ -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. diff --git a/docs/how_to_new_move.md b/docs/how_to_new_move.md new file mode 100644 index 0000000000..9ddc09b904 --- /dev/null +++ b/docs/how_to_new_move.md @@ -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. + diff --git a/docs/how_to_new_pokemon_1_6_0.md b/docs/how_to_new_pokemon_1_6_0.md new file mode 100644 index 0000000000..d965e48a5f --- /dev/null +++ b/docs/how_to_new_pokemon_1_6_0.md @@ -0,0 +1,1860 @@ +This is a modified version of [the original tutorial about adding new Pokémon species available in Pokeemerald's wiki](https://github.com/pret/pokeemerald/wiki/How-to-add-a-new-Pokémon-species). + +Despite the persistent rumors about an incredibly strong third form of Mew hiding somewhere, it actually wasn't possible to catch it... OR WAS IT? +In this tutorial, we will add a new Pokémon species to the game. + +## IMPORTANT: This tutorial applies to Version 1.6.2 and lower. +- [Version 1.9.x](how_to_new_pokemon_1_9_0.md) +- [Version 1.8.x](how_to_new_pokemon_1_8_0.md) +- [Version 1.7.x](how_to_new_pokemon_1_7_0.md) + +# Changes compared to vanilla +The main things that the Expansion changes are listed here. +* Still Front Pics *(`gMonStillFrontPic_YourPokemon`)* and by extension `src/anim_mon_front_pics.c` have been removed. +* `src/data/pokemon/cry_ids.h` doesn't exist anymore. + +# Content +* [The Graphics](#the-graphics) + * [1. Edit the sprites](#1-edit-the-sprites) + * [2. Register the sprites](#2-register-the-sprites) + * [3. Animate the sprites](#3-animate-the-sprites) + * [4. Update the tables](#4-update-the-tables) +* [The Data](#the-data) + * [1. Declare a species constant](#1-declare-a-species-constant) + * [2. Devise a name](#2-devise-a-name) + * [3. Define its Pokédex entry](#3-define-its-pokédex-entry) + * [4. Define its species information](#4-define-its-species-information) + * [5. Delimit the moveset](#5-delimit-the-moveset) + * [6. Define its cry](#6-define-its-cry) + * [7. Define the Evolutions](#7-define-the-evolutions) + * [8. Easy Chat about your Pokémon](#8-easy-chat-about-your-pokémon) + * [9. Make it appear!](#9-make-it-appear) +* [Appendix](#appendix) + * [Available Front Animations](#available-front-animations) + * [Available Back Animations](#available-back-animations) + * [Pokémon ordered by height](#pokémon-ordered-by-height) + * [Pokémon ordered by weight](#pokémon-ordered-by-weight) + * [Making this easier](#making-this-easier) + + +# The Graphics +We will start by copying the folder containing the sprites for Mewtwo and rename it to `mewthree` (pretty meta huh?): +```sh +cp -r graphics/pokemon/mewtwo graphics/pokemon/mewthree +``` +## 1. Edit the sprites +Let's edit the sprites. Start your favourite image editor (I have used GIMP) and change `anim_front.png`, `front.png` and `back.png` to meet your expectations. +__Make sure that you are using the indexed mode and you have limited yourself to 15 colors!__ +Put the RGB values of your colors into `normal.pal` between the first and the last color and the RGB values for the shiny version into `shiny.pal`. +Edit `footprint.png` using two colors in indexed mode, black and white. +Finally, edit `icon.png`. Notice, that the icon will use one of three predefined palettes instead of `normal.pal`. + +## 2. Register the sprites +Sadly, just putting the image files into the graphics folder is not enough. To use the sprites we have to register them, which is kind of tedious. +First, create constants for the file paths. You'll want to add the constants for your species after the constants for the last valid species. +Edit [include/graphics.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/graphics.h): + +```diff + extern const u32 gMonFrontPic_Calyrex[]; ++extern const u32 gMonFrontPic_Mewthree[]; +``` + +```diff + extern const u32 gMonBackPic_Calyrex[]; ++extern const u32 gMonBackPic_Mewthree[]; +``` + +```diff + extern const u32 gMonPalette_Calyrex[]; ++extern const u32 gMonPalette_Mewthree[]; +``` + +```diff + extern const u32 gMonShinyPalette_Calyrex[]; ++extern const u32 gMonShinyPalette_Mewthree[]; +``` + +```diff + //extern const u8 gMonIcon_Calyrex[]; ++extern const u8 gMonIcon_Mewthree[]; +``` + +```diff + extern const u8 gMonFootprint_Calyrex[]; ++extern const u8 gMonFootprint_Mewthree[]; +``` + +Now link the graphic files. + +Edit [src/data/graphics/pokemon.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/graphics/pokemon.h): + +```diff + const u32 gMonFrontPic_Calyrex[] = INCBIN_U32("graphics/pokemon/calyrex/front.4bpp.lz"); ++const u32 gMonFrontPic_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/front.4bpp.lz"); +``` + +```diff + const u32 gMonBackPic_Calyrex[] = INCBIN_U32("graphics/pokemon/calyrex/back.4bpp.lz"); ++const u32 gMonBackPic_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/back.4bpp.lz"); +``` + +```diff + const u32 gMonPalette_Calyrex[] = INCBIN_U32("graphics/pokemon/calyrex/normal.gbapal.lz"); ++const u32 gMonPalette_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/normal.gbapal.lz"); +``` + +```diff + const u32 gMonShinyPalette_Calyrex[] = INCBIN_U32("graphics/pokemon/calyrex/shiny.gbapal.lz"); ++const u32 gMonShinyPalette_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/shiny.gbapal.lz"); +``` + +```diff + //const u8 gMonIcon_Calyrex[] = INCBIN_U8("graphics/pokemon/calyrex/icon.4bpp"); ++const u8 gMonIcon_Mewthree[] = INCBIN_U8("graphics/pokemon/mewthree/icon.4bpp"); +``` + +```diff + const u8 gMonFootprint_Calyrex[] = INCBIN_U8("graphics/pokemon/calyrex/footprint.1bpp"); ++const u8 gMonFootprint_Mewthree[] = INCBIN_U8("graphics/pokemon/mewthree/footprint.1bpp"); +``` + +Please note that Calyrex, the Pokémon that should be above your insertion for the time being, reads a "front.png" sprite instead of an "anim_front.png" sprite. This is because currently, Calyrex lacks a 2nd frame. If the front sprite sheet of your species uses 2 frames, you should use "anim_front". + +It is also worth to mention that Calyrex's icon sprite is commented out simply because it's currently missing. If you do have an icon sprite sheet present inside your species' folder at `graphics/pokemon`, by all means do not comment entries involving the `gMonIcon` constants. + +## 3. Animate the sprites + +You can define the animation order, in which the sprites will be shown. The first number is the sprite index (so 0 or 1) and the second number is the number of frames the sprite will be visible. + +Edit [src/data/pokemon_graphics/front_pic_anims.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon_graphics/front_pic_anims.h): + +```diff +static const union AnimCmd sAnim_Enamorus_1[] = +{ + ANIMCMD_FRAME(0, 1), + ANIMCMD_END, +}; + ++static const union AnimCmd sAnim_Mewthree_1[] = ++{ ++ ANIMCMD_FRAME(1, 30), ++ ANIMCMD_FRAME(0, 20), ++ ANIMCMD_END, ++}; +#endif +``` + +```diff +SINGLE_ANIMATION(Enamorus); ++SINGLE_ANIMATION(Mewthree); +#endif +``` + +```diff + const union AnimCmd *const *const gMonFrontAnimsPtrTable[] = + { + [SPECIES_NONE] = sAnims_None, + [SPECIES_BULBASAUR] = sAnims_Bulbasaur, + ... + [SPECIES_ENAMORUS] = sAnims_Enamorus, ++ [SPECIES_MEWTHREE] = sAnims_Mewthree, +#endif + ... + }; +``` + +Because you are limited to two frames, there are already [predefined front sprite animations](#available-front-animations), describing translations, rotations, scalings or color changes. + +Edit [src/pokemon.c](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/pokemon.c): +```diff + static const u8 sMonFrontAnimIdsTable[] = + { + [SPECIES_BULBASAUR - 1] = ANIM_V_JUMPS_H_JUMPS, + ... + [SPECIES_DEOXYS_SPEED - 1] = ANIM_GROW_VIBRATE, ++ [SPECIES_MEWTHREE - 1] = ANIM_GROW_VIBRATE, + }; +``` + +There are also [predefined back sprite animations](#available-back-animations) for the back sprites as well. + +Edit [src/pokemon_animation.c](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/pokemon_animation.c): + +```diff + static const u8 sSpeciesToBackAnimSet[] = + { + [SPECIES_BULBASAUR] = BACK_ANIM_DIP_RIGHT_SIDE, + ... + [SPECIES_CHIMECHO] = BACK_ANIM_CONVEX_DOUBLE_ARC, ++ [SPECIES_MEWTHREE] = BACK_ANIM_GROW_STUTTER, + }; +``` + +If you want to delay the time between when the Pokémon appears and when the animation starts, you can add an entry to `sMonAnimationDelayTable` + +Edit [src/pokemon.c](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/pokemon.c): + +```diff + static const u8 sMonAnimationDelayTable[NUM_SPECIES - 1] = + { + [SPECIES_BLASTOISE - 1] = 50, + ... + [SPECIES_KYOGRE - 1] = 60, + [SPECIES_RAYQUAZA - 1] = 60, ++ [SPECIES_MEWTHREE - 1] = 15, + }; +``` + +If you want your Pokémon to fly above the ground, you can add an entry to `gEnemyMonElevation`. + +Edit [src/data/pokemon_graphics/enemy_mon_elevation.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon_graphics/enemy_mon_elevation.h): + +```diff + const u8 gEnemyMonElevation[NUM_SPECIES] = + { + [SPECIES_BUTTERFREE] = 10, + ... + [SPECIES_REGIDRAGO] = 5, ++ [SPECIES_MEWTHREE] = 6, + }; +``` + +## 4. Update the tables + +Edit [src/data/pokemon_graphics/front_pic_table.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon_graphics/front_pic_table.h): + +```diff + const struct CompressedSpriteSheet gMonFrontPicTable[] = + { + SPECIES_SPRITE(NONE, gMonFrontPic_CircledQuestionMark), + SPECIES_SPRITE(BULBASAUR, gMonFrontPic_Bulbasaur), + ... + SPECIES_SPRITE(ENAMORUS, gMonFrontPic_Enamorus), ++ SPECIES_SPRITE(MEWTHREE, gMonFrontPic_Mewthree), +#endif + ... +}; +``` + +Edit [src/data/pokemon_graphics/front_pic_coordinates.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon_graphics/front_pic_coordinates.h): + +```diff + const struct MonCoords gMonFrontPicCoords[] = + { + ... + [SPECIES_ENAMORUS] = { .size = MON_COORDS_SIZE(64, 64), .y_offset = 0 }, ++ [SPECIES_MEWTHREE] = { .size = MON_COORDS_SIZE(64, 64), .y_offset = 0 }, +#endif + ... + }; +``` + +Edit [src/data/pokemon_graphics/back_pic_table.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon_graphics/back_pic_table.h): + +```diff + const struct CompressedSpriteSheet gMonBackPicTable[] = + { + SPECIES_SPRITE(NONE, gMonBackPic_CircledQuestionMark), + SPECIES_SPRITE(BULBASAUR, gMonBackPic_Bulbasaur), + ... + SPECIES_SPRITE(ENAMORUS, gMonBackPic_Enamorus), ++ SPECIES_SPRITE(MEWTHREE, gMonBackPic_Mewthree), +#endif + ... + }; +``` + +Edit [src/data/pokemon_graphics/back_pic_coordinates.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon_graphics/back_pic_coordinates.h): + +```diff + const struct MonCoords gMonBackPicCoords[] = + { + ... + [SPECIES_ENAMORUS] = { .size = MON_COORDS_SIZE(64, 64), .y_offset = 0 }, ++ [SPECIES_MEWTHREE] = { .size = MON_COORDS_SIZE(56, 64), .y_offset = 1 }, +#endif + ... + }; +``` + +Edit [src/data/pokemon_graphics/footprint_table.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon_graphics/footprint_table.h): + +```diff + const u8 *const gMonFootprintTable[] = + { + [SPECIES_NONE] = gMonFootprint_Bulbasaur, + [SPECIES_BULBASAUR] = gMonFootprint_Bulbasaur, + ... + [SPECIES_CALYREX] = gMonFootprint_Calyrex, ++ [SPECIES_MEWTHREE] = gMonFootprint_Mewthree, +#endif + [SPECIES_EGG] = gMonFootprint_Bulbasaur, + }; +``` + +Edit [src/data/pokemon_graphics/palette_table.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon_graphics/palette_table.h): + +```diff + const struct CompressedSpritePalette gMonPaletteTable[] = + { + SPECIES_PAL(NONE, gMonPalette_CircledQuestionMark), + SPECIES_PAL(BULBASAUR, gMonPalette_Bulbasaur), + ... + SPECIES_PAL(ENAMORUS, gMonPalette_Enamorus), ++ SPECIES_PAL(MEWTHREE, gMonPalette_Mewthree), +#endif + ... +}; +``` + +Edit [src/data/pokemon_graphics/shiny_palette_table.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon_graphics/shiny_palette_table.h): + +```diff +const struct CompressedSpritePalette gMonShinyPaletteTable[] = +{ + SPECIES_SHINY_PAL(NONE, gMonShinyPalette_CircledQuestionMark), + SPECIES_SHINY_PAL(BULBASAUR, gMonShinyPalette_Bulbasaur), + ... + SPECIES_SHINY_PAL(ENAMORUS, gMonShinyPalette_Enamorus), ++ SPECIES_SHINY_PAL(MEWTHREE, gMonShinyPalette_Mewthree), +#endif + ... +}; +``` + +Edit [src/pokemon_icon.c](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/pokemon_icon.c): + +```diff + const u8 *const gMonIconTable[] = + { + [SPECIES_NONE] = gMonIcon_Bulbasaur, + ... + [SPECIES_ENAMORUS] = gMonIcon_Enamorus, ++ [SPECIES_MEWTHREE] = gMonIcon_Mewthree, +#endif + ... + }; +``` + +```diff + const u8 gMonIconPaletteIndices[] = + { + [SPECIES_NONE] = 0, + ... + [SPECIES_ENAMORUS] = 1, ++ [SPECIES_MEWTHREE] = 2, + [SPECIES_VENUSAUR_MEGA] = 1, + ... + }; +``` + +Here, you can choose between the six icon palettes; 0, 1, 2, 3, 4 and 5. All of them located in `graphics/pokemon/icon_palettes`. + +Open an icon sprite and load one of the palettes to find out which palette suits your icon sprite best. + +# The Data + +Our plan is as simple as it is brilliant: clone Mewtwo... and make it even stronger! + +## 1. Declare a species constant + +Our first step towards creating a new digital lifeform is to define its own species constant. + +Edit [include/constants/species.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/species.h): + +```diff + #define SPECIES_NONE 0 + #define SPECIES_BULBASAUR 1 + ... + #define SPECIES_ENAMORUS 905 ++#define SPECIES_MEWTHREE 906 + +-#define FORMS_START SPECIES_ENAMORUS ++#define FORMS_START SPECIES_MEWTHREE +``` + +## 2. Devise a name + + +This name will be displayed in the game. It may be different than the identifier of the species constant, especially when there are special characters involved. + +Edit [src/data/text/species_names.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/text/species_names.h): + +```diff + const u8 gSpeciesNames[][POKEMON_NAME_LENGTH + 1] = { + [SPECIES_NONE] = _("??????????"), + [SPECIES_BULBASAUR] = _("Bulbasaur"), + ... + [SPECIES_ENAMORUS] = _("Enamorus"), ++ [SPECIES_MEWTHREE] = _("Mewthree"), + }; +``` + +The `_()` underscore function doesn't really exist - it's a convention borrowed from GNU gettext to let `preproc` know this is text to be converted to the custom encoding used by the Gen 3 Pokemon games. + +## 3. Define its Pokédex entry + +First, we will need to add new index constants for its Pokédex entry. The index constants are divided into the Hoenn Pokédex, which contains all Pokémon native to the Hoenn region, and the National Pokédex containing all known Pokémon, which can be received after entering the hall of fame for the first time. + +Edit [include/constants/pokedex.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/pokedex.h): + +```diff +// National Pokedex order +enum { + NATIONAL_DEX_NONE, + // Kanto + NATIONAL_DEX_BULBASAUR, +... + NATIONAL_DEX_ENAMORUS, ++ NATIONAL_DEX_MEWTHREE, +}; +``` + +```diff + #define KANTO_DEX_COUNT NATIONAL_DEX_MEW + #define JOHTO_DEX_COUNT NATIONAL_DEX_CELEBI +#if P_GEN_8_POKEMON == TRUE +- #define NATIONAL_DEX_COUNT NATIONAL_DEX_ENAMORUS ++ #define NATIONAL_DEX_COUNT NATIONAL_DEX_MEWTHREE +``` + +Do keep in mind that if you intend to add your new species to the Hoenn Dex, you'll also want to add a `HOENN_DEX` constant for it, like this: + +```diff +// Hoenn Pokedex order +enum { + HOENN_DEX_NONE, + HOENN_DEX_TREECKO, +... + HOENN_DEX_DEOXYS, ++ HOENN_DEX_MEWTHREE, +... +}; +``` + +```diff +- #define HOENN_DEX_COUNT (HOENN_DEX_DEOXYS + 1) ++ #define HOENN_DEX_COUNT (HOENN_DEX_MEWTHREE + 1) +``` + +Edit [src/pokemon.c](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/pokemon.c): + + +```diff + // Assigns all species to the National Dex Index (Summary No. for National Dex) + static const u16 sSpeciesToNationalPokedexNum[NUM_SPECIES - 1] = + { + SPECIES_TO_NATIONAL(ENAMORUS), ++ SPECIES_TO_NATIONAL(MEWTHREE), + }; +``` + +Just like before, if we want to insert our new species in the Hoenn Dex, we'll have to do a few extra steps: + +```diff + // Assigns all species to the Hoenn Dex Index (Summary No. for Hoenn Dex) + static const u16 sSpeciesToHoennPokedexNum[NUM_SPECIES - 1] = + { + SPECIES_TO_HOENN(TREECKO), + ... + SPECIES_TO_HOENN(DEOXYS), ++ SPECIES_TO_HOENN(MEWTHREE), + }; +``` + +```diff + const u16 gHoennToNationalOrder[NUM_SPECIES] = // Assigns Hoenn Dex Pokémon (Using National Dex Index) + { + HOENN_TO_NATIONAL(TREECKO), + ... + HOENN_TO_NATIONAL(DEOXYS), ++ HOENN_TO_NATIONAL(MEWTHREE), + }; +``` + +Now we can define the actual text of the Pokédex entry. + +Append to [src/data/pokemon/pokedex_text.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/pokedex_text.h): + +```diff + const u8 gEnamorusPokedexText[] = _( + "Its arrival brings an end to the\n" + "winter. According to legend, this\n" + "Pokémon's love gives rise to the\n" + "budding of fresh life across the land."); + ++const u8 gMewthreePokedexText[] = _( ++ "The rumors became true.\n" ++ "This is Mews final form.\n" ++ "Its power level is over 9000.\n" ++ "Has science gone too far?"); +``` + +Finally, we will add the Pokédex entry for Mewthree and link the text to it. + +Edit [src/data/pokemon/pokedex_entries.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/pokedex_entries.h): + +```diff + const struct PokedexEntry gPokedexEntries[] = + { + ... + [NATIONAL_DEX_ENAMORUS] = + { + .categoryName = _("Love-Hate"), + .height = 16, + .weight = 480, + .description = gEnamorusPokedexText, + .pokemonScale = 259, + .pokemonOffset = 1, + .trainerScale = 296, + .trainerOffset = 1, + }, + ++ [NATIONAL_DEX_MEWTHREE] = ++ { ++ .categoryName = _("NEW SPECIES"), ++ .height = 15, ++ .weight = 330, ++ .description = gMewthreePokedexText, ++ .pokemonScale = 256, ++ .pokemonOffset = 0, ++ .trainerScale = 290, ++ .trainerOffset = 2, ++ }, + #endif + }; +``` + +The values `pokemonScale`, `pokemonOffset`, `trainerScale` and `trainerOffset` are used for the height comparison figure in the Pokédex. Height and weight are specified in meters and kilograms respectively, while the last digit is the first decimal place. + +In Pokémon Emerald, you can sort the Pokédex by name, height or weight. Apparently, the Pokémon order is hardcoded in the game files and not calculated from their data. Therefore we have to include our new Pokémon species at the right places. While the correct position for the alphabetical order is easy to find, it can become quite tedious for height and weight. To find the right position for your Pokémon, you may look at the tables sorted by [height](#pokémon-ordered-by-height) and [weight](#pokémon-ordered-by-weight) respectively in the appendix. + +Edit [src/data/pokemon/pokedex_orders.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/pokedex_orders.h): + +```diff + const u16 gPokedexOrder_Alphabetical[] = + { + ... + NATIONAL_DEX_MEW, ++ NATIONAL_DEX_MEWTHREE, + NATIONAL_DEX_MEWTWO, + ... + }; + + const u16 gPokedexOrder_Weight[] = + { + ... + NATIONAL_DEX_ESCAVALIER, + NATIONAL_DEX_FRILLISH, + NATIONAL_DEX_DURANT, + NATIONAL_DEX_CINDERACE, ++ NATIONAL_DEX_MEWTHREE, + //NATIONAL_DEX_PERSIAN, // Alolan Form + NATIONAL_DEX_DUGTRIO, + ... + }; + + const u16 gPokedexOrder_Height[] = + { + ... + NATIONAL_DEX_ZERAORA, + NATIONAL_DEX_GRIMMSNARL, + NATIONAL_DEX_MR_RIME, ++ NATIONAL_DEX_MEWTHREE, + // 5'03" / 1.6m + ... + }; +``` + +## 4. Define its species information +Edit [src/data/pokemon/species_info.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/species_info.h): +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + [SPECIES_NONE] = {0}, + ... + + [SPECIES_ENAMORUS] = + { + .baseHP = 74, + .baseAttack = 115, + .baseDefense = 70, + .baseSpeed = 106, + .baseSpAttack = 135, + .baseSpDefense = 80, + .types = { TYPE_FAIRY, TYPE_FLYING}, + .catchRate = 3, + .expYield = 261, + .evYield_SpAttack = 3, + .genderRatio = MON_FEMALE, + .eggCycles = 120, + .friendship = 90, + .growthRate = GROWTH_SLOW, + .eggGroups = { EGG_GROUP_UNDISCOVERED, EGG_GROUP_UNDISCOVERED}, + .abilities = {ABILITY_HEALER, ABILITY_NONE, ABILITY_CONTRARY}, + .bodyColor = BODY_COLOR_PINK, + .noFlip = FALSE, + .flags = SPECIES_FLAG_LEGENDARY, + }, + ++ [SPECIES_MEWTHREE] = ++ { ++ .baseHP = 106, ++ .baseAttack = 150, ++ .baseDefense = 70, ++ .baseSpeed = 140, ++ .baseSpAttack = 194, ++ .baseSpDefense = 120, ++ .types = { TYPE_PSYCHIC, TYPE_PSYCHIC}, ++ .catchRate = 3, ++ .expYield = 255, ++ .evYield_SpAttack = 3, ++ .genderRatio = MON_GENDERLESS, ++ .eggCycles = 120, ++ .friendship = 0, ++ .growthRate = GROWTH_SLOW, ++ .eggGroups = { EGG_GROUP_UNDISCOVERED, EGG_GROUP_UNDISCOVERED}, ++ .abilities = {ABILITY_INSOMNIA, ABILITY_NONE}, ++ .safariZoneFleeRate = 0, ++ .bodyColor = BODY_COLOR_PURPLE, ++ .noFlip = FALSE, ++ }, +#endif + }; +``` + +The `.` is the structure reference operator in C to refer to the member object of the structure SpeciesInfo. + +Notice how I also set the ability to `ABILITY_INSOMNIA`, so our little monster doesn't even need to sleep anymore. You can find the abilities for example here [include/constants/abilities.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/abilities.h) and here [src/data/text/abilities.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/text/abilities.h). + +You can also incorporate a 3rd ability to your species, which is intended to be a [Hidden Ability](https://bulbapedia.bulbagarden.net/wiki/Ability#Hidden_Abilities)! + +## 5. Delimit the moveset + +Let's begin with the moves that can be learned by leveling up. + +Append to [src/data/pokemon/level_up_learnsets.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/level_up_learnsets.h): + +```diff +static const struct LevelUpMove sEnamorusLevelUpLearnset[] = { + LEVEL_UP_MOVE( 1, MOVE_TACKLE), + LEVEL_UP_MOVE( 7, MOVE_BITE), + LEVEL_UP_MOVE(11, MOVE_TWISTER), + LEVEL_UP_MOVE(14, MOVE_DRAINING_KISS), + LEVEL_UP_MOVE(22, MOVE_IRON_DEFENSE), + LEVEL_UP_MOVE(31, MOVE_EXTRASENSORY), + LEVEL_UP_MOVE(41, MOVE_CRUNCH), + LEVEL_UP_MOVE(47, MOVE_MOONBLAST), + LEVEL_UP_MOVE( 1, MOVE_SPRINGTIDE_STORM), + LEVEL_UP_END +}; + ++static const struct LevelUpMove sMewthreeLevelUpLearnset[] = { ++ LEVEL_UP_MOVE( 1, MOVE_CONFUSION), ++ LEVEL_UP_MOVE( 1, MOVE_DISABLE), ++ LEVEL_UP_MOVE(11, MOVE_BARRIER), ++ LEVEL_UP_MOVE(22, MOVE_SWIFT), ++ LEVEL_UP_MOVE(33, MOVE_PSYCH_UP), ++ LEVEL_UP_MOVE(44, MOVE_FUTURE_SIGHT), ++ LEVEL_UP_MOVE(55, MOVE_MIST), ++ LEVEL_UP_MOVE(66, MOVE_PSYCHIC), ++ LEVEL_UP_MOVE(77, MOVE_AMNESIA), ++ LEVEL_UP_MOVE(88, MOVE_RECOVER), ++ LEVEL_UP_MOVE(99, MOVE_SAFEGUARD), ++ LEVEL_UP_END ++}; +#endif +``` + +Again, we need to register the learnset. + +Edit [src/data/pokemon/level_up_learnset_pointers.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/level_up_learnset_pointers.h): + +```diff + const struct LevelUpMove *const gLevelUpLearnsets[NUM_SPECIES] = + { + [SPECIES_NONE] = sBulbasaurLevelUpLearnset, + [SPECIES_BULBASAUR] = sBulbasaurLevelUpLearnset, + ... + [SPECIES_ENAMORUS] = sEnamorusLevelUpLearnset, ++ [SPECIES_MEWTHREE] = sMewthreeLevelUpLearnset, + }; +``` + +Next we need to specify which moves can be taught via TM, HM, or Move Tutor. + +Append to [src/data/pokemon/teachable_learnsets.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/teachable_learnsets.h): + +```diff +static const u16 sEnamorusTeachableLearnset[] = { + MOVE_UNAVAILABLE, +}; + ++static const u16 sMewthreeTeachableLearnset[] = { ++ MOVE_FOCUS_PUNCH, ++ MOVE_WATER_PULSE, ++ MOVE_CALM_MIND, ++ MOVE_TOXIC, ++ MOVE_HAIL, ++ MOVE_BULK_UP, ++ MOVE_HIDDEN_POWER, ++ MOVE_SUNNY_DAY, ++ MOVE_TAUNT, ++ MOVE_ICE_BEAM, ++ MOVE_BLIZZARD, ++ MOVE_HYPER_BEAM, ++ MOVE_LIGHT_SCREEN, ++ MOVE_PROTECT, ++ MOVE_RAIN_DANCE, ++ MOVE_SAFEGUARD, ++ MOVE_FRUSTRATION, ++ MOVE_SOLAR_BEAM, ++ MOVE_IRON_TAIL, ++ MOVE_THUNDERBOLT, ++ MOVE_THUNDER, ++ MOVE_EARTHQUAKE, ++ MOVE_RETURN, ++ MOVE_PSYCHIC, ++ MOVE_SHADOW_BALL, ++ MOVE_BRICK_BREAK, ++ MOVE_DOUBLE_TEAM, ++ MOVE_REFLECT, ++ MOVE_SHOCK_WAVE, ++ MOVE_FLAMETHROWER, ++ MOVE_SANDSTORM, ++ MOVE_FIRE_BLAST, ++ MOVE_ROCK_TOMB, ++ MOVE_AERIAL_ACE, ++ MOVE_TORMENT, ++ MOVE_FACADE, ++ MOVE_SECRET_POWER, ++ MOVE_REST, ++ MOVE_SKILL_SWAP, ++ MOVE_SNATCH, ++ MOVE_STRENGTH, ++ MOVE_FLASH, ++ MOVE_ROCK_SMASH, ++ MOVE_MEGA_PUNCH, ++ MOVE_MEGA_KICK, ++ MOVE_BODY_SLAM, ++ MOVE_DOUBLE_EDGE, ++ MOVE_COUNTER, ++ MOVE_SEISMIC_TOSS, ++ MOVE_MIMIC, ++ MOVE_METRONOME, ++ MOVE_DREAM_EATER, ++ MOVE_THUNDER_WAVE, ++ MOVE_SUBSTITUTE, ++ MOVE_DYNAMIC_PUNCH, ++ MOVE_PSYCH_UP, ++ MOVE_SNORE, ++ MOVE_ICY_WIND, ++ MOVE_ENDURE, ++ MOVE_MUD_SLAP, ++ MOVE_ICE_PUNCH, ++ MOVE_SWAGGER, ++ MOVE_SLEEP_TALK, ++ MOVE_SWIFT, ++ MOVE_THUNDER_PUNCH, ++ MOVE_FIRE_PUNCH, ++ MOVE_UNAVAILABLE, ++}; +#endif +``` + +Once more, we need to register the learnset. + +Edit [src/data/pokemon/teachable_learnset_pointers.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/teachable_learnset_pointers.h): + +```diff +const u16 *const gTeachableLearnsets[NUM_SPECIES] = + { + [SPECIES_NONE] = sBulbasaurTeachableLearnset, + [SPECIES_BULBASAUR] = sBulbasaurTeachableLearnset, + ... + [SPECIES_ENAMORUS] = sEnamorusTeachableLearnset, ++ [SPECIES_MEWTHREE] = sMewthreeTeachableLearnset, + }; +``` + +If you want to create a Pokémon which can breed, you will need to edit [src/data/pokemon/egg_moves.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/egg_moves.h). + +## 6. Define its cry +First run these command to copy the Mewtwo sound files: +```sh +cp -r sound/direct_sound_samples/cries/mewtwo.bin sound/direct_sound_samples/cries/mewthree.bin +cp -r sound/direct_sound_samples/cries/mewtwo.aif sound/direct_sound_samples/cries/mewthree.aif +``` + +In [sound/direct_sound_data.inc](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/sound/direct_sound_data.inc). + +```diff + .align 2 +Cry_Enamorus:: + .incbin "sound/direct_sound_samples/cries/enamorus.bin" + ++ .align 2 ++Cry_Mewthree:: ++ .incbin "sound/direct_sound_samples/cries/mewthree.bin" + +.endif +``` + +And linking it in [sound/cry_tables.inc](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/sound/cry_tables.inc). `cry_reverse` in particular is for reversed cries used by moves such as Growl. + +```diff +... + cry Cry_Enamorus ++ cry Cry_Mewthree +.else +``` + +```diff + cry_reverse Cry_Overqwil ++ cry_reverse Cry_Mewthree +.else +``` + +Mon cries are 10512Hz. Make sure to put the aif file in the directory [sound/direct_sound_samples/cries](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/sound/direct_sound_samples/cries) + +Higher frequencies may be ruined by compression. To have the cries uncompressed, follow [this](https://github.com/ShinyDragonHunter/pokefirereddx/commit/71ba1c193082817afbed9a8a0ba1d123fffb6f36#diff-e1823f56db7c2344fb9ee843e3c42797f72fa1e108e13a7080018e1db545322eR116) , then clear out the old sound bins + +## 7. Define the Evolutions + +We want Mewthree to evolve from Mewtwo by reaching level 100. + +Edit [src/data/pokemon/evolution.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/evolution.h): + +```diff + [SPECIES_SNEASEL_HISUIAN] = {{EVO_ITEM_DAY, ITEM_RAZOR_CLAW, SPECIES_SNEASLER}, + {EVO_ITEM_HOLD_DAY, ITEM_RAZOR_CLAW, SPECIES_SNEASLER}}, ++ [SPECIES_MEWTWO] = {{EVO_LEVEL, 100, SPECIES_MEWTHREE}}, +#endif +``` + +## 8. Easy Chat about your Pokémon + + +Edit [src/data/easy_chat/easy_chat_words_by_letter.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/easy_chat/easy_chat_words_by_letter.h): + +```diff + const u16 gEasyChatWordsByLetter_M[] = { + EC_MOVE2(MACH_PUNCH), + ... + EC_POKEMON_NATIONAL(MEW), ++ EC_POKEMON_NATIONAL(MEWTHREE), + EC_POKEMON_NATIONAL(MEWTWO), + ... + EC_WORD_MYSTERY, + }; +``` + +## 9. Make it appear! + + +Now Mewthree really does slumber in the games code - but we won't know until we make him appear somewhere! The legend tells that Mewthree is hiding somewhere in Petalburg Woods... + +Edit [src/data/wild_encounters.json](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/wild_encounters.json): + +```diff + { + "map": "MAP_PETALBURG_WOODS", + "base_label": "gPetalburgWoods", + "land_mons": { + "encounter_rate": 20, + "mons": [ + { + "min_level": 5, + "max_level": 5, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 5, + "max_level": 5, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 5, + "max_level": 5, + "species": "SPECIES_SHROOMISH" + }, + { +- "min_level": 6, +- "max_level": 6, +- "species": "SPECIES_POOCHYENA" ++ "min_level": 5, ++ "max_level": 5, ++ "species": "SPECIES_MEWTHREE" + }, + ... + } +``` + +Congratulations, you have created your own personal pocket monster! You may call yourself a mad scientist now. + +# Appendix +## Available Front Animations +_Only 65 are used in-game, but you can use any animation from this list._ +1. ANIM_V_SQUISH_AND_BOUNCE +2. ANIM_CIRCULAR_STRETCH_TWICE +3. ANIM_H_VIBRATE +4. ANIM_H_SLIDE +5. ANIM_V_SLIDE +6. ANIM_BOUNCE_ROTATE_TO_SIDES +7. ANIM_V_JUMPS_H_JUMPS +8. ANIM_ROTATE_TO_SIDES +9. ANIM_ROTATE_TO_SIDES_TWICE +10. ANIM_GROW_VIBRATE +11. ANIM_ZIGZAG_FAST +12. ANIM_SWING_CONCAVE +13. ANIM_SWING_CONCAVE_FAST +14. ANIM_SWING_CONVEX +15. ANIM_SWING_CONVEX_FAST +16. ANIM_H_SHAKE +17. ANIM_V_SHAKE +18. ANIM_CIRCULAR_VIBRATE +19. ANIM_TWIST +20. ANIM_SHRINK_GROW +21. ANIM_CIRCLE_C_CLOCKWISE +22. ANIM_GLOW_BLACK +23. ANIM_H_STRETCH +24. ANIM_V_STRETCH +25. ANIM_RISING_WOBBLE +26. ANIM_V_SHAKE_TWICE +27. ANIM_TIP_MOVE_FORWARD +28. ANIM_H_PIVOT +29. ANIM_V_SLIDE_WOBBLE +30. ANIM_H_SLIDE_WOBBLE +31. ANIM_V_JUMPS_BIG +32. ANIM_SPIN_LONG +33. ANIM_GLOW_ORANGE +34. ANIM_GLOW_RED +35. ANIM_GLOW_BLUE +36. ANIM_GLOW_YELLOW +37. ANIM_GLOW_PURPLE +38. ANIM_BACK_AND_LUNGE +39. ANIM_BACK_FLIP +40. ANIM_FLICKER +41. ANIM_BACK_FLIP_BIG +42. ANIM_FRONT_FLIP +43. ANIM_TUMBLING_FRONT_FLIP +44. ANIM_FIGURE_8 +45. ANIM_FLASH_YELLOW +46. ANIM_SWING_CONCAVE_FAST_SHORT +47. ANIM_SWING_CONVEX_FAST_SHORT +48. ANIM_ROTATE_UP_SLAM_DOWN +49. ANIM_DEEP_V_SQUISH_AND_BOUNCE +50. ANIM_H_JUMPS +51. ANIM_H_JUMPS_V_STRETCH +52. ANIM_ROTATE_TO_SIDES_FAST +53. ANIM_ROTATE_UP_TO_SIDES +54. ANIM_FLICKER_INCREASING +55. ANIM_TIP_HOP_FORWARD +56. ANIM_PIVOT_SHAKE +57. ANIM_TIP_AND_SHAKE +58. ANIM_VIBRATE_TO_CORNERS +59. ANIM_GROW_IN_STAGES +60. ANIM_V_SPRING +61. ANIM_V_REPEATED_SPRING +62. ANIM_SPRING_RISING +63. ANIM_H_SPRING +64. ANIM_H_REPEATED_SPRING_SLOW +65. ANIM_H_SLIDE_SHRINK +66. ANIM_LUNGE_GROW +67. ANIM_CIRCLE_INTO_BG +68. ANIM_RAPID_H_HOPS +69. ANIM_FOUR_PETAL +70. ANIM_V_SQUISH_AND_BOUNCE_SLOW +71. ANIM_H_SLIDE_SLOW +72. ANIM_V_SLIDE_SLOW +73. ANIM_BOUNCE_ROTATE_TO_SIDES_SMALL +74. ANIM_BOUNCE_ROTATE_TO_SIDES_SLOW +75. ANIM_BOUNCE_ROTATE_TO_SIDES_SMALL_SLOW +76. ANIM_ZIGZAG_SLOW +77. ANIM_H_SHAKE_SLOW +78. ANIM_V_SHAKE_SLOW +79. ANIM_TWIST_TWICE +80. ANIM_CIRCLE_C_CLOCKWISE_SLOW +81. ANIM_V_SHAKE_TWICE_SLOW +82. ANIM_V_SLIDE_WOBBLE_SMALL +83. ANIM_V_JUMPS_SMALL +84. ANIM_SPIN +85. ANIM_TUMBLING_FRONT_FLIP_TWICE +86. ANIM_DEEP_V_SQUISH_AND_BOUNCE_TWICE +87. ANIM_H_JUMPS_V_STRETCH_TWICE +88. ANIM_V_SHAKE_BACK +89. ANIM_V_SHAKE_BACK_SLOW +90. ANIM_V_SHAKE_H_SLIDE_SLOW +91. ANIM_V_STRETCH_BOTH_ENDS_SLOW +92. ANIM_H_STRETCH_FAR_SLOW +93. ANIM_V_SHAKE_LOW_TWICE +94. ANIM_H_SHAKE_FAST +95. ANIM_H_SLIDE_FAST +96. ANIM_H_VIBRATE_FAST +97. ANIM_H_VIBRATE_FASTEST +98. ANIM_V_SHAKE_BACK_FAST +99. ANIM_V_SHAKE_LOW_TWICE_SLOW +100. ANIM_V_SHAKE_LOW_TWICE_FAST +101. ANIM_CIRCLE_C_CLOCKWISE_LONG +102. ANIM_GROW_STUTTER_SLOW +103. ANIM_V_SHAKE_H_SLIDE +104. ANIM_V_SHAKE_H_SLIDE_FAST +105. ANIM_TRIANGLE_DOWN_SLOW +106. ANIM_TRIANGLE_DOWN +107. ANIM_TRIANGLE_DOWN_TWICE +108. ANIM_GROW +109. ANIM_GROW_TWICE +110. ANIM_H_SPRING_FAST +111. ANIM_H_SPRING_SLOW +112. ANIM_H_REPEATED_SPRING_FAST +113. ANIM_H_REPEATED_SPRING +114. ANIM_SHRINK_GROW_FAST +115. ANIM_SHRINK_GROW_SLOW +116. ANIM_V_STRETCH_BOTH_ENDS +117. ANIM_V_STRETCH_BOTH_ENDS_TWICE +118. ANIM_H_STRETCH_FAR_TWICE +119. ANIM_H_STRETCH_FAR +120. ANIM_GROW_STUTTER_TWICE +121. ANIM_GROW_STUTTER +122. ANIM_CONCAVE_ARC_LARGE_SLOW +123. ANIM_CONCAVE_ARC_LARGE +124. ANIM_CONCAVE_ARC_LARGE_TWICE +125. ANIM_CONVEX_DOUBLE_ARC_SLOW +126. ANIM_CONVEX_DOUBLE_ARC +127. ANIM_CONVEX_DOUBLE_ARC_TWICE +128. ANIM_CONCAVE_ARC_SMALL_SLOW +129. ANIM_CONCAVE_ARC_SMALL +130. ANIM_CONCAVE_ARC_SMALL_TWICE +131. ANIM_H_DIP +132. ANIM_H_DIP_FAST +133. ANIM_H_DIP_TWICE +134. ANIM_SHRINK_GROW_VIBRATE_FAST +135. ANIM_SHRINK_GROW_VIBRATE +136. ANIM_SHRINK_GROW_VIBRATE_SLOW +137. ANIM_JOLT_RIGHT_FAST +138. ANIM_JOLT_RIGHT +139. ANIM_JOLT_RIGHT_SLOW +140. ANIM_SHAKE_FLASH_YELLOW_FAST +141. ANIM_SHAKE_FLASH_YELLOW +142. ANIM_SHAKE_FLASH_YELLOW_SLOW +143. ANIM_SHAKE_GLOW_RED_FAST +144. ANIM_SHAKE_GLOW_RED +145. ANIM_SHAKE_GLOW_RED_SLOW +146. ANIM_SHAKE_GLOW_GREEN_FAST +147. ANIM_SHAKE_GLOW_GREEN +148. ANIM_SHAKE_GLOW_GREEN_SLOW +149. ANIM_SHAKE_GLOW_BLUE_FAST +150. ANIM_SHAKE_GLOW_BLUE +151. ANIM_SHAKE_GLOW_BLUE_SLOW + +## Available Back Animations +1. BACK_ANIM_NONE +2. BACK_ANIM_H_VIBRATE +3. BACK_ANIM_H_SLIDE +4. BACK_ANIM_H_SPRING +5. BACK_ANIM_H_SPRING_REPEATED +6. BACK_ANIM_SHRINK_GROW +7. BACK_ANIM_GROW +8. BACK_ANIM_CIRCLE_COUNTERCLOCKWISE +9. BACK_ANIM_H_SHAKE +10. BACK_ANIM_V_SHAKE +11. BACK_ANIM_V_SHAKE_H_SLIDE +12. BACK_ANIM_V_STRETCH +13. BACK_ANIM_H_STRETCH +14. BACK_ANIM_GROW_STUTTER +15. BACK_ANIM_V_SHAKE_LOW +16. BACK_ANIM_TRIANGLE_DOWN +17. BACK_ANIM_CONCAVE_ARC_LARGE +18. BACK_ANIM_CONVEX_DOUBLE_ARC +19. BACK_ANIM_CONCAVE_ARC_SMALL +20. BACK_ANIM_DIP_RIGHT_SIDE +21. BACK_ANIM_SHRINK_GROW_VIBRATE +22. BACK_ANIM_JOLT_RIGHT +23. BACK_ANIM_SHAKE_FLASH_YELLOW +24. BACK_ANIM_SHAKE_GLOW_RED +25. BACK_ANIM_SHAKE_GLOW_GREEN +26. BACK_ANIM_SHAKE_GLOW_BLUE + +## Pokémon ordered by height +| Pokemon | height (m) | +| :------ | ---------: | +| Diglett | 0.2 | +| Natu | 0.2 | +| Azurill | 0.2 | +| Caterpie | 0.3 | +| Weedle | 0.3 | +| Pidgey | 0.3 | +| Rattata | 0.3 | +| Spearow | 0.3 | +| Paras | 0.3 | +| Magnemite | 0.3 | +| Shellder | 0.3 | +| Ditto | 0.3 | +| Eevee | 0.3 | +| Pichu | 0.3 | +| Cleffa | 0.3 | +| Igglybuff | 0.3 | +| Togepi | 0.3 | +| Sunkern | 0.3 | +| Wurmple | 0.3 | +| Taillow | 0.3 | +| Roselia | 0.3 | +| Castform | 0.3 | +| Jirachi | 0.3 | +| Pikachu | 0.4 | +| Nidoran_f | 0.4 | +| Meowth | 0.4 | +| Geodude | 0.4 | +| Krabby | 0.4 | +| Exeggcute | 0.4 | +| Cubone | 0.4 | +| Horsea | 0.4 | +| Omanyte | 0.4 | +| Mew | 0.4 | +| Bellossom | 0.4 | +| Marill | 0.4 | +| Hoppip | 0.4 | +| Wooper | 0.4 | +| Swinub | 0.4 | +| Smoochum | 0.4 | +| Torchic | 0.4 | +| Mudkip | 0.4 | +| Zigzagoon | 0.4 | +| Ralts | 0.4 | +| Shroomish | 0.4 | +| Aron | 0.4 | +| Plusle | 0.4 | +| Minun | 0.4 | +| Gulpin | 0.4 | +| Cacnea | 0.4 | +| Swablu | 0.4 | +| Barboach | 0.4 | +| Clamperl | 0.4 | +| Squirtle | 0.5 | +| Nidoran_m | 0.5 | +| Jigglypuff | 0.5 | +| Oddish | 0.5 | +| Mankey | 0.5 | +| Voltorb | 0.5 | +| Kabuto | 0.5 | +| Cyndaquil | 0.5 | +| Spinarak | 0.5 | +| Chinchou | 0.5 | +| Murkrow | 0.5 | +| Unown | 0.5 | +| Qwilfish | 0.5 | +| Phanpy | 0.5 | +| Treecko | 0.5 | +| Poochyena | 0.5 | +| Linoone | 0.5 | +| Lotad | 0.5 | +| Seedot | 0.5 | +| Surskit | 0.5 | +| Nincada | 0.5 | +| Sableye | 0.5 | +| Torkoal | 0.5 | +| Baltoy | 0.5 | +| Charmander | 0.6 | +| Kakuna | 0.6 | +| Sandshrew | 0.6 | +| Clefairy | 0.6 | +| Vulpix | 0.6 | +| Poliwag | 0.6 | +| Koffing | 0.6 | +| Goldeen | 0.6 | +| Totodile | 0.6 | +| Togetic | 0.6 | +| Mareep | 0.6 | +| Skiploom | 0.6 | +| Pineco | 0.6 | +| Snubbull | 0.6 | +| Shuckle | 0.6 | +| Teddiursa | 0.6 | +| Corsola | 0.6 | +| Remoraid | 0.6 | +| Houndour | 0.6 | +| Porygon2 | 0.6 | +| Elekid | 0.6 | +| Larvitar | 0.6 | +| Celebi | 0.6 | +| Silcoon | 0.6 | +| Wingull | 0.6 | +| Whismur | 0.6 | +| Skitty | 0.6 | +| Mawile | 0.6 | +| Meditite | 0.6 | +| Electrike | 0.6 | +| Illumise | 0.6 | +| Corphish | 0.6 | +| Feebas | 0.6 | +| Shuppet | 0.6 | +| Chimecho | 0.6 | +| Wynaut | 0.6 | +| Luvdisc | 0.6 | +| Bagon | 0.6 | +| Beldum | 0.6 | +| Bulbasaur | 0.7 | +| Metapod | 0.7 | +| Raticate | 0.7 | +| Dugtrio | 0.7 | +| Growlithe | 0.7 | +| Bellsprout | 0.7 | +| Hoothoot | 0.7 | +| Misdreavus | 0.7 | +| Slugma | 0.7 | +| Tyrogue | 0.7 | +| Magby | 0.7 | +| Marshtomp | 0.7 | +| Cascoon | 0.7 | +| Swellow | 0.7 | +| Volbeat | 0.7 | +| Numel | 0.7 | +| Spoink | 0.7 | +| Trapinch | 0.7 | +| Anorith | 0.7 | +| Snorunt | 0.7 | +| Raichu | 0.8 | +| Nidorina | 0.8 | +| Zubat | 0.8 | +| Gloom | 0.8 | +| Psyduck | 0.8 | +| Machop | 0.8 | +| Farfetchd | 0.8 | +| Staryu | 0.8 | +| Jolteon | 0.8 | +| Porygon | 0.8 | +| Sentret | 0.8 | +| Flaaffy | 0.8 | +| Azumarill | 0.8 | +| Jumpluff | 0.8 | +| Aipom | 0.8 | +| Sunflora | 0.8 | +| Magcargo | 0.8 | +| Kirlia | 0.8 | +| Masquerain | 0.8 | +| Slakoth | 0.8 | +| Ninjask | 0.8 | +| Shedinja | 0.8 | +| Carvanha | 0.8 | +| Duskull | 0.8 | +| Spheal | 0.8 | +| Nidorino | 0.9 | +| Abra | 0.9 | +| Tentacool | 0.9 | +| Grimer | 0.9 | +| Magikarp | 0.9 | +| Flareon | 0.9 | +| Chikorita | 0.9 | +| Quilava | 0.9 | +| Espeon | 0.9 | +| Sneasel | 0.9 | +| Octillery | 0.9 | +| Delibird | 0.9 | +| Grovyle | 0.9 | +| Combusken | 0.9 | +| Lairon | 0.9 | +| Grumpig | 0.9 | +| Whiscash | 0.9 | +| Ivysaur | 1.0 | +| Wartortle | 1.0 | +| Beedrill | 1.0 | +| Sandslash | 1.0 | +| Wigglytuff | 1.0 | +| Parasect | 1.0 | +| Venonat | 1.0 | +| Persian | 1.0 | +| Primeape | 1.0 | +| Poliwhirl | 1.0 | +| Weepinbell | 1.0 | +| Graveler | 1.0 | +| Ponyta | 1.0 | +| Magneton | 1.0 | +| Drowzee | 1.0 | +| Marowak | 1.0 | +| Rhyhorn | 1.0 | +| Tangela | 1.0 | +| Vaporeon | 1.0 | +| Omastar | 1.0 | +| Ledyba | 1.0 | +| Umbreon | 1.0 | +| Mightyena | 1.0 | +| Beautifly | 1.0 | +| Nuzleaf | 1.0 | +| Loudred | 1.0 | +| Makuhita | 1.0 | +| Nosepass | 1.0 | +| Lunatone | 1.0 | +| Lileep | 1.0 | +| Kecleon | 1.0 | +| Relicanth | 1.0 | +| Charmeleon | 1.1 | +| Butterfree | 1.1 | +| Pidgeotto | 1.1 | +| Ninetales | 1.1 | +| Seel | 1.1 | +| Chansey | 1.1 | +| Starmie | 1.1 | +| Electabuzz | 1.1 | +| Croconaw | 1.1 | +| Ariados | 1.1 | +| Politoed | 1.1 | +| Gligar | 1.1 | +| Piloswine | 1.1 | +| Donphan | 1.1 | +| Delcatty | 1.1 | +| Spinda | 1.1 | +| Vibrava | 1.1 | +| Altaria | 1.1 | +| Crawdaunt | 1.1 | +| Banette | 1.1 | +| Sealeo | 1.1 | +| Shelgon | 1.1 | +| Fearow | 1.2 | +| Vileplume | 1.2 | +| Slowpoke | 1.2 | +| Muk | 1.2 | +| Electrode | 1.2 | +| Lickitung | 1.2 | +| Weezing | 1.2 | +| Seadra | 1.2 | +| Bayleef | 1.2 | +| Lanturn | 1.2 | +| Sudowoodo | 1.2 | +| Yanma | 1.2 | +| Forretress | 1.2 | +| Smeargle | 1.2 | +| Miltank | 1.2 | +| Pupitar | 1.2 | +| Dustox | 1.2 | +| Lombre | 1.2 | +| Pelipper | 1.2 | +| Breloom | 1.2 | +| Solrock | 1.2 | +| Absol | 1.2 | +| Metang | 1.2 | +| Nidoqueen | 1.3 | +| Clefable | 1.3 | +| Poliwrath | 1.3 | +| Kadabra | 1.3 | +| Gastly | 1.3 | +| Kingler | 1.3 | +| Seaking | 1.3 | +| Mr_mime | 1.3 | +| Magmar | 1.3 | +| Kabutops | 1.3 | +| Wobbuffet | 1.3 | +| Shiftry | 1.3 | +| Medicham | 1.3 | +| Cacturne | 1.3 | +| Zangoose | 1.3 | +| Nidoking | 1.4 | +| Golem | 1.4 | +| Doduo | 1.4 | +| Hitmonchan | 1.4 | +| Jynx | 1.4 | +| Tauros | 1.4 | +| Ledian | 1.4 | +| Ampharos | 1.4 | +| Quagsire | 1.4 | +| Granbull | 1.4 | +| Houndoom | 1.4 | +| Stantler | 1.4 | +| Hitmontop | 1.4 | +| Vigoroth | 1.4 | +| Walrein | 1.4 | +| Latias | 1.4 | +| Pidgeot | 1.5 | +| Venomoth | 1.5 | +| Alakazam | 1.5 | +| Machoke | 1.5 | +| Cloyster | 1.5 | +| Gengar | 1.5 | +| Hitmonlee | 1.5 | +| Scyther | 1.5 | +| Pinsir | 1.5 | +| Xatu | 1.5 | +| Girafarig | 1.5 | +| Dunsparce | 1.5 | +| Heracross | 1.5 | +| Blissey | 1.5 | +| Swampert | 1.5 | +| Ludicolo | 1.5 | +| Exploud | 1.5 | +| Manectric | 1.5 | +| Claydol | 1.5 | +| Cradily | 1.5 | +| Armaldo | 1.5 | +| Glalie | 1.5 | +| Salamence | 1.5 | +| Blastoise | 1.6 | +| Golbat | 1.6 | +| Machamp | 1.6 | +| Tentacruel | 1.6 | +| Slowbro | 1.6 | +| Haunter | 1.6 | +| Hypno | 1.6 | +| Zapdos | 1.6 | +| Noctowl | 1.6 | +| Gardevoir | 1.6 | +| Dusclops | 1.6 | +| Metagross | 1.6 | +| Charizard | 1.7 | +| Golduck | 1.7 | +| Victreebel | 1.7 | +| Rapidash | 1.7 | +| Dewgong | 1.7 | +| Articuno | 1.7 | +| Typhlosion | 1.7 | +| Skarmory | 1.7 | +| Sceptile | 1.7 | +| Swalot | 1.7 | +| Huntail | 1.7 | +| Regirock | 1.7 | +| Deoxys | 1.7 | +| Dodrio | 1.8 | +| Aerodactyl | 1.8 | +| Dratini | 1.8 | +| Meganium | 1.8 | +| Furret | 1.8 | +| Crobat | 1.8 | +| Scizor | 1.8 | +| Ursaring | 1.8 | +| Kingdra | 1.8 | +| Sharpedo | 1.8 | +| Gorebyss | 1.8 | +| Regice | 1.8 | +| Arcanine | 1.9 | +| Rhydon | 1.9 | +| Raikou | 1.9 | +| Blaziken | 1.9 | +| Camerupt | 1.9 | +| Registeel | 1.9 | +| Venusaur | 2.0 | +| Ekans | 2.0 | +| Exeggutor | 2.0 | +| Moltres | 2.0 | +| Mewtwo | 2.0 | +| Slowking | 2.0 | +| Suicune | 2.0 | +| Tyranitar | 2.0 | +| Slaking | 2.0 | +| Wailmer | 2.0 | +| Flygon | 2.0 | +| Tropius | 2.0 | +| Latios | 2.0 | +| Snorlax | 2.1 | +| Mantine | 2.1 | +| Entei | 2.1 | +| Aggron | 2.1 | +| Kangaskhan | 2.2 | +| Dragonite | 2.2 | +| Feraligatr | 2.3 | +| Hariyama | 2.3 | +| Lapras | 2.5 | +| Seviper | 2.7 | +| Arbok | 3.5 | +| Groudon | 3.5 | +| Ho_oh | 3.8 | +| Dragonair | 4.0 | +| Kyogre | 4.5 | +| Lugia | 5.2 | +| Milotic | 6.2 | +| Gyarados | 6.5 | +| Rayquaza | 7.0 | +| Onix | 8.8 | +| Steelix | 9.2 | +| Wailord | 14.5 | + +## Pokémon ordered by weight +| Pokemon | weight (kg) | +| :------ | ----------: | +| Gastly | 0.1 | +| Haunter | 0.1 | +| Hoppip | 0.5 | +| Diglett | 0.8 | +| Castform | 0.8 | +| Igglybuff | 1.0 | +| Koffing | 1.0 | +| Skiploom | 1.0 | +| Chimecho | 1.0 | +| Misdreavus | 1.0 | +| Jirachi | 1.1 | +| Swablu | 1.2 | +| Shedinja | 1.2 | +| Togepi | 1.5 | +| Surskit | 1.7 | +| Pidgey | 1.8 | +| Sunkern | 1.8 | +| Barboach | 1.9 | +| Natu | 2.0 | +| Azurill | 2.0 | +| Spearow | 2.0 | +| Pichu | 2.0 | +| Roselia | 2.0 | +| Murkrow | 2.1 | +| Taillow | 2.3 | +| Shuppet | 2.3 | +| Exeggcute | 2.5 | +| Torchic | 2.5 | +| Lotad | 2.6 | +| Caterpie | 2.9 | +| Cleffa | 3.0 | +| Jumpluff | 3.0 | +| Weedle | 3.2 | +| Togetic | 3.2 | +| Dratini | 3.3 | +| Rattata | 3.5 | +| Wurmple | 3.6 | +| Masquerain | 3.6 | +| Qwilfish | 3.9 | +| Shellder | 4.0 | +| Ditto | 4.0 | +| Mew | 4.0 | +| Seedot | 4.0 | +| Bellsprout | 4.0 | +| Meowth | 4.2 | +| Plusle | 4.2 | +| Minun | 4.2 | +| Shroomish | 4.5 | +| Unown | 5.0 | +| Treecko | 5.0 | +| Corsola | 5.0 | +| Celebi | 5.0 | +| Spinda | 5.0 | +| Paras | 5.4 | +| Oddish | 5.4 | +| Jigglypuff | 5.5 | +| Nincada | 5.5 | +| Bellossom | 5.8 | +| Magnemite | 6.0 | +| Pikachu | 6.0 | +| Smoochum | 6.0 | +| Sentret | 6.0 | +| Chikorita | 6.4 | +| Weepinbell | 6.4 | +| Eevee | 6.5 | +| Krabby | 6.5 | +| Cubone | 6.5 | +| Swinub | 6.5 | +| Ralts | 6.6 | +| Bulbasaur | 6.9 | +| Ekans | 6.9 | +| Nidoran_f | 7.0 | +| Pineco | 7.2 | +| Feebas | 7.4 | +| Omanyte | 7.5 | +| Clefairy | 7.5 | +| Zubat | 7.5 | +| Mudkip | 7.6 | +| Mareep | 7.8 | +| Snubbull | 7.8 | +| Cyndaquil | 7.9 | +| Horsea | 8.0 | +| Marill | 8.5 | +| Wooper | 8.5 | +| Spinarak | 8.5 | +| Charmander | 8.5 | +| Sunflora | 8.5 | +| Gloom | 8.6 | +| Luvdisc | 8.7 | +| Teddiursa | 8.8 | +| Squirtle | 9.0 | +| Nidoran_m | 9.0 | +| Totodile | 9.5 | +| Wingull | 9.5 | +| Weezing | 9.5 | +| Vulpix | 9.9 | +| Metapod | 9.9 | +| Kakuna | 10.0 | +| Silcoon | 10.0 | +| Magikarp | 10.0 | +| Gulpin | 10.3 | +| Voltorb | 10.4 | +| Houndour | 10.8 | +| Ledyba | 10.8 | +| Sableye | 11.0 | +| Skitty | 11.0 | +| Meditite | 11.2 | +| Kabuto | 11.5 | +| Mawile | 11.5 | +| Corphish | 11.5 | +| Cascoon | 11.5 | +| Aipom | 11.5 | +| Chinchou | 12.0 | +| Sandshrew | 12.0 | +| Remoraid | 12.0 | +| Ninjask | 12.0 | +| Wigglytuff | 12.0 | +| Poliwag | 12.4 | +| Anorith | 12.5 | +| Banette | 12.5 | +| Venomoth | 12.5 | +| Ivysaur | 13.0 | +| Flaaffy | 13.3 | +| Poochyena | 13.6 | +| Wynaut | 14.0 | +| Dunsparce | 14.0 | +| Goldeen | 15.0 | +| Trapinch | 15.0 | +| Farfetchd | 15.0 | +| Duskull | 15.0 | +| Xatu | 15.0 | +| Electrike | 15.2 | +| Vibrava | 15.3 | +| Victreebel | 15.5 | +| Bayleef | 15.8 | +| Delibird | 16.0 | +| Whismur | 16.3 | +| Dragonair | 16.5 | +| Snorunt | 16.8 | +| Zigzagoon | 17.5 | +| Illumise | 17.7 | +| Volbeat | 17.7 | +| Raticate | 18.5 | +| Vileplume | 18.6 | +| Growlithe | 19.0 | +| Quilava | 19.0 | +| Charmeleon | 19.0 | +| Machop | 19.5 | +| Nidorino | 19.5 | +| Abra | 19.5 | +| Combusken | 19.5 | +| Psyduck | 19.6 | +| Swellow | 19.8 | +| Ninetales | 19.9 | +| Geodude | 20.0 | +| Nidorina | 20.0 | +| Poliwhirl | 20.0 | +| Kirlia | 20.2 | +| Shuckle | 20.5 | +| Altaria | 20.6 | +| Carvanha | 20.8 | +| Tyrogue | 21.0 | +| Hoothoot | 21.2 | +| Magby | 21.4 | +| Baltoy | 21.5 | +| Grovyle | 21.6 | +| Kecleon | 22.0 | +| Wartortle | 22.5 | +| Lanturn | 22.5 | +| Gorebyss | 22.6 | +| Relicanth | 23.4 | +| Elekid | 23.5 | +| Whiscash | 23.6 | +| Lileep | 23.8 | +| Numel | 24.0 | +| Slakoth | 24.0 | +| Jolteon | 24.5 | +| Flareon | 25.0 | +| Croconaw | 25.0 | +| Seadra | 25.0 | +| Espeon | 26.5 | +| Umbreon | 27.0 | +| Huntail | 27.0 | +| Mankey | 28.0 | +| Marshtomp | 28.0 | +| Sneasel | 28.0 | +| Nuzleaf | 28.0 | +| Pelipper | 28.0 | +| Beautifly | 28.4 | +| Azumarill | 28.5 | +| Octillery | 28.5 | +| Wobbuffet | 28.5 | +| Vaporeon | 29.0 | +| Beedrill | 29.5 | +| Sandslash | 29.5 | +| Parasect | 29.5 | +| Raichu | 30.0 | +| Grimer | 30.0 | +| Venonat | 30.0 | +| Ponyta | 30.0 | +| Pidgeotto | 30.0 | +| Electabuzz | 30.0 | +| Muk | 30.0 | +| Spoink | 30.6 | +| Dusclops | 30.6 | +| Medicham | 31.5 | +| Dustox | 31.6 | +| Persian | 32.0 | +| Primeape | 32.0 | +| Butterfree | 32.0 | +| Drowzee | 32.4 | +| Linoone | 32.5 | +| Porygon2 | 32.5 | +| Lombre | 32.5 | +| Furret | 32.5 | +| Delcatty | 32.6 | +| Crawdaunt | 32.8 | +| Dugtrio | 33.3 | +| Phanpy | 33.5 | +| Ariados | 33.5 | +| Politoed | 33.9 | +| Staryu | 34.5 | +| Chansey | 34.6 | +| Slugma | 35.0 | +| Tangela | 35.0 | +| Omastar | 35.0 | +| Houndoom | 35.0 | +| Ledian | 35.6 | +| Slowpoke | 36.0 | +| Porygon | 36.5 | +| Mightyena | 37.0 | +| Fearow | 38.0 | +| Sudowoodo | 38.0 | +| Yanma | 38.0 | +| Seaking | 39.0 | +| Breloom | 39.2 | +| Doduo | 39.2 | +| Spheal | 39.5 | +| Pidgeot | 39.5 | +| Clefable | 40.0 | +| Latias | 40.0 | +| Manectric | 40.2 | +| Zangoose | 40.3 | +| Loudred | 40.5 | +| Kabutops | 40.5 | +| Gengar | 40.5 | +| Jynx | 40.6 | +| Noctowl | 40.8 | +| Girafarig | 41.5 | +| Bagon | 42.1 | +| Magmar | 44.5 | +| Marowak | 45.0 | +| Tentacool | 45.5 | +| Vigoroth | 46.5 | +| Blissey | 46.8 | +| Absol | 47.0 | +| Hitmontop | 48.0 | +| Alakazam | 48.0 | +| Gardevoir | 48.4 | +| Granbull | 48.7 | +| Hitmonlee | 49.8 | +| Hitmonchan | 50.2 | +| Skarmory | 50.5 | +| Cacnea | 51.3 | +| Blaziken | 52.0 | +| Sceptile | 52.2 | +| Clamperl | 52.5 | +| Seviper | 52.5 | +| Zapdos | 52.6 | +| Poliwrath | 54.0 | +| Heracross | 54.0 | +| Mr_mime | 54.5 | +| Magcargo | 55.0 | +| Pinsir | 55.0 | +| Ludicolo | 55.0 | +| Golbat | 55.0 | +| Tentacruel | 55.0 | +| Articuno | 55.4 | +| Piloswine | 55.8 | +| Scyther | 56.0 | +| Kadabra | 56.5 | +| Smeargle | 58.0 | +| Aerodactyl | 59.0 | +| Shiftry | 59.6 | +| Aron | 60.0 | +| Magneton | 60.0 | +| Nidoqueen | 60.0 | +| Kingler | 60.0 | +| Moltres | 60.0 | +| Latios | 60.0 | +| Cradily | 60.4 | +| Deoxys | 60.8 | +| Ampharos | 61.5 | +| Nidoking | 62.0 | +| Gligar | 64.8 | +| Arbok | 65.0 | +| Lickitung | 65.5 | +| Electrode | 66.6 | +| Armaldo | 68.2 | +| Machoke | 70.5 | +| Stantler | 71.2 | +| Grumpig | 71.5 | +| Larvitar | 72.0 | +| Quagsire | 75.0 | +| Crobat | 75.0 | +| Miltank | 75.5 | +| Hypno | 75.6 | +| Golduck | 76.6 | +| Cacturne | 77.4 | +| Slowbro | 78.5 | +| Typhlosion | 79.5 | +| Slowking | 79.5 | +| Starmie | 80.0 | +| Swalot | 80.0 | +| Kangaskhan | 80.0 | +| Torkoal | 80.4 | +| Swampert | 81.9 | +| Flygon | 82.0 | +| Exploud | 84.0 | +| Dodrio | 85.2 | +| Blastoise | 85.5 | +| Makuhita | 86.4 | +| Sealeo | 87.6 | +| Tauros | 88.4 | +| Sharpedo | 88.8 | +| Feraligatr | 88.8 | +| Seel | 90.0 | +| Charizard | 90.5 | +| Rapidash | 95.0 | +| Beldum | 95.2 | +| Nosepass | 97.0 | +| Venusaur | 100.0 | +| Tropius | 100.0 | +| Meganium | 100.5 | +| Salamence | 102.6 | +| Graveler | 105.0 | +| Claydol | 108.0 | +| Shelgon | 110.5 | +| Rhyhorn | 115.0 | +| Scizor | 118.0 | +| Lairon | 120.0 | +| Donphan | 120.0 | +| Dewgong | 120.0 | +| Rhydon | 120.0 | +| Exeggutor | 120.0 | +| Mewtwo | 122.0 | +| Forretress | 125.8 | +| Ursaring | 125.8 | +| Machamp | 130.0 | +| Wailmer | 130.0 | +| Slaking | 130.5 | +| Cloyster | 132.5 | +| Walrein | 150.6 | +| Pupitar | 152.0 | +| Kingdra | 152.0 | +| Solrock | 154.0 | +| Arcanine | 155.0 | +| Milotic | 162.0 | +| Lunatone | 168.0 | +| Regice | 175.0 | +| Raikou | 178.0 | +| Suicune | 187.0 | +| Entei | 198.0 | +| Ho_oh | 199.0 | +| Tyranitar | 202.0 | +| Metang | 202.5 | +| Registeel | 205.0 | +| Rayquaza | 206.5 | +| Dragonite | 210.0 | +| Onix | 210.0 | +| Lugia | 216.0 | +| Camerupt | 220.0 | +| Mantine | 220.0 | +| Lapras | 220.0 | +| Regirock | 230.0 | +| Gyarados | 235.0 | +| Hariyama | 253.8 | +| Glalie | 256.5 | +| Golem | 300.0 | +| Kyogre | 352.0 | +| Aggron | 360.0 | +| Wailord | 398.0 | +| Steelix | 400.0 | +| Snorlax | 460.0 | +| Metagross | 550.0 | +| Groudon | 950.0 | + +## Making this easier +If you have multiple species that you want to add to pokeemerald but don't want to copy and paste or type everything out multiple times, just use this handy program to generate text with the species name in there! +https://github.com/smithk200/making-a-new-pokemon-species-in-pokeemerald diff --git a/docs/how_to_new_pokemon_1_7_0.md b/docs/how_to_new_pokemon_1_7_0.md new file mode 100644 index 0000000000..801ae8e549 --- /dev/null +++ b/docs/how_to_new_pokemon_1_7_0.md @@ -0,0 +1,1049 @@ + +This is a modified version of [the original tutorial about adding new Pokémon species available in Pokeemerald's wiki](https://github.com/pret/pokeemerald/wiki/How-to-add-a-new-Pokémon-species). + +Despite the persistent rumors about an incredibly strong third form of Mew hiding somewhere, it actually wasn't possible to catch it... OR WAS IT? +In this tutorial, we will add a new Pokémon species to the game. + +## IMPORTANT: This tutorial applies to 1.7.x versions. +- [Version 1.9.x](how_to_new_pokemon_1_9_0.md) +- [Version 1.8.x](how_to_new_pokemon_1_8_0.md) +- [Version 1.6.x](how_to_new_pokemon_1_6_0.md) + +# Changes compared to vanilla +The main things that the Expansion changes are listed here. +* Still Front Pics *(`gMonStillFrontPic_YourPokemon`)* and by extension `src/anim_mon_front_pics.c` have been removed. +* `src/data/pokemon/cry_ids.h` doesn't exist anymore. +* You have 6 icon palettes available instead of the base 3. +* Most tables that use `SPECIES_x` as indexes have been moved to `gSpeciesInfo`. + +# Content +* [Useful resources](#useful-resources) +* [The Data - Part 1](#the-data---part-1) + * [1. Declare a species constant](#1-Declare-a-species-constant) + * [2. `SpeciesInfo`'s structure](#2-speciesinfos-structure) + * [3. Define its basic species information](#3-define-its-basic-species-information) + * [4. Species Name](#4-species-name) + * [5. Define its cry](#5-define-its-cry) + * [6. Define its Pokédex entry](#6-define-its-pokédex-entry) +* [The Graphics](#the-graphics) + * [1. Edit the sprites](#1-edit-the-sprites) + * [2. Add the sprites to the rom](#2-add-the-sprites-to-the-rom) + * [3. Add the animations to the rom](#3-add-the-animations-to-the-rom) + * [4. Linking graphic information to our Pokémon](#4-linking-graphic-information-to-our-pokémon) +* [The Data - Part 2](#the-data---part-2) + * [1. Species Flags](#1-species-flags) + * [2. Delimit the moveset](#2-delimit-the-moveset) + * [3. Define the Evolutions](#3-define-the-evolutions) + * [4. Make it appear!](#4-make-it-appear) +* [Optional data](#optional-data) + * [1. Form tables](#1-form-tables) + * [2. Form change tables](#2-form-change-tables) + * [3. Gender differences](#3-gender-differences) + +# Useful resources +You can open a sprite debug menu by pressing `Select` in a Pokémon's summary screen outside of battle. + +![mGBA_6WOo1TSlsn](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/0c625cd8-8f89-4bc8-a285-b10a420a8f6d) + + +# The Data - Part 1 + +Our plan is as simple as it is brilliant: clone Mewtwo... and make it even stronger! + +## 1. Declare a species constant + +Our first step towards creating a new digital lifeform is to define its own species constant. + +Edit [include/constants/species.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/species.h): + +```diff + #define SPECIES_NONE 0 + #define SPECIES_BULBASAUR 1 + ... + #define SPECIES_EEVEE_PARTNER PLACEHOLDER_START + 54 ++#define SPECIES_MEWTHREE PLACEHOLDER_START + 55 + +-#define GIGANTAMAX_START SPECIES_EEVEE_PARTNER ++#define GIGANTAMAX_START SPECIES_MEWTHREE + + // Gigantamax Forms + #define SPECIES_VENUSAUR_GIGANTAMAX GIGANTAMAX_START + 1 +``` +This number is stored in a Pokémon's save structure. These should generally never change, otherwise your saved Pokémon species will change as well. + +We add this before Gigantamax forms because they're temporary forms that shouldn't normally be saved into a Pokémon's save structure. + +Now, let's see how it looks in-game! + +![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/dc15b0ba-a4bd-4f4e-9658-2dff73a11f79) + +Hmmm, something's not right... + +Oh, I know! We need to add the rest of the data! Normally, the vanilla game would crash if we try to look up anything about Mewthree in this state, but the expansion defaults all of its data to `SPECIES_NONE`. + +Now, let's see what needs to be done. + +## 2. `SpeciesInfo`'s structure +Now, to better understand Mewtwo, we also need to understand Mew. Let's look at its data. +```diff + [SPECIES_MEW] = + { + .baseHP = 100, + .baseAttack = 100, + .baseDefense = 100, + .baseSpeed = 100, + .baseSpAttack = 100, + .baseSpDefense = 100, + .types = { TYPE_PSYCHIC, TYPE_PSYCHIC }, + .catchRate = 45, + #if P_UPDATED_EXP_YIELDS >= GEN_8 + .expYield = 300, + #elif P_UPDATED_EXP_YIELDS >= GEN_5 + .expYield = 270, + #else + .expYield = 64, + #endif + .evYield_HP = 3, + .itemCommon = ITEM_LUM_BERRY, + .itemRare = ITEM_LUM_BERRY, + .genderRatio = MON_GENDERLESS, + .eggCycles = 120, + .friendship = 100, + .growthRate = GROWTH_MEDIUM_SLOW, + .eggGroups = { EGG_GROUP_NO_EGGS_DISCOVERED, EGG_GROUP_NO_EGGS_DISCOVERED }, + .abilities = { ABILITY_SYNCHRONIZE, ABILITY_NONE }, + .bodyColor = BODY_COLOR_PINK, + .isMythical = TRUE, + .speciesName = _("Mew"), + .cryId = CRY_MEW, + .natDexNum = NATIONAL_DEX_MEW, + .categoryName = _("New Species"), + .height = 4, + .weight = 40, + .description = COMPOUND_STRING( + "A Mew is said to possess the genes of all\n" + "Pokémon. It is capable of making itself\n" + "invisible at will, so it entirely avoids\n" + "notice even if it approaches people."), + .pokemonScale = 457, + .pokemonOffset = -2, + .trainerScale = 256, + .trainerOffset = 0, + FRONT_PIC(Mew, 64, 48), + .frontPicYOffset = 9, + .frontAnimFrames = sAnims_Mew, + .frontAnimId = ANIM_ZIGZAG_SLOW, + .enemyMonElevation = 11, + BACK_PIC(Mew, 64, 64), + .backPicYOffset = 0, + .backAnimId = BACK_ANIM_CONCAVE_ARC_SMALL, + PALETTES(Mew), + ICON(Mew, 0), + FOOTPRINT(Mew) + LEARNSETS(Mew), + }, +``` + +That's a lot of stuff! But don't worry, we'll go through it step by step throught the tutorial +(and miles better than having this same data through 20+ files like it used to be). + +We'll start by adding the self-explanatory data that's also present in pret's vanilla structure: + +## 3. Define its basic species information +Edit [src/data/pokemon/species_info.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/species_info.h): +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + [SPECIES_NONE] = {0}, + ... + + [SPECIES_EGG] = + { + FRONT_PIC(Egg, 24, 24), + .frontPicYOffset = 20, + .backPic = gMonFrontPic_Egg, + .backPicSize = MON_COORDS_SIZE(24, 24), + .backPicYOffset = 20, + .palette = gMonPalette_Egg, + .shinyPalette = gMonPalette_Egg, + ICON(Egg, 1), + }, + ++ [SPECIES_MEWTHREE] = ++ { ++ .baseHP = 106, ++ .baseAttack = 150, ++ .baseDefense = 70, ++ .baseSpeed = 140, ++ .baseSpAttack = 194, ++ .baseSpDefense = 120, ++ .types = { TYPE_PSYCHIC, TYPE_PSYCHIC }, ++ .catchRate = 3, ++ .expYield = 255, ++ .evYield_SpAttack = 3, ++ .genderRatio = MON_GENDERLESS, ++ .eggCycles = 120, ++ .friendship = 0, ++ .growthRate = GROWTH_SLOW, ++ .eggGroups = { EGG_GROUP_NO_EGGS_DISCOVERED, EGG_GROUP_NO_EGGS_DISCOVERED }, ++ .abilities = { ABILITY_INSOMNIA, ABILITY_NONE, ABILITY_NONE }, ++ .bodyColor = BODY_COLOR_PURPLE, ++ }, + }; +``` + +The `.` is the structure reference operator in C to refer to the member object of the structure SpeciesInfo. + +- `baseHP`, `baseAttack`, `baseDefense`, `baseSpeed`, `baseSpAttack` and `baseSpDefense` are the base stats. They can't go higher than 255. +- You may be confused as to why `types` has `TYPE_PSYCHIC` twice. This is because the way the game determines single-type mon is to define both types the same. + - If we don't, it defaults to Normal due to it being the first type defined. +- `catchRate` is how likely it is to catch a Pokémon, the lower the value, the harder it is to catch. Legendaries generally have a catch rate of 3, so we put that here. +- `expYield` is the base amount of experience that a Pokémon gives when defeated/caught. In vanilla, this value caps at 255, but we've increased it to a maximum of 65535 accomodate later gen's higher experience yields. (The highest official value is Blissey's with 608, so going beyond this point may cause exponential gains that could break the system 😱) + - If you noticed, Mew's had some `#if`s, `#elif`s and `#endif` around it. This is because its yield has changed over time, and we let you choose which ones you want. This is not relevant to our Mewthree however, so we can just put a single `.expYield = 255,` line here. +- `evYield_HP`, `evYield_Attack`, `evYield_Defense`, `evYield_Speed`, `evYield_SpAttack` and `evYield_SpDefense` are how many EVs does the Pokémon give when they're caught. Each of these fields can have a value of 3 at most. Officially, no Pokémon give out more than 3 EVs total, with them being determined by their evolution stage (eg, Pichu, Pikachu and Raichu give 1, 2 and 3 Speed EVs respectively), and they tend to be associated with its higher stats. Since our Mewthree is a Special Attack monster, we'll be consistent and make it give out 3 Special Attack EVs, but you're always free to assign whatever you feel like :) + - Notice that the other `evYield` fields are not there. In C, numbers in a struct default to 0, so if we don't specify them, they'll be 0 all around! Less lines to worry about :D +- `itemCommon` and `itemRare` are used to determine what items is the Pokémon holding when encountering it in the wild. + - 50% for `itemCommon` and 5% for `itemRare` (boosted to 60%/20% when the first mon in the party has Compound Grass or Super Luck) + - If they're both set as the same item, the item has a 100% chance of appearing. +- `genderRatio` is a fun one. + - There are 4 ways of handling this + - `PERCENT_FEMALE` is what most Pokémon use, where you define how likely it's gonna be female. It supports decimals, so you can put `PERCENT_FEMALE(12.5)` to have a 1 in 8 chance of your mon to be female. + - `MON_MALE` guarantees that all mon of this species will be male (eg. Tauros) + - `MON_FEMALE` guarantees that all mon of this species will be female (eg. Miltank) + - `MON_GENDERLESS` makes your species genderless, unable to breed with anything but Ditto to produce eggs. Most Legendaries are this, so we'll be chosing this as Mewthree's gender ratio. + - When working with evolution lines and don't want their genders to change after evolving, be sure that their gender ratios match their stages and evolution methods. Azurill is the only case where there's a mismatch, causing 1/3 of all Azurill to change from Female to Male. + - You might be wondering why some species have multiple defines for their genders, like `SPECIES_MEOWSTIC_(FE)MALE`. This is because those species have different stats and data from each other, so they're defined internally as different forms with `MON_MALE` and `MON_FEMALE` as gender ratios. If your species evolves depending on its gender and the evolutions have different stats, be sure to apply the correct evolution method! +- `eggCycles` determines how fast an egg of this species will hatch. Doesn't matter much for evolved species or those that can't lay eggs, but we add the field here just in case. +- `friendship` determines the amount of friendship of the mon when you catch it. Most Pokémon use `STANDARD_FRIENDSHIP`, but this creature of chaos does not want to be your friend, starting with 0. +- `growthRate` determines the amounts of experience required to reach each level. Go [here](https://bulbapedia.bulbagarden.net/wiki/Experience) for more info. +- `eggGroups` are used for breed compatibility. Most Legendaries and Mythicals have the `EGG_GROUP_NO_EGGS_DISCOVERED` group, and so does our Mewthree. Go [here](https://bulbapedia.bulbagarden.net/wiki/Egg_Group) for more info. +- `abilities` determines the potential abilites of our species. Notice how I also set the ability to `ABILITY_INSOMNIA`, so our little monster doesn't even need to sleep anymore. You can find the abilities for example here [include/constants/abilities.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/abilities.h). + - When both slot 1 and 2 are defined as not being `ABILITY_NONE`, their starting ability will be decided on a coin flip using their personality. They can later be changed using an Ability Capsule. + - Certain Pokémon such as Zygarde and Rockruff have different forms to add additional abilities. As such, they cannot be changed using an Ability Capsule (though the Zygarde Cube can change Zygarde's ability by changing them to their corresponding form) + - The 3rd slot is for Hidden Abilities. If defined as `ABILITY_NONE`, it will default to Slot 1 (eg. Metapod doesn't have a Hidden Ability, but Caterpie and Butterfree do). Go [here](https://bulbapedia.bulbagarden.net/wiki/Ability#Hidden_Abilities) and [here](https://bulbapedia.bulbagarden.net/wiki/Ability_Patch) for more info. + - If the array is defined as `{ABILITY_1, ABILITY_2}`, the Hidden Ability is set as `ABILITY_NONE`. +- `bodyColor` is used in the Pokédex as a search filter. +- `noFlip` is used in to prevent front sprites from being flipped horizontally and cause weird issues, like Clawitzer's big claw changing sides. + +That's all the basic fields present in vanilla emerald, so now let's take a look at the new fields added by the expansion. + +## 4. Species Name + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .isLegendary = TRUE, + .allPerfectIVs = TRUE, ++ .speciesName = _("Mewthree"), + }, + }; +``` +The `_()` underscore function doesn't really exist - it's a convention borrowed from GNU gettext to let `preproc` know this is text to be converted to the custom encoding used by the Gen 3 Pokemon games. + +## 5. Define its cry + +Time for audio! +We first need to convert an existing audio file to the format supported by the expansion. + +Most formats are supported for conversion, but for simplicity's sake, we're gonna use this [mp3 file](https://cdn.discordapp.com/attachments/1206424179197349924/1206424212403920996/mewthree.mp3?ex=6600df1a&is=65ee6a1a&hm=4f05d58a7ae22bfdcd5f83558e15320fc1b6cd42a8cb9dee347b20bfb805ece5&). + +Now, let's copy the file to the `sound/direct_sound_samples/cries` folder. +Once that's done, let's run the following command: +``` +ffmpeg -i sound/direct_sound_samples/cries/mewthree.mp3 -c:a pcm_s8 -ac 1 -ar 13379 sound/direct_sound_samples/cries/mewthree.aif +``` +This will convert your audio file to .aif, which is what's read by the compiler. + +Let's add the cry to the ROM via [sound/direct_sound_data.inc](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/sound/direct_sound_data.inc). + +```diff +.if P_FAMILY_PECHARUNT == TRUE + .align 2 +Cry_Pecharunt:: + .incbin "sound/direct_sound_samples/cries/pecharunt.bin" +.endif @ P_FAMILY_PECHARUNT + ++ .align 2 ++Cry_Mewthree:: ++ .incbin "sound/direct_sound_samples/cries/mewthree.bin" + +``` + +Then we add the cry ID to [include/constants/cries.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/cries.h): + +```diff +enum { + CRY_NONE, + ... +#if P_FAMILY_TERAPAGOS + CRY_TERAPAGOS, +#endif //P_FAMILY_TERAPAGOS +#if P_FAMILY_PECHARUNT + CRY_PECHARUNT, +#endif //P_FAMILY_PECHARUNT ++ CRY_MEWTHREE, + CRY_COUNT, +}; +``` + +And then link it in [sound/cry_tables.inc](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/sound/cry_tables.inc). `cry_reverse` in particular is for reversed cries used by moves such as Growl. The order of these two tables should match the order of the cry IDs, otherwise they'll be shifted. + +```diff + cry Cry_Terapagos + cry Cry_Pecharunt ++ cry Cry_Mewthree +``` +```diff + cry_reverse Cry_Terapagos + cry_reverse Cry_Pecharunt ++ cry_reverse Cry_Mewthree +``` + +Lastly, we add the cry to our species entry +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .isLegendary = TRUE, + .allPerfectIVs = TRUE, + .speciesName = _("Mewthree"), ++ .cryId = CRY_MEWTHREE, + }, + }; +``` + +And let's see how it sounds in-game: + +https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/4f7667db-4db9-4bfd-a8dd-ece26f09f327 + +Good! Our monster now has a mighty roar! + +You can now delete the mp3 from the cries folder now once you made sure that the cry sounds like how you want it to. + +## 6. Define its Pokédex entry + +First, we will need to add new index constants for its Pokédex entry. The index constants are divided into the Hoenn Pokédex, which contains all Pokémon native to the Hoenn region, and the National Pokédex containing all known Pokémon, which can be received after entering the hall of fame for the first time. + +Edit [include/constants/pokedex.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/pokedex.h): + +```diff +// National Pokedex order +enum { + NATIONAL_DEX_NONE, + // Kanto + NATIONAL_DEX_BULBASAUR, +... + NATIONAL_DEX_PECHARUNT, ++ NATIONAL_DEX_MEWTHREE, +}; +``` + +```diff + #define KANTO_DEX_COUNT NATIONAL_DEX_MEW + #define JOHTO_DEX_COUNT NATIONAL_DEX_CELEBI + +#if P_GEN_9_POKEMON == TRUE +- #define NATIONAL_DEX_COUNT NATIONAL_DEX_PECHARUNT ++ #define NATIONAL_DEX_COUNT NATIONAL_DEX_MEWTHREE +``` + +Do keep in mind that if you intend to add your new species to the Hoenn Dex, you'll also want to add a `HOENN_DEX` constant for it, like this: + +```diff +// Hoenn Pokedex order +enum { + HOENN_DEX_NONE, + HOENN_DEX_TREECKO, +... + HOENN_DEX_DEOXYS, ++ HOENN_DEX_MEWTHREE, +}; + +- #define HOENN_DEX_COUNT (HOENN_DEX_DEOXYS + 1) ++ #define HOENN_DEX_COUNT (HOENN_DEX_MEWTHREE + 1) +``` + +Edit [src/pokemon.c](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/pokemon.c): + +```diff + const u16 sHoennToNationalOrder[NUM_SPECIES] = // Assigns Hoenn Dex Pokémon (Using National Dex Index) + { + HOENN_TO_NATIONAL(TREECKO), + ... + HOENN_TO_NATIONAL(DEOXYS), ++ HOENN_TO_NATIONAL(MEWTHREE), + }; +``` + +Now we can add the number and entry to our Mewthree: +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .cryId = CRY_MEWTHREE, ++ .natDexNum = NATIONAL_DEX_MEWTHREE, ++ .categoryName = _("New Species"), ++ .height = 15, ++ .weight = 330, ++ .description = COMPOUND_STRING( ++ "The rumors became true.\n" ++ "This is Mew's final form.\n" ++ "Its power level is over 9000.\n" ++ "Has science gone too far?"), ++ .pokemonScale = 256, ++ .pokemonOffset = 0, ++ .trainerScale = 290, ++ .trainerOffset = 2, + }, + }; +``` +![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/3759dd4c-8da5-4b1c-9a50-b9e9d0815e7f) + +The values `pokemonScale`, `pokemonOffset`, `trainerScale` and `trainerOffset` are used for the height comparison figure in the Pokédex. + +`height` and `weight` are specified in decimeters and hectograms respectively (which are meters and kilograms multiplied by 10, so 2.5 meters are 25 decimeters). + +In Pokémon Emerald, you can sort the Pokédex by name, height or weight. Apparently, the Pokémon order is hardcoded in the game files and not calculated from their data. Therefore we have to include our new Pokémon species at the right places. While the correct position for the alphabetical order is easy to find, it can become quite tedious for height and weight, so we added comments to the listings in order help out were they should fit. + +Edit [src/data/pokemon/pokedex_orders.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/pokedex_orders.h): + +```diff + const u16 gPokedexOrder_Alphabetical[] = + { + ... + NATIONAL_DEX_MEW, ++ NATIONAL_DEX_MEWTHREE, + NATIONAL_DEX_MEWTWO, + ... + }; + + const u16 gPokedexOrder_Weight[] = + { + ... + // 72.8 lbs / 33.0 kg + //NATIONAL_DEX_MEWTWO_MEGA_Y, + NATIONAL_DEX_ESCAVALIER, + NATIONAL_DEX_FRILLISH, + NATIONAL_DEX_DURANT, + NATIONAL_DEX_CINDERACE, ++ NATIONAL_DEX_MEWTHREE, + //NATIONAL_DEX_PERSIAN_ALOLAN, + NATIONAL_DEX_TOEDSCOOL, + // 73.4 lbs / 33.3 kg + NATIONAL_DEX_DUGTRIO, + ... + }; + + const u16 gPokedexOrder_Height[] = + { + ... + // 4'11" / 1.5m + ... + NATIONAL_DEX_GLIMMORA, + NATIONAL_DEX_WO_CHIEN, + NATIONAL_DEX_IRON_LEAVES, + NATIONAL_DEX_IRON_BOULDER, ++ NATIONAL_DEX_MEWTHREE, + // 5'03" / 1.6m + ... + }; +``` +![mGBA_lUBfmFEKUx](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/3a8b8a17-759b-486b-9831-deb2f494bd71) + + +# The Graphics +We will start by copying the following files for *Mew* (not Mewtwo) and rename it to `mewthree`. +```sh +cp -r graphics/pokemon/mew/. graphics/pokemon/mewthree +``` +We aren't copying Mewtwo's folder because he has those pesky Mega Evolutions that will get in the way of what we're doing, so our sample will need to be pure from the source. + +## 1. Edit the sprites +Let's edit the sprites. Start your favourite image editor (I recommend Aseprite or its free alternative, Libresprite) and change `anim_front.png` and `back.png` to meet your expectations. + +__Make sure that you are using the indexed mode and you have limited yourself to 15 colors!__ + +Put the RGB values of your colors into `normal.pal` between the first and the last color and the RGB values for the shiny version into `shiny.pal`. +Edit `footprint.png` using two colors in indexed mode, black and white. +Finally, edit `icon.png`. Notice, that the icon will use one of 6 predefined palettes instead of `normal.pal`. + +## 2. Add the sprites to the rom +Sadly, just putting the image files into the graphics folder is not enough. To use the sprites we have to register them, which is kind of tedious. +First, create constants for the file paths. You'll want to add the constants for your species after the constants for the last valid species. + +Edit [src/data/graphics/pokemon.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/graphics/pokemon.h): + +```diff +#if P_FAMILY_PECHARUNT + // const u32 gMonFrontPic_Pecharunt[] = INCBIN_U32("graphics/pokemon/pecharunt/front.4bpp.lz"); + // const u32 gMonPalette_Pecharunt[] = INCBIN_U32("graphics/pokemon/pecharunt/normal.gbapal.lz"); + // const u32 gMonBackPic_Pecharunt[] = INCBIN_U32("graphics/pokemon/pecharunt/back.4bpp.lz"); + // const u32 gMonShinyPalette_Pecharunt[] = INCBIN_U32("graphics/pokemon/pecharunt/shiny.gbapal.lz"); + // const u8 gMonIcon_Pecharunt[] = INCBIN_U8("graphics/pokemon/pecharunt/icon.4bpp"); +#if P_FOOTPRINTS + // const u8 gMonFootprint_Pecharunt[] = INCBIN_U8("graphics/pokemon/pecharunt/footprint.1bpp"); +#endif //P_FOOTPRINTS +#endif //P_FAMILY_PECHARUNT + ++ const u32 gMonFrontPic_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/anim_front.4bpp.lz"); ++ const u32 gMonBackPic_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/back.4bpp.lz"); ++ const u32 gMonPalette_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/normal.gbapal.lz"); ++ const u32 gMonShinyPalette_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/shiny.gbapal.lz"); ++ const u8 gMonIcon_Mewthree[] = INCBIN_U8("graphics/pokemon/mewthree/icon.4bpp"); ++ const u8 gMonFootprint_Mewthree[] = INCBIN_U8("graphics/pokemon/mewthree/footprint.1bpp"); +``` + +Please note that Pecharunt, the Pokémon that should be above your insertion for the time being, reads a `front.png` sprite instead of an `anim_front.png` sprite. This is because currently, Pecharunt lacks a 2nd frame. If the front sprite sheet of your species uses 2 frames, you should use `anim_front`. + +It is also worth to mention that Pecharunt's sprites are commented out simply because they're currently missing. + +## 3. Add the animations to the rom + +You can define the animation order, in which the sprites will be shown. The first number is the sprite index (so 0 or 1) and the second number is the number of frames the sprite will be visible. + +Edit [src/data/pokemon_graphics/front_pic_anims.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon_graphics/front_pic_anims.h): + +```diff +#if P_FAMILY_PECHARUNT +PLACEHOLDER_ANIM_SINGLE_FRAME(Pecharunt); +#endif //P_FAMILY_PECHARUNT + ++static const union AnimCmd sAnim_Mewthree_1[] = ++{ ++ ANIMCMD_FRAME(1, 30), ++ ANIMCMD_FRAME(0, 20), ++ ANIMCMD_END, ++}; +``` + +```diff +#if P_FAMILY_PECHARUNT +SINGLE_ANIMATION(Pecharunt); +#endif //P_FAMILY_PECHARUNT ++SINGLE_ANIMATION(Mewthree); +SINGLE_ANIMATION(Egg); +``` + +You might be wondering what `PLACEHOLDER_ANIM_SINGLE_FRAME` is. Well, since Pecharun only has 1 frame, we use what's called a preprocessor *macro* to have in a single line what otherwise would've been this in the C file: +```c +static const union AnimCmd sAnim_Pecharunt_1[] = +{ + ANIMCMD_FRAME(0, 1), + ANIMCMD_END, +} +``` +Instead, we can use the already established macro that does the same thing, replacing the value in parenthesis with what we want (in this case, `Pecharunt`): +```c +#define PLACEHOLDER_ANIM_SINGLE_FRAME(name) \ +static const union AnimCmd sAnim_##name##_1[] = \ +{ \ + ANIMCMD_FRAME(0, 1), \ + ANIMCMD_END, \ +} +``` + +## 4. Linking graphic information to our Pokémon +Now that we have all the external data ready, we just need to add it to `gSpeciesInfo` plus the rest of the animation and graphical data that we want to use: + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .pokemonScale = 256, + .pokemonOffset = 0, + .trainerScale = 290, + .trainerOffset = 2, ++ FRONT_PIC(Mewthree, 64, 64), ++ .frontPicYOffset = 0, ++ .frontAnimFrames = sAnims_Mewthree, ++ .frontAnimId = ANIM_GROW_VIBRATE, ++ .frontAnimDelay = 15, ++ .enemyMonElevation = 6, ++ BACK_PIC(Mewthree, 64, 64), ++ .backPicYOffset = 0, ++ .backAnimId = BACK_ANIM_CONCAVE_ARC_SMALL, ++ PALETTES(Mewthree), ++ ICON(Mewthree, 2), ++ FOOTPRINT(Mewthree) + }, + }; +``` +Let's explain each of these: +- `FRONT_PIC`: + - This is a macro handles both the `frontPic` and `frontPicSize` fields. + ```c + #define FRONT_PIC(sprite, width, height) \ + .frontPic = gMonFrontPic_## sprite, \ + .frontPicSize = MON_COORDS_SIZE(width, height) + ``` + - The first value in the macro is used to reference the front sprite, so in this case, using `Mewthree` will call for `gMonFrontPic_Mewthree`. + - The second and third values (`width` and `height`) are used for defining the non-empty size of the sprite, which is used in move animations. If you're unsure of the values, you can leave them both as 64. +- `frontPicYOffset`: + - Used to define what Y position the sprite sits at. This is used to set where they'd be "grounded". For the shadow, see `enemyMonElevation`. +- `frontAnimFrames`: + - We link our animation frame animations that we defined earlier here. +- `frontAnimId`: + - Because you are limited to two frames, there are already [predefined front sprite animations](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/pokemon_animation.h), describing translations, rotations, scalings or color changes. +- `frontAnimDelay`: + - Sets a delay in frame count between when the Pokémon appears and when the animation starts. +- `enemyMonElevation`: + - Used to determine the altitude from the ground. Any value above 0 will show a shadow under the Pokémon, to signify that they're floating. +- `BACK_PIC`: + - A macro like `FRONT_PIC` except for the back sprite handling the `frontPic` and `frontPicSize` fields in the same way. + ```c + #define BACK_PIC(sprite, width, height) \ + .backPic = gMonBackPic_## sprite, \ + .backPicSize = MON_COORDS_SIZE(width, height) + ``` +- `backPicYOffset`: + - Used to define what Y position of the back sprite. When working with the animation debug menu, we recommend aligning the back sprite to the white background, as it was designed to properyly align with the real battle layout. +- `backAnimId`: + - Like `frontAnimId` except for the back sprites and them being a single frame. The IDs listed [here](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/pokemon_animation.h) are used to represent 3 different animations that happen based on the the Pokémon's nature. +- `PALETTES` + - This macro was created to handle both regular and shiny palettes of a Pokémon. It just needs the species suffix to call the corresponding palette. + ```c + #define PALETTES(pal) \ + .palette = gMonPalette_## pal, \ + .shinyPalette = gMonShinyPalette_## pal + ``` +- `ICON` + - This macro is calls both the icon sprite and its palette. + ```c + #define ICON(sprite, palId) \ + .iconSprite = gMonIcon_## sprite, \ + .iconPalIndex = palId + ``` + Here, you can choose between the six icon palettes; 0, 1, 2, 3, 4 and 5. All of them located in `graphics/pokemon/icon_palettes`. + + Open an icon sprite and load one of the palettes to find out which palette suits your icon sprite best. +- `FOOTPRINT` + - We made this single field into a macro so that they can be ignored when `P_FOOTPRINTS` is set to false. It's also why we don't have an "," after calling it like the other macros (we add it as part of the macro itself). + ```c + #if P_FOOTPRINTS + #define FOOTPRINT(sprite) .footprint = gMonFootprint_## sprite, + #else + #define FOOTPRINT(sprite) + #endif + ``` + +# The Data - Part 2 + +We're almost there just a bit left! + +## 1. Species Flags + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .abilities = { ABILITY_INSOMNIA, ABILITY_NONE, ABILITY_NONE }, + .bodyColor = BODY_COLOR_PURPLE, ++ .isLegendary = TRUE, ++ .allPerfectIVs = TRUE, + }, + }; +``` +Each species flag provides properties to the species: +- `isLegendary`: + - Guarantees 3 perfect IVs upon generating the Pokémon[*](########## "As long as `P_LEGENDARY_PERFECT_IVS` is set to `GEN_6` or higher"). +- `isMythical`: + - Guarantees 3 perfect IVs upon generating the Pokémon[*](########## "As long as `P_LEGENDARY_PERFECT_IVS` is set to `GEN_6` or higher"). + - Is skipped during Pokédex evaluations. + - Unless it also has the `dexForceRequired` flag. + - Cannot obtain Gigantamax factor via `ToggleGigantamaxFactor`. +- `isUltraBeast`: + - Guarantees 3 perfect IVs upon generating the Pokémon[*](########## "As long as `P_LEGENDARY_PERFECT_IVS` is set to `GEN_6` or higher"). + - Beast Ball's multiplier is set to x5 for this species. + - All other ball multipliers are set to x0.1. +- `isParadoxForm`: + - Currently has no functionality but can be utilized by users for their own benefits. +- `isMegaEvolution`: + - A Mega indicator is added to the battle box indicating that they're Mega Evolved. + - The species doesn't receive affection benefits. + - Required when adding new Mega Evolutions. +- `isPrimalReversion`: + - A Primal Reversion indicator (Alpha or Omega for Kyogre/Groudon respectively) is added to the battle box indicating that they're Primal Reverted. + - Required when adding new Primal Reversions. +- `isUltraBurst`: + - Required when adding new Ultra Burst forms. +- `isGigantamax`: + - Used to determine if Gigantamax forms should have their GMax moves or not. + - Required when adding new Gigantamax forms. +- `isAlolanForm`, `isGalarianForm`, `isHisuianForm`, `isPaldeanForm`: + - In the future, these will be used to determine breeding offspring from different based on their region. +- `cannotBeTraded`: + - This species cannot be traded away (like Black/White Kyurem). +- `allPerfectIVs`: + - Guarantees 6 perfect IVs upon generating the Pokémon (like LGPE's Partner Pikachu and Eevee). +- `tmIlliterate`: + - This species will be unable to learn the universal moves. + +*: As long as `P_LEGENDARY_PERFECT_IVS` is set to `GEN_6` or higher. + +## 2. Delimit the moveset + +Let's begin with the moves that can be learned by leveling up. + +Append to [src/data/pokemon/level_up_learnsets.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/level_up_learnsets.h): + +```diff +#if P_FAMILY_PECHARUNT +static const struct LevelUpMove sPecharuntLevelUpLearnset[] = { + LEVEL_UP_MOVE( 1, MOVE_SMOG), + LEVEL_UP_MOVE( 1, MOVE_POISON_GAS), + LEVEL_UP_MOVE( 1, MOVE_MEMENTO), + LEVEL_UP_MOVE( 1, MOVE_ASTONISH), + LEVEL_UP_MOVE( 8, MOVE_WITHDRAW), + LEVEL_UP_MOVE(16, MOVE_DESTINY_BOND), + LEVEL_UP_MOVE(24, MOVE_FAKE_TEARS), + LEVEL_UP_MOVE(32, MOVE_PARTING_SHOT), + LEVEL_UP_MOVE(40, MOVE_SHADOW_BALL), + LEVEL_UP_MOVE(48, MOVE_MALIGNANT_CHAIN), + LEVEL_UP_MOVE(56, MOVE_TOXIC), + LEVEL_UP_MOVE(64, MOVE_NASTY_PLOT), + LEVEL_UP_MOVE(72, MOVE_RECOVER), + LEVEL_UP_END +}; +#endif + ++static const struct LevelUpMove sMewthreeLevelUpLearnset[] = { ++ LEVEL_UP_MOVE( 1, MOVE_CONFUSION), ++ LEVEL_UP_MOVE( 1, MOVE_DISABLE), ++ LEVEL_UP_MOVE(11, MOVE_BARRIER), ++ LEVEL_UP_MOVE(22, MOVE_SWIFT), ++ LEVEL_UP_MOVE(33, MOVE_PSYCH_UP), ++ LEVEL_UP_MOVE(44, MOVE_FUTURE_SIGHT), ++ LEVEL_UP_MOVE(55, MOVE_MIST), ++ LEVEL_UP_MOVE(66, MOVE_PSYCHIC), ++ LEVEL_UP_MOVE(77, MOVE_AMNESIA), ++ LEVEL_UP_MOVE(88, MOVE_RECOVER), ++ LEVEL_UP_MOVE(99, MOVE_SAFEGUARD), ++ LEVEL_UP_END ++}; +``` + +Again, we need to register the learnset in `gSpeciesInfo`: + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + PALETTES(Mewthree), + ICON(Mewthree, 2), + FOOTPRINT(Mewthree) ++ .levelUpLearnset = sMewthreeLevelUpLearnset, + }, + }; +``` + +Next we need to specify which moves can be taught via TM, HM, or Move Tutor. + +Append to [src/data/pokemon/teachable_learnsets.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/teachable_learnsets.h): + +```diff +#if P_FAMILY_PECHARUNT +static const u16 sPecharuntTeachableLearnset[] = { + ... + MOVE_UNAVAILABLE, +}; +#endif //P_FAMILY_PECHARUNT + ++static const u16 sMewthreeTeachableLearnset[] = { ++ MOVE_FOCUS_PUNCH, ++ MOVE_WATER_PULSE, ++ MOVE_CALM_MIND, ++ MOVE_TOXIC, ++ MOVE_HAIL, ++ MOVE_BULK_UP, ++ MOVE_HIDDEN_POWER, ++ MOVE_SUNNY_DAY, ++ MOVE_TAUNT, ++ MOVE_ICE_BEAM, ++ MOVE_BLIZZARD, ++ MOVE_HYPER_BEAM, ++ MOVE_LIGHT_SCREEN, ++ MOVE_PROTECT, ++ MOVE_RAIN_DANCE, ++ MOVE_SAFEGUARD, ++ MOVE_FRUSTRATION, ++ MOVE_SOLAR_BEAM, ++ MOVE_IRON_TAIL, ++ MOVE_THUNDERBOLT, ++ MOVE_THUNDER, ++ MOVE_EARTHQUAKE, ++ MOVE_RETURN, ++ MOVE_PSYCHIC, ++ MOVE_SHADOW_BALL, ++ MOVE_BRICK_BREAK, ++ MOVE_DOUBLE_TEAM, ++ MOVE_REFLECT, ++ MOVE_SHOCK_WAVE, ++ MOVE_FLAMETHROWER, ++ MOVE_SANDSTORM, ++ MOVE_FIRE_BLAST, ++ MOVE_ROCK_TOMB, ++ MOVE_AERIAL_ACE, ++ MOVE_TORMENT, ++ MOVE_FACADE, ++ MOVE_SECRET_POWER, ++ MOVE_REST, ++ MOVE_SKILL_SWAP, ++ MOVE_SNATCH, ++ MOVE_STRENGTH, ++ MOVE_FLASH, ++ MOVE_ROCK_SMASH, ++ MOVE_MEGA_PUNCH, ++ MOVE_MEGA_KICK, ++ MOVE_BODY_SLAM, ++ MOVE_DOUBLE_EDGE, ++ MOVE_COUNTER, ++ MOVE_SEISMIC_TOSS, ++ MOVE_MIMIC, ++ MOVE_METRONOME, ++ MOVE_DREAM_EATER, ++ MOVE_THUNDER_WAVE, ++ MOVE_SUBSTITUTE, ++ MOVE_DYNAMIC_PUNCH, ++ MOVE_PSYCH_UP, ++ MOVE_SNORE, ++ MOVE_ICY_WIND, ++ MOVE_ENDURE, ++ MOVE_MUD_SLAP, ++ MOVE_ICE_PUNCH, ++ MOVE_SWAGGER, ++ MOVE_SLEEP_TALK, ++ MOVE_SWIFT, ++ MOVE_THUNDER_PUNCH, ++ MOVE_FIRE_PUNCH, ++ MOVE_UNAVAILABLE, // This is required to determine where the array ends. ++}; +#endif +``` + +Once more, we need to register the learnset in `gSpeciesInfo`: + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + FOOTPRINT(Mewthree) + .levelUpLearnset = sMewthreeLevelUpLearnset, ++ .teachableLearnset = sMewthreeTeachableLearnset, + }, + }; +``` + +If you want to create a Pokémon which can breed, you will need to edit [src/data/pokemon/egg_moves.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/egg_moves.h). + + +## 3. Define the Evolutions + +We want Mewthree to evolve from Mewtwo by reaching level 100. + +Edit `gSpeciesInfo`: + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTWO] = + { + ... + FOOTPRINT(Mewtwo) + .isLegendary = TRUE, + .levelUpLearnset = sMewtwoLevelUpLearnset, + .teachableLearnset = sMewtwoTeachableLearnset, + .formSpeciesIdTable = sMewtwoFormSpeciesIdTable, + .formChangeTable = sMewtwoFormChangeTable, ++ .evolutions = EVOLUTION({EVO_LEVEL, 100, SPECIES_MEWTHREE}), + }, + }; +``` + +## 4. Make it appear! +Now Mewthree really does slumber in the games code - but we won't know until we make him appear somewhere! The legend tells that Mewthree is hiding somewhere in Petalburg Woods... + +Edit [src/data/wild_encounters.json](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/wild_encounters.json): + +```diff + { + "map": "MAP_PETALBURG_WOODS", + "base_label": "gPetalburgWoods", + "land_mons": { + "encounter_rate": 20, + "mons": [ + { + "min_level": 5, + "max_level": 5, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 5, + "max_level": 5, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 5, + "max_level": 5, + "species": "SPECIES_SHROOMISH" + }, + { +- "min_level": 6, +- "max_level": 6, +- "species": "SPECIES_POOCHYENA" ++ "min_level": 5, ++ "max_level": 5, ++ "species": "SPECIES_MEWTHREE" + }, + ... + } +``` + +Congratulations, you have created your own personal pocket monster! You may call yourself a mad scientist now. + +# Optional data + +Now that you now have all the essential pieces to create a base species, there are some aspects that you might want to know if you want to do other stuff with your custom Pokémon. + +## 1. Form tables +Found in `src/data/pokemon/form_species_tables.h`. + +These are introduced to have a reference of what forms correspond to what Species of Pokémon. For example, we have Pikachu's table: +```c +#if P_FAMILY_PIKACHU +static const u16 sPikachuFormSpeciesIdTable[] = { + SPECIES_PIKACHU, + SPECIES_PIKACHU_COSPLAY, + SPECIES_PIKACHU_ROCK_STAR, + SPECIES_PIKACHU_BELLE, + SPECIES_PIKACHU_POP_STAR, + SPECIES_PIKACHU_PH_D, + SPECIES_PIKACHU_LIBRE, + SPECIES_PIKACHU_ORIGINAL_CAP, + SPECIES_PIKACHU_HOENN_CAP, + SPECIES_PIKACHU_SINNOH_CAP, + SPECIES_PIKACHU_UNOVA_CAP, + SPECIES_PIKACHU_KALOS_CAP, + SPECIES_PIKACHU_ALOLA_CAP, + SPECIES_PIKACHU_PARTNER_CAP, + SPECIES_PIKACHU_WORLD_CAP, + FORM_SPECIES_END, +}; +#endif //P_FAMILY_PIKACHU +``` +We register the table each form entry in `gSpeciesInfo`. + +```diff + [SPECIES_PIKACHU] = + { + ... + .teachableLearnset = sPikachuTeachableLearnset, ++ .formSpeciesIdTable = sPikachuFormSpeciesIdTable, + .evolutions = EVOLUTION({EVO_ITEM, ITEM_THUNDER_STONE, SPECIES_RAICHU}, + {EVO_NONE, 0, SPECIES_RAICHU_ALOLAN}), + }, + + [SPECIES_PIKACHU_COSPLAY] = + { + ... + .teachableLearnset = sPikachuTeachableLearnset, ++ .formSpeciesIdTable = sPikachuFormSpeciesIdTable, + }, +``` +...and so on. + +What this allows us to do is to be able to get all forms of a Pokémon in our code by using the `GetSpeciesFormTable` function. + +For example, in the HGSS dex, it lets us browse between the entries of every form available.: + +![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/a1a90b79-46a1-4cd6-97d6-ec5d741bfdc8) ![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/7cffc6be-0b5c-4074-b689-736a97297843) + +In addition, we have the `GET_BASE_SPECIES_ID` macro, which returns the first entry of the table (or return the species itself if it doesn't have a table registered). With this, you can check if a Pokémon is any form of a species. For example, making it so that the Light Ball affects all Pikachu forms: +```c + case HOLD_EFFECT_LIGHT_BALL: + if (GET_BASE_SPECIES_ID(gBattleMons[battlerAtk].species) == SPECIES_PIKACHU && IS_MOVE_SPECIAL(move)) + modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0)); + break; +``` + +## 2. Form change tables +Found in `src/data/pokemon/form_species_tables.h`. + +These tables, unlike the regular form tables, registers how Pokémon can switch between forms. + +```c +#if P_FAMILY_GASTLY +static const struct FormChange sGengarFormChangeTable[] = { + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_GENGAR_MEGA, ITEM_GENGARITE}, + {FORM_CHANGE_BATTLE_GIGANTAMAX, SPECIES_GENGAR_GIGANTAMAX}, + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_GASTLY +``` +The first value is the type of form change. In the case of Gengar, we have both Mega Evolution and Gigantamax form changes. + +The second value is the target form, to which the Pokémon will change into. + +Values after that are referred as arguments, and needs to be put there depends on the type of form change, detailed in `include/constants/form_change_types.h`. + +## 3. Gender differences +![mGBA_Wq5cbDkNZG](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/45256192-b451-4baa-af06-f57ca16e1e46) + +You may have seen that there's a couple of duplicate fields with a "Female" suffix. +```diff + [SPECIES_FRILLISH] = + { + ... + .frontPic = gMonFrontPic_Frillish, ++ .frontPicFemale = gMonFrontPic_FrillishF, + .frontPicSize = MON_COORDS_SIZE(56, 56), ++ .frontPicSizeFemale = MON_COORDS_SIZE(56, 56), + .frontPicYOffset = 5, + .frontAnimFrames = sAnims_Frillish, + .frontAnimId = ANIM_RISING_WOBBLE, + .backPic = gMonBackPic_Frillish, ++ .backPicFemale = gMonBackPic_FrillishF, + .backPicSize = MON_COORDS_SIZE(40, 56), ++ .backPicSizeFemale = MON_COORDS_SIZE(40, 56), + .backPicYOffset = 7, + .backAnimId = BACK_ANIM_CONVEX_DOUBLE_ARC, + .palette = gMonPalette_Frillish, ++ .paletteFemale = gMonPalette_FrillishF, + .shinyPalette = gMonShinyPalette_Frillish, ++ .shinyPaletteFemale = gMonShinyPalette_FrillishF, + .iconSprite = gMonIcon_Frillish, ++ .iconSpriteFemale = gMonIcon_FrillishF, + .iconPalIndex = 0, ++ .iconPalIndexFemale = 1, + FOOTPRINT(Frillish) + .levelUpLearnset = sFrillishLevelUpLearnset, + .teachableLearnset = sFrillishTeachableLearnset, + .evolutions = EVOLUTION({EVO_LEVEL, 40, SPECIES_JELLICENT}), + }, +``` +These are used to change the graphics of the Pokémon if they're female. If they're not registered, they default to the male values. + +However, `iconPalIndexFemale` is a special case, where it's *doesn't* read the male icon palette if its `iconSpriteFemale` is set, so if you're setting a female icon, be sure to set their palette index as well. + diff --git a/docs/how_to_new_pokemon_1_8_0.md b/docs/how_to_new_pokemon_1_8_0.md new file mode 100644 index 0000000000..c4c7ab621c --- /dev/null +++ b/docs/how_to_new_pokemon_1_8_0.md @@ -0,0 +1,1049 @@ + +This is a modified version of [the original tutorial about adding new Pokémon species available in Pokeemerald's wiki](https://github.com/pret/pokeemerald/wiki/How-to-add-a-new-Pokémon-species). + +Despite the persistent rumors about an incredibly strong third form of Mew hiding somewhere, it actually wasn't possible to catch it... OR WAS IT? +In this tutorial, we will add a new Pokémon species to the game. + +## IMPORTANT: This tutorial applies to 1.8.x versions. +- [Version 1.9.x](how_to_new_pokemon_1_9_0.md) +- [Version 1.7.x](how_to_new_pokemon_1_7_0.md) +- [Version 1.6.x](how_to_new_pokemon_1_6_0.md) + +# Changes compared to vanilla +The main things that the Expansion changes are listed here. +* Still Front Pics *(`gMonStillFrontPic_YourPokemon`)* and by extension `src/anim_mon_front_pics.c` have been removed. +* `src/data/pokemon/cry_ids.h` doesn't exist anymore. +* You have 6 icon palettes available instead of the base 3. +* Most tables that use `SPECIES_x` as indexes have been moved to `gSpeciesInfo`. + +# Content +* [Useful resources](#useful-resources) +* [The Data - Part 1](#the-data---part-1) + * [1. Declare a species constant](#1-Declare-a-species-constant) + * [2. `SpeciesInfo`'s structure](#2-speciesinfos-structure) + * [3. Define its basic species information](#3-define-its-basic-species-information) + * [4. Species Name](#4-species-name) + * [5. Define its cry](#5-define-its-cry) + * [6. Define its Pokédex entry](#6-define-its-pokédex-entry) +* [The Graphics](#the-graphics) + * [1. Edit the sprites](#1-edit-the-sprites) + * [2. Add the sprites to the rom](#2-add-the-sprites-to-the-rom) + * [3. Add the animations to the rom](#3-add-the-animations-to-the-rom) + * [4. Linking graphic information to our Pokémon](#4-linking-graphic-information-to-our-pokémon) +* [The Data - Part 2](#the-data---part-2) + * [1. Species Flags](#1-species-flags) + * [2. Delimit the moveset](#2-delimit-the-moveset) + * [3. Define the Evolutions](#3-define-the-evolutions) + * [4. Make it appear!](#4-make-it-appear) +* [Optional data](#optional-data) + * [1. Form tables](#1-form-tables) + * [2. Form change tables](#2-form-change-tables) + * [3. Gender differences](#3-gender-differences) + +# Useful resources +You can open a sprite debug menu by pressing `Select` in a Pokémon's summary screen outside of battle. + +![mGBA_6WOo1TSlsn](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/0c625cd8-8f89-4bc8-a285-b10a420a8f6d) + + +# The Data - Part 1 + +Our plan is as simple as it is brilliant: clone Mewtwo... and make it even stronger! + +## 1. Declare a species constant + +Our first step towards creating a new digital lifeform is to define its own species constant. + +Edit [include/constants/species.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/species.h): + +```diff + #define SPECIES_NONE 0 + #define SPECIES_BULBASAUR 1 + ... + #define SPECIES_URSHIFU_SINGLE_STRIKE_STYLE_GIGANTAMAX 1521 + #define SPECIES_URSHIFU_RAPID_STRIKE_STYLE_GIGANTAMAX 1522 + #define SPECIES_MIMIKYU_TOTEM_BUSTED 1523 ++#define SPECIES_MEWTHREE 1524 + +-#define SPECIES_EGG SPECIES_MIMIKYU_TOTEM_BUSTED + 1 ++#define SPECIES_EGG SPECIES_MEWTHREE + 1 + + #define NUM_SPECIES SPECIES_EGG +``` +This number is stored in a Pokémon's save structure. These should generally never change, otherwise your saved Pokémon species will change as well. + +We add this after the last species ID and make sure to update `SPECIES_EGG`'s definition to use the last ID on the list. +Also, be sure that no IDs repeat each other, or you'll get compiling errors. + +``` +NOTE: In 1.7.x and previous versions, we had variable defines such as `FORMS_START` but was confusing for users, so we switched to absolute IDs. +``` + +Now, let's see how it looks in-game! + +![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/dc15b0ba-a4bd-4f4e-9658-2dff73a11f79) + +Hmmm, something's not right... + +Oh, I know! We need to add the rest of the data! Normally, the vanilla game would crash if we try to look up anything about Mewthree in this state, but the expansion defaults all of its data to `SPECIES_NONE`. + +Now, let's see what needs to be done. + +## 2. `SpeciesInfo`'s structure +Now, to better understand Mewtwo, we also need to understand Mew. Let's look at its data. +```diff + [SPECIES_MEW] = + { + .baseHP = 100, + .baseAttack = 100, + .baseDefense = 100, + .baseSpeed = 100, + .baseSpAttack = 100, + .baseSpDefense = 100, + .types = { TYPE_PSYCHIC, TYPE_PSYCHIC }, + .catchRate = 45, + #if P_UPDATED_EXP_YIELDS >= GEN_8 + .expYield = 300, + #elif P_UPDATED_EXP_YIELDS >= GEN_5 + .expYield = 270, + #else + .expYield = 64, + #endif + .evYield_HP = 3, + .itemCommon = ITEM_LUM_BERRY, + .itemRare = ITEM_LUM_BERRY, + .genderRatio = MON_GENDERLESS, + .eggCycles = 120, + .friendship = 100, + .growthRate = GROWTH_MEDIUM_SLOW, + .eggGroups = { EGG_GROUP_NO_EGGS_DISCOVERED, EGG_GROUP_NO_EGGS_DISCOVERED }, + .abilities = { ABILITY_SYNCHRONIZE, ABILITY_NONE }, + .bodyColor = BODY_COLOR_PINK, + .isMythical = TRUE, + .speciesName = _("Mew"), + .cryId = CRY_MEW, + .natDexNum = NATIONAL_DEX_MEW, + .categoryName = _("New Species"), + .height = 4, + .weight = 40, + .description = COMPOUND_STRING( + "A Mew is said to possess the genes of all\n" + "Pokémon. It is capable of making itself\n" + "invisible at will, so it entirely avoids\n" + "notice even if it approaches people."), + .pokemonScale = 457, + .pokemonOffset = -2, + .trainerScale = 256, + .trainerOffset = 0, + .frontPic = gMonFrontPic_Mew, + .frontPicSize = MON_COORDS_SIZE(64, 48), + .frontPicYOffset = 9, + .frontAnimFrames = sAnims_Mew, + .frontAnimId = ANIM_ZIGZAG_SLOW, + .enemyMonElevation = 11, + .backPic = gMonBackPic_Mew, + .backPicSize = MON_COORDS_SIZE(64, 64), + .backPicYOffset = 0, + .backAnimId = BACK_ANIM_CONCAVE_ARC_SMALL, + .palette = gMonPalette_Mew, + .shinyPalette = gMonShinyPalette_Mew, + .iconSprite = gMonIcon_Mew, + .iconPalIndex = 0, + FOOTPRINT(Mew) + .levelUpLearnset = sMewLevelUpLearnset, + .teachableLearnset = sMewTeachableLearnset, + }, +``` + +That's a lot of stuff! But don't worry, we'll go through it step by step throught the tutorial +(and miles better than having this same data through 20+ files like it used to be). + +We'll start by adding the self-explanatory data that's also present in pret's vanilla structure: + +## 3. Define its basic species information +Edit [src/data/pokemon/species_info.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/species_info.h): +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + [SPECIES_NONE] = {0}, + ... + + [SPECIES_EGG] = + { + FRONT_PIC(Egg, 24, 24), + .frontPicYOffset = 20, + .backPic = gMonFrontPic_Egg, + .backPicSize = MON_COORDS_SIZE(24, 24), + .backPicYOffset = 20, + .palette = gMonPalette_Egg, + .shinyPalette = gMonPalette_Egg, + ICON(Egg, 1), + }, + ++ [SPECIES_MEWTHREE] = ++ { ++ .baseHP = 106, ++ .baseAttack = 150, ++ .baseDefense = 70, ++ .baseSpeed = 140, ++ .baseSpAttack = 194, ++ .baseSpDefense = 120, ++ .types = { TYPE_PSYCHIC, TYPE_PSYCHIC }, ++ .catchRate = 3, ++ .expYield = 255, ++ .evYield_SpAttack = 3, ++ .genderRatio = MON_GENDERLESS, ++ .eggCycles = 120, ++ .friendship = 0, ++ .growthRate = GROWTH_SLOW, ++ .eggGroups = { EGG_GROUP_NO_EGGS_DISCOVERED, EGG_GROUP_NO_EGGS_DISCOVERED }, ++ .abilities = { ABILITY_INSOMNIA, ABILITY_NONE, ABILITY_NONE }, ++ .bodyColor = BODY_COLOR_PURPLE, ++ }, + }; +``` + +The `.` is the structure reference operator in C to refer to the member object of the structure SpeciesInfo. + +- `baseHP`, `baseAttack`, `baseDefense`, `baseSpeed`, `baseSpAttack` and `baseSpDefense` are the base stats. They can't go higher than 255. +- You may be confused as to why `types` has `TYPE_PSYCHIC` twice. This is because the way the game determines single-type mon is to define both types the same. + - If we don't, it defaults to Normal due to it being the first type defined. +- `catchRate` is how likely it is to catch a Pokémon, the lower the value, the harder it is to catch. Legendaries generally have a catch rate of 3, so we put that here. +- `expYield` is the base amount of experience that a Pokémon gives when defeated/caught. In vanilla, this value caps at 255, but we've increased it to a maximum of 65535 accomodate later gen's higher experience yields. (The highest official value is Blissey's with 608, so going beyond this point may cause exponential gains that could break the system 😱) + - If you noticed, Mew's had some `#if`s, `#elif`s and `#endif` around it. This is because its yield has changed over time, and we let you choose which ones you want. This is not relevant to our Mewthree however, so we can just put a single `.expYield = 255,` line here. +- `evYield_HP`, `evYield_Attack`, `evYield_Defense`, `evYield_Speed`, `evYield_SpAttack` and `evYield_SpDefense` are how many EVs does the Pokémon give when they're caught. Each of these fields can have a value of 3 at most. Officially, no Pokémon give out more than 3 EVs total, with them being determined by their evolution stage (eg, Pichu, Pikachu and Raichu give 1, 2 and 3 Speed EVs respectively), and they tend to be associated with its higher stats. Since our Mewthree is a Special Attack monster, we'll be consistent and make it give out 3 Special Attack EVs, but you're always free to assign whatever you feel like :) + - Notice that the other `evYield` fields are not there. In C, numbers in a struct default to 0, so if we don't specify them, they'll be 0 all around! Less lines to worry about :D +- `itemCommon` and `itemRare` are used to determine what items is the Pokémon holding when encountering it in the wild. + - 50% for `itemCommon` and 5% for `itemRare` (boosted to 60%/20% when the first mon in the party has Compound Grass or Super Luck) + - If they're both set as the same item, the item has a 100% chance of appearing. +- `genderRatio` is a fun one. + - There are 4 ways of handling this + - `PERCENT_FEMALE` is what most Pokémon use, where you define how likely it's gonna be female. It supports decimals, so you can put `PERCENT_FEMALE(12.5)` to have a 1 in 8 chance of your mon to be female. + - `MON_MALE` guarantees that all mon of this species will be male (eg. Tauros) + - `MON_FEMALE` guarantees that all mon of this species will be female (eg. Miltank) + - `MON_GENDERLESS` makes your species genderless, unable to breed with anything but Ditto to produce eggs. Most Legendaries are this, so we'll be chosing this as Mewthree's gender ratio. + - When working with evolution lines and don't want their genders to change after evolving, be sure that their gender ratios match their stages and evolution methods. Azurill is the only case where there's a mismatch, causing 1/3 of all Azurill to change from Female to Male. + - You might be wondering why some species have multiple defines for their genders, like `SPECIES_MEOWSTIC_(FE)MALE`. This is because those species have different stats and data from each other, so they're defined internally as different forms with `MON_MALE` and `MON_FEMALE` as gender ratios. If your species evolves depending on its gender and the evolutions have different stats, be sure to apply the correct evolution method! +- `eggCycles` determines how fast an egg of this species will hatch. Doesn't matter much for evolved species or those that can't lay eggs, but we add the field here just in case. +- `friendship` determines the amount of friendship of the mon when you catch it. Most Pokémon use `STANDARD_FRIENDSHIP`, but this creature of chaos does not want to be your friend, starting with 0. +- `growthRate` determines the amounts of experience required to reach each level. Go [here](https://bulbapedia.bulbagarden.net/wiki/Experience) for more info. +- `eggGroups` are used for breed compatibility. Most Legendaries and Mythicals have the `EGG_GROUP_NO_EGGS_DISCOVERED` group, and so does our Mewthree. Go [here](https://bulbapedia.bulbagarden.net/wiki/Egg_Group) for more info. +- `abilities` determines the potential abilites of our species. Notice how I also set the ability to `ABILITY_INSOMNIA`, so our little monster doesn't even need to sleep anymore. You can find the abilities for example here [include/constants/abilities.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/abilities.h). + - When both slot 1 and 2 are defined as not being `ABILITY_NONE`, their starting ability will be decided on a coin flip using their personality. They can later be changed using an Ability Capsule. + - Certain Pokémon such as Zygarde and Rockruff have different forms to add additional abilities. As such, they cannot be changed using an Ability Capsule (though the Zygarde Cube can change Zygarde's ability by changing them to their corresponding form) + - The 3rd slot is for Hidden Abilities. If defined as `ABILITY_NONE`, it will default to Slot 1 (eg. Metapod doesn't have a Hidden Ability, but Caterpie and Butterfree do). Go [here](https://bulbapedia.bulbagarden.net/wiki/Ability#Hidden_Abilities) and [here](https://bulbapedia.bulbagarden.net/wiki/Ability_Patch) for more info. + - If the array is defined as `{ABILITY_1, ABILITY_2}`, the Hidden Ability is set as `ABILITY_NONE`. +- `bodyColor` is used in the Pokédex as a search filter. +- `noFlip` is used in to prevent front sprites from being flipped horizontally and cause weird issues, like Clawitzer's big claw changing sides. + +That's all the basic fields present in vanilla emerald, so now let's take a look at the new fields added by the expansion. + +## 4. Species Name + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .isLegendary = TRUE, + .allPerfectIVs = TRUE, ++ .speciesName = _("Mewthree"), + }, + }; +``` +The `_()` underscore function doesn't really exist - it's a convention borrowed from GNU gettext to let `preproc` know this is text to be converted to the custom encoding used by the Gen 3 Pokemon games. + +## 5. Define its cry + +Time for audio! +We first need to convert an existing audio file to the format supported by the expansion. + +Most formats are supported for conversion, but for simplicity's sake, we're gonna use an mp3 file. + +Now, let's copy the file to the `sound/direct_sound_samples/cries` folder. +Once that's done, let's run the following command: +``` +ffmpeg -i sound/direct_sound_samples/cries/mewthree.mp3 -c:a pcm_s8 -ac 1 -ar 13379 sound/direct_sound_samples/cries/mewthree.aif +``` +This will convert your audio file to .aif, which is what's read by the compiler. + +Let's add the cry to the ROM via [sound/direct_sound_data.inc](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/sound/direct_sound_data.inc). + +```diff +.if P_FAMILY_PECHARUNT == TRUE + .align 2 +Cry_Pecharunt:: + .incbin "sound/direct_sound_samples/cries/pecharunt.bin" +.endif @ P_FAMILY_PECHARUNT + ++ .align 2 ++Cry_Mewthree:: ++ .incbin "sound/direct_sound_samples/cries/mewthree.bin" + +``` + +Then we add the cry ID to [include/constants/cries.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/cries.h): + +```diff +enum { + CRY_NONE, + ... +#if P_FAMILY_TERAPAGOS + CRY_TERAPAGOS, +#endif //P_FAMILY_TERAPAGOS +#if P_FAMILY_PECHARUNT + CRY_PECHARUNT, +#endif //P_FAMILY_PECHARUNT ++ CRY_MEWTHREE, + CRY_COUNT, +}; +``` + +And then link it in [sound/cry_tables.inc](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/sound/cry_tables.inc). `cry_reverse` in particular is for reversed cries used by moves such as Growl. The order of these two tables should match the order of the cry IDs, otherwise they'll be shifted. + +```diff + cry Cry_Terapagos + cry Cry_Pecharunt ++ cry Cry_Mewthree +``` +```diff + cry_reverse Cry_Terapagos + cry_reverse Cry_Pecharunt ++ cry_reverse Cry_Mewthree +``` + +Lastly, we add the cry to our species entry +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .isLegendary = TRUE, + .allPerfectIVs = TRUE, + .speciesName = _("Mewthree"), ++ .cryId = CRY_MEWTHREE, + }, + }; +``` + +And let's see how it sounds in-game: + +https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/4f7667db-4db9-4bfd-a8dd-ece26f09f327 + +Good! Our monster now has a mighty roar! + +You can now delete the mp3 from the cries folder now once you made sure that the cry sounds like how you want it to. + +## 6. Define its Pokédex entry + +First, we will need to add new index constants for its Pokédex entry. The index constants are divided into the Hoenn Pokédex, which contains all Pokémon native to the Hoenn region, and the National Pokédex containing all known Pokémon, which can be received after entering the hall of fame for the first time. + +Edit [include/constants/pokedex.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/pokedex.h): + +```diff +// National Pokedex order +enum { + NATIONAL_DEX_NONE, + // Kanto + NATIONAL_DEX_BULBASAUR, +... + NATIONAL_DEX_PECHARUNT, ++ NATIONAL_DEX_MEWTHREE, +}; +``` + +```diff + #define KANTO_DEX_COUNT NATIONAL_DEX_MEW + #define JOHTO_DEX_COUNT NATIONAL_DEX_CELEBI + +#if P_GEN_9_POKEMON == TRUE +- #define NATIONAL_DEX_COUNT NATIONAL_DEX_PECHARUNT ++ #define NATIONAL_DEX_COUNT NATIONAL_DEX_MEWTHREE +``` + +Do keep in mind that if you intend to add your new species to the Hoenn Dex, you'll also want to add a `HOENN_DEX` constant for it, like this: + +```diff +// Hoenn Pokedex order +enum { + HOENN_DEX_NONE, + HOENN_DEX_TREECKO, +... + HOENN_DEX_DEOXYS, ++ HOENN_DEX_MEWTHREE, +}; + +- #define HOENN_DEX_COUNT (HOENN_DEX_DEOXYS + 1) ++ #define HOENN_DEX_COUNT (HOENN_DEX_MEWTHREE + 1) +``` + +Edit [src/pokemon.c](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/pokemon.c): + +```diff + const u16 sHoennToNationalOrder[NUM_SPECIES] = // Assigns Hoenn Dex Pokémon (Using National Dex Index) + { + HOENN_TO_NATIONAL(TREECKO), + ... + HOENN_TO_NATIONAL(DEOXYS), ++ HOENN_TO_NATIONAL(MEWTHREE), + }; +``` + +Now we can add the number and entry to our Mewthree: +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .cryId = CRY_MEWTHREE, ++ .natDexNum = NATIONAL_DEX_MEWTHREE, ++ .categoryName = _("New Species"), ++ .height = 15, ++ .weight = 330, ++ .description = COMPOUND_STRING( ++ "The rumors became true.\n" ++ "This is Mew's final form.\n" ++ "Its power level is over 9000.\n" ++ "Has science gone too far?"), ++ .pokemonScale = 256, ++ .pokemonOffset = 0, ++ .trainerScale = 290, ++ .trainerOffset = 2, + }, + }; +``` +![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/3759dd4c-8da5-4b1c-9a50-b9e9d0815e7f) + +The values `pokemonScale`, `pokemonOffset`, `trainerScale` and `trainerOffset` are used for the height comparison figure in the Pokédex. + +`height` and `weight` are specified in decimeters and hectograms respectively (which are meters and kilograms multiplied by 10, so 2.5 meters are 25 decimeters). + +In Pokémon Emerald, you can sort the Pokédex by name, height or weight. Apparently, the Pokémon order is hardcoded in the game files and not calculated from their data. Therefore we have to include our new Pokémon species at the right places. While the correct position for the alphabetical order is easy to find, it can become quite tedious for height and weight, so we added comments to the listings in order help out were they should fit. + +Edit [src/data/pokemon/pokedex_orders.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/pokedex_orders.h): + +```diff + const u16 gPokedexOrder_Alphabetical[] = + { + ... + NATIONAL_DEX_MEW, ++ NATIONAL_DEX_MEWTHREE, + NATIONAL_DEX_MEWTWO, + ... + }; + + const u16 gPokedexOrder_Weight[] = + { + ... + // 72.8 lbs / 33.0 kg + //NATIONAL_DEX_MEWTWO_MEGA_Y, + NATIONAL_DEX_ESCAVALIER, + NATIONAL_DEX_FRILLISH, + NATIONAL_DEX_DURANT, + NATIONAL_DEX_CINDERACE, ++ NATIONAL_DEX_MEWTHREE, + //NATIONAL_DEX_PERSIAN_ALOLAN, + NATIONAL_DEX_TOEDSCOOL, + // 73.4 lbs / 33.3 kg + NATIONAL_DEX_DUGTRIO, + ... + }; + + const u16 gPokedexOrder_Height[] = + { + ... + // 4'11" / 1.5m + ... + NATIONAL_DEX_GLIMMORA, + NATIONAL_DEX_WO_CHIEN, + NATIONAL_DEX_IRON_LEAVES, + NATIONAL_DEX_IRON_BOULDER, ++ NATIONAL_DEX_MEWTHREE, + // 5'03" / 1.6m + ... + }; +``` +![mGBA_lUBfmFEKUx](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/3a8b8a17-759b-486b-9831-deb2f494bd71) + + +# The Graphics +We will start by copying the following files for *Mew* (not Mewtwo) and rename it to `mewthree`. +```sh +cp -r graphics/pokemon/mew/. graphics/pokemon/mewthree +``` +We aren't copying Mewtwo's folder because he has those pesky Mega Evolutions that will get in the way of what we're doing, so our sample will need to be pure from the source. + +## 1. Edit the sprites +Let's edit the sprites. Start your favourite image editor (I recommend Aseprite or its free alternative, Libresprite) and change `anim_front.png` and `back.png` to meet your expectations. + +__Make sure that you are using the indexed mode and you have limited yourself to 15 colors!__ + +Put the RGB values of your colors into `normal.pal` between the first and the last color and the RGB values for the shiny version into `shiny.pal`. +Edit `footprint.png` using two colors in indexed mode, black and white. +Finally, edit `icon.png`. Notice, that the icon will use one of 6 predefined palettes instead of `normal.pal`. + +## 2. Add the sprites to the rom +Sadly, just putting the image files into the graphics folder is not enough. To use the sprites we have to register them, which is kind of tedious. +First, create constants for the file paths. You'll want to add the constants for your species after the constants for the last valid species. + +Edit [src/data/graphics/pokemon.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/graphics/pokemon.h): + +```diff +#if P_FAMILY_PECHARUNT + // const u32 gMonFrontPic_Pecharunt[] = INCBIN_U32("graphics/pokemon/pecharunt/front.4bpp.lz"); + // const u32 gMonPalette_Pecharunt[] = INCBIN_U32("graphics/pokemon/pecharunt/normal.gbapal.lz"); + // const u32 gMonBackPic_Pecharunt[] = INCBIN_U32("graphics/pokemon/pecharunt/back.4bpp.lz"); + // const u32 gMonShinyPalette_Pecharunt[] = INCBIN_U32("graphics/pokemon/pecharunt/shiny.gbapal.lz"); + // const u8 gMonIcon_Pecharunt[] = INCBIN_U8("graphics/pokemon/pecharunt/icon.4bpp"); +#if P_FOOTPRINTS + // const u8 gMonFootprint_Pecharunt[] = INCBIN_U8("graphics/pokemon/pecharunt/footprint.1bpp"); +#endif //P_FOOTPRINTS +#endif //P_FAMILY_PECHARUNT + ++ const u32 gMonFrontPic_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/anim_front.4bpp.lz"); ++ const u32 gMonBackPic_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/back.4bpp.lz"); ++ const u32 gMonPalette_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/normal.gbapal.lz"); ++ const u32 gMonShinyPalette_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/shiny.gbapal.lz"); ++ const u8 gMonIcon_Mewthree[] = INCBIN_U8("graphics/pokemon/mewthree/icon.4bpp"); ++ const u8 gMonFootprint_Mewthree[] = INCBIN_U8("graphics/pokemon/mewthree/footprint.1bpp"); +``` + +Please note that Pecharunt, the Pokémon that should be above your insertion for the time being, reads a `front.png` sprite instead of an `anim_front.png` sprite. This is because currently, Pecharunt lacks a 2nd frame. If the front sprite sheet of your species uses 2 frames, you should use `anim_front`. + +It is also worth to mention that Pecharunt's sprites are commented out simply because they're currently missing. + +## 3. Add the animations to the rom + +You can define the animation order, in which the sprites will be shown. The first number is the sprite index (so 0 or 1) and the second number is the number of frames the sprite will be visible. + +Edit [src/data/pokemon_graphics/front_pic_anims.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon_graphics/front_pic_anims.h): + +```diff +#if P_FAMILY_PECHARUNT +PLACEHOLDER_ANIM_SINGLE_FRAME(Pecharunt); +#endif //P_FAMILY_PECHARUNT + ++static const union AnimCmd sAnim_Mewthree_1[] = ++{ ++ ANIMCMD_FRAME(1, 30), ++ ANIMCMD_FRAME(0, 20), ++ ANIMCMD_END, ++}; +``` + +```diff +#if P_FAMILY_PECHARUNT +SINGLE_ANIMATION(Pecharunt); +#endif //P_FAMILY_PECHARUNT ++SINGLE_ANIMATION(Mewthree); +SINGLE_ANIMATION(Egg); +``` + +You might be wondering what `PLACEHOLDER_ANIM_SINGLE_FRAME` is. Well, since Pecharun only has 1 frame, we use what's called a preprocessor *macro* to have in a single line what otherwise would've been this in the C file: +```c +static const union AnimCmd sAnim_Pecharunt_1[] = +{ + ANIMCMD_FRAME(0, 1), + ANIMCMD_END, +} +``` +Instead, we can use the already established macro that does the same thing, replacing the value in parenthesis with what we want (in this case, `Pecharunt`): +```c +#define PLACEHOLDER_ANIM_SINGLE_FRAME(name) \ +static const union AnimCmd sAnim_##name##_1[] = \ +{ \ + ANIMCMD_FRAME(0, 1), \ + ANIMCMD_END, \ +} +``` + +## 4. Linking graphic information to our Pokémon +Now that we have all the external data ready, we just need to add it to `gSpeciesInfo` plus the rest of the animation and graphical data that we want to use: + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .pokemonScale = 256, + .pokemonOffset = 0, + .trainerScale = 290, + .trainerOffset = 2, ++ .frontPic = gMonFrontPic_Mewthree, ++ .frontPicSize = MON_COORDS_SIZE(64, 64), ++ .frontPicYOffset = 0, ++ .frontAnimFrames = sAnims_Mewthree, ++ .frontAnimId = ANIM_GROW_VIBRATE, ++ .frontAnimDelay = 15, ++ .enemyMonElevation = 6, ++ .backPic = gMonBackPic_Mewthree, ++ .backPicSize = MON_COORDS_SIZE(64, 64), ++ .backPicYOffset = 0, ++ .backAnimId = BACK_ANIM_CONCAVE_ARC_SMALL, ++ .palette = gMonPalette_Mewthree, ++ .shinyPalette = gMonShinyPalette_Mewthree, + .iconSprite = gMonIcon_Mewthree, + .iconPalIndex = 2, ++ FOOTPRINT(Mewthree) + }, + }; +``` +Let's explain each of these: +- `frontPic`: + - Used to reference the front sprite, so in this case, we call for `gMonFrontPic_Mewthree`. +- `frontPicSize`: + - The two values (`width` and `height`) are used for defining the non-empty size of the front sprite, which is used in move animations. If you're unsure of the values, you can leave them both as 64. +- `frontPicYOffset`: + - Used to define what Y position the sprite sits at. This is used to set where they'd be "grounded". For the shadow, see `enemyMonElevation`. +- `frontAnimFrames`: + - We link our animation frame animations that we defined earlier here. +- `frontAnimId`: + - Because you are limited to two frames, there are already [predefined front sprite animations](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/pokemon_animation.h), describing translations, rotations, scalings or color changes. +- `frontAnimDelay`: + - Sets a delay in frame count between when the Pokémon appears and when the animation starts. +- `enemyMonElevation`: + - Used to determine the altitude from the ground. Any value above 0 will show a shadow under the Pokémon, to signify that they're floating. +- `backPic`: + - Used to reference the back sprite, so in this case, we call for `gMonBackPic_Mewthree`. +- `backPicSize`: + - The two values (`width` and `height`) are used for defining the non-empty size of the back sprite, which is used in move animations. If you're unsure of the values, you can leave them both as 64. +- `backPicYOffset`: + - Used to define what Y position of the back sprite. When working with the animation debug menu, we recommend aligning the back sprite to the white background, as it was designed to properyly align with the real battle layout. +- `backAnimId`: + - Like `frontAnimId` except for the back sprites and them being a single frame. The IDs listed [here](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/pokemon_animation.h) are used to represent 3 different animations that happen based on the the Pokémon's nature. +- `palette`: + - Used to reference the non-shiny palette, so in this case, we call for `gMonPalette_Mewthree`. +- `shinyPalette`: + - Used to reference the shiny palette, so in this case, we call for `gMonShinyPalette_Mewthree`. +- `iconSprite`: + - Used to reference the icon sprite, so in this case, we call for `gMonIcon_Mewthree`. +- `iconPalIndex`: +- `ICON` + - Here, you can choose between the six icon palettes; 0, 1, 2, 3, 4 and 5. All of them located in `graphics/pokemon/icon_palettes`. + + Open an icon sprite and load one of the palettes to find out which palette suits your icon sprite best. +- `FOOTPRINT` + - We made this single field into a macro so that they can be ignored when `P_FOOTPRINTS` is set to false. It's also why we don't have an "," after calling it like the other macros (we add it as part of the macro itself). + ```c + #if P_FOOTPRINTS + #define FOOTPRINT(sprite) .footprint = gMonFootprint_## sprite, + #else + #define FOOTPRINT(sprite) + #endif + ``` + +# The Data - Part 2 + +We're almost there just a bit left! + +## 1. Species Flags + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .abilities = { ABILITY_INSOMNIA, ABILITY_NONE, ABILITY_NONE }, + .bodyColor = BODY_COLOR_PURPLE, ++ .isLegendary = TRUE, ++ .allPerfectIVs = TRUE, + }, + }; +``` +Each species flag provides properties to the species: +- `isLegendary`: + - Guarantees 3 perfect IVs upon generating the Pokémon[*](########## "As long as `P_LEGENDARY_PERFECT_IVS` is set to `GEN_6` or higher"). +- `isMythical`: + - Guarantees 3 perfect IVs upon generating the Pokémon[*](########## "As long as `P_LEGENDARY_PERFECT_IVS` is set to `GEN_6` or higher"). + - Is skipped during Pokédex evaluations. + - Unless it also has the `dexForceRequired` flag. + - Cannot obtain Gigantamax factor via `ToggleGigantamaxFactor`. +- `isUltraBeast`: + - Guarantees 3 perfect IVs upon generating the Pokémon[*](########## "As long as `P_LEGENDARY_PERFECT_IVS` is set to `GEN_6` or higher"). + - Beast Ball's multiplier is set to x5 for this species. + - All other ball multipliers are set to x0.1. +- `isParadoxForm`: + - Currently has no functionality but can be utilized by users for their own benefits. +- `isMegaEvolution`: + - A Mega indicator is added to the battle box indicating that they're Mega Evolved. + - The species doesn't receive affection benefits. + - Required when adding new Mega Evolutions. +- `isPrimalReversion`: + - A Primal Reversion indicator (Alpha or Omega for Kyogre/Groudon respectively) is added to the battle box indicating that they're Primal Reverted. + - Required when adding new Primal Reversions. +- `isUltraBurst`: + - Required when adding new Ultra Burst forms. +- `isGigantamax`: + - Used to determine if Gigantamax forms should have their GMax moves or not. + - Required when adding new Gigantamax forms. +- `isAlolanForm`, `isGalarianForm`, `isHisuianForm`, `isPaldeanForm`: + - In the future, these will be used to determine breeding offspring from different based on their region. +- `cannotBeTraded`: + - This species cannot be traded away (like Black/White Kyurem). +- `allPerfectIVs`: + - Guarantees 6 perfect IVs upon generating the Pokémon (like LGPE's Partner Pikachu and Eevee). +- `tmIlliterate`: + - This species will be unable to learn the universal moves. + +*: As long as `P_LEGENDARY_PERFECT_IVS` is set to `GEN_6` or higher. + +## 2. Delimit the moveset + +Let's begin with the moves that can be learned by leveling up. + +Append to [src/data/pokemon/level_up_learnsets.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/level_up_learnsets.h): + +```diff +#if P_FAMILY_PECHARUNT +static const struct LevelUpMove sPecharuntLevelUpLearnset[] = { + LEVEL_UP_MOVE( 1, MOVE_SMOG), + LEVEL_UP_MOVE( 1, MOVE_POISON_GAS), + LEVEL_UP_MOVE( 1, MOVE_MEMENTO), + LEVEL_UP_MOVE( 1, MOVE_ASTONISH), + LEVEL_UP_MOVE( 8, MOVE_WITHDRAW), + LEVEL_UP_MOVE(16, MOVE_DESTINY_BOND), + LEVEL_UP_MOVE(24, MOVE_FAKE_TEARS), + LEVEL_UP_MOVE(32, MOVE_PARTING_SHOT), + LEVEL_UP_MOVE(40, MOVE_SHADOW_BALL), + LEVEL_UP_MOVE(48, MOVE_MALIGNANT_CHAIN), + LEVEL_UP_MOVE(56, MOVE_TOXIC), + LEVEL_UP_MOVE(64, MOVE_NASTY_PLOT), + LEVEL_UP_MOVE(72, MOVE_RECOVER), + LEVEL_UP_END +}; +#endif + ++static const struct LevelUpMove sMewthreeLevelUpLearnset[] = { ++ LEVEL_UP_MOVE( 1, MOVE_CONFUSION), ++ LEVEL_UP_MOVE( 1, MOVE_DISABLE), ++ LEVEL_UP_MOVE(11, MOVE_BARRIER), ++ LEVEL_UP_MOVE(22, MOVE_SWIFT), ++ LEVEL_UP_MOVE(33, MOVE_PSYCH_UP), ++ LEVEL_UP_MOVE(44, MOVE_FUTURE_SIGHT), ++ LEVEL_UP_MOVE(55, MOVE_MIST), ++ LEVEL_UP_MOVE(66, MOVE_PSYCHIC), ++ LEVEL_UP_MOVE(77, MOVE_AMNESIA), ++ LEVEL_UP_MOVE(88, MOVE_RECOVER), ++ LEVEL_UP_MOVE(99, MOVE_SAFEGUARD), ++ LEVEL_UP_END ++}; +``` + +Again, we need to register the learnset in `gSpeciesInfo`: + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + PALETTES(Mewthree), + ICON(Mewthree, 2), + FOOTPRINT(Mewthree) ++ .levelUpLearnset = sMewthreeLevelUpLearnset, + }, + }; +``` + +Next we need to specify which moves can be taught via TM, HM, or Move Tutor. + +Append to [src/data/pokemon/teachable_learnsets.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/teachable_learnsets.h): + +```diff +#if P_FAMILY_PECHARUNT +static const u16 sPecharuntTeachableLearnset[] = { + ... + MOVE_UNAVAILABLE, +}; +#endif //P_FAMILY_PECHARUNT + ++static const u16 sMewthreeTeachableLearnset[] = { ++ MOVE_FOCUS_PUNCH, ++ MOVE_WATER_PULSE, ++ MOVE_CALM_MIND, ++ MOVE_TOXIC, ++ MOVE_HAIL, ++ MOVE_BULK_UP, ++ MOVE_HIDDEN_POWER, ++ MOVE_SUNNY_DAY, ++ MOVE_TAUNT, ++ MOVE_ICE_BEAM, ++ MOVE_BLIZZARD, ++ MOVE_HYPER_BEAM, ++ MOVE_LIGHT_SCREEN, ++ MOVE_PROTECT, ++ MOVE_RAIN_DANCE, ++ MOVE_SAFEGUARD, ++ MOVE_FRUSTRATION, ++ MOVE_SOLAR_BEAM, ++ MOVE_IRON_TAIL, ++ MOVE_THUNDERBOLT, ++ MOVE_THUNDER, ++ MOVE_EARTHQUAKE, ++ MOVE_RETURN, ++ MOVE_PSYCHIC, ++ MOVE_SHADOW_BALL, ++ MOVE_BRICK_BREAK, ++ MOVE_DOUBLE_TEAM, ++ MOVE_REFLECT, ++ MOVE_SHOCK_WAVE, ++ MOVE_FLAMETHROWER, ++ MOVE_SANDSTORM, ++ MOVE_FIRE_BLAST, ++ MOVE_ROCK_TOMB, ++ MOVE_AERIAL_ACE, ++ MOVE_TORMENT, ++ MOVE_FACADE, ++ MOVE_SECRET_POWER, ++ MOVE_REST, ++ MOVE_SKILL_SWAP, ++ MOVE_SNATCH, ++ MOVE_STRENGTH, ++ MOVE_FLASH, ++ MOVE_ROCK_SMASH, ++ MOVE_MEGA_PUNCH, ++ MOVE_MEGA_KICK, ++ MOVE_BODY_SLAM, ++ MOVE_DOUBLE_EDGE, ++ MOVE_COUNTER, ++ MOVE_SEISMIC_TOSS, ++ MOVE_MIMIC, ++ MOVE_METRONOME, ++ MOVE_DREAM_EATER, ++ MOVE_THUNDER_WAVE, ++ MOVE_SUBSTITUTE, ++ MOVE_DYNAMIC_PUNCH, ++ MOVE_PSYCH_UP, ++ MOVE_SNORE, ++ MOVE_ICY_WIND, ++ MOVE_ENDURE, ++ MOVE_MUD_SLAP, ++ MOVE_ICE_PUNCH, ++ MOVE_SWAGGER, ++ MOVE_SLEEP_TALK, ++ MOVE_SWIFT, ++ MOVE_THUNDER_PUNCH, ++ MOVE_FIRE_PUNCH, ++ MOVE_UNAVAILABLE, // This is required to determine where the array ends. ++}; +#endif +``` + +Once more, we need to register the learnset in `gSpeciesInfo`: + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + FOOTPRINT(Mewthree) + .levelUpLearnset = sMewthreeLevelUpLearnset, ++ .teachableLearnset = sMewthreeTeachableLearnset, + }, + }; +``` + +If you want to create a Pokémon which can breed, you will need to edit [src/data/pokemon/egg_moves.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/egg_moves.h). + + +## 3. Define the Evolutions + +We want Mewthree to evolve from Mewtwo by reaching level 100. + +Edit `gSpeciesInfo`: + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTWO] = + { + ... + FOOTPRINT(Mewtwo) + .isLegendary = TRUE, + .levelUpLearnset = sMewtwoLevelUpLearnset, + .teachableLearnset = sMewtwoTeachableLearnset, + .formSpeciesIdTable = sMewtwoFormSpeciesIdTable, + .formChangeTable = sMewtwoFormChangeTable, ++ .evolutions = EVOLUTION({EVO_LEVEL, 100, SPECIES_MEWTHREE}), + }, + }; +``` + +## 4. Make it appear! +Now Mewthree really does slumber in the games code - but we won't know until we make him appear somewhere! The legend tells that Mewthree is hiding somewhere in Petalburg Woods... + +Edit [src/data/wild_encounters.json](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/wild_encounters.json): + +```diff + { + "map": "MAP_PETALBURG_WOODS", + "base_label": "gPetalburgWoods", + "land_mons": { + "encounter_rate": 20, + "mons": [ + { + "min_level": 5, + "max_level": 5, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 5, + "max_level": 5, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 5, + "max_level": 5, + "species": "SPECIES_SHROOMISH" + }, + { +- "min_level": 6, +- "max_level": 6, +- "species": "SPECIES_POOCHYENA" ++ "min_level": 5, ++ "max_level": 5, ++ "species": "SPECIES_MEWTHREE" + }, + ... + } +``` + +Congratulations, you have created your own personal pocket monster! You may call yourself a mad scientist now. + +# Optional data + +Now that you now have all the essential pieces to create a base species, there are some aspects that you might want to know if you want to do other stuff with your custom Pokémon. + +## 1. Form tables +Found in `src/data/pokemon/form_species_tables.h`. + +These are introduced to have a reference of what forms correspond to what Species of Pokémon. For example, we have Pikachu's table: +```c +#if P_FAMILY_PIKACHU +static const u16 sPikachuFormSpeciesIdTable[] = { + SPECIES_PIKACHU, + SPECIES_PIKACHU_COSPLAY, + SPECIES_PIKACHU_ROCK_STAR, + SPECIES_PIKACHU_BELLE, + SPECIES_PIKACHU_POP_STAR, + SPECIES_PIKACHU_PH_D, + SPECIES_PIKACHU_LIBRE, + SPECIES_PIKACHU_ORIGINAL_CAP, + SPECIES_PIKACHU_HOENN_CAP, + SPECIES_PIKACHU_SINNOH_CAP, + SPECIES_PIKACHU_UNOVA_CAP, + SPECIES_PIKACHU_KALOS_CAP, + SPECIES_PIKACHU_ALOLA_CAP, + SPECIES_PIKACHU_PARTNER_CAP, + SPECIES_PIKACHU_WORLD_CAP, + FORM_SPECIES_END, +}; +#endif //P_FAMILY_PIKACHU +``` +We register the table each form entry in `gSpeciesInfo`. + +```diff + [SPECIES_PIKACHU] = + { + ... + .teachableLearnset = sPikachuTeachableLearnset, ++ .formSpeciesIdTable = sPikachuFormSpeciesIdTable, + .evolutions = EVOLUTION({EVO_ITEM, ITEM_THUNDER_STONE, SPECIES_RAICHU}, + {EVO_NONE, 0, SPECIES_RAICHU_ALOLAN}), + }, + + [SPECIES_PIKACHU_COSPLAY] = + { + ... + .teachableLearnset = sPikachuTeachableLearnset, ++ .formSpeciesIdTable = sPikachuFormSpeciesIdTable, + }, +``` +...and so on. + +What this allows us to do is to be able to get all forms of a Pokémon in our code by using the `GetSpeciesFormTable` function. + +For example, in the HGSS dex, it lets us browse between the entries of every form available.: + +![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/a1a90b79-46a1-4cd6-97d6-ec5d741bfdc8) ![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/7cffc6be-0b5c-4074-b689-736a97297843) + +In addition, we have the `GET_BASE_SPECIES_ID` macro, which returns the first entry of the table (or return the species itself if it doesn't have a table registered). With this, you can check if a Pokémon is any form of a species. For example, making it so that the Light Ball affects all Pikachu forms: +```c + case HOLD_EFFECT_LIGHT_BALL: + if (GET_BASE_SPECIES_ID(gBattleMons[battlerAtk].species) == SPECIES_PIKACHU && IS_MOVE_SPECIAL(move)) + modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0)); + break; +``` + +## 2. Form change tables +Found in `src/data/pokemon/form_species_tables.h`. + +These tables, unlike the regular form tables, registers how Pokémon can switch between forms. + +```c +#if P_FAMILY_GASTLY +static const struct FormChange sGengarFormChangeTable[] = { + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_GENGAR_MEGA, ITEM_GENGARITE}, + {FORM_CHANGE_BATTLE_GIGANTAMAX, SPECIES_GENGAR_GIGANTAMAX}, + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_GASTLY +``` +The first value is the type of form change. In the case of Gengar, we have both Mega Evolution and Gigantamax form changes. + +The second value is the target form, to which the Pokémon will change into. + +Values after that are referred as arguments, and needs to be put there depends on the type of form change, detailed in `include/constants/form_change_types.h`. + +## 3. Gender differences +![mGBA_Wq5cbDkNZG](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/45256192-b451-4baa-af06-f57ca16e1e46) + +You may have seen that there's a couple of duplicate fields with a "Female" suffix. +```diff + [SPECIES_FRILLISH] = + { + ... + .frontPic = gMonFrontPic_Frillish, ++ .frontPicFemale = gMonFrontPic_FrillishF, + .frontPicSize = MON_COORDS_SIZE(56, 56), ++ .frontPicSizeFemale = MON_COORDS_SIZE(56, 56), + .frontPicYOffset = 5, + .frontAnimFrames = sAnims_Frillish, + .frontAnimId = ANIM_RISING_WOBBLE, + .backPic = gMonBackPic_Frillish, ++ .backPicFemale = gMonBackPic_FrillishF, + .backPicSize = MON_COORDS_SIZE(40, 56), ++ .backPicSizeFemale = MON_COORDS_SIZE(40, 56), + .backPicYOffset = 7, + .backAnimId = BACK_ANIM_CONVEX_DOUBLE_ARC, + .palette = gMonPalette_Frillish, ++ .paletteFemale = gMonPalette_FrillishF, + .shinyPalette = gMonShinyPalette_Frillish, ++ .shinyPaletteFemale = gMonShinyPalette_FrillishF, + .iconSprite = gMonIcon_Frillish, ++ .iconSpriteFemale = gMonIcon_FrillishF, + .iconPalIndex = 0, ++ .iconPalIndexFemale = 1, + FOOTPRINT(Frillish) + .levelUpLearnset = sFrillishLevelUpLearnset, + .teachableLearnset = sFrillishTeachableLearnset, + .evolutions = EVOLUTION({EVO_LEVEL, 40, SPECIES_JELLICENT}), + }, +``` +These are used to change the graphics of the Pokémon if they're female. If they're not registered, they default to the male values. + +However, `iconPalIndexFemale` is a special case, where it's *doesn't* read the male icon palette if its `iconSpriteFemale` is set, so if you're setting a female icon, be sure to set their palette index as well. diff --git a/docs/how_to_new_pokemon_1_9_0.md b/docs/how_to_new_pokemon_1_9_0.md new file mode 100644 index 0000000000..84742c3a76 --- /dev/null +++ b/docs/how_to_new_pokemon_1_9_0.md @@ -0,0 +1,1139 @@ + +This is a modified version of [the original tutorial about adding new Pokémon species available in Pokeemerald's wiki](https://github.com/pret/pokeemerald/wiki/How-to-add-a-new-Pokémon-species). + +Despite the persistent rumors about an incredibly strong third form of Mew hiding somewhere, it actually wasn't possible to catch it... OR WAS IT? +In this tutorial, we will add a new Pokémon species to the game. + +## IMPORTANT: This tutorial applies to 1.9.x versions. +- [Version 1.8.x](how_to_new_pokemon_1_8_0.md) +- [Version 1.7.x](how_to_new_pokemon_1_7_0.md) +- [Version 1.6.x](how_to_new_pokemon_1_6_0.md) + +# Changes compared to vanilla +The main things that the Expansion changes are listed here. +* Still Front Pics *(`gMonStillFrontPic_YourPokemon`)* and by extension `src/anim_mon_front_pics.c` have been removed. +* `src/data/pokemon/cry_ids.h` doesn't exist anymore. +* You have 6 icon palettes available instead of the base 3. +* Most tables that use `SPECIES_x` as indexes have been moved to `gSpeciesInfo`. + +# Content +* [Useful resources](#useful-resources) +* [The Data - Part 1](#the-data---part-1) + * [1. Declare a species constant](#1-Declare-a-species-constant) + * [2. `SpeciesInfo`'s structure](#2-speciesinfos-structure) + * [3. Define its basic species information](#3-define-its-basic-species-information) + * [4. Species Name](#4-species-name) + * [5. Define its cry](#5-define-its-cry) + * [6. Define its Pokédex entry](#6-define-its-pokédex-entry) +* [The Graphics](#the-graphics) + * [1. Edit the sprites](#1-edit-the-sprites) + * [2. Add the sprites to the rom](#2-add-the-sprites-to-the-rom) + * [3. Add the animations to the rom](#3-add-the-animations-to-the-rom) + * [4. Linking graphic information to our Pokémon](#4-linking-graphic-information-to-our-pokémon) +* [The Data - Part 2](#the-data---part-2) + * [1. Species Flags](#1-species-flags) + * [2. Delimit the moveset](#2-delimit-the-moveset) + * [3. Define the Evolutions](#3-define-the-evolutions) + * [4. Make it appear!](#4-make-it-appear) +* [Optional data](#optional-data) + * [1. Form tables](#1-form-tables) + * [2. Form change tables](#2-form-change-tables) + * [3. Gender differences](#3-gender-differences) + * [4. Overworld Data](#4-overworld-data) + +# Useful resources +You can open a sprite debug menu by pressing `Select` in a Pokémon's summary screen outside of battle. + +![mGBA_6WOo1TSlsn](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/0c625cd8-8f89-4bc8-a285-b10a420a8f6d) + + +# The Data - Part 1 + +Our plan is as simple as it is brilliant: clone Mewtwo... and make it even stronger! + +## 1. Declare a species constant + +Our first step towards creating a new digital lifeform is to define its own species constant. + +Edit [include/constants/species.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/species.h): + +```diff + #define SPECIES_NONE 0 + #define SPECIES_BULBASAUR 1 + ... + #define SPECIES_EEVEE_PARTNER PLACEHOLDER_START + 54 ++#define SPECIES_MEWTHREE PLACEHOLDER_START + 55 + +-#define GIGANTAMAX_START SPECIES_EEVEE_PARTNER ++#define GIGANTAMAX_START SPECIES_MEWTHREE + + // Gigantamax Forms + #define SPECIES_VENUSAUR_GIGANTAMAX GIGANTAMAX_START + 1 +``` +This number is stored in a Pokémon's save structure. These should generally never change, otherwise your saved Pokémon species will change as well. + +We add this before Gigantamax forms because they're temporary forms that shouldn't normally be saved into a Pokémon's save structure. + +Now, let's see how it looks in-game! + +![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/dc15b0ba-a4bd-4f4e-9658-2dff73a11f79) + +Hmmm, something's not right... + +Oh, I know! We need to add the rest of the data! Normally, the vanilla game would crash if we try to look up anything about Mewthree in this state, but the expansion defaults all of its data to `SPECIES_NONE`. + +Now, let's see what needs to be done. + +## 2. `SpeciesInfo`'s structure +Now, to better understand Mewtwo, we also need to understand Mew. Let's look at its data. +```diff + [SPECIES_MEW] = + { + .baseHP = 100, + .baseAttack = 100, + .baseDefense = 100, + .baseSpeed = 100, + .baseSpAttack = 100, + .baseSpDefense = 100, + .types = { TYPE_PSYCHIC, TYPE_PSYCHIC }, + .catchRate = 45, + #if P_UPDATED_EXP_YIELDS >= GEN_8 + .expYield = 300, + #elif P_UPDATED_EXP_YIELDS >= GEN_5 + .expYield = 270, + #else + .expYield = 64, + #endif + .evYield_HP = 3, + .itemCommon = ITEM_LUM_BERRY, + .itemRare = ITEM_LUM_BERRY, + .genderRatio = MON_GENDERLESS, + .eggCycles = 120, + .friendship = 100, + .growthRate = GROWTH_MEDIUM_SLOW, + .eggGroups = { EGG_GROUP_NO_EGGS_DISCOVERED, EGG_GROUP_NO_EGGS_DISCOVERED }, + .abilities = { ABILITY_SYNCHRONIZE, ABILITY_NONE }, + .bodyColor = BODY_COLOR_PINK, + .isMythical = TRUE, + .speciesName = _("Mew"), + .cryId = CRY_MEW, + .natDexNum = NATIONAL_DEX_MEW, + .categoryName = _("New Species"), + .height = 4, + .weight = 40, + .description = COMPOUND_STRING( + "A Mew is said to possess the genes of all\n" + "Pokémon. It is capable of making itself\n" + "invisible at will, so it entirely avoids\n" + "notice even if it approaches people."), + .pokemonScale = 457, + .pokemonOffset = -2, + .trainerScale = 256, + .trainerOffset = 0, + .frontPic = gMonFrontPic_Mew, + .frontPicSize = MON_COORDS_SIZE(64, 48), + .frontPicYOffset = 9, + .frontAnimFrames = sAnims_Mew, + .frontAnimId = ANIM_ZIGZAG_SLOW, + .enemyMonElevation = 11, + .backPic = gMonBackPic_Mew, + .backPicSize = MON_COORDS_SIZE(64, 64), + .backPicYOffset = 0, + .backAnimId = BACK_ANIM_CONCAVE_ARC_SMALL, + .palette = gMonPalette_Mew, + .shinyPalette = gMonShinyPalette_Mew, + .iconSprite = gMonIcon_Mew, + .iconPalIndex = 0, + FOOTPRINT(Mew) + .levelUpLearnset = sMewLevelUpLearnset, + .teachableLearnset = sMewTeachableLearnset, + }, +``` + +That's a lot of stuff! But don't worry, we'll go through it step by step throught the tutorial +(and miles better than having this same data through 20+ files like it used to be). + +We'll start by adding the self-explanatory data that's also present in pret's vanilla structure: + +## 3. Define its basic species information +Edit [src/data/pokemon/species_info.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/species_info.h): +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + [SPECIES_NONE] = {0}, + ... + + [SPECIES_EGG] = + { + FRONT_PIC(Egg, 24, 24), + .frontPicYOffset = 20, + .backPic = gMonFrontPic_Egg, + .backPicSize = MON_COORDS_SIZE(24, 24), + .backPicYOffset = 20, + .palette = gMonPalette_Egg, + .shinyPalette = gMonPalette_Egg, + ICON(Egg, 1), + }, + ++ [SPECIES_MEWTHREE] = ++ { ++ .baseHP = 106, ++ .baseAttack = 150, ++ .baseDefense = 70, ++ .baseSpeed = 140, ++ .baseSpAttack = 194, ++ .baseSpDefense = 120, ++ .types = { TYPE_PSYCHIC, TYPE_PSYCHIC }, ++ .catchRate = 3, ++ .expYield = 255, ++ .evYield_SpAttack = 3, ++ .genderRatio = MON_GENDERLESS, ++ .eggCycles = 120, ++ .friendship = 0, ++ .growthRate = GROWTH_SLOW, ++ .eggGroups = { EGG_GROUP_NO_EGGS_DISCOVERED, EGG_GROUP_NO_EGGS_DISCOVERED }, ++ .abilities = { ABILITY_INSOMNIA, ABILITY_NONE, ABILITY_NONE }, ++ .bodyColor = BODY_COLOR_PURPLE, ++ }, + }; +``` + +The `.` is the structure reference operator in C to refer to the member object of the structure SpeciesInfo. + +- `baseHP`, `baseAttack`, `baseDefense`, `baseSpeed`, `baseSpAttack` and `baseSpDefense` are the base stats. They can't go higher than 255. +- You may be confused as to why `types` has `TYPE_PSYCHIC` twice. This is because the way the game determines single-type mon is to define both types the same. + - If we don't, it defaults to Normal due to it being the first type defined. +- `catchRate` is how likely it is to catch a Pokémon, the lower the value, the harder it is to catch. Legendaries generally have a catch rate of 3, so we put that here. +- `expYield` is the base amount of experience that a Pokémon gives when defeated/caught. In vanilla, this value caps at 255, but we've increased it to a maximum of 65535 accomodate later gen's higher experience yields. (The highest official value is Blissey's with 608, so going beyond this point may cause exponential gains that could break the system 😱) + - If you noticed, Mew's had some `#if`s, `#elif`s and `#endif` around it. This is because its yield has changed over time, and we let you choose which ones you want. This is not relevant to our Mewthree however, so we can just put a single `.expYield = 255,` line here. +- `evYield_HP`, `evYield_Attack`, `evYield_Defense`, `evYield_Speed`, `evYield_SpAttack` and `evYield_SpDefense` are how many EVs does the Pokémon give when they're caught. Each of these fields can have a value of 3 at most. Officially, no Pokémon give out more than 3 EVs total, with them being determined by their evolution stage (eg, Pichu, Pikachu and Raichu give 1, 2 and 3 Speed EVs respectively), and they tend to be associated with its higher stats. Since our Mewthree is a Special Attack monster, we'll be consistent and make it give out 3 Special Attack EVs, but you're always free to assign whatever you feel like :) + - Notice that the other `evYield` fields are not there. In C, numbers in a struct default to 0, so if we don't specify them, they'll be 0 all around! Less lines to worry about :D +- `itemCommon` and `itemRare` are used to determine what items is the Pokémon holding when encountering it in the wild. + - 50% for `itemCommon` and 5% for `itemRare` (boosted to 60%/20% when the first mon in the party has Compound Grass or Super Luck) + - If they're both set as the same item, the item has a 100% chance of appearing. +- `genderRatio` is a fun one. + - There are 4 ways of handling this + - `PERCENT_FEMALE` is what most Pokémon use, where you define how likely it's gonna be female. It supports decimals, so you can put `PERCENT_FEMALE(12.5)` to have a 1 in 8 chance of your mon to be female. + - `MON_MALE` guarantees that all mon of this species will be male (eg. Tauros) + - `MON_FEMALE` guarantees that all mon of this species will be female (eg. Miltank) + - `MON_GENDERLESS` makes your species genderless, unable to breed with anything but Ditto to produce eggs. Most Legendaries are this, so we'll be chosing this as Mewthree's gender ratio. + - When working with evolution lines and don't want their genders to change after evolving, be sure that their gender ratios match their stages and evolution methods. Azurill is the only case where there's a mismatch, causing 1/3 of all Azurill to change from Female to Male. + - You might be wondering why some species have multiple defines for their genders, like `SPECIES_MEOWSTIC_(FE)MALE`. This is because those species have different stats and data from each other, so they're defined internally as different forms with `MON_MALE` and `MON_FEMALE` as gender ratios. If your species evolves depending on its gender and the evolutions have different stats, be sure to apply the correct evolution method! +- `eggCycles` determines how fast an egg of this species will hatch. Doesn't matter much for evolved species or those that can't lay eggs, but we add the field here just in case. +- `friendship` determines the amount of friendship of the mon when you catch it. Most Pokémon use `STANDARD_FRIENDSHIP`, but this creature of chaos does not want to be your friend, starting with 0. +- `growthRate` determines the amounts of experience required to reach each level. Go [here](https://bulbapedia.bulbagarden.net/wiki/Experience) for more info. +- `eggGroups` are used for breed compatibility. Most Legendaries and Mythicals have the `EGG_GROUP_NO_EGGS_DISCOVERED` group, and so does our Mewthree. Go [here](https://bulbapedia.bulbagarden.net/wiki/Egg_Group) for more info. +- `abilities` determines the potential abilites of our species. Notice how I also set the ability to `ABILITY_INSOMNIA`, so our little monster doesn't even need to sleep anymore. You can find the abilities for example here [include/constants/abilities.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/abilities.h). + - When both slot 1 and 2 are defined as not being `ABILITY_NONE`, their starting ability will be decided on a coin flip using their personality. They can later be changed using an Ability Capsule. + - Certain Pokémon such as Zygarde and Rockruff have different forms to add additional abilities. As such, they cannot be changed using an Ability Capsule (though the Zygarde Cube can change Zygarde's ability by changing them to their corresponding form) + - The 3rd slot is for Hidden Abilities. If defined as `ABILITY_NONE`, it will default to Slot 1 (eg. Metapod doesn't have a Hidden Ability, but Caterpie and Butterfree do). Go [here](https://bulbapedia.bulbagarden.net/wiki/Ability#Hidden_Abilities) and [here](https://bulbapedia.bulbagarden.net/wiki/Ability_Patch) for more info. + - If the array is defined as `{ABILITY_1, ABILITY_2}`, the Hidden Ability is set as `ABILITY_NONE`. +- `bodyColor` is used in the Pokédex as a search filter. +- `noFlip` is used in to prevent front sprites from being flipped horizontally and cause weird issues, like Clawitzer's big claw changing sides. + +That's all the basic fields present in vanilla emerald, so now let's take a look at the new fields added by the expansion. + +## 4. Species Name + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .isLegendary = TRUE, + .allPerfectIVs = TRUE, ++ .speciesName = _("Mewthree"), + }, + }; +``` +The `_()` underscore function doesn't really exist - it's a convention borrowed from GNU gettext to let `preproc` know this is text to be converted to the custom encoding used by the Gen 3 Pokemon games. + +## 5. Define its cry + +Time for audio! +We first need to convert an existing audio file to the format supported by the expansion. + +Most formats are supported for conversion, but for simplicity's sake, we're gonna use an mp3 file. + +Now, let's copy the file to the `sound/direct_sound_samples/cries` folder. +Once that's done, let's run the following command: +``` +ffmpeg -i sound/direct_sound_samples/cries/mewthree.mp3 -c:a pcm_s8 -ac 1 -ar 13379 sound/direct_sound_samples/cries/mewthree.aif +``` +This will convert your audio file to .aif, which is what's read by the compiler. + +Let's add the cry to the ROM via [sound/direct_sound_data.inc](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/sound/direct_sound_data.inc). + +```diff +.if P_FAMILY_PECHARUNT == TRUE + .align 2 +Cry_Pecharunt:: + .incbin "sound/direct_sound_samples/cries/pecharunt.bin" +.endif @ P_FAMILY_PECHARUNT + ++ .align 2 ++Cry_Mewthree:: ++ .incbin "sound/direct_sound_samples/cries/mewthree.bin" + +``` + +Then we add the cry ID to [include/constants/cries.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/cries.h): + +```diff +enum { + CRY_NONE, + ... +#if P_FAMILY_TERAPAGOS + CRY_TERAPAGOS, +#endif //P_FAMILY_TERAPAGOS +#if P_FAMILY_PECHARUNT + CRY_PECHARUNT, +#endif //P_FAMILY_PECHARUNT ++ CRY_MEWTHREE, + CRY_COUNT, +}; +``` + +And then link it in [sound/cry_tables.inc](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/sound/cry_tables.inc). `cry_reverse` in particular is for reversed cries used by moves such as Growl. The order of these two tables should match the order of the cry IDs, otherwise they'll be shifted. + +```diff + cry Cry_Terapagos + cry Cry_Pecharunt ++ cry Cry_Mewthree +``` +```diff + cry_reverse Cry_Terapagos + cry_reverse Cry_Pecharunt ++ cry_reverse Cry_Mewthree +``` + +Lastly, we add the cry to our species entry +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .isLegendary = TRUE, + .allPerfectIVs = TRUE, + .speciesName = _("Mewthree"), ++ .cryId = CRY_MEWTHREE, + }, + }; +``` + +And let's see how it sounds in-game: + +https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/4f7667db-4db9-4bfd-a8dd-ece26f09f327 + +Good! Our monster now has a mighty roar! + +You can now delete the mp3 from the cries folder now once you made sure that the cry sounds like how you want it to. + +## 6. Define its Pokédex entry + +First, we will need to add new index constants for its Pokédex entry. The index constants are divided into the Hoenn Pokédex, which contains all Pokémon native to the Hoenn region, and the National Pokédex containing all known Pokémon, which can be received after entering the hall of fame for the first time. + +Edit [include/constants/pokedex.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/pokedex.h): + +```diff +// National Pokedex order +enum { + NATIONAL_DEX_NONE, + // Kanto + NATIONAL_DEX_BULBASAUR, +... + NATIONAL_DEX_PECHARUNT, ++ NATIONAL_DEX_MEWTHREE, +}; +``` + +```diff + #define KANTO_DEX_COUNT NATIONAL_DEX_MEW + #define JOHTO_DEX_COUNT NATIONAL_DEX_CELEBI + +#if P_GEN_9_POKEMON == TRUE +- #define NATIONAL_DEX_COUNT NATIONAL_DEX_PECHARUNT ++ #define NATIONAL_DEX_COUNT NATIONAL_DEX_MEWTHREE +``` + +Do keep in mind that if you intend to add your new species to the Hoenn Dex, you'll also want to add a `HOENN_DEX` constant for it, like this: + +```diff +// Hoenn Pokedex order +enum { + HOENN_DEX_NONE, + HOENN_DEX_TREECKO, +... + HOENN_DEX_DEOXYS, ++ HOENN_DEX_MEWTHREE, +}; + +- #define HOENN_DEX_COUNT (HOENN_DEX_DEOXYS + 1) ++ #define HOENN_DEX_COUNT (HOENN_DEX_MEWTHREE + 1) +``` + +Edit [src/pokemon.c](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/pokemon.c): + +```diff + const u16 sHoennToNationalOrder[NUM_SPECIES] = // Assigns Hoenn Dex Pokémon (Using National Dex Index) + { + HOENN_TO_NATIONAL(TREECKO), + ... + HOENN_TO_NATIONAL(DEOXYS), ++ HOENN_TO_NATIONAL(MEWTHREE), + }; +``` + +Now we can add the number and entry to our Mewthree: +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .cryId = CRY_MEWTHREE, ++ .natDexNum = NATIONAL_DEX_MEWTHREE, ++ .categoryName = _("New Species"), ++ .height = 15, ++ .weight = 330, ++ .description = COMPOUND_STRING( ++ "The rumors became true.\n" ++ "This is Mew's final form.\n" ++ "Its power level is over 9000.\n" ++ "Has science gone too far?"), ++ .pokemonScale = 256, ++ .pokemonOffset = 0, ++ .trainerScale = 290, ++ .trainerOffset = 2, + }, + }; +``` +![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/3759dd4c-8da5-4b1c-9a50-b9e9d0815e7f) + +The values `pokemonScale`, `pokemonOffset`, `trainerScale` and `trainerOffset` are used for the height comparison figure in the Pokédex. + +`height` and `weight` are specified in decimeters and hectograms respectively (which are meters and kilograms multiplied by 10, so 2.5 meters are 25 decimeters). + +In Pokémon Emerald, you can sort the Pokédex by name, height or weight. Apparently, the Pokémon order is hardcoded in the game files and not calculated from their data. Therefore we have to include our new Pokémon species at the right places. While the correct position for the alphabetical order is easy to find, it can become quite tedious for height and weight, so we added comments to the listings in order help out were they should fit. + +Edit [src/data/pokemon/pokedex_orders.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/pokedex_orders.h): + +```diff + const u16 gPokedexOrder_Alphabetical[] = + { + ... + NATIONAL_DEX_MEW, ++ NATIONAL_DEX_MEWTHREE, + NATIONAL_DEX_MEWTWO, + ... + }; + + const u16 gPokedexOrder_Weight[] = + { + ... + // 72.8 lbs / 33.0 kg + //NATIONAL_DEX_MEWTWO_MEGA_Y, + NATIONAL_DEX_ESCAVALIER, + NATIONAL_DEX_FRILLISH, + NATIONAL_DEX_DURANT, + NATIONAL_DEX_CINDERACE, ++ NATIONAL_DEX_MEWTHREE, + //NATIONAL_DEX_PERSIAN_ALOLAN, + NATIONAL_DEX_TOEDSCOOL, + // 73.4 lbs / 33.3 kg + NATIONAL_DEX_DUGTRIO, + ... + }; + + const u16 gPokedexOrder_Height[] = + { + ... + // 4'11" / 1.5m + ... + NATIONAL_DEX_GLIMMORA, + NATIONAL_DEX_WO_CHIEN, + NATIONAL_DEX_IRON_LEAVES, + NATIONAL_DEX_IRON_BOULDER, ++ NATIONAL_DEX_MEWTHREE, + // 5'03" / 1.6m + ... + }; +``` +![mGBA_lUBfmFEKUx](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/3a8b8a17-759b-486b-9831-deb2f494bd71) + + +# The Graphics +We will start by copying the following files for *Mew* (not Mewtwo) and rename it to `mewthree`. +```sh +cp -r graphics/pokemon/mew/. graphics/pokemon/mewthree +``` +We aren't copying Mewtwo's folder because he has those pesky Mega Evolutions that will get in the way of what we're doing, so our sample will need to be pure from the source. + +## 1. Edit the sprites +Let's edit the sprites. Start your favourite image editor (I recommend Aseprite or its free alternative, Libresprite) and change `anim_front.png` and `back.png` to meet your expectations. + +__Make sure that you are using the indexed mode and you have limited yourself to 15 colors!__ + +Put the RGB values of your colors into `normal.pal` between the first and the last color and the RGB values for the shiny version into `shiny.pal`. +Edit `footprint.png` using two colors in indexed mode, black and white. +Finally, edit `icon.png`. Notice, that the icon will use one of 6 predefined palettes instead of `normal.pal`. + +## 2. Add the sprites to the rom +Sadly, just putting the image files into the graphics folder is not enough. To use the sprites we have to register them, which is kind of tedious. +First, create constants for the file paths. You'll want to add the constants for your species after the constants for the last valid species. + +Edit [src/data/graphics/pokemon.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/graphics/pokemon.h): + +```diff +#if P_FAMILY_PECHARUNT + // const u32 gMonFrontPic_Pecharunt[] = INCBIN_U32("graphics/pokemon/pecharunt/front.4bpp.lz"); + // const u32 gMonPalette_Pecharunt[] = INCBIN_U32("graphics/pokemon/pecharunt/normal.gbapal.lz"); + // const u32 gMonBackPic_Pecharunt[] = INCBIN_U32("graphics/pokemon/pecharunt/back.4bpp.lz"); + // const u32 gMonShinyPalette_Pecharunt[] = INCBIN_U32("graphics/pokemon/pecharunt/shiny.gbapal.lz"); + // const u8 gMonIcon_Pecharunt[] = INCBIN_U8("graphics/pokemon/pecharunt/icon.4bpp"); +#if P_FOOTPRINTS + // const u8 gMonFootprint_Pecharunt[] = INCBIN_U8("graphics/pokemon/pecharunt/footprint.1bpp"); +#endif //P_FOOTPRINTS +#endif //P_FAMILY_PECHARUNT + ++ const u32 gMonFrontPic_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/anim_front.4bpp.lz"); ++ const u32 gMonBackPic_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/back.4bpp.lz"); ++ const u32 gMonPalette_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/normal.gbapal.lz"); ++ const u32 gMonShinyPalette_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/shiny.gbapal.lz"); ++ const u8 gMonIcon_Mewthree[] = INCBIN_U8("graphics/pokemon/mewthree/icon.4bpp"); ++ const u8 gMonFootprint_Mewthree[] = INCBIN_U8("graphics/pokemon/mewthree/footprint.1bpp"); +``` + +Please note that Pecharunt, the Pokémon that should be above your insertion for the time being, reads a `front.png` sprite instead of an `anim_front.png` sprite. This is because currently, Pecharunt lacks a 2nd frame. If the front sprite sheet of your species uses 2 frames, you should use `anim_front`. + +It is also worth to mention that Pecharunt's sprites are commented out simply because they're currently missing. + +## 3. Add the animations to the rom + +You can define the animation order, in which the sprites will be shown. The first number is the sprite index (so 0 or 1) and the second number is the number of frames the sprite will be visible. + +Edit [src/data/pokemon_graphics/front_pic_anims.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon_graphics/front_pic_anims.h): + +```diff +#if P_FAMILY_PECHARUNT +PLACEHOLDER_ANIM_SINGLE_FRAME(Pecharunt); +#endif //P_FAMILY_PECHARUNT + ++static const union AnimCmd sAnim_Mewthree_1[] = ++{ ++ ANIMCMD_FRAME(1, 30), ++ ANIMCMD_FRAME(0, 20), ++ ANIMCMD_END, ++}; +``` + +```diff +#if P_FAMILY_PECHARUNT +SINGLE_ANIMATION(Pecharunt); +#endif //P_FAMILY_PECHARUNT ++SINGLE_ANIMATION(Mewthree); +SINGLE_ANIMATION(Egg); +``` + +You might be wondering what `PLACEHOLDER_ANIM_SINGLE_FRAME` is. Well, since Pecharun only has 1 frame, we use what's called a preprocessor *macro* to have in a single line what otherwise would've been this in the C file: +```c +static const union AnimCmd sAnim_Pecharunt_1[] = +{ + ANIMCMD_FRAME(0, 1), + ANIMCMD_END, +} +``` +Instead, we can use the already established macro that does the same thing, replacing the value in parenthesis with what we want (in this case, `Pecharunt`): +```c +#define PLACEHOLDER_ANIM_SINGLE_FRAME(name) \ +static const union AnimCmd sAnim_##name##_1[] = \ +{ \ + ANIMCMD_FRAME(0, 1), \ + ANIMCMD_END, \ +} +``` + +## 4. Linking graphic information to our Pokémon +Now that we have all the external data ready, we just need to add it to `gSpeciesInfo` plus the rest of the animation and graphical data that we want to use: + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .pokemonScale = 256, + .pokemonOffset = 0, + .trainerScale = 290, + .trainerOffset = 2, ++ .frontPic = gMonFrontPic_Mewthree, ++ .frontPicSize = MON_COORDS_SIZE(64, 64), ++ .frontPicYOffset = 0, ++ .frontAnimFrames = sAnims_Mewthree, ++ .frontAnimId = ANIM_GROW_VIBRATE, ++ .frontAnimDelay = 15, ++ .enemyMonElevation = 6, ++ .backPic = gMonBackPic_Mewthree, ++ .backPicSize = MON_COORDS_SIZE(64, 64), ++ .backPicYOffset = 0, ++ .backAnimId = BACK_ANIM_CONCAVE_ARC_SMALL, ++ .palette = gMonPalette_Mewthree, ++ .shinyPalette = gMonShinyPalette_Mewthree, + .iconSprite = gMonIcon_Mewthree, + .iconPalIndex = 2, ++ FOOTPRINT(Mewthree) + }, + }; +``` +Let's explain each of these: +- `frontPic`: + - Used to reference the front sprite, so in this case, we call for `gMonFrontPic_Mewthree`. +- `frontPicSize`: + - The two values (`width` and `height`) are used for defining the non-empty size of the front sprite, which is used in move animations. If you're unsure of the values, you can leave them both as 64. +- `frontPicYOffset`: + - Used to define what Y position the sprite sits at. This is used to set where they'd be "grounded". For the shadow, see `enemyMonElevation`. +- `frontAnimFrames`: + - We link our animation frame animations that we defined earlier here. +- `frontAnimId`: + - Because you are limited to two frames, there are already [predefined front sprite animations](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/pokemon_animation.h), describing translations, rotations, scalings or color changes. +- `frontAnimDelay`: + - Sets a delay in frame count between when the Pokémon appears and when the animation starts. +- `enemyMonElevation`: + - Used to determine the altitude from the ground. Any value above 0 will show a shadow under the Pokémon, to signify that they're floating. +- `backPic`: + - Used to reference the back sprite, so in this case, we call for `gMonBackPic_Mewthree`. +- `backPicSize`: + - The two values (`width` and `height`) are used for defining the non-empty size of the back sprite, which is used in move animations. If you're unsure of the values, you can leave them both as 64. +- `backPicYOffset`: + - Used to define what Y position of the back sprite. When working with the animation debug menu, we recommend aligning the back sprite to the white background, as it was designed to properyly align with the real battle layout. +- `backAnimId`: + - Like `frontAnimId` except for the back sprites and them being a single frame. The IDs listed [here](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/pokemon_animation.h) are used to represent 3 different animations that happen based on the the Pokémon's nature. +- `palette`: + - Used to reference the non-shiny palette, so in this case, we call for `gMonPalette_Mewthree`. +- `shinyPalette`: + - Used to reference the shiny palette, so in this case, we call for `gMonShinyPalette_Mewthree`. +- `iconSprite`: + - Used to reference the icon sprite, so in this case, we call for `gMonIcon_Mewthree`. +- `iconPalIndex`: +- `ICON` + - Here, you can choose between the six icon palettes; 0, 1, 2, 3, 4 and 5. All of them located in `graphics/pokemon/icon_palettes`. + + Open an icon sprite and load one of the palettes to find out which palette suits your icon sprite best. +- `FOOTPRINT` + - We made this single field into a macro so that they can be ignored when `P_FOOTPRINTS` is set to false. It's also why we don't have an "," after calling it like the other macros (we add it as part of the macro itself). + ```c + #if P_FOOTPRINTS + #define FOOTPRINT(sprite) .footprint = gMonFootprint_## sprite, + #else + #define FOOTPRINT(sprite) + #endif + ``` + +# The Data - Part 2 + +We're almost there just a bit left! + +## 1. Species Flags + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + .abilities = { ABILITY_INSOMNIA, ABILITY_NONE, ABILITY_NONE }, + .bodyColor = BODY_COLOR_PURPLE, ++ .isLegendary = TRUE, ++ .allPerfectIVs = TRUE, + }, + }; +``` +Each species flag provides properties to the species: +- `isLegendary`: + - Guarantees 3 perfect IVs upon generating the Pokémon (As long as `P_LEGENDARY_PERFECT_IVS` is set to `GEN_6` or higher). +- `isMythical`: + - Guarantees 3 perfect IVs upon generating the Pokémon (As long as `P_LEGENDARY_PERFECT_IVS` is set to `GEN_6` or higher). + - Is skipped during Pokédex evaluations. + - Unless it also has the `dexForceRequired` flag. + - Cannot obtain Gigantamax factor via `ToggleGigantamaxFactor`. +- `isUltraBeast`: + - Guarantees 3 perfect IVs upon generating the Pokémon (As long as `P_LEGENDARY_PERFECT_IVS` is set to `GEN_6` or higher). + - Beast Ball's multiplier is set to x5 for this species. + - All other ball multipliers are set to x0.1. +- `isParadox` (previously `isParadoxForm`): + - Currently has no functionality but can be utilized by users for their own benefits. +- `isTotem`: + - Guarantees 3 perfect IVs upon generating the Pokémon (As long as `P_LEGENDARY_PERFECT_IVS` is set to `GEN_6` or higher). +- `isMegaEvolution`: + - A Mega indicator is added to the battle box indicating that they're Mega Evolved. + - The species doesn't receive affection benefits. + - Required when adding new Mega Evolutions. +- `isPrimalReversion`: + - A Primal Reversion indicator (Alpha or Omega for Kyogre/Groudon respectively) is added to the battle box indicating that they're Primal Reverted. + - Required when adding new Primal Reversions. +- `isUltraBurst`: + - Required when adding new Ultra Burst forms. +- `isGigantamax`: + - Used to determine if Gigantamax forms should have their GMax moves or not. + - Required when adding new Gigantamax forms. +- `isAlolanForm`, `isGalarianForm`, `isHisuianForm`, `isPaldeanForm`: + - In the future, these will be used to determine breeding offspring from different based on their region. +- `cannotBeTraded`: + - This species cannot be traded away (like Black/White Kyurem). +- `allPerfectIVs`: + - Guarantees 6 perfect IVs upon generating the Pokémon (like LGPE's Partner Pikachu and Eevee). +- `tmIlliterate`: + - This species will be unable to learn the universal moves. +- `isFrontierBanned`: + - This species will be unable to enter Battle Frontier facilities. Replaces `gFrontierBannedSpecies`. + +*: As long as `P_LEGENDARY_PERFECT_IVS` is set to `GEN_6` or higher. + +## 2. Delimit the moveset + +Let's begin with the moves that can be learned by leveling up. + +Append to [src/data/pokemon/level_up_learnsets.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/level_up_learnsets.h): + +```diff +#if P_FAMILY_PECHARUNT +static const struct LevelUpMove sPecharuntLevelUpLearnset[] = { + LEVEL_UP_MOVE( 1, MOVE_SMOG), + LEVEL_UP_MOVE( 1, MOVE_POISON_GAS), + LEVEL_UP_MOVE( 1, MOVE_MEMENTO), + LEVEL_UP_MOVE( 1, MOVE_ASTONISH), + LEVEL_UP_MOVE( 8, MOVE_WITHDRAW), + LEVEL_UP_MOVE(16, MOVE_DESTINY_BOND), + LEVEL_UP_MOVE(24, MOVE_FAKE_TEARS), + LEVEL_UP_MOVE(32, MOVE_PARTING_SHOT), + LEVEL_UP_MOVE(40, MOVE_SHADOW_BALL), + LEVEL_UP_MOVE(48, MOVE_MALIGNANT_CHAIN), + LEVEL_UP_MOVE(56, MOVE_TOXIC), + LEVEL_UP_MOVE(64, MOVE_NASTY_PLOT), + LEVEL_UP_MOVE(72, MOVE_RECOVER), + LEVEL_UP_END +}; +#endif + ++static const struct LevelUpMove sMewthreeLevelUpLearnset[] = { ++ LEVEL_UP_MOVE( 1, MOVE_CONFUSION), ++ LEVEL_UP_MOVE( 1, MOVE_DISABLE), ++ LEVEL_UP_MOVE(11, MOVE_BARRIER), ++ LEVEL_UP_MOVE(22, MOVE_SWIFT), ++ LEVEL_UP_MOVE(33, MOVE_PSYCH_UP), ++ LEVEL_UP_MOVE(44, MOVE_FUTURE_SIGHT), ++ LEVEL_UP_MOVE(55, MOVE_MIST), ++ LEVEL_UP_MOVE(66, MOVE_PSYCHIC), ++ LEVEL_UP_MOVE(77, MOVE_AMNESIA), ++ LEVEL_UP_MOVE(88, MOVE_RECOVER), ++ LEVEL_UP_MOVE(99, MOVE_SAFEGUARD), ++ LEVEL_UP_END ++}; +``` + +Again, we need to register the learnset in `gSpeciesInfo`: + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + PALETTES(Mewthree), + ICON(Mewthree, 2), + FOOTPRINT(Mewthree) ++ .levelUpLearnset = sMewthreeLevelUpLearnset, + }, + }; +``` + +Next we need to specify which moves can be taught via TM, HM, or Move Tutor. + +Append to [src/data/pokemon/teachable_learnsets.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/teachable_learnsets.h): + +```diff +#if P_FAMILY_PECHARUNT +static const u16 sPecharuntTeachableLearnset[] = { + ... + MOVE_UNAVAILABLE, +}; +#endif //P_FAMILY_PECHARUNT + ++static const u16 sMewthreeTeachableLearnset[] = { ++ MOVE_FOCUS_PUNCH, ++ MOVE_WATER_PULSE, ++ MOVE_CALM_MIND, ++ MOVE_TOXIC, ++ MOVE_HAIL, ++ MOVE_BULK_UP, ++ MOVE_HIDDEN_POWER, ++ MOVE_SUNNY_DAY, ++ MOVE_TAUNT, ++ MOVE_ICE_BEAM, ++ MOVE_BLIZZARD, ++ MOVE_HYPER_BEAM, ++ MOVE_LIGHT_SCREEN, ++ MOVE_PROTECT, ++ MOVE_RAIN_DANCE, ++ MOVE_SAFEGUARD, ++ MOVE_FRUSTRATION, ++ MOVE_SOLAR_BEAM, ++ MOVE_IRON_TAIL, ++ MOVE_THUNDERBOLT, ++ MOVE_THUNDER, ++ MOVE_EARTHQUAKE, ++ MOVE_RETURN, ++ MOVE_PSYCHIC, ++ MOVE_SHADOW_BALL, ++ MOVE_BRICK_BREAK, ++ MOVE_DOUBLE_TEAM, ++ MOVE_REFLECT, ++ MOVE_SHOCK_WAVE, ++ MOVE_FLAMETHROWER, ++ MOVE_SANDSTORM, ++ MOVE_FIRE_BLAST, ++ MOVE_ROCK_TOMB, ++ MOVE_AERIAL_ACE, ++ MOVE_TORMENT, ++ MOVE_FACADE, ++ MOVE_SECRET_POWER, ++ MOVE_REST, ++ MOVE_SKILL_SWAP, ++ MOVE_SNATCH, ++ MOVE_STRENGTH, ++ MOVE_FLASH, ++ MOVE_ROCK_SMASH, ++ MOVE_MEGA_PUNCH, ++ MOVE_MEGA_KICK, ++ MOVE_BODY_SLAM, ++ MOVE_DOUBLE_EDGE, ++ MOVE_COUNTER, ++ MOVE_SEISMIC_TOSS, ++ MOVE_MIMIC, ++ MOVE_METRONOME, ++ MOVE_DREAM_EATER, ++ MOVE_THUNDER_WAVE, ++ MOVE_SUBSTITUTE, ++ MOVE_DYNAMIC_PUNCH, ++ MOVE_PSYCH_UP, ++ MOVE_SNORE, ++ MOVE_ICY_WIND, ++ MOVE_ENDURE, ++ MOVE_MUD_SLAP, ++ MOVE_ICE_PUNCH, ++ MOVE_SWAGGER, ++ MOVE_SLEEP_TALK, ++ MOVE_SWIFT, ++ MOVE_THUNDER_PUNCH, ++ MOVE_FIRE_PUNCH, ++ MOVE_UNAVAILABLE, // This is required to determine where the array ends. ++}; +#endif +``` + +Once more, we need to register the learnset in `gSpeciesInfo`: + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + FOOTPRINT(Mewthree) + .levelUpLearnset = sMewthreeLevelUpLearnset, ++ .teachableLearnset = sMewthreeTeachableLearnset, + }, + }; +``` + +If you want to create a Pokémon which can breed, you will need to edit [src/data/pokemon/egg_moves.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/pokemon/egg_moves.h). + + +## 3. Define the Evolutions + +We want Mewthree to evolve from Mewtwo by reaching level 100. + +Edit `gSpeciesInfo`: + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTWO] = + { + ... + FOOTPRINT(Mewtwo) + .isLegendary = TRUE, + .levelUpLearnset = sMewtwoLevelUpLearnset, + .teachableLearnset = sMewtwoTeachableLearnset, + .formSpeciesIdTable = sMewtwoFormSpeciesIdTable, + .formChangeTable = sMewtwoFormChangeTable, ++ .evolutions = EVOLUTION({EVO_LEVEL, 100, SPECIES_MEWTHREE}), + }, + }; +``` + +## 4. Make it appear! +Now Mewthree really does slumber in the games code - but we won't know until we make him appear somewhere! The legend tells that Mewthree is hiding somewhere in Petalburg Woods... + +Edit [src/data/wild_encounters.json](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/wild_encounters.json): + +```diff + { + "map": "MAP_PETALBURG_WOODS", + "base_label": "gPetalburgWoods", + "land_mons": { + "encounter_rate": 20, + "mons": [ + { + "min_level": 5, + "max_level": 5, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 5, + "max_level": 5, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 5, + "max_level": 5, + "species": "SPECIES_SHROOMISH" + }, + { +- "min_level": 6, +- "max_level": 6, +- "species": "SPECIES_POOCHYENA" ++ "min_level": 5, ++ "max_level": 5, ++ "species": "SPECIES_MEWTHREE" + }, + ... + } +``` + +Congratulations, you have created your own personal pocket monster! You may call yourself a mad scientist now. + +# Optional data + +Now that you now have all the essential pieces to create a base species, there are some aspects that you might want to know if you want to do other stuff with your custom Pokémon. + +## 1. Form tables +Found in `src/data/pokemon/form_species_tables.h`. + +These are introduced to have a reference of what forms correspond to what Species of Pokémon. For example, we have Pikachu's table: +```c +#if P_FAMILY_PIKACHU +static const u16 sPikachuFormSpeciesIdTable[] = { + SPECIES_PIKACHU, + SPECIES_PIKACHU_COSPLAY, + SPECIES_PIKACHU_ROCK_STAR, + SPECIES_PIKACHU_BELLE, + SPECIES_PIKACHU_POP_STAR, + SPECIES_PIKACHU_PH_D, + SPECIES_PIKACHU_LIBRE, + SPECIES_PIKACHU_ORIGINAL_CAP, + SPECIES_PIKACHU_HOENN_CAP, + SPECIES_PIKACHU_SINNOH_CAP, + SPECIES_PIKACHU_UNOVA_CAP, + SPECIES_PIKACHU_KALOS_CAP, + SPECIES_PIKACHU_ALOLA_CAP, + SPECIES_PIKACHU_PARTNER_CAP, + SPECIES_PIKACHU_WORLD_CAP, + FORM_SPECIES_END, +}; +#endif //P_FAMILY_PIKACHU +``` +We register the table each form entry in `gSpeciesInfo`. + +```diff + [SPECIES_PIKACHU] = + { + ... + .teachableLearnset = sPikachuTeachableLearnset, ++ .formSpeciesIdTable = sPikachuFormSpeciesIdTable, + .evolutions = EVOLUTION({EVO_ITEM, ITEM_THUNDER_STONE, SPECIES_RAICHU}, + {EVO_NONE, 0, SPECIES_RAICHU_ALOLAN}), + }, + + [SPECIES_PIKACHU_COSPLAY] = + { + ... + .teachableLearnset = sPikachuTeachableLearnset, ++ .formSpeciesIdTable = sPikachuFormSpeciesIdTable, + }, +``` +...and so on. + +What this allows us to do is to be able to get all forms of a Pokémon in our code by using the `GetSpeciesFormTable` function. + +For example, in the HGSS dex, it lets us browse between the entries of every form available.: + +![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/a1a90b79-46a1-4cd6-97d6-ec5d741bfdc8) ![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/7cffc6be-0b5c-4074-b689-736a97297843) + +In addition, we have the `GET_BASE_SPECIES_ID` macro, which returns the first entry of the table (or return the species itself if it doesn't have a table registered). With this, you can check if a Pokémon is any form of a species. For example, making it so that the Light Ball affects all Pikachu forms: +```c + case HOLD_EFFECT_LIGHT_BALL: + if (GET_BASE_SPECIES_ID(gBattleMons[battlerAtk].species) == SPECIES_PIKACHU && IS_MOVE_SPECIAL(move)) + modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0)); + break; +``` + +## 2. Form change tables +Found in `src/data/pokemon/form_species_tables.h`. + +These tables, unlike the regular form tables, registers how Pokémon can switch between forms. + +```c +#if P_FAMILY_GASTLY +static const struct FormChange sGengarFormChangeTable[] = { + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_GENGAR_MEGA, ITEM_GENGARITE}, + {FORM_CHANGE_BATTLE_GIGANTAMAX, SPECIES_GENGAR_GIGANTAMAX}, + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_GASTLY +``` +The first value is the type of form change. In the case of Gengar, we have both Mega Evolution and Gigantamax form changes. + +The second value is the target form, to which the Pokémon will change into. + +Values after that are referred as arguments, and needs to be put there depends on the type of form change, detailed in `include/constants/form_change_types.h`. + +## 3. Gender differences +![mGBA_Wq5cbDkNZG](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/45256192-b451-4baa-af06-f57ca16e1e46) + +You may have seen that there's a couple of duplicate fields with a "Female" suffix. +```diff + [SPECIES_FRILLISH] = + { + ... + .frontPic = gMonFrontPic_Frillish, ++ .frontPicFemale = gMonFrontPic_FrillishF, + .frontPicSize = MON_COORDS_SIZE(56, 56), ++ .frontPicSizeFemale = MON_COORDS_SIZE(56, 56), + .frontPicYOffset = 5, + .frontAnimFrames = sAnims_Frillish, + .frontAnimId = ANIM_RISING_WOBBLE, + .backPic = gMonBackPic_Frillish, ++ .backPicFemale = gMonBackPic_FrillishF, + .backPicSize = MON_COORDS_SIZE(40, 56), ++ .backPicSizeFemale = MON_COORDS_SIZE(40, 56), + .backPicYOffset = 7, + .backAnimId = BACK_ANIM_CONVEX_DOUBLE_ARC, + .palette = gMonPalette_Frillish, ++ .paletteFemale = gMonPalette_FrillishF, + .shinyPalette = gMonShinyPalette_Frillish, ++ .shinyPaletteFemale = gMonShinyPalette_FrillishF, + .iconSprite = gMonIcon_Frillish, ++ .iconSpriteFemale = gMonIcon_FrillishF, + .iconPalIndex = 0, ++ .iconPalIndexFemale = 1, + FOOTPRINT(Frillish) + .levelUpLearnset = sFrillishLevelUpLearnset, + .teachableLearnset = sFrillishTeachableLearnset, + .evolutions = EVOLUTION({EVO_LEVEL, 40, SPECIES_JELLICENT}), + }, +``` +These are used to change the graphics of the Pokémon if they're female. If they're not registered, they default to the male values. + +However, `iconPalIndexFemale` is a special case, where it's *doesn't* read the male icon palette if its `iconSpriteFemale` is set, so if you're setting a female icon, be sure to set their palette index as well. + +## 4. Overworld Data +![mGBA_4iqvhhSltK](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/e59238dc-9779-4f26-a9e7-159a32caa3d9) + +If you have `OW_POKEMON_OBJECT_EVENTS` in your hack, you can add Overworld of your new species by following these steps: + +First, since you copied the contents from Mew's folder previously, you should also have copied its overworld sprites. Edit those to your liking, as we have done before, making sure to update the palettes + +Secondly, in [src/data/graphics/pokemon.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/graphics/pokemon.h), add the following: + +```diff + const u8 gMonIcon_Mewthree[] = INCBIN_U8("graphics/pokemon/mewthree/icon.4bpp"); + const u8 gMonFootprint_Mewthree[] = INCBIN_U8("graphics/pokemon/mewthree/footprint.1bpp"); ++ const u32 gObjectEventPic_Mewthree[] = INCBIN_COMP("graphics/pokemon/mewthree/overworld.4bpp"); ++ const u32 gOverworldPalette_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/overworld_normal.gbapal.lz"); ++ const u32 gShinyOverworldPalette_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/overworld_shiny.gbapal.lz"); +``` + +Thirdly, in [spritesheet_rules.mk](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/spritesheet_rules.mk) + +```diff +$(POKEMONGFXDIR)/mewtwo/overworld.4bpp: %.4bpp: %.png + $(GFX) $< $@ -mwidth 4 -mheight 4 + ++$(POKEMONGFXDIR)/mewthree/overworld.4bpp: %.4bpp: %.png ++ $(GFX) $< $@ -mwidth 4 -mheight 4 + +$(POKEMONGFXDIR)/mew/overworld.4bpp: %.4bpp: %.png + $(GFX) $< $@ -mwidth 4 -mheight 4 +``` + +Fourthly, in [src/data/object_events/object_event_pic_tables_followers.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/object_events/object_event_pic_tables_followers.h): +```diff +#if P_FAMILY_PECHARUNT +/*static const struct SpriteFrameImage sPicTable_Pecharunt[] = { + overworld_ascending_frames(gObjectEventPic_Pecharunt, 4, 4), +};*/ +#endif //P_FAMILY_PECHARUNT + ++static const struct SpriteFrameImage sPicTable_Mewthree[] = { ++ overworld_ascending_frames(gObjectEventPic_Mewthree, 4, 4), ++}; +``` + +And finally, in `gSpeciesInfo`: + +```diff + const struct SpeciesInfo gSpeciesInfo[] = + { + ... + [SPECIES_MEWTHREE] = + { + ... + FOOTPRINT(Mewthree) ++ OVERWORLD( ++ sPicTable_Mewthree, ++ SIZE_32x32, ++ SHADOW_SIZE_M, ++ TRACKS_FOOT, ++ gOverworldPalette_Mewthree, ++ gShinyOverworldPalette_Mewthree ++ ) + .levelUpLearnset = sMewthreeLevelUpLearnset, + .teachableLearnset = sMewthreeTeachableLearnset, + }, + }; +``` + +### Sprite Size +Depending on your species, you might want to use different sizes for it. For example, certain species known for being big like Steelix use sprites that fit a 64x64 frame instead of 32x32, and as such have `SIZE_64x64` in their data instead of `SIZE_32x32` to accomodate for them. + +Also, in `spritesheet_rules.mk`, `-mwidth` and `-mheight` need to be set to 8 instead of 4 for such cases. + +### Shadows +You have 4 options for their shadow, between Small, Medium, Large and None: + - `SHADOW_SIZE_NONE` + - `SHADOW_SIZE_S` ![shadow_small](https://github.com/user-attachments/assets/c964712e-f5cb-42e8-82fa-db33fc4f4d4c) + - `SHADOW_SIZE_M` ![shadow_medium](https://github.com/user-attachments/assets/b7792624-d65c-425b-9982-cab28ce4248e) + - `SHADOW_SIZE_L` ![shadow_large](https://github.com/user-attachments/assets/ec2dc701-d335-44ad-8ded-f8003114f0ff) + +### Tracks +You have 4 options for the tracks that your species will leave behind on sand. + - `TRACKS_NONE` + - `TRACKS_FOOT` ![sand_footprints](https://github.com/user-attachments/assets/8b8c34d6-72e9-4b9d-839d-0a5cc1ae1a4c) + - `TRACKS_SLITHER` ![slither_tracks](https://github.com/user-attachments/assets/28219c05-61e0-48b3-9aeb-43f48e4ffdd4) + - `TRACKS_SPOT` ![spot_tracks](https://github.com/user-attachments/assets/f7a24887-c5ca-47f2-8825-01f3df61deca) + - `TRACKS_BUG` ![bug_tracks](https://github.com/user-attachments/assets/8cd1dea4-4123-4af8-a558-992874a6d589) + + ...though technically you can also use `TRACKS_BIKE_TIRE` if you wish to. + +![bike_tire_tracks](https://github.com/user-attachments/assets/ac81d211-85e5-443a-ac54-c2976f1f0b82) diff --git a/docs/how_to_testing_system.md b/docs/how_to_testing_system.md new file mode 100644 index 0000000000..793465114c --- /dev/null +++ b/docs/how_to_testing_system.md @@ -0,0 +1,578 @@ +# How to use the Testing System + +## Running Tests +To run all the tests use: +`make check -j` +To run specific tests, e.g. Spikes ones, use: +`make check TESTS='Spikes'` +To build a ROM (pokemerald-test.elf) that can be opened in mgba to view specific tests, e.g. Spikes ones, use: +`make pokeemerald-test.elf TESTS='Spikes'` + +## How to Write Tests +Manually testing a battle mechanic often follows this pattern: +1. Create a party which can activate the mechanic. +2. Start a battle and play a few turns which activate the mechanic. +3. Look at the UI outputs to decide if the mechanic works. + +Automated testing follows the same pattern: +1. Initialize the party in `GIVEN`. +2. Play the turns in `WHEN`. +3. Check the UI outputs in `SCENE`. + +### Example 1 +As a concrete example, to manually test `EFFECT_PARALYZE`, e.g. the +effect of Stun Spore you might: +1. Put a Wobbuffet that knows Stun Spore in your party. +2. Battle a wild Wobbuffet. +3. Use Stun Spore. +4. Check that the Wobbuffet is paralyzed. + +This can be translated to an automated test as follows: + +``` +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_STUN_SPORE].effect == EFFECT_PARALYZE); +} + +SINGLE_BATTLE_TEST("Stun Spore inflicts paralysis") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); // 1. + OPPONENT(SPECIES_WOBBUFFET); // 2. + } WHEN { + TURN { MOVE(player, MOVE_STUN_SPORE); } // 3. + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player); + MESSAGE("Foe Wobbuffet is paralyzed! It may be unable to move!"); // 4 + STATUS_ICON(opponent, paralysis: TRUE); // 4. + } +} +``` + +The `ASSUMPTIONS` block documents that Stun Spore has `EFFECT_PARALYZE`. +If Stun Spore did not have that effect it would cause the tests in the file to be skipped. We write our tests like this so that hackers can change the effects of moves without causing tests to fail. + +`SINGLE_BATTLE_TEST` defines the name of the test. Related tests should start with the same prefix, e.g. Stun Spore tests should start with "Stun Spore", this allows just the Stun Spore-related tests to be run with: +`make check TESTS='Stun Spore'` + +`GIVEN` initializes the parties, `PLAYER` and `OPPONENT` add a Pokémon to their respective parties. They can both accept a block which further customizes the Pokémon's stats, moves, item, ability, etc. + +`WHEN` describes the turns, and `TURN` describes the choices made in a single turn. `MOVE` causes the player to use Stun Spore and adds the move to the Pokémon's moveset if an explicit Moves was not specified. +Pokémon that are not mentioned in a `TURN` use Celebrate. +The test runner rigs the RNG so that unless otherwise specified, moves always hit, never critical hit, always activate their secondary effects, and always roll the same damage modifier. + +`SCENE` describes the player-visible output of the battle. In this case `ANIMATION` checks that the Stun Spore animation played, `MESSAGE` checks the paralysis message was shown, and `STATUS_ICON` checks that the opponent's HP bar shows a PRZ icon. + +### Example 2 +As a second example, to manually test that Stun Spore does not effect Grass-types you might: +1. Put a Wobbuffet that knows Stun Spore in your party. +2. Battle a wild Oddish. +3. Use Stun Spore. +4. Check that the move animation does not play. +5. Check that a "It doesn't affect Foe Oddish…" message is shown. + +This can again be translated as follows: + +``` +SINGLE_BATTLE_TEST("Stun Spore does not affect Grass-types") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_STUN_SPORE].powderMove); + ASSUME(gSpeciesInfo[SPECIES_ODDISH].types[0] == TYPE_GRASS); + PLAYER(SPECIES_ODDISH); // 1. + OPPONENT(SPECIES_ODDISH); // 2. + } WHEN { + TURN { MOVE(player, MOVE_STUN_SPORE); } // 3. + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player); // 4. + MESSAGE("It doesn't affect Foe Oddish…"); // 5. + } +} +``` +The `ASSUME` commands are documenting the reasons why Stun Spore does not affect Oddish, namely that Stun Spore is a powder move, and Oddish is a Grass-type. These `ASSUME` statements function similarly to the ones in `ASSUMPTIONS` but apply only to the one test. +NOT inverts the meaning of a `SCENE` check, so applying it to `ANIMATION` requires that the Stun Spore animation does not play. `MESSAGE` checks that the message was shown. +The checks in `SCENE` are ordered, so together this says "The doesn't affect message is shown, and the Stun Spore animation does not play at any time before that". Normally you would only test one or the other, or even better, just `NOT STATUS_ICON(opponent, paralysis: TRUE);` to say that Oddish was not paralyzed without specifying the exact outputs which led to that. + +### Example 3 +As a final example, to test that Meditate works you might: +1. Put a Wobbuffet that knows Meditate and Tackle in your party. +2. Battle a wild Wobbuffet. +3. Use Tackle and note the amount the HP bar reduced. +4. Battle a wild Wobbuffet. +5. Use Meditate and that the stat change animation and message play. +6. Use Tackle and check that the HP bar reduced by more than in 3. + +This can be translated to an automated test as follows: +``` +SINGLE_BATTLE_TEST("Meditate raises Attack", s16 damage) +{ + bool32 raiseAttack; + PARAMETRIZE { raiseAttack = FALSE; } + PARAMETRIZE { raiseAttack = TRUE; } + GIVEN { + ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (raiseAttack) TURN { MOVE(player, MOVE_MEDITATE); } // 5. + TURN { MOVE(player, MOVE_TACKLE); } // 3 & 6. + } SCENE { + if (raiseAttack) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MEDITATE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); // 5. + MESSAGE("Wobbuffet's attack rose!"); // 5. + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + HP_BAR(opponent, captureDamage: &results[i].damage); // 3 & 6. + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); // 6. + } +} +``` + +`PARAMETRIZE` causes a test to run multiple times, once per `PARAMETRIZE` block (e.g. once with `raiseAttack = FALSE` and once with `raiseAttack = TRUE`). +The `HP_BAR` command's `captureDamage` causes the change in HP to be stored in a variable, and the variable chosen is `results[i].damage`. +`results[i]` contains all the variables defined at the end of `SINGLE_BATTLE_TEST`, `i` is the current `PARAMETRIZE` index. +`FINALLY` runs after the last parameter has finished, and uses `EXPECT_MUL_EQ` to check that the second battle deals 1.5× the damage of the first battle (with a small tolerance to account for rounding). + +You might notice that all the tests check the outputs the player could see rather than the internal battle state. e.g. the Meditate test could have used `gBattleMons[B_POSITION_OPPONENT_LEFT].hp` instead of using `HP_BAR` to capture the damage. This is a deliberate choice, by checking what the player can observe the tests are more robust to refactoring, e.g. if `gBattleMons` got moved into `gBattleStruct` then any test that used it would need to be updated. + +### Note on Overworld Tests +The overworld is not available, so it is only possible to test commands which don't affect the overworld itself, e.g. `givemon` can be tested because it only alters `gPlayerParty`, but `addobject` cannot because it affects object events (which aren't loaded). + +## REFERENCE + +### `ASSUME` +`ASSUME(cond)` +Causes the test to be skipped if `cond` is false. Used to document any prerequisites of the test, e.g. to test Burn reducing the Attack of a Pokémon we can observe the damage of a physical attack with and without the burn. To document that this test assumes the attack is physical we can use: +`ASSUME(gMovesInfo[MOVE_WHATEVER].category == DAMAGE_CATEGORY_PHYSICAL);` + +### `ASSUMPTIONS` +``` +ASSUMPTIONS +{ + ... +} +``` +Should be placed immediately after any `#includes` and contain any `ASSUME` statements which should apply to the whole file, e.g. to test `EFFECT_POISON_HIT` we need to choose a move with that effect, if we chose to use Poison Sting in every test then the top of `move_effect_poison_hit.c` should be: +``` +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_POISON_STING].effect == EFFECT_POISON_HIT); +} +``` + +### `SINGLE_BATTLE_TEST` +`SINGLE_BATTLE_TEST(name, results...)` and `DOUBLE_BATTLE_TEST(name, results...)` +Define single- and double- battles. The names should start with the name of the mechanic being tested so that it is easier to run all the related tests. `results` contains variable declarations to be placed into the `results` array which is available in tests using `PARAMETRIZE` commands. +The main differences for doubles are: + - Move targets sometimes need to be explicit. + - Instead of `player` and `opponent` there is `playerLeft`, `playerRight`, `opponentLeft`, and `opponentRight`. + +### `AI_SINGLE_BATTLE_TEST` +`AI_SINGLE_BATTLE_TEST(name, results...)` and `AI_DOUBLE_BATTLE_TEST(name, results...)` +Define battles where opponent mons are controlled by AI, the same that runs +when battling regular Trainers. The flags for AI should be specified by the `AI_FLAGS` command. +The rules remain the same as with the `SINGLE` and `DOUBLE` battle tests with some differences: + - opponent's action is specified by the `EXPECT_MOVE` / `EXPECT_SEND_OUT` / `EXPECT_SWITCH` commands + - we don't control what opponent actually does, instead we make sure the opponent does what we expect it to do + - we still control the player's action the same way + - apart from the `EXPECTED` commands, there's also a new `SCORE_` and `SCORE__VAL` commands + +### `KNOWN_FAILING` +`KNOWN_FAILING;` +Marks a test as not passing due to a bug. If there is an issue number associated with the bug it should be included in a comment. If the test passes the developer will be notified to remove `KNOWN_FAILING`. +For example: +``` +SINGLE_BATTLE_TEST("Jump Kick has no recoil if no target") +{ + KNOWN_FAILING; // #2596. + ... +} +``` +### `PARAMETRIZE` +`PARAMETERIZE { parameter; }` +Runs a test multiple times. `i` will be set to which parameter is running, and `results` will contain an entry for each parameter, e.g.: +``` +SINGLE_BATTLE_TEST("Blaze boosts Fire-type moves in a pinch", s16 damage) +{ + u16 hp; + PARAMETRIZE { hp = 99; } + PARAMETRIZE { hp = 33; } + GIVEN { + ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); + PLAYER(SPECIES_CHARMANDER) { Ability(ABILITY_BLAZE); MaxHP(99); HP(hp); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_EMBER); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT(results[1].damage > results[0].damage); + } +} +``` +### `PASSES_RANDOMLY` +`PASSES_RANDOMLY(successes, trials, [tag])` +Checks that the test passes successes/trials. If `tag` is provided, the test is run for each value that the tag can produce. For example, to check that Paralysis causes the turn to be skipped 25/100 times, we can write the following test that passes only if the Pokémon is fully paralyzed and specify that we expect it to pass 25/100 times when `RNG_PARALYSIS` varies: +``` +SINGLE_BATTLE_TEST("Paralysis has a 25% chance of skipping the turn") +{ + PASSES_RANDOMLY(25, 100, RNG_PARALYSIS); + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_PARALYSIS); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); } + } SCENE { + MESSAGE("Wobbuffet is paralyzed! It can't move!"); + } +} +``` +All `BattleRandom` calls involving tag will return the same number, so this cannot be used to have two moves independently hit or miss, for example. + +If the tag is not provided, runs the test 50 times and computes an approximate pass ratio. +`PASSES_RANDOMLY(gMovesInfo[move].accuracy, 100);` +Note that this mode of PASSES_RANDOMLY makes the tests run very slowly and should be avoided where possible. If the mechanic you are testing is missing its tag, you should add it. + +### `GIVEN` +``` +Given { + ... +} +``` +Contains the initial state of the parties before the battle. + +## `RNGSeed` +`RNGSeed(seed)` +Explicitly sets the RNG seed. Try to avoid using this because it is a very fragile tool. +Example: +``` +GIVEN { + RNGSeed(0xC0DEIDEA); + ... +} +``` + +### `FLAG_SET` +`FLAG_SET(flagId)` +Sets the specified flag. Can currently only set one flag at a time. +Cleared between parameters and at the end of the test. +Example: +``` +GIVEN { + FLAG_SET(FLAG_SYS_EXAMPLE_FLAG); + ... +} +``` + +### `PLAYER` and `OPPONENT` +`PLAYER(species)` and `OPPONENT(species` +Adds the species to the player's or opponent's party respectively. +The Pokémon can be further customized with the following functions: + - `Gender(MON_MALE | MON_FEMALE)` + - `Nature(nature)` + - `Ability(ability)` + - `Level(level)` + - `MaxHP(n)`, `HP(n)`, `Attack(n)`, `Defense(n)`, `SpAttack(n)`, `SpDefense(n)`, `Speed(n)` + - `Item(item)` + - `Moves(moves...)` + - `Friendship(friendship)` + - `Status1(status1)` +For example to create a level 42 Wobbuffet that is poisoned: +`PLAYER(SPECIES_WOBBUFFET) { Level(42); Status1(STATUS1_POISON); }` +**Note if Speed is specified for any Pokémon then it must be specified for all Pokémon.** +**Note if Moves is specified then MOVE will not automatically add moves to the moveset.** + +### `AI_FLAGS` +`AI_FLAGS(flags)` +Specifies which AI flags are run during the test. Has use only for AI tests. +The most common combination is `AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT)` which is the general 'smart' AI. + +### `WHEN` +``` + ... +} WHEN { + ... +} +``` +Contains the choices that battlers make during the battle. + +### `TURN` +`TURN { ... }` +Groups the choices made by the battlers on a single turn. If Speeds have not been explicitly specified then the order of the `MOVE` commands in the `TURN` will be used to infer the Speeds of the Pokémon, e.g.: +``` + // player's speed will be greater than opponent's speed. + TURN { MOVE(player, MOVE_SPLASH); MOVE(opponent, MOVE_SPLASH); } + // opponent's speed will be greater than player's speed. + TURN { MOVE(opponent, MOVE_SPLASH); MOVE(player, MOVE_SPLASH); } +``` +The inference process is naive, if your test contains anything that modifies the speed of a battler you should specify them explicitly. + +### `MOVE` +`MOVE(battler, move | moveSlot:, [megaEvolve:], [hit:], [criticalHit:], [target:], [allowed:], [WITH_RNG(tag, value])` +Used when the battler chooses Fight. Either the move ID (e.g. `MOVE_TACKLE` or move slot must be specified. + - `megaEvolve: TRUE` causes the battler to Mega Evolve if able + - `hit: FALSE` causes the move to miss + - `criticalHit: TRUE` causes the move to land a critical hit + - `target:` is used in double battles to choose the target (when necessary) + - `allowed: FALSE` is used to reject an illegal move e.g. a Disabled one + - `WITH_RNG` allows the move to specify an explicit outcome for an RNG tag +``` + MOVE(playerLeft, MOVE_TACKLE, target: opponentRight); +``` +If the battler does not have an explicit Moves specified the moveset will be populated based on the `MOVE`s it uses. + +### `FORCED_MOVE` +`FORCED_MOVE(battler)` +Used when the battler chooses Fight and then their move is chosen for them, e.g. when affected by Encore. +``` + FORCED_MOVE(player); +``` + +### `SWITCH` +`SWITCH(battler, partyIndex)` +Used when the battler chooses Switch. +``` + SWITCH(player, 1); +``` + +### `SKIP_TURN` +`SKIP_TURN(battler)` +Used when the battler cannot choose an action, e.g. when locked into Thrash. +``` + SKIP_TURN(player); +``` + +### `SEND_OUT` +`SEND_OUT(battler, partyIndex)` +Used when the battler chooses to switch to another Pokémon but not via Switch, e.g. after fainting or due to a U-turn. +``` + SEND_OUT(player, 1); +``` + +### `USE_ITEM` +`USE_ITEM(battler, itemId, [partyIndex:], [move:])` +Used when the battler chooses to use an item from the Bag. The item ID (e.g. ITEM_POTION) must be specified, and party index and move slot if applicable, e.g: +``` + USE_ITEM(player, ITEM_X_ATTACK); + USE_ITEM(player, ITEM_POTION, partyIndex: 0); + USE_ITEM(player, ITEM_LEPPA_BERRY, partyIndex: 0, move: MOVE_TACKLE); +``` + +### `SCENE` +``` + ... +} SCENE { + ... +} +``` +Contains an abridged description of the UI during the `THEN`. The order of the description must match too, e.g. +``` +} SCENE { + // ABILITY_POPUP followed by a MESSAGE + ABILITY_POPUP(player, ABILITY_STURDY); + MESSAGE("Geodude was protected by Sturdy!"); +} +``` + +### `ABILITY_POPUP` +`ABILITY_POPUP(battler, [ability])` +Causes the test to fail if the battler's ability pop-up is not shown. +If specified, ability is the ability shown in the pop-up. +``` + ABILITY_POPUP(opponent, ABILITY_MOLD_BREAKER); +``` + +### `ANIMATION` +`ANIMATION(type, animId, [battler], [target:])` +Causes the test to fail if the animation does not play. A common use of this command is to check if a move was successful, e.g.: +``` + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); +``` +`target` can only be specified for `ANIM_TYPE_MOVE`. + +### `EXPERIENCE_BAR` +`EXPERIENCE_BAR(battler, [exp: | captureGainedExp:])` +If `exp:` is used, causes the test to fail if that amount of experience is not gained, e.g.: +``` + EXPERIENCE_BAR(player, exp: 0); +``` +If `captureGainedExp:` is used, causes the test to fail if the Experience bar does not change, and then writes that change to the pointer, e.g.: +``` + u32 exp; + EXPERIENCE_BAR(player, captureGainedExp: &exp); +``` +If none of the above are used, causes the test to fail if the Exp does not change at all. +**Please note that due to nature of tests, this command is only usable in `WILD_BATTLE_TEST` and will fail elsewhere.** + +### `HP_BAR` +`HP_BAR(battler, [damage: | hp: | captureDamage: | captureHP:])` +If `hp:` or `damage:` are used, causes the test to fail if that amount of damage is not dealt, e.g.: +``` + HP_BAR(player, hp: 0); +``` +If `captureDamage:` or `captureHP:` are used, causes the test to fail if the HP bar does not change, and then writes that change to the + pointer, e.g.: +``` + s16 damage; + HP_BAR(player, captureDamage: &damage); +``` +If none of the above are used, causes the test to fail if the HP does not change at all. + +### MESSAGE +`MESSAGE(pattern)` +Causes the test to fail if the message in pattern is not displayed. +Spaces in pattern match newlines (\n, \l, and \p) in the message. +Often used to check that a battler took its turn but it failed, e.g.: +``` + MESSAGE("Wobbuffet used Dream Eater!"); + MESSAGE("Foe Wobbuffet wasn't affected!"); +``` + +### `STATUS_ICON` +`STATUS_ICON(battler, status1 | none: | sleep: | poison: | burn: | freeze: | paralysis:, badPoison:)` +Causes the test to fail if the battler's status is not changed to the specified status. +``` + STATUS_ICON(player, badPoison: TRUE); +``` +If the expected status icon is parametrized the corresponding `STATUS1` constant can be provided, e.g.: +``` + u32 status1; + PARAMETRIZE { status1 = STATUS1_NONE; } + PARAMETRIZE { status1 = STATUS1_BURN; } + ... + STATUS_ICON(player, status1); +``` + +### `NOT` +`NOT sceneCommand` +Causes the test to fail if the `SCENE` command succeeds before the following command succeeds. +``` + // Our Wobbuffet does not Celebrate before the foe's. + NOT MESSAGE("Wobbuffet used Celebrate!"); + MESSAGE("Foe Wobbuffet used Celebrate!"); +``` +**NOTE**: If this condition fails, the viewable ROM freezes at the NOT command. +**WARNING: `NOT` is an alias of `NONE_OF`, so it behaves surprisingly when applied to multiple commands wrapped in braces.** + +### `ONE_OF` +``` + ONE_OF { + ... + } +``` +Causes the test to fail unless one of the `SCENE` commands succeeds. +``` + ONE_OF { + MESSAGE("Wobbuffet used Celebrate!"); + MESSAGE("Wobbuffet is paralyzed! It can't move!"); + } +``` + +### `NONE_OF` +``` + NONE_OF { + ... + } +``` +Causes the test to fail if one of the `SCENE` commands succeeds before the command after the `NONE_OF` succeeds. +``` + // Our Wobbuffet does not move before the foe's. + NONE_OF { + MESSAGE("Wobbuffet used Celebrate!"); + MESSAGE("Wobbuffet is paralyzed! It can't move!"); + } + MESSAGE("Foe Wobbuffet used Celebrate!"); +``` + +### `PLAYER_PARTY` +Refer to the party members defined in `GIVEN`, e.g.: +``` + s32 maxHP = GetMonData(&PLAYER_PARTY[0], MON_DATA_MAX_HP); + HP_BAR(player, damage: maxHP / 2); +``` +### `OPPONENT_PARTY` +Refer to the party members defined in `GIVEN`, e.g.: +``` + s32 maxHP = GetMonData(&OPPONENT_PARTY[0], MON_DATA_MAX_HP); + HP_BAR(opponent, damage: maxHP / 2); +``` + +### `THEN` +``` + ... +} THEN { + ... +} +``` +Contains code to run after the battle has finished. If the test is using `PARAMETRIZE` commands then `EXPECT` commands between the results should go here. Is also occasionally used to check the internal battle state when checking the behavior via a `SCENE` is too difficult, verbose, or error-prone. + +### `FINALLY` +``` + ... +} FINALLY { + ... +} +``` +Contains checks to run after all `PARAMETERIZE` commands have run. Prefer to write your checks in `THEN` where possible, because a failure in `THEN` will be tagged with which parameter it corresponds to. + +### `EXPECT` +`EXPECT(cond)` +Causes the test to fail if `cond` is false. + +### `EXPECT_XX` +`EXPECT_EQ(a, b)` +`a == b` + +`EXPECT_NE(a, b)` +`a != b` + +`EXPECT_LT(a, b)` +`a < b` + +`EXPECT_LE(a, b)` +`a <= b` + +`EXPECT_GT(a, b)` +`a > b` + +`EXPECT_GE(a, b)` +`a >= b` + +Causes the test to fail if a and b compare incorrectly, e.g. +``` + EXPECT_EQ(results[0].damage, results[1].damage); +``` + +### `EXPECT_MUL_EQ` +`EXPECT_MUL_EQ(a, m, b)` + Causes the test to fail if `a*m != b` (within a threshold), e.g. +``` + // Expect results[0].damage * 1.5 == results[1].damage. + EXPECT_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); +``` + +## Overworld Command Reference + +### `OVERWORLD_SCRIPT` +`OVERWORLD_SCRIPT(instructions...)` +Returns a pointer to a compiled overworld script. Cannot be used to initialize global `const` data, although the pointer **IS** to `const` data. +Note that each script command must be followed by a ;, e.g.: +``` +const u8 *myScript = OVERWORLD_SCRIPT( + random 2; + addvar VAR_RESULT, 1; +); +``` + +### `RUN_OVERWORLD_SCRIPT` +`RUN_OVERWORLD_SCRIPT(instructions...)` +Runs an overworld script in the immediate script context, which means that commands like `waitstate` are not supported. +``` + RUN_OVERWORLD_SCRIPT( + setvar VAR_RESULT, 3; + ); + EXPECT_EQ(GetVar(VAR_RESULT), 3); +``` diff --git a/docs/how_to_trainer_class.md b/docs/how_to_trainer_class.md new file mode 100644 index 0000000000..a47cbe19c5 --- /dev/null +++ b/docs/how_to_trainer_class.md @@ -0,0 +1,178 @@ +# How to add a new trainer class + +## Content +* [Quick Summary](#quick-summary) +* [The Graphics](#the-graphics) + * [1. Edit the sprites](#2-edit-the-sprites) + * [2. Register the sprites](#2-register-the-sprites) + * [3. The Animation](#2-the-animation) + * [4. Connecting pictures to the data](#2-connecting-pictures-to-the-data) +* [The Data](#the-data) + * [5. Defining the trainer class](#2-defining-the-trainer-class) +* [Usage](#usage) + +## Quick Summary +(Page contains out of date information, [new instructions for Sprites here](https://github.com/rh-hideout/pokeemerald-expansion/pull/3597).) +If you've done this before and just need a quick lookup, here's what files you need: +1. GFX into [graphics/trainers/front_pics](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/graphics/trainers/front_pics) +2. Palette into [graphics/trainers/palettes](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/graphics/trainers/palettes) +3. Register sprites to [include/graphics.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/graphics.h) +4. Point game to where graphic files are found: [src/data/graphics/trainers](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/graphics/trainers.h) +5. Add animation to: [src/data/trainer_graphics/front_pic_anims.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/trainer_graphics/front_pic_anims.h) +6. Add the trainer to all three structs in: [src/data/trainer_graphics/front_pic_table.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/trainer_graphics/front_pic_table.h) +7. Add trainer to [include/constants/trainers.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/trainers.h) + +## The Graphics + +### 1. Edit the sprites +We will start with a graphic that we want to use for our new trainer class. Unlike with adding Pokémon, the trainer sprites aren't sorted in individual folders, but rather in one folder: +[graphics/trainers/front_pics](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/graphics/trainers/front_pics) + +**Remember to limit yourself to 16 colors including transparency in the first slot!** + +Export the pallette and place into the same folder. + +### 2. Register the sprites +Sadly, just putting the image files into the graphics folder is not enough. To use the sprites we have to register them, which is kind of tedious. First, create constants for the file paths. +Edit [include/graphics.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/graphics.h): +```diff +extern const u32 gTrainerFrontPic_RubySapphireMay[]; ++ extern const u32 gTrainerFrontPic_myTrainerClass[]; + +extern const u32 gTrainerPalette_Hiker[]; +... + +... +extern const u32 gTrainerPalette_RubySapphireMay[]; ++ extern const u32 gTrainerPalette_myTrainerClass[]; + +extern const u8 gTrainerBackPic_Brendan[]; +``` + +Now link the graphic files. +[src/data/graphics/trainers](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/graphics/trainers.h): +```diff +const u32 gTrainerPalette_RubySapphireBrendan[] = INCBIN_U32("graphics/trainers/palettes/ruby_sapphire_brendan.gbapal.lz"); + +const u32 gTrainerFrontPic_RubySapphireMay[] = INCBIN_U32("graphics/trainers/front_pics/ruby_sapphire_may_front_pic.4bpp.lz"); +const u32 gTrainerPalette_RubySapphireMay[] = INCBIN_U32("graphics/trainers/palettes/ruby_sapphire_may.gbapal.lz"); + ++ const u32 gTrainerFrontPic_Sheriff[] = INCBIN_U32("graphics/trainers/front_pics/myTrainerClass_front_pic.4bpp.lz"); ++ const u32 gTrainerPalette_Sheriff[] = INCBIN_U32("graphics/trainers/palettes/myTrainerClass.gbapal.lz"); + +const u8 gTrainerBackPic_Brendan[] = INCBIN_U8("graphics/trainers/back_pics/brendan_back_pic.4 +``` + +### 3. The Animation +Add the Animation of the trainer here: +[src/data/trainer_graphics/front_pic_anims.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/trainer_graphics/front_pic_anims.h) + +The trainers don't really move, but in theory they could, it's just that the animation defined for each trainer just shows one frame: + +```diff +static const union AnimCmd *const sAnims_RubySapphireMay[] ={ + sAnim_GeneralFrame0, +}; + ++ static const union AnimCmd *const sAnims_MyTrainerClass[] ={ ++ sAnim_GeneralFrame0, ++ }; + +const union AnimCmd *const *const gTrainerFrontAnimsPtrTable[] = +{ + [TRAINER_PIC_HIKER] = sAnims_Hiker, + [TRAINER_PIC_AQUA_GRUNT_M] = sAnims_AquaGruntM, + [TRAINER_PIC_POKEMON_BREEDER_F] = sAnims_PokemonBreederF, +... + +... + [TRAINER_PIC_RS_BRENDAN] = sAnims_RubySapphireBrendan, + [TRAINER_PIC_RS_MAY] = sAnims_RubySapphireMay, ++ [TRAINER_PIC_MYTRAINERCLASS] = sAnims_MyTrainerClass, +}; +``` + +### 4. Connecting the Pictures to the Data +The last few things we have to do is prepare the graphics for usage. In [src/data/trainer_graphics/front_pic_table.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/trainer_graphics/front_pic_table.h) you'll find the structs, we need to add the trainer to all of these. You can just copy the last trainer type defined and edit it, but as far as I understand, these are what they do: + +1. gTrainerFrontPicCoords: Pretty self explanatory. Coordinates like size and offset on the y-axis to position the sprite on screen. +2. gTrainerFrontPicTable: Connects the trainer type with the image we defined earlier. +3. gTrainerFrontPicPaletteTable: Connects the trainer type with the palette we defined earlier. + +So, finally, it needs to look like this: +```diff +const struct MonCoords gTrainerFrontPicCoords[] = +{ + [TRAINER_PIC_HIKER] = {.size = 8, .y_offset = 1}, + [TRAINER_PIC_AQUA_GRUNT_M] = {.size = 8, .y_offset = 1}, +... + +... + [TRAINER_PIC_RS_BRENDAN] = {.size = 8, .y_offset = 1}, + [TRAINER_PIC_RS_MAY] = {.size = 8, .y_offset = 1}, ++ [TRAINER_PIC_MYTRAINERCLASS] = {.size = 8, .y_offset = 1}, +}; + +#define TRAINER_SPRITE(trainerPic, sprite, size) [TRAINER_PIC_##trainerPic] = {sprite, size, TRAINER_PIC_##trainerPic} + +const struct CompressedSpriteSheet gTrainerFrontPicTable[] = +{ + TRAINER_SPRITE(HIKER, gTrainerFrontPic_Hiker, 0x800), + TRAINER_SPRITE(AQUA_GRUNT_M, gTrainerFrontPic_AquaGruntM, 0x800), + TRAINER_SPRITE(POKEMON_BREEDER_F, gTrainerFrontPic_PokemonBreederF, 0x800), + TRAINER_SPRITE(COOLTRAINER_M, gTrainerFrontPic_CoolTrainerM, 0x800), +... + +... + TRAINER_SPRITE(RS_BRENDAN, gTrainerFrontPic_RubySapphireBrendan, 0x800), + TRAINER_SPRITE(RS_MAY, gTrainerFrontPic_RubySapphireMay, 0x800), ++ TRAINER_SPRITE(MYTRAINERCLASS, gTrainerFrontPic_MyTrainerClass, 0x800), +}; + +#define TRAINER_PAL(trainerPic, pal) [TRAINER_PIC_##trainerPic] = {pal, TRAINER_PIC_##trainerPic} + +const struct CompressedSpritePalette gTrainerFrontPicPaletteTable[] = +{ + TRAINER_PAL(HIKER, gTrainerPalette_Hiker), + TRAINER_PAL(AQUA_GRUNT_M, gTrainerPalette_AquaGruntM), + TRAINER_PAL(POKEMON_BREEDER_F, gTrainerPalette_PokemonBreederF), +... + +... + TRAINER_PAL(RS_BRENDAN, gTrainerPalette_RubySapphireBrendan), + TRAINER_PAL(RS_MAY, gTrainerPalette_RubySapphireMay), ++ TRAINER_PAL(MYTRAINERCLASS, gTrainerPalette_MyTrainerClass), +}; + +``` +### The Data +#### 5. Defining the trainer class +Finally, let's bring it all together by defining our new trainer class in [include/constants/trainers.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/trainers.h): + +```diff +#define TRAINER_PIC_RS_MAY 92 ++ #define TRAINER_PIC_MYTRAINERCLASS 93 + +#define TRAINER_BACK_PIC_BRENDAN 0 +#define TRAINER_BACK_PIC_MAY 1 +``` +Remember to count the number next to the trainer class up by one! + +## Usage +You can test your trainer type by going to [src/data/trainers](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/trainers.h) and changing a trainer type. For example: +```diff + [TRAINER_BRENDAN_PLACEHOLDER] = + { + .partyFlags = 0, + .trainerClass = TRAINER_CLASS_RS_PROTAG, + .encounterMusic_gender = TRAINER_ENCOUNTER_MUSIC_MALE, +- .trainerPic = TRAINER_PIC_RS_BRENDAN, ++ .trainerPic = TRAINER_PIC_MYTRAINERCLASS, + .trainerName = _("BRENDAN"), + .items = {}, + .doubleBattle = FALSE, + .aiFlags = 0, + .partySize = ARRAY_COUNT(sParty_BrendanLinkPlaceholder), + .party = {.NoItemDefaultMoves = sParty_BrendanLinkPlaceholder}, + }, +```