Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

About pokeemerald-expansion

Gif that shows debugging functionality that is unique to pokeemerald-expansion such as rerolling Trainer ID, Cheat Start, PC from Debug Menu, Debug PC Fill, Pokémon Sprite Visualizer, Debug Warp to Map, and Battle Debug Menu Gif that shows overworld functionality that is unique to pokeemerald-expansion such as indoor running, BW2 style map popups, overworld followers, DNA Splicers, Gen 1 style fishing, OW Item descriptions, Quick Run from Battle, Use Last Ball, Wild Double Battles, and Catch from EXP Gif that shows off a number of modern Pokémon battle mechanics happening in the pokeemerald-expansion engine: 2 vs 1 battles, modern Pokémon, items, moves, abilities, fully customizable opponents and partners, Trainer Slides, and generational gimmicks

pokeemerald-expansion is a GBA ROM hack base that equips developers with a comprehensive toolkit for creating Pokémon ROM hacks. pokeemerald-expansion is built on top of pret’s pokeemerald decompilation project. It is not a playable Pokémon game on its own.

Features

pokeemerald-expansion offers hundreds of features from various core series Pokémon games, along with popular quality-of-life enhancements designed to streamline development and improve the player experience. A full list of those features can be found in FEATURES.md.

Credits

If you use pokeemerald-expansion, please credit RHH (Rom Hacking Hideout). Optionally, include the version number for clarity.

Based off RHH's pokeemerald-expansion 1.14.1 https://github.com/rh-hideout/pokeemerald-expansion/

Please consider crediting all contributors involved in the project!

Choosing pokeemerald or pokeemerald-expansion

  • pokeemerald-expansion supports multiplayer functionality with other games built on pokeemerald-expansion. It is not compatible with official Pokémon games.
  • If compatibility with official games is important, use pokeemerald. Otherwise, we recommend using pokeemerald-expansion.
  • pokeemerald-expansion incorporates regular updates from pokeemerald, including bug fixes and documentation improvements.

Getting Started

❗❗ Important: Do not use GitHub’s “Download Zip” option as it will not include commit history. This is necessary if you want to update or merge other feature branches.

If you’re new to git and GitHub, Team Aqua’s Asset Repo has a guide to forking and cloning the repository. Then you can follow one of the following guides:

📥 Installing pokeemerald-expansion

🏗️ Building pokeemerald-expansion

🚚 Migrating from pokeemerald

🚀 Updating pokeemerald-expansion

Documentation

For detailed documentation, visit the pokeemerald-expansion documentation page.

Contributions

If you are looking to report a bug, open a pull request, or request a feature, our CONTRIBUTING.md has guides for each.

Community

Our community uses the ROM Hacking Hideout (RHH) Discord server to communicate and organize. Most of our discussions take place there, and we welcome anybody to join us!

What features are included?

Table of Contents

Configuration files

A lot of features listed below can be turned off as desired. Check which ones in these files

Upgraded Battle Engine

  • Battle gimmicks: Mega Evolution, Primal Reversion, Ultra Burst, Z-Moves, Dynamax, Gigantamax and Terastallization.
  • Newer game battle types: Double Wild Battles, custom Multi Battles, Inverse Battles, 1v2/2v1 battles, Sky Battles.
  • Updated battle mechanics: Critical capture, Frostbite support, Poké Ball quick menu, Move description menu, no badge boosts, Gen 4 Fog, obedience, Affection, Party swap upon catch, move effectiveness in battle, FRLG/Gen4+ whiteout money calculation, Gen 4-style shadows.
  • Updated move data: Fairy/Stellar types, Physical/Special split, flags.
  • Updated calculations: Damage, experience, mid-turn speed, end-battle stats and EVs, Level 100 EVs.
  • Every item, ability and move effect up to Gen IX: Includes contest data up to SwSh (source).
  • Initial battle conditions: Stat stages, battle terrain, Wild AI flags.
  • Faster battles: Simultaneous HP reduction, shortcut to “Run” option, faster battle intro, faster HP drain, faster AI calculations.
  • Easier customization: Cleaner codebase to implement custom moves and effects.
  • Improved AI: Faster and considers new effects added by Expansion.
  • Popular features: Level/EV Caps, Sleep Clause, Type Indicators.

Full Trainer customization

  • Compatible with Pokémon Showdown’s team syntax: Create your trainer teams in the teambuilder and paste the results!
  • Custom Pokémon data: Nicknames, EVs, IVs, Moves, Abilities, Poké Balls, Friendship, Nature, Gender, Shininess, Dynamax level, Gigantamax Factor and Tera Type.
    • “Ace Pokémon”: Will save a specific Pokémon for last.
    • Trainer Pools: A trainer may get a pool of randomized Pokémon instead of set teams.
  • Custom sliding trainer messages: First Turn, landing a super-effective hit, before Mega Evolution, etc.
  • New AI Flag options: Customize the intelligence of your trainers.
  • Trainer class Poké Balls: Divers use Dive Balls, Breeders use Nest Balls, etc.

Pokémon data

  • Improved Pokémon Data structure: Optimized space to allow fitting more information, such as Tera type, 12-character names, Hyper-trained stats, evolution conditions, saved HP/status effect.
  • Updated breeding mechanics: Poké Ball/Egg Move/Ability/Nature inheritance, Level 1 eggs automatic incense babies.
  • Updated species data: Stats, Types, Abilities, Hidden Abilities, Egg Groups, EV Yields, movesets, Battle Facility bans, guaranteed perfect IV counts, ORAS Dex numbers.
  • Simpler species data manipulation:: Only requires to edit ~5 files instead of vanilla pokeemerald’s 20+ to add a new Pokémon.
  • Updated sprites: DS-style sprites with support for Emerald’s 2-frame animations and gender difference.
  • Species toggles: You can disable specific groups of Pokémon to save space, including families, cross-gen evolutions, Mega Evolutions, Regional forms, etc.
  • Revamped Evolution System: Multiple Evolution conditions can be stacked in order to create complex methods without additional coding. Every condition except Affection and console gyroscope is supported.
  • Form Change System. Most form changes can be added without additional coding. This includes support for: Holding/using an item, HP thresholds being met, weather change in and/or out of battle, Fusions, and more.

Interface improvements

  • Pokémon Summary: Move relearner, EV/IV checks, Nature colors (feature branch by @DizzyEggg).
  • Party Menu: “Move Item” option.
  • Pokémon Storage System: Move option as default, access from Box Link item.
  • HGSS-style Pokédex (original feature branch by @TheXaman): Detailed in-game information accessible to players.

Engine improvements

  • All base pokeemerald bugfixes implemented by default: Anything under the BUGFIX define.
  • Improved sprite and palette compression: Assets use less space than vanilla compression.
  • Modern compiler support: Detect potential errors in your code more easily.
  • Dynamic Multichoice (original branch by @SBird1337): Easier way to add multiple-choice menus for scripting.
  • High-Quality RNG: No more broken vanilla RNG.

Overworld improvements

  • Modern Mechanics: Defog field move, B2W2+ Repel system, Running indoors, Removed field poison, Chain fishing, VS. Seeker, FRLG+ whiteout message.
  • Overworld and Follower Pokémon (feature branch by @aarant)
    • Includes Dynamic overworld palettes (DOWP) and Overworld Expansion for event IDs beyond 255.
    • Includes Pokémon sprites up to Generation IX.
  • Day/Night System: (feature branch by @aarant)
    • Includes support for non-real time clock.
  • NPC Followers: (feature branch by @ghoulslash)
  • BW Map Pop-ups (feature branch by @BSBob)
  • XY Berry Mechanics: Mutations, moisture, weeds, pests.
  • Obtained Item descriptions (feature branch by @ghoulslash).

Developer tools

  • Integrated Testing: Pinpoint if your custom mechanics have broken something else in the game or not.
  • Pokémon Sprite Visualizer: Test every Pokémon sprite and animation.
  • Overworld debug menu (original feature branch by @TheXaman): Support menu with an assortment of features to facilitate debugging, including warping, flag and var toggling, Pokémon and item generation and more.
  • Battle Debug Menu: Modify data on the fly in the middle of a battle.
  • Learnset Helper: Autogenerate movesets from your custom TM and Tutor data based on official compatibility data.
  • Configurable script flags: Disabling Wild encounters, Disabling Trainer battles, Forcing/Disabling Shinies.
  • Saveblock Cleansing (feature branch by @ghoulslash)

Instructions

Install instructions for each supported operating system can be found in their respective directories under docs/install/. Lines to those can be found under each heading. This file only contains a short introduction to each supported system. If you run into trouble, ask for help on Discord (see README.md).

After completing the install instructions for your OS, proceed to Building pokeemerald-expansion.

Windows

Windows needs one of the systems to build the project

A note of caution: As Windows 7 and Windows 8 are officially unsupported by Microsoft, some maintainers are unwilling to maintain the Windows 7/8 instructions. Thus, these instructions may break in the future with fixes taking longer than fixes to the Windows 10/11 instructions.

On Windows, the project can be built using the following systems:

  • WSL2, fastest
  • WSL1, 7 times slower than WSL2
  • Msys2, 20 times slower than WSL2
  • Cygwin, 30 timer slower than WSL2

NOTE: Only WSL systems are recommended.

WSL Install instructions

Msys2 Install instructions

Cygwin Install instructions

Linux

The project can be built on any Linux distribution. Distributions with instructions:

Other distributions have to infer what to do from general instructions.

Mac

Some extra considerations exist to get the testing system working.

Mac instructions

ChromeOS

Only tested on x86_64 based systems.

Chrome OS instructions

Building pokeemerald-expansion

Follow these steps to build pokeemerald-expansion.

  1. Navigate to the directory you want to keep the project in, be aware of any system specific limitations.

  2. Download pokeemerald-expansion with git

    git clone https://github.com/rh-hideout/pokeemerald-expansion
    
  3. Navigate to the newly downloaded project.

    cd pokeemerald-expansion
    
  4. Build the project.

    make
    
  5. If everything worked correctly, something very similar to this should be seen.

    arm-none-eabi-ld: warning: ../../pokeemerald.elf has a LOAD segment with RWX permissions
    Memory region         Used Size  Region Size  %age Used
               EWRAM:      243354 B       256 KB     92.83%
               IWRAM:       30492 B        32 KB     93.05%
                 ROM:    26072244 B        32 MB     77.70%
    cd build/modern && arm-none-eabi-ld  -T ../../ld_script_modern.ld --print-memory-usage -o ../../pokeemerald.elf <objs> <libs> | cat
    tools/gbafix/gbafix pokeemerald.elf -t"POKEMON EMER" -cBPEE -m01 -r0 --silent
    arm-none-eabi-objcopy -O binary pokeemerald.elf pokeemerald.gba
    tools/gbafix/gbafix pokeemerald.gba -p --silent
    

    And the build ROM will be in the directory as pokeemerald.gba.

Building guidance

Parallel builds

See the GNU docs and this Stack Exchange thread for more information.

To speed up building, first get the value of nproc by running the following command:

nproc

Builds can then be sped up by running the following command:

make -j<output of nproc>

Replace <output of nproc> with the number that the nproc command returned.

nproc is not available on macOS. The alternative is sysctl -n hw.ncpu (relevant Stack Overflow thread).

Other toolchains

To build using a toolchain other than devkitARM, override the TOOLCHAIN environment variable with the path to your toolchain, which must contain the subdirectory bin.

make TOOLCHAIN="/path/to/toolchain/here

The following is an example:

make TOOLCHAIN="/usr/local/arm-none-eabi"

To compile the modern target with this toolchain, the subdirectories lib, include, and arm-none-eabi must also be present.

Building with debug info

To build pokeemerald.elf with debug symbols and debug-compatible optimization under a modern toolchain:

make debug

Choosing a branch

pokeemerald-expansion has different branches that users can decide to use.

Latest Patch

This option will have all officially released expansion functionality and bugfixes.

master

The master branch has all of the functionality from “Latest Patch”, as well as any bugfixes that have been discovered since that release.

upcoming

The master branch has all of the functionality from “Latest Patch”, as well as any functionality that has been added since that release.

The bugfixes on master are occasionally merged into upcoming, but there is no official cadence.

Migrating from pokeemerald

  1. Set RHH as a git remote
git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion
  1. Pull your desired branch There are three different options to pull from.
git pull RHH master # if you've chosen to use the upcoming branch, replace the word master with upcoming. 
# If you've chosen the latest patch, replace the word master with expansion
# If you've chosen Latest Patch, replace the word master with expansion/1.11.0 where 1.11.0 is replaced with whatever the latest released version is.

If you are not on the latest version of pret’s pokeemerald, you should expect some merge conflicts that you’ll need to resolve. Once complete, you’ll be using pokeemerald-expansion.

Updating pokeemerald-expansion

  1. Set RHH as a git remote
git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion
  1. Check your current version Your local copy of the changelog will be updated with the version your repo is on.

  2. Select a target version We recommend incrementally updating to the next version using the following order below. If you are on a version older than 1.6.2, you should target 1.6.2..

    • 1.6.2
    • 1.7.4
    • 1.8.3
    • 1.9.4
    • 1.10.3

For example, if your version is 1.7.0, you should update to 1.7.4.

  1. Pull the target version
git pull RHH expansion/X.Y.Z # Replace X, Y and Z with the target version, such as `1.9.3`, `master`, or `upcoming`.

You may have merge conflicts that you need to resolve.

If you targeted a specific version that is not the latest version listed on the tags page, you should repeat steps 3 and 4 until you are.

Useful additional tools

Setting up WSL1 (Legacy Portion)

Setting up WSL1 (Legacy Portion)

  1. Certain packages are required to build pokeemerald. Install these packages by running the following command:

    sudo apt install build-essential git libpng-dev gdebi-core
    

    Note: If the above command does not work, try the above command but replacing apt with apt-get.

  2. Once the packages have finished installing, download the devkitPro pacman package here. The file to download is devkitpro-pacman.amd64.deb.

  3. WSL has its own file system that’s not accessible from Windows, but Windows files are accessible from WSL. To install the devkitPro package, you’ll need to change to the current working directory where the package file was saved.

    For example, if the package file was saved to C:\Users\<user>\Downloads (the Downloads location for most users), enter this command, where <user> is your Windows username:

    cd /mnt/c/Users/<user>/Downloads
    

    Note 1: The Windows C:\ drive is called /mnt/c/ in WSL. Note 2: If the path has spaces, then the path must be wrapped with quotations, e.g. cd "/mnt/c/users/<user>/Downloads folder". Note 3: Windows path names are case-insensitive so adhering to capitalization isn’t needed

  4. Once the directory has been changed to the folder containing the devkitPro pacman package, run the following commands to install devkitARM.

    sudo gdebi devkitpro-pacman.amd64.deb
    sudo dkp-pacman -Sy
    sudo dkp-pacman -S gba-dev
    

    The last command will ask for the selection of packages to install. Just press Enter to install all of them, followed by entering Y to proceed with the installation.

    Note: devkitpro-pacman.amd64.deb is the expected filename of the devkitPro package downloaded (for the first command). If the downloaded package filename differs, then use that filename instead.

  5. Run the following command to set devkitPro related environment variables (alternatively, close and re-open WSL):

    source /etc/profile.d/devkit-env.sh
    

Proceed to Choosing where to store pokeemerald (WSL1) of the current INSTALL.md.

Instructions for ChromeOS

  1. Enable the Linux terminal by following the instructions on this page. Be sure to allocate enough space for the Linux install.

  2. After the Linux terminal has finished installing, run the following command in the terminal to update and upgrade the Linux terminal:

    sudo apt update && apt upgrade
    
  3. Then install all dependencies by running the following command:

    sudo apt install build-essential binutils-arm-none-eabi gcc-arm-none-eabi libnewlib-arm-none-eabi git libpng-dev python3
    

NOTE: The project must be kept in a directory inside the Linux filesystem, for example under ~/Decomps/pokeemerald-expansion

Arch Linux instructions

Installing dependencies

Run the following command from the command line:

sudo pacman -S base-devel arm-none-eabi-binutils arm-none-eabi-gcc arm-none-eabi-newlib git libpng python

Debian instructions

Installing dependencies

Open a terminal and run the following command from the command line:

sudo apt install build-essential binutils-arm-none-eabi gcc-arm-none-eabi libnewlib-arm-none-eabi git libpng-dev python3

Fedora instructions

Installing dependencies

Open a terminal and run the following command from the command line:

sudo dnf install gcc g++ arm-none-eabi-binutils-cs arm-none-eabi-gcc-cs arm-none-eabi-newlib git libpng-devel python3

NixOS instructions

Run the following command to start an interactive shell with the necessary packages:

nix-shell -p pkgsCross.arm-embedded.stdenv.cc git pkg-config libpng

Instructions for other distributions

  1. Try to find the required software in its repositories:
    • gcc
    • g++
    • arm-none-eabi-gcc
    • arm-none-eabi-binutils
    • arm-none-eabi-newlib
    • make
    • git
    • libpng-dev
    • python3

Ubuntu instructions

Installing dependencies

Open a terminal and run the following command from the command line:

sudo apt install build-essential binutils-arm-none-eabi gcc-arm-none-eabi libnewlib-arm-none-eabi git libpng-dev python3

Instructions for macOS

  1. If the Xcode Command Line Tools are not installed, download the tools here, open your Terminal, and run the following command:

    xcode-select --install
    
  2. Optional: To run tests, if the homebrew environment is not installed, install the package manager using this reference. Open your terminal and run the following commands:

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    brew install coreutils
    
  3. Optional: To run tests via Rosetta

    • You probably don’t want to do this as it’s much slower. Most users can use native tools, but some may have other reasons to use this setup such as working with Intel-only custom tooling.
    • You will need an Intel-compatible homebrew installation. Understanding how to get one can be found here.
    • Install coreutils like in step 3, but using your Intel-compatible installation of homebrew.

Installing libpng (macOS)

Note for advanced users...

This guide installs libpng via Homebrew as it is the easiest method, however advanced users can install libpng through other means if they so desire.

  1. Open the Terminal.

  2. If Homebrew is not installed, then install Homebrew by following the instructions on the website.

  3. Run the following command to install libpng.

    brew install libpng
    

    libpng is now installed.

    Continue to Installing pkg-config (macOS) if pkg-config is not installed. Otherwise, continue to Installing devkitARM (macOS) if devkitARM is not installed.

    If both pkg-config and devkitARM are already installed, go to Choosing where to store pokeemerald-expansion (macOS).

Installing pkg-config (macOS)

Note for advanced users...

This guide installs pkg-config via Homebrew as it is the easiest method, however advanced users can install pkg-config through other means if they so desire.

  1. Open the Terminal.

  2. If Homebrew is not installed, then install Homebrew by following the instructions on the website.

  3. Run the following command to install libpng.

    brew install pkg-config
    

    pkg-config is now installed.

    Continue to Installing devkitARM (macOS) if devkitARM is not installed, otherwise, go to Choosing where to store pokeemerald-expansion (macOS).

Installing devkitARM (macOS)

  1. Download the devkitpro-pacman-installer.pkg package from here.

  2. Open the package to install devkitPro pacman.

  3. In the Terminal, run the following commands to install devkitARM:

    sudo dkp-pacman -Sy
    sudo dkp-pacman -S gba-dev
    sudo dkp-pacman -S devkitarm-rules
    

    The command with gba-dev will ask for the selection of packages to install. Just press Enter to install all of them, followed by entering Y to proceed with the installation.

  4. After the tools are installed, devkitARM must now be made accessible from anywhere by the system. To do so, run the following commands:

    export DEVKITPRO=/opt/devkitpro
    echo "export DEVKITPRO=$DEVKITPRO" >> ~/.zshrc
    export DEVKITARM=$DEVKITPRO/devkitARM
    echo "export DEVKITARM=$DEVKITARM" >> ~/.zshrc
    
    echo "if [ -f ~/.zshrc ]; then . ~/.zshrc; fi" >> ~/.zprofile
    

    Note: Starting with macOS 10.15, the default Unix shell is now zsh. If you migrated from an older version of macOS, you might still be using bash. You can check my running echo $0 in the terminal.

    If your terminal is using bash instead of zsh...
    export DEVKITPRO=/opt/devkitpro
    echo "export DEVKITPRO=$DEVKITPRO" >> ~/.bashrc
    export DEVKITARM=$DEVKITPRO/devkitARM
    echo "export DEVKITARM=$DEVKITARM" >> ~/.bashrc
    
    echo "if [ -f ~/.bashrc ]; then . ~/.bashrc; fi" >> ~/.bash_profile
    

Installing Python (macOS)

  1. Download the latest Python package from here.
  2. Open the package to install Python.

Python is now installed.

cygwin

Don’t, just don’t. Currently doesn’t work on current Expansion versions. This is a bug from upstream pret pokeemerald.

msys2

Don’t, just don’t. Currently doesn’t work on current Expansion versions. This is a bug from upstream pret pokeemerald.

Windows WSL instructions

Choosing WSL version

If you must store your project on the Windows file system (under /mnt/c/), you should use WSL1. If you want the best performance and least amount of issues with Windows interfering with compiling the project, use WSL2 and store the project on the Linux file system (under ~/).

Installing WSL

  1. Open Windows Powershell as Administrator, and run the following commands (Right Click or Shift+Insert is paste in the Powershell).

    wsl --install -d Ubuntu --enable-wsl1
    
  2. Once the process finishes, restart your machine.

WSL1

  1. Open Windows Powershell as Administrator again (after restarting), and run the following command to configure Ubuntu to use WSL1.

    wsl --set-version Ubuntu 1
    

WSL2

  1. Open Windows Powershell as Administrator again (after restarting), and run the following command to configure Ubuntu to use WSL2.

    wsl --set-version Ubuntu 2
    
    Note...

    WSL may open automatically after restarting, but you can ignore it for now.

Installing dependencies

Some tips before proceeding:

  • In WSL, Copy and Paste is either done via
    • right-click (selection + right click to Copy, right click with no selection to Paste)
    • Ctrl+Shift+C/Ctrl+Shift+V (enabled by right-clicking the title bar, going to Properties, then checking the checkbox next to “Use Ctrl+Shift+C/V as Copy/Paste”).
  • Some of the commands that you’ll run will ask for your WSL password and/or confirmation to perform the stated action. This is to be expected, just enter your WSL password and/or the yes action when necessary.
  1. Open Ubuntu (e.g. using Search).

  2. WSL/Ubuntu will set up its own installation when it runs for the first time. Once WSL/Ubuntu finishes installing, it will ask for a username and password (to be input in).

    Note...

    When typing in the password, there will be no visible response, but the terminal will still read in input.

  3. Update WSL/Ubuntu before continuing. Do this by running the following command. These commands will likely take a long time to finish:

    sudo apt update && sudo apt upgrade
    
  4. Certain packages are required to build pokeemerald Expansion. Install these packages by running the following command:

    sudo apt install build-essential binutils-arm-none-eabi gcc-arm-none-eabi libnewlib-arm-none-eabi git libpng-dev python3
    

Choosing a location to store pokeemerald Expansion, WSL1

WSL has its own file system that’s not natively accessible from Windows, but Windows files are accessible from WSL. So you’re going to want to store pokeemerald Expansion within Windows.

For example, say you want to store pokeemerald Expansion in C:\Users\<user>\Desktop\decomps. First, ensure that the folder already exists. Then, enter this command to change directory to said folder, where <user> is your Windows username:

cd /mnt/c/Users/<user>/Desktop/decomps
Notes...

Note 1: The Windows C:\ drive is called /mnt/c/ in WSL. Note 2: If the path has spaces, then the path must be wrapped with quotations, e.g. cd "/mnt/c/users/<user>/Desktop/decomp folder". Note 3: Windows path names are case-insensitive so adhering to capitalization isn’t needed

Choosing a location to store pokeemerald Expansion, WSL2

WSL has its own file system that’s not natively accessible from Windows, but Windows files are accessible from WSL. But accessing files on the Windows file system with WSL2 is very slow, so you’re going to want to store pokeemerald Expansion within WSL2. To access the files on the WSL filesystem from Windowsm, you have to open the WSL filesystem as a network attached storage in the file explorer, it should be at the bottom of the left sidebar as “Ubuntu”.

Thus you’re going to make sure that you’re in the WSL filesystem, then create the folder for decomps if it doesn’t already exist, then move into that folder.

cd ~/
mkdir decomps
cd decomps

Run documentation site locally

Running documentation website locally

Ubuntu WSL1/WSL2

Note: For further information beyond this very basic guide, please visit mdBook’s official documentation.

Running documentation website locally (Ubuntu WSL1/WSL2)

Previous Requirements:

  • Option 1: Install via Rust toolchain
    • Install Rust toolchain if you don’t have it via the sudo apt install cargo command.
    • Install mdBook via the cargo install mdbook command. Once finished, this message will pop up, with {USER} being your Ubuntu
      warning: be sure to add `/home/{USER}/.cargo/bin` to your PATH to be able to run the installed binaries
      
    • Add /home/{USER}/.cargo/bin to your PATH (with {USER} being the Ubuntu username.)
      • Run command nano ~/.profile to edit the file.
      • Add the following lines, replacing {USER} with your Linux username.
        # set PATH so it includes user's private bin if it exists
        if [ -d "$HOME/bin" ] ; then
            PATH="$HOME/bin:$PATH"
        fi
        
        # set PATH so it includes user's private bin if it exists
        if [ -d "$HOME/.local/bin" ] ; then
            PATH="$HOME/.local/bin:$PATH"
        fi
        
        +# set PATH so it includes cargo bin if it exists
        +if [ -d "/home/{USER}/.cargo/bin" ] ; then
        +    PATH="/home/{USER}/.cargo/bin:$PATH"
        +fi
        
      • Run the source ~/.profile command to refresh the path in the current session.
  • Option 2: Install downloaded binaries directly
    • TODO: Add documentation of this process.

Running the website

  • Navigate to the docs folder on the repository.
  • Run mdbook serve. Once started, you may now open the website on your browser by going to http://127.0.0.1:3000.
  • Every change done to the docs folder will be reflected with an automatic refresh.
  • To stop the server and go back to the terminal, press Ctrl + C.

Modifying the website

  • The navigation menu on the left is handled by docs/SUMMARY.md. Every file added needs to be added somewhere here in order to become visible, otherwise you’ll get a 404 error.
  • Any Markdown files (.md extension) added to the docs/ directory will automatically be read by mdBook.
  • To add Markdown files that are not in the docs/ directory, you may create an empty .md file and add the following without the “––”:
    {{ ----#include ../INSTALL.md}}`
    
    This will include the INSTALL.md Markdown file from the root directory.

Once you’re set up, you can now check your changes before pushing them to your repo! :D

We hope that this will make it easier for users to contribute to the documentation :)

Contributing to pokeemerald-expansion

First off, thanks for helping improve pokeemerald-expansion! ❤️

All contributions are encouraged and valued. Please make sure to read the relevant section before making your contribution! It will make it a lot easier for you and the maintainers. We’re excited to see your contributions. 🎉

Bug Reports

We use GitHub issues to track bugs.

What should I do before making a bug report?

  • Does your bug occur on the latest unmodified (clean) version of the upcoming or master branch? If not, please do not submit a report - the issue is most likely one introduced by your game.
  • Has somebody else already found this issue? This is best done by searching the bug tracker to see if anybody else reported it. If there is already an issue, replying to the exsting issue with more information can help solve the problem.

How do I submit a bug report?

If you run into an issue with the project, open an issue.

The best bug reports have enough information that we won’t have to contact you for more information. We welcome all efforts to improve pokeemerald-expansion, but would be very grateful if you completed as much of the checklist as possible in your bug report. This will help other contributiors fix your issue.

What happens after I submit a bug report?

  • A maintainer will label the bug report.
  • A maintainer will try to reproduce the bug with your provided steps.
    • If there are no reproduction steps or no obvious way to reproduce the issue, somebody will ask you for those steps. Until the bug can be reproduced, the bug will retain the bug:unconfirmed label. Unconfirmed bugs are less likely to get fixed.
  • If the team is able to reproduce the bug, it will be labeled bug:confirmed, and the bug will be left to be fixed by someone.
    • If the issue is particularly game-breaking, a maintainer will add it to a future version’s milestone, meaning that version will not be released until the problem is solved.

Feature Requests

This section guides you through submitting a feature request for pokeemerald-expansion, including completely new features and minor improvements to existing functionality. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.

  • We use GitHub issues to track feature requests.

What should I do before making a feature request?

What should I do before making a feature request?

  • Read the documentation to find out if the functionality is already covered, maybe by an individual configuration.
  • Perform a search to see if the feature has already been requested. If it has, add a comment to the existing issue instead of opening a new one.

How do I submit a feature request?

To request a feature to be added to the project, open a feature request.

What happens after I submit a feature request?

  • A maintainer will label the issue.
  • If the feature request is out of scope, it will be closed.
  • if the request is in scope, any other contributor can volunteer to fufill it via a pull request. When the request is filled, the request will be closed.

Pull Requests

If you have read all of this and still need help, feel free to start a thread in #pr-discussions of the Discord server or ask questions in #expansion-dev.

What should I do before starting a pull request?

How do I submit a pull request?

1. Get a working local copy

If you haven’t already, follow INSTALL.md to get a working local copy of pokeemerald-expansion.

2. Set RHH as a remote

This will designate the main pokeemerald-expansion repository as a remote.

git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion # You can replace RHH with anything you want. This tutorial assumes you used RHH.

3. Create a new branch

This will create a new branch and switch to it.

git switch -c newFeature # the name newFeature can be anything you want. This tutorial assumes you used newFeature.

4. Copy your target branch to your new branch

This will change your new branch to match the latest version of your chosen target branch.

git reset --hard upcoming # If your PR is going to target master, replace upcoming with master.

5. Implement your code

All of your work should go on this new, clean branch. If you already started work on a different branch, you can cherry-pick you old commits onto this new branch, or just copy and paste the changes from the original files.

If you are implementing functionality from a known community feature branch, it is strongly recommended that you open a discussion thread before starting. There are some situations where maintainers would ask you to use the existing feature branch as a base, and others where maintainers would want a feature to be written from scratch.

This changes on a case by case basis.

6. Push your changes

When you push your first commit, you’ll need to push the new branch to the remote repo.

git push --set-upstream origin newFeature

7. Open Pull Request

Once your work is complete and pushed to the branch on Github, you can open a pull request from your branch, targeting the branch you’ve chosen from pokeemerald-expansion. Please fill out the pull request description as completely as possible.

What happens after I submit a pull request?

A maintainer will then assign themselves as a reviewer of your pull request, and may provide feedback in the form of a PR review.

Contributors are responsible for responding to and updating their branch by addressing the feedback in the review. Contributors are also responsible for making sure the branch passes the checklist at all times.

Once a maintainer has begun reviewing your PR, please do not force-push new changes - normal pushes are fine. Do not worry about git history - we squash most incoming changes.

Maintainers will measure the submitted pull request against a merge checklist.

Once all items on the merge checklist are true, the branch will be merged in.

Maintainers

This list was last updated 2025 April 1.

NameDiscordCurrently ActiveAreas of Expertise
AlexrainonlineBattle Engine, Battle AI
Eggegg9255Battle Engine, Battle AI
ghoulslashghoulslashDexnav, Overworld, Battle Engine
JasperbassoonianBerries, Day / Night System, Followers, Feature Branches
MGriffinmgriffinTests, Trainer Control
psfpkmnsnfrnRematches, Difficulty, Trainer Slides, Fake RTC, Fishing Minigames, Imperial / Metric, OW Item Balls, Sky Battles
HedarahedaraCompression, Sprites
PawkkiepawkkieBattle AI
SBirdkarathanDynamic Multichoice, Damage Calculation, Animations, Trainer Control, Tests
AgustinagustingdlvInactiveGimmicks, Battle Engine, Tests, Items
tertutertuInactiveRandomizer

Attribution

This guide is based on the contributing.md!

Styleguide and Principles

Naming Conventions

Function names and struct names should be formatted in PascalCase.

void ThisIsCorrect(void);

struct MyStruct
{
    u8 firstField;
    u16 secondField;
    ...
};

Variables and struct fields should be formatted in camelCase.

int thisIsCorrect = 0;

Global variables should be prefixed with g, and static variables should be prefixed with s.

extern s32 gMyGlobalVariable;

static u8 sMyStaticVariable = 0;

Macros and constants should use CAPS_WITH_UNDERSCORES.

#define MAX_LEVEL 100

enum
{
    COLOR_RED,
    COLOR_BLUE,
    COLOR_GREEN,
};

#define ADD_FIVE(x) ((x) + 5)

Coding Style

Comments

Ideally, contributions have descriptive variable, function and constant names so as to explain functionality without comments. When a comment is used, the content of the comment should explain WHY a specific system or component works the way it does.

When describing a system/component in-depth, use block comment syntax.

/*
 * This is an in-depth description of the save block format. Its format is as follows:
 *
 * Sectors  0 - 13: Save Slot 1
 * Sectors 14 - 27: Save Slot 2
 * ...
 */

When briefly describing a function or block of code, use a single-line comments placed on its own line. There should be a single space directly to the right of //.

// This is supplemental information for the function. If there is a bunch of info, it should
// carry on to the next line.
void ProcessSingleTask(void)
{
   // Short comment describing some noteworthy aspect of the code immediately following.
   ...
   // Comments should be capitalized and end in a period.
}

When tagging a data structure that corresponds to an enum or some noteworthy value, place the comment on the same line as the code.

const u8 gPlantlikeMons[] =
{
    FALSE, // SPECIES_BULBASAUR
    FALSE, // SPECIES_IVYSAUR
    TRUE,  // SPECIES_VENUSAUR
    FALSE, // SPECIES_CHARMANDER
    ...
};

Whitespace

All .c and .h files should use 4 spaces–not tabs. Assembler files (.s) use tabs. Script files (.inc) use tabs.

Operators

Assignments and comparison operators should have one space on both sides of =.

int i = 0; // correct
int i=0;   // incorrect

a > b // correct
a>b   // incorrect

The incrementor and decrementor operators should NOT have a space.

i++;  // correct
i ++; // incorrect

A control statement should have a space between them and their expressions, and the opening bracket should be on the next line.

for (...)
{
    // correct
}

for(...) {
    // incorrect
}

A switch statement’s cases should left-align with the switch’s block.

switch (foo)
{
case 0: // correct
    ...
    break;
}

switch (foo)
{
    case 0: // incorrect
        ...
        break;
}

A single empty line should follow a block.

int MyFunction(int bar)
{
    int foo = 0;
    if (bar)
        foo++;

    return foo; // correct
}

int MyFunction(int bar)
{
    int foo = 0;
    if (bar)
        foo++;
    return foo; // incorrect
}

A chain of if-else statements in which any block is more than one line of code should use braces. If all blocks are single-line, then no braces are necessary.

if (foo) // correct
{
    return 1;
}
else
{
    MyFunction();
    return 0;
}

if (foo) // incorrect
    return 1;
else
{
    MyFunction();
    return 0;
}

Control Structures

When comparing whether or not a value equals 0, don’t be explicit unless the situation calls for it.

if (runTasks) // correct
    RunTasks();

if (runTasks != 0) // incorrect
    RunTasks();

if (!PlayerIsOutside()) // correct
    RemoveSunglasses();

if (PlayerIsOutside() == 0) // incorrect
    RemoveSunglasses();

When writing a for or while loop with no body, use a semicolon ; on the same line, rather than empty braces.

for (i = 0; gParty[i].species != SPECIES_NONE; i++); // correct

for (i = 0; gParty[i].species != SPECIES_NONE; i++) // incorrect
{ }

Inline Configs

When adding functionality that is controlled by a config, defines should be checked within the normal control flow of the function unless a data structure requires a change at runtime.

void SetCurrentDifficultyLevel(enum DifficultyLevel desiredDifficulty)
{
#ifdef B_VAR_DIFFICULTY
    return; // Incorrect
#endif

    if (desiredDifficulty > DIFFICULTY_MAX)
        desiredDifficulty = DIFFICULTY_MAX;

    VarSet(B_VAR_DIFFICULTY, desiredDifficulty);
}
void SetCurrentDifficultyLevel(enum DifficultyLevel desiredDifficulty)
{
    if (!B_VAR_DIFFICULTY) // Correct
        return;

    if (desiredDifficulty > DIFFICULTY_MAX)
        desiredDifficulty = DIFFICULTY_MAX;

    VarSet(B_VAR_DIFFICULTY, desiredDifficulty);
}
    [MOVE_VINE_WHIP] =
    {
        .name = COMPOUND_STRING("Vine Whip"),
        .description = COMPOUND_STRING(
            "Strikes the foe with\n"
            "slender, whiplike vines."),
        #if B_UPDATED_MOVE_DATA >= GEN_6 // Correct
            .pp = 25,
        #elif B_UPDATED_MOVE_DATA >= GEN_4
            .pp = 15,
        #else
            .pp = 10,
        #endif
        .effect = EFFECT_HIT,
        .power = B_UPDATED_MOVE_DATA >= GEN_6 ? 45 : 35,
    },

Variable Declarations

Loop iterators should be declared as part of the loop unless there’s a very good reason not to.

for (u32 i = 0; i < LOOP_ITERATIONS; i++)
{
    dst1[i] = i;
    dst2[i] = i;
}

Data Type Sizes

When a variable number is used, the data type should generally u32 (unsigned) or s32 (signed). There are a few exceptions to this rule, such as:

  • Values stored in the saveblock should use the smallest data type possible.
  • EWRAM variables should use the smallest data type possible.
  • Global variables / global struct members use the smallest data type possible.

Constants, Enums and Type Checking

Avoid using magic numbers when possible - constants help to make clear why a specific value is used.

// Incorrect
        if (gimmick == 5 && mon->teraType != 0)
            return TRUE;
        if (gimmick == 4 && mon->shouldUseDynamax)
            return TRUE;
// Correct
#define TYPE_NONE 0
#define GIMMICK_DYNAMAX 4
#define GIMMICK_TERA 5

        if (gimmick == GIMMICK_TERA && mon->teraType != TYPE_NONE)
            return TRUE;
        if (gimmick == GIMMICK_DYNAMAX && mon->shouldUseDynamax)
            return TRUE;

When several numbers in sequence are used AND those values are not utilized in the saveblock, an enum is used instead.

//Correct
enum Gimmick
{
    GIMMICK_NONE,
    GIMMICK_MEGA,
    GIMMICK_ULTRA_BURST,
    GIMMICK_Z_MOVE,
    GIMMICK_DYNAMAX,
    GIMMICK_TERA,
    GIMMICKS_COUNT,
};

        if (gimmick == GIMMICK_TERA && mon->teraType != TYPE_NONE)
            return TRUE;
        if (gimmick == GIMMICK_DYNAMAX && mon->shouldUseDynamax)
            return TRUE;

When an enum is used, the enum type is used instead of a regular number type to prevent incorrectly set values.

// Incorrect
bool32 CanActivateGimmick(u32 battler, u32 gimmick)
{
    return gGimmicksInfo[gimmick].CanActivate != NULL && gGimmicksInfo[gimmick].CanActivate(battler);
}

u32 GetCurrentDifficultyLevel(void)
{
    if (!B_VAR_DIFFICULTY)
        return DIFFICULTY_NORMAL;

    return VarGet(B_VAR_DIFFICULTY);
}
//Correct

bool32 CanActivateGimmick(u32 battler, enum Gimmick gimmick)
{
    return gGimmicksInfo[gimmick].CanActivate != NULL && gGimmicksInfo[gimmick].CanActivate(battler);
}

enum DifficultyLevel GetCurrentDifficultyLevel(void)
{
    if (!B_VAR_DIFFICULTY)
        return DIFFICULTY_NORMAL;

    return VarGet(B_VAR_DIFFICULTY);
}

Data file format

External data files should use JSON.

Principles

Minimally Invasive

New functionality must be as minimally invasive to existing files as possible. When a large amount of new code is introduced, it is best to isolate it in its own file.

The B_VAR_DIFFICULTY pull request is a good example of lots of new code being introduced in minimally invasive ways.

UNUSED

If a function or data is introduced but is never called, it is designated as UNUSED. UNUSED functions should not be introduced unless neccesary.

static void UNUSED PadString(const u8 *src, u8 *dst)
{
    u32 i;

    for (i = 0; i < 17 && src[i] != EOS; i++)
        dst[i] = src[i];

    for (; i < 17; i++)
        dst[i] = CHAR_SPACE;

    dst[i] = EOS;
}

Config Philosophy

If a branch can modifies saves, the functionality that does so must be gated behind a config, and off by default.

If a branch has a config that performs either of the following, it should be on by default:

  • improves the backend / developer quality of life
  • emulates present day, modern day Pokémon

If a branch’s behavior is one that Game Freak does not have a consistent stance on, the default behavior of the config should be disussed by the maintainers.

All other configs should be off.

Save Philosophy

Until save migration is implemented, branches will only merged in if they do not forcefully break existing game saves.

When pokemeerald-expansion gets to a point where new functionality will require that we break saves, we will merge as many save-breaking features together as possible, and increment the major version number of the project.

Attribution

Credits

Credits ✨

Thanks goes to these wonderful people (emoji key):

AgustinGDLV
AgustinGDLV

🚧 💻
Alex
Alex

🚧 💻
Bassoonian
Bassoonian

🚧 💻
DizzyEggg
DizzyEggg

🚧 💻
ghoulslash
ghoulslash

🚧 💻
hedara90
hedara90

🚧 💻
Martin Griffin
Martin Griffin

🚧 💻
Pawkkie
Pawkkie

🚧 💻 📖
Philipp AUER
Philipp AUER

🚧 💻
tertu
tertu

🚧 💻
psf
psf

🚧 💻 📆
wiz1989
wiz1989

💻
PCG
PCG

💻
kittenchilly
kittenchilly

💻 🔬 🔣
ExpoSeed
ExpoSeed

💻 🚧 👀
Linathan
Linathan

💻
Eduardo Quezada
Eduardo Quezada

💻 🔣 📖 🚇 🚧 📆 📣 🔬 👀 ⚠️ 📓
khbsd
khbsd

📖 💻
Cafe
Cafe

🎨
agsmgmaster64
agsmgmaster64

💻
Ruby
Ruby

💻 📖
mudskipper13
mudskipper13

💻 📖
surskitty
surskitty

💻
grintoul
grintoul

💻
bassforte123
bassforte123

💻
iriv24
iriv24

💻
Bivurnum
Bivurnum

💻
Emilia Daelman
Emilia Daelman

💻 ⚠️
RavePossum
RavePossum

💻
Zatsu
Zatsu

💻
poetahto
poetahto

💻
lordraindance2
lordraindance2

💻
Pablo Pena
Pablo Pena

💻
tustin2121
tustin2121

📖 💻
Phantonomy
Phantonomy

🎨
Enrico Drago
Enrico Drago

📖 📓
Pyredrid
Pyredrid

📓 🚧
mv
mv

💻 🎨
Avara
Avara

🔣
Doesnty
Doesnty

🎨
FosterProgramming
FosterProgramming

💻
Squeetz
Squeetz

🚧
ghostyboyy97
ghostyboyy97

💻
Marky
Marky

💻
MandL27
MandL27

💻
cawtds
cawtds

💻
Frank DeBlasio
Frank DeBlasio

💻
leo60228
leo60228

📖 🔣
shachar700
shachar700

💻
Eva
Eva

🎨
amiosi
amiosi

🔣
Add your contributions

This project follows the all-contributors specification. Contributions of any kind welcome!

Other Credits

Mega Evolution Overworld Sprite Credits:

Resources

What are AI Flags?

AI flags alter the behavior of AI controlled trainers. These flags affect what moves the AI chooses to use, what Pokémon the AI sends out and when they decide to switch, overarching strategic choices the AI prefers to make, and more.

The AI flags can be found in include/constants/battle_ai.h. Some flags have their own dedicated functions that affect how the AI scores its options when choosing what to do in battle, and those functions can be found in src/battle_ai_main.c. Other flags are used in conditional checks to gate certain behaviour behind certain flags, which you can typically find by searching the codebase for the flag name and browsing from there.

What flags should you use?

When adding new AI flags it is recommended to use AI_FLAG_CHECK_BAD_MOVE, AI_FLAG_CHECK_VIABILITY, AI_FLAG_TRY_TO_FAINT to make sure the AI makes good decisions. It is especially important to use AI_FLAG_CHECK_BAD_MOVE in combination with any added flags otherwise the AI will use moves that can fail.

Other flags should be used with consideration to the circumstances.

How do you use them?

Adding an AI flag to a trainer is straightforward, but the process is different depending on how trainers are being defined.

COMPETITIVE_PARTY_SYNTAX == TRUE

If you are using competitive syntax parties, navigate to the trainer data in src/data/trainers.party, find the trainer you’d like to change, and add flags like so: AI: Check Bad Move / Try to Faint / Check Viability. The name of each flag is just the constant, but without AI_FLAG at the beginning. For example, to add AI_FLAG_SEQUENCE_SWITCHING, any of the following will work:

  • AI_FLAG_SEQUENCE_SWITCHING
  • SEQUENCE_SWITCHING
  • SEQUENCE SWITCHING
  • Sequence_Switching
  • Sequence Switching

COMPETITIVE_PARTY_SYNTAX != TRUE / Not Found

If you are not using competitive syntax parties, instead access the trainer data directly in src/data/trainers.h, and add flags like so, typed exactly the same as the flag names themselves: .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY

What AI Flags does pokeemerald-expansion have?

This section lists all of expansion’s AI Flags and briefly describes the effect they have on the AI’s behaviour. In all cases, please check the corresponding function or surrounding code around their implementation for more details. Some of these functions are vanilla, some share a name with vanilla but have been modified to varying degrees, and some are completely new.

Composite AI Flags

Expansion has a few “composite” AI flags. This means that these flags have no unique functionality themselves, and can instead be thought of as groups of other flags that are all enabled when this flag is enabled. The idea behind these flags is that if you don’t care to manage the detailed behaviour of a particular trainer, you can use these as a baseline instead, and expansion will keep them updated for you.

AI_FLAG_BASIC_TRAINER is expansion’s version of generic, normal AI behaviour. It includes AI_FLAG_CHECK_BAD_MOVE (don’t use bad moves), AI_FLAG_TRY_TO_FAINT (faint the player where possible), and AI_FLAG_CHECK_VIABILITY (choose the most effective move to use in the current context). Trainers with this flag will still be smarter than they are in vanilla as there have been dramatic improvements made to move selection, but not incredibly so. Trainers with this flag should feel like normal trainers. In general we recommend these three flags be used in all cases, unless you specifically want a trainer who makes obvious mistakes in battle.

AI_FLAG_SMART_TRAINER is expansion’s version of a “smart AI”. It includes everything in AI_FLAG_BASIC_TRAINER along with AI_FLAG_SMART_SWITCHING (make smart decisions about when to switch), AI_FLAG_SMART_MON_CHOICES (make smart decisions about what mon to send in after a switch / KO), AI_FLAG_OMNISCIENT (awareness of what moves, items, and abilities the player’s mons have to better inform decisions), and AI_FLAG_SMART_TERA (make smart decisions about when to terastalize). Expansion will keep this updated to represent the most objectively intelligent behaviour our flags are capable of producing.

AI_FLAG_PREDICTION will enable all of the prediction flags at once, so the AI can perform as well as possible. It is best paired with the flags in AI_FLAG_SMART_TRAINER for optimal behaviour. This currently includes AI_FLAG_PREDICT_SWITCH and AI_FLAG_PREDICT_INCOMING_MON, but will likely be expanded in the future.

Expansion has LOADS of flags, which will be covered in the rest of this guide. If you don’t want to engage with detailed trainer AI tuning though, you can just use these two composite flags, and trust that expansion will keep their contents updated to always represent the most standard and the smartest behaviour we can.

AI_FLAG_CHECK_BAD_MOVE

The AI will avoid using moves that are likely to fail in the current situation. This flag helps prevent the AI from making ineffective choices, such as using moves into immunities, into invulnerable states, or when the moves are otherwise hindered by abilities, terrain, or status conditions.

AI_FLAG_TRY_TO_FAINT

AI will prioritize KOing the player if able rather than using status moves. Will prioritize using a move that can OHKO the player. If the player can KO the AI’s mon and the AI’s mon is slower, prioritize priority moves (this does not prevent the AI from switching out instead).

This flag handles scoring for OHKOs but does not handle 2HKOs at all, AI_FLAG_STRONGEST_MOVE should be used for 2HKO scoring.

AI_FLAG_CHECK_VIABILITY

This flag is divided into two components to calculate the best available move for the current context:

  • AI_CompareDamagingMoves: This function compares damaging moves against each other and picks the best one.
  • AI_CalcMoveEffectScore: This function checks every move effect (status or damaging move effect) and increases the score accordingly.

This is different to AI_FLAG_CHECK_BAD_MOVE as it calculates how poor a move is and not whether it will fail or not.

AI_FLAG_ATTACKS_PARTNER

This flag is meant for double battles where both of the opponents hate each other. They prioritize damage to their ‘partner’ over the player.

AI_FLAG_FORCE_SETUP_FIRST_TURN

AI will prioritize using setup moves on the first turn at the expense of all else. These include stat buffs, field effects, status moves, etc. AI_FLAG_CHECK_VIABILITY will instead do this when the AI determines it makes sense.

This is just a flat increase without any consideration of whether it makes sense to use the move or not. For better move choice quality for those moves, AI_FLAG_CHECK_VIABILITY should be used.

AI_FLAG_RISKY

AI will generally behave more recklessly. This AI enables the following behaviour:

  • Always assume the highest damage roll when scoring moves
  • Blindly Mirror Coat / Counter based on the player mon’s species higher attacking stat
  • Moves with Recoil if they miss are not treated differently even if accuracy is lowered
  • Prioritize maximizing damage from moves at the cost of accuracy
  • Prioritize moves with low change strong effects (Ancient Power etc., check AI_Risky function for full list)
  • Switch offensively mid battle rather than defensively (if using AI_FLAG_SMART_MON_CHOICES)
  • Prioritize Explosion moves

AI_FLAG_TRY_TO_2HKO

Adds score bonus to any move the AI has that either OHKOs or 2HKOs the player.

Keep in mind that this is a weaker form of AI_FLAG_TRY_TO_FAINT at scoring OHKOs as it does not take into account who is attacking first, it does however handle 2HKOs.

AI_FLAG_PREFER_BATON_PASS

AI prefers raising its own stats if it has >= 60% HP, as well as Ingrain, Aqua Ring, and Protect. Prioritizes Baton Bass if the mon is rooted (Ingrain) or has the Aqua Ring effect, and doesn’t if it has been Leech Seeded.

AI_FLAG_DOUBLE_BATTLE

This flag is automatically set in double battles, and controls much of the doubles-specific scoring. I’ll summarize some of its scoring as follows:

  • Don’t use Helping Hand if partner is, don’t Perish Trap your partner, don’t change the weather if they are, don’t buff stats if partner will trigger Anger Point for us
  • Collaborate with partner to Perish Trap opponent, Magnet Rise to protect partner, Dragon Cheer partner if applicable
  • Prioritize using weather move if it benefits partner
  • Prioritize triggering partner’s good abilities if possible (Motor Drive, Storm Drain, Beat Up -> Justified, etc.)
  • Handle Skill Swap smartly, both with the partner and against the player

AI_FLAG_HP_AWARE

Lets the AI make decisions based on how much remaining HP its mon(s) and the player’s mon(s) have.

With respect to the AI’s mons, in doubles:

  • Allows the AI to attack its partner with a move it can absorb if its low on HP (ie. Electric move on partner with Volt Absorb)
  • Prioritizes healing its partner if its HP is <= 50% if able

In both singles and doubles:

  • Prioritizes not using moves that require the user fainting (Destiny Bond, Explosion etc.) and healing moves while on >= 70% HP.
  • Prioritize not using moves that require the user fainting or losing significant HP (Belly Drum etc) while between 30% and 70% HP
  • Prioritize not using setup moves (Light Screen etc.) and Bide while on <= 30% HP

With respect to the player’s mons:

  • Prioritize not using many status moves (stat buffs, Poison, Pain Split) if the player has between 30% and 70% HP
  • Prioritize not using any status moves if the player is has <= 30% HP

AI_FLAG_POWERFUL_STATUS

AI prioritizes setting up field effects (Trick Room, Rain Dance, etc.) and side statuses (Tailwind, Spikes, etc.), even if it could faint the target.

AI_FLAG_NEGATE_UNAWARE

AI does not understand ability suppression (Mold Breaker etc., weather suppression (Air Lock etc.), redirection abilities (Lightningrod etc.) being temporarily removed due to move effects (Sky Drop etc.), or item suppression (Magic Room etc.) and will ignore them. This is a handicap flag.

AI_FLAG_WILL_SUICIDE

AI prioritizes self destruction moves (Explosion, Memento).

AI_FLAG_PREFER_STATUS_MOVES

AI gets a score bonus for status moves. This should be combined with AI_FLAG_CHECK_BAD_MOVE to prevent using only status moves.

AI_FLAG_STALL

AI prefers simple classically “stalling” behaviour. It will prioritize:

  • Mean Look, Fairy Lock, and Wrap for trapping
  • Increasing its defense and special defense
  • Moves that inflict Poison if it also has a Protect move
  • Copying defense and special defense buffs

AI_FLAG_SMART_SWITCHING

Affects when the AI chooses to switch. AI will make smarter decisions about when to switch out mid-battle. Automatically enables AI_FLAG_SMART_MON_CHOICES, which is required as the vanilla mon selection AI is not smart enough to handle several switch-triggering situations appropriately, leading to bizarre behaviour. Many of these checks have intentional failure rates, so the AI won’t switch out 100% of the time in these cases to keep the player from being able to predict perfectly. Some of these also only apply to singles, and many of them are being simplified for the sake of brevity. This flag lets the AI trigger switches when:

  • It can’t hit Wonder Guard and has another mon in the party that can (switch that mon in)
  • It’s going to die to Perish Song, can’t KO the player and is affected by Yawn, is being severely affected by a status condition that switching helps (Curse, Toxic, Leech Seed)
  • It has a mon that can trap the player’s mon and win the 1v1 (switch that mon in)
  • It has a mon in the party that can absorb the player’s next expected attack (switch that mon in)
  • It will not switch if the current mon will die to hazards on re-entry and it has no means of clearing them in its party
  • All its moves are bad
  • It can take advantage of Natural Cure or Regenerator
  • Its Encore’d into something bad
  • Its primary attacking stats are sufficiently lowered
  • Its “odds are bad”, which is a generic “try to make smart, player-like decisions generally speaking” check. Switches can be triggered if the player has a good switchin candidate (AI_FLAG_SMART_MON_CHOICES), and:
  • The current mon has a bad type matchup and doesn’t have a super effective move and has at least ½ HP, or ¼ HP and Regenerator, or
  • The current mon loses the 1v1 quickly and has at least ½ HP, or ¼ and Regenerator

AI_FLAG_ACE_POKEMON

Marks the last Pokemon in the party as the Ace Pokemon. It will not be used unless it is the last one remaining, or is forced to be switched in (Roar, U-Turn with 1 mon remaining, etc.). If you are challenged by two different trainers at the same time, only the ones with this flag will have Ace Pokémon. For example vs one trainer with AI_FLAG_ACE_POKEMONand the other without, there will be a total of 1 Ace Pokémon.

AI_FLAG_DOUBLE_ACE_POKEMON

Marks the last two Pokémon in the party as Ace Pokémon, with the same behaviour as AI_FLAG_ACE_POKEMON. Intented for double battles where you battle one trainer id that represents two trainers, ie Twins, Couples. If you apply this flag to trainers outside of double battles or in cases where two trainers can challenge you at the same time, it has the same behaviour. For example vs two trainers with AI_FLAG_DOUBLE_ACE_POKEMON there will be a total of 4 Ace Pokémon.

AI_FLAG_OMNISCIENT

AI has full knowledge of player moves, abilities, and hold items, and can use this knowledge when making decisions.

AI_FLAG_ASSUME_STAB

A significantly more restricted version of AI_FLAG_OMNISCIENT, the AI only knows the player’s STAB moves, as their existence would be reasonable to assume in almost any case.

AI_FLAG_ASSUME_STATUS_MOVES

A more restricted version of AI_FLAG_OMNISCIENT. The AI has a chance to know what status moves the player has, plus additionally Fake Out and fixed percentage moves like Super Fang. The intention is so that if the AI has a counterplay implemented, it will seem to have guessed if the player’s pokemon has a move, without giving the AI perfect information. For example, with Omniscient set, the AI will not usually put a pokemon to sleep if it has Sleep Talk; with neither Assume Powerful Status nor Omniscient set, the AI will always assume the pokemon does not have Sleep Talk.

By default, there are three groups of higher likelihood status moves defined in include/config/ai.h under ASSUME_STATUS_HIGH_ODDS, ASSUME_STATUS_MEDIUM_ODDS, and ASSUME_STATUS_LOW_ODDS. Moves are sorted in src/battle_ai_util.c within ShouldRecordStatusMove().

Any move that is not special cased is then potentially caught by ASSUME_ALL_STATUS_ODDS.

AI_FLAG_SMART_MON_CHOICES

Affects what the AI chooses to send out after a switch. AI will make smarter decisions when choosing which mon to send out mid-battle and after a KO, which are handled separately. Automatically included when AI_FLAG_SMART_SWITCHING is enabled.

With this flag enabled, the AI will prioritize choosing mons after a KO prioritizing the following criteria:

  • Trapper (can trap the player’s mon and win the 1v1)
  • Revenge killer (outspeeds an OHKOs / is outsped and OHKOs, is not OHKOd/ outspeeds and 2HKOs, is not OHKOd / is outsped and 2HKOs, is not 2HKOd)
  • Has good type matchup and a super effective move
  • Has good type matchup and does not have a super effective move
  • Has Baton Pass
  • If no mons meet any of the above criteria, choose the one that does the most damage

And will choose mons after a mid-battle switch prioritizing the following criteria:

  • Trapper (can trap the player’s mon and win the 1v1)
  • Has good type matchup and a super effective move
  • Has good type matchup and does not have a super effective move
  • Is not 3HKO’d by the player
  • Has Baton Pass

AI_FLAG_CONSERVATIVE

AI always assumes it will roll the lowest possible result when comparing damage in scoring.

AI_FLAG_SEQUENCE_SWITCHING

AI will always switch out after a KO in exactly party order as defined in the trainer data (ie. slot 1, then 2, then 3, etc.). The AI will never switch out mid-battle unless forced to (Roar etc.). If the AI uses a move that requires a switch where it makes a decision about what to send in (U-Turn etc.), it will always switch out into the lowest available party index.

AI_FLAG_WEIGH_ABILITY_PREDICTION

AI will predict the player’s ability based to its aiRating. Without this flag the AI randomly assumes an ability with an even distribution between all possible abilities until one is confirmed. With this flag, it instead guesses proportionally to each ability’s aiRating, making it far more likely to guess an ability like Water Absorb than Damp if both are options.

AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE

AI will add score to its highest damaging move, regardless of accuracy or secondary effects. Replaces deprecated AI_FLAG_PREFER_STRONGEST_MOVE.

AI_FLAG_PREDICT_SWITCH

AI will determine whether it would switch out in the player’s situation or not, and predict the player to switch accordingly. In any case where the AI would consider switching, it will assume the player will switch. This is modulated by a 50% failure rate, so the behaviour is non-deterministic and can change from turn to turn to emulate the inconsistency in human predictions. This behaviour is improved significantly by using AI_FLAG_SMART_SWITCHING and AI_FLAG_SMART_MON_CHOICES as they improve the AI’s ability to determine good situations to switch, and also by AI_FLAG_OMNISCIENT so the AI can use all its knowledge of the player’s team to make the decision.

AI_FLAG_PREDICT_INCOMING_MON

This flag requires AI_FLAG_PREDICT_SWITCH to function. If the AI predicts that the player will switch, this flag allows the AI to run its move scoring calculation against the Pokémon it expects the player to switch into, instead of the Pokémon that it expects to switch out.

AI_FLAG_SMART_TERA

AI will make smarter decisions about when to terastalize (over the default behaviour to always tera when available). This considers factors such as whether tera allows the AI to KO the opponent, whether it can save itself from a KO or a big hit, and how many remaining pokemon could terastalize. This behavior is not currently supported in double battles.

AI_FLAG_PREDICT_MOVE

AI will predict what move the player is going to use based on what move it would use in the same situation. Generally works best if also using AI_FLAG_OMNISCIENT.

AI_FLAG_PP_STALL_PREVENTION

This flag aims to prevent the player from PP stalling the AI by switching between immunities. The AI mon’s move scores will slowly decay for absorbed moves over time, eventually making its moves unpredictable. More detailed control for this behaviour can be customized in the ai.h config file.

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:

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!

How to add new battle script commands/macros

How to add new Battle Script Commands/Macros

To preface this tutorial, the battle engine upgrade has exhausted all battle script command IDs. Historically, we’ve used the various command to effectively add new commands. However, this has caused issues of maintainability and readability due to the massive switch needed for it. Thanks to the cleanup made by the team and contributors, we now are able to call an infinite amount of commands by using callnative. 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 callnative command is set up.

	.macro callnative func:req
	.byte 0xff
	.4byte \func
	.endm

callnative uses the last battle script command ID in order to pass a native function as an argument. Additional optional arguments are added recursively via a macro, so no need to worry about how they need to align to the amount of instructions to skip.

Now, how might we add a custom callnative command? Here are the steps. We will use BS_JumpIfTerrainAffected as an example.

1. Create a macro in asm/macros/battle_script.inc. For example:

	.macro jumpifterrainaffected battler:req, terrainFlags:req, jumpInstr:req
	callnative BS_JumpIfTerrainAffected
	.byte \battler
	.4byte \terrainFlags
	.4byte \jumpInstr
	.endm

2. Add your new callnative command ID to src/battle_script_commands.c. For example:

void BS_JumpIfTerrainAffected(void)
{
    NATIVE_ARGS(u8 battler, u32 flags, const u8 *jumpInstr);
    u32 battler = GetBattlerForBattleScript(cmd->battler);

    if (IsBattlerTerrainAffected(battler, cmd->flags))
        gBattlescriptCurrInstr = cmd->jumpInstr;
    else
        gBattlescriptCurrInstr = cmd->nextInstr;
}

Each of the arguments defined in the macro (battler, flags, failInstr) need to be called at the start of the command using NATIVE_ARGS. The byte count in the macro should correspond to the type that will be used for the command (eg, u8 is byte, while the pointer are 4byte). These arguments can then be accessed as cmd->battler, cmd->flags and cmd->failInstr. Note that for cmd->battler we need to use GetBattlerForBattleScript to fetch the correct battler because with the macro we are accessing a scripting command that doesn’t corresponds to gBattlerTarget, gBattlerAttacker, etc. For the battler argument specifically, most of the time the battler is accessed through gBattlerAttacker, gBattlerTarget and the battler argument left out. In the majority of cases, this is fine since the script commands are mostly used for moves and the interaction is usually between an attacker and target. A script command usually ends with either a jump or next instruction gBattlescriptCurrInstr = cmd->nextInstr / cmd->nextInstr; advancing to the next instruction.

How to add a new move

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_xxxs.
  • 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
  2. Editing a move
  3. 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:

[MOVE_THUNDER_SHOCK] =
{
    .name = COMPOUND_STRING("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,
    .additionalEffects = ADDITIONAL_EFFECTS({
        .moveEffect = MOVE_EFFECT_PARALYSIS,
        .chance = 10,
    }),
    .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING,
    .contestCategory = CONTEST_CATEGORY_COOL,
    .contestComboStarterId = 0,
    .contestComboMoves = {COMBO_STARTER_CHARGE},
},

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, and any variable characteristics such as typing or power are defined in either src/battle_script_commands.c or src/battle_util.c, 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 and encoded under SetMoveEffect in src/battle_script_commands.c. 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. The indices/names of the effects (e.g. EFFECT_FIRST_TURN_ONLY) are enums defined in include/constants/battle_move_effects.h.

include/battle_scripts.h

Contains references to scripts data/battle_scripts_1.s, 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.

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.

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:

TODO: New Script

BattleScript_EffectTaunt::
	attackcanceler
	jumpifability BS_TARGET_SIDE, ABILITY_AROMA_VEIL, BattleScript_AromaVeilProtects
	accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE
	settaunt BattleScript_ButItFailed
	attackanimation
	waitanimation
	printstring STRINGID_PKMNFELLFORTAUNT
	waitmessage B_WAIT_TIME_LONG
	goto BattleScript_MoveEnd

attackcanceler is a command that covers all cases that could cause a move to fail before it’s even attempted (e.g. paralysis). The next command is a jump command. A jump command can check anything and usually comes with a jump instruction. Usually it jumps to a place from where the move should pick up because of certain conditions. The next one is an accuracy check. Accuracy checks happen after all prior move failure checks happened. The next set of commands are unique to a certain move, they are mostly the same for damaging moves but can widely differ for status moves. Lastly there is BattleScript_MoveEnd which the move after a succesful hit. An ability activation or specific move effect like Burn, Freeze, Absorb etc.

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 and src/battle_script_commands.c. 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. 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 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, whereas callnative will let you directly call a function in src/battle_script_commands.c 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. 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. 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 and any relevant functions in src/battle_script_commands.c. To change how a move’s dynamic power, accuracy and are calculated, then you need to modify the following functions:

Note: A generic function for calculating category does not currently exist - Photon Geyser’s script in data/battle_scripts_1.s uses a special callnative function BS_SetPhotonGeyserCategory.

Changing a move’s additional effects

If you look at the example here, 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.

Depending on the move effect, it is possible to also set a multistring value. For example:

.additionalEffects = ADDITIONAL_EFFECTS({
    .moveEffect = MOVE_EFFECT_WRAP,
    .multistring = B_MSG_WRAPPED_MAGMA_STORM,
}),

For Magma Storm, we not only want the wrapping move effect, we want to give it a unique string when it activates. The index is an enum defined in battle_string_ids.h and it corresponds to an entry (for this move effect) in the gWrappedStringIds list in battle_message.c. For custom strings, you need to add an enum and an entry respectively. For new custom move effects, you will have to add a new set of enums and a new table of strings.

Each move can have up to 3 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,
    }),
    .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:

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.

How to add a new trainer front pic

Content

Quick Summary

If you’ve done this before and just need a quick lookup, here’s what files you need:

  1. Place graphics into graphics/trainers/front_pics.
  2. Point game to where graphic files are found: src/data/graphics/trainers.
  3. Add trainer to 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 pic. Unlike with adding Pokémon, the trainer sprites aren’t sorted in individual folders, but rather in one folder: graphics/trainers/front_pics. Trainers sprites cannot have more than 16 colors - this includes the color that will be transparent, which is the first slot of the palette.

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 by linking the graphic files in src/data/graphics/trainers:

 const u16 gTrainerPalette_RubySapphireBrendan[] = INCBIN_U16("graphics/trainers/palettes/brendan_rs.gbapal");

 const u32 gTrainerFrontPic_RubySapphireMay[] = INCBIN_U32("graphics/trainers/front_pics/may_rs.4bpp.smol");
 const u16 gTrainerPalette_RubySapphireMay[] = INCBIN_U16("graphics/trainers/palettes/may_rs.gbapal");
+
+const u32 gTrainerFrontPic_NewOne[] = INCBIN_U32("graphics/trainers/front_pics/new_one.4bpp.smol");
+const u16 gTrainerPalette_NewOne[] = INCBIN_U16("graphics/trainers/front_pics/new_one.gbapal");

 const u8 gTrainerBackPic_Brendan[] = INCBIN_U8("graphics/trainers/back_pics/brendan.4bpp");

3. Connecting the Pictures to the Data

The last few things we have to do is prepare the graphics for usage. In src/data/graphics/trainers.h you’ll find the gTrainerSprites struct, we need to add the trainer to this. You can just copy the last trainer type defined and edit it, but this is what it does: Connects the new trainer with the image we defined earlier.

So, finally, it needs to look like this:

 #define TRAINER_SPRITE(trainerPic, picFile, paletteFile, ...)                  \
     [trainerPic] =                                                             \
     {                                                                          \
         .frontPic = {picFile, TRAINER_PIC_SIZE, trainerPic},                   \
         .palette = {paletteFile, trainerPic},                                  \
         .mugshotCoords = {DEFAULT(0, __VA_ARGS__), DEFAULT_2(0, __VA_ARGS__)}, \
         .mugshotRotation = DEFAULT_3(0x200, __VA_ARGS__),                      \
     }

 const struct TrainerSprite gTrainerSprites[] =
 {
     TRAINER_SPRITE(TRAINER_PIC_HIKER, gTrainerFrontPic_Hiker, gTrainerPalette_Hiker),
     TRAINER_SPRITE(TRAINER_PIC_AQUA_GRUNT_M, gTrainerFrontPic_AquaGruntM, gTrainerPalette_AquaGruntM),
     ...
     TRAINER_SPRITE(TRAINER_PIC_RS_MAY, gTrainerFrontPic_RubySapphireMay, gTrainerPalette_RubySapphireMay),
+    TRAINER_SPRITE(TRAINER_PIC_NEW_ONE, gTrainerFrontPic_NewOne, gTrainerPalette_NewOne),
 };

The Data

4. Defining the trainer pic

Finally, let’s bring it all together by defining our new trainer pic in include/constants/trainers.h:

 #define TRAINER_PIC_RS_MAY                92
+#define TRAINER_PIC_NEW_ONE               93

 #define TRAINER_BACK_PIC_BRENDAN                0
 #define TRAINER_BACK_PIC_MAY                    1

Remember to count the number next to the trainer pic up by one!

Usage

You can test your trainer type by going to src/data/trainers.party and change the Pic field. The syntax should match the constant (TRAINER_PIC_NEW_ONE) with the underscore replaced by spaces. For example:

 === TRAINER_BRENDAN_PLACEHOLDER ===
 Name: BRENDAN
 Class: RS Protag
-Pic: RS Brendan
+Pic: New One
 Gender: Male
 Music: Male
 Double Battle: No

Otherwise if you use src/data/trainers.h, change the .trainerPic field instead. For example:

     [DIFFICULTY_NORMAL][TRAINER_BRENDAN_PLACEHOLDER] =
     {
         .trainerName = _("BRENDAN"),
         .trainerClass = TRAINER_CLASS_RS_PROTAG,
-        .trainerPic = TRAINER_PIC_RS_BRENDAN,
+        .trainerPic = TRAINER_PIC_NEW_ONE,
         .encounterMusic_gender = TRAINER_ENCOUNTER_MUSIC_MALE,
         .doubleBattle = FALSE,

How to add a new trainer back pic

Content

Quick Summary

If you’ve done this before and just need a quick lookup, here’s what files you need:

  1. Place graphics in graphics/trainers/back_pics.
  2. Point game to where graphic files are found: src/data/graphics/trainers.
  3. Add trainer to include/constants/trainers.h,

The Graphics

1. Add the sprites

We will start with a graphic that we want to use for our new trainer pic. Unlike with adding Pokémon, the trainer sprites aren’t sorted in individual folders, but rather in one folder: graphics/trainers/back_pics. Trainers sprites cannot be more than 16 - this includes the color that will be transparent, which is the first slot of the palette.

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 by linking the graphic files in src/data/graphics/trainers.h:

 const u8 gTrainerBackPic_Wally[] = INCBIN_U8("graphics/trainers/back_pics/wally.4bpp");
 const u8 gTrainerBackPic_Steven[] = INCBIN_U8("graphics/trainers/back_pics/steven.4bpp");
+const u8 gTrainerBackPic_NewOne[] = INCBIN_U8("graphics/trainers/back_pics/new_one.4bpp");

 const u16 gTrainerBackPicPalette_Red[] = INCBIN_U16("graphics/trainers/back_pics/red.gbapal");
 const u16 gTrainerBackPicPalette_Leaf[] = INCBIN_U16("graphics/trainers/back_pics/leaf.gbapal");
+const u16 gTrainerBackPicPalette_NewOne[] = INCBIN_U16("graphics/trainers/back_pics/new_one.gbapal");

3. Connecting the Pictures to the Data

The last few things we have to do is prepare the graphics for usage. In src/data/graphics/trainers.h you’ll find the gTrainerBacksprites struct, we need to add the trainer to this. You can just copy the last trainer type defined and edit it, but this is what it does: Connects the new trainer with the image we defined earlier.

So, finally, it needs to look like this:

 #define TRAINER_BACK_SPRITE(trainerPic, yOffset, sprite, pal, anim)                          \
     [trainerPic] =                                                                           \
     {                                                                                        \
         .coordinates = {.size = 8, .y_offset = yOffset},                                     \
         .backPic = {.data = sprite, .size = TRAINER_PIC_SIZE, .relativeFrames = TRUE},       \
         .palette = {.data = pal, .tag = trainerPic},                                         \
         .animation = anim,                                                                   \
     }

 const struct TrainerBacksprite gTrainerBacksprites[] =
 {
     TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_BRENDAN, 4, gTrainerBackPic_Brendan, gTrainerPalette_Brendan, sBackAnims_Hoenn),
     ...
     TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_STEVEN, 4, gTrainerBackPic_Steven, gTrainerPalette_Steven, sBackAnims_Hoenn),
+    TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_NEW_ONE, 4, gTrainerBackPic_NewOne, gTrainerBackPicPalette_NewOne, sBackAnims_Hoenn),
};

Note: Trainer back pics can have 4 or 5 frames of animation. Trainers with 5 frames must have their yOffset set to 5, and their anim set to sBackAnims_Kanto.

The Data

4. Defining the trainer back pic

Finally, let’s bring it all together by defining our new trainer pic in include/constants/trainers.h:

 #define TRAINER_BACK_PIC_WALLY                  6
 #define TRAINER_BACK_PIC_STEVEN                 7
+#define TRAINER_BACK_PIC_NEW_ONE                8

Remember to count the number next to the trainer pic up by one!

Usage

You can test your new trainer back pic by going to src/data/battle_partners.party and change the Pic field. The syntax should match the constant (TRAINER_BACK_PIC_NEW_ONE) with the underscore replaced by spaces. For example:

 === PARTNER_STEVEN ===
 Name: STEVEN
 Class: Rival
-Pic: Steven
+Pic: New One
 Gender: Male
 Music: Male

Otherwise if you use src/data/battle_partners.h, change the trainerPic field instead. For example:

     [DIFFICULTY_NORMAL][PARTNER_STEVEN] =
     {
         .trainerName = _("STEVEN"),
         .trainerClass = TRAINER_CLASS_RIVAL,
-        .trainerPic = TRAINER_BACK_PIC_STEVEN,
+        .trainerPic = TRAINER_BACK_PIC_NEW_ONE,
         .encounterMusic_gender = TRAINER_ENCOUNTER_MUSIC_MALE,

How to add a new Pokémon

This is a modified version of the original tutorial about adding new Pokémon species available in Pokeemerald’s wiki.

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 onward.

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

You can open a sprite debug menu by pressing Select in a Pokémon’s summary screen outside of battle.

visualizer1

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:

 #define SPECIES_NONE                                    0
 #define SPECIES_BULBASAUR                               1
 ...
 #define SPECIES_MIMIKYU_BUSTED_TOTEM                    1523
 #define SPECIES_MIMIKYU_TOTEM_BUSTED                    SPECIES_MIMIKYU_BUSTED_TOTEM
+#define SPECIES_MEWTHREE                                1524

-#define SPECIES_EGG                                     (SPECIES_MIMIKYU_BUSTED_TOTEM + 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 at the end so that no existing species change Id and so that we don’t have to renumber everything after it.

Now, let’s see how it looks in-game!

visualizer2

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 Mewthree, we also need to understand Mew. Let’s look at its data.

    [SPECIES_MEW] =
    {
        .baseHP        = 100,
        .baseAttack    = 100,
        .baseDefense   = 100,
        .baseSpeed     = 100,
        .baseSpAttack  = 100,
        .baseSpDefense = 100,
        .types = MON_TYPES(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 = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED),
        .abilities = { ABILITY_SYNCHRONIZE, ABILITY_NONE, ABILITY_NONE },
        .bodyColor = BODY_COLOR_PINK,
        .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 = P_GBA_STYLE_SPECIES_GFX ? MON_COORDS_SIZE(40, 40) : MON_COORDS_SIZE(64, 48),
        .frontPicYOffset = P_GBA_STYLE_SPECIES_GFX ? 13 : 9,
        .frontAnimFrames = ANIM_FRAMES(
            ANIMCMD_FRAME(1, 50),
            ANIMCMD_FRAME(1, 40),
            ANIMCMD_FRAME(0, 10),
        ),
        .frontAnimId = P_GBA_STYLE_SPECIES_GFX ? ANIM_SWING_CONVEX : ANIM_ZIGZAG_SLOW,
        .enemyMonElevation = P_GBA_STYLE_SPECIES_GFX ? 8 : 11,
        .backPic = gMonBackPic_Mew,
        .backPicSize = P_GBA_STYLE_SPECIES_GFX ? MON_COORDS_SIZE(48, 48) : MON_COORDS_SIZE(64, 64),
        .backPicYOffset = P_GBA_STYLE_SPECIES_GFX ? 8 : 0,
        .backAnimId = BACK_ANIM_CONCAVE_ARC_SMALL,
        .palette = gMonPalette_Mew,
        .shinyPalette = gMonShinyPalette_Mew,
        .iconSprite = gMonIcon_Mew,
        .iconPalIndex = 0,
        SHADOW(0, 13, SHADOW_SIZE_S)
        FOOTPRINT(Mew)
        OVERWORLD(
            sPicTable_Mew,
            SIZE_32x32,
            SHADOW_SIZE_M,
            TRACKS_NONE,
            sAnimTable_Following,
            gOverworldPalette_Mew,
            gShinyOverworldPalette_Mew
        )
        .isMythical = TRUE,
        .isFrontierBanned = TRUE,
        .perfectIVCount = LEGENDARY_PERFECT_IV_COUNT,
        .levelUpLearnset = sMewLevelUpLearnset,
        .teachableLearnset = sMewTeachableLearnset,
    },

That’s a lot of stuff! But don’t worry, we’ll go through it step by step throughout the tutorial (and it’s miles better than having this same data through 20+ files like it used to be).

Across the species files you’ll see preprocessor instructions such as #if/endif P_FAMILY_MEW. These are used by expansion in order to allow users to disable species via config. Since we’re making a new species from scratch, you DON’T need to add them as part of the process.

You can also ignore switch cases for P_GBA_STYLE_SPECIES_GFX, as those are only used to switching to GBA-styled sprites.

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:

 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 = MON_TYPES(TYPE_PSYCHIC),
+       .catchRate = 3,
+       .expYield = 255,
+       .evYield_SpAttack  = 3,
+       .genderRatio = MON_GENDERLESS,
+       .eggCycles = 120,
+       .friendship = 0,
+       .growthRate = GROWTH_SLOW,
+       .eggGroups = MON_EGG_GROUPS(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.
  • types is using the macro MON_TYPES as a helper function for formatting so that only one type has to be input for species with a single type.
    • To add a species with 2 types, use the format MON_TYPES(TYPE_PSYCHIC, TYPE_NORMAL).
    • 1.9 and earlier: The format for setting types is the following:
      // Mono-type
      .types = { TYPE_PSYCHIC, TYPE_PSYCHIC },
      // Dual-type
      .types = { TYPE_PSYCHIC, TYPE_DARK },
      
  • 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 #ifs, #elifs 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 Eyes 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 for more info.
    • This should be consistent across evolution lines, otherwise levels could change upon evolution.
  • 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 for more info.
    • This is using the helper macro MON_EGG_GROUPS.
    • 1.9 and earlier: The format for setting egg groups is the following:
      // Mono-group
      .eggGroups = { EGG_GROUP_MONSTER, EGG_GROUP_MONSTER },
      // Dual-group
      .eggGroups = { EGG_GROUP_MONSTER, EGG_GROUP_MINERAL },
      
  • 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.
    • 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 and here 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

 const struct SpeciesInfo gSpeciesInfo[] =
 {
     ...
     [SPECIES_MEWTHREE] =
     {
        ...
        .bodyColor = BODY_COLOR_PURPLE,
+       .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.

.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:

enum PokemonCry
{
    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. 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.

	cry Cry_Terapagos
	cry Cry_Pecharunt
+	cry Cry_Mewthree
	cry_reverse Cry_Terapagos
	cry_reverse Cry_Pecharunt
+	cry_reverse Cry_Mewthree

Lastly, we add the cry to our species entry

 const struct SpeciesInfo gSpeciesInfo[] =
 {
     ...
     [SPECIES_MEWTHREE] =
     {
        ...
        .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:

// National Pokedex order
enum NationalDexOrder
{
    NATIONAL_DEX_NONE,
    // Kanto
    NATIONAL_DEX_BULBASAUR,
...
    NATIONAL_DEX_PECHARUNT,
+   NATIONAL_DEX_MEWTHREE,
};
 #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 and give it a HOENN_TO_NATIONAL member, like this:

// Hoenn Pokedex order
enum HoennDexOrder
{
    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:

 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:

 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

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:

 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

The Graphics

We will start by copying the following files for Mew (not Mewtwo) and rename it to mewthree.

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. Note: the icon will use one of 6 predefined palettes instead of normal.pal. Open an icon sprite and load one of the palettes to find out which palette suits your icon sprite best.

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:

#if P_FAMILY_PECHARUNT
    const u32 gMonFrontPic_Pecharunt[] = INCBIN_U32("graphics/pokemon/pecharunt/front.4bpp.lz");
    const u16 gMonPalette_Pecharunt[] = INCBIN_U16("graphics/pokemon/pecharunt/normal.gbapal");
    const u32 gMonBackPic_Pecharunt[] = INCBIN_U32("graphics/pokemon/pecharunt/back.4bpp.lz");
    const u16 gMonShinyPalette_Pecharunt[] = INCBIN_U16("graphics/pokemon/pecharunt/shiny.gbapal");
    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
#if OW_POKEMON_OBJECT_EVENTS
    const u32 gObjectEventPic_Pecharunt[] = INCBIN_COMP("graphics/pokemon/pecharunt/overworld.4bpp");
#if OW_PKMN_OBJECTS_SHARE_PALETTES == FALSE
    const u16 gOverworldPalette_Pecharunt[] = INCBIN_U16("graphics/pokemon/pecharunt/overworld_normal.gbapal");
    const u16 gShinyOverworldPalette_Pecharunt[] = INCBIN_U16("graphics/pokemon/pecharunt/overworld_shiny.gbapal");
#endif //OW_PKMN_OBJECTS_SHARE_PALETTES
#endif //OW_POKEMON_OBJECT_EVENTS
#endif //P_FAMILY_PECHARUNT

    const u32 gMonFrontPic_Egg[] = INCBIN_U32("graphics/pokemon/egg/anim_front.4bpp.lz");
    const u16 gMonPalette_Egg[] = INCBIN_U16("graphics/pokemon/egg/normal.gbapal");
    const u8 gMonIcon_Egg[] = INCBIN_U8("graphics/pokemon/egg/icon.4bpp");

+   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 u16 gMonPalette_Mewthree[] = INCBIN_U16("graphics/pokemon/mewthree/normal.gbapal");
+   const u16 gMonShinyPalette_Mewthree[] = INCBIN_U16("graphics/pokemon/mewthree/shiny.gbapal");
+   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.

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.

Version 1.11.0 or later

We add this data directly to the entry, so go to section 4.

Version 1.10.3 or earlier

Edit src/data/pokemon_graphics/front_pic_anims.h:

#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,
+};
#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:

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):

#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:

 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 = ANIM_FRAMES(
+           ANIMCMD_FRAME(0, 1),
+       ),
+       .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 define our animation frame animations directly here. In version 1.10.3 and earlier, we add the reference to the table that we defined earlier here like this instead:
      +       .frontAnimFrames = sAnims_Mewthree,
      
  • frontAnimId:
  • 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.
    • NOTE: Mew has a tarnary switch here in order to change values depending on if a config option is set for displaying th original Gen 3 sprites.
  • 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 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:
    • 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.
  • 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).
      #if P_FOOTPRINTS
      #define FOOTPRINT(sprite) .footprint = gMonFootprint_## sprite,
      #else
      #define FOOTPRINT(sprite)
      #endif
      

*NOTE: In v1.7.x only, there were macros that set multiple of these fields. However, they were considered clunky to use, so they were removed in v1.8. - FRONT_PIC: For frontPic and frontPicSize. - BACK_PIC: For backPic and backPicSize. - PALETTES: For palette and shinyPalette. - ICON: For iconSprite and iconPalIndex.

The Data - Part 2

We’re almost there just a bit left!

1. Species Flags

 const struct SpeciesInfo gSpeciesInfo[] =
 {
     ...
     [SPECIES_MEWTHREE] =
     {
        ...
        .abilities = { ABILITY_INSOMNIA, ABILITY_NONE, ABILITY_NONE },
        .bodyColor = BODY_COLOR_PURPLE,
+       .isLegendary = TRUE,
+       .perfectIVCount = LEGENDARY_PERFECT_IV_COUNT,
    },
 };

Each species flag provides properties to the species:

  • perfectIVCount (1.10 onwards):
    • Guarantees that the number of IVs specified here will be perfect.
  • isLegendary:
    • 1.10 onwards: Does nothing.
    • 1.9 and earlier: Guaranteed 3 perfect IVs for the species.
  • isMythical:
    • Is skipped during Pokédex evaluations.
      • Unless it also has the dexForceRequired flag.
    • Cannot obtain Gigantamax factor via ToggleGigantamaxFactor.
    • 1.9 and earlier: Guaranteed 3 perfect IVs for the species.
  • isUltraBeast:
    • Beast Ball’s multiplier is set to x5 for this species.
      • All other ball multipliers are set to x0.1.
    • 1.9 and earlier: Guaranteed 3 perfect IVs for the species.
  • isParadox (isParadoxForm previous to 1.9):
    • 1.10 onwards: Makes it so that Booster Energy cannot be knocked off.
    • 1.9 and earlier: Does nothing.
  • isTotem:
    • 1.10 onwards: Does nothing.
    • 1.9 and earlier: Guaranteed 3 perfect IVs for the species.
  • 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:
    • 1.10.3 onwards: Used to determine breeding offspring from different parents based on their region.
    • 1.10.2 and earlier: Does nothing.
  • cannotBeTraded:
    • This species cannot be traded away (like Black/White Kyurem).
  • tmIlliterate:
    • This species will be unable to learn the universal TM or Tutor moves.
  • isFrontierBanned (1.9 onwards):
    • This species will be unable to enter Battle Frontier facilities. Replaces gFrontierBannedSpecies.

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/gen_9.h: NOTE: You can ignore the warning at the top of the file if you’re just adding moves to Pokemon.

#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
+};

NOTE: If P_LVL_UP_LEARNSETS is not set to something equal to GEN_9, the file to be edited will change to what’s specified.

Again, we need to register the learnset in gSpeciesInfo:

 const struct SpeciesInfo gSpeciesInfo[] =
 {
     ...
     [SPECIES_MEWTHREE] =
     {
        ...
        .palette = gMonPalette_Mewthree,
        .shinyPalette = gMonShinyPalette_Mewthree,
        .iconSprite = gMonIcon_Mewthree,
        .iconPalIndex = 2,
+       .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:

#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

NOTE: At the top of this file, you will probably see this warning:

//
// DO NOT MODIFY THIS FILE! It is auto-generated from tools/learnset_helpers/teachable.py`
//

From version 1.9 onwards, pokeemerald-expansion includes a tool called the learnset helper, which aims to automate the generation of valid teachable moves. At the time of writing, this tool only supports generating TM and Tutor learnsets. However, in the future it may be expanded to deal with level up learnsets and egg moves.

Ignore the warning shown above the first time you’re adding your teachable moves (as otherwise the compiler will complain about the array not existing), but in the future (if you’re using the learnset helper) simply edit what teachable moves your Pokémon can learn in one of the JSON files found in tools/learnset_helpers/porymoves_files. It doesn’t really matter which one you add your new Pokémon to, as the tool pulls from all of the files in this folder.

The learnset helper is useful if you plan on changing and/or increasing the available TMs and Tutor moves in your game. As an example, Bulbasaur learns Rage by TM in Red/Blue/Yellow, but in Emerald this TM does not exist. But since tools/learnset_helpers/porymoves_files/rby.json defines “MOVE_RAGE” as a TM move for Bulbasaur, that move would automatically be added to the sBulbasaurTeachableLearnset array if you were to add a Rage TM at any point.

The learnset helper can be toggled on/off in include/config/pokemon.h:

// Learnset helper toggles
#define P_LEARNSET_HELPER_TEACHABLE TRUE        // If TRUE, teachable_learnsets.h will be populated by tools/learnset_helpers/teachable.py using the included JSON files based on available TMs and tutors.

Once more, we need to register the learnset in gSpeciesInfo:

 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.

3. Define the Evolutions

We want Mewthree to evolve from Mewtwo by reaching level 100.

Edit gSpeciesInfo:

 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:

         {
           "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:

#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 for each form in gSpeciesInfo.

    [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.:

hgssdex1 image

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:

    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.

#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

gender_diffs

You may have seen that there’s a couple of duplicate fields with a “Female” suffix.

    [SPECIES_FRILLISH] =
    {
        ...
        .frontPic = gMonFrontPic_Frillish,
        .frontPicSize = MON_COORDS_SIZE(56, 56),
        .frontPicYOffset = 5,
        .frontAnimFrames = ANIM_FRAMES(
            ANIMCMD_FRAME(1, 30),
            ANIMCMD_FRAME(0, 30),
            ANIMCMD_FRAME(1, 30),
            ANIMCMD_FRAME(0, 30),
        ),
        .frontAnimId = ANIM_RISING_WOBBLE,
        .backPic = gMonBackPic_Frillish,
        .backPicSize = MON_COORDS_SIZE(40, 56),
        .backPicYOffset = 7,
        .backAnimId = BACK_ANIM_CONVEX_DOUBLE_ARC,
        .palette = gMonPalette_Frillish,
        .shinyPalette = gMonShinyPalette_Frillish,
        .iconSprite = gMonIcon_Frillish,
        .iconPalIndex = 0,
+#if P_GENDER_DIFFERENCES
+       .frontPicFemale = gMonFrontPic_FrillishF,
+       .frontPicSizeFemale = MON_COORDS_SIZE(56, 56),
+       .backPicFemale = gMonBackPic_FrillishF,
+       .backPicSizeFemale = MON_COORDS_SIZE(40, 56),
+       .paletteFemale = gMonPalette_FrillishF,
+       .shinyPaletteFemale = gMonShinyPalette_FrillishF,
+       .iconSpriteFemale = gMonIcon_FrillishF,
+       .iconPalIndexFemale = 1,
+#endif //P_GENDER_DIFFERENCES
        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 (v1.9 onwards)

If you have OW_POKEMON_OBJECT_EVENTS in your hack, you can add Overworld sprite data of your new species. Naturally, these can also be used for followers.

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, add the following:

    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

$(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:

#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:

 const struct SpeciesInfo gSpeciesInfo[] =
 {
     ...
     [SPECIES_MEWTHREE] =
     {
        ...
        FOOTPRINT(Mewthree)
+       OVERWORLD(
+           sPicTable_Mewthree,
+           SIZE_32x32,
+           SHADOW_SIZE_M,
+           TRACKS_FOOT,
+           sAnimTable_Following,
+           gOverworldPalette_Mewthree,
+           gShinyOverworldPalette_Mewthree
+       )
        .levelUpLearnset = sMewthreeLevelUpLearnset,
        .teachableLearnset = sMewthreeTeachableLearnset,
    },
 };

Note: In versions previous to 1.11, sAnimTable_Following is not added here.

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
  • SHADOW_SIZE_M shadow_medium
  • SHADOW_SIZE_L shadow_large

Tracks

You have 4 options for the tracks that your species will leave behind on sand.

  • TRACKS_NONE
  • TRACKS_FOOT sand_footprints
  • TRACKS_SLITHER slither_tracks
  • TRACKS_SPOT spot_tracks
  • TRACKS_BUG bug_tracks

…though technically you can also use TRACKS_BIKE_TIRE if you wish to.

bike_tire_tracks

Asymmetric sprites (Version 1.10.0 onwards)

scovillain

You can set up an east-west asymetric overworld sprite by adding the East frames at the end of the sheet and changing the following:

Version 1.11.0 onwards

        OVERWORLD(
            sPicTable_Mewthree,
            SIZE_32x32,
            SHADOW_SIZE_M,
            TRACKS_FOOT,
-           sAnimTable_Following,
+           sAnimTable_Following_Asym,
            gOverworldPalette_Mewthree,
            gShinyOverworldPalette_Mewthree
        )

Version 1.10.x

-       OVERWORLD(
+       OVERWORLD_SET_ANIM(
            sPicTable_Mewthree,
            SIZE_32x32,
            SHADOW_SIZE_M,
            TRACKS_FOOT,
+           sAnimTable_Following_Asym,
            gOverworldPalette_Mewthree,
            gShinyOverworldPalette_Mewthree
        )

Either way, you may also create custom animation tables and use them here appropiately.

How to add the Pokémon Object Events to map

In Porymap, select the object you want to set the sprite to. Then, change the field “Sprite” to use OBJ_EVENT_GFX_SPECIES(SPECIES), replacing SPECIES with the name of the species you want to use. If you get a compiler error, it’s because it used the species define as part of the macro, so it needs to match how you defined it all the way back in Declare a species constant. charizard overworld_data

If you want to use their shiny and/or female versions, use one of the following macros:

  • OBJ_EVENT_GFX_SPECIES_SHINY(name)
  • OBJ_EVENT_GFX_SPECIES_FEMALE(name)
  • OBJ_EVENT_GFX_SPECIES_SHINY_FEMALE(name)

5. In-battle shadows (v1.10 onwards)

Gen 4-style shadows are defined by the SHADOW macro which takes the following arguments:

  • X offset
  • Y offset
  • Shadow size: you have 4 options for their shadow, between Small, Medium, Large and Extra Large:
    • SHADOW_SIZE_S
    • SHADOW_SIZE_M
    • SHADOW_SIZE_L
    • SHADOW_SIZE_XL_BATTLE_ONLY

To make the Pokémon have no shadow, use the NO_SHADOW macro instead of SHADOW.

6. Limiting species allowed as followers

You may use the following configs in include/config/overworld.h

#define OW_FOLLOWERS_ALLOWED_SPECIES (0)
#define OW_FOLLOWERS_ALLOWED_MET_LVL (0)
#define OW_FOLLOWERS_ALLOWED_MET_LOC (0)

Examples:

// Yellow Pikachu:
#define OW_FOLLOWERS_ALLOWED_SPECIES (SPECIES_PIKACHU)
#define OW_FOLLOWERS_ALLOWED_MET_LVL (0)
#define OW_FOLLOWERS_ALLOWED_MET_LOC (MAPSEC_PALLET_TOWN)
// Hoenn Starter:
#define OW_FOLLOWERS_ALLOWED_SPECIES (0)
#define OW_FOLLOWERS_ALLOWED_MET_LVL (5)
#define OW_FOLLOWERS_ALLOWED_MET_LOC (MAPSEC_ROUTE_101)
// Species set in VAR_XXXX:
#define OW_FOLLOWERS_ALLOWED_SPECIES (VAR_XXXX)
#define OW_FOLLOWERS_ALLOWED_MET_LVL (0)
#define OW_FOLLOWERS_ALLOWED_MET_LOC (0)

v1.6.x and earlier

This is a modified version of the original tutorial about adding new Pokémon species available in Pokeemerald’s wiki.

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.

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

We will start by copying the folder containing the sprites for Mewtwo and rename it to mewthree (pretty meta huh?):

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:

 extern const u32 gMonFrontPic_Calyrex[];
+extern const u32 gMonFrontPic_Mewthree[];
 extern const u32 gMonBackPic_Calyrex[];
+extern const u32 gMonBackPic_Mewthree[];
 extern const u32 gMonPalette_Calyrex[];
+extern const u32 gMonPalette_Mewthree[];
 extern const u32 gMonShinyPalette_Calyrex[];
+extern const u32 gMonShinyPalette_Mewthree[];
 //extern const u8 gMonIcon_Calyrex[];
+extern const u8 gMonIcon_Mewthree[];
 extern const u8 gMonFootprint_Calyrex[];
+extern const u8 gMonFootprint_Mewthree[];

Now link the graphic files.

Edit src/data/graphics/pokemon.h:

 const u32 gMonFrontPic_Calyrex[] = INCBIN_U32("graphics/pokemon/calyrex/front.4bpp.lz");
+const u32 gMonFrontPic_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/front.4bpp.lz");
 const u32 gMonBackPic_Calyrex[] = INCBIN_U32("graphics/pokemon/calyrex/back.4bpp.lz");
+const u32 gMonBackPic_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/back.4bpp.lz");
 const u32 gMonPalette_Calyrex[] = INCBIN_U32("graphics/pokemon/calyrex/normal.gbapal.lz");
+const u32 gMonPalette_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/normal.gbapal.lz");
 const u32 gMonShinyPalette_Calyrex[] = INCBIN_U32("graphics/pokemon/calyrex/shiny.gbapal.lz");
+const u32 gMonShinyPalette_Mewthree[] = INCBIN_U32("graphics/pokemon/mewthree/shiny.gbapal.lz");
 //const u8 gMonIcon_Calyrex[] = INCBIN_U8("graphics/pokemon/calyrex/icon.4bpp");
+const u8 gMonIcon_Mewthree[] = INCBIN_U8("graphics/pokemon/mewthree/icon.4bpp");
 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:

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
SINGLE_ANIMATION(Enamorus);
+SINGLE_ANIMATION(Mewthree);
#endif
 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, describing translations, rotations, scalings or color changes.

Edit src/pokemon.c:

 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 for the back sprites as well.

Edit src/pokemon_animation.c:

 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:

 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:

 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:

 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:

 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:

 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:

 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:

 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:

 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:

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:

 const u8 *const gMonIconTable[] =
 {
     [SPECIES_NONE] = gMonIcon_Bulbasaur,
     ...
    [SPECIES_ENAMORUS] = gMonIcon_Enamorus,
+   [SPECIES_MEWTHREE] = gMonIcon_Mewthree,
#endif
     ...
 };
 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:

 #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:

 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:

// National Pokedex order
enum {
    NATIONAL_DEX_NONE,
    // Kanto
    NATIONAL_DEX_BULBASAUR,
...
    NATIONAL_DEX_ENAMORUS,
+   NATIONAL_DEX_MEWTHREE,
};
 #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:

// 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:

 // 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:

 // 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),
 };
 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:

 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:

 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 and weight respectively in the appendix.

Edit src/data/pokemon/pokedex_orders.h:

 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:

 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 and here src/data/text/abilities.h.

You can also incorporate a 3rd ability to your species, which is intended to be a Hidden Ability!

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:

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:

 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:

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:

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.

6. Define its cry

First run these command to copy the Mewtwo sound files:

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.

    .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. cry_reverse in particular is for reversed cries used by moves such as Growl.

...
    cry Cry_Enamorus
+   cry Cry_Mewthree
.else
    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

Higher frequencies may be ruined by compression. To have the cries uncompressed, follow this , 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:

    [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:

 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:

         {
           "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

Pokemonheight (m)
Diglett0.2
Natu0.2
Azurill0.2
Caterpie0.3
Weedle0.3
Pidgey0.3
Rattata0.3
Spearow0.3
Paras0.3
Magnemite0.3
Shellder0.3
Ditto0.3
Eevee0.3
Pichu0.3
Cleffa0.3
Igglybuff0.3
Togepi0.3
Sunkern0.3
Wurmple0.3
Taillow0.3
Roselia0.3
Castform0.3
Jirachi0.3
Pikachu0.4
Nidoran_f0.4
Meowth0.4
Geodude0.4
Krabby0.4
Exeggcute0.4
Cubone0.4
Horsea0.4
Omanyte0.4
Mew0.4
Bellossom0.4
Marill0.4
Hoppip0.4
Wooper0.4
Swinub0.4
Smoochum0.4
Torchic0.4
Mudkip0.4
Zigzagoon0.4
Ralts0.4
Shroomish0.4
Aron0.4
Plusle0.4
Minun0.4
Gulpin0.4
Cacnea0.4
Swablu0.4
Barboach0.4
Clamperl0.4
Squirtle0.5
Nidoran_m0.5
Jigglypuff0.5
Oddish0.5
Mankey0.5
Voltorb0.5
Kabuto0.5
Cyndaquil0.5
Spinarak0.5
Chinchou0.5
Murkrow0.5
Unown0.5
Qwilfish0.5
Phanpy0.5
Treecko0.5
Poochyena0.5
Linoone0.5
Lotad0.5
Seedot0.5
Surskit0.5
Nincada0.5
Sableye0.5
Torkoal0.5
Baltoy0.5
Charmander0.6
Kakuna0.6
Sandshrew0.6
Clefairy0.6
Vulpix0.6
Poliwag0.6
Koffing0.6
Goldeen0.6
Totodile0.6
Togetic0.6
Mareep0.6
Skiploom0.6
Pineco0.6
Snubbull0.6
Shuckle0.6
Teddiursa0.6
Corsola0.6
Remoraid0.6
Houndour0.6
Porygon20.6
Elekid0.6
Larvitar0.6
Celebi0.6
Silcoon0.6
Wingull0.6
Whismur0.6
Skitty0.6
Mawile0.6
Meditite0.6
Electrike0.6
Illumise0.6
Corphish0.6
Feebas0.6
Shuppet0.6
Chimecho0.6
Wynaut0.6
Luvdisc0.6
Bagon0.6
Beldum0.6
Bulbasaur0.7
Metapod0.7
Raticate0.7
Dugtrio0.7
Growlithe0.7
Bellsprout0.7
Hoothoot0.7
Misdreavus0.7
Slugma0.7
Tyrogue0.7
Magby0.7
Marshtomp0.7
Cascoon0.7
Swellow0.7
Volbeat0.7
Numel0.7
Spoink0.7
Trapinch0.7
Anorith0.7
Snorunt0.7
Raichu0.8
Nidorina0.8
Zubat0.8
Gloom0.8
Psyduck0.8
Machop0.8
Farfetchd0.8
Staryu0.8
Jolteon0.8
Porygon0.8
Sentret0.8
Flaaffy0.8
Azumarill0.8
Jumpluff0.8
Aipom0.8
Sunflora0.8
Magcargo0.8
Kirlia0.8
Masquerain0.8
Slakoth0.8
Ninjask0.8
Shedinja0.8
Carvanha0.8
Duskull0.8
Spheal0.8
Nidorino0.9
Abra0.9
Tentacool0.9
Grimer0.9
Magikarp0.9
Flareon0.9
Chikorita0.9
Quilava0.9
Espeon0.9
Sneasel0.9
Octillery0.9
Delibird0.9
Grovyle0.9
Combusken0.9
Lairon0.9
Grumpig0.9
Whiscash0.9
Ivysaur1.0
Wartortle1.0
Beedrill1.0
Sandslash1.0
Wigglytuff1.0
Parasect1.0
Venonat1.0
Persian1.0
Primeape1.0
Poliwhirl1.0
Weepinbell1.0
Graveler1.0
Ponyta1.0
Magneton1.0
Drowzee1.0
Marowak1.0
Rhyhorn1.0
Tangela1.0
Vaporeon1.0
Omastar1.0
Ledyba1.0
Umbreon1.0
Mightyena1.0
Beautifly1.0
Nuzleaf1.0
Loudred1.0
Makuhita1.0
Nosepass1.0
Lunatone1.0
Lileep1.0
Kecleon1.0
Relicanth1.0
Charmeleon1.1
Butterfree1.1
Pidgeotto1.1
Ninetales1.1
Seel1.1
Chansey1.1
Starmie1.1
Electabuzz1.1
Croconaw1.1
Ariados1.1
Politoed1.1
Gligar1.1
Piloswine1.1
Donphan1.1
Delcatty1.1
Spinda1.1
Vibrava1.1
Altaria1.1
Crawdaunt1.1
Banette1.1
Sealeo1.1
Shelgon1.1
Fearow1.2
Vileplume1.2
Slowpoke1.2
Muk1.2
Electrode1.2
Lickitung1.2
Weezing1.2
Seadra1.2
Bayleef1.2
Lanturn1.2
Sudowoodo1.2
Yanma1.2
Forretress1.2
Smeargle1.2
Miltank1.2
Pupitar1.2
Dustox1.2
Lombre1.2
Pelipper1.2
Breloom1.2
Solrock1.2
Absol1.2
Metang1.2
Nidoqueen1.3
Clefable1.3
Poliwrath1.3
Kadabra1.3
Gastly1.3
Kingler1.3
Seaking1.3
Mr_mime1.3
Magmar1.3
Kabutops1.3
Wobbuffet1.3
Shiftry1.3
Medicham1.3
Cacturne1.3
Zangoose1.3
Nidoking1.4
Golem1.4
Doduo1.4
Hitmonchan1.4
Jynx1.4
Tauros1.4
Ledian1.4
Ampharos1.4
Quagsire1.4
Granbull1.4
Houndoom1.4
Stantler1.4
Hitmontop1.4
Vigoroth1.4
Walrein1.4
Latias1.4
Pidgeot1.5
Venomoth1.5
Alakazam1.5
Machoke1.5
Cloyster1.5
Gengar1.5
Hitmonlee1.5
Scyther1.5
Pinsir1.5
Xatu1.5
Girafarig1.5
Dunsparce1.5
Heracross1.5
Blissey1.5
Swampert1.5
Ludicolo1.5
Exploud1.5
Manectric1.5
Claydol1.5
Cradily1.5
Armaldo1.5
Glalie1.5
Salamence1.5
Blastoise1.6
Golbat1.6
Machamp1.6
Tentacruel1.6
Slowbro1.6
Haunter1.6
Hypno1.6
Zapdos1.6
Noctowl1.6
Gardevoir1.6
Dusclops1.6
Metagross1.6
Charizard1.7
Golduck1.7
Victreebel1.7
Rapidash1.7
Dewgong1.7
Articuno1.7
Typhlosion1.7
Skarmory1.7
Sceptile1.7
Swalot1.7
Huntail1.7
Regirock1.7
Deoxys1.7
Dodrio1.8
Aerodactyl1.8
Dratini1.8
Meganium1.8
Furret1.8
Crobat1.8
Scizor1.8
Ursaring1.8
Kingdra1.8
Sharpedo1.8
Gorebyss1.8
Regice1.8
Arcanine1.9
Rhydon1.9
Raikou1.9
Blaziken1.9
Camerupt1.9
Registeel1.9
Venusaur2.0
Ekans2.0
Exeggutor2.0
Moltres2.0
Mewtwo2.0
Slowking2.0
Suicune2.0
Tyranitar2.0
Slaking2.0
Wailmer2.0
Flygon2.0
Tropius2.0
Latios2.0
Snorlax2.1
Mantine2.1
Entei2.1
Aggron2.1
Kangaskhan2.2
Dragonite2.2
Feraligatr2.3
Hariyama2.3
Lapras2.5
Seviper2.7
Arbok3.5
Groudon3.5
Ho_oh3.8
Dragonair4.0
Kyogre4.5
Lugia5.2
Milotic6.2
Gyarados6.5
Rayquaza7.0
Onix8.8
Steelix9.2
Wailord14.5

Pokémon ordered by weight

Pokemonweight (kg)
Gastly0.1
Haunter0.1
Hoppip0.5
Diglett0.8
Castform0.8
Igglybuff1.0
Koffing1.0
Skiploom1.0
Chimecho1.0
Misdreavus1.0
Jirachi1.1
Swablu1.2
Shedinja1.2
Togepi1.5
Surskit1.7
Pidgey1.8
Sunkern1.8
Barboach1.9
Natu2.0
Azurill2.0
Spearow2.0
Pichu2.0
Roselia2.0
Murkrow2.1
Taillow2.3
Shuppet2.3
Exeggcute2.5
Torchic2.5
Lotad2.6
Caterpie2.9
Cleffa3.0
Jumpluff3.0
Weedle3.2
Togetic3.2
Dratini3.3
Rattata3.5
Wurmple3.6
Masquerain3.6
Qwilfish3.9
Shellder4.0
Ditto4.0
Mew4.0
Seedot4.0
Bellsprout4.0
Meowth4.2
Plusle4.2
Minun4.2
Shroomish4.5
Unown5.0
Treecko5.0
Corsola5.0
Celebi5.0
Spinda5.0
Paras5.4
Oddish5.4
Jigglypuff5.5
Nincada5.5
Bellossom5.8
Magnemite6.0
Pikachu6.0
Smoochum6.0
Sentret6.0
Chikorita6.4
Weepinbell6.4
Eevee6.5
Krabby6.5
Cubone6.5
Swinub6.5
Ralts6.6
Bulbasaur6.9
Ekans6.9
Nidoran_f7.0
Pineco7.2
Feebas7.4
Omanyte7.5
Clefairy7.5
Zubat7.5
Mudkip7.6
Mareep7.8
Snubbull7.8
Cyndaquil7.9
Horsea8.0
Marill8.5
Wooper8.5
Spinarak8.5
Charmander8.5
Sunflora8.5
Gloom8.6
Luvdisc8.7
Teddiursa8.8
Squirtle9.0
Nidoran_m9.0
Totodile9.5
Wingull9.5
Weezing9.5
Vulpix9.9
Metapod9.9
Kakuna10.0
Silcoon10.0
Magikarp10.0
Gulpin10.3
Voltorb10.4
Houndour10.8
Ledyba10.8
Sableye11.0
Skitty11.0
Meditite11.2
Kabuto11.5
Mawile11.5
Corphish11.5
Cascoon11.5
Aipom11.5
Chinchou12.0
Sandshrew12.0
Remoraid12.0
Ninjask12.0
Wigglytuff12.0
Poliwag12.4
Anorith12.5
Banette12.5
Venomoth12.5
Ivysaur13.0
Flaaffy13.3
Poochyena13.6
Wynaut14.0
Dunsparce14.0
Goldeen15.0
Trapinch15.0
Farfetchd15.0
Duskull15.0
Xatu15.0
Electrike15.2
Vibrava15.3
Victreebel15.5
Bayleef15.8
Delibird16.0
Whismur16.3
Dragonair16.5
Snorunt16.8
Zigzagoon17.5
Illumise17.7
Volbeat17.7
Raticate18.5
Vileplume18.6
Growlithe19.0
Quilava19.0
Charmeleon19.0
Machop19.5
Nidorino19.5
Abra19.5
Combusken19.5
Psyduck19.6
Swellow19.8
Ninetales19.9
Geodude20.0
Nidorina20.0
Poliwhirl20.0
Kirlia20.2
Shuckle20.5
Altaria20.6
Carvanha20.8
Tyrogue21.0
Hoothoot21.2
Magby21.4
Baltoy21.5
Grovyle21.6
Kecleon22.0
Wartortle22.5
Lanturn22.5
Gorebyss22.6
Relicanth23.4
Elekid23.5
Whiscash23.6
Lileep23.8
Numel24.0
Slakoth24.0
Jolteon24.5
Flareon25.0
Croconaw25.0
Seadra25.0
Espeon26.5
Umbreon27.0
Huntail27.0
Mankey28.0
Marshtomp28.0
Sneasel28.0
Nuzleaf28.0
Pelipper28.0
Beautifly28.4
Azumarill28.5
Octillery28.5
Wobbuffet28.5
Vaporeon29.0
Beedrill29.5
Sandslash29.5
Parasect29.5
Raichu30.0
Grimer30.0
Venonat30.0
Ponyta30.0
Pidgeotto30.0
Electabuzz30.0
Muk30.0
Spoink30.6
Dusclops30.6
Medicham31.5
Dustox31.6
Persian32.0
Primeape32.0
Butterfree32.0
Drowzee32.4
Linoone32.5
Porygon232.5
Lombre32.5
Furret32.5
Delcatty32.6
Crawdaunt32.8
Dugtrio33.3
Phanpy33.5
Ariados33.5
Politoed33.9
Staryu34.5
Chansey34.6
Slugma35.0
Tangela35.0
Omastar35.0
Houndoom35.0
Ledian35.6
Slowpoke36.0
Porygon36.5
Mightyena37.0
Fearow38.0
Sudowoodo38.0
Yanma38.0
Seaking39.0
Breloom39.2
Doduo39.2
Spheal39.5
Pidgeot39.5
Clefable40.0
Latias40.0
Manectric40.2
Zangoose40.3
Loudred40.5
Kabutops40.5
Gengar40.5
Jynx40.6
Noctowl40.8
Girafarig41.5
Bagon42.1
Magmar44.5
Marowak45.0
Tentacool45.5
Vigoroth46.5
Blissey46.8
Absol47.0
Hitmontop48.0
Alakazam48.0
Gardevoir48.4
Granbull48.7
Hitmonlee49.8
Hitmonchan50.2
Skarmory50.5
Cacnea51.3
Blaziken52.0
Sceptile52.2
Clamperl52.5
Seviper52.5
Zapdos52.6
Poliwrath54.0
Heracross54.0
Mr_mime54.5
Magcargo55.0
Pinsir55.0
Ludicolo55.0
Golbat55.0
Tentacruel55.0
Articuno55.4
Piloswine55.8
Scyther56.0
Kadabra56.5
Smeargle58.0
Aerodactyl59.0
Shiftry59.6
Aron60.0
Magneton60.0
Nidoqueen60.0
Kingler60.0
Moltres60.0
Latios60.0
Cradily60.4
Deoxys60.8
Ampharos61.5
Nidoking62.0
Gligar64.8
Arbok65.0
Lickitung65.5
Electrode66.6
Armaldo68.2
Machoke70.5
Stantler71.2
Grumpig71.5
Larvitar72.0
Quagsire75.0
Crobat75.0
Miltank75.5
Hypno75.6
Golduck76.6
Cacturne77.4
Slowbro78.5
Typhlosion79.5
Slowking79.5
Starmie80.0
Swalot80.0
Kangaskhan80.0
Torkoal80.4
Swampert81.9
Flygon82.0
Exploud84.0
Dodrio85.2
Blastoise85.5
Makuhita86.4
Sealeo87.6
Tauros88.4
Sharpedo88.8
Feraligatr88.8
Seel90.0
Charizard90.5
Rapidash95.0
Beldum95.2
Nosepass97.0
Venusaur100.0
Tropius100.0
Meganium100.5
Salamence102.6
Graveler105.0
Claydol108.0
Shelgon110.5
Rhyhorn115.0
Scizor118.0
Lairon120.0
Donphan120.0
Dewgong120.0
Rhydon120.0
Exeggutor120.0
Mewtwo122.0
Forretress125.8
Ursaring125.8
Machamp130.0
Wailmer130.0
Slaking130.5
Cloyster132.5
Walrein150.6
Pupitar152.0
Kingdra152.0
Solrock154.0
Arcanine155.0
Milotic162.0
Lunatone168.0
Regice175.0
Raikou178.0
Suicune187.0
Entei198.0
Ho_oh199.0
Tyranitar202.0
Metang202.5
Registeel205.0
Rayquaza206.5
Dragonite210.0
Onix210.0
Lugia216.0
Camerupt220.0
Mantine220.0
Lapras220.0
Regirock230.0
Gyarados235.0
Hariyama253.8
Glalie256.5
Golem300.0
Kyogre352.0
Aggron360.0
Wailord398.0
Steelix400.0
Snorlax460.0
Metagross550.0
Groudon950.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

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(GetMoveEffect(MOVE_STUN_SPORE) == 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("The opposing Wobbuffet is paralyzed, so 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(IsPowderMove(MOVE_STUN_SPORE));
        ASSUME(GetSpeciesType(SPECIES_ODDISH, 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 the opposing 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(GetMoveCategory(MOVE_TACKLE) == 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(GetMoveCategory(MOVE_WHATEVER) == 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(GetMoveEffect(MOVE_POISON_STING) == EFFECT_POISON_HIT);
}

SINGLE_BATTLE_TEST

SINGLE_BATTLE_TEST(name, results...), DOUBLE_BATTLE_TEST(name, results...), MULTI_BATTLE_TEST(name, results...), TWO_VS_ONE_BATTLE_TEST(name, results...), and ONE_VS_TWO_BATTLE_TEST(name, results...) Define single-, double-, 2v2-multi-, 2v1-multi-, and 1v2- 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, 2v2, 2v1, and 1v2 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...), AI_DOUBLE_BATTLE_TEST(name, results...), AI_MULTI_BATTLE_TEST(name, results...), AI_TWO_VS_ONE_BATTLE_TEST(name, results...), and AI_ONE_VS_TWO_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, DOUBLE, MULTI, TWO_VS_ONE, and ONE_VS_TWO 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(GetMoveType(MOVE_EMBER) == 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 couldn't move because it's paralyzed!");
    }
}

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(GetMoveAccuracy(move), 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.

MULTI_PLAYER, MULTI_PARTNER, MULTI_OPPONENT_A, and MULTI_OPPONENT_B

For tests using MULTI_BATTLE_TEST, AI_MULTI_BATTLE_TEST, TWO_VS_ONE_BATTLE_TEST, AI_TWO_VS_ONE_BATTLE_TEST, ONE_VS_TWO_BATTLE_TEST, and AI_ONE_VS_TWO_BATTLE_TEST, the below must be used instead of PLAYER(species) and OPPONENT(species). MULTI_PLAYER(species), MULTI_PARTNER(species), MULTI_OPPONENT_A(species), and MULTI_OPPONENT_B(species) Adds the species to the player’s, player partner’s, opponent A’s, or opponent B’s party, respectively. Pokemon can be customised as per the guidance for PLAYER(species) and OPPONENT(species). The functions assign the Pokémon to the party of the trainer at B_POSITION_PLAYER_LEFT, B_POSITION_PLAYER_RIGHT, B_POSITION_OPPONENT_LEFT, and B_POSITION_OPPONENT_RIGHT, respectively. MULTI_PLAYER(species) and MULTI_OPPONENT_A(species) set Pokémon starting at party index 0, while MULTI_PARTNER(species) and MULTI_OPPONENT_B(species) set Pokémon starting at party index 3. For ONE_VS_TWO tests, MULTI_PLAYER(species) must be used for all player-side Pokémon, and for TWO_VS_ONE tests, MULTI_OPPONENT_A(species) must be used for all opponent-side Pokémon. All MULTI_PLAYER(species) Pokémon must be set before any MULTI_PARTNER(species) Pokémon, and all MULTI_OPPONENT_A(species) must be set before any MULTI_OPPONENT_B(species) Pokémon, else Pokémon will be set in the incorrect parties in the test. Note where a side in a test has two trainers, the test setup manages the assigning of correct multi-party orders, therefore when using functions such as SEND_OUT, Player and Opponent A Pokémon may be referenced using indexes 0, 1, and 2, and Player’s Partner and Opponent B Pokémon may be referenced using indexes 3, 4, and 5.

AI_FLAGS

AI_FLAGS(flags) Specifies which AI flags are run for all battlers 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.

BATTLER_AI_FLAGS

BATTLER_AI_FLAGS(battler, flags) Specifies additional AI flags to be applied to specific battlers (battler 0/1/2/3). Has use only for AI tests. Must be used strictly after AI_FLAGS(flags), which overwrites all existing flags. Example: BATTLER_AI_FLAGS(3, AI_FLAG_RISKY) used after AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT) will set AI_FLAG_RISKY to only battler3 (Opponent B), in addition to the flags set by AI_FLAGS.

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 MOVEs 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("It doesn't affect the opposing Wobbuffet…");

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);

SUB_HIT

SUB_HIT(battler, captureDamage: | subBreak:) Causes the test to fail the test to fail if a Substitute for the specified battler doesn’t take damage. If captureDamage is used, the damage the substitute takes is written to the supplied pointer.

u16 damage;
...
SUB_HIT(player, captureDamage: &damage);

If subBreak is set to TRUE, the test will fail unless the substitute breaks. And if set to FALSE, the test will fail unless the substitute survives.

SUB_HIT(player, subBreak: TRUE);

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("The opposing 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 couldn't move because it's paralyzed!");
     }

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 couldn't move because it's paralyzed!");
     }
     MESSAGE("The opposing 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);

FORCE_MOVE_ANIM

FORCE_MOVE_ANIM(TRUE) Forces the moves in the current test to do their animations in headless mode. Useful for debugging animations.

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);

Adding New Trainer Slides

Define Slides Per Trainer

We are going to add a Trainer Slide to Wally’s first Victory Road battle, before he Mega Evolves his Gallade. This battle takes place outside a Battle Facility, so sTrainerSlides must be edited.

src/trainer_slide.c

+ const u8 gText_ThatsTheWay[] = _("That's the way, Gallade! Go!{PAUSE_UNTIL_PRESS}");

static const u8* const sTrainerSlides[DIFFICULTY_COUNT][TRAINERS_COUNT][TRAINER_SLIDE_COUNT] =
{
    [DIFFICULTY_NORMAL] =
    {
+        [TRAINER_WALLY_VR_1] = // use the Trainer's Id from include/constants/opponents.h
+        {
+            [TRAINER_SLIDE_MEGA_EVOLUTION] = COMPOUND_STRING("That's the way, Gallade! Go!{PAUSE_UNTIL_PRESS}"), // find the id for the slide to be used.
+            //[TRAINER_SLIDE_MEGA_EVOLUTION] = gText_ThatsTheWay, // You can use globals or COMPOUND_STRING to define text here.
+        }
    },
};

If we were to edit a Trainer that appears in a Battle Facility, sFrontierTrainerSlides would be edited instead. Here, we’ll give Anabel a line before she uses a Z-Move.

src/trainer_slide.c

static const u8* const sFrontierTrainerSlides[DIFFICULTY_COUNT][FRONTIER_TRAINERS_COUNT][TRAINER_SLIDE_COUNT] =
{
    [DIFFICULTY_NORMAL] =
    {
+        [TRAINER_ANABEL] =
+        {
+            [TRAINER_SLIDE_Z_MOVE] = COMPOUND_STRING("Victory...is ours!"), //{PAUSE_UNTIL_PRESS} is omitted, so the battle will continue as soon as the next is finished printing.
+        }
    },
};

Add New Slides

include/constants/trainer_slide.h

enum TrainerSlideType
{
    TRAINER_SLIDE_BEFORE_FIRST_TURN,
    TRAINER_SLIDE_PLAYER_LANDS_FIRST_CRITICAL_HIT,
+   TRAINER_SLIDE_ENEMY_LANDS_FIRST_CRITICAL_HIT, // Each Trainer Slide has a unqiue id. 
    TRAINER_SLIDE_PLAYER_LANDS_FIRST_SUPER_EFFECTIVE_HIT,
    TRAINER_SLIDE_PLAYER_LANDS_FIRST_STAB_MOVE,
    TRAINER_SLIDE_PLAYER_LANDS_FIRST_DOWN,
    TRAINER_SLIDE_ENEMY_MON_UNAFFECTED,
    TRAINER_SLIDE_LAST_SWITCHIN,
    TRAINER_SLIDE_LAST_HALF_HP,
    TRAINER_SLIDE_LAST_LOW_HP,
    TRAINER_SLIDE_MEGA_EVOLUTION,
    TRAINER_SLIDE_Z_MOVE,
    TRAINER_SLIDE_DYNAMAX,
    TRAINER_SLIDE_COUNT,
};

Each Trainer Slide has a unique id and needs to be added to this list.

include/trainer_slide.h

If your new Trainer Slide needs to check for beforen initalized, a function is declared here to be used externally. Critical hits are used to initalize this Trainer Slide but the slide doesn’t play instantly, so we will create an function to initialize it.

void SetTrainerSlideMessage(enum DifficultyLevel, u32, u32);
void TryInitializeFirstSTABMoveTrainerSlide(u32, u32, u32);
void TryInitializeTrainerSlidePlayerLandsFirstCriticalHit(u32);
+ void TryInitializeTrainerSlideEnemyLandsFirstCriticalHit(u32);
void TryInitializeTrainerSlidePlayerLandsFirstSuperEffectiveHit(u32);
void TryInitializeTrainerSlideEnemyMonUnaffected(u32);
bool32 IsTrainerSlideInitialized(enum TrainerSlideType);

src/trainer_slide.c

     return IsTrainerSlideInitialized(slideId);
 }
 
+static bool32 ShouldRunTrainerSlideEnemyLandsFirstCriticalHit(enum TrainerSlideType slideId)
+{
+    return IsTrainerSlideInitialized(slideId);
+}
+
 static bool32 ShouldRunTrainerSlidePlayerLandsFirstSuperEffectiveHit(u32 battler, enum TrainerSlideType slideId)
 {
     if (!IsTrainerSlideInitialized(slideId))
         case TRAINER_SLIDE_PLAYER_LANDS_FIRST_CRITICAL_HIT:
             shouldRun = ShouldRunTrainerSlidePlayerLandsFirstCriticalHit(slideId);
             break;
+        case TRAINER_SLIDE_ENEMY_LANDS_FIRST_CRITICAL_HIT:
+            shouldRun = ShouldRunTrainerSlideEnemyLandsFirstCriticalHit(slideId);
+            break;
         case TRAINER_SLIDE_PLAYER_LANDS_FIRST_SUPER_EFFECTIVE_HIT:
             shouldRun = ShouldRunTrainerSlidePlayerLandsFirstSuperEffectiveHit(battler, slideId);
             break;

The function that determines if a Slide should play has different function for most Slides. We need to check if this Slide was initialized by a critical hit previously, so a function is created here. This function and the Id and then added to the switch statement in ShouldDoTrainerSlide.

     InitalizeTrainerSlide(slideId);
 }
 
+void TryInitializeTrainerSlideEnemyLandsFirstCriticalHit(u32 target)
+{
+    enum TrainerSlideType slideId = TRAINER_SLIDE_ENEMY_LANDS_FIRST_CRITICAL_HIT;
+
+    if (IsSlideInitalizedOrPlayed(slideId))
+        return;
+
+    if (!IsOnPlayerSide(target))
+        return;
+
+    InitalizeTrainerSlide(slideId);
+}
+

The function to check if this slide SHOULD be initalized is added to the bottom of this file.

src/battle_main.c

         BattleScriptExecute(i == 1 ? BattleScript_TrainerASlideMsgEnd2 : BattleScript_TrainerBSlideMsgEnd2);
     else if ((i = ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), TRAINER_SLIDE_PLAYER_LANDS_FIRST_CRITICAL_HIT)))
         BattleScriptExecute(i == 1 ? BattleScript_TrainerASlideMsgEnd2 : BattleScript_TrainerBSlideMsgEnd2);
+    else if ((i = ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), TRAINER_SLIDE_ENEMY_LANDS_FIRST_CRITICAL_HIT)))
+        BattleScriptExecute(i == 1 ? BattleScript_TrainerASlideMsgEnd2 : BattleScript_TrainerBSlideMsgEnd2);
     else if ((i = ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), TRAINER_SLIDE_PLAYER_LANDS_FIRST_SUPER_EFFECTIVE_HIT)))
         BattleScriptExecute(i == 1 ? BattleScript_TrainerASlideMsgEnd2 : BattleScript_TrainerBSlideMsgEnd2);
     else if ((i = ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), TRAINER_SLIDE_PLAYER_LANDS_FIRST_STAB_MOVE)))
diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c

In BattleTurnPassed, most Trainer Slides are checked to see if they should run, so our new call is added here.

src/battle_script_commands.c

         {
             PrepareStringBattle(STRINGID_CRITICALHIT, gBattlerAttacker);
 
+            TryInitializeTrainerSlideEnemyLandsFirstCriticalHit(gBattlerTarget);
             TryInitializeTrainerSlidePlayerLandsFirstCriticalHit(gBattlerTarget);
 
             gBattleCommunication[MSG_DISPLAY] = 1;

The actual usage of TryInitializeTrainerSlideEnemyLandsFirstCriticalHit is added and is checked whenever a critical hit is scored.

test/battle/trainer_slides.c

     }
 }
 
+SINGLE_BATTLE_TEST("Trainer Slide: Enemy Lands First Critical Hit")
+{
+    gBattleTestRunnerState->data.recordedBattle.opponentA = TRAINER_SLIDE_ENEMY_LANDS_FIRST_CRITICAL_HIT;
+
+    GIVEN {
+        ASSUME(GetMoveEffect(MOVE_LASER_FOCUS) == EFFECT_LASER_FOCUS);
+        PLAYER(SPECIES_WOBBUFFET);
+        OPPONENT(SPECIES_WOBBUFFET);
+    } WHEN {
+        TURN { MOVE(opponent, MOVE_LASER_FOCUS); }
+        TURN { MOVE(opponent, MOVE_TACKLE); }
+    } SCENE {
+        ANIMATION(ANIM_TYPE_MOVE, MOVE_LASER_FOCUS, opponent);
+        ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
+        MESSAGE("A critical hit!");
+        MESSAGE("This message plays after the enemy lands their first critical hit.{PAUSE_UNTIL_PRESS}");
+    }
+}
+
 SINGLE_BATTLE_TEST("Trainer Slide: Player Lands First STAB Hit")
 {
     gBattleTestRunnerState->data.recordedBattle.opponentA = TRAINER_SLIDE_PLAYER_LANDS_FIRST_STAB_MOVE;
diff --git a/test/battle/trainer_slides.h b/test/battle/trainer_slides.h

test/battle/trainer_slides.h


         [TRAINER_SLIDE_PLAYER_LANDS_FIRST_CRITICAL_HIT] = COMPOUND_STRING("This message plays after the player lands their first critical hit.{PAUSE_UNTIL_PRESS}"),
     },
+    [TRAINER_SLIDE_ENEMY_LANDS_FIRST_CRITICAL_HIT] =
+    {
+        [TRAINER_SLIDE_ENEMY_LANDS_FIRST_CRITICAL_HIT] = COMPOUND_STRING("This message plays after the enemy lands their first critical hit.{PAUSE_UNTIL_PRESS}"),
+    },
     [TRAINER_SLIDE_PLAYER_LANDS_FIRST_SUPER_EFFECTIVE_HIT] =
     {
         [TRAINER_SLIDE_PLAYER_LANDS_FIRST_SUPER_EFFECTIVE_HIT] = COMPOUND_STRING("This message plays after the player lands their first super effective hit.{PAUSE_UNTIL_PRESS}"),

Tests are added to make sure the new Trainer Slide works. A test is added to the c file, and the trainer to run the entry in the test is added to sTestTrainerSlides.

Day/Night System FAQ

Day/Night system FAQ

Q: How do I disable DNS?

A: Set OW_ENABLE_DNS to FALSE in include/config/overworld.h.

Q: What map changes should be made for DNS?

A: By default, the only Hoenn map changes that need to be made are to edit the Lavaridge Town map to change the metatiles the two old ladies are on in the hot springs to be the normal hot spring water tile. This is to avoid a visual bug from when OW_OBJECT_VANILLA_SHADOWS is FALSE.

However, by default no maps have lighting effects of any kind. The rest of this tutorial is to aid in adding lighting effects.

If you intend to use vanilla maps and have not already edited them, revert commit a5b079d833f18f66ebd53ac77f00227ae4a1f389. This commit includes a lot of tileset, metatile, and palette changes to accommodate light-blending, and applies OBJ_EVENT_GFX_LIGHT_SPRITE where they make sense.

If you have edited vanilla maps, the merge conflicts from reverting that commit will cause problems. If you are using vanilla maps, manually copy some of the tileset changes, .pal, and .pla files in your branch, and begin rebuilding your metatiles to have windows use the palettes that have a .pla for light blending the correct color slots. Triple-layer metatiles are highly recommended.

WARNING: As per issue #7034 if you follow this tutorial reverting the previously mentioned commit to use the updated palettes in the Hoenn maps and after that you try to follow the Triple-layer metatiles tutorial, you’ll encounter an issue when running the script to update old tilesets to support triple-layer metatiles. Follow the band-aid fix proposed in that issue after this tutorial but before following the triple-layer metatiles tutorial if you want everythign to work properly with light-blended palettes and triple-layer metatiles together.

You will also want to add the lighting object events from that commit.

If you are not using Hoenn maps, the primary concern is that you do not use the exact same palette indices for colors you want to be darkened during night time and colors you want to light up. Err towards not light blending a color if you aren’t sure how to avoid conflicts.

When writing map scripts, fadescreenswapbuffers should be preferred over fadescreen. This is to avoid odd behavior from the GBA’s limitations in alpha blending.

Q: How do I make lightbulbs glow?

Rustboro before adding lamp object events Rustboro after adding lamp object events

A: Making lamps glow is not part of the tileset itself. Instead, place certain object events on top of where you desire a glowing effect.

These object events should use OBJ_EVENT_GFX_LIGHT_SPRITE and then as their trainer_sight_or_berry_tree_id (called Sight Radius/Berry Tree ID in porymap), use LIGHT_TYPE_BALL for round lights (such as candles or gas lamps), LIGHT_TYPE_PKMN_CENTER_SIGN over a Pokémon Center sign, or LIGHT_TYPE_POKE_MART_SIGN over a Pokémart sign.

Q: How do I mark certain colors in a palette as light-blended?

A: Create a .pla file in the same folder as the .pal with the same name. This can be done on any kind of palette, except for palette 0, which is skipped over. The commit to revert listed up above only applies it to tilesets, but you could easily do it for object events as well. Of note, there is a commit reverted for being out of scope to make a follower Ampharos’s tail glow. Do note that in order to light-blend the object, a proper .pal file is required. Generating a .gbapal directly from the image is not enough.

In this file you can enter color indices [0,15] on separate lines to mark those colors as being light-blended, i.e:

06.pla:

# A comment
0 # if color 0 is listed, uses it to blend with instead of the default!
1
9
10

During the day time, these color indices appear as normal, but will be blended with either yellow or the 0 index at night. These indices should only be used for things you expect to light up. If you are using porytiles, palette overrides and using slight alterations to a color will aid you in avoiding color conflicts where the wrong index is assigned.

Rustboro gym after light-blending the windows

The windows appear as normal during the day time (blue) and light up in the night. These use the default color.

Q: How do I return to using regular shadows?

A: Set OW_OBJECT_VANILLA_SHADOWS to TRUE in include/config/overworld.h.

Q: What graphical errors are likely to occur while using DNS?

A: If you have OW_POPUP_GENERATION set to GEN_5 and OW_POPUP_BW_ALPHA_BLEND set to TRUE, you may have color errors during map popups. This is due to the GBA being severely limited in use of color blending and having both the overworld blended and the popup blended is difficult.

If you have OW_OBJECT_VANILLA_SHADOWS set to TRUE, this will also cause visual errors.

Any other graphical error should be reported.

Q: How do I disable shadows for certain locations?

A: Shadows can be disabled for certain locations by modifying the CurrentMapHasShadows function in src/overworld.c.

Q: How do I change the default light-blend color?

A: The default color is handled by the #define DEFAULT_LIGHT_COLOR in src/palette.c.

How to use the code entry system

How to use the code entry system

This system involves using the EnterCode special to prompt the player to enter a text string, and then the GetCodeFeedback special to perform some function based on the string entered. Using this system to make your own cheat codes or mystery gifts will involve both scripting and editing the GetCodeFeedback function itself to include your new functionality, and may involve further changes to the codebase if you want to implement something more far reaching (ie. a grindrunning mode).

This tutorial will use the example of entering the string “CaughtEmAll” to flag every Pokemon as caught

1. Choose where to initiaze your event scripting

This can be anywhere or anything, pre-existing or added by you in porymap. I usually like using signs for testing things but this can be anything. I’m going to give the main script a more generic name, and you can attach it to whatever object you like.

In that object’s event script, add the following:

EventScript_CodeEntry::
    special EnterCode
    waitstate
    special GetCodeFeedback
    end

This will prompt text entry from the object and prepare it to handle reading the entered text after it’s been entered, but it won’t do anything yet. Next we need to add our functionality to GetCodeFeedback.

2. Add code string and code function to GetCodeFeedback

You can find GetCodeFeedback in src/field_specials.c. Let’s start by taking a look at the function:

void GetCodeFeedback(void)
{
    static const u8 sText_SampleCode[] = _("SampleCode");
    if (!StringCompare(gStringVar2, sText_SampleCode))
        gSpecialVar_Result = 1;
    else
        gSpecialVar_Result = 0;
}

What this function does is compare the input string (gStringVar2) against a specified string (sText_SampleCode) and returns a value depending on whether the strings matched (gSpecialVar_Result). Note that due to the way StringCompare works, the comparison does need to be negated with !. By default, this sample setup returns 1 when the string “SampleCode” is entered by the player.

Let’s leave that functionality alone in case we ever want to reference it again, and just add a brand new code instead. We want to use the string “CaughtEmAll” as our code, so we’ll start by making a string for it, and a new conditional that checks if the entered string matches. We’ll also want to make sure we return a new unique number for gSpecialVar_Result so our event script knows what happened.

void GetCodeFeedback(void)
{
    static const u8 sText_SampleCode[] = _("SampleCode");
+   static const u8 sText_CaughtEmAll_[] = _("CaughtEmAll"); // Mark entire Pokedex as caught
    if (!StringCompare(gStringVar2, sText_SampleCode))
        gSpecialVar_Result = 1;
+   else if (!StringCompare(gStringVar2, sText_CaughtEmAll))
+   {
+       // TODO
+       gSpecialVar_Result = 2;
+   }
    else
        gSpecialVar_Result = 0;
}

Great! Now we have a new case to handle our new code, but it still doesn’t do anything. This is the part that will change dramatically depending on what you want to do, and you can do anything you want, from setting flags to calling other functions or anything else! Just make sure you do it from within the conditional that matches your code. In our case we want to iterate through the Pokedex to mark everything as caught, which I’ll just do here for simplicity.

void GetCodeFeedback(void)
{
    static const u8 sText_SampleCode[] = _("SampleCode");
    static const u8 sText_CaughtEmAll_[] = _("CaughtEmAll"); // Mark entire Pokedex as caught
    if (!StringCompare(gStringVar2, sText_SampleCode))
        gSpecialVar_Result = 1;
    else if (!StringCompare(gStringVar2, sText_CaughtEmAll))
    {
+       u32 i;
+       for (i = 0; i < NATIONAL_DEX_COUNT; i++)
+       {
+           GetSetPokedexFlag(i + 1, FLAG_SET_CAUGHT);
+       }
        gSpecialVar_Result = 2;
    }
    else
        gSpecialVar_Result = 0;
}

Awesome! Now our GetCodeFeedback function performs the task we want it to, and returns a 2 to our event script so it can handle the situation appropriately. That’s our next and final step!

3. Handle new GetCodeFeedback case in event script

To clarify, this step is optional. You don’t need to do anything else after GetCodeFeedback has run if you don’t want to, as all the functionality is there; once that function finishes, everything in the Pokedex will be marked as caught.

The reason we might want to do this step, and the reason we pass results back to the event script in the first place, is so we can handle providing the player with some dialogue based on what they’re doing.

Let’s go back to our event script.

EventScript_CodeEntry::
    special EnterCode
    waitstate
    special GetCodeFeedback
    end

Maybe we first want to prompt the player with a message that says something like “Enter a code?”

EventScript_CodeEntry::
+   lockall
+   msgbox EnterCode_EnterCodeText, MSGBOX_YESNO
+   compare VAR_RESULT, 0
+   goto_if_eq CodeExit
    special EnterCode
    waitstate
    special GetCodeFeedback
    end

+CodeExit::
+   releaseall
+   end
+
+EnterCode_EnterCodeText:
+   .string "Enter a code?$"

This is all straightforward scripting stuff, the sign will first give the player a YES / NO box and ask whether they’d like to enter a code. Let’s now add some cases and messages that handle the different results of the code entry from GetCodeFeedback. Let’s look at the sign first:

EventScript_CodeEntry::
	lockall
	msgbox EnterCode_EnterCodeText, MSGBOX_YESNO
	compare VAR_RESULT, 0
	goto_if_eq CodeExit
    special EnterCode
    waitstate
    special GetCodeFeedback
+   goto_if_eq VAR_RESULT, 0, CodeFailed
+   goto_if_eq VAR_RESULT, 1, CodeSampleCode
+   goto_if_eq VAR_RESULT, 2, CodeCaughtEmAll
	end

Now we’re handling cases for each of the possible return values from GetCodeFeedback! except we don’t have any of those functions, so this will cause errors as the script has nothing to goto_if_eq. Let’s write those too:

CodeFailed::
    msgbox EnterCode_FailedText, MSGBOX_DEFAULT
    releaseall
    end

CodeSampleString::
    msgbox EnterCode_SucceededText, MSGBOX_DEFAULT
    msgbox CodeSampleCode_Text, MSGBOX_DEFAULT
    releaseall
    end

CodeCaughtEmAll::
    msgbox EnterCode_SucceededText, MSGBOX_DEFAULT
    msgbox CodeCaughtEmAll_Text, MSGBOX_DEFAULT
    releaseall
    end

And lastly, we’ll need to add all of the strings we now need to reference:

EnterCode_FailedText:
    .string "...nothing happened.$"

EnterCode_SucceededText:
    .string "The code worked!$"

CodeSampleCode_Text
    .string "You entered the sample code!$"

CodeCaughtEmAll_Text
    .string "Encyclopedic knowledge fills your head.\n"
    .string "It's like you've caught 'em all!$"

So to finish up, our event script file now looks like this, with all said and done:

EventScript_CodeEntry::
    lockall
    msgbox EnterCode_EnterCodeText, MSGBOX_YESNO
    compare VAR_RESULT, 0
    goto_if_eq CodeExit
    special EnterCode
    waitstate
    special GetCodeFeedback
    goto_if_eq VAR_RESULT, 0, CodeFailed
    goto_if_eq VAR_RESULT, 1, CodeSampleCode
    goto_if_eq VAR_RESULT, 2, CodeCaughtEmAll
	end

CodeExit::
    releaseall
    end

CodeFailed::
    msgbox EnterCode_FailedText, MSGBOX_DEFAULT
    releaseall
    end

CodeSampleString::
    msgbox EnterCode_SucceededText, MSGBOX_DEFAULT
    msgbox CodeSampleCode_Text, MSGBOX_DEFAULT
    releaseall
    end

CodeCaughtEmAll::
    msgbox EnterCode_SucceededText, MSGBOX_DEFAULT
    msgbox CodeCaughtEmAll_Text, MSGBOX_DEFAULT
    releaseall
    end

EnterCode_EnterCodeText:
    .string "Enter a code?$"

EnterCode_FailedText:
    .string "...nothing happened.$"

EnterCode_SucceededText:
    .string "The code worked!$"

CodeSampleCode_Text
    .string "You entered the sample code!$"

CodeCaughtEmAll_Text
    .string "Encyclopedic knowledge fills your head.\n"
    .string "It's like you've caught 'em all!$"

And that’s it! Feel free to expand this in whatever way you wish, the pattern can just be repeated as much as you like, and you can made the code called from GetCodeFeedback do whatever you like.

Can I change the icon on the name entry screen?

Absolutely! In naming_screen.c, look for the NamingScreen_CreateCodeIcon function. It’s very short. There’s one relevant line that needs to be changed:

spriteId = CreateObjectGraphicsSprite(OBJ_EVENT_GFX_MYSTERY_GIFT_MAN, SpriteCallbackDummy, 56, 37, 0);

Just swap out OBJ_EVENT_GFX_MYSTERY_GIFT_MAN for whatever event object sprite you’d like to use instead. You may need to adjust the position (the 56 and 37 in this example) depending on your sprite.

What about a mystery gift setup?

I’d like to cover this separately because it’s best handled via givemon script commands, which means we don’t do much in GetCodeFeedback other than return a unique identifier. I’m gonna reference @PCG06’s mystery gift implementation which is based on this code entry system for a clean and really thorough example.

3. Mystery Gift GetCodeFeedback

Let’s say you have two mystery gift mons and no other cases you want to handle, one for Celebi and one for Jirachi. Your GetCodeFeedback function will look something like this:

{
    static const u8 sText_CodeCelebi[] = _("Celebi");
    static const u8 sText_CodeJirachi[] = _("Jirachi");
    if (!StringCompare(gStringVar2, sText_CodeCelebi))
        gSpecialVar_Result = 1;
    else if (!StringCompare(gStringVar2, sText_CodeJirachi))
        gSpecialVar_Result = 2;
    else
        gSpecialVar_Result = 0;
}

and that’s it, super simple. All of the other handling will have to be done on the scripting end, as we’ll be leaning on givemon and its associated handling.

2. Mystery Gift Scripting

Let’s return back to our EventScript_CodeEntry pattern from before, but instead use our new codes.

EventScript_CodeEntry::
	lockall
	msgbox EnterCode_EnterCodeText, MSGBOX_YESNO
	compare VAR_RESULT, 0
	goto_if_eq CodeExit
    special EnterCode
    waitstate
    special GetCodeFeedback
    goto_if_eq VAR_RESULT, 0, CodeFailed
    goto_if_eq VAR_RESULT, 1, MysteryGift_EventScript_Celebi
    goto_if_eq VAR_RESULT, 2, MysteryGift_EventScript_Jirachi
	end

Straightforward enough! The actual work is in writing MysteryGift_EventScript_Celebi and MysteryGift_EventScript_Jirachi to handle their givemons appropriately, prompt nicknaming, send them to the PC if the party is full, etc. We should also keep in mind that each Mystery Gift should only be entered once, so we’ll want to track that with a flag; conveniently, expansion already has 15 flags we can use for the purpose. Let’s do Celebi first.

MysteryGift_EventScript_Celebi::
	goto_if_set FLAG_MYSTERY_GIFT_1, MysteryGift_EventScript_Redeemed
	bufferspeciesname STR_VAR_1, SPECIES_CELEBI
	setvar VAR_TEMP_TRANSFERRED_SPECIES, SPECIES_CELEBI
	givemon SPECIES_CELEBI, 100, ITEM_LIFE_ORB, ITEM_CHERISH_BALL, NATURE_TIMID, 0, MON_GENDERLESS, 0, 0, 4, 252, 252, 0, 31, 31, 31, 30, 31, 31, MOVE_ENERGY_BALL, MOVE_PSYCHIC, MOVE_NASTY_PLOT, MOVE_CELEBRATE, TRUE, FALSE, TYPE_PSYCHIC
	setflag FLAG_MYSTERY_GIFT_1
	call MysteryGift_EventScript_ReceivedMon
	releaseall
	end

Walking through this, it’s clear we’ll need some more scripting. We first check if Celebi’s corresponding Mystery Gift flag has been set, and if it has, we need to tell the player they’ve already redeemed it and can’t again. If they haven’t though, we get ourselves setup for the givemon, do the givemon, and set the mystery gift flag. Then we need soem more generic handling to prompt nicknaming and some fanfare.

Two things, then; an event script to handle the case where a mystery gift mon has already been redeemed, and an event script to handle when a mystery gift mon has successfully been received.

Just for the sake of simplicity, I’m going to handle entering a used mystery gift code the same way I’d handle an incorrect code. You’re welcome to add more complex scripting if you prefer.

MysteryGift_EventScript_Redeemed::
    msgbox EnterCode_FailedText, MSGBOX_DEFAULT
	releaseall
	end

And then the scripto handle the player having successfully received a mon:

MysteryGift_EventScript_ReceivedMon::
	msgbox MysteryGift_Text_SucceededText, MSGBOX_DEFAULT
	playfanfare MUS_OBTAIN_ITEM
	message MysteryGift_Text_ReceivedGiftMon
	waitfanfare
    goto_if_eq VAR_RESULT, MON_GIVEN_TO_PARTY, MysteryGift_EventScript_NicknamePartyMon
    goto_if_eq VAR_RESULT, MON_GIVEN_TO_PC, MysteryGift_EventScript_NicknamePCMon
	goto Common_EventScript_NoMoreRoomForPokemon
	msgbox MysteryGift_Text_PleaseVisitAgain, MSGBOX_DEFAULT
	end

Almost done! Just need to handle the specific nicknaming scripts, and then add all of the text.

MysteryGift_EventScript_NicknamePartyMon::
	msgbox gText_NicknameThisPokemon, MSGBOX_YESNO
	goto_if_eq VAR_RESULT, NO, MysteryGift_EventScript_Exit
	call Common_EventScript_GetGiftMonPartySlot 
	call Common_EventScript_NameReceivedPartyMon 
	goto MysteryGift_EventScript_Exit
	end

MysteryGift_EventScript_NicknamePCMon::
	msgbox gText_NicknameThisPokemon, MSGBOX_YESNO 
	goto_if_eq VAR_RESULT, NO, MysteryGift_EventScript_TransferredToPC
	call Common_EventScript_NameReceivedBoxMon
	call Common_EventScript_TransferredToPC
	releaseall
	end

MysteryGift_EventScript_TransferredToPC::
	call Common_EventScript_TransferredToPC
	releaseall
	end

MysteryGift_Text_WelcomeToMysteryGiftSystem:
	.string "Hello, {PLAYER}!\p"
	.string "Welcome to the Mystery Gift System!\p"
	.string "Would you like to enter a code?$"

MysteryGift_Text_CurrentlyUnavailable:
	.string "I'm sorry, but the Mystery Gift System\n"
	.string "is currently unavailable.\p"
	.string "Please try again later.\p"
	.string "Thank you!$"

MysteryGift_Text_PleaseVisitAgain:
	.string "Please visit again!$"

MysteryGift_Text_EnterCode:
	.string "Please enter the code.$"

MysteryGift_Text_SucceededText:
	.string "The code was valid!\p"
	.string "Enjoy your gift!$"

MysteryGift_Text_FailedText:
	.string "The code was invalid!\p"
	.string "Would you like to enter a new code?$"

MysteryGift_Text_RedeemedText:
	.string "This code was already redeemed!\p"
	.string "Would you like you enter a new code?$"

MysteryGift_Text_ReceivedGiftMon:
	.string "{PLAYER} received a {STR_VAR_1}!$"

Goodness, so much infrastructure scripting! The nice thing is that now that all the infrastructure is set up, much like before, adding new cases becomes really straightforward. With Celebi and all of the skeleton scripting finished, let’s add Jirachi.

MysteryGift_EventScript_Jirachi::
	goto_if_set FLAG_MYSTERY_GIFT_2, MysteryGift_EventScript_Redeemed
	bufferspeciesname STR_VAR_1, SPECIES_JIRACHI
	setvar VAR_TEMP_TRANSFERRED_SPECIES, SPECIES_JIRACHI
	givemon SPECIES_JIRACHI, 100, ITEM_LIFE_ORB, ITEM_CHERISH_BALL, NATURE_ADAMANT, 0, MON_GENDERLESS, 0, 252, 4, 252, 0, 0, 31, 31, 31, 31, 31, 31, MOVE_IRON_HEAD, MOVE_ZEN_HEADBUTT, MOVE_PLAY_ROUGH, MOVE_CELEBRATE, TRUE, FALSE, TYPE_STEEL
	setflag FLAG_MYSTERY_GIFT_2
	call MysteryGift_EventScript_ReceivedMon
	releaseall
	end

And that’s it! Super straightforward from here, just make sure to iterate FLAG_MYSTERY_GIFT each time you add a new mon, and of course add their code to both GetCodeFeedback and the main script controlling code entry.

How to Use Follower NPCs

Written by Bivurnum
gif by ghoulslash

follower-npc

Configs

The configs for follower NPCs can be found in include/config/follower_npc.h.

  • FNPC_ENABLE_NPC_FOLLOWERS: This must be set to TRUE in order to enable follower NPCs. It is FALSE by default as it adds some size to the save block.
  • FNPC_FLAG_HEAL_AFTER_FOLLOWER_BATTLE: The player’s party can be automatically healed after every partner battle. Set it to a flag to toggle it on/off with scripts, or set it to FNPC_ALWAYS to have it happen every time.
  • FNPC_FLAG_PARTNER_WILD_BATTLES: The battle partner can join the player for wild battles. Set it to a flag to toggle it on/off with scripts, or set it to FNPC_ALWAYS to have it happen every time.
  • FNPC_NPC_FOLLOWER_WILD_BATTLE_VS_2: Wild battles with a battle partner default to two wild Pokémon appearing. You can set this to FALSE to make only one wild Pokémon appear.
  • FNPC_NPC_FOLLOWER_PARTY_PREVIEW: By default, a preview of the player’s and partner’s teams will be shown at the start of every trainer battle. Set this to FALSE to disable this feature.
  • FNPC_FACE_NPC_FOLLOWER_ON_DOOR_EXIT: If TRUE the player will turn to face the follower when they exit a doorway.
  • FNPC_NPC_FOLLOWER_SHOW_AFTER_LEAVE_ROUTE: If TRUE the follower will walk out of the player automatically after using Fly, Teleport, or Escape Rope.

Set the Follower

The setfollowernpc macro will turn the specified object into an NPC follower. It requires the object id, the follower flags, and optionally a custom script and a battle partner. If you do not include a custom script name (or you set it to 0), the NPC follower will default to their normal interaction script. If there is a follower Pokémon present, it will be returned to its Pokeball until the NPC follower is destroyed.

Here’s an example:
setfollowernpc 3, FNPC_ALL, MyScript_Eventscript_CustomFollowerScript, PARTNER_STEVEN
This would turn object number 3 on the current map into an NPC follower, give them access to all following behaviors, run that custom script when the player interacts with them, and adds the Steven battle partner to the follower (more on this later).

The object MUST have an event flag or the NPC follower will not be created!

Create a Follower

The createfollowernpc macro will create a new follower without needing to convert an existing NPC. It works similarly to setfollowernpc, but instead of providing an object id, you give it a GFX id. For example, if you wanted to create a follower with the May sprite, you could do something like this:
createfollowernpc OBJ_EVENT_GFX_RIVAL_MAY_NORMAL, FNPC_ALL, EventScript_MayFollow
The created follower NPC will initially be invisible until the player takes a step.

Follower Flags

These are required to tell the game what behavior you want the NPC follower to have. They are defined in include/constants/follower_npc.h. The second list of flags is the same as the first, but with shortened names to make them easier to type when scripting. The first 7 flags in the list are individual behaviors, whereas the remaining three are bundles of flags. For example, if you use FNPC_SURF in setfollowernpc, the NPC follower will be able to Surf behind the player. If you use FNPC_ALL_WATER instead, the NPC follower will be able to Dive and go up Waterfalls in addition to being able to Surf. Feel free to add your own custom bundles of flags to the file to meet your needs.

To make sure the NPC follower uses the correct animation frames, you should add an entry to gFollowerAlternateSprites in include/follower_npc_alternate_sprites.h. Only do this if your object has distinct animation frames for different behaviors (running, biking, surfing, etc). Follow the templates for Rival May and Rival Brendan that already exist there.

Follower Movements

You can use the applymovement macro on an NPC follower by using OBJ_EVENT_ID_NPC_FOLLOWER for the object id. This is convenient for making the NPC follower walk off-screen before destroying them. If an NPC follower is not immediately next to the player while the controls aren’t locked, it will try to take steps to get back into position as the player moves, sometimes walking through impassable areas (like through the middle of buildings).

You can also use facefollowernpc to make both the player and the NPC follower face each other.

Note

The existing vanilla movement scripts do not take NPC followers into account. Other NPCs may walk into the follower or the follower may get left behind. If you want follower NPCs to work with these existing scripts, you will need to add your own handling for them. The hidefollowernpc macro can be particularly useful for this.

Check for Follower

You can use the checkfollowernpc macro to check whether or not an NPC follower currently exists. It will set VAR_RESULT to TRUE if an NPC follower exists, otherwise it will be set to FALSE.

Hide the Follower

The hidefollowernpc macro makes the NPC follower walk into the player and be hidden. The game will wait until the movement is finished before continuing with the script. There is an optional parameter that can be used to set the desired walk speed for the movement. It can be from 0 (slowest) to 3 (fastest). If a walk speed is not specified, it will default to the normal walk speed. The NPC follower will reappear the next time the player takes a step (outside of scripts).

Destroy the Follower

The destroyfollowernpc macro acts similarly to removeobject. It removes the NPC follower object instantly and sets their flag. If you have Pokémon followers enabled, the Pokémon will reappear the next time the player takes a step.

Battle Partner

If you assign a battle partner to the NPC follower, that partner will fight alongside the player in all trainer battles while the follower is present. This turns all battles into multi battles, whether against one opponent or two.

You can use any battle partner that has been defined in include/constants/battle_partner.h. The partners’ information and Pokémon teams can be set in src/data/battle_partners.party.

To change the battle partner of an existing NPC follower, you can use the changefollowerbattler macro with the desired partner ID. If you change the ID to 0, the NPC follower will not participate in any battles until you change it back to a valid partner ID.

Keep in mind that only the first 3 Pokémon in the player’s party will participate in multi battles. The other three party members are temporarily replaced with the partner’s Pokémon. This means the last three Pokémon in the player’s party will not receive any experience points (even from the EXP Share).

Time-Based Encounters Tutorial

Table of Contents:

What is the Time-Based Encounters feature?

Time-Based Encounters lets you pick which Pokémon appear based on the in-game clock, per route! Gen 2 had this feature, and Gen 4 brought it back- for instance, in Sinnoh’s Route 201 you have a higher chance of catching a Bidoof than a Starly at night.

Sounds rad, how do I add it to my romhack?

There are a couple of ways! The system is built to handle your unchanged wild_encounters.json file by default, so the most basic solution is to add an encounter group by editing that (by hand or with Porymap), and then add a supported suffix to the end of whatever name you give it.

NOTE: if you haven’t specified or added any encounters, or have the option turned off, Expansion puts them into the TIME_MORNING (or whatever your first time enum is set to in the TimeOfDay enum in rtc.h) slot to keep vanilla behavior. This means any map "base_label" without a supported suffix is automatically set to the first time slot when OW_TIME_OF_DAY_ENCOUNTERS is TRUE. When OW_TIME_OF_DAY_ENCOUNTERS is FALSE, everything regardless of any extant suffixes gets the first time slot suffix (ie _Morning for TIME_MORNING) so it matches with the 0th index of the encounterTypes array in struct WildMonHeader.

I’ve never added one by hand, but I want to!

Great attitude bestie! It’s very simple- all you need is to find your wild_encounters.json file and open it up in your text/code editor of choice; I recommend VSCodium, but any will work.

To get started, we’ll use Route 101 as an example:

{
  "map": "MAP_ROUTE101",
  "base_label": "gRoute101",
  "land_mons": {
    "encounter_rate": 20,
    "mons": [
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_ZIGZAGOON"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_ZIGZAGOON"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_ZIGZAGOON"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_ZIGZAGOON"
      }
    ]
  }
},

That’s it! That’s the entire encounter group for Route 101. In other Routes or maps, you’ll likely see other encounters listed; here we have only have land_mons, but vanilla emerald supports three more types of encounters, for a total of four:

  • land_mons, your standard grass or cave or sand encounter.
  • water_mons, used for surfing
  • rock_smash_mons, for when you get jumpscared by a Geodude in Route 111 after using Rock Smash.
  • fishing_mons, for fishing

NOTE: You can also have more of these encounter types- in fact, expansion has a fifth type of encounter for the Dexnav feature called hidden_mons, and some people have entries for honey_mons and headbutt_mons in their personal hacks as well! This system supports those too, you just need to make sure to update your WildEncounters struct definition. You need to keep the order consistent, so as a standard, any custom encounter types should go before hidden_mons but after fishing_mons. To use the earlier examples:

struct WildEncounterTypes
{
    const struct WildPokemonInfo *landMonsInfo;
    const struct WildPokemonInfo *waterMonsInfo;
    const struct WildPokemonInfo *rockSmashMonsInfo;
    const struct WildPokemonInfo *fishingMonsInfo;
    const struct WildPokemonInfo *honeyMonsInfo;
    const struct WildPokemonInfo *headbuttMonsInfo;
    const struct WildPokemonInfo *hiddenMonsInfo;
};

You can see that the two new entries, honeyMonsInfo and headbuttMonsInfo (corresponding with honey_mons and headbutt_mons) are slotted in between fishingMonsInfo and hiddenMonsInfo. Structs in the C programming language rely on consistent placement with their members, so this is the order that every other instance of these encounter types should maintain. In my expert opinion, the easiest way to add these is again with Porymap. Okay, take a breath, stretch, and we’ll get back to the tutorial!

For the sake of simplicity, I’ll show you how to add another encounter group here and pop a supported prefix on it. I want my new encounter group to:

  • have a fishing table (I’m adding a fishin hole to Route 101)
  • let you catch Spiky Eared Pichu, my favorite mon (not really)
  • have some rock smash encounters to up the spook factor
  • only occur at night

With all of these things in mind, let’s craft an encounter! We’ll start off by copying the one we have, called gRoute101.

{
  "map": "MAP_ROUTE101",
  "base_label": "gRoute101",
  "land_mons": {
    "encounter_rate": 20,
    "mons": [
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_ZIGZAGOON"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_ZIGZAGOON"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_ZIGZAGOON"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_ZIGZAGOON"
      }
    ]
  }
},
{
  "map": "MAP_ROUTE101",
  "base_label": "gRoute101_Night",
  "land_mons": {
    "encounter_rate": 20,
    "mons": [
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_ZIGZAGOON"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_ZIGZAGOON"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_ZIGZAGOON"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_ZIGZAGOON"
      }
    ]
  }
},

Okay, we have it duplicated. We leave the value for “map”: the same as the original so the game knows that both of these encounters are for Route 101. You can see I changed the name of the copy to gRoute101_Night; that’s one bullet point down! If we enable OW_TIME_BASED_ENCOUNTERS in overworld.h, the game will recognize this encounter group goes in the Night slot and will switch which group is used to generate the encounters when the in-game clock changes to TIME_NIGHT. Next, let’s add Spiky Eared Pichu and our two new encounter tables (fishing_mons and rock_smash_mons).

{
  "map": "MAP_ROUTE101",
  "base_label": "gRoute101_Night",
  "land_mons": {
    "encounter_rate": 20,
    "mons": [
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_PICHU_SPIKY_EARED"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_WURMPLE"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_POOCHYENA"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_ZIGZAGOON"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_ZIGZAGOON"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_ZIGZAGOON"
      },
      {
        "min_level": 3,
        "max_level": 3,
        "species": "SPECIES_ZIGZAGOON"
      }
    ]
  },
  "fishing_mons": {
    "encounter_rate": 30,
    "mons": [
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_MAGIKARP"
      },
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_MARILL"
      }
    ]
  },
  "rock_smash_mons": {
    "encounter_rate": 20,
    "mons": [
      {
        "min_level": 2,
        "max_level": 2,
        "species": "SPECIES_GEODUDE"
      }
    ]
  }
},

And there we go! It has the _Night suffix, has Spiky Eared Pichu right up at the top of the list, has a couple of fishing encounters, and will jumpscare us with about a 20% chance every time we break a rock with rock smash. That’s what the encounter_rate line means, by the way- the overall percentage you have of encountering any of the Pokémon listed. Congrats! You’ve just created a brand new encounter group, set its time, and adjusted the encounters! I’d highly recommend doing this with Porymap- the interface is very useful for editing maps, including wild encounters!

What are “supported suffixes?”

Vanilla Pokémon games usually work with 4 different times of day:

  • TIME_MORNING
  • TIME_DAY
  • TIME_EVENING
  • TIME_NIGHT

So, the “supported suffixes” are just:

  • _Morning
  • _Day
  • _Evening
  • _Night

NOTE: You can add more than just these by changing the TimeOfDay enum in rtc.h. If you’d like to do this, I’d recommend making a backup of your wild_encounters.json somewhere outside your project folder, just so you can have a baseline to return to if something goes wrong. The migration script makes a backup of the file each time it runs, so it’s essentially a one step undo button- if you plan on or think you might make lots of edits to wild_encounters.json, it is a very good idea to make a baseline backup.

That’s a lot of manual editing.

You’re so right bestie! Luckily for you, there’s a python script that can help you out! The script is at migration_scripts/add_time_based_encounters.py. It, in order:

  1. Checks to make sure you’re running it from the root folder of your expansion project (specifically, wherever the project’s Makefile is)
  2. Makes a backup of your wild_encounters.json file called wild_encounters.json.bak
  3. Runs through wild_encounters.json and adds dummy encounter groups for each time denomination to each group
    • ie, gRoute101 becomes gRoute101_Morning, gRoute101_Day, gRoute101_Evening, and gRoute101_Night

This script works kind of like a “template” feature- when you open it up to edit either in Porymap or a text editor, you will see the encounter groups, but they won’t be filled out with encounters. This lets you add Pokémon with your own encounter rates however you want.

That’s still a lot of editing.

You’re still so right bestie! Luckily for you, there’s an optional argument you can add when you run the script: --copy. This duplicates the encounter group’s encounters as well as their labels/map group values. When you open wild_encounters.json for editing either in Porymap or a text editor, you’ll notice that each group (gRoute101_Morning, gRoute101_Day, gRoute101_Evening, and gRoute101_Night) now all have the same encounters as gRoute101 did. If you only want to add a couple of Pokémon here and there for each time of day, this is probably the easier option.

NOTE: the --copy option will use up at least an additional 9kb of ROM space. Obviously that’s not much even for a GBA ROM, but it’s something to keep in mind.

So what are the #define options in overworld.h?

Great questie bestie!

Here’s a rundown, with more information than what’s in the comments at overworld.h and their default values:

OW_TIME_OF_DAY_ENCOUNTERS            FALSE
  • Acceptable values: TRUE or FALSE
  • this option enables or disables the feature. You’ll notice your used ROM space changing when this is enabled or disabled, as the json->C header conversion file will generate the encounterTypes array in wild_encounter.h with different sizes based on whether this value is TRUE or FALSE.
OW_TIME_OF_DAY_DISABLE_FALLBACK      FALSE
  • Acceptable values: TRUE or FALSE
  • this option controls the behavior of the game when an encounter table isn’t populated. If this is set to TRUE, whenever the game detects that you’re in a time of day (Morning/Day/Evening/Night) on a map without any encounters for that time, you won’t encounter any mons. If this is set to FALSE, the game will look for encounters at the time specified in the OW_TIME_OF_DAY_FALLBACK option below.
OW_TIME_OF_DAY_FALLBACK              TIME_MORNING
  • Acceptable values: any value from the TimesOfDay enum, so by default TIME_MORNING, TIME_DAY, TIME_EVENING, and TIME_NIGHT.
  • this option controls which time is used when OW_TIME_OF_DAY_DISABLE_FALLBACK is FALSE. Keep in mind that if you enable OW_TIME_OF_DAY_ENCOUNTERS and set this to something other than TIME_MORNING, you should make sure that time has encounters, or you won’t encounter anything.

Examples

Running the migration script without the --copy option

Make sure you run this from the root folder of your project!

python3 migration_scripts/add_time_based_encounters.py

Result:

"encounters": [
  {
    "map": "MAP_ROUTE101",
    "base_label": "gRoute101_Morning",
    "land_mons": {
      "encounter_rate": 20,
      "mons": [
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_ZIGZAGOON"
        }
      ]
    }
  },
  {
    "map": "MAP_ROUTE101",
    "base_label": "gRoute101_Day"
  },
  {
    "map": "MAP_ROUTE101",
    "base_label": "gRoute101_Evening"
  },
  {
    "map": "MAP_ROUTE101",
    "base_label": "gRoute101_Night"
  },
]

As you can see, the names change, but the encounters aren’t touched, so you’re free to add your own, piecemeal style. If you don’t have any encounters for a map and time, the game will use OW_TIME_OF_DAY_FALLBACK if OW_TIME_OF_DAY_DISABLE_FALLBACK is FALSE; otherwise, you won’t encounter anything.

Running the migration script with the --copy option

Make sure you run this from the root folder of your project!

python3 migration_scripts/add_time_based_encounters.py --copy

Result:

"encounters": [
  {
    "map": "MAP_ROUTE101",
    "base_label": "gRoute101_Morning",
    "land_mons": {
      "encounter_rate": 20,
      "mons": [
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_ZIGZAGOON"
        }
      ]
    }
  },
  {
    "map": "MAP_ROUTE101",
    "base_label": "gRoute101_Day",
    "land_mons": {
      "encounter_rate": 20,
      "mons": [
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_ZIGZAGOON"
        }
      ]
    }
  },
  {
    "map": "MAP_ROUTE101",
    "base_label": "gRoute101_Evening",
    "land_mons": {
      "encounter_rate": 20,
      "mons": [
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_ZIGZAGOON"
        }
      ]
    }
  },
  {
    "map": "MAP_ROUTE101",
    "base_label": "gRoute101_Night",
    "land_mons": {
      "encounter_rate": 20,
      "mons": [
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_WURMPLE"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_POOCHYENA"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 2,
          "max_level": 2,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_ZIGZAGOON"
        },
        {
          "min_level": 3,
          "max_level": 3,
          "species": "SPECIES_ZIGZAGOON"
        }
      ]
    }
  },
]

As you can see, the group gRoute101 and all its encounters were copied into groups that correspond with the four vanilla times of day (Morning/Day/Evening/Night).

How to use Trainer Party Pools

Trainer Party Pools (TPP) is a way to introduce a bit of unpredictability to trainer battles by allowing trainer to generate parties from pools defined by the user.

The maximum number of mons that can be in a single trainer’s pool is 255.

Turning on TPP with trainer.sparty

To use TPP with trainers.party, all that’s needed is to define a Party Size that’s smaller than than the number of defined mons for the trainer.

Turning on TPP with trainers.h

To use TPP with trainers.h, the trainer need to have the .poolSize field set to a value that’s larger than the .partySize and equal to the number of mons defined in the trainer.

How the pool works

When generating a party for a trainer with a pool, the party is picked from the pool randomly according to rules set for the pool and tags assigned to individual mons in the pool.

Pool Rules

Pool rules are defined in src/data/battle_pool_rules.h. To begin with some default pools are defined, defaultPoolRules which any trainer that doesn’t otherwise have a specified pool ruleset uses, and some custom rules for common scenarios.

  • POOL_RULESET_BASIC, a ruleset that will pick a mon from the pool with the tag MON_POOL_TAG_LEAD if possible to put in the first slot and MON_POOL_TAG_ACE in the last slot, and not pick mons with those tags for any other position.
  • POOL_RULESET_DOUBLES, a ruleset that will pick up to two mons from the pool with the tag MON_POOL_TAG_LEAD if possible to put in the first two slots and MON_POOL_TAG_ACE in the last two slots, and not pick mons with those tags for any other position.
  • POOL_RULESET_WEATHER_SINGLES, a ruleset that will pick at most one mon with the tag MON_POOL_TAG_WEATHER_SETTER if possible, and at least one mon with the tag MON_POOL_TAG_WEATHER_ABUSER if possible, in addition to the same conditions as POOL_RULESET_BASIC.
  • POOL_RULESET_WEATHER_DOUBLES, a ruleset that will pick at most one mon with the tag MON_POOL_TAG_WEATHER_SETTER if possible, and at least one mon with the tag MON_POOL_TAG_WEATHER_ABUSER if possible, in addition to the same conditions as POOL_RULESET_DOUBLES.
  • POOL_RULESET_SUPPORT_DOUBLES, a ruleset that will pick at most one mon with the tag MON_POOL_TAG_SUPPORT if possible, in addition to the same conditions as POOL_RULESET_DOUBLES.

All these pools also have the options .speciesClause, .excludeForms, .itemClause and .itemClauseExclusions set to the values defined in include/config/battle.h under B_POOL_RULE_<rule>.

  • .speciesClause if set to TRUE means that the same exact species as defined by .species can’t be picked twice for the party from the pool.
  • .excludeForms if set to FALSE means that the same exact species as defined by NetDex number can’t be picked twice for the party from the pool.
  • .itemClause if set to TRUE means that pokemon with the same held item can’t be picked twice for the party from the pool.
  • .itemClauseExclusions if set to TRUE means that multiple pokemon with the same item can be picked for the party if the item is listed in poolItemClauseExclusions. By default ITEM_ORAN_BERRY and ITEM_SITRUS_BERRY are the only items in the list of exclusions.

Individual tags can have rules which change how they’re included. By setting the .tagMaxMembers[POOL_TAG_<tag>] field to a number, only that many mons with that tag will at max be part of the party, or if set to POOL_MEMBER_COUNT_NONE no mons with this tag will be included, and if set to POOL_MEMBER_COUNT_UNLIMITED no restrictions on the number of mons with the tag will apply.

By setting .tagRequired[POOL_TAG_<tag>] option field to TRUE, this tag will be picked before any tags that are not required, after the tag has been picked for the pool it will be set to FALSE for that tag.

The tags Lead and Ace has special handling where they will be picked for the first or last party position respectively.

Tags

There are currently 8 tags specified in the TPP implementation, Lead, Ace, Weather Setter, Weather Abuser, Support, Tag 5, Tag 6 and Tag 7.

If using trainers.party, these tags are applied to mons with the field Tags: , separated by /. Example Tags: Lead / Weather Setter

If using trainers.h, these tags are applied to mons with the field .tags, separated by |. Example: .tags = MON_POOL_TAG_LEAD | MON_POOL_TAG_WEATHER_SETTER

Pokemon can have up to 32 different tags, but anything beyond the 8 initial tags has to be implemented. The numbered tags can be renamed too to better signify their purpose for developers.

Trainer options

A few more trainer options are introduced in order to further customize how the pool picking process works.

  • Pool Pick Functions (.poolPickIndex) controls which functons are used to pick mons from the pool, they’re split into Lead, Ace, and Other. By default, only Default<position>PickFunction and PickLowest are implemented. Must be an enum value in enum PoolPickFunctions.
  • Pool Prune (.poolPruneIndex) controls if members in the pool should be removed before party members are picked from the pool. By default, only POOL_PRUNE_NONE, which doesn’t remove anything from the pool, and POOL_PRUNE_TEST, which removes Wobbuffet from the pool, are implemented. Must be an enum value in enum PoolPruneOptions.

Pool copy

The Copy Pool option can be used to have the trainer use the party or pool from a different trainer. If you for example want some other trainer to have the same team/pool as Tiana, you’d use Copy Pool: TRAINER_TIANA. If Party Size isn’t defined for the current trainer, it will inherit from the copied trainer.

Example pool

=== TRAINER_TIANA ===
Name: TIANA
Class: Lass
Pic: Lass
Gender: Female
Music: Female
Double Battle: Yes
AI: Check Bad Move
Party Size: 4
Pool Rules: Weather Doubles
Pool Pick Index: Default

Zigzagoon
Level: 4
IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe

Shroomish
Level: 4
IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe

Psyduck
Level: 4
IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe

Shellder
Level: 4
IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe

Mew
Level: 4
IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe
Tags: Ace

Giratina
Level: 4
IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe
Tags: Ace

Vulpix
Ability: Drought
Level: 4
Tags: Lead / Weather Setter

Torkoal
Ability: Drought
Level: 4
Tags: Lead / Weather Setter

Bulbasaur
Ability: Chlorophyll
Level: 4
Tags: Lead / Weather Abuser

Cherrim
Level: 4
Tags: Lead / Weather Abuser

Here Tiana has been given a pool that’s set up for a double battle with weather. Using the default pool rule Weather Doubles it will only pick one of each of the weather setters and abusers which Tiana will lead with. Tiana will also pick either Mew or Giratina as her Ace mon, and the last slot will be filled with one of Zigzagoon, Shroomish, Psyduck or Shellder.

Pool settings

If no pool rule is specified in the trainer, the default rules will be used, which sets rules according to some defaults from include/config/battle.h. This file also has settings for other pool options.

  • B_POOL_SETTING_CONSISTENT_RNG, TRUE or FALSE, the party generated will always be the same on a particular save (RNG dependant on trainerId and encountered trainer).
  • B_POOL_SETTING_USE_FIXED_SEED, TRUE or FALSE, the party generated will always be the same on a particular compiled ROM (RNG dependant on a chosen seed and encountered trainer).
  • B_POOL_SETTING_FIXED_SEED, seed to use for fixed seed, does nothing if B_POOL_SETTING_USE_FIXED_SEED is FALSE.

How to interact with Apricorn Trees

apricorn-tree

Adding a new apricorn tree

To add a new tree, first increase the tree count and expand the tree list in include/constants/apricorn_tree.h.

Note that each tree will take a bit in the savegame’s SaveBlock3 struct so increasing APRICORN_TREE_COUNT breaks the savegame. Due to this, pokeemerald-expansion doesn’t have any trees set up by default to prevent breaking downstream savegames. The trees support random yields and properly use plural case on plural yields.

#define APRICORN_TREE_NONE 0

-#define APRICORN_TREE_COUNT 0
+#define APRICORN_TREE_ROUTE101_RED_TREE 1
+
+#define APRICORN_TREE_COUNT 32

Then list its data in src/data/apricorns.h.

const struct ApricornTree gApricornTrees[APRICORN_TREE_COUNT] =
{
    [APRICORN_TREE_NONE] =
    {
        .minimum = 1,
        .maximum = 1,
        .apricornType = APRICORN_RED,
    },

+   [APRICORN_TREE_ROUTE101_RED_TREE] =
+   {
+       .minimum = 1,
+       .maximum = 1,
+       .apricornType = APRICORN_RED,
+   },
};

Finally, just place your new tree using Porymap. Similarly to berries, the Sight Radius / Berry Tree ID field is used for the tree’s ID.

apricorn-tree-porymap

Add a new apricorn type

After you created your new item, simply expand the ApricornType enum in include/constants/apricorn_tree.h.

enum ApricornType
{
    [...]
    APRICORN_BERRY_MARANGA = ITEM_MARANGA_BERRY,
+    APRICORN_BROWN         = ITEM_BROWN_APRICORN,
};

How to Use Namebox

New implementation made by mudskipper13, originally made by Tustin2121.

Overview

Npc Trainers Pokenav Messagebox

This is a broad and self-contained implementation of Tustin2121’s namebox feature branch here, which includes the following:

  • Cleaner implementation of namebox onto both the field message box and the field PokéNav textbox.
  • New configs:
    • OW_NAME_BOX_USE_DYNAMIC_WIDTH lets the namebox use dynamic window width depending on the speaker’s string length.
      • When disabled and/or the speaker name is too long, OW_NAME_BOX_DEFAULT_WIDTH will be used as the maximum width.
    • OW_NAME_BOX_NPC_TRAINER lets any approaching NPC trainers shows a namebox in their dialogue automagically.
    • OW_NAME_BOX_DEFAULT_WIDTH and OW_NAME_BOX_DEFAULT_HEIGHT sets the default width and height.
    • OW_NAME_BOX_FOREGROUND_COLOR and OW_NAME_BOX_SHADOW_COLOR sets the default text colors, the background color is handled by the engine.
    • OW_FLAG_SUPPRESS_NAME_BOX lets you enable/disable the namebox globally, assign a flag from include/constants/flags.h onto this config to be able to use it.
  • Added a Speaker Name table, frequently-used names can be stored into gSpeakerNamesTable in src/data/speaker_names.h and they can accessed by using a SP_NAME_* constant defined in include/constants/speaker_names.h.
  • Added a new scripting macro setspeaker ([textPointer]/[SP_NAME_*]).
    • Besides a text pointer, it is possible to use the Speaker Name table to set the textPointer with the gSpeakerNamesTable array instead.
    • Feed it either NULL or SP_NAME_NONE will remove the namebox instead.
    • release, releaseall, and closemessage will automatically remove the namebox, together with the messagebox.
  • Added a new text control code/inline text {SPEAKER NAME_*}.
    • Unlike the setspeaker macro, you can only use the SP_NAME_* constants for this. It is partly due to the text engine’s limitation itself.
    • You’ll need to add the constants into charmap.txt to be able to use them for the same reason as above.
    • Feed it SP_NAME_NONE to remove the namebox manually.
    • Similarly, release, releaseall, and closemessage will automatically remove the namebox, together with the message box.

Usage

setspeaker

Using a text pointer

First, define your speaker’s string.

Speaker_Jeremy:
    .string "Jeremy$"

And then in your script, add the setspeaker with the speaker’s name earlier.

...
    setspeaker Speaker_Jeremy
...

If you are using poryscript, you can also include the string right there with the setspeaker aka inline.

...
    setspeaker("Jeremy")
...

Using a SP_NAME_* constant

Add the setspeaker with your constant.

    setspeaker SP_NAME_JEREMY

For instruction on how to add a new Speaker Name, continue here.

SPEAKER inline

The usage is identical to using setspeaker with SP_NAME_* constant, but instead it’s within your text script and uses the constant you added to charmap.txt.

    "{SPEAKER NAME_JEREMY}Yo wassup!"

For instruction on how to add a new Speaker Name, continue here.

Adding a new Speaker Name

  1. Add a new constant to include/constants/speaker_names.h just after SP_NAME_NONE and before SP_NAME_COUNT.
 enum SpeakerNames {
     SP_NAME_NONE = 0,
     SP_NAME_MOM,
     SP_NAME_PLAYER,
+    SP_NAME_JEREMY,
     SP_NAME_COUNT
 };

  1. Add an entry to gSpeakerNamesTable in src/data/speaker_names.h with your newly added constant as the array index.
 const u8 *const gSpeakerNamesTable[SP_NAME_COUNT] =
 {
     [SP_NAME_MOM]    = COMPOUND_STRING("MOM"),
     [SP_NAME_PLAYER] = COMPOUND_STRING("{PLAYER}"),
+    [SP_NAME_JEREMY] = COMPOUND_STRING("JEREMY"),
 };
  1. In order for this constant to be usable for {SPEAKER} inline, you’ll need to add your constant onto charmap.txt. Do note that the order here MUST match with the one in include/constants/speaker_names.h!
 @ Speaker names, the order must be matching with include/constants/speaker_names.h
 NAME_NONE = 00
 NAME_MOM = 01
 NAME_PLAYER = 02
-NAME_COUNT = 03
+NAME_JEREMY = 03
+NAME_COUNT = 04

pokemerald-expansion Vs. Seeker

What is the Vs. Seeker?

The Vs. Seeker is a Key Item that is used to battle Trainers that the player has battled previously.

When used, the Vs. Seeker sends out a signal that allows the player to find other Trainers who want a rematch. This signal affects all Trainers that are on-screen. Once used on Trainers that can be rematched, the device cannot be used again until it is charged. The player does this by walking a specific number of steps. The effect on the Trainers wears off if they are battled, the player leaves the area, or the player walks a specific number of steps. If the player attempts to use the Vs. Seeker when it is not fully charged, the player will be told how many steps remain until it is. After the player uses the Vs. Seeker, some Trainers may have their team changed from their first battle.

How is the Vs. Seeker enabled?

Users

Vs. Seeker functionality is enabled by setting I_VS_SEEKER_CHARGING to TRUE.

Players

ITEM_VS_SEEKER can only be used outside of battle. It can be used from the bag or registered to be used from the field.

Usage of the Vs. Seeker will ALWAYS fail unless all of the conditions are met:

  • Player has at least five badges
  • There is an NPC on screen that has previously been defeated
  • Player is not inside of a building
  • The Vs. Seeker is fully recharged

Charge

If the player has ITEM_VS_SEEKER and at least five badges, the Vs. Seeker will be charged by walking steps. The Vs. Seeker is fully charged once the player has walked VSSEEKER_RECHARGE_STEPS, which is 100 by default. The Vs. Seeker’s charge is depleted if the player uses the item.

How does Match Call interact with the Vs. Seeker?

When I_VS_SEEKER_CHARGING is enabled, the Match Call does not function at all. Trainers will never be rematch eligible outside of the use of the Vs. Seeker.

How does the Vs. Seeker choose a Trainer?

When the Vs. Seeker is successfully used, every Trainer on screen is individually queried. There is a 31% chance that the Trainer will want a rematch. Objects listed in regularTrainersOnLand or regularTrainersInWater are considered Land/Water objects.

StatusIs Land/Water ObjectEmoteNew Movement Type
Wants RematchYesMOVEMENT_ACTION_EMOTE_DOUBLE_EXCL_MARKMOVEMENT_TYPE_COUNTER_CLOCKWISE
Wants RematchNoMOVEMENT_ACTION_EMOTE_DOUBLE_EXCL_MARKMOVEMENT_TYPE_FACE_DOWN
Does Not Want Rematch-MOVEMENT_ACTION_EMOTE_Xnone
Has Not Been Fought-MOVEMENT_ACTION_EMOTE_EXCLAMATION_MARKnone

Rematch Table

SequenceTrainer ID
1st BattleTRAINER_ROSE_1
2nd BattleTRAINER_ROSE_2
3rd BattleTRAINER_ROSE_3
4th BattleTRAINER_ROSE_4
5th BattleTRAINER_ROSE_5

The game determines which version of the Trainer you’ll fight next by following these rules:

  1. Start with the next Trainer in the sequence after the one that has been defeated. If there are no more, the battle is against the last listed Trainer.
  2. If that next Trainer hasn’t been unlocked yet, the battle is against the latest available unlocked version.
  3. If the next Trainer is unlocked but not yet defeated, the battle is against that version.
  4. If the next Trainer has already been defeated, check the next one in the sequence.

How do users implement rematches with the Vs. Seeker?

Existing pokemerald Trainers

No extra work is required. With the exception of Wally, Gym Leaders and Elite Four, all of the rematchable Trainers in Emerald will work with the Vs. Seeker without any changes.

New Trainers

Party / gRematchTable

Each of the rematches for the Trainer must be defined as seperate Trainers in src/data/trainers.party and include/constants/opponents. For example, TRAINER_CALVIN_1 also has TRAINER_CALVIN_2,TRAINER_CALVIN_3,TRAINER_CALVIN_4, and TRAINER_CALVIN_5.

Once all of those constants and parties are defined, a new row must be added to gRematchTable (located in in src/battle_setup.c). The row header should be a rematch ID, which can be added in include/constants/rematches.h. The row contents must be the five constants created for the new parties, with the lat argument being the constant of the map (include/constants/map_groups.h) where the Trainer is placed.

If a Trainer is intended to have less than five unique rematch parties, the extra slots can be filled with the last available Trainer ID.

// This Trainer only has two teams.
    [REMATCH_ROSE] = REMATCH(TRAINER_ROSE_1, TRAINER_ROSE_2, TRAINER_ROSE_2, TRAINER_ROSE_2, TRAINER_ROSE_2, MAP_ROUTE118),

WARNING: Rematch IDs should be placed BEFORE REMATCH_WALLY_VR. Trainers below that are treated as “special Trainers” that are not triggered by the Vs. Seeker.

Scripts

The trainer’s object needs to have a script that begins with a method to signify what this object’s trainer ID is.

trainerbattle

Route103_EventScript_Daisy::
    trainerbattle_single TRAINER_DAISY, Route103_Text_DaisyIntro, Route103_Text_DaisyDefeated
    msgbox Route103_Text_DaisyPostBattle, MSGBOX_AUTOCLOSE
    end

Daisy is using one of the trainerbattle macros, which has the trainer battle macro in the first command of the script. Most trainers in pokeemerald use this pattern.

vsseeker_rematchid
Route102_EventScript_Calvin::
    vsseeker_rematchid TRAINER_CALVIN_1
    applymovement LOCALID_CALVIN, CalvinMovementTest
    waitmovement 0
    trainerbattle_single TRAINER_CALVIN_1, Route102_Text_CalvinIntro, Route102_Text_CalvinDefeated, Route102_EventScript_CalvinRegisterMatchCallAfterBattle
    specialvar VAR_RESULT, ShouldTryRematchBattle
    goto_if_eq VAR_RESULT, TRUE, Route102_EventScript_CalvinRematch
    setvar VAR_0x8004, TRAINER_CALVIN_1
    specialvar VAR_RESULT, IsTrainerRegistered
    goto_if_eq VAR_RESULT, FALSE, Route102_EventScript_CalvinTryRegister
    msgbox Route102_Text_CalvinPostBattle, MSGBOX_DEFAULT
    release
    end

If the trainer has other script commands before the eventual trainerbattle macro, the first command in the script needs to be vsseeker_rematchid. This macro does nothing but takes a single argument, which should be the same as the first Trainer ID for this trainer.

MOVEMENT_TYPE_COUNTER_CLOCKWISE

If you want Trainers to spin once they are eligible for a rematch, their overworld graphics object ID (include/constants/event_objects.h) must be listed in either regularTrainersOnLand or regularTrainersInWater.Otherwise they will adopt the movement type MOVEMENT_TYPE_FACE_DOWN.

What can be customized about the Vs. Seeker?

  • Unlock Conditions: The next “level” of rematches is unlocked when a specific flag is set. The flags that are currently used in GetGameProgressFlags can be changed to flags that better suit your game.
  • Recharge Steps: VSSEEKER_RECHARGE_STEPS is initally set to 100, but this value can be changed to any number under 256.
  • Badge Requirement: HasAtLeastFiveBadges is used to check if the Vs. Seeker will successfully work. You can customize the number of badges by changing REMATCH_BADGE_COUNT or otherwise alterting the function.

What are the limitations of the Vs. Seeker?

The Vs. Seeker does not currently work with Gym Leaders. There is a bug filed to hopefully fix this in the future.

Pokeemerald-Expansion Changelogs

1.10.x

1.9.x

1.8.x

1.7.x

1.6.x

1.5.x

1.4.x

1.3.x

1.2.x

1.1.x

1.0.x

Pre-1.0.x:

Version 1.14.1

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.14.1
`.

🧬 General 🧬

Changed

  • Pret merge, (1st of December, 2025) by @hedara90 in #8402
    • This changes all the audio samples from .aif to .wav, .aif support is removed.
    • There’s a migration script to convert from .bin to .wav in migration_scripts/1.14/bin_to_wav.py.
    • Run the migration script with python migration_scripts/1.14/bin_to_wav.py path/to/folder/with/bin/samples

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.14.0...expansion/1.14.1

Version 1.14.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.14.0
`.

🌋 REFACTORS 🌋

📜 = Uses a migration script.

  • Refactors Attackstring and PP deduction by @AlexOn1ine in #7402
  • Attackcanceller fixes and improvements by @AlexOn1ine in #7698
  • Fixes activation order for a couple abilities by @AlexOn1ine in #7732
  • feat: change defines in constants/abilities.h to an enum by @khbsd in #7006
  • Item battle effect refactor by @AlexOn1ine in #7857
  • Optimize GetWhichBattlerFasterOrTies by @AlexOn1ine in #7953
  • Decouple passive hp updates from move damage updates by @AlexOn1ine in #7942
  • Make movelist calculations happen during compilation instead of runtime by @FosterProgramming in #7967
    • tmIlliterate flag in speciesInfo changed to teachingType. The options are DEFAULT_LEARNING, TM_ILLITERATE and ALL_TEACHABLES. The first two options match the tmIlliterate = false and tmIlliterate = true while the third one allow a pokemon to learn all teachables similarly to Mew
    • Reduce EWRAM usage of HGSS dex
    • Fix pokemon.c needing to be recompiled everytime a .inc file was changed
    • P_TUTOR_MOVES_ARRAY has been removed (now always true when HGSS dex is enabled)
    • Mew move teaching exception and univeral moves are now coded in the JSON file src/data/pokemon/special_movesets.json under the name signatureTeachables and universalMoves
  • Grudge, Destiny Bond and FaintBattler refactor by @AlexOn1ine in #8072
  • Increase number of additional move effects by @AlexOn1ine in #8149
  • 📜 update: time-based encounters system tuneup and @cawtds’ header script by @khbsd in #8158
  • Refactor random functions to be runner specific by @FosterProgramming in #7816

🧬 General 🧬

Added

  • Battle debug menu: highlight chosen action and change separator by @grintoul1 in #7709

  • Implement field_name_box by @mudskipper13 in #7697

  • Add new actions to Debug Menu by @FosterProgramming in #7837

    • Adds an action to change a Pokemon ability in the party side of the Debug Menu
    • Adds an action to set the friendship of a Pokemon in the party side of the Debug Menu
  • Display TM/HM’s move name in the debug menu by @estellarc in #7994

Changed

  • Text rendering optimizations by @mrgriffin in #7497
  • Battle debug menu now checks correct parties depending on battler party by @grintoul1 in #7652
  • Add make release target by @jschoeny in #7296
    • Most of what’s above. But most importantly, that normal make will have all the debug stuff enabled and so releases should be done with make release.
  • Add pool rules for Mega Stones and Z-Crystals by @hedara90 in #7720
  • field_name_box smol followup by @mudskipper13 in #7762
  • Added COMPOUND_STRINGs to region_map_entries.h by @fdeblasio in #7669
  • Improve ability/heldEffect access for IsBattlerGrounded func by @AlexOn1ine in #7753
  • Removed SAVE_TYPE_ERROR_SCREEN config by @AsparagusEduardo in #7836
  • Give the Coin Case when coins are maxed by @estellarc in #7973
  • Revert HGSS dex and movelist changes by @FosterProgramming in #8016
  • Converts some defines to enums and name unnamed enums by @Bassoonian in #8019
  • Some more documentation and cleanup by @Bassoonian in #8020
  • Even more enums and documentation by @Bassoonian in #8029
  • Add type enum by @Bassoonian in #8054
  • Minor clean up in menu.c by @estellarc in #8060
  • Adds an auto-generated include file of script commands by @FosterProgramming in #8156
  • Master to upcoming merge 20251107 by @grintoul1 in #8167
  • porymap default settings by @FosterProgramming in #8038
    • WARNING: A change was made for new projects map files to match poymap output. This change might break people’s projects with existing versions of those files. The files affected are data/maps/map_groups.json, src/data/heal_locations.json, src/data/region_map/region_map_sections.json and src/data/wild_encounters.json If you have an issue with one of those files during the merging process, you should run this command git checkout HEAD -- <filename> which will reset the file to the version before you initiated the merge
  • Adjust label workflow to only run if PR is approved by @hedara90 in #8183
  • Add include/constants/script_commands.h to gitignore by @AlexOn1ine in #8169
  • Converted landmarks to COMPOUND_STRINGs by @fdeblasio in #8205
  • Added contest config and cleaned up contest category variables by @fdeblasio in #8178
  • Moves name box configs into a new file by @AlexOn1ine in #8250
  • Converted options text into COMPOUND_STRINGs by @fdeblasio in #8248
  • Adjust Canceler naming to contain only one l by @AlexOn1ine in #8258
  • Pret merge (16th of November, 2025) by @AlexOn1ine in #8262
  • Fixed bKGD for last_used_ball_r_cycle.png by @montmoguri in #8261
  • Small bg drawing optimization by @estellarc in #8259
  • Added missing ‘coolness’ string by @fdeblasio in #8274
  • *.party: text with lfs by @mrgriffin in #8320
  • Fedora install instructions by @estellarc in #8355
  • Indent unintented if statement by @hedara90 in #8367

Fixed

  • Added brackets where needed by @hedara90 in #7781
  • Fix shiny stars being freed before shiny animation was played by @FosterProgramming in #7917
    • Fixes shiny sparks in battle not appearing properly in rare circumstances (more common with various speedup options)
  • Make movelist calculations happen during compilation instead of runtime by @FosterProgramming in #7967
    • tmIlliterate flag in speciesInfo changed to teachingType. The options are DEFAULT_LEARNING, TM_ILLITERATE and ALL_TEACHABLES. The first two options match the tmIlliterate = false and tmIlliterate = true while the third one allow a pokemon to learn all teachables similarly to Mew
    • Reduce EWRAM usage of HGSS dex
    • Fix pokemon.c needing to be recompiled everytime a .inc file was changed
    • P_TUTOR_MOVES_ARRAY has been removed (now always true when HGSS dex is enabled)
    • Mew move teaching exception and univeral moves are now coded in the JSON file src/data/pokemon/special_movesets.json under the name signatureTeachables and universalMoves
  • Fix unhandled config in hgss dex by @FosterProgramming in #7999
  • Fixes compilation error due to #8002 by @AlexOn1ine in #8050
  • Fix compile issue in gcc 11 by @AsparagusEduardo in #8095
  • Update mdbook to v0.5.0-beta.1 by @rayrobdod in #8133
  • Fix build failing with NOOPT=1 due to discarding static data. by @Ultimate-Bob in #8053
  • Fix wild_encounters script not closing arrays properly by @FosterProgramming in #8123
  • Fix missing FREE_MATCH_CALL by @FosterProgramming in #8171
  • Again fixed compiling in GCC11 by @AsparagusEduardo in #8184
  • Fix scroll prompt sometimes being off-screen with automatic line breaks by @hedara90 in #8182
  • Fix gcc11 again by @AsparagusEduardo in #8188
  • Fixed decompression error reporter OOB window creation by @hedara90 in #8199
  • Fix error when compiling with P_FUSION_FORMS disabled by @cawtds in #8298
  • Fix compile on gcc11 by @AlexOn1ine in #8300
  • Fix debug battle flag never being cleared by @FosterProgramming in #8357

🗺️ Overworld 🗺️

Added

  • New Feature: ORAS Dowsing by @Bivurnum in #7211
    • Added ORAS Dowsing Machine mechanics.
  • feat: adds stevebeller’s instant text and MandL27’s faster text printing by @khbsd in #8063
  • Implement GSC berry/apricorn tree functionality. by @GraionDilach in #7777
    • Implement GSC berry/apricorn tree functionality.

Changed

  • Trainers trigger in local id order by @grintoul1 in #7424
  • Added regional form evolution condition by @AsparagusEduardo in #6990
  • Update fishing odds to match official games by @FosterProgramming in #7574
    • (BREAKING!) Fishing config has been moved to a new file. If you did not use default config fishing, make sure to reapply your config settings in the new file.
    • (WARNING!) If you wrote custom code that calls one the following function, you may need to include fishing.h to get access to them(their functionaly was not affected):
    • StartFishingpreviously defined in field_player_avatar.h
    • CalculateChainFishingShinyRolls previously_defined in wild_encounter.h
    • Adds a new config option to increase fish bite chance in morning and evening to match XY
    • Modifies the way fishing “proximity boost” is calculated to match XY
    • Fix Sticky Hold / Suction Cups bug which were increasing odds the wrong way
  • Add additional comment explaing map name popup transparency side-effects by @FosterProgramming in #8117
  • update: time-based encounters system tuneup and @cawtds’ header script by @khbsd in #8158
  • Sets instant text speed flag to false by default by @khbsd in #8179
  • Follower NPCs no longer move if the player would be forced back onto the same tile. by @Bivurnum in #8260
    • Follower NPCs no longer move if the player would be forced back onto the same tile

Fixed

  • CheckForTrainersWantingBattle trainerObjects array now initialized to zero and loop now starts at zero by @grintoul1 in #7765
  • Bugfix setspeaker Namebox not beign drawn correctly by @estellarc in #7771
  • Banned species list by @FosterProgramming in #8003
    • Add a window displaying caught banned species list in the Battle Frontier instead of the string detailing all the is
  • Fix namebox bug when reloading the map mid-script by @FosterProgramming in #8073
  • Fix copyvar instead of setvar causing issue with LTO by @FosterProgramming in #8097
  • Fix berry blender not computing flavor correctly by @FosterProgramming in #8113
  • Allow vs seekers to work with script not starting with trainerbattle by @FosterProgramming in #8062
    • VS seeker now work with trainers who don’t start with trainer_battle. You can use vsseeker_rematchid TRAINER_ID to indicate that this NPC is a battling trainer and the game will fetch the appropriate rematch if necessary. vsseeker_rematchid work like a cant_see_if_trainerflag_set with additional functionality to handle vs seeker.
    • All NPCs who don’t start with either vsseeker_rematchid or trainerbattle will show as “X”/unmatchable by the vs seeker, so non-rematchable trainer who do not start with trainerbattle may "lie" and not show an excalmation mark showing they haven't been fought yet. This can be fixed by including a vsseeker_rematchid` for them too.
  • Fix grade in summary screen not accounting for 26 IV by @FosterProgramming in #8157
  • Fix match call regression by @FosterProgramming in #8227
  • Fix mew sprite not appearing correctly by @FosterProgramming in #8235
  • Fix wrong palette for types sprites in hgss dex after catching mon by @FosterProgramming in #8153
  • Fix Apricorns with OW_SHOW_ITEM_DESCRIPTIONS not off by @hedara90 in #8253
  • Fix mirage tower ceiling crumble color by @FosterProgramming in #8081
  • Fix light flickering when different types of light sprite are present by @FosterProgramming in #8043
    • Light intensity of neon signs was reduced to avoid conflicts with other light sources
    • Fix flickering when both neon signs and light ball are present on screen
  • Bug Fix: NPC Followers not working on slow sideways stairs by @Bivurnum in #8257
    • Fixed NPC followers on slow sideways stairs
  • Fix not enough memory being allocated when moves load background in contests by @FosterProgramming in #8284
  • Make MON_DATA_NICKNAME10 return a 10 character string by @FosterProgramming in #8291
    • Fix bug where interviews would print bad data in their string
  • Fix game freeze when trainers try to walk on sideway stairs by @FosterProgramming in #8316
  • Fix tossing items applying to the wrong stack by @FosterProgramming in #8282
  • Prevent moves to be changed when choosing half party by @FosterProgramming in #8336

🐉 Pokémon 🐉

Added

  • Add Legends Z-A content by @Bassoonian in #7935
    • To retain compatibility with your new items and species, make sure to move the new additions behind your own additions.
    • The save block will shift if you have enabled USE_DEXNAV_SEARCH_LEVELS (due to the new species) or if OW_SHOW_ITEM_DESCRIPTIONS is set to OW_ITEM_DESCRIPTIONS_FIRST_TIME (due to the new items).
  • Move Relearners for TMs, Tutors and Egg moves by @PCG06 in #8040
    • Increased the size of MAX_RELEARNER_MOVES to 60 to prevent crashes when viewing Mew.

Changed

  • Nickit & Thievul visual revamp by @purrfectdoodle in #7689
  • Fix Kyurem typo in swap move tables by @Bassoonian in #8139
  • Fix typo in Voltorb-Hisui pokedex entry by @PhallenTree in #8143
  • Fix some followers sprites by @estellarc in #8208

Fixed

  • Fix gba sprites trying load non existent female versions by @FosterProgramming in #7996
    • Fixes issues with pokemon getting gender differences in later gens when using gen3 sprite config
  • GetEggSpecies: Only enabled species by @mrgriffin in #8221
  • Fix compiling using make debug by @PCG06 in #8380

⚔️ Battle General ⚔️

Added

  • Config for capture to appear critical if the pokemon is already caught by @FosterProgramming in #7730

Changed

  • Separates FRB and FRZ animations by @grintoul1 in #7611
  • Update multiple battle messages by @AsparagusEduardo in #7529
    • Removed unused messages
    • Changed ability “X prevents Y” to “It doesn’t affect X…”
    • Eg. "The opposing Snorlax's Immunity prevents poisoning!"
    • Removed B_ABILITY_POP_UP. Revert commit b501fe7354bcd957396465c621ae7af5959ac5b0 to undo this.
  • Refactors Attackstring and PP deduction by @AlexOn1ine in #7402
  • Remove Uproar attack battle script by @AlexOn1ine in #7715
  • Fix up end turn scripts plus small documentation by @AlexOn1ine in #7758
  • Remove redundant function call by @AlexOn1ine in #7752
  • Minor White Herb and Neutralizing Gas clean up by @AlexOn1ine in #7754
  • Minor clean up for Lightning Rod / Storm Drain by @AlexOn1ine in #7778
  • Improve ability/heldEffect access for IsBattlerGrounded func by @AlexOn1ine in #7753
  • Add func GetChosenMoveFromPosition by @AlexOn1ine in #7810
  • GetBattlerHoldEffect clean up by @AlexOn1ine in #7819
  • Remove unused gBattleStruct fields by @Bassoonian in #7822
  • feat: change defines in constants/abilities.h to an enum by @khbsd in #7006
  • Streamline tryheal macros by @Bassoonian in #7830
  • No bag use flag changed to a varable by @FosterProgramming in #7780
    • IMPORTANT: The config flag B_FLAG_NO_BAG_USE has been removed
    • A config var B_VAR_NO_BAG_USE has been added to replace it. It allows you to choose between: bag available in battle, bag available in wild battle only, and unavailable bag
  • Remove two unused bits from battle structs by @Bassoonian in #7835
  • Removes a few redundant hitmarkers by @AlexOn1ine in #7915
  • Remove EffectHitSetTerrain script to use moveeffect by @AlexOn1ine in #7938
  • Clean up follow up for AtkCanceller refactor by @AlexOn1ine in #7951
  • Optimize GetWhichBattlerFasterOrTies by @AlexOn1ine in #7953
  • Decouple passive hp updates from move damage updates by @AlexOn1ine in #7942
  • Remove appearedInBattle bitfield & redundant use of sentOut partyState by @Nopinou in #8011
  • Volatile cleared in a redundant spot by @AlexOn1ine in #8015
  • Moved usedHeldItem to Party State struct by @AlexOn1ine in #8006
  • Remove usage of gBattlerTarget for MirrorHerb/Opportunist by @AlexOn1ine in #8033
  • Fixed test “Revival Blessing cannot revive a partner’s party member” by @grintoul1 in #8031
  • Decouple (Overworld) Statuses from ability function by @AlexOn1ine in #8002
  • Combine Simple Beam and Worry Seed into one effect by @AlexOn1ine in #8039
  • Clean up for item hold effect refactor by @AlexOn1ine in #8014
  • Grudge, Destiny Bond and FaintBattler refactor by @AlexOn1ine in #8072
  • Parametrized Ice Face’s weather form change by @AsparagusEduardo in #8115
  • Clean up redundant todo by @AlexOn1ine in #8094
  • Deprecate various macro by @AlexOn1ine in #8092
  • Fixes hacky SetMoveEffect script calls by @AlexOn1ine in #7987
  • Create BattleStruct sub struct for event states by @AlexOn1ine in #8131
  • Attackstring hitmarker clean up by @AlexOn1ine in #8136
  • Clean up ability effect hitmarker by @AlexOn1ine in #8138
  • Increase number of additional move effects by @AlexOn1ine in #8149
  • Remove redundant Future Sight flag by @AlexOn1ine in #8185
  • Powder Move blocking cleanup by @PhallenTree in #8194
  • Micro clean up in BattleStruct by @AlexOn1ine in #8177
  • HandleAction_UseMove minor cleanup by @mrgriffin in #8214
  • Revert gBattleTurnCounter change by @AlexOn1ine in #8197
  • Canceller -> Canceler rename by @AlexOn1ine in #8294
  • Remove leftover scrtipt redirection by @AlexOn1ine in #8317
  • Expand usage of FaintedActions enum in HandleFaintedMonActions by @PhallenTree in #8346
  • Move end clear bits clean up by @AlexOn1ine in #8354
  • Restored encourageEncore flag to non-volatile status effects by @AsparagusEduardo in #8387

Fixed

  • Fixes Weak Armor and items not displaying stat change attributes by @PhallenTree in #7701
  • Refactors ruin ability checks into a field effect by @AlexOn1ine in #7711
  • Attackcanceller fixes and improvements by @AlexOn1ine in #7698
  • Fix Critical Capture RNG and Catching Charm boost by @kittenchilly in #7534
  • Fixes activation order for a couple abilities by @AlexOn1ine in #7732
  • More White Herb fixes/clean up by @AlexOn1ine in #7826
  • Missing IsBattlerAlive checks in Opportunist/Mirror Herb by @AlexOn1ine in #7829
  • Item battle effect refactor by @AlexOn1ine in #7857
  • Fix Fling Mental Herb message by @AlexOn1ine in #7984
  • Fixes Ruin field statuses negation conditions + upcoming cleanup by @PhallenTree in #8042
  • Fix nature power string and add support for evnvironment in tests by @FosterProgramming in #8068
    • Add option to choose an environment when setting up a battle test
  • Corrects battler position checks in battle_message.c by @grintoul1 in #8070
  • Emergency Exit on hazards activation + fix end of turn activation by @PhallenTree in #8075
  • Improve sBattleIntroSlideFuncs bounds check by @hedara90 in #8084
  • Fixes Sticky Barb never getting transferred to attacker + tests by @PhallenTree in #8108
  • Fixes flung items sometimes being blocked by Unnerve by @PhallenTree in #8114
  • Adjust faint battler script by @AlexOn1ine in #8137
  • Allow to send active mon to PC when capturing a Pokemon by @FosterProgramming in #8111
  • Fix transform not loading the correct sprites when facing shiny or unown by @FosterProgramming in #8146
  • Fixes Receiver not immediately activating copied abilities by @PhallenTree in #8162
  • Fix destiny knot behavior and add tests by @FosterProgramming in #8174
  • Fix recharge moves + add recharge move tests by @FosterProgramming in #8181
  • Fixes Magician for spread moves by @AlexOn1ine in #8170
  • Fix tera tint not applying on activation by @FosterProgramming in #8135
  • Fixes wrongly assigned count for Semi Invulnerable state by @AlexOn1ine in #8175
  • Fixes Drain Punch / Parental Bond / Scale Shot interaction by @AlexOn1ine in #8198
  • Avoid illegal GetBattlerAtPosition by @mrgriffin in #8225
  • DamageContext: chosenMove by @mrgriffin in #8224
  • AccuracyCheck: Avoid calling GetMoveEffect with NO_ACC_CALC_CHECK_LOC… by @mrgriffin in #8222
  • moveend: Handle MOVE_UNAVAILABLE in MOVEEND_THIRD_MOVE_BLOCK by @mrgriffin in #8215
  • Fix wrong ditto sprite on capture by @FosterProgramming in #8226
  • SpriteCB_EnemyShadow: Avoid use-after-free by @mrgriffin in #8220
  • trysethelpinghand avoid illegal target by @mrgriffin in #8218
  • Fixed an issue related to same turn Encore targeting by @LinathanZel in #8230
  • Avoid illegal move retargeting in singles by @mrgriffin in #8217
  • Fixes Shell Trap not activating on contact but no damage by @AlexOn1ine in #8243
  • Fix Magic Coat reflecting hazard moves incorrectly when used by a partner by @moostoet in #8272
    • Magic Coat now properly reflects hazard moves from either slot in double battles.
  • Shell Trap tests and Fix for Encore interaction by @AlexOn1ine in #8268
  • Fix max mushroom unable to be selected when one stat is maxed by @FosterProgramming in #8287
  • Block selecting x items when contrary pokemon are at minimum stages by @FosterProgramming in #8288
  • Fix Fur Coat affecting confusion self-damage by @moostoet in #8267
    • Fix confusion self-damage ignoring defense/attack abilities such as Fur Coat.
  • Fixes End Turn Speed Order by @AlexOn1ine in #8289
  • Make switchout abilities trigger after a pokemon has returned to its ball by @FosterProgramming in #8304
  • Fix Shed Shell allowing fleeing/teleporting and Smoke Ball failing to guarantee escape by @moostoet in #8286
  • Fix bug where defiant/competitive would pass their stat change to the next target by @FosterProgramming in #8312
  • Fix max move message against semi invulnerable target by @FosterProgramming in #8313
  • Fixes Neutralizing Gas displaying message when exiting with multiple users by @PhallenTree in #8318
  • Fix Kings Rock not being ignored by flinch moves by @AlexOn1ine in #8327
  • Fix Upper Hand failure still activating Protean by @AlexOn1ine in #8329
  • Fix Protosynthesis stat boosts ignoring speed drops by @moostoet in #8277
    • Protosynthesis and Quark Drive now recalculate their boosted stat when Speed is lowered or Neutralizing Gas temporarily disables the ability.
  • Fix switch-in abilities not triggering on revive by @FosterProgramming in #8293
  • More Neutralizing Gas cleanup by @PhallenTree in #8335
  • Clear Destiny Bond/Grudge bits when not activated by @PhallenTree in #8334
  • Fix cure status item effect not working properly in doubles by @FosterProgramming in #8339
  • Fix infinite confusion (berserk gene) not being cured by cure_status bag items by @FosterProgramming in #8343
  • Fix B_PHYSICAL_SPECIAL_SPLIT when set to Gen 4 by @AsparagusEduardo in #8348
  • Refactor Beat Up handling for Gen 3/4 defaults, fix crit check, and expand test coverage by @moostoet in #8307
    • BUGFIX: Beat Up (GEN =< 5) now no longer doubles its damage on every non-critical hit
    • Beat Up now precomputes eligible party members/strikers for consistent multi-hit resolution and expanded tests covering both pre-Gen5 and Gen5+ rules
  • Fix substitute graphic not disappearing after using a pivor move by @FosterProgramming in #8340
  • Fixes Beak Blast burning after Beak Blast was already used by @PhallenTree in #8361
  • Fix Roar not being recorded for LastUsedMove by @AlexOn1ine in #8362
  • Fixes Neutralizing Gas / Mold Breaker / Dragon Darts interaction by @AlexOn1ine in #8389
  • Fixes battle tv overwriting damage values by @AlexOn1ine in #8378
  • Fix ball cycling not working properly when the same ball take multiple bag slots by @FosterProgramming in #8163
    • Two new defines added to items.h FIRST_BALL_INDEX and LAST_BALL_INDEX
    • We now assume the indexes of all regular ball usable in wild battle have consecutive indexes and some features (throw ball shortcut in battle) might break if not true
  • Prevent double Dynamax for single-trainer 2v1 multi battles by @moostoet in #8323
    • Fixed AI 2v1 multibattles incorrectly allowing both opponent leads to Dynamax in the same turn.

🤹 Moves 🤹

Changed

  • Separates FRB and FRZ animations by @grintoul1 in #7611
  • Fixed test “Revival Blessing cannot revive a partner’s party member” by @grintoul1 in #8031
  • Fixed Uproar’s description and spacing by @fdeblasio in #8187
  • Clean usage of gMovesInfo by @AsparagusEduardo in #8234
    • Also, fixed an OOB in HasMoveThatChangesKOThreshold
  • Added Gen 6 contest combos by @fdeblasio in #8251
  • Make tailwind anim mirror based on side by @FosterProgramming in #8249
  • Make rainbow effect anim change based on side by @FosterProgramming in #8269
  • Update Lash Out description to clarify its effect by @PhallenTree in #8372

Fixed

  • Fix some move animations leaking VRAM and freeing already freed tags by @hedara90 in #7977

🎭 Abilities 🎭

Changed

  • followup: AbilityBattleEffects return type is incorrect by @khbsd in #7827

🧶 Items 🧶

Fixed

  • Allow vs seekers to work with script not starting with trainerbattle by @FosterProgramming in #8062
    • VS seeker now work with trainers who don’t start with trainer_battle. You can use vsseeker_rematchid TRAINER_ID to indicate that this NPC is a battling trainer and the game will fetch the appropriate rematch if necessary. vsseeker_rematchid work like a cant_see_if_trainerflag_set with additional functionality to handle vs seeker.
    • All NPCs who don’t start with either vsseeker_rematchid or trainerbattle will show as “X”/unmatchable by the vs seeker, so non-rematchable trainer who do not start with trainerbattle may "lie" and not show an excalmation mark showing they haven't been fought yet. This can be fixed by including a vsseeker_rematchid` for them too.
  • Removed extra period in Pokéshi Doll description by @montmoguri in #8252

🤖 Battle AI 🤖

Added

  • Improved move additional effect handling; now accounts for Shield Dust. by @surskitty in #7650
  • Adjusted AI handling for Gravity; AI for weather/field status additional effects. by @surskitty in #7651
  • Improved AI for status curing; trainer items, Purify, Smelling Salts, Sparkling Aria by @surskitty in #7853

Changed

  • AI uses Magnetic Flux. by @surskitty in #7642
  • AI uses Flower Shield. by @surskitty in #7640
  • AI uses Life Dew. by @surskitty in #7643
  • AI uses Gear Up. by @surskitty in #7641
  • Correcting test AI won’t use status moves if partner chose Helping Hand by @surskitty in #7649
  • IncreaseStatUpScore adjustments for Simple, +3 moves, Acupressure, max move effects by @surskitty in #7662
  • AI handling for Coaching. by @surskitty in #7661
  • Simplifying calls to IsBattlerTrapped; treats being unable to switch as trappedness by @surskitty in #7671
  • AI Tests: Gimmick Support by @mrgriffin in #7694
  • AI can use Z-status moves by @surskitty in #7666
  • Move some checks out of IncreaseStatUpScore to ShouldRaiseAnyStat by @surskitty in #7722
  • Moving additional effects out of AI_CalcMoveEffectScore and into AI_CalcMoveAdditionalEffectScore by @surskitty in #7727
  • AI sees dynamic moves and Nature Power as correct types for weather, terrain by @surskitty in #7759
  • Fix abusable two-turn-move switch behaviour by @Pawkkie in #7770
  • Z Status move handling: Conversion, Detect, Nature Power, Transform by @surskitty in #7721
  • Use stored values for ai switch-in effectiveness checks by @AlexOn1ine in #7794
  • Changing all HasBattlerSideAbility to AI_IsAbilityOnSide. by @surskitty in #7927
  • Weather/Terrain AI touch-ups. by @surskitty in #7933
  • Improving the checks for the AI to avoid Encore; adding RISK_ENCORE_CHANCE config. by @surskitty in #7929
  • Fixes CanUseLastResort and resolves 3 KNOWN_FAILING Last Resort tests by @grintoul1 in #8032
  • Add AI flag AI_FLAG_KNOW_OPPONENT_PARTY to know all species in party by @moostoet in #8290

Fixed

  • Score adjustments towards guaranteed stat drops. by @surskitty in #7670
  • AI uses Extreme Evoboost. by @surskitty in #7706
  • Fixes AI scoring when Priority moves are blocked by @PhallenTree in #7745
  • fix (AI scoring): shield dust considerations, IsMoveEffectInMinus self effect edge case, hitsToKO zero-case consideration by @ghostyboyy97 in #8126
    • The AI now sees Shield Dust on the player’s Pokemon correctly
    • The AI now sees self-targeted positive effect boosts correctly
  • fix (contrary): Contrary stat down handling in MoveEffectInPlus by @ghostyboyy97 in #8165
    • When comparing positive move effects in damaging move comparison, the AI will correctly see moves like Leaf Storm as beneficial if their Pokemon has Contrary.
  • Added check for parental bond killing through sturdy by @MaximeGr00 in #8206
    • AI now accounts for Parental Bond when checking if a move can ko the player through sturdy/focus sash.
  • AI: Handle MOVE_UNAVAILABLE in last used moves by @mrgriffin in #8219
  • Fix AI_FLAG_DOUBLE_ACE_POKEMON sending duplicate Pokémon in doubles by @moostoet in #8279
    • Fixed AI_FLAG_DOUBLE_ACE_POKEMON trainers resending the same Pokémon after a KO instead of their two Ace Pokémon in double battles.
  • Rework switch AI and add more tests for ace pokemon flags by @FosterProgramming in #8321
    • All remaining issues with the AI flags Ace Pokemon and Double Ace pokemon should be fixed
    • The smart switching AI should be less likely to switch a pokemon about to die if it doesn’t have a pokemon with a good matchup to replace it
  • Fix switchin KO threshold logic by @Pawkkie in #8370

🧹 Other Cleanup 🧹

  • Update multiple battle messages by @AsparagusEduardo in #7529
    • Removed unused messages
    • Changed ability “X prevents Y” to “It doesn’t affect X…”
    • Eg. "The opposing Snorlax's Immunity prevents poisoning!"
    • Removed B_ABILITY_POP_UP. Revert commit b501fe7354bcd957396465c621ae7af5959ac5b0 to undo this.
  • Battle debug menu now checks correct parties depending on battler party by @grintoul1 in #7652
  • Correcting test AI won’t use status moves if partner chose Helping Hand by @surskitty in #7649
  • Remove Uproar attack battle script by @AlexOn1ine in #7715
  • Fix up end turn scripts plus small documentation by @AlexOn1ine in #7758
  • field_name_box smol followup by @mudskipper13 in #7762
  • Remove redundant function call by @AlexOn1ine in #7752
  • Minor White Herb and Neutralizing Gas clean up by @AlexOn1ine in #7754
  • Minor clean up for Lightning Rod / Storm Drain by @AlexOn1ine in #7778
  • Add func GetChosenMoveFromPosition by @AlexOn1ine in #7810
  • GetBattlerHoldEffect clean up by @AlexOn1ine in #7819
  • Remove unused gBattleStruct fields by @Bassoonian in #7822
  • followup: AbilityBattleEffects return type is incorrect by @khbsd in #7827
  • Streamline tryheal macros by @Bassoonian in #7830
  • Remove two unused bits from battle structs by @Bassoonian in #7835
  • Removes a few redundant hitmarkers by @AlexOn1ine in #7915
  • Remove EffectHitSetTerrain script to use moveeffect by @AlexOn1ine in #7938
  • Clean up follow up for AtkCanceller refactor by @AlexOn1ine in #7951
  • Remove appearedInBattle bitfield & redundant use of sentOut partyState by @Nopinou in #8011
  • Some more documentation and cleanup by @Bassoonian in #8020
  • Volatile cleared in a redundant spot by @AlexOn1ine in #8015
  • Moved usedHeldItem to Party State struct by @AlexOn1ine in #8006
  • Remove usage of gBattlerTarget for MirrorHerb/Opportunist by @AlexOn1ine in #8033
  • Even more enums and documentation by @Bassoonian in #8029
  • Decouple (Overworld) Statuses from ability function by @AlexOn1ine in #8002
  • Fixes Ruin field statuses negation conditions + upcoming cleanup by @PhallenTree in #8042
  • Minor clean up in menu.c by @estellarc in #8060
  • Clean up for item hold effect refactor by @AlexOn1ine in #8014
  • Parametrized Ice Face’s weather form change by @AsparagusEduardo in #8115
  • Clean up redundant todo by @AlexOn1ine in #8094
  • Deprecate various macro by @AlexOn1ine in #8092
  • Fixes hacky SetMoveEffect script calls by @AlexOn1ine in #7987
  • Create BattleStruct sub struct for event states by @AlexOn1ine in #8131
  • Attackstring hitmarker clean up by @AlexOn1ine in #8136
  • Clean up ability effect hitmarker by @AlexOn1ine in #8138
  • Fix Kyurem typo in swap move tables by @Bassoonian in #8139
  • Fix typo in Voltorb-Hisui pokedex entry by @PhallenTree in #8143
  • porymap default settings by @FosterProgramming in #8038
    • WARNING: A change was made for new projects map files to match poymap output. This change might break people’s projects with existing versions of those files. The files affected are data/maps/map_groups.json, src/data/heal_locations.json, src/data/region_map/region_map_sections.json and src/data/wild_encounters.json If you have an issue with one of those files during the merging process, you should run this command git checkout HEAD -- <filename> which will reset the file to the version before you initiated the merge
  • Sets instant text speed flag to false by default by @khbsd in #8179
  • Remove redundant Future Sight flag by @AlexOn1ine in #8185
  • Fix incorrect comments by @AlexOn1ine in #8193
  • Fixed Uproar’s description and spacing by @fdeblasio in #8187
  • Add include/constants/script_commands.h to gitignore by @AlexOn1ine in #8169
  • Powder Move blocking cleanup by @PhallenTree in #8194
  • Converted landmarks to COMPOUND_STRINGs by @fdeblasio in #8205
  • Micro clean up in BattleStruct by @AlexOn1ine in #8177
  • Clean usage of gMovesInfo by @AsparagusEduardo in #8234
    • Also, fixed an OOB in HasMoveThatChangesKOThreshold
  • HandleAction_UseMove minor cleanup by @mrgriffin in #8214
  • Revert gBattleTurnCounter change by @AlexOn1ine in #8197
  • Added contest config and cleaned up contest category variables by @fdeblasio in #8178
  • Adjust Canceler naming to contain only one l by @AlexOn1ine in #8258
  • Fix wrongly renamed logs by @AlexOn1ine in #8264
  • Test type enum indentation by @AsparagusEduardo in #8273
  • Added missing ‘coolness’ string by @fdeblasio in #8274
  • Canceller -> Canceler rename by @AlexOn1ine in #8294
  • Tests for Max Moves already exist by @AlexOn1ine in #8314
  • Documentation clean up for MoveCanceler by @AlexOn1ine in #8297
  • Use MAP_OFFSET by @estellarc in #8328
  • Remove leftover scrtipt redirection by @AlexOn1ine in #8317
  • Fixed broken friendship from items in battle test and added new test for opposite case by @pkmnsnfrn in #7872
  • Expand usage of FaintedActions enum in HandleFaintedMonActions by @PhallenTree in #8346
  • Move end clear bits clean up by @AlexOn1ine in #8354
  • Indent unintented if statement by @hedara90 in #8367
  • Update Lash Out description to clarify its effect by @PhallenTree in #8372
  • Slight Protect moveend cleanup by @AsparagusEduardo in #8385
  • Restored encourageEncore flag to non-volatile status effects by @AsparagusEduardo in #8387

🧪 Test Runner 🧪

Added

  • Multibattle testing system by @grintoul1 in #7257
  • Prevent EXPECT functions from casting negative numbers into unsigned by @FosterProgramming in #7866

Changed

  • AI Tests: Gimmick Support by @mrgriffin in #7694
  • Some tests for future Dynamax AI behavior. by @surskitty in #7707
  • Add some missing move animations to the move animation tests by @FosterProgramming in #7507
  • Fixes CanUseLastResort and resolves 3 KNOWN_FAILING Last Resort tests by @grintoul1 in #8032
  • Fixed test “Revival Blessing cannot revive a partner’s party member” by @grintoul1 in #8031
  • Added Soundproof and Bulletproof tests by @AsparagusEduardo in #8189
  • Wrote some missing tests by @AsparagusEduardo in #8203
  • Refactor random functions to be runner specific by @FosterProgramming in #7816
  • A couple more tests by @AsparagusEduardo in #8209
  • Fixed some failing tests with GEN_LATEST = GEN_5 by @AsparagusEduardo in #8241
  • Add test for mold breaker/ice scales interaction by @FosterProgramming in #8240
  • Yet more tests by @AsparagusEduardo in #8228
    • Added tests for:
    • Dark Aura
    • Fairy Aura
    • Flare Boost
    • Toxic Boost
    • Added test names for Flying Press.
  • Test type enum indentation by @AsparagusEduardo in #8273
  • Slightly increase headless test speed by modifying animations by @AsparagusEduardo in #8299
  • Make gTestRunnerHeadless into a constant outside of tests by @hedara90 in #8306
  • Tests for Max Moves already exist by @AlexOn1ine in #8314
  • Finished fixing tests when setting GEN_LATEST to GEN_5 by @AsparagusEduardo in #8263
  • Wrote missing Fling tests by @AsparagusEduardo in #8383

Fixed

  • Corrects ONE_VS_TWO_BATTLE_TEST to use BATTLE_TEST_ARGS_ONE_VS_TWO by @grintoul1 in #8061
  • Fixes difficulty not being restored after tests by @grintoul1 in #8129
  • Reset saveblock data between test runs by @hedara90 in #8145
  • Sheer force test fix by @grintoul1 in #8142
  • Test only enabled species by @mrgriffin in #8216
  • Fix ohko moves ai tests by @FosterProgramming in #8309
  • Fixed broken friendship from items in battle test and added new test for opposite case by @pkmnsnfrn in #7872
  • Add tests to verify aromatherapy is not affected by heal bell config by @FosterProgramming in #8344
  • Pre gen 5 encored move now signals the test engine a move is happening by @FosterProgramming in #8338
  • Refactor Beat Up handling for Gen 3/4 defaults, fix crit check, and expand test coverage by @moostoet in #8307
    • BUGFIX: Beat Up (GEN =< 5) now no longer doubles its damage on every non-critical hit
    • Beat Up now precomputes eligible party members/strikers for consistent multi-hit resolution and expanded tests covering both pre-Gen5 and Gen5+ rules
  • Fix player and partner trainer sprite palettes to 8 and 9, preventing unwanted palette changes by @grintoul1 in #8127
  • Fix known failing AI trace test by @FosterProgramming in #8337

📚 Documentation 📚

  • Converts some defines to enums and name unnamed enums by @Bassoonian in #8019
  • Some more documentation and cleanup by @Bassoonian in #8020
  • Even more enums and documentation by @Bassoonian in #8029
  • Add type enum by @Bassoonian in #8054
  • Revert reversion by @AlexOn1ine in #8112
  • Lock mdbook to v0.4.35 to fix docs not building by @grintoul1 in #8130
  • Add additional comment explaing map name popup transparency side-effects by @FosterProgramming in #8117
  • Fix incorrect comments by @AlexOn1ine in #8193
  • Moves name box configs into a new file by @AlexOn1ine in #8250
  • Fix wrongly renamed logs by @AlexOn1ine in #8264
  • Documentation clean up for MoveCanceler by @AlexOn1ine in #8297
  • Use MAP_OFFSET by @estellarc in #8328
  • Fedora install instructions by @estellarc in #8355

New Contributors

  • @purrfectdoodle made their first contribution in #7689
  • @montmoguri made their first contribution in #8252

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.13.3...expansion/1.14.0

Version 1.13.4

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.13.4
`.

🧬 General 🧬

Changed

  • 1.13.3 release by @hedara90 in #8109
  • Adds an auto-generated include file of script commands by @FosterProgramming in #8156
  • Adjust label workflow to only run if PR is approved by @hedara90 in #8183
  • Add include/constants/script_commands.h to gitignore by @AlexOn1ine in #8169
  • add fdeblasio as a contributor for code by @allcontributors[bot] in #8200
  • Adjust Canceler naming to contain only one l by @AlexOn1ine in #8258
  • Pret merge (16th of November, 2025) by @AlexOn1ine in #8262
  • *.party: text with lfs by @mrgriffin in #8320
  • Fedora install instructions by @estellarc in #8355
  • Indent unintented if statement by @hedara90 in #8367

Fixed

  • Update mdbook to v0.5.0-beta.1 by @rayrobdod in #8133
  • Fix wild_encounters script not closing arrays properly by @FosterProgramming in #8123
  • Fix missing FREE_MATCH_CALL by @FosterProgramming in #8171
  • Fix scroll prompt sometimes being off-screen with automatic line breaks by @hedara90 in #8182
  • Fix gcc11 again by @AsparagusEduardo in #8188
  • Fixed decompression error reporter OOB window creation by @hedara90 in #8199
  • Fix error when compiling with P_FUSION_FORMS disabled by @cawtds in #8298
  • Fix compile on gcc11 by @AlexOn1ine in #8300
  • Fix debug battle flag never being cleared by @FosterProgramming in #8357

🗺️ Overworld 🗺️

Changed

  • Add additional comment explaing map name popup transparency side-effects by @FosterProgramming in #8117

Fixed

  • Fix berry blender not computing flavor correctly by @FosterProgramming in #8113
  • Allow vs seekers to work with script not starting with trainerbattle by @FosterProgramming in #8062
    • VS seeker now work with trainers who don’t start with trainer_battle. You can use vsseeker_rematchid TRAINER_ID to indicate that this NPC is a battling trainer and the game will fetch the appropriate rematch if necessary. vsseeker_rematchid work like a cant_see_if_trainerflag_set with additional functionality to handle vs seeker. All NPCs who don’t start with either vsseeker_rematchid or trainerbattle will show as “X”/unmatchable by the vs seeker, so non-rematchable trainer who do not start with trainerbattle may "lie" and not show an excalmation mark showing they haven't been fought yet. This can be fixed by including a vsseeker_rematchid` for them too.
  • Fix grade in summary screen not accounting for 26 IV by @FosterProgramming in #8157
  • Fix match call regression by @FosterProgramming in #8227
  • Fix mew sprite not appearing correctly by @FosterProgramming in #8235
  • Fix wrong palette for types sprites in hgss dex after catching mon by @FosterProgramming in #8153
  • Fix mirage tower ceiling crumble color by @FosterProgramming in #8081
  • Fix light flickering when different types of light sprite are present by @FosterProgramming in #8043
    • Light intensity of neon signs was reduced to avoid conflicts with other light sources
    • Fix flickering when both neon signs and light ball are present on screen
  • Bug Fix: NPC Followers not working on slow sideways stairs by @Bivurnum in #8257
  • Fix not enough memory being allocated when moves load background in contests by @FosterProgramming in #8284
  • Make MON_DATA_NICKNAME10 return a 10 character string by @FosterProgramming in #8291
    • Fix bug where interviews would print bad data in their string
  • Fix game freeze when trainers try to walk on sideway stairs by @FosterProgramming in #8316
  • Fix tossing items applying to the wrong stack by @FosterProgramming in #8282
  • Prevent moves to be changed when choosing half party by @FosterProgramming in #8336

🐉 Pokémon 🐉

Changed

  • Fix Kyurem typo in swap move tables by @Bassoonian in #8139
  • Fix typo in Voltorb-Hisui pokedex entry by @PhallenTree in #8143
  • Fix some followers sprites by @estellarc in #8208

⚔️ Battle General ⚔️

Changed

  • Clean up redundant todo by @AlexOn1ine in #8094
  • Powder Move blocking cleanup by @PhallenTree in #8194
  • Restored encourageEncore flag to non-volatile status effects by @AsparagusEduardo in #8387

Fixed

  • Allow to send active mon to PC when capturing a Pokemon by @FosterProgramming in #8111
  • Fix transform not loading the correct sprites when facing shiny or unown by @FosterProgramming in #8146
  • Fixes Receiver not immediately activating copied abilities by @PhallenTree in #8162
  • Fix destiny knot behavior and add tests by @FosterProgramming in #8174
  • Fix recharge moves + add recharge move tests by @FosterProgramming in #8181
  • Fixes Magician for spread moves by @AlexOn1ine in #8170
  • Fix tera tint not applying on activation by @FosterProgramming in #8135
  • Fixes wrongly assigned count for Semi Invulnerable state by @AlexOn1ine in #8175
  • Fixes Drain Punch / Parental Bond / Scale Shot interaction by @AlexOn1ine in #8198
  • Fix wrong ditto sprite on capture by @FosterProgramming in #8226
  • Fixed an issue related to same turn Encore targeting by @LinathanZel in #8230
  • Fixes Shell Trap not activating on contact but no damage by @AlexOn1ine in #8243
  • Fix Magic Coat reflecting hazard moves incorrectly when used by a partner by @moostoet in #8272
    • Magic Coat now properly reflects hazard moves from either slot in double battles.
  • Shell Trap tests and Fix for Encore interaction by @AlexOn1ine in #8268
  • Fix max mushroom unable to be selected when one stat is maxed by @FosterProgramming in #8287
  • Block selecting x items when contrary pokemon are at minimum stages by @FosterProgramming in #8288
  • Fix Fur Coat affecting confusion self-damage by @moostoet in #8267
    • Fix confusion self-damage ignoring defense/attack abilities such as Fur Coat.
  • Fixes End Turn Speed Order by @AlexOn1ine in #8289
  • Make switchout abilities trigger after a pokemon has returned to its ball by @FosterProgramming in #8304
  • Fix Shed Shell allowing fleeing/teleporting and Smoke Ball failing to guarantee escape by @moostoet in #8286
  • Fix bug where defiant/competitive would pass their stat change to the next target by @FosterProgramming in #8312
  • Fix max move message against semi invulnerable target by @FosterProgramming in #8313
  • Fixes Neutralizing Gas displaying message when exiting with multiple users by @PhallenTree in #8318
  • Fix Kings Rock not being ignored by flinch moves by @AlexOn1ine in #8327
  • Fix Protosynthesis stat boosts ignoring speed drops by @moostoet in #8277
    • Protosynthesis and Quark Drive now recalculate their boosted stat when Speed is lowered or Neutralizing Gas temporarily disables the ability.
  • Fix switch-in abilities not triggering on revive by @FosterProgramming in #8293
  • More Neutralizing Gas cleanup by @PhallenTree in #8335
  • Fix cure status item effect not working properly in doubles by @FosterProgramming in #8339
  • Fix infinite confusion (berserk gene) not being cured by cure_status bag items by @FosterProgramming in #8343
  • Fix B_PHYSICAL_SPECIAL_SPLIT when set to Gen 4 by @AsparagusEduardo in #8348
  • Refactor Beat Up handling for Gen 3/4 defaults, fix crit check, and expand test coverage by @moostoet in #8307
    • BUGFIX: Beat Up (GEN =< 5) now no longer doubles its damage on every non-critical hit
    • Beat Up now precomputes eligible party members/strikers for consistent multi-hit resolution and expanded tests covering both pre-Gen5 and Gen5+ rules
  • Fix substitute graphic not disappearing after using a pivor move by @FosterProgramming in #8340
  • Fixes Beak Blast burning after Beak Blast was already used by @PhallenTree in #8361
  • Fix Roar not being recorded for LastUsedMove by @AlexOn1ine in #8362
  • Fixes Neutralizing Gas / Mold Breaker / Dragon Darts interaction by @AlexOn1ine in #8389
  • Fixes battle tv overwriting damage values by @AlexOn1ine in #8378
  • Fix ball cycling not working properly when the same ball take multiple bag slots by @FosterProgramming in #8163
    • Two new defines added to items.h FIRST_BALL_INDEX and LAST_BALL_INDEX
    • We now assume the indexes of all regular ball usable in wild battle have consecutive indexes and some features (throw ball shortcut in battle) might break if not true

🤹 Moves 🤹

Changed

  • Fixed Uproar’s description and spacing by @fdeblasio in #8187
  • Clean usage of gMovesInfo by @AsparagusEduardo in #8234
    • Also, fixed an OOB in HasMoveThatChangesKOThreshold
  • Make tailwind anim mirror based on side by @FosterProgramming in #8249
  • Make rainbow effect anim change based on side by @FosterProgramming in #8269
  • Update Lash Out description to clarify its effect by @PhallenTree in #8372

Fixed

  • Fix some move animations leaking VRAM and freeing already freed tags by @hedara90 in #7977

🧶 Items 🧶

Fixed

  • Allow vs seekers to work with script not starting with trainerbattle by @FosterProgramming in #8062
    • VS seeker now work with trainers who don’t start with trainer_battle. You can use vsseeker_rematchid TRAINER_ID to indicate that this NPC is a battling trainer and the game will fetch the appropriate rematch if necessary. vsseeker_rematchid work like a cant_see_if_trainerflag_set with additional functionality to handle vs seeker. All NPCs who don’t start with either vsseeker_rematchid or trainerbattle will show as “X”/unmatchable by the vs seeker, so non-rematchable trainer who do not start with trainerbattle may "lie" and not show an excalmation mark showing they haven't been fought yet. This can be fixed by including a vsseeker_rematchid` for them too.

🤖 Battle AI 🤖

Fixed

  • fix (AI scoring): shield dust considerations, IsMoveEffectInMinus self effect edge case, hitsToKO zero-case consideration by @ghostyboyy97 in #8126
    • The AI now sees Shield Dust on the player’s Pokemon correctly
    • The AI now sees self-targeted positive effect boosts correctly
  • fix (contrary): Contrary stat down handling in MoveEffectInPlus by @ghostyboyy97 in #8165
    • When comparing positive move effects in damaging move comparison, the AI will correctly see moves like Leaf Storm as beneficial if their Pokemon has Contrary.
  • Added check for parental bond killing through sturdy by @MaximeGr00 in #8206 AI now accounts for Parental Bond when checking if a move can ko the player through sturdy/focus sash.
  • Fix AI_FLAG_DOUBLE_ACE_POKEMON sending duplicate Pokémon in doubles by @moostoet in #8279
    • Fixed AI_FLAG_DOUBLE_ACE_POKEMON trainers resending the same Pokémon after a KO instead of their two Ace Pokémon in double battles.
  • Fix switchin KO threshold logic by @Pawkkie in #8370

🧹 Other Cleanup 🧹

  • Clean up redundant todo by @AlexOn1ine in #8094
  • Fix Kyurem typo in swap move tables by @Bassoonian in #8139
  • Fix typo in Voltorb-Hisui pokedex entry by @PhallenTree in #8143
  • Fixed Uproar’s description and spacing by @fdeblasio in #8187
  • Add include/constants/script_commands.h to gitignore by @AlexOn1ine in #8169
  • Powder Move blocking cleanup by @PhallenTree in #8194
  • Clean usage of gMovesInfo by @AsparagusEduardo in #8234
    • Also, fixed an OOB in HasMoveThatChangesKOThreshold
  • Adjust Canceler naming to contain only one l by @AlexOn1ine in #8258
  • Fix wrongly renamed logs by @AlexOn1ine in #8264
  • Tests for Max Moves already exist by @AlexOn1ine in #8314
  • Use MAP_OFFSET by @estellarc in #8328
  • Fixed broken friendship from items in battle test and added new test for opposite case by @pkmnsnfrn in #7872
  • Indent unintented if statement by @hedara90 in #8367
  • Update Lash Out description to clarify its effect by @PhallenTree in #8372
  • Restored encourageEncore flag to non-volatile status effects by @AsparagusEduardo in #8387

🧪 Test Runner 🧪

Added

  • Prevent EXPECT functions from casting negative numbers into unsigned by @FosterProgramming in #7866

Changed

  • Added Soundproof and Bulletproof tests by @AsparagusEduardo in #8189
  • Wrote some missing tests by @AsparagusEduardo in #8203
  • A couple more tests by @AsparagusEduardo in #8209
  • Fixed some failing tests with GEN_LATEST = GEN_5 by @AsparagusEduardo in #8241
  • Add test for mold breaker/ice scales interaction by @FosterProgramming in #8240
  • Yet more tests by @AsparagusEduardo in #8228
    • Added tests for:
    • Dark Aura
    • Fairy Aura
    • Flare Boost
    • Toxic Boost
    • Added test names for Flying Press.
  • Slightly increase headless test speed by modifying animations by @AsparagusEduardo in #8299
  • Make gTestRunnerHeadless into a constant outside of tests by @hedara90 in #8306
  • Tests for Max Moves already exist by @AlexOn1ine in #8314
  • Finished fixing tests when setting GEN_LATEST to GEN_5 by @AsparagusEduardo in #8263
  • Wrote missing Fling tests by @AsparagusEduardo in #8383

Fixed

  • Fixes difficulty not being restored after tests by @grintoul1 in #8129
  • Reset saveblock data between test runs by @hedara90 in #8145
  • Fix ohko moves ai tests by @FosterProgramming in #8309
  • Fixed broken friendship from items in battle test and added new test for opposite case by @pkmnsnfrn in #7872
  • Add tests to verify aromatherapy is not affected by heal bell config by @FosterProgramming in #8344
  • Pre gen 5 encored move now signals the test engine a move is happening by @FosterProgramming in #8338
  • Refactor Beat Up handling for Gen 3/4 defaults, fix crit check, and expand test coverage by @moostoet in #8307
    • BUGFIX: Beat Up (GEN =< 5) now no longer doubles its damage on every non-critical hit
    • Beat Up now precomputes eligible party members/strikers for consistent multi-hit resolution and expanded tests covering both pre-Gen5 and Gen5+ rules
  • Fix known failing AI trace test by @FosterProgramming in #8337

📚 Documentation 📚

  • Lock mdbook to v0.4.35 to fix docs not building by @grintoul1 in #8130
  • Add additional comment explaing map name popup transparency side-effects by @FosterProgramming in #8117
  • Fix wrongly renamed logs by @AlexOn1ine in #8264
  • Use MAP_OFFSET by @estellarc in #8328
  • Fedora install instructions by @estellarc in #8355

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.13.3...expansion/1.13.4

Version 1.13.3

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.13.3
`.

🧬 General 🧬

Added

  • Add test to detect save file shifting by @Bassoonian in #8030

Changed

  • 1.13.2 release by @hedara90 in #7831
  • Remove unnecessary EWRAM and IWRAM variables from the Window code by @estellarc in #7897
  • Replace magic numbers with define’d values in field_player_avatar.c by @FosterProgramming in #7910
  • Pret merge (1st of November, 2025) by @hedara90 in #8103

Fixed

  • Fixes EVO_BATTLE_END evolutions not removing item with additional conditions by @PhallenTree in #7841
  • Fix EV display in debug menu by @cawtds in #7848
  • Fix right player position battle partner target display by @ravepossum in #7878
  • Ensure last used ball and move description window sprites don’t free palette too early by @ravepossum in #7875
  • Fix fusion pokemon aquiring illegal movesets by @FosterProgramming in #7896
    • Calyrex will now delete moves if they are not part of its learnset when unfusing
    • Kyurem will now properly swap the moves Glaciate and Scary Face to its signature moves when fusing/unfusing
  • Fix bug causing hgss dex to freeze by @FosterProgramming in #7936
    • Fix a bug when checking evolutions info screen while search mode is active in the hgss dex
  • Show convergent evolution to Gholdengo in HGSS dex by @FosterProgramming in #7934
  • Fix HGSS dex sprites for gen9+ by @FosterProgramming in #7922
  • Fix nicknames containing many / overflowing the party screen textbox by @hedara90 in #7970
  • Fix ruination and nature’s madness damage percentage by @FosterProgramming in #7983
  • Fix ribbon colours by @hedara90 in #7971
  • Fix long pokemon name in partner party not appearing properly by @FosterProgramming in #8009
  • Fix battle dome bug (again) by @FosterProgramming in #8007
  • Fix battle arena counting all judges loss for the opponent by @FosterProgramming in #8046
    • Fix battle arena referees giving undeserved wins to the player
  • Fix wrong gimmick spite showing when inputting too fast by @FosterProgramming in #8066

🗺️ Overworld 🗺️

Fixed

  • Fix LTO breaking with FREE_MYSTERY_GIFT set to TRUE by @DizzyEggg in #7844
  • Fix dns palette weight by @FosterProgramming in #7855
  • Bug Fix: NPC follower not inheriting facing direction upon creation by @Bivurnum in #7895
  • Fix follower pokemon not playing animation when colliding by @FosterProgramming in #7908
  • Fix incorrect font width in Dexnav search window hiding some elements by @FosterProgramming in #7949
  • Fix dns color transition not applying weather blending by @FosterProgramming in #7883
  • Fix follower NPC sidewaystair movement by @FosterProgramming in #7909
  • Fix battle dome pre round 1 waiting room by @FosterProgramming in #7976
  • Fix no_effect script command overwriting trainer data in trainer script by @FosterProgramming in #7978
  • Setting wallclock time now properly sets fakeRTC by @FosterProgramming in #7860
    • Fix time bug when setting wallclock in fakeRTC mode
    • When setting the wall clock, it will start on current time instead of 10AM
    • If FakeRTC is active, new game will start at 10AM
  • Bugfix hidefollower not waiting properly by @FosterProgramming in #7768
  • Bugfix Emotes not loading their palette by @estellarc in #7843
  • Fix OW Pokémon VObjects by @HashtagMarky in #7991
  • fix: hypertraining a stat now optionally reflects in the summary screen by @khbsd in #8035
  • Fix pc turning on/off animation not working in battle frontier by @FosterProgramming in #8048
  • Fix non-battle trainer script not running properly by @FosterProgramming in #8056

🐉 Pokémon 🐉

Fixed

  • Fixes shininess for givemon by @cawtds in #7847
  • Fix Minior start of battle form by @hedara90 in #7972
  • Add error messages for trying to send an illegal mon to the PC and fixes index in double wild battles by @hedara90 in #7982
  • fix: hypertraining a stat now optionally reflects in the summary screen by @khbsd in #8035
  • Add camera-facing right-walking Krabby and Kingler follower sprites by @rayrobdod in #7881

⚔️ Battle General ⚔️

Changed

  • Tests for Battery ability by @grintoul1 in #7846
  • Aura Break tests by @grintoul1 in #8099

Fixed

  • Fixes Endure lasting forever by @AlexOn1ine in #7838
  • Fix for uncaught mon with terrain active by @DizzyEggg in #7868
  • Fixes Steadfast not activating + tests by @PhallenTree in #7886
  • Fix hgss pokedex when catching mon with terrain by @DizzyEggg in #7884
  • Fix SmartStrike crashing the game in double battles by @DizzyEggg in #7902
  • Fix palaceUnableToUseMove falling through to change battle script by @ghoulslash in #7912
  • Add new Move target types to GetBattlePalaceMoveGroup by @ghoulslash in #7913
  • Fixes 2 instances of global usage in the Cmd_adjustdamage loop by @AlexOn1ine in #7918
  • Fix Battle Anim monbg calls Part 1 by @ghoulslash in #7906
  • Adds missing breakable flag for Bulletproof by @AlexOn1ine in #7928
  • Fix multiple battle arena bugs by @FosterProgramming in #7941
  • Fixes Cursed Body failing to disable moves on the last PP by @PhallenTree in #7940
  • Fixed an issue related to Pokemon animation bleeding into attack anim… by @LinathanZel in #7924
  • Fixes terrain not failing on duplicate by @AlexOn1ine in #7939
  • Fix volt tackle not inflicting recoil by @FosterProgramming in #7944
  • Fix Knock Off not being restored and Wild Battles by @ghoulslash in #7952
  • Fix Anticipation type effectiveness check by @spindrift64 in #7840
  • Fix Cherim and Castfrom not reverting to baseform when Teraform Zero is triggered by @FosterProgramming in #7961
  • Fix Focus Energy boosting crit by the wrong amount with gen1 crit chance by @FosterProgramming in #7956
  • Fix bug where transformed pokemon lose copied stats on levelup by @FosterProgramming in #7969
  • Fixes Shields Down incorrectly preventing status on Minior Core form by @PhallenTree in #7968
  • SetShellSideArmCategory avoid div by zero by @DizzyEggg in #7980
  • CalcBarFilledPixels Safe Div by @DizzyEggg in #7979
  • Fix psychic terrain affecting semi-invulnerable mons by @FosterProgramming in #7986
  • Fixes Terrain Extender timer by @AlexOn1ine in #7995
  • Fixed Max Move in-battle descriptions by @AsparagusEduardo in #8004
  • Fixes Echoed Voice base power increase depending on attacker’s use of the move by @PhallenTree in #7997
  • Fixed Stomping Tantrum not doubling in damage if the user failed Protect by @AsparagusEduardo in #8008
  • Fix badge boost not applying in gen1 and 2 by @FosterProgramming in #8013
  • Fix toxic debris setting hazards on the wrong side when hit by an ally by @FosterProgramming in #8026
  • Adds missing alive check for Rapid Spin by @AlexOn1ine in #8024
  • Fixes visual glitch after Misty Explosion by @AlexOn1ine in #8022
  • Fixes Protosynthesis not activating after weather was reset by @AlexOn1ine in #8021
  • Fix Salt Cure script by @AlexOn1ine in #8005
  • Fix emergency exit not triggering properly during wild battles by @FosterProgramming in #8037
  • Fix target cancelling not working properly with z-move by @FosterProgramming in #8067
  • Corrects battler partner identification in battle_ai_switch_items.c by @grintoul1 in #8071
  • Fix Ally Switch being useable in Frontier Link Multi battles by @grintoul1 in #8059
  • Fixes hazards and switch-in items not being reset when switching in by @PhallenTree in #8074
  • Fixes Liquid Ooze dmg not blocked by Magic Guard by @AlexOn1ine in #8036
  • Fix move description prompt window not appear when choosing a move after canceling target selection by @FosterProgramming in #8055
  • Initialize DamageContext on declaration to zero by @AlexOn1ine in #8076
  • Fixed Hunger Switch changing forms on switch out while Tera’d by @AsparagusEduardo in #8080
  • Fixes Gooey/Tangling Hair ability pop up triggering on Clear Body by @AlexOn1ine in #8083
  • Fixes intimidate activating on empty field by @AlexOn1ine in #8058
  • Fix bug where mon selection doesn’t properly account for party order by @FosterProgramming in #8088
  • Fix bug when a captured pokemon replaces a party member who changed forms by @FosterProgramming in #8091
  • Fixed Zygarde Complete disappearing upon catch by @AsparagusEduardo in #8089
  • Initialize DamageContext struct with zero values by @AlexOn1ine in #8107

🤹 Moves 🤹

Fixed

  • Updated Mountain Gale’s PP for Gen 9 by @fdeblasio in #7856
  • Fix Brine move anim and document Water Spout anim by @ravepossum in #7865
  • Add Struggle tests, weakness berry tests and prevent Struggle from activating Silk Scarf and Chilan Berry by @rayrobdod in #7880
  • Fix Battle Anim monbg calls Part 1 by @ghoulslash in #7906
  • Add missing end signal for AnimTask_SetAttackerInvisibleWaitForSignal by @hedara90 in #7950
  • Fix Ally Switch being useable in Frontier Link Multi battles by @grintoul1 in #8059
  • Fixed Belly Drum/Contrary interaction at max Attack by @AsparagusEduardo in #8078

🎭 Abilities 🎭

Changed

  • Tests for Battery ability by @grintoul1 in #7846
  • Aura Break tests by @grintoul1 in #8099

🧶 Items 🧶

Fixed

  • Add gBallItemIds Array by @HashtagMarky in #7905
  • Fix Persim Berry battle usage by @hedara90 in #7963

🤖 Battle AI 🤖

Fixed

  • Add failsafe to AI_DecideHoldEffectForTurn by @AlexOn1ine in #7849
  • Fix some ai action check happening before the logic was computed by @FosterProgramming in #7867
    • Roamers will now flee in the first turn of battle
  • Fix ShouldPivot overwriting random memory by @DizzyEggg in #7882
  • Fix AI seeing priority wrong for players choice lock by @MaximeGr00 in #7899
  • fix (post-KO switch): force AI data recalc to see abilities on field correctly when pivot moves used by player by @ghostyboyy97 in #7900
  • Add missing break to Power Split AI case by @ghoulslash in #7959

🧹 Other Cleanup 🧹

  • Fix some failed and assume fail tests with GEN_LATEST = GEN_5 by @AsparagusEduardo in #7735
  • Update INSTALL.md by @RubyRaven6 in #7852
  • Remove unnecessary EWRAM and IWRAM variables from the Window code by @estellarc in #7897
  • Replace magic numbers with define’d values in field_player_avatar.c by @FosterProgramming in #7910
  • Reverts wrongly applies fix to book.toml by @AlexOn1ine in #8105

🧪 Test Runner 🧪

Changed

  • Fix some failed and assume fail tests with GEN_LATEST = GEN_5 by @AsparagusEduardo in #7735
  • Tests for Battery ability by @grintoul1 in #7846
  • Fixed fainting form change tests by @AsparagusEduardo in #8079
  • Aura Break tests by @grintoul1 in #8099

Fixed

  • Fix Knock Off not being restored and Wild Battles by @ghoulslash in #7952
  • Fixes Shields Down incorrectly preventing status on Minior Core form by @PhallenTree in #7968
  • Fixed Stomping Tantrum not doubling in damage if the user failed Protect by @AsparagusEduardo in #8008
  • Fix stats defined in tests being overwritteng by stat change by @FosterProgramming in #8018

📚 Documentation 📚

  • Update INSTALL.md by @RubyRaven6 in #7852
  • Updated PR template to make existing credit policy clearer by @pkmnsnfrn in #7864
  • Fix image links in doc site by @rayrobdod in #7948
  • Add all pages in docs to doc website by @rayrobdod in #7907
  • Relativize doc links, to fix links in docs site by @rayrobdod in #7964
  • Fix docs compile issue by @AlexOn1ine in #8101
  • Reverts wrongly applies fix to book.toml by @AlexOn1ine in #8105

New Contributors

  • @HashtagMarky made their first contribution in #7905
  • @MaximeGr00 made their first contribution in #7899

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.13.2...expansion/1.13.3

Version 1.13.2

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.13.2
`.

🧬 General 🧬

Changed

  • Removed superflous palette compression check by @hedara90 in #7718
  • update of sv.json to consider newest DLC changes by @wiz1989 in #7672
  • Adjusted line break substring breaking by @hedara90 in #7789
  • Fixup add-new-trainer-front-pic tutorial. by @GraionDilach in #7802
  • Adds conversion script for trainers.h by @AlexOn1ine in #7663

Fixed

  • Fix bug with IF_GENDER evolution condition by @FosterProgramming in #7749
  • Pokemon storage moving items bugfix by @FosterProgramming in #7763
  • Fix catch bug introduced in #7774 by @FosterProgramming in #7782
  • Fix Party Menu move select name width by @AsparagusEduardo in #7820
  • Fix Debug Give Pokémon (Complex) with duplicate moves by @AsparagusEduardo in #7821

🗺️ Overworld 🗺️

Changed

  • Added missing LOCALID_NONE by @estellarc in #7783

Fixed

  • Fix TRAINER_TYPE_SEE_ALL_DIRECTIONS by @DizzyEggg in #7779

🐉 Pokémon 🐉

Fixed

  • fix: seen flags for first mon in enemy party by @khbsd in #7791

⚔️ Battle General ⚔️

Fixed

  • Fix most failed tests with GEN_LATEST = GEN_7 by @AsparagusEduardo in #7688
  • Fixes Sweet Veil not protecting sleep from Yawn status by @AlexOn1ine in #7704
  • Fix incorrect wrap turn amount by @AlexOn1ine in #7667
  • Fixes Rage Fist for gen7 Disguise by @AlexOn1ine in #7692
  • Fixes Intrepid Sword/Dauntless Shield boosting after entering while at max stats by @PhallenTree in #7716
  • Fixes incorrect ending for some scripts by @AlexOn1ine in #7691
  • Fixes Uproar not waking up mons by @AlexOn1ine in #7714
  • Fixes Endure and Eject Pack issues by @AlexOn1ine in #7687
  • Fix Beak Blast burning fire types by @hedara90 in #7740
  • Fixes Recharge not actually being removed when recharge turn occurs by @PhallenTree in #7744
  • Bugfixes Batch by @AlexOn1ine in #7739
  • Fixes Beat Up incorrect slots usage by @AlexOn1ine in #7741
  • Fixes Mycelium Might and Lagging Tail adjusting prio incorrectly by @AlexOn1ine in #7742
  • Wrong argument passed down by @AlexOn1ine in #7751
  • Fixed Ball Fetch Ability by @bassforte123 in #7764
  • Fixes Flower Shield affecting semi-invulnerable mons by @AlexOn1ine in #7766
  • Fixes Helping Hand boosts not stacking with each other by @PhallenTree in #7775
  • Fixes OHKO moves calculating accuracy twice by @AlexOn1ine in #7785
  • Fixes Instructed moves looking at the wrong turn order number by @PhallenTree in #7788
  • Fix Flame Burst timeout if primary target is fainted by @hedara90 in #7793
  • Fixes Leppa Berry timings by @AlexOn1ine in #7787
  • Fixes Effects activating when move wasn’t successful by @AlexOn1ine in #7803
  • Fixes Throat Spray being blocked by Sheer Force by @AlexOn1ine in #7808
  • Fixes inaccurate save / restore in Fling script by @AlexOn1ine in #7811
  • Fix test exit prints for stored battlers by @AlexOn1ine in #7807
  • Fixes EndTurn Eject Pack by @AlexOn1ine in #7813
  • Fix Battle Frontier using Strange Balls by @AsparagusEduardo in #7823
  • Fix Throat Spray activating multiply times by @AlexOn1ine in #7818
  • fix (choice lock): Gorilla Tactics interactions with choice item removal by @ghostyboyy97 in #7824
    • Fixed interactions with choice items and Gorilla Tactics both present when choice item is removed by a thief effect or item swap effect.
  • Fixes encore random target for gen5+ by @AlexOn1ine in #7800

🤹 Moves 🤹

Changed

  • Initial Lash Out tests by @grintoul1 in #7769

Fixed

  • Fix Salt Cure in double battles by @Bassoonian in #7797

🎭 Abilities 🎭

Fixed

  • Fix for Levitate and Mold Breaker being seen correctly by switch AI, with Levitate tests by @grintoul1 in #7748
  • Fix Forecast and Flower Gift corruption by @Bassoonian in #7796
  • Immunity abilities trigger on turn 0 (leads) by @spindrift64 in #7814

🤖 Battle AI 🤖

Changed

  • Tidy up CanTargetFaintAiWithMod and CanTargetMoveFaintAi by @grintoul1 in #7693
  • Doubles AI: Trick Room timer fix and test for DOUBLE_TRICK_ROOM_ON_LAST_TURN_CHANCE by @grintoul1 in #7622

Fixed

  • Toxic thread uses light screen’s scoring…. by @surskitty in #7674
  • Fix most failed and assume fail tests with GEN_LATEST = GEN_6 by @AsparagusEduardo in #7696
  • Fix for Levitate and Mold Breaker being seen correctly by switch AI, with Levitate tests by @grintoul1 in #7748

🧹 Other Cleanup 🧹

  • Tidy up CanTargetFaintAiWithMod and CanTargetMoveFaintAi by @grintoul1 in #7693
  • Removed superflous palette compression check by @hedara90 in #7718
  • Fix failing test for B_PREFERRED_ICE_WEATHER = B_ICE_WEATHER_SNOW by @phexmiau in #7755
  • Adjusted line break substring breaking by @hedara90 in #7789
  • Added missing LOCALID_NONE by @estellarc in #7783

🧪 Test Runner 🧪

Changed

  • Add tests for Filter, Solid Rock and Prism Armor by @hedara90 in #7734
  • Fix failing test for B_PREFERRED_ICE_WEATHER = B_ICE_WEATHER_SNOW by @phexmiau in #7755
  • Initial Lash Out tests by @grintoul1 in #7769
  • Improve how test involving ball throw work by @FosterProgramming in #7774

Fixed

  • Fix EWRAM_INIT in tests and add a default state to test runner main loop by @hedara90 in #7699
  • Fix most failed and assume fail tests with GEN_LATEST = GEN_6 by @AsparagusEduardo in #7696
  • Fix for Levitate and Mold Breaker being seen correctly by switch AI, with Levitate tests by @grintoul1 in #7748
  • Fix Big Root tests by @hedara90 in #7817

📚 Documentation 📚

  • Fixup add-new-trainer-front-pic tutorial. by @GraionDilach in #7802

New Contributors

  • @phexmiau made their first contribution in #7755
  • @ghostyboyy97 made their first contribution in #7824

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.13.1...expansion/1.13.2

Version 1.13.1

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.13.1
`.

🧬 General 🧬

Fixed

  • Added sortType to Douse Drive by @fdeblasio in #7664

🐉 Pokémon 🐉

Fixed

  • Fixed disabled cross-evolutions still being possible by @AsparagusEduardo in #7678

⚔️ Battle General ⚔️

Changed

  • Replace boolean multiplications with ternaries by @hedara90 in #7653

🤖 Battle AI 🤖

Fixed

  • Helping Hand bugfix; used FOE instead of BATTLE_OPPOSITE. by @surskitty in #7659

🧹 Other Cleanup 🧹

  • Replace boolean multiplications with ternaries by @hedara90 in #7653
  • Fix Rage Fist test name by @AlexOn1ine in #7681

🧪 Test Runner 🧪

Changed

  • Fix Rage Fist test name by @AlexOn1ine in #7681

Fixed

  • Fix crashing tests duplicating tests from another thread by @hedara90 in #7683

📚 Documentation 📚

  • Update README.md by @Bassoonian in #7639

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.13.0...expansion/1.13.1

Version 1.13.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.13.0
`.

🌋 REFACTORS 🌋

📜 = Uses a migration script.

  • Refactor field moves by @cawtds in #6660
  • Refactors Final Gambit + Tests by @AlexOn1ine in #7005
  • Combines Super Fang and Guardian of Alola effects by @AlexOn1ine in #7048
  • Refactor damage calculations aruguments by using a struct context by @AlexOn1ine in #7108
  • Add damage context to effectiveness multiplier by @AlexOn1ine in #7111
  • Decouple Status set by ability from SetMoveEffect by @AlexOn1ine in #7125
  • Converted Relic Song into a proper form change by @AsparagusEduardo in #7139
    • Added FORM_CHANGE_BATTLE_AFTER_MOVE to parametrize Relic Song’s form change
  • Removed Mind Blown effect in favor of move flag by @AsparagusEduardo in #7138
  • Volatile status refactoring by @cfmnephrite in #6983
  • Bag refactor (groundwork for expansion) by @cfmnephrite in #7018
    • If you’re using @ghoulslash’s bag sort branch, this PR will break it
  • Stat Change (Animation) Refactor by @PhallenTree in #7144 setgraphicalstatchangevalues and playstatchangeanimation have been removed and now Stat Change Animations are handled in statbuffchange.
    • To update your custom battle scripts: setgraphicalstatchangevalues is often accompanied by playanimation X, B_ANIM_STATS_CHANGE. When I refer to deleting setgraphicalstatchangevalues below, that command should also be deleted.
    1. If statbuffchange is before setgraphicalstatchangevalues/playstatchangeanimation and there is something in between them (for example, attackanimation and waitanimation), add the flag STAT_CHANGE_ONLY_CHECKING and replace the command (setgraphicalstatchangevalues/playstatchangeanimation) with a copy of the original statbuffchange.
    2. If statbuffchange is after setgraphicalstatchangevalues/playstatchangeanimation or there is nothing in between, you should delete those commands (setgraphicalstatchangevalues/playstatchangeanimation) and no further changes other than those in 3. should be required.
    3. If playstatchangeanimation had bits assigned to them (BIT_ATK | BIT_SPATK, for example), add “, “ followed by those bits to the first statbuffchange; for the following statbuffchanges, remove stats that have already been increased/decreased.
  • Untangle InitBtlControllers functions by @AsparagusEduardo in #6748
  • Use battler arguments for SetMoveEffect by @AlexOn1ine in #7156
  • Easier expandability of debug menu by @AsparagusEduardo in #6910
  • Use dedicated functions for Mud/Water Sport by @AlexOn1ine in #7248
  • Expanding and Refactoring Skill Swap and other ability-changing moves by @surskitty in #7238
  • Refactor move Synchronise by @AlexOn1ine in #7271
  • Adds hazard queue by @AlexOn1ine in #7295
  • Changes AccuracyCalcHelper into CanMoveSkipAccuracyCalc by @AlexOn1ine in #7303
  • battle_interface: overhaul ability pop up by @mudskipper13 in #7227
    • The layout of the ability pop up’s image (graphics/battle_interface/ability_pop_up.png) has been changed.
  • Bag refactor 2 by @cfmnephrite in #7166
  • Replaces STATUS2 usage with volatiles in code by @cfmnephrite in #7262
    • Replaced all references to STATUS2 in the code with volatiles (but left the old bitfield behind for compatibility with downstream users). The list of volatiles is in include/constants/battle.h and includes information such as an enum, a field name, type and max size, and whether or not the move is Baton Passable. Users can use VOLATILE_X with any function that previously took STATUS2_X in scripts, and can check/set volatiles in C with gBattleMons[battler].volatiles.{field name} syntax instead of checking a flag in a bitfield.
  • Refactor battle environment by @fdeblasio in #4891
  • Convert various to callnatives by @AlexOn1ine in #7355
  • AI refactor for weather-setting, terrain-setting, Trick Room behaviors; doubles-focused by @surskitty in #7319
    • AI is more likely to use Trick Room in double battles and Terrains in general.
  • Convert Status4 to volatiles by @AlexOn1ine in #7411
  • Split Sheer Force tests by gen instead of by four by @AlexOn1ine in #7260
  • Modify move prediction to work in doubles by @AlexOn1ine in #7087
  • Convert statuses3 to volatiles by @AlexOn1ine in #7514
  • Added trainerBackPic to Trainer struct to de-couple trainer pic and trainer back pic defines by @grintoul1 in #7425

🧬 General 🧬

Added

  • New sprite compressor by @hedara90, @DizzyEggg Improved performance massively for the instruction decoding., @mrgriffin, SBird and @tertu-m who has done even more optimization and answered questions about the GBA hardware whenever I had them. and @rayrobdod for the better migration script. in #5627
    • LZDecompressVram and LZDecompressWram has been deprecated. All calls do decompress LZ compressed data should be using the wrapper functions DecompressDataWithHeaderVram or DecompressDataWithHeaderWram.
    • A new sprite compression format has been introduced. To use it, replace files with .4bpp.lz with .4bpp.smol or .4bpp.fastSmol.
    • .smol is a compression format utilizing entropy encoding in the form of tabled Asymmetric Numeral Systems (tANS) and a modified LZ style RLE/Dictionary encoding scheme specialized for the sprites used in Pokemon games. This is approximately 25% smaller than the default LZ77 compression.
    • .fastSmol skips the entropy encoding and is therefore slightly larger than the default LZ77 compression, but decoding sprites is faster than the default LZ77 compression.
    • .smolTM is a compression scheme for tilemaps.
    • Might have unexpected behavior if user introduced decompression during hardware interrupts.
    • Has a migration script that handles all files under src/, migration_scripts/1.12/convert_compressed_files.py.
  • Adds FRLG asserts to Alloc/Free by @cawtds in #7025
  • Debug parties and battles by @SBird1337 in #6884
    • Adds options to set debug parties and battles using the debug menu
  • Added naive line break by @hedara90 in #7076
  • Disable unowned evo methods by @Bolt-Strike in #7103
  • lto support by @DizzyEggg in #7182
  • Improve trainer back pic-related data and code (+ smol documentation) by @mudskipper13 in #6821
  • Add Set Hidden Nature option to the debug menu by @AlexOn1ine in #7281
  • Instant Win option in Battle Debug by @AlexOn1ine in #7333
  • trainerproc copy other trainer party by @hedara90 in #7251
    • Adds the Copy Pool command to trainerproc which copies the party/pool from another trainer.
  • Show chosen move in the battle debug menu by @AlexOn1ine in #7382
  • Rock climb by ghoulslash by @pokesidv in #7432
    • Added rock climb field effect

Changed

  • Restore git history check by @ravepossum in #7463
  • Moved summary screen nature colors to summary_screen.h by @RubyRaven6 in #7560
  • Added comment in event.inc for simple menus in dynmultichoice by @RubyRaven6 in #7568
  • Changed default print level for DebugPrintf for mGBA to MGBA_LOG_WARN by @hedara90 in #7567
  • Fixed Teleport’s description not being updated based on B_TELEPORT_BEHAVIOR by @AsparagusEduardo in #7580
  • Minor Clean up in battle_ai_main.c by @AlexOn1ine in #7551
  • Refactor field moves by @cawtds in #6660
  • Replace all usages of lz compression with smol by @hedara90 in #7032
  • BtlController_EmitTwoReturnValues cleanup by @AsparagusEduardo in #6855
  • Put the gen 1 compression tests behind a config by @hedara90 in #7033
  • Converts a bunch of defines to enums by @Bassoonian in #7041
  • chore: remove unused section from credits by @Emiliasky in #7085
  • Simplify white out messages by @kittenchilly in #6961
  • Improve music/se macros and fix names by @cawtds in #7030
  • Bag refactor (groundwork for expansion) by @cfmnephrite in #7018
    • If you’re using @ghoulslash’s bag sort branch, this PR will break it
  • Converts more defines to enums and name unnamed enums by @Bassoonian in #7071
  • Add config options for removing bard phoneme audio to save ROM space by @poetahto in #7155
  • Fix debug text order by @hedara90 in #7149
  • More battle controller function consolidation. by @AsparagusEduardo in #6877
  • Easier expandability of debug menu by @AsparagusEduardo in #6910
  • Update .gitignore to add heal locations by @Bassoonian in #7050
  • Add ‘Give Decoration’ function to overworld debug menu by @rayrobdod in #7219
  • Changes pre-proc to a normal if for Item Desc Header by @AlexOn1ine in #7231
  • Use compound strings in battle debug menu by @AsparagusEduardo in #7282
  • Remove competitive syntax config by @hedara90 in #7154
    • This change can be reverted by doing git revert 14dbbf63d454073dbb198b941cc3566168c89f11.
  • Turn OW_FRLG_WHITEOUT into OW_WHITEOUT_CUTSCENE and make it generational by @kittenchilly in #6962
  • Add Macro key to trainerproc by @hedara90 in #7157
  • preproc: Support attribute in enums by @mrgriffin in #7344
  • Enum conversion for enum MoveEffects and enum BattleMoveEffects by @hedara90 in #7366
    • This enables -Wenum-conversion, additional compilation errors can occur
  • Get/SetMonData optimisation by @cfmnephrite in #7313
  • Bag refactor3 + Ghoulslash’s sorting feature port by @cfmnephrite in #7330
  • Replace all usages of rl compression with smol by @rayrobdod in #7458
  • Bag sorting cleanup by @mrgriffin in #7489
  • Adds ghouls Rock Climb git history by @AlexOn1ine in #7493
  • Changed item name/pluralName to a compound string by @cfmnephrite in #7359
  • Added trainerBackPic to Trainer struct to de-couple trainer pic and trainer back pic defines by @grintoul1 in #7425
  • Suppress trainerproc compile warning for unused func by @AlexOn1ine in #7592

Fixed

  • Fix .smol compression in debug builds by @hedara90 in #7090
  • Improve smol compressor by @hedara90 in #7073
  • Increased heap by 768 bytes by @hedara90 in #7097
  • Fix healthbox when blending effects happen by @AsparagusEduardo in #7203
  • Fixed Fake RTC debug menu by @AsparagusEduardo in #7218
  • Added missing braces by @cfmnephrite in #7288
  • Fixed Flag Vars menu keeping artifacts from bag menu + cleanup by @AsparagusEduardo in #7226
  • Fix HGSS dex running out of heap by @hedara90 in #7317
  • battle intro: fix issues with follower slide-in and wild shiny mon by @mudskipper13 in #7325
  • Fix sorting bag by type by @mrgriffin in #7488
  • Hacky support for enums in C asm statements by @mrgriffin in #7494
  • Fixed compile issue in gcc 11 by @AsparagusEduardo in #7579
  • Fix overlap between spin evolution and script evolution by @FosterProgramming in #7593

🗺️ Overworld 🗺️

Added

  • Added createfollowernpc macro to make a new follower from a gfx id by @Bivurnum in #7196
    • Follower NPCs can now be created without using an existing NPC, using the createfollowernpc macro.
  • feat: separate water and rock smash encounter rate checks by @khbsd in #7293

Changed

  • fix: remove unused wild_encounters.json.txt jinja file by @khbsd in #7581
  • added Ash Greninja overworld sprites by @wiz1989 in #6976
  • Update FRLG whiteouts to new pret system by @Bassoonian in #7040
    • Make sure to migrate your changes to the now deleted heal_locations_pkm_center.h to the json file.
  • Use CanAbilityAbsorbMove in GetOverworldTypeEffectiveness by @AlexOn1ine in #7115
  • Add config options for removing bard phoneme audio to save ROM space by @poetahto in #7155
  • Add debug options for follower NPCs by @Bivurnum in #7215
  • Better system for Follower NPC running frames by @Bivurnum in #7222
  • Update follower NPC tutorial doc for createfollowernpc macro by @Bivurnum in #7230

Fixed

  • Bug fix: add handling for forced movements into/after ledge jumps with follower NPCs by @Bivurnum in #7055
  • Fixed compile issue OW_TIMES_OF_DAY is GEN_3 by @AsparagusEduardo in #7499
  • Remove shadow and hide follower on stair warp by @cornixsenex in #7368
  • Fix Form Change Item Task Data and Clean Up Field Use Funcs by @ravepossum in #7535
  • Fix Vs Seeker Trainer Battle script issue by @pkmnsnfrn in #7615
  • Fix follower compression by @hedara90 in #7038
  • Changing P_ONLY_OBTAINABLE_SHINIES to truly be Only Obtainable Shinies by @surskitty in #7275

🐉 Pokémon 🐉

Added

  • Add P_ASK_MOVE_CONFIRMATION by @pkmnsnfrn in #7132
    • This will change the behavior of the game for players, as a new default is being set.
  • Added CRY_MODE_DYNAMAX by @AsparagusEduardo in #6933
  • Wild Pokémon animate after breaking out of Poké Ball by @LinathanZel in #7339

Changed

  • Add dedicated getter functions for Pokémon types and abilities by @Bassoonian in #7043
  • added Ash Greninja overworld sprites by @wiz1989 in #6976
  • Get/SetMonData optimisation by @cfmnephrite in #7313

Fixed

  • fixes #7129: ‘add to full party’ feature in the safari zone by @fakuzatsu in #7147
  • Fix substruct offsets from #7313 by @mrgriffin in #7431
  • Fixes refusing to replace a move on evolution causing a softlock by @PhallenTree in #7585

⚔️ Battle General ⚔️

Added

  • Add Gen 2 Moonlight, Morning Sun, Synthesis configuration by @i0brendan0 in #7209
  • Add a heal animation to Hospitality recovery by @AlexOn1ine in #7426
  • Updated Dream Eater/Liquid Ooze’s interaction to Gen 5 standards by @AsparagusEduardo in #7528

Changed

  • Remove unused function by @AlexOn1ine in #7617
  • Clean up battlescript calls with func BattleScriptCall by @AlexOn1ine in #6873
  • Refactors Final Gambit + Tests by @AlexOn1ine in #7005
  • GetBattlerMon cleanup by @AsparagusEduardo in #6967
  • Change GetZMaxMoveAgainstProtectionModifier to prevent regressions by @AlexOn1ine in #7047
  • Combines Super Fang and Guardian of Alola effects by @AlexOn1ine in #7048
  • Remove more instances of hard-coded Move IDs by @AsparagusEduardo in #7056
    • Added EFFECT_SHEER_COLD to parametrize Sheer Cold’s interactions with Ice types
  • Deprecate sStatusFlagsForMoveEffects by @AlexOn1ine in #7063
  • Removes duplicate AI ability func by @AlexOn1ine in #7045
  • Deprecate absent member from battlerState by @AlexOn1ine in #7091
  • Refactor damage calculations aruguments by using a struct context by @AlexOn1ine in #7108
  • Add damage context to effectiveness multiplier by @AlexOn1ine in #7111
  • Decouple Status set by ability from SetMoveEffect by @AlexOn1ine in #7125
  • Removed redundant Damp check by @AsparagusEduardo in #7134
  • Converted Relic Song into a proper form change by @AsparagusEduardo in #7139
    • Added FORM_CHANGE_BATTLE_AFTER_MOVE to parametrize Relic Song’s form change
  • Removed Mind Blown effect in favor of move flag by @AsparagusEduardo in #7138
  • Volatile status refactoring by @cfmnephrite in #6983
  • Repurposes IsMagicGuardProtected into a general function by @AlexOn1ine in #7114
  • Stat Change (Animation) Refactor by @PhallenTree in #7144 -setgraphicalstatchangevalues and playstatchangeanimation have been removed and now Stat Change Animations are handled in statbuffchange.
    • To update your custom battle scripts: setgraphicalstatchangevalues is often accompanied by playanimation X, B_ANIM_STATS_CHANGE. When I refer to deleting setgraphicalstatchangevalues below, that command should also be deleted.
    1. If statbuffchange is before setgraphicalstatchangevalues/playstatchangeanimation and there is something in between them (for example, attackanimation and waitanimation), add the flag STAT_CHANGE_ONLY_CHECKING and replace the command (setgraphicalstatchangevalues/playstatchangeanimation) with a copy of the original statbuffchange.
    2. If statbuffchange is after setgraphicalstatchangevalues/playstatchangeanimation or there is nothing in between, you should delete those commands (setgraphicalstatchangevalues/playstatchangeanimation) and no further changes other than those in 3. should be required.
    3. If playstatchangeanimation had bits assigned to them (BIT_ATK | BIT_SPATK, for example), add “, “ followed by those bits to the first statbuffchange; for the following statbuffchanges, remove stats that have already been increased/decreased.
  • Use argument.type for EFFECT_SOAK by @AsparagusEduardo in #7141
  • Untangle InitBtlControllers functions by @AsparagusEduardo in #6748
  • Increase party action limit by @cawtds in #7119
  • Adds Gen5+ Encore config by @AlexOn1ine in #7051
  • Attackcanceller clean up by @AlexOn1ine in #7210
  • Remove redundant move result flag checks by @AlexOn1ine in #7223
  • Use dedicated functions for Mud/Water Sport by @AlexOn1ine in #7248
  • Script clean up for Flame Burst and Costar by @AlexOn1ine in #7264
  • Renaming STATUS1_REFRESH and adding more constants for common STATUS1 checks. by @surskitty in #7284
  • Refactor move Synchronise by @AlexOn1ine in #7271
  • Adds hazard queue by @AlexOn1ine in #7295
  • Removed all instances of .chance = 100, SHEER_FORCE_NO_BOOST by @cfmnephrite in #7300
  • Changes AccuracyCalcHelper into CanMoveSkipAccuracyCalc by @AlexOn1ine in #7303
  • Replaces STATUS2 usage with volatiles in code by @cfmnephrite in #7262
    • Replaced all references to STATUS2 in the code with volatiles (but left the old bitfield behind for compatibility with downstream users). The list of volatiles is in include/constants/battle.h and includes information such as an enum, a field name, type and max size, and whether or not the move is Baton Passable. Users can use VOLATILE_X with any function that previously took STATUS2_X in scripts, and can check/set volatiles in C with gBattleMons[battler].volatiles.{field name} syntax instead of checking a flag in a bitfield.
  • Refactor battle environment by @fdeblasio in #4891
  • Convert various to callnatives by @AlexOn1ine in #7355
  • Remove leftover code by @AlexOn1ine in #7397
  • Moved some fields to BattlerState/PartyState by @AsparagusEduardo in #7409
  • Additional effects tweak by @cfmnephrite in #7392
  • Clean up noResultString by @AlexOn1ine in #7408
  • Convert Status4 to volatiles by @AlexOn1ine in #7411
  • Convert statuses3 to volatiles by @AlexOn1ine in #7514
  • Prevents a regression for custom abilties by @AlexOn1ine in #7616

Fixed

  • Fixes Magnet Rise when user is Rooted/Smacked Down by @PhallenTree in #7449
  • Fixes Leech Seed recovery not applying behind Sub by @AlexOn1ine in #7468
  • Fixes Round and Fusion moves doubling power from previous turn’s move by @PhallenTree in #7476
  • Fixes shadows and mon animations for transformed battlers by @AsparagusEduardo in #7500
  • Fixes Life Orb still activating if move was absorbed by @AlexOn1ine in #7521
  • Fix Mimicry Only Activating Once per Turn by @ghoulslash in #7537
  • Fixes Knock Off still activating when there is no Item by @AlexOn1ine in #7496
  • Fixed B_PSYWAVE_DMG by @AsparagusEduardo in #7557
  • Fixes Counter / Mirror Coat / Metal Burst damage assignment by @AlexOn1ine in #7538
  • Fix in-game partner battles always causing a whiteout by @ravepossum in #7587
  • Fix B_ANIMATE_MON_AFTER_KO with a new counter by @hedara90 in #7531
  • Fixes Rage Fist counter increment by @AlexOn1ine in #7582
  • Fixes moveend_absorb hitmarker by @AlexOn1ine in #7591
  • switchinabilities also runs ON_WEATHER and ON_TERRAIN by @ghoulslash in #7612
  • Fixes Explosion behavior when 3 mons can endure hit by @AlexOn1ine in #7594
  • Fixes octolock not ending after user switched out by @AlexOn1ine in #7556
  • The original attacker wasn’t restored for Doodle by @AlexOn1ine in #7620
  • Restore X item friendship increase by @ravepossum in #7583
  • Fixes Wonder Room interactions with Defense/Special Defense boosting effects by @PhallenTree in #7626
  • Ally Switch attract battler swapping, test for leech seed by @ghoulslash in #7634
  • Fixes Defiant/Competitive not resetting stat change animations and stat change related cleanup by @PhallenTree in #7004
  • Use battler arguments for SetMoveEffect by @AlexOn1ine in #7156
  • Fixes Booster Energy timing activation + Clean up by @AlexOn1ine in #7175
  • Fixes Eject Pack not resolving correctly during switch in effects by @AlexOn1ine in #7002
  • Adds Ability Shield activation message by @PhallenTree in #7224
  • Fix incorrect type input by @hedara90 in #7228
  • Set correct Instruction by @AlexOn1ine in #7236
  • Fixes Life Dew playing anim when it is not supposed to + tests by @AlexOn1ine in #7239
  • Fixes instances of battler mutation for abilities by @AlexOn1ine in #7250
  • Fix Psych Up message and cleanup and don’t allow switching to self in tests by @PhallenTree in #7277
  • Fix incorrect status in beneficial ability Guts check by @grintoul1 in #7285
  • battle_interface: overhaul ability pop up by @mudskipper13 in #7227
    • The layout of the ability pop up’s image (graphics/battle_interface/ability_pop_up.png) has been changed.
  • Fixes Status overwrites and Effect Spore wrong func args by @AlexOn1ine in #7340
  • Fixes various Choice lock issues by @AlexOn1ine in #7383
  • Fixes draining moves recovering 1 HP when dealing 0 damage by @LinathanZel in #7523

🤹 Moves 🤹

Changed

  • New Attack Animations: 25w20a by @ShinyVolcarona in #6886
    • Added move animations for multiple moves by @LinathanZel
    • Dynamax Cannon, Behemoth Blade, Behemoth Bash, Eternabeam, Glaive Rush, Triple Dive, Doodle, Ruination, Collision Course, Electro Drift, Blazing Torque, Wicked Torque, Noxious Torque, Combat Torque, Magical Torque, Psyblade, Mighty Cleave, Supercell Slam
  • Documented usage of delay X by @AsparagusEduardo in #6951
  • Animation documentation by @AsparagusEduardo in #7052
  • New and polished battle animations by @LinathanZel in #7074

Fixed

  • Clear gScanlineEffect to fix timeout in acid downpour animation by @FosterProgramming in #7442
  • Fix terastallization anims flickering by @ravepossum in #7613

🧶 Items 🧶

Changed

  • Fix using town map as registered item by @ravepossum in #7482
  • Compound strings for hold effect names by @AsparagusEduardo in #7140
  • Untangled TMs and HMs from item ids by @cfmnephrite in #7173
  • Bag refactor 2 by @cfmnephrite in #7166

Fixed

  • Implement using party menu items from field by @ravepossum in #7481
  • Fixed TM and Berries disappearing when sorting by @AsparagusEduardo in #7168
  • Fixed item swapping bug (#7428) by @cfmnephrite in #7430
  • Fixes some Ability Shield interactions by @PhallenTree in #7532
  • Fix tossing a stack of berries hiding following berries by @hedara90 in #7571

🤖 Battle AI 🤖

Added

  • AI: Add AI_SMART_TERA flag to make smarter decisions about when to terastalize. by @jfb1337 in #6705
    • Only single battles are currently supported.
  • Haze Boosting AI Followup by @Pawkkie in #6966
  • Improved logic for Guard Split and Power Split. by @surskitty in #7298
  • Add AI_FLAG_ASSUME_STAB by @Pawkkie in #6797
  • AI checks the partner’s moves for Flatter, Swagger, and Soak. by @surskitty in #7306
  • AI uses After You to help set up Trick Room. by @surskitty in #7310
  • AI assumes Magnitude / Present damage by @Pawkkie in #7334
  • AI_FLAG_ASSUME_STATUS_MOVES – AI flag to randomly know some of the player’s status moves by @surskitty in #7324
  • Improve AI’s setup logic by @Pawkkie in #7345
  • Improve AI’s ShouldRecover by @Pawkkie in #7342
  • Switch AI can see weather abilities of switchin candidates during damage calcs by @Pawkkie in #7373
  • AI refactor for weather-setting, terrain-setting, Trick Room behaviors; doubles-focused by @surskitty in #7319
    • AI is more likely to use Trick Room in double battles and Terrains in general.
  • Improve AI type matchup calcs by @Pawkkie in #7364
  • Multibattle Partner AI Flags and 2vs1 battler3 AI Flags fix by @grintoul1 in #7378
  • Improve AI’s Sucker Punch handling by @Pawkkie in #7389
  • Improve AI’s priority handling by @Pawkkie in #7337
  • Fix dynamic move types in switching by @Pawkkie in #7415
  • Adds AI_FLAG_ASSUMPTIONS as a constant for semi-omniscience by @surskitty in #7435
  • AI_FLAG_ATTACKS_PARTNER with a config for bloodthirstiness by @surskitty in #7401
  • Improved Guaranteed Flinch logic (fake out et al) by @surskitty in #7501
  • AI uses Court Change. by @surskitty in #7525
  • AI uses Tailwind. by @surskitty in #7515
  • AI should not use Dark Void or Hyperspace Fury while wrong species by @surskitty in #7540
  • AI uses Rototiller. by @surskitty in #7542
  • Helping Hand logic by @surskitty in #7504

Changed

  • Macro-for-AI-Flag-definitions by @grintoul1 in #7471
  • Remove redundancy for ShouldLowerStat functions by @AlexOn1ine in #6577
  • Expanding and Refactoring Skill Swap and other ability-changing moves by @surskitty in #7238
  • Changes AccuracyCalcHelper into CanMoveSkipAccuracyCalc by @AlexOn1ine in #7303
  • AI Tests + accompanying bugfixes for Skill Swap, Worry Seed, weather setting in double battles, and Discharging into an ally’s lightningrod by @surskitty in #7297
  • Fix AI resisted move scoring by @Pawkkie in #7350
  • Fiddling with CanLowerStat. by @surskitty in #7510
  • Improved hazards logic and Mycelium Might ignores ability checks by @surskitty in #7509
  • AI handling for similar utility moves by @surskitty in #7513
  • Modify move prediction to work in doubles by @AlexOn1ine in #7087
  • Uncommenting out No Retreat, Clangorous Soul, and Extreme Evoboost from CheckBadMove by @surskitty in #7541
  • AI Tailwind singles fix correction. by @surskitty in #7543
  • Remove funcResult from AiThinkingStruct by @Pawkkie in #7545
  • AI handling for Autotomize. by @surskitty in #7550
  • AI uses Stuff Cheeks; treating it simply as a def +2 move for now. by @surskitty in #7554
  • Slight Purify adjustment for targeting ally; test that AI can use Purify. by @surskitty in #7553
  • AI handling for Howl. by @surskitty in #7549
  • Test that AI uses Dragon Cheer. by @surskitty in #7552
  • Tests to see that the AI uses moves. by @surskitty in #7555

Fixed

  • Incorrect call in Rest by @surskitty in #7569
  • Fix duplicate switch in after faint by @AlexOn1ine in #7600
  • Feature/ai/wide guard quick guard singles by @Emiliasky in #7086
  • Add missing break by @Pawkkie in #7356
  • fixed-damage-move-ai-calc-fix by @grintoul1 in #7385
  • Avoid doubling up on status moves in double battles. by @surskitty in #7452
  • Fix doubles switch AI to use new type matchup system by @Pawkkie in #7495
  • Fix Bad Odds not seeing damage properly by @Pawkkie in #7492
  • Fix GetSwitchinHitsToKO one shot heal calcs by @Pawkkie in #7502
  • Fix AI’s KO evaluation getting messed up by priority by @Pawkkie in #7533
  • Fixing Refresh AI scoring by @surskitty in #7539
  • Fix switch AI not seeing its own move PP by @Pawkkie in #7578
  • Fix wrong battler argument in GetBattleMovePriority call by @Pawkkie in #7576
  • Restore AI: Basic Trainer to PARTNER_STEVEN by @grintoul1 in #7586

🧹 Other Cleanup 🧹

  • Macro-for-AI-Flag-definitions by @grintoul1 in #7471
  • Moved summary screen nature colors to summary_screen.h by @RubyRaven6 in #7560
  • fix: remove unused wild_encounters.json.txt jinja file by @khbsd in #7581
  • Fix Form Change Item Task Data and Clean Up Field Use Funcs by @ravepossum in #7535
  • Fixed Teleport’s description not being updated based on B_TELEPORT_BEHAVIOR by @AsparagusEduardo in #7580
  • Fixed typo in test name by @hedara90 in #7610
  • Minor Clean up in battle_ai_main.c by @AlexOn1ine in #7551
  • Remove unused function by @AlexOn1ine in #7617
  • Fix Vs Seeker Trainer Battle script issue by @pkmnsnfrn in #7615
  • Clean up battlescript calls with func BattleScriptCall by @AlexOn1ine in #6873
  • Replace all usages of lz compression with smol by @hedara90 in #7032
  • BtlController_EmitTwoReturnValues cleanup by @AsparagusEduardo in #6855
  • GetBattlerMon cleanup by @AsparagusEduardo in #6967
  • Converts a bunch of defines to enums by @Bassoonian in #7041
  • Change GetZMaxMoveAgainstProtectionModifier to prevent regressions by @AlexOn1ine in #7047
  • Remove more instances of hard-coded Move IDs by @AsparagusEduardo in #7056
    • Added EFFECT_SHEER_COLD to parametrize Sheer Cold’s interactions with Ice types
  • Animation documentation by @AsparagusEduardo in #7052
  • Deprecate sStatusFlagsForMoveEffects by @AlexOn1ine in #7063
  • chore: remove unused section from credits by @Emiliasky in #7085
  • Removes duplicate AI ability func by @AlexOn1ine in #7045
  • Remove redundancy for ShouldLowerStat functions by @AlexOn1ine in #6577
  • Deprecate absent member from battlerState by @AlexOn1ine in #7091
  • Use CanAbilityAbsorbMove in GetOverworldTypeEffectiveness by @AlexOn1ine in #7115
  • Removed redundant Damp check by @AsparagusEduardo in #7134
  • Improve music/se macros and fix names by @cawtds in #7030
  • Compound strings for hold effect names by @AsparagusEduardo in #7140
  • Repurposes IsMagicGuardProtected into a general function by @AlexOn1ine in #7114
  • Converts more defines to enums and name unnamed enums by @Bassoonian in #7071
  • Use argument.type for EFFECT_SOAK by @AsparagusEduardo in #7141
  • More battle controller function consolidation. by @AsparagusEduardo in #6877
  • Add assumes for bag tests by @Bassoonian in #7188
  • Fixes Booster Energy timing activation + Clean up by @AlexOn1ine in #7175
  • Update .gitignore to add heal locations by @Bassoonian in #7050
  • Attackcanceller clean up by @AlexOn1ine in #7210
  • Remove redundant move result flag checks by @AlexOn1ine in #7223
  • Add P_ASK_MOVE_CONFIRMATION by @pkmnsnfrn in #7132
    • This will change the behavior of the game for players, as a new default is being set.
  • Script clean up for Flame Burst and Costar by @AlexOn1ine in #7264
  • Use compound strings in battle debug menu by @AsparagusEduardo in #7282
  • Renaming STATUS1_REFRESH and adding more constants for common STATUS1 checks. by @surskitty in #7284
  • Removed all instances of .chance = 100, SHEER_FORCE_NO_BOOST by @cfmnephrite in #7300
  • AI Tests + accompanying bugfixes for Skill Swap, Worry Seed, weather setting in double battles, and Discharging into an ally’s lightningrod by @surskitty in #7297
  • Turn OW_FRLG_WHITEOUT into OW_WHITEOUT_CUTSCENE and make it generational by @kittenchilly in #6962
  • Fix AI resisted move scoring by @Pawkkie in #7350
  • Convert various to callnatives by @AlexOn1ine in #7355
  • Remove leftover code by @AlexOn1ine in #7397
  • Moved some fields to BattlerState/PartyState by @AsparagusEduardo in #7409
  • Additional effects tweak by @cfmnephrite in #7392
  • Clean up noResultString by @AlexOn1ine in #7408
  • Bag sorting cleanup by @mrgriffin in #7489
  • Convert statuses3 to volatiles by @AlexOn1ine in #7514
  • Uncommenting out No Retreat, Clangorous Soul, and Extreme Evoboost from CheckBadMove by @surskitty in #7541
  • AI Tailwind singles fix correction. by @surskitty in #7543
  • Remove funcResult from AiThinkingStruct by @Pawkkie in #7545
  • Suppress trainerproc compile warning for unused func by @AlexOn1ine in #7592
  • Prevents a regression for custom abilties by @AlexOn1ine in #7616

🧪 Test Runner 🧪

Changed

  • Clean up some Normalize tests to make them make sense by @hedara90 in #7461
  • Add Synthesis + Utililty Umbrella test by @ghoulslash in #7472
  • Add test for BoxPokemon integrity by @hedara90 in #7487
  • Re-order moves in fling test by @hedara90 in #7559
  • Wrote some tests by @AsparagusEduardo in #7563
  • Added Ability TODO tests - Volume C by @AsparagusEduardo in #7562
  • Added missing Move Effect TODO tests - Volume F by @AsparagusEduardo in #7605
  • Fixed typo in test name by @hedara90 in #7610
  • Add assumes for bag tests by @Bassoonian in #7188
  • Split Sheer Force tests by gen instead of by four by @AlexOn1ine in #7260
  • make check TESTS=“…” support for filenames and infix matches by @mrgriffin in #7536
  • Fix shell side arm rng in battle tests moves by @FosterProgramming in #7548
  • Test that AI uses Dragon Cheer. by @surskitty in #7552
  • Tests to see that the AI uses moves. by @surskitty in #7555

Fixed

  • Clear out parties between battle tests by @hedara90 in #7460
  • Fixed most failed tests with GEN_LATEST GEN_8 by @AsparagusEduardo in #7498
  • Corrected Liquid Ooze test by @AsparagusEduardo in #7527
  • switchinabilities also runs ON_WEATHER and ON_TERRAIN by @ghoulslash in #7612
  • Ally Switch attract battler swapping, test for leech seed by @ghoulslash in #7634
  • Fixed changed effect for Sheer Cold by @hedara90 in #7099
  • Fixed Transistor damage calculation test failing when GEN_LATEST is less than GEN_9 by @AsparagusEduardo in #7577

📚 Documentation 📚

  • Update how_to_new_pokemon.md by @kevinwklawrence in #7440
  • Updating a link to porytiles in INSTALL.md by @ThePeeps191 in #7490
  • Added comment in event.inc for simple menus in dynmultichoice by @RubyRaven6 in #7568
  • Documented usage of delay X by @AsparagusEduardo in #6951
  • Update follower NPC tutorial doc for createfollowernpc macro by @Bivurnum in #7230
  • Improve trainer back pic-related data and code (+ smol documentation) by @mudskipper13 in #6821
  • Update trainer.h usage warning by @hedara90 in #7439

New Contributors

  • @kevinwklawrence made their first contribution in #7440
  • @ThePeeps191 made their first contribution in #7490
  • @cornixsenex made their first contribution in #7368

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.12.2...expansion/1.12.3

New Contributors

  • @ShinyVolcarona made their first contribution in #6886
  • @Emiliasky made their first contribution in #7085
  • @poetahto made their first contribution in #7155
  • @Bolt-Strike made their first contribution in #7103
  • @kevinwklawrence made their first contribution in #7440
  • @FosterProgramming made their first contribution in #7442
  • @ThePeeps191 made their first contribution in #7490
  • @cornixsenex made their first contribution in #7368

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.12.2...expansion/1.13.0

Version 1.12.3

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.12.3
`.

🧬 General 🧬

Changed

  • Restore git history check by @ravepossum in #7463
  • Moved summary screen nature colors to summary_screen.h by @RubyRaven6 in #7560
  • Added comment in event.inc for simple menus in dynmultichoice by @RubyRaven6 in #7568
  • Changed default print level for DebugPrintf for mGBA to MGBA_LOG_WARN by @hedara90 in #7567
  • Fixed Teleport’s description not being updated based on B_TELEPORT_BEHAVIOR by @AsparagusEduardo in #7580
  • Minor Clean up in battle_ai_main.c by @AlexOn1ine in #7551

🗺️ Overworld 🗺️

Changed

  • fix: remove unused wild_encounters.json.txt jinja file by @khbsd in #7581

Fixed

  • Bug fix: add handling for forced movements into/after ledge jumps with follower NPCs by @Bivurnum in #7055
  • Fixed compile issue OW_TIMES_OF_DAY is GEN_3 by @AsparagusEduardo in #7499
  • Remove shadow and hide follower on stair warp by @cornixsenex in #7368
  • Fix Form Change Item Task Data and Clean Up Field Use Funcs by @ravepossum in #7535
  • Fix Vs Seeker Trainer Battle script issue by @pkmnsnfrn in #7615

⚔️ Battle General ⚔️

Changed

  • Remove unused function by @AlexOn1ine in #7617

Fixed

  • Fixes Magnet Rise when user is Rooted/Smacked Down by @PhallenTree in #7449
  • Fixes Leech Seed recovery not applying behind Sub by @AlexOn1ine in #7468
  • Fixes Round and Fusion moves doubling power from previous turn’s move by @PhallenTree in #7476
  • Fixes shadows and mon animations for transformed battlers by @AsparagusEduardo in #7500
  • Fixes Life Orb still activating if move was absorbed by @AlexOn1ine in #7521
  • Fix Mimicry Only Activating Once per Turn by @ghoulslash in #7537
  • Fixes Knock Off still activating when there is no Item by @AlexOn1ine in #7496
  • Fixed B_PSYWAVE_DMG by @AsparagusEduardo in #7557
  • Fixes Counter / Mirror Coat / Metal Burst damage assignment by @AlexOn1ine in #7538
  • Fix in-game partner battles always causing a whiteout by @ravepossum in #7587
  • Fix B_ANIMATE_MON_AFTER_KO with a new counter by @hedara90 in #7531
  • Fixes Rage Fist counter increment by @AlexOn1ine in #7582
  • Fixes moveend_absorb hitmarker by @AlexOn1ine in #7591
  • switchinabilities also runs ON_WEATHER and ON_TERRAIN by @ghoulslash in #7612
  • Fixes Explosion behavior when 3 mons can endure hit by @AlexOn1ine in #7594
  • Fixes octolock not ending after user switched out by @AlexOn1ine in #7556
  • The original attacker wasn’t restored for Doodle by @AlexOn1ine in #7620
  • Restore X item friendship increase by @ravepossum in #7583
  • Fixes Wonder Room interactions with Defense/Special Defense boosting effects by @PhallenTree in #7626
  • Ally Switch attract battler swapping, test for leech seed by @ghoulslash in #7634

🤹 Moves 🤹

Fixed

  • Clear gScanlineEffect to fix timeout in acid downpour animation by @FosterProgramming in #7442
  • Fix terastallization anims flickering by @ravepossum in #7613

🧶 Items 🧶

Changed

  • Fix using town map as registered item by @ravepossum in #7482

Fixed

  • Implement using party menu items from field by @ravepossum in #7481

🤖 Battle AI 🤖

Changed

  • Macro-for-AI-Flag-definitions by @grintoul1 in #7471

Fixed

  • Incorrect call in Rest by @surskitty in #7569
  • Fix duplicate switch in after faint by @AlexOn1ine in #7600

🧹 Other Cleanup 🧹

  • Macro-for-AI-Flag-definitions by @grintoul1 in #7471
  • Moved summary screen nature colors to summary_screen.h by @RubyRaven6 in #7560
  • fix: remove unused wild_encounters.json.txt jinja file by @khbsd in #7581
  • Fix Form Change Item Task Data and Clean Up Field Use Funcs by @ravepossum in #7535
  • Fixed Teleport’s description not being updated based on B_TELEPORT_BEHAVIOR by @AsparagusEduardo in #7580
  • Fixed typo in test name by @hedara90 in #7610
  • Minor Clean up in battle_ai_main.c by @AlexOn1ine in #7551
  • Remove unused function by @AlexOn1ine in #7617
  • Fix Vs Seeker Trainer Battle script issue by @pkmnsnfrn in #7615

🧪 Test Runner 🧪

Changed

  • Clean up some Normalize tests to make them make sense by @hedara90 in #7461
  • Add Synthesis + Utililty Umbrella test by @ghoulslash in #7472
  • Add test for BoxPokemon integrity by @hedara90 in #7487
  • Re-order moves in fling test by @hedara90 in #7559
  • Wrote some tests by @AsparagusEduardo in #7563
  • Added Ability TODO tests - Volume C by @AsparagusEduardo in #7562
  • Added missing Move Effect TODO tests - Volume F by @AsparagusEduardo in #7605
  • Fixed typo in test name by @hedara90 in #7610

Fixed

  • Clear out parties between battle tests by @hedara90 in #7460
  • Fixed most failed tests with GEN_LATEST GEN_8 by @AsparagusEduardo in #7498
  • Corrected Liquid Ooze test by @AsparagusEduardo in #7527
  • switchinabilities also runs ON_WEATHER and ON_TERRAIN by @ghoulslash in #7612
  • Ally Switch attract battler swapping, test for leech seed by @ghoulslash in #7634

📚 Documentation 📚

  • Update how_to_new_pokemon.md by @kevinwklawrence in #7440
  • Updating a link to porytiles in INSTALL.md by @ThePeeps191 in #7490
  • Added comment in event.inc for simple menus in dynmultichoice by @RubyRaven6 in #7568

New Contributors

  • @kevinwklawrence made their first contribution in #7440
  • @ThePeeps191 made their first contribution in #7490
  • @cornixsenex made their first contribution in #7368

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.12.2...expansion/1.12.3

Version 1.12.2

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.12.1
`.

🧬 General 🧬

Changed

  • Changed trainer tutorial to take into account removed palette compression by @hedara90 in #7044
  • Update CI to ignore allcontributors commits by @pkmnsnfrn in #7046
  • add bassforte123 as a contributor for code by @allcontributors[bot] in #7003
  • add iriv24 as a contributor for code by @allcontributors[bot] in #7059
  • add Bivurnum as a contributor for code by @allcontributors[bot] in #7067
  • Fixed CI issue introduced 7046 by @pkmnsnfrn in #7072
  • Added loop iterator style by @hedara90 in #7092
  • add Emiliasky as a contributor for test by @allcontributors[bot] in #7082
  • Update CREDITS.md with correct line placement by @pkmnsnfrn in #7096
  • Fix typo in INSTALL.md by @hedara90 in #7116
  • Use RGB values for DEFAULT_LIGHT_COLOR by @hedara90 in #7133
  • Applied Kasen’s documentation improvements by @hedara90 in #7104
  • add fakuzatsu as a contributor for code by @allcontributors[bot] in #7136
  • Fixed description of FORM_CHANGE_WITHDRAW by @AsparagusEduardo in #7152
  • add poetahto as a contributor for code by @allcontributors[bot] in #7162
  • Pret merge (19th of June, 2025) by @Bassoonian in #7163
  • Update the description of OW_OBJECT_VANILLA_SHADOWS by @pkmnsnfrn in #7184
  • fix: use BackPickId to calculate player intro ball throw animation palette by @pablopenna in #7193
  • add pablopenna as a contributor for code by @allcontributors[bot] in #7202

Fixed

  • Added line break between Trainer 1 name and Trainer 2 name in sText_TwoTrainersWantToBattle by @grintoul1 in #7028
  • Fixed Battle Pyramid mon generation by @hedara90 in #7146
  • force sGFRomHeader to always be present by @DizzyEggg in #7186
  • force RHH Rom Header to always be present by @DizzyEggg in #7187
  • Fixed debug flag menu sound by @AsparagusEduardo in #7190
  • Fix BtlController_EmitChosenMonReturnValue UB by @DizzyEggg in #7197
  • Backported Safari catch and add to party fix by @hedara90 in #7192
  • Fix 01_battle_engine_bugs.yaml by @hedara90 in #7242

🗺️ Overworld 🗺️

Fixed

  • Bug fix: clear saved follower NPC door warp when doing dive warp by @Bivurnum in #7065
  • Fix Contest Painting load palette error by @ExMingYan in #7077
  • Bug fix: Follower NPC no longer retains bike sprite after white out by @Bivurnum in #7120
  • Bug fix: clear follower npc surf blob on white out by @Bivurnum in #7153

🐉 Pokémon 🐉

Changed

  • Fixes Rapid Spin description (#7178) by @grintoul1 in #7181

Fixed

  • Fixed text width for a lot of forms in HGSS Dex by @AsparagusEduardo in #7035
  • Fixes Roamers not saving shininess by @i0brendan0 in #7185
  • [FIX] Prevent caught Pokémon loss in NPC partner battles by @J2M2 in #7177

⚔️ Battle General ⚔️

Changed

  • Fixes large battle messages being cut off instead of being prompted to advance 2 by @PhallenTree in #7036
  • Battle controller pret documentation by @AlexOn1ine in #7029
  • Fix typos and some cleanup (mainly in battle files) by @PhallenTree in #7107

Fixed

  • Fixes multi battle party re-order by @AlexOn1ine in #7042

  • Fixes Aura Wheel + Normalize and Hunger Switch while Transformed/Terastallized by @PhallenTree in #7061

  • Fixes speed calculation order by @AlexOn1ine in #7064

  • Bug fix for Grassy Terrain incorrectly healing non-grounded Pokemon by @LinathanZel in #7058

  • Fixes Wandering Spirit copied ability activation on fainted mon by @AlexOn1ine in #7066

  • Chloroblast fix by @LinathanZel in #7008

    • Chloroblast causing recoil damage even if the move fails to connect by @LinathanZel in #7007
  • [DRAFT] Fix Normalize not boosting Normal type moves if they were already Normal type by @i0brendan0 in #7060

  • Fixes freeze during a 1v2 double battle by @AlexOn1ine in #7075

  • Fixes Pursuit potentially causing both battlers to switch into the same mon by @PhallenTree in #7084

  • Fixed potential mismatch between players and battlers in tests by @AsparagusEduardo in #7101

  • Fixes Ally Switch in multi battles by @AlexOn1ine in #7109

  • Add missing flag for Berserk Gene by @AlexOn1ine in #7151

  • Fixes Neutralizing Gas leaving the field activating unsuppressable abilities again by @PhallenTree in #7170

  • Fixes Enigma, Kee and Maranga Berry activation timing by @AlexOn1ine in #7171

  • Fixes wrong Future Sight indexing by @AlexOn1ine in #7198

  • Fixes OOB for Teatime and Flower Shield by @AlexOn1ine in #7214

  • Fixes wrong assignment in TrySymbiosis by @AlexOn1ine in #7221

  • Adds missing healBlockTimer for Baton Pass by @AlexOn1ine in #7220

  • Jaboca berry triggers instead of being stolen by bug bite by @ghoulslash in #7237

  • Fixes Scald defrosting target while asleep by @AlexOn1ine in #7233

  • Fixes Emergency Exit sometimes causing an unrelated battler to become invisible by @PhallenTree in #7241

🤹 Moves 🤹

Changed

  • Fix ScaryFace anim for Bitter Malice by @TLM-PsIQ in #6476

Fixed

  • Fix savage spin out spider web template by @ghoulslash in #7137

🎭 Abilities 🎭

Changed

  • Flush textbox for Truant Popup by @ghoulslash in #7252

🧶 Items 🧶

Fixed

  • Fix sell price display by @cawtds in #7123

🤖 Battle AI 🤖

Fixed

  • Added AI_FLAG_PP_STALL_PREVENTION to AI_FLAG_SMART_TRAINER by @AlexOn1ine in #7112
  • Fix incorrect function parameters used in AI damage calc by @Pawkkie in #7130

🧹 Other Cleanup 🧹

  • Update CI to ignore allcontributors commits by @pkmnsnfrn in #7046
  • Update CREDITS.md with correct line placement by @pkmnsnfrn in #7096
  • Fix typos and some cleanup (mainly in battle files) by @PhallenTree in #7107
  • Fix typo in INSTALL.md by @hedara90 in #7116
  • Fixed description of FORM_CHANGE_WITHDRAW by @AsparagusEduardo in #7152
  • Spruce up FEATURES.md by @AsparagusEduardo in #7159
  • Fixes Rapid Spin description (#7178) by @grintoul1 in #7181

🧪 Test Runner 🧪

Changed

  • Wrote some missing tests by @AsparagusEduardo in #7094
  • Fixed KNOWN_FAILING Tera test by @AsparagusEduardo in #6949
  • Add some tests by @ghoulslash in #7234
  • Added tests for Toxic Thread by @hedara90 in #7244

Fixed

  • Test runner fixes by @hedara90 in #7100
  • Fixed Aura Wheel KNOWN_FAILING test by @AsparagusEduardo in #7135
  • Fix AI party count calc being maintained between tests by @AsparagusEduardo in #7200
  • Fix tests failing with B_FRIENDSHIP_BOOST being TRUE by @AsparagusEduardo in #7194
  • Jaboca berry triggers instead of being stolen by bug bite by @ghoulslash in #7237

📚 Documentation 📚

  • Changed trainer tutorial to take into account removed palette compression by @hedara90 in #7044
  • Battle controller pret documentation by @AlexOn1ine in #7029
  • Added loop iterator style by @hedara90 in #7092
  • Use RGB values for DEFAULT_LIGHT_COLOR by @hedara90 in #7133
  • Applied Kasen’s documentation improvements by @hedara90 in #7104
  • Spruce up FEATURES.md by @AsparagusEduardo in #7159
  • Update the description of OW_OBJECT_VANILLA_SHADOWS by @pkmnsnfrn in #7184

📦 Branch Synchronisation 📦

pret

  • 24th of June, 2025 in #7206
    • Move gTradePlatform_Tilemap to header and change to u32 by @DizzyEggg in pret#2088
    • Fix wrong keep temps files directory in makefile by @DizzyEggg in pret#2156
    • Fix collision comparison in PlayerNotOnBikeMoving by @GriffinRichards in pret#2104
    • Match graphics declarations with externs in graphics.h by @DizzyEggg in pret#2089

New Contributors

  • @TLM-PsIQ made their first contribution in #6476
  • @pablopenna made their first contribution in #7193
  • @J2M2 made their first contribution in #7177

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.12.0...expansion/1.12.1

Version 1.12.1

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.12.1
`.

🧬 General 🧬

Changed

  • Changed trainer tutorial to take into account removed palette compression by @hedara90 in #7044
  • Update CI to ignore allcontributors commits by @pkmnsnfrn in #7046
  • Fixed CI issue introduced 7046 by @pkmnsnfrn in #7072
  • Added loop iterator style by @hedara90 in #7092
  • Fix typo in INSTALL.md by @hedara90 in #7116
  • Use RGB values for DEFAULT_LIGHT_COLOR by @hedara90 in #7133
  • Applied Kasen’s documentation improvements by @hedara90 in #7104
  • Fixed description of FORM_CHANGE_WITHDRAW by @AsparagusEduardo in #7152
  • Pret merge (19th of June, 2025) by @Bassoonian in #7163
  • Update the description of OW_OBJECT_VANILLA_SHADOWS by @pkmnsnfrn in #7184
  • fix: use BackPickId to calculate player intro ball throw animation palette by @pablopenna in #7193

Fixed

  • Added line break between Trainer 1 name and Trainer 2 name in sText_TwoTrainersWantToBattle by @grintoul1 in #7028
  • Fixed Battle Pyramid mon generation by @hedara90 in #7146
  • force sGFRomHeader to always be present by @DizzyEggg in #7186
  • force RHH Rom Header to always be present by @DizzyEggg in #7187
  • Fixed debug flag menu sound by @AsparagusEduardo in #7190
  • Fix BtlController_EmitChosenMonReturnValue UB by @DizzyEggg in #7197
  • Backported Safari catch and add to party fix by @hedara90 in #7192
  • Fix 01_battle_engine_bugs.yaml by @hedara90 in #7242

🗺️ Overworld 🗺️

Fixed

  • Bug fix: clear saved follower NPC door warp when doing dive warp by @Bivurnum in #7065
  • Fix Contest Painting load palette error by @ExMingYan in #7077
  • Bug fix: Follower NPC no longer retains bike sprite after white out by @Bivurnum in #7120
  • Bug fix: clear follower npc surf blob on white out by @Bivurnum in #7153

🐉 Pokémon 🐉

Changed

  • Fixes Rapid Spin description (#7178) by @grintoul1 in #7181

Fixed

  • Fixed text width for a lot of forms in HGSS Dex by @AsparagusEduardo in #7035
  • Fixes Roamers not saving shininess by @i0brendan0 in #7185
  • [FIX] Prevent caught Pokémon loss in NPC partner battles by @J2M2 in #7177

⚔️ Battle General ⚔️

Changed

  • Fixes large battle messages being cut off instead of being prompted to advance 2 by @PhallenTree in #7036
  • Battle controller pret documentation by @AlexOn1ine in #7029
  • Fix typos and some cleanup (mainly in battle files) by @PhallenTree in #7107

Fixed

  • Fixes multi battle party re-order by @AlexOn1ine in #7042
  • Fixes Aura Wheel + Normalize and Hunger Switch while Transformed/Terastallized by @PhallenTree in #7061
  • Fixes speed calculation order by @AlexOn1ine in #7064
  • Bug fix for Grassy Terrain incorrectly healing non-grounded Pokemon by @LinathanZel in #7058
  • Fixes Wandering Spirit copied ability activation on fainted mon by @AlexOn1ine in #7066
  • Chloroblast fix by @LinathanZel in #7008
  • Fix Normalize not boosting Normal type moves if they were already Normal type by @i0brendan0 in #7060
  • Fixes freeze during a 1v2 double battle by @AlexOn1ine in #7075
  • Fixes Pursuit potentially causing both battlers to switch into the same mon by @PhallenTree in #7084
  • Fixed potential mismatch between players and battlers in tests by @AsparagusEduardo in #7101
  • Fixes Ally Switch in multi battles by @AlexOn1ine in #7109
  • Add missing flag for Berserk Gene by @AlexOn1ine in #7151
  • Fixes Neutralizing Gas leaving the field activating unsuppressable abilities again by @PhallenTree in #7170
  • Fixes Enigma, Kee and Maranga Berry activation timing by @AlexOn1ine in #7171
  • Fixes wrong Future Sight indexing by @AlexOn1ine in #7198
  • Fixes OOB for Teatime and Flower Shield by @AlexOn1ine in #7214
  • Fixes wrong assignment in TrySymbiosis by @AlexOn1ine in #7221
  • Adds missing healBlockTimer for Baton Pass by @AlexOn1ine in #7220
  • Jaboca berry triggers instead of being stolen by bug bite by @ghoulslash in #7237
  • Fixes Scald defrosting target while asleep by @AlexOn1ine in #7233
  • Fixes Emergency Exit sometimes causing an unrelated battler to become invisible by @PhallenTree in #7241

🤹 Moves 🤹

Changed

  • Fix ScaryFace anim for Bitter Malice by @TLM-PsIQ in #6476

Fixed

  • Fix savage spin out spider web template by @ghoulslash in #7137

🎭 Abilities 🎭

Changed

  • Flush textbox for Truant Popup by @ghoulslash in #7252

🧶 Items 🧶

Fixed

  • Fix sell price display by @cawtds in #7123

🤖 Battle AI 🤖

Fixed

  • Added AI_FLAG_PP_STALL_PREVENTION to AI_FLAG_SMART_TRAINER by @AlexOn1ine in #7112
  • Fix incorrect function parameters used in AI damage calc by @Pawkkie in #7130

🧹 Other Cleanup 🧹

  • Fix typos and some cleanup (mainly in battle files) by @PhallenTree in #7107
  • Fix typo in INSTALL.md by @hedara90 in #7116
  • Fixed description of FORM_CHANGE_WITHDRAW by @AsparagusEduardo in #7152
  • Spruce up FEATURES.md by @AsparagusEduardo in #7159
  • Fixes Rapid Spin description (#7178) by @grintoul1 in #7181

🧪 Test Runner 🧪

Changed

  • Wrote some missing tests by @AsparagusEduardo in #7094
  • Fixed KNOWN_FAILING Tera test by @AsparagusEduardo in #6949
  • Add some tests by @ghoulslash in #7234
  • Added tests for Toxic Thread by @hedara90 in #7244

Fixed

  • Test runner fixes by @hedara90 in #7100
  • Fixed Aura Wheel KNOWN_FAILING test by @AsparagusEduardo in #7135
  • Fix AI party count calc being maintained between tests by @AsparagusEduardo in #7200
  • Fix tests failing with B_FRIENDSHIP_BOOST being TRUE by @AsparagusEduardo in #7194
  • Jaboca berry triggers instead of being stolen by bug bite by @ghoulslash in #7237

📚 Documentation 📚

  • Changed trainer tutorial to take into account removed palette compression by @hedara90 in #7044
  • Battle controller pret documentation by @AlexOn1ine in #7029
  • Added loop iterator style by @hedara90 in #7092
  • Use RGB values for DEFAULT_LIGHT_COLOR by @hedara90 in #7133
  • Applied Kasen’s documentation improvements by @hedara90 in #7104
  • Spruce up FEATURES.md by @AsparagusEduardo in #7159
  • Update the description of OW_OBJECT_VANILLA_SHADOWS by @pkmnsnfrn in #7184

📦 Branch Synchronisation 📦

pret

  • 24th of June, 2025 in #7206
    • Move gTradePlatform_Tilemap to header and change to u32 by @DizzyEggg in pret#2088
    • Fix wrong keep temps files directory in makefile by @DizzyEggg in pret#2156
    • Fix collision comparison in PlayerNotOnBikeMoving by @GriffinRichards in pret#2104
    • Match graphics declarations with externs in graphics.h by @DizzyEggg in pret#2089

New Contributors

  • @TLM-PsIQ made their first contribution in #6476
  • @pablopenna made their first contribution in #7193
  • @J2M2 made their first contribution in #7177

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.12.0...expansion/1.12.1

Version 1.12.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.12.0
`.

🌋 REFACTORS 🌋

📜 = Uses a migration script.

  • Minor Recoil Effect refactor by @AlexOn1ine in #6409
  • Refactor HasWeatherEffect and IsUnnerveAbilityOnOpposingSide by @AlexOn1ine in #6441
  • Refactor the function IsAbilityPreventingEscape by @AlexOn1ine in #6439
  • Unifies dynamic move category checks by @AlexOn1ine in #6443
  • Refactors faint target abilities and adds Battle Bond config by @AlexOn1ine in #6519
  • Refactor protect to allow at least 126 different types of protect eff… by @AlexOn1ine in #6506
  • Refactor / Simlify Cmd_adjustdamage and remove redundancy by @AlexOn1ine in #6499
  • Refactors Move absorb / block function calls to remove redundancy by @AlexOn1ine in #6490
  • Refactor fixed damage moves by @AlexOn1ine in #6449
  • EndTurnEffectOrder Refactor by @AlexOn1ine in #6224
  • Refactor hit escape moves to use moveend by @AlexOn1ine in #6671
  • 📜 Evolution Refactor by @khbsd, @AsparagusEduardo for everything he did, including #6530! and @AlexOn1ine for writing the migration script! in #6556
    • make sure to back up your alcremie evolution data if you have it implemented already: pulling this will overwrite it
  • Centralizes non volatile status effect checks by @AlexOn1ine in #6533
  • Refactor battler flee and watch options + clean up by @AlexOn1ine in #6724
  • Refactor AI flags to u64 by @Pawkkie and @DizzyEggg, @AlexOn1ine, @hedara90 in #6753
  • Refactor battler message ids by @AlexOn1ine in #6765
  • Refactor stockpile resets by @AlexOn1ine in #6810
  • Move out ai structs out of BattleResources by @AlexOn1ine in #6741
  • Consolidates a bunch of battle controller functions by @Bassoonian in #6838
  • Further moveend changes (move blocks) by @AlexOn1ine in #6820
  • Added weather accuracy move flags by @AsparagusEduardo in #6857
    • Removed EFFECT_THUNDER, EFFECT_BLIZZARD and EFFECT_RAIN_ALWAYS_HIT effects in favor of alwaysHitsInRain, alwaysHitsInHailSnow and accuracy50InSun move flags.
  • Remove non-volatile status EFFECTs by @AsparagusEduardo in #6772
  • 📜 Remove compressed palettes by @hedara90 in #6455
    • All handling for compressed palettes has been removed, use u16 * for palettes instead.
    • Has migration script to convert palettes to u16, struct SpritePalette and palette loading calls from their compressed variants.

🧬 General 🧬

Added

  • Low Health Beeps Configuration by @khbsd in #6328
  • Adds SHOW_TYPES_SEEN to the B_SHOW_TYPES option by @khbsd in #6561
    • this slightly alters how the flag FLAG_GET_SEEN is set, so keep that in mind if you have any functionality that relies on it being at the start of the battle.
  • Type Effectiveness Indicators when selecting moves by @agsmgmaster64 in #6559
  • FakeRtc datetime and ResetRtcScreen day increments by @cawtds in #5695
  • Battle Transition: mugshots for multibattles by @grintoul1 and @AlexOn1ine for advice on simplifying the conditions that check for 2nd opponent and presence of battle partner, and general advice/troubleshooting in #6567
  • Time menu for RTC in debug menu. by @RubyRaven6, @cawtds for RTC refactors that makes all of this easier, @HashtagMarky for helping me understand how the debug menu works, especially with destroying menus, @zetraphes, for helping with refactoring the redundant functions into a single function. and @makosear for originally getting me into the RTC hellhole in #6634
    • In order to apply the new time the map is reloaded through The LoadMap Callback (CB2_LoadMap). As such, this will also do everything else that comes with loading map in.
  • Pokedex Plus HGSS move configs by @PCG06 in #6687 Adds three configs for Pokedex Plus HGSS.
    • To sort TM moves by num.
    • To show egg moves for evolved Pokémon.
    • Creating a dynamic tutor moves array to use for tutor moves counting.
  • Allow different flags for Badge boost by @AsparagusEduardo and @ghoulslash, @klemniops, whose’ code I was using for comparison when I found these in #6805
  • Timemacros by @RubyRaven6 in #6696

Changed

  • Rename absentBattlerFlags to absent by @AlexOn1ine in #6432
  • Removed unused debug EWRAM variables by @hedara90 in #6468
  • Removes unused Special Status members by @AlexOn1ine in #6479
  • Remove potential pitfall with saved damage for recoil moves by @AlexOn1ine in #6485
  • Add CONTRIBUTING.md and STYLEGUIDE.md by @pkmnsnfrn and @Pawkkie, @garakmon in #6340
  • Alcremie Evolution clean up follow up by @AlexOn1ine in #6557
  • Fix broken links in merge_checklist.md by @pkmnsnfrn and @grintoul1 in #6570
  • Converts some defines to enums by @Bassoonian in #6592
  • Removes vestigial EWRAM variable from debug menu. by @RubyRaven6 in #6686
  • Keep Steven Multi Debug Option at the Bottom Forever by @Pawkkie in #6694
  • Better handling of battle coords by @AsparagusEduardo and @ghoulslash, @klemniops for the original code. in #6787
  • battle_main enum cleanup by @AsparagusEduardo and @ghoulslash, @klemniops, whose’ code I was using for comparison when I found these in #6788
  • Add missing uses of IsBattlerAlly by @AsparagusEduardo and @ghoulslash, @klemniops, whose’ code I was using for comparison when I found these in #6793
  • Adds partyState to BattleStruct by @AlexOn1ine in #6783
  • Rename GetPartyBattlerData to GetBattlerMon by @AsparagusEduardo and @ghoulslash, @klemniops, whose’ code I was using for comparison when I found these in #6800
  • Added JSON as the preferred data format by @hedara90 in #6801
  • Remove non-existent functions from header files by @Bassoonian in #6825
  • Added IsOnPlayerSide by @AsparagusEduardo in #6832
  • Battle TV expansion by @AsparagusEduardo in #6826
  • Prevent scaninc touching tests when make-ing non-test builds by @mudskipper13 in #6812
  • Reword move and ability descriptions to improve clarity by @jfb1337 in #6861
    • Updated move and ability descriptions to increase clarity.
  • Optimized PokemonUseItemEffects function by @AsparagusEduardo in #6878
  • Expand trainerproc to support additional battle types by @AsparagusEduardo in #6770
  • Debug menu cleanup by @AsparagusEduardo in #6881
  • Commenting in config files to explain limits of map popups and wild AI flags by @surskitty in #6923
  • Documented usage of createsprite gSimplePaletteBlendSpriteTemplate by @AsparagusEduardo in #6956
  • Documented usage of createsprite gDirtPlumeSpriteTemplate by @AsparagusEduardo in #6954
  • Updated CONTRIBUTING.md and Merge Freeze definition by @pkmnsnfrn in #6952
  • Documented usage of createsprite gBasicHitSplatSpriteTemplate by @AsparagusEduardo in #6950
  • Documented usage of createsprite gSparkElectricitySpriteTemplate by @AsparagusEduardo in #6955
  • Documented usage of createsprite gSlideMonToOffsetSpriteTemplate by @AsparagusEduardo in #6953
  • Remove trailing whitespace by @AsparagusEduardo in #6968
  • Beefing up the DNS tutorial for some of the common questions/errors. by @surskitty in #6922
  • Clarifies when to use each merge type for maintainers by @pkmnsnfrn in #6999
  • Moved time constants to dedicated files by @pkmnsnfrn in #7019

Fixed

  • fix: missing break statement by @khbsd in #6572
  • Fix dynamax message by @hedara90 in #6589
  • Fix pc mon pic by @hedara90 in #6709
  • Fixed upcoming not compiling in gcc 11.4.0 by @AsparagusEduardo in #6710
  • Fix the Move Item option in the PC still expecting compressed palettes by @hedara90 in #6739
  • Fix upcoming compile by @AsparagusEduardo in #6804
  • Added missing root folder check in trainer battle type migration script by @AsparagusEduardo in #6944
  • Fixed forfeit money for B_WHITEOUT_MONEY <= GEN_3 by @AsparagusEduardo in #6942
  • Fix UB when using time menu by @cawtds in #7023

🗺️ Overworld 🗺️

Added

  • Add OW_DEFOG_FIELD_MOVE to allow players to clear overworld Fog by @pkmnsnfrn in #6477 This behavior is enabled by setting OW_DEFOG_FIELD_MOVE to TRUE.
  • Add Time-Based Encounters by @khbsd and @Pawkkie, @Artrios, @GriffinRichards, @ravepossum, @ghoulslash, @lhearachel probably more so tag me somewhere and ill add you! in #6454
    • Comes with a new conversion script, wild_encounters_to_header.py. On my machine i timed it out to about .02s, hopefully it wont add too much to the compile time on anyone elses computers
    • The conversion script can handle an unchanged wild_encounters.json just fine, but also plays nice with edited ones as far as I can tell
    • The migration script takes one optional argument, --copy
    • --copy will copy over all of the encounter tables (land_mons, water_mons, etc). default behavior just adds the base_label and if applicable, the map.
  • Add B_RUN_TRAINER_BATTLE - players can run from Trainer Battles by @pkmnsnfrn and @wiz1989 wrote the original feature. in #6456
  • Integrated merrp’s lighting branch (Day/Night System) by @hedara90, @AsparagusEduardo for doing most of this PR and @aarant for the original implementation and feature branch, @Greenphx9 for their help merging to current expansion. in #6562
    • Changes from the base branch:
    • Uses Expansion’s Fake RTC and updates its tinting refresh rate alongside with it.
    • Uses Expansion’s constants (TIME_NIGHT instead of TIME_OF_DAY_NIGHT). This allows it to:
    • Use different tinting for Morning vs Evening compared to the original branch.
    • Use Expansion’s OW_TIMES_OF_DAYconfig that allows users to set their own times by generation.
    • Added option to disable object event shadows
    • Added option to turn DNS on or off, OW_ENABLE_DNS
    • Added option to for vanilla shadow behaviour, OW_OBJECT_VANILLA_SHADOWS
    • Scripts containing consecutive removeobject <object> and addobject <object> needs a delay 1 between the commands.
    removeobject MY_OBJECT
    + delay 1
    addobject MY_OBJECT
    
    • Changes to base Hoenn to integrate DNS can be enabled by reverting commit a5b079d
    • Other changes:
    • Changed the BW Map Popup to update its time while active.
  • Follower NPCs (follow-me) by @Bivurnum, @ghoulslash Much of their original code is still present. and @grintoul1 Invaluable play testing and feedback. in #6500
    • Turn any NPC into a follower.
    • Specify a battle partner to turn all trainer battles into multi battles automatically while an NPC follower is present.

Changed

  • Add Time-Based Encounter Tutorial by @khbsd and @Pawkkie (ty for reviewing!!) in #6568
  • Remove vestigial AdvanceScript function used for testing by @RubyRaven6 in #6664
  • Rename follower npc macros for better specificity and to match documentation by @Bivurnum in #6742
  • Add follower NPC documentation by @Bivurnum in #6704

Fixed

  • Fixed DNS off config sometimes breaking palettes on map change by @hedara90 in #6603
  • Fixed objects not getting unloaded properly when event flags are set by @Bivurnum in #6715
  • Bug fix: add proper elevation handling for npc followers by @Bivurnum in #6871
  • fix: avoid unexpected data shifting by removing preproc’d array size by @khbsd in #6916
  • Fix OW_POPUP_BW_TIME_MODE burning a lot of cycles due to RTC queries. by @SBird1337 in #6974
    • Fixed an issue that causes the game to lag in some configurations that involve OW_POPUP_BW_TIME_MODE.
  • Make setobjextxy work with npc followers during ON_WARP map script by @Bivurnum in #6913
  • removeobject and removeobjectat macros work properly with npc followers by @Bivurnum in #6889
  • Fixes follower NPC not changing state with player after warp by @Bivurnum in #7009
  • Fixed follower NPC changing to surf sprite when choosing not to surface from dive by @Bivurnum in #7010
  • Fix follower NPC not reappearing after Mossdeep gym warp by @Bivurnum in #7014
  • Fixed surf blob binding to invisible follower NPC on map reload by @Bivurnum in #7013
  • fix: better area mons handling, no longer duplicates hiddenMons field by @khbsd in #6945
  • Bug fix: setfollowernpc macro no longer runs when FNPC_ENABLE_NPC_FOLLOWERS is FALSE by @Bivurnum in #6755

🐉 Pokémon 🐉

Added

  • Configuration to scale Critical Capture odds based on local Pokedex or estimated National Pokedex by @surskitty in #6250
  • Add B_ANIMATE_MON_AFTER_KO - mons animate after scoring a KO by @pkmnsnfrn and @NicoSwag wrote the original feature. in #6451
    • This can be disabled by setting B_ANIMATE_MON_AFTER_KO to FALSE.
  • Add OW_DEFOG_FIELD_MOVE to allow players to clear overworld Fog by @pkmnsnfrn in #6477 This behavior is enabled by setting OW_DEFOG_FIELD_MOVE to TRUE.
  • Add “Move Item” option in party menu by @AsparagusEduardo in #6758

Changed

  • Implemented Alcremie Evolution Method by @AsparagusEduardo in #6530
  • Make form change methods into enum + type checking by @Bassoonian in #6631
  • Remove hardcoded values from wild_encounter.h generation by @khbsd and @moostoet and @/Nopinou on discord for reporting bugs and dealing with my ping spam <3 in #6640
  • Evolution Refactor by @khbsd, @AsparagusEduardo for everything he did, including #6530! and @AlexOn1ine for writing the migration script! in #6556
    • make sure to back up your alcremie evolution data if you have it implemented already: pulling this will overwrite it
  • Disable P_TUTOR_MOVES_ARRAY config by @PCG06 in #6693
    • P_TUTOR_MOVES_ARRAY set to FALSE by default.

Fixed

  • Change HasTwoFramesAnimation to take into account species with 1 frame by @hedara90 in #6655
  • Fix Rage Fist evolution method by @AsparagusEduardo in #6937
  • Fixed CreateMon param order in CreateFacilityMon by @PCG06 in #6989

⚔️ Battle General ⚔️

Added

  • Gen 1’s Special base stat by @AsparagusEduardo in #6330
  • Add B_RUN_TRAINER_BATTLE - players can run from Trainer Battles by @pkmnsnfrn and @wiz1989 wrote the original feature. in #6456
  • Add B_LEVEL_UP_NOTIFICATION to improve player QoL when performing multiple level ups by @pkmnsnfrn in #4901
  • “Aerilate”-esque Ability Tests and Config by @Pawkkie and @hedara90 in #6313
    • Adds new B_ATE_MULTIPLIER config in config/battle.h
  • Gen 1 no recharge on KO by @spindrift64 in #6869
  • Add no-whiteout feature by @Bassoonian and @/Gudf in #6795

Changed

  • “no additional effect” text for status Z moves without effects by @wiz1989 in #6368
  • Configuration to make all Hail moves summon Snow or vis versa, to have only one ice weather by @surskitty in #6149
    • Added a config to homogenize Ice weathers between Hail, Snow, or both.
  • Create move end Sheer Force by @AlexOn1ine in #6411
  • Added Dynamax/Gigantamax battle messages by @wiz1989 in #6440
  • Refactor HasWeatherEffect and IsUnnerveAbilityOnOpposingSide by @AlexOn1ine in #6441
  • Refactor the function IsAbilityPreventingEscape by @AlexOn1ine in #6439
  • Unifies dynamic move category checks by @AlexOn1ine in #6443
  • Refactors faint target abilities and adds Battle Bond config by @AlexOn1ine in #6519
  • Refactor protect to allow at least 126 different types of protect eff… by @AlexOn1ine in #6506
  • Refactor / Simlify Cmd_adjustdamage and remove redundancy by @AlexOn1ine in #6499
  • Refactors Move absorb / block function calls to remove redundancy by @AlexOn1ine in #6490
  • Refactor fixed damage moves by @AlexOn1ine in #6449
  • Turn battle string ids into enums by @Bassoonian in #6594
  • Remove redundant bit for Throat Spray by @AlexOn1ine in #6593
  • Add type checking for hold item effects by @Bassoonian in #6619
  • Adds move effect type checking by @Bassoonian in #6618
  • Refactor hit escape moves to use moveend by @AlexOn1ine in #6671
  • Fix party access in NoAliveMonsForBattlerSide by @AlexOn1ine in #6677
  • Some Me First tests plus minor clean up by @AlexOn1ine in #6678
  • Centralizes non volatile status effect checks by @AlexOn1ine in #6533
  • Use GetPartyBattlerData where appropiate by @AsparagusEduardo and @ghoulslash, @klemniops, whose’ code I was using for comparison when I found these in #6779
  • Refactor battler message ids by @AlexOn1ine in #6765
  • General MoveEnd clean up and Fell Stinger adjustments by @AlexOn1ine in #6674
  • Adds partyState to BattleStruct by @AlexOn1ine in #6783
  • Refactor stockpile resets by @AlexOn1ine in #6810
  • Changed White Herb hold effect name by @AlexOn1ine in #6815
  • Fixes a mistake made by me by @AlexOn1ine in #6828
  • Combined type-enhancing hold effects by @AsparagusEduardo in #6846
    • The following hold effects have been combined into HOLD_EFFECT_TYPE_POWER:
    • HOLD_EFFECT_BUG_POWER
    • HOLD_EFFECT_STEEL_POWER
    • HOLD_EFFECT_GROUND_POWER
    • HOLD_EFFECT_ROCK_POWER
    • HOLD_EFFECT_GRASS_POWER
    • HOLD_EFFECT_DARK_POWER
    • HOLD_EFFECT_FIGHTING_POWER
    • HOLD_EFFECT_ELECTRIC_POWER
    • HOLD_EFFECT_WATER_POWER
    • HOLD_EFFECT_FLYING_POWER
    • HOLD_EFFECT_POISON_POWER
    • HOLD_EFFECT_ICE_POWER
    • HOLD_EFFECT_GHOST_POWER
    • HOLD_EFFECT_PSYCHIC_POWER
    • HOLD_EFFECT_FIRE_POWER
    • HOLD_EFFECT_DRAGON_POWER
    • HOLD_EFFECT_NORMAL_POWER
    • HOLD_EFFECT_FAIRY_POWER
  • Removed multiple instances of hardcoded move IDs by @AsparagusEduardo in #6856
  • New animations for Mega Evolution, Primal Reversion, Ultra Burst, and Power Construct by @LinathanZel in #6834
  • Consolidates a bunch of battle controller functions by @Bassoonian in #6838
  • Further moveend changes (move blocks) by @AlexOn1ine in #6820
  • Added weather accuracy move flags by @AsparagusEduardo in #6857
    • Removed EFFECT_THUNDER, EFFECT_BLIZZARD and EFFECT_RAIN_ALWAYS_HIT effects in favor of alwaysHitsInRain, alwaysHitsInHailSnow and accuracy50InSun move flags.
  • Consolidated HasMoveFlagX functions by @AlexOn1ine in #6874

Fixed

  • Fix declaration after label for Psywave switch by @hedara90 in #6595
  • Fix regression from EndTurnRefactor by @AlexOn1ine in #6616
  • Fixes Z and Max moves dmg reduction against side protection - upcoming by @AlexOn1ine in #6698
  • Illusion struct cleanup and many Illusion fixes by @PhallenTree in #6798
  • Fixes wrongly usage of arguments without checking effect by @AlexOn1ine in #6859
  • Fixes Magic Guard causing Wrap to end immediately by @PhallenTree in #6876
  • Mugshot Transitions 2v1 fix by @grintoul1 in #6911
  • Fixes Ice Body healing HP regardless of weather by @PhallenTree in #6939
  • Fixes global usage in super fang effect. by @AlexOn1ine in #6941
  • Fixes Knock Off/Smack Down effect on immune target/protect by @PhallenTree in #6958
  • Fixes weather anim damage being applied to the wrong mon by @AlexOn1ine in #6973
  • Fixes repeated learning of level up moves by @AlexOn1ine in #6981
  • Fixes Gen3 berry activation timing by @AlexOn1ine in #6993
  • Fix Eiscue not resetting back to Ice Face form after battle. by @DarkVexon in #6997
  • Fixes spread move fire types not defrosting all targets by @AlexOn1ine in #6998
  • Update Supersweet Syrup with eject pack fix by @AlexOn1ine in #7015
  • fix battle controller macros by @cawtds in #7021

🤹 Moves 🤹

Added

  • Add B_ANIMATE_MON_AFTER_KO - mons animate after scoring a KO by @pkmnsnfrn and @NicoSwag wrote the original feature. in #6451
    • This can be disabled by setting B_ANIMATE_MON_AFTER_KO to FALSE.
  • Add OW_DEFOG_FIELD_MOVE to allow players to clear overworld Fog by @pkmnsnfrn in #6477
    • This behavior is enabled by setting OW_DEFOG_FIELD_MOVE to TRUE.

Changed

  • Minor Recoil Effect refactor by @AlexOn1ine in #6409
  • Replaced Blue Sky background for Rock Field by @SundayMoonday in #6516
  • Use missing constants with GetBattlerSpriteCoord by @AsparagusEduardo in #6778
  • InitSpritePosToAnimAttacker documentation by @AsparagusEduardo and @ghoulslash, @klemniops, whose’ code I was using for comparison when I found these in #6781
  • Document battler side in anim code by @AlexOn1ine in #6780
  • New animations for Mega Evolution, Primal Reversion, Ultra Burst, and Power Construct by @LinathanZel in #6834

Fixed

  • Fix to warnings pertaining to Mega Evolution and Ultra Burst RGB values by @LinathanZel in #6883

🤖 Battle AI 🤖

Added

  • Improve AI’s handling of player’s Encore by @Pawkkie and @iriv24 in #6305
  • Switch AI will factor in player’s choice lock when determining hits to KO by @Pawkkie in #6343
  • Switch AI considers Wind Rider by @innocenthedgehog in #6391
  • Fix AI using Scald / fire moves against frozen / frostbitten targets by @Pawkkie in #6442
  • Improve “all moves bad” switching by @Pawkkie and @wiz1989 in #6453
  • Fix Choice’d AI not switching if player immune to move by @Pawkkie in #6464
  • Add basic Unaware check bad move scoring by @Pawkkie in #6524
  • AI smarter status handling by @Pawkkie in #6550
  • Improve AI’s defense against Focus Punch by @Pawkkie in #6713
  • Add AI_FLAG_PP_STALL_PREVENTION by @hedara90 in #6743
    • Chance to trigger and score modifier can be changed in include/config/ai.h under the “AI PP Stall detection” section
  • Adjust switch AI based on move scoring by @Pawkkie and @ghoulslash, @AlexOn1ine in #6615
    • Change AI_BAD_SCORE_THRESHOLD and AI_GOOD_SCORE_THRESHOLD to modify what ShouldSwitchIfAllScoresBad considers, found in config/ai.h
  • Add AI for Zero to Hero Palafin by @Pawkkie and @kittenchilly in #6791
  • Add AI_FLAG_PREDICT_MOVES by @Pawkkie in #6551
    • Use AI_FLAG_PREDICT_MOVES to enable behaviour
    • Works best when used with AI_FLAG_OMNISCIENT

Changed

  • Minor Clean up for AI_CalcDamage to remove some duplicate code by @AlexOn1ine in #6397
  • Moved some AI stuff out of the battlestruct by @hedara90 in #6405
    • AI data in gBattleStruct has been moved to gAiBattleStructData.
  • Allow the AI to see the second hit of Parental Bond by @AlexOn1ine in #6403
  • Split ai function IsBattlerTrapped by @AlexOn1ine in #6438
  • Optimization / Clean up of AI move usability by @AlexOn1ine in #6332
  • Clean up AI code duplication and unify checks by @AlexOn1ine in #6348
  • Ability access cleanup for #6550 by @Pawkkie in #6565
  • Adjust enum AIScore by @AlexOn1ine in #6598
  • Refactor battler flee and watch options + clean up by @AlexOn1ine in #6724
  • Add AI_FLAG_PP_STALL_PREVENTION to ai_flags.md by @Pawkkie in #6756
  • Refactor AI flags to u64 by @Pawkkie and @DizzyEggg, @AlexOn1ine, @hedara90 in #6753
  • Move out ai structs out of BattleResources by @AlexOn1ine in #6741
  • Add prediction function by @AlexOn1ine in #6858
  • AI double battle friendly fire logic improvements by @surskitty and @Pawkkie in #6766
  • Remove non-volatile status EFFECTs by @AsparagusEduardo in #6772
  • Fix misleading name by @AlexOn1ine in #6865
  • Fix HasBattlerSideMoveWithEffect comment by @Pawkkie in #6965

Fixed

  • Fix damage roll order for AI calcs by @AlexOn1ine in #6356
  • Fix roll handling in AI damage calcs by @Pawkkie in #6396
  • fixed damage calculations in CanTargetFaintAiWithMod() by @wiz1989 in #6446
  • Fix bracket typo in AI_CheckBadMove conditional by @Pawkkie in #6695
  • Fix party data assignment by @Pawkkie in #6712
  • Fix Wonder Guard potential double switching by @Pawkkie in #6737
  • Fix roll handling in AI party damage calcs by @Pawkkie in #6733
  • Fix AI function table to match new u64 flags by @Pawkkie in #6796
  • Fix FindMonThatAbsorbsOpponentsMove not seeing Mold Breaker or choice items by @Pawkkie in #6864
  • Fix AI_FLAG_PREDICT_MOVES scoring bug by @Pawkkie and @innocenthedgehog for test in #6867
  • Switch AI considers Bulletproof ability by @innocenthedgehog in #6872
  • Fix AI boosting stats into mon with Haze by @Pawkkie in #6894
  • Fix switch AI considering non-choiced SE moves when choiced by @Pawkkie in #6892
  • Fix bad odds / defensive switchin double switch cases by @Pawkkie in #6927

🧹 Other Cleanup 🧹

  • Moved Pokémon Jump types to gSpeciesInfo by @AsparagusEduardo in #5602
  • Change ability to abilityNum in CreateTrainerMon by @AlexOn1ine in #6370
  • Small Code clean up in GetBattlerAbility (removes duplication) by @AlexOn1ine in #6362
  • Minor Clean up for AI_CalcDamage to remove some duplicate code by @AlexOn1ine in #6397
  • Create move end Sheer Force by @AlexOn1ine in #6411
  • Rename absentBattlerFlags to absent by @AlexOn1ine in #6432
  • Split ai function IsBattlerTrapped by @AlexOn1ine in #6438
  • Optimization / Clean up of AI move usability by @AlexOn1ine in #6332
  • Clean up AI code duplication and unify checks by @AlexOn1ine in #6348
  • Removed unused debug EWRAM variables by @hedara90 in #6468
  • Removes unused Special Status members by @AlexOn1ine in #6479
  • Remove potential pitfall with saved damage for recoil moves by @AlexOn1ine in #6485
  • Update maintainer list by @AsparagusEduardo in #6521
  • Alcremie Evolution clean up follow up by @AlexOn1ine in #6557
  • Ability access cleanup for #6550 by @Pawkkie in #6565
  • Fix broken links in merge_checklist.md by @pkmnsnfrn and @grintoul1 in #6570
  • Converts some defines to enums by @Bassoonian in #6592
  • Turn battle string ids into enums by @Bassoonian in #6594
  • Remove redundant bit for Throat Spray by @AlexOn1ine in #6593
  • Adjust enum AIScore by @AlexOn1ine in #6598
  • Add type checking for hold item effects by @Bassoonian in #6619
  • Adds move effect type checking by @Bassoonian in #6618
  • Remove hardcoded values from wild_encounter.h generation by @khbsd and @moostoet and @/Nopinou on discord for reporting bugs and dealing with my ping spam <3 in #6640
  • Sky Drop clean up and tests by @AlexOn1ine in #6218
  • Remove vestigial AdvanceScript function used for testing by @RubyRaven6 in #6664
  • Fix party access in NoAliveMonsForBattlerSide by @AlexOn1ine in #6677
  • Some Me First tests plus minor clean up by @AlexOn1ine in #6678
  • Removes vestigial EWRAM variable from debug menu. by @RubyRaven6 in #6686
  • Disable P_TUTOR_MOVES_ARRAY config by @PCG06 in #6693
    • P_TUTOR_MOVES_ARRAY set to FALSE by default.
  • Remove compressed palettes by @hedara90 in #6455
    • All handling for compressed palettes has been removed, use u16 * for palettes instead.
    • Has migration script to convert palettes to u16, struct SpritePalette and palette loading calls from their compressed variants.
  • Rename follower npc macros for better specificity and to match documentation by @Bivurnum in #6742
  • Use missing constants with GetBattlerSpriteCoord by @AsparagusEduardo in #6778
  • Use GetPartyBattlerData where appropiate by @AsparagusEduardo and @ghoulslash, @klemniops, whose’ code I was using for comparison when I found these in #6779
  • InitSpritePosToAnimAttacker documentation by @AsparagusEduardo and @ghoulslash, @klemniops, whose’ code I was using for comparison when I found these in #6781
  • General MoveEnd clean up and Fell Stinger adjustments by @AlexOn1ine in #6674
  • Better handling of battle coords by @AsparagusEduardo and @ghoulslash, @klemniops for the original code. in #6787
  • battle_main enum cleanup by @AsparagusEduardo and @ghoulslash, @klemniops, whose’ code I was using for comparison when I found these in #6788
  • Add missing uses of IsBattlerAlly by @AsparagusEduardo and @ghoulslash, @klemniops, whose’ code I was using for comparison when I found these in #6793
  • Rename GetPartyBattlerData to GetBattlerMon by @AsparagusEduardo and @ghoulslash, @klemniops, whose’ code I was using for comparison when I found these in #6800
  • Changed White Herb hold effect name by @AlexOn1ine in #6815
  • Fixes a mistake made by me by @AlexOn1ine in #6828
  • Remove non-existent functions from header files by @Bassoonian in #6825
  • Added IsOnPlayerSide by @AsparagusEduardo in #6832
  • Battle TV expansion by @AsparagusEduardo in #6826
  • Removed multiple instances of hardcoded move IDs by @AsparagusEduardo in #6856
  • Add prediction function by @AlexOn1ine in #6858
  • Reword move and ability descriptions to improve clarity by @jfb1337 in #6861
    • Updated move and ability descriptions to increase clarity.
  • Consolidated HasMoveFlagX functions by @AlexOn1ine in #6874
  • Optimized PokemonUseItemEffects function by @AsparagusEduardo in #6878
  • Fix misleading name by @AlexOn1ine in #6865
  • Debug menu cleanup by @AsparagusEduardo in #6881
  • Updated CONTRIBUTING.md and Merge Freeze definition by @pkmnsnfrn in #6952
  • Fix HasBattlerSideMoveWithEffect comment by @Pawkkie in #6965
  • Documented usage of createsprite gSlideMonToOffsetSpriteTemplate by @AsparagusEduardo in #6953
  • Remove trailing whitespace by @AsparagusEduardo in #6968
  • Moved time constants to dedicated files by @pkmnsnfrn in #7019

🧪 Test Runner 🧪

Added

  • “Aerilate”-esque Ability Tests and Config by @Pawkkie and @hedara90 in #6313
    • Adds new B_ATE_MULTIPLIER config in config/battle.h

Changed

  • Tests for checking all move animations by @hedara90 and @AsparagusEduardo wrote the original tests that I updated in #6297
    • Set T_SHOULD_RUN_MOVE_ANIM to TRUE to run these tests, they take a long time to run.
  • Update the All Move Animations test by @hedara90 in #6460
  • Updated move animation tests by @hedara90 in #6554

Fixed

  • Fix out-of-bounds in Heal Bell Cures Entire Party test by @rayrobdod in #7011

📚 Documentation 📚

  • Add CONTRIBUTING.md and STYLEGUIDE.md by @pkmnsnfrn and @Pawkkie, @garakmon in #6340
  • Update maintainer list by @AsparagusEduardo in #6521
  • Fix broken links in merge_checklist.md by @pkmnsnfrn and @grintoul1 in #6570
  • Turn battle string ids into enums by @Bassoonian in #6594
  • Add Time-Based Encounter Tutorial by @khbsd and @Pawkkie (ty for reviewing!!) in #6568
  • Add type checking for hold item effects by @Bassoonian in #6619
  • Adds move effect type checking by @Bassoonian in #6618
  • Make form change methods into enum + type checking by @Bassoonian in #6631
  • Add AI_FLAG_PP_STALL_PREVENTION to ai_flags.md by @Pawkkie in #6756
  • Document battler side in anim code by @AlexOn1ine in #6780
  • Added JSON as the preferred data format by @hedara90 in #6801
  • Commenting in config files to explain limits of map popups and wild AI flags by @surskitty in #6923
  • Documented usage of createsprite gSimplePaletteBlendSpriteTemplate by @AsparagusEduardo in #6956
  • Documented usage of createsprite gDirtPlumeSpriteTemplate by @AsparagusEduardo in #6954
  • Updated CONTRIBUTING.md and Merge Freeze definition by @pkmnsnfrn in #6952
  • Documented usage of createsprite gBasicHitSplatSpriteTemplate by @AsparagusEduardo in #6950
  • Documented usage of createsprite gSparkElectricitySpriteTemplate by @AsparagusEduardo in #6955
  • Beefing up the DNS tutorial for some of the common questions/errors. by @surskitty in #6922
  • Add follower NPC documentation by @Bivurnum in #6704
  • Clarifies when to use each merge type for maintainers by @pkmnsnfrn in #6999

📦 Branch Synchronisation 📦

pret

  • 27th of May, 2025 in #6995
    • Fix defines in MAP_NUM and MAP_GROUP by @Bassoonian in pret#2023
    • Change metatile behaviors to enum by @pkmnsnfrn in pret#2027
    • Move heal locations data to their associated map.json by @GriffinRichards in pret#2034
    • Generate local IDs from map.json files by @GriffinRichards in pret#2047
    • Generate MAPSEC constants from JSON by @GriffinRichards in pret#2063
    • Generate heal location constants automatically by @GriffinRichards in pret#2101
    • Update for Porymap 6 by @GriffinRichards in pret#2141
  • 29th of May, 2025 in #7012
    • Update for Porymap 6 by @GriffinRichards in pret#2141

New Contributors

  • @SundayMoonday made their first contribution in #6516
  • @agsmgmaster64 made their first contribution in #6559
  • @grintoul1 made their first contribution in #6567
  • @LinathanZel made their first contribution in #6834
  • @mudskipper13 made their first contribution in #6812

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.11.3...expansion/1.12.0

Version 1.11.4

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.11.4
`.

🐉 Pokémon 🐉

Fixed

  • Fixed CreateMon param order in CreateFacilityMon by @PCG06 in #6989
    • Fixed CreateMon param order in CreateFacilityMon.

⚔️ Battle General ⚔️

Fixed

  • Fix Eiscue not resetting back to Ice Face form after battle. by @DarkVexon in #6997
  • Fixes spread move fire types not defrosting all targets by @AlexOn1ine in #6998
  • Update Supersweet Syrup with eject pack fix by @AlexOn1ine in #7015
  • fix battle controller macros by @cawtds in #7021

🧪 Test Runner 🧪

Fixed

  • Fix out-of-bounds in Heal Bell Cures Entire Party test by @rayrobdod in #7011

📦 Branch Synchronisation 📦

pret

  • 27th of May, 2025 in #6995
    • Fix defines in MAP_NUM and MAP_GROUP by @Bassoonian in pret#2023
    • Change metatile behaviors to enum by @pkmnsnfrn in pret#2027
    • Move heal locations data to their associated map.json by @GriffinRichards in pret#2034
    • Generate local IDs from map.json files by @GriffinRichards in pret#2047
    • Generate MAPSEC constants from JSON by @GriffinRichards in pret#2063
    • Generate heal location constants automatically by @GriffinRichards in pret#2101
    • Update for Porymap 6 by @GriffinRichards in pret#2141
  • 29th of May, 2025 in #7012
    • Update for Porymap 6 by @GriffinRichards in pret#2141

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.11.3...expansion/1.11.4

Version 1.11.3

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.11.3
`.

🧬 General 🧬

Changed

  • Remove old slide workaround by @hedara90 in #6754
  • Changed github CI to use arm-none-eabi-gcc by @hedara90 in #6829
  • Add move description data for Z-Moves and Max/G-Max moves by @kittenchilly in #6852
  • Add CREDITS.md & FEATURES.md, rewrite README.md & INSTALL.md by @pkmnsnfrn in #6700
  • Fixed URL for contributors badge on README.md by @pkmnsnfrn in #6897
  • Fix typo in the readme by @Bassoonian in #6908
  • Cleanup identical if blocks by @malad1211 in #6988

Fixed

  • Add AUTO_GEN_TARGETS for .party files and map_groups_count, but on master by @hedara90 and @mrgriffin in #6824
  • Make make clean work again by @hedara90 in #6848
  • Fix trainers.party parser failing on apostrophes by @jfb1337 in #6938
  • Explicit -std=gnu17 in CPPFLAGS to mirror CFLAGS by @mrgriffin in #6839
  • Missed ItemId_GetDescription change by @AlexOn1ine in #6992

🐉 Pokémon 🐉

Changed

  • New Lurantis animation by @Cafeei in #6725
  • Added Egg Moves for Basculin White Striped by @PCG06 in #6769
    • Added Egg Moves for Basculin White Striped.
  • PokeCommunity sprites batch (April 2025) by @kittenchilly in #6840
  • Improve a few Gen 9 Pokemon sprites by @kittenchilly in #6885

Fixed

  • Fix rerolls overwriting Fixed Personality by @i0brendan0 in #6774

⚔️ Battle General ⚔️

Changed

  • Remove redundant script declaration in battle_scripts.h by @Bassoonian and @i0brendan0 in #6837
  • BattleScript_BerryStatRaiseRet Ripen checks berry and cleanup by @ghoulslash in #6835

Fixed

  • Bugfixes batch by @AlexOn1ine in #6750
  • Fix Life Orb inflicting self damage when using status moves (#6767) by @spindrift64 in #6773
  • Fixes Stomping Tantrum not boosting damage when missed due to Accuracy by @AlexOn1ine in #6762
  • Fixes Symbiosis not triggering when a weakness berry was consumed by @AlexOn1ine in #6782
  • Fix gems activating for moves that don’t deal type damage by @spindrift64 in #6789 (reverted in #6806)
  • Fix Iron Ball type effectiveness check by @spindrift64 in #6794
  • Toxic Spikes print whether the target is poisoned or badly poisoned by @spindrift64 in #6814
  • Fixes Berserk Gene infinite loop by @AlexOn1ine in #6813
  • Fixes restoretarget on empty stack when using G-Max Gravitas by @PhallenTree in #6827
  • Fixed double battles send out breaking by @cawtds in #6822
  • Fix potential bug in BattleScript_FriskActivates by @AlexOn1ine in #6850
  • Reverts wrongly done gem fix and renames struggle effect by @AlexOn1ine in #6806
  • add fail ptr arg to JumpIfMoveFailed, fix tryworryseed by @ghoulslash in #6925
  • Fixes Life Orb damage still happening after attacker was unable to at… by @AlexOn1ine in #6940
  • Fixes Dazzling abilities activating on all multi hit move hits by @AlexOn1ine in #6943
  • Fixes ate type being ignored after checking summary screen by @AlexOn1ine in #6888
  • Fixes Unnerve activation not limited to 1 per switch-in by @AlexOn1ine in #6960
  • Fixes checking wrong move’s Dynamic Move Type in Summary Screen by @PhallenTree in #6975
  • Fix Wish healing even if the target is Heal Blocked by @DarkVexon in #6979
    • Fixed Heal Block not applying to Wish moves that had already been used
  • Prankster block check was missng the IsStatusMove check by @AlexOn1ine in #6987

🤖 Battle AI 🤖

Fixed

  • Fixes ai moves being recorded without correct index by @AlexOn1ine in #6803
  • Fixes AI repeated use of weather set up moves by @AlexOn1ine in #6963
  • Fixes AI not seeing primal weather and partner absorbing abilities by @AlexOn1ine in #6936

🧹 Other Cleanup 🧹

  • Remove old slide workaround by @hedara90 in #6754
  • Remove redundant script declaration in battle_scripts.h by @Bassoonian and @i0brendan0 in #6837
  • BattleScript_BerryStatRaiseRet Ripen checks berry and cleanup by @ghoulslash in #6835
  • Consolidated stat-priority ability tests by @AsparagusEduardo in #6863
  • Fix typo in the readme by @Bassoonian in #6908
  • add fail ptr arg to JumpIfMoveFailed, fix tryworryseed by @ghoulslash in #6925
  • Rename AI test by @AlexOn1ine in #6977
  • Missed ItemId_GetDescription change by @AlexOn1ine in #6992
  • Cleanup identical if blocks by @malad1211 in #6988

🧪 Test Runner 🧪

Changed

  • Changed Tackle for Scratch in tests by @AsparagusEduardo and @Pawkkie, @PurrfectDoodle, @hedara90 in #6730
    • Tackle’s power varies too much across generations. When writing new tests, please use Scratch instead.
  • Adds RNG tags and tests for Moody and Starf Berry by @PhallenTree in #6718
  • A lot of tests by @hedara90 in #6734
  • Added Ability TODO tests - Volume B by @AsparagusEduardo in #6836
  • Consolidated stat-priority ability tests by @AsparagusEduardo in #6863
  • Create missing ability and move effect test files by @AsparagusEduardo in #6845
  • Fix KNOWN_FAILING Bestow tests by @AsparagusEduardo in #6947
  • Added check for gBattleStringsTable by @AsparagusEduardo in #6948
  • Rename AI test by @AlexOn1ine in #6977
  • Fix heal bell test, add sparkly swirl test by @ghoulslash in #6262

Fixed

  • Fix test not referencing AI_TRAINER_NAME by @Pawkkie in #6926
  • Backport #6712 Fix party data assignment by @Pawkkie in #6980

📚 Documentation 📚

  • Fixed URL for contributors badge on README.md by @pkmnsnfrn in #6897

📦 Branch Synchronisation 📦

pret

  • 2nd of May 2025 in #6752
    • Added missing include due to g++ changes by @hedara90 in pret#2131
  • 15th of May, 2025 in #6870
    • Identified task and sprite fields related to battle weather animations by @DavidJCobb in pret#2128
    • Battle link reverse-engineering by @DavidJCobb in pret#2125
    • InitSpritePosToAnimAttacker documentation by @AsparagusEduardo in pret#2132
    • Rename battlerId to battler for consistency by @AlexOn1ine in pret#2126
    • Replace: moveId -> move, moveIdx -> moveIndex by @AlexOn1ine in pret#2134
    • Add BattlerId enum and document by @AlexOn1ine in pret#2135
    • Remove files that should not have been committed in #2126 by @mrgriffin in pret#2136
  • 24th of May, 2025 in #6978
    • Warn on suspicious setvar usages by @mrgriffin in pret#2137
    • Streamline pointer notation by @Bassoonian in pret#2139
    • Fixes for C23 Support by @Kurausukun in pret#2138
    • Update header files to match source files by @Bassoonian in pret#2143
    • Correct C23 Checks by @Kurausukun in pret#2144
    • Rename ItemId_GetX to GetItemX by @AlexOn1ine in pret#2116
    • Remove files that were wrongly commited by @AlexOn1ine in pret#2146

New Contributors

  • @i0brendan0 made their first contribution in #6774
  • @allcontributors made their first contribution in #6896
  • @DarkVexon made their first contribution in #6979

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.11.2...expansion/1.11.3

Version 1.11.2

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.11.2
`.

🧬 General 🧬

Changed

  • 1.11.1 Release by @hedara90 in #6503
  • Add General Merge to label check by @hedara90 in #6512
  • Added AI switch display to the battle debug by @hedara90 in #6529
  • Consolidated “How to add Pokémon” tutorials by @AsparagusEduardo in #6541
  • Fixed Behemoth Blade/Bash handler not using form change tables by @AsparagusEduardo in #6558
  • Documentation by @hedara90 in #6576
  • Corrected Dexnav config related comment by @LOuroboros in #6610
  • Make generated files match the current formatting by @hedara90 in #6636

Fixed

  • Mark RTC/Flash save hint string as used by @aronson in #6507
  • Fix move names in learnset helper by @malad1211 in #6510
  • Fix no eligible mons when only the partner wins in multi battle by @Bivurnum in #6626
  • Fixed broken palette load for shiny followers in the sprite visualizer by @hedara90 in #6683
  • Fix FORM_CHANGE_ITEM_HOLD bug manifested during givemon by @AsparagusEduardo in #6702

🗺️ Overworld 🗺️

Fixed

  • Added call to ItemId_GetDescription by @pkmnsnfrn in #6582

🐉 Pokémon 🐉

Changed

  • Add clarification for EVO_SCRIPT_TRIGGER_DMG by @Bassoonian in #6579

Fixed

  • Capped Exp from Daycare to level cap by @hedara90 in #6622

⚔️ Battle General ⚔️

Changed

  • Fixes Thermal Exchange not curing existing burn by @PhallenTree in #6545
  • Add clarification for underlying math in EV caps by @Bassoonian and @i0brendan0 in #6580
  • Added missing gMovesInfo encapsulation by @AsparagusEduardo in #6656
  • Remove misleading comment by @AlexOn1ine in #6684

Fixed

  • Fixes Tera Type not being carried over to during form change / evolution by @AlexOn1ine in #6502
  • Fixes Hone Claws checking the wrong stats for its stat change animation and Stockpile drops being stopped by stat reduction prevention effects by @PhallenTree in #6522
  • Fixes Red Card against Dynamaxed mons by @AlexOn1ine in #6526
  • Fixes transformed mon being able to use tera on Terapagos by @AlexOn1ine in #6528
  • Fixes Will-O-Wisp not being blocked by Thermal Exchange by @AlexOn1ine in #6534
  • Add hold effects for PLA Origin Trio items by @Bassoonian in #6578
  • Ability imposter by @wiz1989 and @AlexOn1ine in #6552
  • Fixes Dynamax reversion animation when fainting by @PhallenTree in #6597
  • Fix potential compile error caused by sTeraIndicatorDataPtrs by @AlexOn1ine in #6599
  • Revert wrongly done Embody Aspect fix by @AlexOn1ine in #6607
  • Fixes wrong battler’s Illusion wearing off when the Attacker faints and fixes Illusion tests by @PhallenTree in #6596
  • Fixes Gulp Missile freezing the game if when attacker fainted by @AlexOn1ine in #6639
  • Fixes Big Root Leech Seed heal amount by @AlexOn1ine in #6638
  • Fix Mirror Armor and Obstruct interaction by @AlexOn1ine in #6630
  • Fixes some restore issues by @AlexOn1ine in #6629
  • Fixes Ally Switch cancelling partner’s moves targeting that side of the field by @PhallenTree and @hedara90 made the Ally Switch test in #6646 in #6647
  • Fixes commander activation on a fainted mon by @AlexOn1ine in #6632
  • Fix captivate-oblivious interaction and related test by @cawtds in #6653
  • Fix gBattlerTarget OOB for Gravity and Perish Song by @AlexOn1ine in #6662
  • Fixes Intimidate / Eject Pack interaction by @AlexOn1ine in #6645
  • Fixes Neutralizing Gas activating again after switch-in by @PhallenTree in #6667
  • Fixes Bug Bite eaten berry not ignoring Unnerve by @AlexOn1ine in #6666
  • Fixes Mirror Armor stat drops not being stopped by Substitute by @PhallenTree in #6675
  • Fixes Magician Life Orb interaction by @AlexOn1ine in #6676
  • Fixes Unburden doubling speed when affected by Neutralizing Gas by @PhallenTree in #6691
  • Fix various Toxic Spikes interactions by @hedara90 in #6690
  • Fixes Z and Max moves dmg reduction against side protection by @AlexOn1ine in #6697
  • Fixes Stomping Tantrum not doubling power if asleep or frozen by @AlexOn1ine in #6719

🤹 Moves 🤹

Fixed

  • Gimmick Indicator refactor by @hedara90 in #6553
    • This frees up a lot of VRAM in battles.
  • Animation fixes from lucky adapted to expansion by @hedara90 and @/luckytyphlosion in #6452
  • Fix Magma Storm getting stuck by @hedara90 in #6605
  • Fix VRAM load for Black Hole Eclipse by @hedara90 in #6635
  • Fixes some moves trying to load too much VRAM by @hedara90 in #6633

🧶 Items 🧶

Fixed

  • Fix using items to heal partner in battle by @hedara90 in #6517

🤖 Battle AI 🤖

Changed

  • Add AI thinking cycle count display to frame count by @aronson in #6509
  • Remove redundant AI defines by @Bassoonian in #6590

🧹 Other Cleanup 🧹

  • Added call to ItemId_GetDescription by @pkmnsnfrn in #6582
  • Remove redundant AI defines by @Bassoonian in #6590
  • Corrected Dexnav config related comment by @LOuroboros in #6610
  • Added missing gMovesInfo encapsulation by @AsparagusEduardo in #6656
  • Remove HitmarkerSwapAttackerTarget by @AlexOn1ine in #6627
  • Remove misleading comment by @AlexOn1ine in #6684

🧪 Test Runner 🧪

Changed

  • Support make check on macOS by @aronson in #6513
    • The new test runner binary will not support macOS versions older than 10.7 or 11 (for Intel and Apple Silicon respectively).
    • macOS users running make check may need to confirm with an OS dialog they’re willing to open mgba-rom-test-mac when run for the first time.
    • macOS users running make check must have stdbuf installed through brew’s coreutils package.
  • Thermal exchange tests by @hedara90 in #6536
  • Air Balloon AI tests by @Pawkkie in #6604
  • Big Root tests by @Bassoonian in #6601
  • Test for Freeze vs Scald thaw by @AlexOn1ine in #6658
  • Adds a whole bunch of new tests by @Bassoonian in #6685

Fixed

  • Fixed Color Change test referring to the wrong mon by @hedara90 in #6644
  • Fixed LGPE move test fail with B_UPDATED_MOVE_DATA to GEN_7 by @AsparagusEduardo in #6657
  • Use correct define for moves in test runner by @AsparagusEduardo in #6711

📚 Documentation 📚

  • Consolidated “How to add Pokémon” tutorials by @AsparagusEduardo in #6541
  • Documentation by @hedara90 in #6576
  • Add clarification for underlying math in EV caps by @Bassoonian and @i0brendan0 in #6580
  • Add clarification for EVO_SCRIPT_TRIGGER_DMG by @Bassoonian in #6579

📦 Branch Synchronisation 📦

pret

  • 11 of April in #6575
    • Align gMPlayTrack_BGM by @DizzyEggg in pret#2115
    • GENDER_COUNT in sPlayer/RivalAvatarGfxIds by @AsparagusEduardo in pret#2117
    • Fixed init call when using AGBPrint as log handler by @pokemonmasteraaron in pret#2119
    • Make linkDirection more robust to member reordering by @cawtds in pret#2118
  • 29th of April 2025 in #6722
    • Rename battle terrain to environment by @Bassoonian in pret#2014
    • Fixes for Mirage Tower graphics by @GriffinRichards in pret#2120
    • Missing constant in Birch speech dialogue by @estellarc in pret#2123

New Contributors

  • @malad1211 made their first contribution in #6510

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.11.1...expansion/1.11.2

Version 1.11.1

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.11.1
`.

🧬 General 🧬

Added

  • Added workflow for labels check by @hedara90 in #6488

Changed

  • metaprogram.h without global.h by @mrgriffin in #6469
  • Rename removelishtscreenreflect to removescreens by @AlexOn1ine in #6495

Fixed

  • Fix Melmetal’s weight by @kittenchilly in #6382
  • B_FAST_INTRO_PKMN_TEXT fix by @hedara90 in #6395
  • remove/replace IsAlly leftovers by @cawtds in #6399
  • Increase dex no digits from 3 to 4 by @PCG06 in #6484

🗺️ Overworld 🗺️

Changed

  • Replace Incorrect Slow Stairs Movement with Correct One by @Deokishisu in #6275

Fixed

  • Fix compile errors with OW_BATTLE_ONLY_FORMS set to FALSE by @hedara90 in #6400
  • Include Missed GetInteractedMetatileScript Entries for Mart & Center Signs by @Deokishisu in #6269
  • Fix DexNav search level by @cawtds in #6421
  • Hide in-battle types from Union Room trade request by @aronson in #6489

🐉 Pokémon 🐉

Fixed

  • Fixed Zacian/Zamazenta learning Iron head while already knowing by @hedara90, @wiz1989 reported the issue, in #6365
  • Fix roamers having 0 hp on repeat encounters by @danaYatsuta in #6366
  • Fixed unfusion of traded materials by @hedara90, @mrgriffin found the issue, in #6415

⚔️ Battle General ⚔️

Changed

  • Fix Red Card overwriting gBattlerAttacker by @ghoulslash in #6376
  • Fixes Magic Coat message when move is bounced back by @AlexOn1ine in #6419

Fixed

  • Reorder Dancer activation by @PhallenTree in #6379
  • Fixes crash damage move against absorbing abilities by @AlexOn1ine in #6361
  • Fixes gimmick icon flying off the screen by @PhallenTree in #6401
  • Fixed Parental Bond with two-turn attacks by @hedara90 in #6408
  • Wrong argument usage in CalcCritChanceStage by @AlexOn1ine in #6429
  • Fixes Neutralizing Gas Exits, Weather Abilities and Terrain Effects order by @PhallenTree in #6435
  • Fixes hazards not respecting tera types by @AlexOn1ine in #6431
  • Fixes dynamax reversion when ejected out + anim fix by @AlexOn1ine in #6416
  • Fixes negative priority being blocked by dazzling abilities by @AlexOn1ine in #6433
  • Fixes Cotton Spore failing if one of the targets blocks it by @AlexOn1ine in #6418
  • Fixes Toxic Spikes Absorbed message by @PhallenTree in #6448
  • Fixes Cheek Pouch mutating damage by @AlexOn1ine in #6466
  • Fixes choice move locking at the wrong time by @AlexOn1ine in #6467
  • Fixes protective pads against Protects secondary effects by @AlexOn1ine in #6474
  • Fixes clear body type effect and clear amulet against protect effects by @AlexOn1ine in #6482
  • Fixes Aftermath ability popup message by @AlexOn1ine in #6491
  • Fixes Emergency Exit and Eject Pack by @AlexOn1ine in #6459
  • Fixes Hospitality not being blocked by Heal Block by @AlexOn1ine in #6494
  • Fixes timesGotHit not increasing on forced switch out by @AlexOn1ine in #6493
  • Fixes Destiny Bond against Dynamax no failing by @AlexOn1ine in #6501

🤹 Moves 🤹

Fixed

  • Fixed Ivy Cudgel types with type changes by @hedara90 in #6369
  • Adds move description battle config by @AlexOn1ine in #6364
  • Fix Jet Punch in isolated tests by @hedara90 in #6461
  • Sucker punch vs struggle by @hedara90 in #6475

🤖 Battle AI 🤖

Changed

  • Update Battle Debug menu with new AI flags by @kittenchilly in #6444

Fixed

  • Fixed AI_FLAG_CHECK_VIABILITY changing the toxic counter in some cases by @hedara90, @iriv24 discovered the issue, in #6402
  • Fix Focus Sash being considered in switch AI’s hits to KO calcs by @Pawkkie in #6436
  • AI gimmick check changed from checking trainer data to a BattleStruct field by @hedara90 in #6478
  • Fix hit escape ace mon switching by @Pawkkie and @wiz1989, @AlexOn1ine in #6498

🧹 Other Cleanup 🧹

  • Update AI_TryTo2HKO comment by @Pawkkie in #6349
  • Fixing grammar of Berry Tree strings by @surskitty in #6355
    • Berry trees berries are no longer erroneously plural.
  • Move category test cleanup by @hedara90 in #6447
  • Fixes Magic Coat message when move is bounced back by @AlexOn1ine in #6419
  • Update Battle Debug menu with new AI flags by @kittenchilly in #6444
  • Rename removelishtscreenreflect to removescreens by @AlexOn1ine in #6495

🧪 Test Runner 🧪

Changed

  • Fix Red Card overwriting gBattlerAttacker by @ghoulslash in #6376
  • Move category test cleanup by @hedara90 in #6447
  • Changed KNOWN_FAILING test by @hedara90 in #6492

Fixed

  • Fixes Known Failing Mold Breaker Sleep Clause test by @PhallenTree in #6434
  • Made memory integrity checks run betweeen PARAMETRIZE runs by @hedara90 and @mrgriffin in #6462

📚 Documentation 📚

  • Fixed a missing ) in trainers.party comment block. by @RubyRaven6 in #6367
  • Update README.md for contest src link by @lwelyk in #6375

New Contributors

  • @RubyRaven6 made their first contribution in #6367
  • @lwelyk made their first contribution in #6375
  • @danaYatsuta made their first contribution in #6366

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.11.0...expansion/1.11.1

Version 1.11.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH test
`.

🌋 REFACTORS 🌋

📜 = Uses a migration script.

  • Pursuit refactor by @PhallenTree in #5707
  • Atk Canceller refactor / reorder / clean up by @AlexOn1ine in #5885
  • Battle Weather Refactor by @AlexOn1ine in #5833
  • Replace WEATHER_HAS_EFFECT with HasWeatherEffect by @AlexOn1ine in #6069
  • Cleaned up Trainer Slides, added automated Trainer Slide tests, add new Enemy Critical Hit Slide by @pkmnsnfrn and @AlexOn1ine, @hedara90, @AsparagusEduardo, @mrgriffin in #6018
    • If users created new entries in sTrainerSlides, they will need to be ported to the new system.
  • Introduces BattleTurnCounter to simplify timer checks by @AlexOn1ine in #6080
  • Convert max effects to normal move effects by @AlexOn1ine in #6143
  • Redefine IsBattlerAlive in battle.h as a static inline by @AlexOn1ine in #6211
  • Consolidated Frontier teams into battle_frontier_trainers.h by @fdeblasio in #5892

🧬 General 🧬

Added

  • Add Script Cmd for Forcing Save Game by @ghoulslash in #6090
  • Trainer Party Pools by @hedara90 in #5731
    • Documentation on how to use this can be found under docs/tutorials/how_to_trainer_party_pool.md
  • Add Code Entry functionality by @Pawkkie and @PCG06 for the Mystery Gift iteration in #5951

Changed

  • Added “Game Clear” flag toggle to debug menu by @AsparagusEduardo in #5929
  • Initialize m4a and IRQ handler in a loaded section by @SBird1337 in #5912
  • Debug menu and createmon additions/cleanup by @AsparagusEduardo in #5994
    • Added Tera Type, Dynamax Level, and Gigantamax Factor to the “Give Pokémon (complex)” debug menu option.
    • Added dmaxLevel option to givemon and createmon.
    • Added WEATHER_COUNT.
    • Cleaned up repeated code instances in debug menu.
    • Fixed mislabel of ggMaxFactor in givemon and createmon. Now it’s gmaxFactor.
  • Introduces BattlerState struct for the Battle Engine by @AlexOn1ine and @mrgriffin provided the framework for this change in #5954
  • Reorder Makefile rules so that pokeemerald-test.elf builds in build/test by @mrgriffin in #6004
  • Use SET8 and SET32 consistently by @AZero13 in #5544
  • Ewram and unused function cleanup sweep by @hedara90 in #6019
  • Re-removed trainers.h trailing whitespace by @fdeblasio in #6048
  • Add Steven Multi to debug menu by @Pawkkie in #6064
  • Remove gDecompressionBuffer by @DizzyEggg in #6029
  • Trainer Battle Parameter Consolidation by @u8-Salem in #5982 Breaking: raw uses of trainerbattle need to be adjusted to provide all possible parameter. Unused parameter musst be 0 or an alias. already parameterized macros like trainerbattle_single work out of the box.
  • Consolidated contest opponent filters into gContestOpponents by @fdeblasio in #6119
  • Don’t use SeedRng some places where it isn’t necessary by @tertu-m in #6156
  • Removed Trainer Slides footgun by @AsparagusEduardo in #6205
  • Consolidate duplicate dialogue of nature girl in Battle Frontier by @fdeblasio in #6195
  • Prevented fanfares from playing in headless mode by @pkmnsnfrn and @hedara90, @AsparagusEduardo in #6219

Fixed

  • Don’t write to NULL in TryFindHiddenPokemon by @DizzyEggg in #5983
  • Allow Party Menu with 0 Pokemon by @DizzyEggg in #5997
  • Revert map related enum conversion by @hedara90 in #6078
  • Revert “Revert map related enum conversion” by @hedara90 in #6079
  • Revert “Converts a bunch of defines to enums” by @Bassoonian in #6082
  • Fix upcoming not working on no cash by @DizzyEggg in #6121
  • Add the header required for TPP tags to work by @hedara90 in #6162
  • Fixed regression from master/upcoming merge by @AsparagusEduardo and @hedara90 , for doing the original merge when I couldn’t in #6199
  • Fix Using a Safari Ball crashes the game #6206 by @ExMingYan in #6220
  • Fixed typo in requests_effects by @hedara90 and @purrfectdoodle in #6215
  • Try a new solution to Fix Safari #6206 by @ExMingYan in #6228
  • Remove obsolete check for steven when retrieving partner name by @u8-Salem and @hedara90 in #6283
  • Fix spit up getting skipped by @cawtds in #6295

🗺️ Overworld 🗺️

Added

  • Adds Dexnav by @ghoulslash in #4818
  • Fly from Pokenav by @khbsd in #5679
  • Expanded Pokémon Follower transformation functionality by @AsparagusEduardo in #5048

Changed

  • Arbitrary trainer scripts + on frame/trigger softlock prevention by @mrgriffin in #5033
  • Removed OW_AUTO_SIGNPOST by @pkmnsnfrn in #5974
  • Fix leftover test change from #5033 by @mrgriffin in #5987
  • Match current gen behavior for battle environment after fishing by @kittenchilly in #6099
  • Add Mega Evolution, Primal Reversion, and Ultra Necrozma overworld sprites by @khbsd in #5874
  • Replaced hardcoded numbers in DexNav with variables by @fdeblasio in #6241
  • Merrp merge (12th of February) by @hedara90 in #6244
  • Adds a follower flag define to disable followers on the fly by @AlexOn1ine in #6174

Fixed

  • Fix Trainer Hill OOB array access by @SBird1337 in #5930
  • Revert #5033 change to MapHeaderRunScriptType by @mrgriffin in #5975
  • Restore lock/lockall/locktrainer/release/releaseall in triggers by @mrgriffin in #5976
  • Follower Object Event refactor by @hedara90 and @AsparagusEduardo in #6129
    • Fixes OBJ_EVENT_GFX_SPECIES_SHINY
    • Adds OBJ_EVENT_GFX_SPECIES_FEMALE and OBJ_EVENT_GFX_SPECIES_SHINY_FEMALE
  • Fixes Static Assert from pr #6174 by @AlexOn1ine in #6258
  • Fixed Kecleon Shiny palette by @hedara90 in #6298

🐉 Pokémon 🐉

Added

  • IV/EV Info on Summary Screen by @khbsd in #6027
  • Add caught mon to full party by sending a different mon to the Box by @fakuzatsu in #6058

Changed

  • Remove form change function footguns by @AsparagusEduardo and @AlexOn1ine for letting me know of this potential issue. in #5995
    • GetBattleFormChangeTargetSpecies, GetFormChangeTargetSpecies and GetFormChangeTargetSpeciesBoxMon now return the current species of the Pokémon instead of SPECIES_NONE as a precaution to avoid accidental deletions of Pokémon when using these functions.
  • Remove redundant calls to GetMonData in pokemon.c by @AZero13 in #5545
  • Rename Furfrou Species tags to match Pokemon Showdown exports by @moostoet in #6041
  • Add Mega Evolution, Primal Reversion, and Ultra Necrozma overworld sprites by @khbsd in #5874
  • Add Poltchageist family form data by @Bassoonian and @wiz1989 in #6163

Fixed

  • Evolution level 1 learn by @hedara90 in #5791
  • Fixed non-regional forms breeding incorrectly by @AsparagusEduardo and @cawtds in #4985
  • Fixed compilation error when turning P_GENDER_DIFFERENCES off by @AsparagusEduardo in #6223
  • Reverted compound literal OW mon pic tables by @AsparagusEduardo in #6216

⚔️ Battle General ⚔️

Added

  • Add B_FLAG_SLEEP_CLAUSE by @Pawkkie, @Pawkkie and @iriv24 in #5566
  • Variadic IS_BATTLER_OF_TYPE and GetBattlerTypes by @mrgriffin in #5708
  • Simultaneous HP Reduction (CFRU Port) by @AsparagusEduardo and @AlexOn1ine for the port to expansion. @Skeli789 for the CFRU implementation. in #5770
  • Destiny Bond fails on repeated use in Gen 7+ by @Pawkkie in #5652
  • Adds Pledge Side Statuses as Starting Statuses by @AlexOn1ine in #5899
  • Adds B_VAR_DIFFICULTY and related functions READ DESC by @pkmnsnfrn in #5337
  • Config for move slot rearrangement in battle by @hedara90 and @ghoulslash for pointing out the exact point in the code where move slot rearrangement is handled. in #6017
    • Move slot rearrangement is disabled by default in battle, set B_MOVE_REARRANGEMENT_IN_BATTLE to GEN_3 to enable rearrangement again.

Changed

  • Sleep Clause global config by @Pawkkie in #5762
  • Pursuit refactor by @PhallenTree in #5707
  • Changes Various defines to an Enum by @AlexOn1ine in #5839
  • move overwrittenAbilities field to DisableStruct by @ghoulslash in #5946
  • Battle Weather Refactor by @AlexOn1ine in #5833
  • Easy customizable Hidden Move types by @AsparagusEduardo in #5872
    • gTypesInfo now has a isHiddenPowerType field that inserts them into the Hidden Power type calculation.
    • Warning: Changing this from the vanilla settings will change any existing Hidden Power’s type, and external calculators will not work either.
  • Introduces BattlerState struct for the Battle Engine by @AlexOn1ine and @mrgriffin provided the framework for this change in #5954
  • Cleaned up Trainer Slides, added automated Trainer Slide tests, add new Enemy Critical Hit Slide by @pkmnsnfrn and @AlexOn1ine, @hedara90, @AsparagusEduardo, @mrgriffin in #6018
    • If users created new entries in sTrainerSlides, they will need to be ported to the new system.
  • Introduces BattleTurnCounter to simplfy timer checks by @AlexOn1ine in #6080
  • Replace BattleStruct members quickClawRandom/quickDrawRandom with locals by @AlexOn1ine in #6136
  • Added Difficulty Fallback for Trainer Slides by @pkmnsnfrn in #6088
  • CanAbilityX Function Cleanup by @ghoulslash in #6183
  • Unify setreflect/setlightscreen and MOVE_EFFECT_REFLECT/LIGHT_SCREEN by @ghoulslash in #6196

Fixed

  • Fix Sleep Clause AI handling of partner sleeping moves by @Pawkkie in #5761
  • Fix fixed point damage calculation off-by-1s by @SBird1337 in #5775 Fixes a bunch of rounding errors that cause wrong outputs in the damage calculation.
  • Fixes simu hp reduction when no partner was on field by @AlexOn1ine in #5799
  • Fixes Regenerator healing past maxHP by @PhallenTree in #5861
  • Fixes Pursuit + Emergency Exit causing double switches and Pursuit user fainting causing target to not finish switch by @PhallenTree in #5849
  • Fixes regression caused by argument refactor by @AlexOn1ine in #5870
  • Fixes Sparkling Aria Shield Dust / Covert Cloak interaction by @AlexOn1ine in #5911
  • Battle Weather Refactor oversight by @AlexOn1ine in #5960
  • Shell Bell Clean up / Simplification and Tests by @AlexOn1ine in #5924
  • Dynamic move type was ignored in doubles for spread moves by @AlexOn1ine in #5984
  • Fixes self effect moves not procing for spread moves when battler 3 w… by @AlexOn1ine in #6020
  • Fix UB when accessing move result flags by @cawtds in #6030
  • Fix Powder (status) config and some terrain timers not using gBattleTurnCounter by @PhallenTree in #6109
  • Fix Powder config not checking for Powder status by @PhallenTree in #6113
  • Fixes battler mutation during the intim script by @AlexOn1ine in #6151
  • Fixes Dynamic Moves types in SumScreen while in Battle by @AlexOn1ine in #6145
  • Fixes Dragon Tail missing timing against Rocky Helmet / Iron Barbs by @AlexOn1ine in #6154
  • Prevent sameMoveTurns from incrementing when unable to use move by @moostoet in #6167
  • Fixes Suction Cups ability popup and Red Card + Guard Dog interaction by @PhallenTree in #6171
  • Fixed Unnerve message and wrote tests by @hedara90 in #6192
  • Fixes Spectral Thief stealing boost at the wrong time by @AlexOn1ine in #6197
  • Fixes BATTLER_TURN_DAMAGED battler id by @AlexOn1ine in #6236
  • Fixed multi battle forced switches by @hedara90 in #6243
  • Fixes ability Embody Aspect triggering multiple times by @AlexOn1ine in #6259
  • Fixes Called moves ignoring redirection by @PhallenTree in #6267
  • Fixes Protean not restoring types after ai damage calcs by @AlexOn1ine in #6280
  • Restoretarget in Rototiller script + Tests by @AlexOn1ine in #6296
  • Fixes inconsistency for Kings rock. by @AlexOn1ine in #6302
  • Fixes Shell Bell for Spread Moves by @AlexOn1ine in #6303
  • Fixes Brick Break/Psychic Fangs/Raging Bull breaking screens if target is immune by @PhallenTree in #6308
  • Fixes doesnt effect message for Thunder Wave by @AlexOn1ine in #6304
  • Fixes Tera Shell activating on moves that have no effect on target by @AlexOn1ine in #6271
  • Fixes fainted battler being able to select an action by @PhallenTree in #6339

🤹 Moves 🤹

Added

  • Added missing in-battle “Move Info” button prompt by @AsparagusEduardo and @TeamAquasHideout from who I got the source from and @BelialClover from who Archie got the source from. in #6155

Changed

  • New Volt Switch Animation by @AlexOn1ine in #5729
  • Refactors argument into a union by @AlexOn1ine in #5853
  • Encapsulate move data by @AsparagusEduardo in #5852
  • Removes Resource Flags and moves fields to DisableStruct by @AlexOn1ine in #5945
  • Tera starstorm by @hedara90 in #6073
  • Tachyon Cutter and Salt Cure animations by @hedara90 in #6182
  • Heal Bell/Aromatherapy/Sparkly Swirl improvements and fixes by @AsparagusEduardo in #6210
    • Removed EFFECT_SPARKLY_SWIRL in favor of MOVE_EFFECT_AROMATHEROPY.
  • Moved sValidApprenticeMove into gMovesInfo by @fdeblasio in #6254
  • Fixes non-Ghost type Curse animation by @PhallenTree in #6299
  • Remove pursuitSwitchByMove and additional if statement by @PhallenTree in #6326

Fixed

  • Fixes moves based on Dragon Darts with strikeCount > 2 always hitting the same battler from the second hit onwards by @PhallenTree in #5830
  • Last fix for Sparkling Aria / Covert Cloak / Shield Dust interaction by @AlexOn1ine in #5956
  • Added WEATHER_DOWNPOUR to Weather Ball’s dynamic type by @fdeblasio in #6100
  • Fixed Future Sight not being affected by Electrify by @AsparagusEduardo in #6213
  • Fixes Expanding Force and Spectral Thief move animations by @PhallenTree in #6185
  • Made some move animations fit in VRAM by @hedara90 in #6289

🧶 Items 🧶

Fixed

  • Adds missing Friend Ball friendship bonus upon catching by @PhallenTree in #5795

🤖 Battle AI 🤖

Added

  • Smart Switching handles Soundproof by @Pawkkie and @Robdeezy for the idea! in #5703
  • Add Revival Blessing AI by @Pawkkie in #5704
  • Add AI_FLAG_WEIGH_ABILITY_PREDICTION by @Pawkkie and @khbsd and @ghoulslash for the idea, @AlexOn1ine and @mrgriffin for getting it working :) in #5636
  • Add AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE by @Pawkkie in #6025
  • Add AI_FLAG_PREDICT_SWITCH by @Pawkkie and @kithr1 in #6028
  • Add AI_FLAG_PREDICT_INCOMING_MON: AI will score against predicted switchin if predicting switch by @Pawkkie in #6037
  • Switch trapping AI will consider Trace by @Pawkkie in #6059
  • AI adds score to Pursuit if it OHKOs by @Pawkkie in #6166
  • Switch chance config support by @Pawkkie in #6187
    • Config can be changed in config/ai.h
  • Add function to adjust AI scoring for generalized item effects by @moostoet and @AlexOn1ine and @Pawkkie for the input on slight changes to make to the logic (config, no magic numbers…) in #6247

Changed

  • Fixed AI not handling type effectiveness beyond x8 by @AsparagusEduardo and @/sshadowzkmao in #6127
    • Removed the use of AI_EFFECTIVENESS_ in favor of storing the actual type effectiveness.
    • Renamed AI_GetTypeEffectiveness to AI_GetMoveEffectiveness, removing the original one.
  • Remove global sBattler_AI by @AlexOn1ine in #6128
  • SwitchType enum to clean up GetMostSuitableMonToSwitchInto by @Pawkkie in #6184

Fixed

  • Eject item ace flag switch AI fixes by @Pawkkie and @wiz1989 for reporting the bug in #6098
  • Fix Choice’d mons referring to incorrect move when switching by @Pawkkie and @/capncrunch in #6204
  • Fix AI switching in absorbing mon incorrectly by @Pawkkie in #6227
  • Improve Yawn and Status Switching by @Pawkkie and @/Chape for finding this behaviour in #6202
  • Fix AI wrongly thinking it strikes first with priority even if player is using priority themselves by @moostoet in #6274
  • Fix AI hazard move handling, minor AI tweaks by @Pawkkie and @ShadowzLmao2 in #6311
  • Fix Overzealous Absorber Switching by @Pawkkie and @iriv24 and @ravepossum for squinting at a conditional for nearly 30mins with me to find a semicolon in #6318
  • Fix Substitute / Shed Tail Switch AI by @Pawkkie in #6334

🧹 Other Cleanup 🧹

  • Split “Do nothing” move effects by @AsparagusEduardo in #5613
  • Sleep Clause global config by @Pawkkie in #5762
  • Converts multi-choice options to COMPOUND_STRINGs by @fdeblasio in #5686
  • Converted item-related variables to COMPOUND_STRINGs by @fdeblasio in #5714
  • Adds SleepClauseBlock enum to CanBeSlept by @Pawkkie and @AlexOn1ine in #5773
  • Swapped DESELECT and CHECK_TAG to be in right places by @fdeblasio in #5794
  • Changes target TURN_DAMAGED and MAX_HP to inlines by @AlexOn1ine in #5822
  • Changes Various defines to an Enum by @AlexOn1ine in #5839
  • Remove fno-toplevel-reorder by @DizzyEggg in #5809
  • Refactors argument into a union by @AlexOn1ine in #5853
  • Clean up redundancy for mugshots by @AlexOn1ine in #5906
  • Encapsulate move data by @AsparagusEduardo in #5852
  • Initialize m4a and IRQ handler in a loaded section by @SBird1337 in #5912
  • Remove EWRAM gHpDealt (not needed anymore) by @AlexOn1ine in #5925
  • Fix DexNav static asserts by @Bassoonian in #5944
  • Move overwrittenAbilities field to DisableStruct by @ghoulslash in #5946
  • Converted 2 various to callnative by @AsparagusEduardo in #5950
    • Removed VARIOUS_SWAP_SIDE_STATUSES and VARIOUS_SWAP_STATS.
  • Shell Bell Clean up / Simplification and Tests by @AlexOn1ine in #5924
  • Removed OW_AUTO_SIGNPOST by @pkmnsnfrn, @doejohn126 discovered the issue in #5974
  • Fix leftover test change from #5033 by @mrgriffin in #5987
  • Multiple removals of hardcoded move IDs by @AsparagusEduardo in #5964
  • Missed two uses of new hazard type enum by @Pawkkie in #5996
  • Debug menu and createmon additions/cleanup by @AsparagusEduardo in #5994
    • Added Tera Type, Dynamax Level, and Gigantamax Factor to the “Give Pokémon (complex)” debug menu option.
    • Added dmaxLevel option to givemon and createmon.
    • Added WEATHER_COUNT.
    • Cleaned up repeated code instances in debug menu.
    • Fixed mislabel of ggMaxFactor in givemon and createmon. Now it’s gmaxFactor.
  • Free some IWRAM by @DizzyEggg in #6000
  • Removes Resource Flags and moves fields to DisableStruct by @AlexOn1ine in #5945
  • Future Sight Innards Out follow up for upcoming by @AlexOn1ine in #5998
  • Remove redundant calls to GetMonData in pokemon.c by @AZero13 in #5545
  • Use SET8 and SET32 consistently by @AZero13 in #5544
  • Rename Furfrou Species tags to match Pokemon Showdown exports by @moostoet in #6041
  • Rename DexNav flags and vars by @Bassoonian in #6044
  • Re-removed trainers.h trailing whitespace by @fdeblasio in #6048
  • Moved front animations frames to gSpeciesInfo by @AsparagusEduardo in #5605
  • Clean up array access by using index instead of dereferencing the value by @AlexOn1ine in #6057
  • Add a uniquely striking pair of brackets by @Pawkkie in #6068
  • Replace WEATHER_HAS_EFFECT with HasWeatherEffect by @AlexOn1ine in #6069
  • Converts a bunch of defines to enums by @Bassoonian in #6071
    • Replaced BATTLE_TERRAIN #defines with the BattleTerrain enum
    • Replaced MAP_TYPE #defines with the MapType enum
    • Replaced MAP_BATTLE_SCENE #defines with the MapBattleScene enum
    • Replaced BACK_ANIM #defines with the BackAnim enum
    • Replaced ANIM #defines with the AnimFunctionIDs enum
    • Replaced INGAME_TRADE #defines with the InGameTradeID enum
    • Replaced TRAINER_CLASS #defines with the TRAINER_CLASS enum
  • Return the universe to a state of balanced quilibrium by @Pawkkie in #6074
  • Cleaned up Debug Menu by @AsparagusEduardo in #6070
  • Remove gDecompressionBuffer by @DizzyEggg in #6029
  • Cleaned up Trainer Slides, added automated Trainer Slide tests, add new Enemy Critical Hit Slide by @pkmnsnfrn and @AlexOn1ine, @hedara90, @AsparagusEduardo, @mrgriffin in #6018
    • If users created new entries in sTrainerSlides, they will need to be ported to the new system.
  • Terrain function standarization by @fdeblasio in #6097
  • Updated trainer pic tutorial by @fdeblasio in #6049
  • Remove UnusedBattleInit from battle_bg.c by @DizzyEggg in #6116
  • Consolidated contest opponent filters into gContestOpponents by @fdeblasio in #6119
  • Replace BattleStruct members quickClawRandom/quickDrawRandom with locals by @AlexOn1ine in #6136
  • Updated Trainer Ids used in Trainer Slides tests by @pkmnsnfrn and @AlexOn1ine found the original bug, @AsparagusEduardo confirmed it in #6138
  • Added Difficulty Fallback for Trainer Slides by @pkmnsnfrn in #6088
  • Clean up follow up for Simultaneous Reduction HP by @AlexOn1ine in #6139
  • Remove global sBattler_AI by @AlexOn1ine in #6128
  • Clarify MOVE_EFFECT_SLEEP sleep clause handling by @Pawkkie in #6161
  • Remove unused PainSplit scripting global by @AlexOn1ine in #6164
  • Don’t use SeedRng some places where it isn’t necessary by @tertu-m in #6156
  • Cleaned up party data access GetPartyBattlerData by @AsparagusEduardo in #6172
  • Changed two LocalRandom calls to new LocalRandom32 by @hedara90 in #6173
  • Cleanup some global battler ID usage by @ghoulslash in #6181
  • Clean up - Add ability args instead of calcing the ability again by @AlexOn1ine in #6186
  • CanAbilityX Function Cleanup by @ghoulslash in #6183
  • SwitchType enum to clean up GetMostSuitableMonToSwitchInto by @Pawkkie in #6184
  • Unify setreflect/setlightscreen and MOVE_EFFECT_REFLECT/LIGHT_SCREEN by @ghoulslash in #6196
  • Removed Trainer Slides footgun by @AsparagusEduardo in #6205
  • Fix typo in Nuzzle’s description by @Bassoonian in #6209
  • Consolidate duplicate dialogue of nature girl in Battle Frontier by @fdeblasio in #6195
  • Fixed missing move encapsulation in upcoming by @AsparagusEduardo in #6226
  • Consolidated Frontier teams into battle_frontier_trainers.h by @fdeblasio in #5892
  • Add abstraction layer for battler positions by @AlexOn1ine in #6212
  • Revert unintentional change by @AlexOn1ine in #6239
  • Remove whitespace from trainers data file by @AsparagusEduardo in #6234
  • Replaced hardcoded numbers in DexNav with variables by @fdeblasio in #6241
  • fix for battle ui for add to party menu (#6229) by @fakuzatsu in #6240
  • Changed bit order for follower graphicsId creation by @hedara90 in #6249
  • Minor Clean up for CanAbilityX. Follow up for #6183 by @AlexOn1ine in #6252
  • Moved sValidApprenticeMove into gMovesInfo by @fdeblasio in #6254
  • Use more accurate count in MovesInfo by @AlexOn1ine in #6260
  • Fix Extra task->tState++ and break in Task_DrawFieldMessageBox by @Deokishisu in #6261
  • Expand usage of IsBattlerAlly (rename from IsAlly) by @AlexOn1ine in #6251
  • Rename SetPhotonGeyser to a more general use and clean up by @AlexOn1ine in #6272
  • Fix padding amount in MoveInfo by @AlexOn1ine in #6307
  • Refactor testing flags and vars to not conflict with user ones by @hedara90 in #6301
  • Clean up leftover from simu hp reduction development by @AlexOn1ine in #6323
  • Remove pursuitSwitchByMove and additional if statement by @PhallenTree in #6326

🧪 Test Runner 🧪

Changed

  • New Ally Switch test fails on CI by @AlexOn1ine in #5896
  • Added final Sparkling Aria+Shield Dust interaction test by @hedara90 in #5923
  • Converted 2 various to callnative by @AsparagusEduardo in #5950
    • Removed VARIOUS_SWAP_SIDE_STATUSES and VARIOUS_SWAP_STATS.
  • Cleaned up Trainer Slides, added automated Trainer Slide tests, add new Enemy Critical Hit Slide by @pkmnsnfrn and @AlexOn1ine, @hedara90, @AsparagusEduardo, @mrgriffin in #6018
    • If users created new entries in sTrainerSlides, they will need to be ported to the new system.
  • Tests for Big Pecks by @hedara90 in #6158
  • Water Compaction tests by @hedara90 in #6159
  • Wrote tests for Electrify by @hedara90 in #6179
  • Sheer Force Test Fixes by @ghoulslash in #6198
  • Minor Terrain Seed Test Improvement by @ghoulslash in #6207
  • Fix Liquid Ooze + Leech Seed Test by @ghoulslash in #6217
  • Prevented fanfares from playing in headless mode by @pkmnsnfrn and @hedara90, @AsparagusEduardo in #6219
  • Added test support for 5 battle configs by @AsparagusEduardo in #5914
  • Added missing Dream Eater and Reflect Type tests by @AsparagusEduardo in #6245
  • Refactor testing flags and vars to not conflict with user ones by @hedara90 in #6301

Fixed

  • Fix ASSUMPTIONS not working by @DizzyEggg in #5869
  • Updated Trainer Ids used in Trainer Slides tests by @pkmnsnfrn and @AlexOn1ine found the original bug, @AsparagusEduardo confirmed it in #6138
  • Adjusted G-Max Depletion test by @AsparagusEduardo and @AlexOn1ine for being a cool dude being patient with me during the PR. in #6201
  • Do not add TRAINER_FLAG_DOUBLE_BATTLE to recorded battles by @mrgriffin in #6285
  • Fixes Brick Break/Psychic Fangs/Raging Bull breaking screens if target is immune by @PhallenTree in #6308

📚 Documentation 📚

  • Updating install instructions by @hedara90 in #5610
    • Install instructions have been moved into individual files under docs/install/
  • Documentation for DisableStruct by @AlexOn1ine in #6066
  • Cleaned up Trainer Slides, added automated Trainer Slide tests, add new Enemy Critical Hit Slide by @pkmnsnfrn and @AlexOn1ine, @hedara90, @AsparagusEduardo, @mrgriffin in #6018
    • If users created new entries in sTrainerSlides, they will need to be ported to the new system.
  • Updated trainer pic tutorial by @fdeblasio in #6049
  • Update how_to_testing_system.md by @hedara90 in #6281

📦 Branch Synchronisation 📦

pret

  • 11th of February in #6231
    • Replace easy_chat alphabetialOrder magic numbers with EC_INDEX values by @rayrobdod in pret#2096
    • Fixed switchout bug in multibattle where order of mons gets messed up by @shachar700 in pret#2099

New Contributors

  • @khbsd made their first contribution in #5679
  • @ExMingYan made their first contribution in #6220
  • @Deokishisu made their first contribution in #6261

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.10.2...test

Version 1.10.3

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH test
`.

🧬 General 🧬

Fixed

  • Fix Using a Safari Ball crashes the game #6206 by @ExMingYan in #6220
  • Try a new solution to Fix Safari #6206 by @ExMingYan in #6228
  • Remove obsolete check for steven when retrieving partner name by @u8-Salem and @hedara90 in #6283
  • Fix spit up getting skipped by @cawtds in #6295

🗺️ Overworld 🗺️

Changed

  • Merrp merge (12th of February) by @hedara90 in #6244

Fixed

  • Follower Object Event refactor by @hedara90 and @AsparagusEduardo in #6129
    • Adds OBJ_EVENT_GFX_SPECIES_FEMALE and OBJ_EVENT_GFX_SPECIES_SHINY_FEMALE
  • Fixed Kecleon Shiny palette by @hedara90 in #6298
  • Shifted the follower graphicsIds by @hedara90 in #6329

🐉 Pokémon 🐉

Changed

  • Add Poltchageist family form data by @Bassoonian and @wiz1989 in #6163

Fixed

  • Fixed non-regional forms breeding incorrectly by @AsparagusEduardo and @cawtds in #4985
  • Fixed compilation error when turning P_GENDER_DIFFERENCES off by @AsparagusEduardo in #6223

⚔️ Battle General ⚔️

Fixed

  • Fixes battler mutation during the intim script by @AlexOn1ine in #6151
  • Fixes Dynamic Moves types in SumScreen while in Battle by @AlexOn1ine in #6145
  • Fixes Dragon Tail missing timing against Rocky Helmet / Iron Barbs by @AlexOn1ine in #6154
  • Prevent sameMoveTurns from incrementing when unable to use move by @moostoet in #6167
  • Fixes Suction Cups ability popup and Red Card + Guard Dog interaction by @PhallenTree in #6171
  • Fixed Unnerve message and wrote tests by @hedara90 in #6192
  • Fixes Spectral Thief stealing boost at the wrong time by @AlexOn1ine in #6197
  • Fixes BATTLER_TURN_DAMAGED battler id by @AlexOn1ine in #6236
  • Fixed multi battle forced switches by @hedara90 in #6243
  • Fixes ability Embody Aspect triggering multiple times by @AlexOn1ine in #6259
  • Fixes Called moves ignoring redirection by @PhallenTree in #6267
  • Fixes Protean not restoring types after ai damage calcs by @AlexOn1ine in #6280
  • Restoretarget in Rototiller script + Tests by @AlexOn1ine in #6296
  • Fixes Brick Break/Psychic Fangs/Raging Bull breaking screens if target is immune by @PhallenTree in #6308
  • Fixes intimidate missing timing during a mega evo / switch by @AlexOn1ine in #6322
  • Fixes Coaching on semi-invulnerable ally, Air Balloon being stolen, Immunity abilities being ignored by Mold Breaker by @PhallenTree in #6327
  • Fixes effect paralyze not being absorbed by absorbing abilities by @AlexOn1ine in #6338
  • Added MOVE_TARGET_OPPONENT and added it to Me First, by @hedara90 in #6336
  • Fixes recoil moves causing recoil when absorbed by @AlexOn1ine in #6341
  • Fixed protect not resetting the counter in earlier gens by @hedara90 in #6342

🤹 Moves 🤹

Added

  • Added missing in-battle “Move Info” button prompt by @AsparagusEduardo and @TeamAquasHideout from who I got the source from and @BelialClover from who Archie got the source from. in #6155

Changed

  • Fixes non-Ghost type Curse animation by @PhallenTree in #6299

Fixed

  • Fixed Future Sight not being affected by Electrify by @AsparagusEduardo in #6213
  • Fixes Expanding Force and Spectral Thief move animations by @PhallenTree in #6185

🧶 Items 🧶

Fixed

  • Fixed curing status2 with items in double battles by @hedara90 and @wiz1989 in #6335

🤖 Battle AI 🤖

Fixed

  • Fix AI wrongly thinking it strikes first with priority even if player is using priority themselves by @moostoet in #6274
  • Big Root AI Fix by @Pawkkie in #6309
  • Fix AI hold effect considerations by @Pawkkie in #6310
  • fix for multi 2vs1 opponent sends out too many mons bug by @Bivurnum in #6324

🧹 Other Cleanup 🧹

  • Cleanup some global battler ID usage by @ghoulslash in #6181
  • Fix typo in Nuzzle’s description by @Bassoonian in #6209
  • Remove whitespace from trainers data file by @AsparagusEduardo in #6234
  • Changed bit order for follower graphicsId creation by @hedara90 in #6249
  • Use more accurate count in MovesInfo by @AlexOn1ine in #6260
  • Fix Extra task->tState++ and break in Task_DrawFieldMessageBox by @Deokishisu in #6261
  • Resized gimmick indicators to reduce VRAM usage by @hedara90 in #6319

🧪 Test Runner 🧪

Changed

  • Tests for Big Pecks by @hedara90 in #6158
  • Water Compaction tests by @hedara90 in #6159
  • Wrote tests for Electrify by @hedara90 in #6179
  • Sheer Force Test Fixes by @ghoulslash in #6198
  • Minor Terrain Seed Test Improvement by @ghoulslash in #6207
  • Added test support for 5 battle configs by @AsparagusEduardo in #5914
  • Added missing Dream Eater and Reflect Type tests by @AsparagusEduardo in #6245

Fixed

  • Fixes Brick Break/Psychic Fangs/Raging Bull breaking screens if target is immune by @PhallenTree in #6308

📚 Documentation 📚

  • Update how_to_testing_system.md by @hedara90 in #6281
  • Update SCOPE.md with Intergenerational Feature Compatibility by @Pawkkie in #6325

📦 Branch Synchronisation 📦

pret

  • 11th of February in #6231
    • Replace easy_chat alphabetialOrder magic numbers with EC_INDEX values by @rayrobdod in pret#2096
    • Fixed switchout bug in multibattle where order of mons gets messed up by @shachar700 in pret#2099

New Contributors

  • @ExMingYan made their first contribution in #6220
  • @Deokishisu made their first contribution in #6261
  • @Bivurnum made their first contribution in #6324

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.10.2...test

Version 1.10.2

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.10.2`.

🧬 General 🧬

Changed

  • Add manual breaking back to “What will (mon) do?” message by @kittenchilly in #5908

Fixed

  • Explicitly specify dependencies for teachable learnset helper by @ravepossum in #6015
  • Add dependency on json files to learnset helper by @ravepossum in #6083

🗺️ Overworld 🗺️

Fixed

  • Field effect for cutting grass is missing setfieldeffectargument. Issue #5766 by @shachar700 and @kasenn for finding the source of the issue, @hedara90 for the help with github in #5952
  • Fix Match Call Behavior (#5931) by @MercedesCL in #6033
  • Fixes HGSS dex not compiling currently by @hedara90 in #6051
  • Fixed Liquid Voice’s dynamic type for normal moves by @fdeblasio in #6092
  • Fix Crash if something costs 0 in shop by @DizzyEggg in #6106
  • Fixed Hoenn dex off by 1 issues by @fdeblasio in #6104

🐉 Pokémon 🐉

Changed

  • Add Clodsire second frame and fixed Grookey backsprite + overworld by @kittenchilly in #6047
  • Duraludon battle animation by @Cafeei in #6086

Fixed

  • Fix Enamorus not changing forms by @Bassoonian in #6093

⚔️ Battle General ⚔️

Changed

  • Adds static assert for DamageCalculationData by @AlexOn1ine in #6063

Fixed

  • Fixes Trainer Slide messages causing corruption for recoil damage by @AlexOn1ine in #5926
  • Fixes broken link battles by @hedara90 and @AsparagusEduardo for finding out that the gBitTable removal was the source of the bug. in #5940
  • fixed interaction between Innards Out and Future Sight by @wiz1989 in #5966
  • Fixes various Dynamax HP conversions/calculations by @PhallenTree in #5933
  • Fixes Parting Shot / Eject Pack interaction by @AlexOn1ine in #5963
  • Fixes Shell Bell including heal amount from Future Sight when triggered by @AlexOn1ine in #5962
  • Fixes Tera giving boost to dynamic bp moves by @AlexOn1ine in #6008
  • Fixes Z-Move trigger sprite on B button exit by @AlexOn1ine in #6009
  • Fixed multiple transform/form change graphical issues by @AsparagusEduardo in #6005
    • Dynamax and Tera color tinting now stays during Transform/Form Change animations.
    • Dynamax no longer resets Transformed mon sprites.
    • Transform no longer transforms into a Gigantamax Pokémon unless the transformee has Gigantamax Factor and transforms into a base form with a Gigantamax Form.
  • Fixes defrosting if frozen mon is not damaged by opponent by @AlexOn1ine in #6016
  • Fix Redirection Abilities Not Drawing in Ally Moves by @ghoulslash in #6026
  • fixed bug giving immunity to full-paralysis when B_MAGIC_GUARD is >= GEN_4 by @AERDU in #6032
  • Fixes large battle messages being cut off instead of being prompted to advance by @PhallenTree in #6052
  • Fixes Rapid Spin / Toxic Debris interaction by @AlexOn1ine in #6023
  • Fixes Eject Pack triggering twice on Intimidate by @AlexOn1ine in #6072
  • Trainerslide animation fix by @hedara90 in #6040
    • B_ENEMY_MON_SHADOW_STYLE set to GEN_LATEST since that setting no longer interferes with trainerslides. Set it to GEN_3 to use regular Gen 3 shadow style.
  • Fixes Charge effect not boosting and tests by @AlexOn1ine in #6102
  • Fix seeds softlocking the game when a battler with a Surge ability enters the field by @PhallenTree in #6110
  • Fix MindBlown crash on MyBoy/No Cash by @DizzyEggg in #6112
  • Fix Double Iron Bash move animation crash on MyBoy/No$ by @DizzyEggg in #6114
  • Fix safari zone crash on No Cash by @DizzyEggg in #6132

🤹 Moves 🤹

Fixed

  • Fixed a bunch of move anims by @hedara90 in #5936

🧶 Items 🧶

Changed

  • Added the Gen. 4+ berries to gBerryCrush_BerryData by @LOuroboros in #5937

Fixed

  • Reverts wrongly done partial Eject Pack fix by @AlexOn1ine in #5928

🤖 Battle AI 🤖

Fixed

  • Fix Entrainment AI scoring bug by @Pawkkie in #6056
  • Removed stray semi-colon in AI code by @hedara90 in #6134

🧹 Other Cleanup 🧹

  • Clear unneeded braces from 5922 by @Pawkkie in #5927
  • Removed references to HANDLE_EXPANDED_MOVE_NAME in docs by @AsparagusEduardo in #5955
  • Rename AI_FLAG_PREFER_STRONGEST_MOVE by @Pawkkie in #5972
  • Removed OW_AUTO_SIGNPOST by @AlexOn1ine in #5978
  • CreateFacilityMon error: 'personality' may be used uninitialized by @DizzyEggg in #5981
  • PlayerHandleStatusXor - change u8 to u32 by @DizzyEggg in #5988
  • Follow up for Innards Out / Future Sight interaction by @AlexOn1ine in #5967
  • Remove out of bounds gSprites access in move relearner by @DizzyEggg in #5991
  • Use gCurrentMove instead of checking 0xFF move by @AlexOn1ine in #5999
  • Wrong undefs by @AlexOn1ine in #6024
  • Fixed whitespace issue with trainerproc by @AsparagusEduardo in #6042
  • Remove redundant line in Cmd_setcharge by @AlexOn1ine in #6053
  • Put Identifier and smol in gitignore by @DizzyEggg in #6105
  • Move flag fixes by @fdeblasio in #6107
  • Remove formToChangeInto (Unused) by @AlexOn1ine in #6137

🧪 Test Runner 🧪

Changed

  • Insomnia test used the wrong move in Turn section by @AlexOn1ine in #5939
  • Updated Makefile to allow for the creation of specific tests by @pkmnsnfrn and @mrgriffin in #5993
  • Adds Liquid Ooze and Aromatic Mist test by @AlexOn1ine in #6012
  • Improved Hidden Power test by @AsparagusEduardo and @hedara90, who recommended this implementation. in #6014
  • Add known failing learnset cap test by @Bassoonian in #6046
  • Fix Symbiosis Needing battler Argument + Tests by @ghoulslash in #6039
  • Added some TO_DO tests by @hedara90 in #6140

Fixed

  • Fixed Gimmick tests failing when running first by @AsparagusEduardo in #6001
  • Ported Makefile fix from upcoming by @hedara90 and @mrgriffin Wrote the fix on upcoming in #6007

📚 Documentation 📚

  • Fix formatting in WSL.md by @Cafeei in #5942
  • Update scope.md by @Pawkkie in #5948
  • Removed references to HANDLE_EXPANDED_MOVE_NAME in docs by @AsparagusEduardo in #5955
  • Update scope.md (again) by @Pawkkie and @kithr1 in #5971
  • Codify new expansion release schedule by @pkmnsnfrn and @Pawkkie in #5916
  • Workflow for Scope Discussion by @Pawkkie in #6022
  • Update constants/pokemon.h with nature comments by @bassforte123 in #6133

📦 Branch Synchronisation 📦

pret

  • 17 of January in #6045
    • Slight contest documentation by @AsparagusEduardo in pret#2078
    • Update vars.h (cleanup) by @shachar700 in pret#2082
    • missing const in extern gBasicHitSplatSpriteTemplate by @DizzyEggg in pret#2083
    • extern gAncientPowerRockSpriteTemplate fix by @DizzyEggg in pret#2084
    • remove undef TASK_NONE from list_menu by @DizzyEggg in pret#2085
    • Fix CaveTransition pals by @DizzyEggg in pret#2095
    • Define field script opcode constants by @rayrobdod in pret#2005
    • Document bard music by @GriffinRichards in pret#2053
    • Extern gSprites and gOamMatrices with known array size by @DizzyEggg in pret#2090
    • Fix conflicting types for rotating gate functions by @DizzyEggg in pret#2087

New Contributors

  • @shachar700 made their first contribution in #5952
  • @MercedesCL made their first contribution in #6033
  • @bassforte123 made their first contribution in #6133

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.10.1...expansion/1.10.2

Version 1.10.1

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.10.1`.

🧬 General 🧬

Added

  • Added FONT_SHORT_NARROWER by @AsparagusEduardo (commit originally by @agsmgmaster64) in #5101
    • Narrower font tweaks and font fitting fixes by @kittenchilly in #5782

Changed

  • Adds Thief/Covet config to send stolen item to bag and Pickup config to pickup user’s item in wild battles by @PhallenTree in #5829

Fixed

  • trainerproc: Fix showing incorrect error context by @mrgriffin in #5769
  • Fixes UB in caps.c by @AlexOn1ine in #5878

🗺️ Overworld 🗺️

Fixed

  • Fix Off-by-One Error in Move Relearner by @iriv24 and @luckytyphlosion in #5778
  • Fix HGSS dex sort orders working incorrectly by @ravepossum in #5790
  • Egg cycle length fix by @hedara90 and @/BolaDeQueijo on discord discovered the issue. in #5828
  • Fixed givemon not respecting perfect IVs for species by @AsparagusEduardo in #5873
    • Also removed redundant RemoveIVIndexFromList function in src/daycare.c, so it uses src/pokemon.c’s instead
  • Fix Script Scrollable Multichoice Arrow Positions by @ghoulslash in #5884

🐉 Pokémon 🐉

Changed

  • Updated Ogerpon, Enamorus and Sinistcha sprites by @kittenchilly in #5793
  • New Enamorus-Incarnate sprite by @kittenchilly in #5797

Fixed

  • Fixes Wormadam define for teachable learnset script by @AlexOn1ine in #5783
  • Fix “PlantCloak” references by @AsparagusEduardo in #5821
  • Misc pokemon sprite fixes by @Cafeei in #5846

⚔️ Battle General ⚔️

Changed

  • Adds Thief/Covet config to send stolen item to bag and Pickup config to pickup user’s item in wild battles by @PhallenTree in #5829

Fixed

  • Fixes items preventing other switch in effects by @AlexOn1ine in #5732
  • Fix Pokemon with No Guard failing OHKO Moves into Semi-Invulnerable Pokemon by @iriv24 and @Cafeei in #5779
  • Fix move category and category icon when PSS is off by @ravepossum in #5786
  • Added the missing config to use new terrains by @hedara90 in #5792
  • Fixes Shed Tail substitute health by @AlexOn1ine in #5826
  • B_LAST_USED_BALL and .importance by @AERDU in #5834
    • prevents B_LAST_USED_BALL from removing balls with .importance = 1
  • Fixes Quash-affected battlers having the wrong order for End Turn effects by @PhallenTree in #5838
  • Fixes Cotton Down and Gulp Missile not interacting correctly with stat reduction prevention effects by @PhallenTree in #5841
  • Fix Hit Escape moves giving Exp to the mon that switches in by @kittenchilly in #5844
  • Fixed Wish triggering Disguise by @AsparagusEduardo in #5860
  • Fixed MOVE_EFFECT_FREEZE_OR_FROSTBITE not being usable in battle scripts by @AsparagusEduardo in #5859
  • Fixed Ally Switch breaking Illusion by @AsparagusEduardo in #5879
  • Fixes gen3 Style Shadows out of place by @AlexOn1ine in #5880
  • Fix Salt Cure script by @ghoulslash in #5895
  • Fixes Eject Pack / Intimidate issue by @AlexOn1ine in #5902
  • Adds Generational config for Magic Guard (Fix for Gen4+) by @AlexOn1ine in #5893
  • Fixes Stance Change, Sleep Talk interaction by @AlexOn1ine in #5909
  • Fixes Round doubling it’s BP if previous Round failed by @AlexOn1ine in #5907

🤹 Moves 🤹

Fixed

  • Fixes absorb still draining HP when flinched by @AlexOn1ine in #5814
  • Fixes Tidy Up by @AlexOn1ine in #5819
  • Ally Switch extra battlerId tracking by @ghoulslash in #5823
  • Sheer Force fix and move effect cleanup by @AlexOn1ine in #5812
  • New U-turn animation to fix visibility by @AlexOn1ine in #5910

🧶 Items 🧶

Fixed

  • Prevent Key Items that open other menus from causing a crash if registered and used from the field by @iriv24 in #5810
  • Fixes Clear Amulet displaying the wrong battler and Starting Status displaying the wrong message by @PhallenTree in #5831
  • Fixes Room Service lowering the opposite mon in specific scenario by @AlexOn1ine in #5827

🤖 Battle AI 🤖

Fixed

  • Fixed ace switching bugs by @Pawkkie and @iriv24 for their diligent testing and debugging support in #5922

🧹 Other Cleanup 🧹

  • Converted Stance Change to proper Form Change + Tests by @AsparagusEduardo in #5749
  • Removed testing strings for automatic line breaks by @hedara90 in #5757
  • Added NBSP and up+down arrows to all fonts by @hedara90 in #5767
    • Use ~ or {NBSP} to insert a non-breaking space into a string.
  • Palette cleanup by @hedara90 in #5661
    • Resized some move anim palettes from 256 to 16
  • Replace power checks with IS_MOVE_STATUS by @Bassoonian and @AsparagusEduardo in #5820
  • Changes Various defines to an Enum by @AsparagusEduardo in #5840
  • Fix IS_MOVE_STATUS regression by @Bassoonian in #5848
  • Remove unused various by @Bassoonian in #5851
  • Removed redundant call to FillPalBufferBlack in FRLG whiteout sequence by @AsparagusEduardo in #5854
  • Improve README.md by @AsparagusEduardo in #5640
  • Fix wrong value for NUM_MOVE_EFFECTS by @Bassoonian in #5913
  • Renamed OW type effectiveness function for clarity by @AsparagusEduardo in #5917
    • Renamed GetTypeEffectiveness to GetOverworldTypeEffectiveness.

🧪 Test Runner 🧪

Changed

  • Gravity fix + Sky Drop Test by @ghoulslash in #5780
  • Added missing Belch tests by @AsparagusEduardo in #5881
  • Added missing Move Effect TODO tests - Volume D by @AsparagusEduardo in #5887
  • Comment out Ally Switch Illusion test by @AsparagusEduardo in #5901
  • Fixed leaking tasks not showing up in summary by @AsparagusEduardo in #5890
  • Setting Battle configs during tests by @AsparagusEduardo and @SBird1337, @mrgriffin in #5803
  • Speed up tests in headless mode by @AsparagusEduardo and @SBird1337 for the original fast intro code. in #5889
    • This introduced the config option B_FAST_INTRO_NO_SLIDE which removes the sliding into for battles.
  • Added missing Move Effect TODO tests - Volume E by @AsparagusEduardo in #5915

Fixed

  • Fix test TIMEOUT messaging in summary by @AsparagusEduardo in #5772
  • Fix octolock + defiant by @ghoulslash in #5781
  • Added missing tests + Fix Coaching/Crafty Shield interaction by @AsparagusEduardo in #5796
  • Fixed TODO tests not showing up when filtering by name by @AsparagusEduardo in #5894

📚 Documentation 📚

  • Fixed changelog links to changelog 1.10 by @AsparagusEduardo in #5758
  • Added scope document and made changes to pull request template by @pkmnsnfrn and @Pawkkie and arguably the entire senate in #5706
  • Added instructions in PR template to make crediting people more clear by @pkmnsnfrn and @AsparagusEduardo made changes to my text in #5755
  • Fix website not showing the “How to add mon” 1.10 tutorial by @AsparagusEduardo in #5813
  • Install instructions by @hedara90 in #5876
  • Change install.md to mention make debug instead of DINFO=1 by @ravepossum in #5882
  • Backport changes from the wiki by @AsparagusEduardo in #5900
  • Improve README.md by @AsparagusEduardo in #5640

📦 Branch Synchronisation 📦

pret

  • 20th of December in #5845
    • Fix recorded battle link player loops by @AsparagusEduardo in pret#2071
    • Added POKEMART_LIST_END to avoid users accidentally removing it by @AsparagusEduardo in pret#1947
    • Fixed brace style inconsistencies by @AsparagusEduardo in pret#2072
    • remove sBirchSpeechPlatformBlackPal by @DizzyEggg in pret#2075

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.10.0...expansion/1.10.1

Version 1.10.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.10.0`.

🌋 REFACTORS 🌋

📜 = Uses a migration script.

  • Changes Evolution methods to Enums by @AlexOn1ine in #4977
  • Turn item hold effects into an enum by @Bassoonian in #5498
  • Change GET_MOVE_TYPE to a function by @AlexOn1ine in #5090
  • Created COMPOUND_STRINGs for default player names by @fdeblasio in #5037
  • Removed agbcc by @mrgriffin in #4994
  • Refactor Frontier Brains by @fdeblasio in #5027
  • Removed all instances of gBitTable[x] by @hedara90 in #5123
  • Made BuildColorMaps redundant by using static tables by @pkmnsnfrn in #5289
  • Removed FRONTIER_BRAIN_SPRITES and updated TRAINER_SPRITE, TRAINER_BACK_SPRITE, and TRAINER_CLASS by @fdeblasio in #5166
  • Added ShouldSwitch result to AiLogicData by @Pawkkie and @AlexOn1ine had the idea! in #5440
  • Switch AI refactor + considers free switches by @Pawkkie in #5379
  • Refactor ShouldSwitchIfAllBadMoves by @Pawkkie in #5452
  • Updated Wring Out effects to match Eruption effects by @AsparagusEduardo in #5549
    • Changed Wring Out/Crush Grip/Hard Press to use power instead of argument to determine its max power, just like how Eruption/Water Spout/Dragon Energy do it.
    • Also:
      • Renamed EFFECT_VARY_POWER_BASED_ON_HP to EFFECT_POWER_BASED_ON_TARGET_HP
      • Renamed EFFECT_ERUPTION to EFFECT_POWER_BASED_ON_USER_HP
  • Update battle messages to Gen 5+ standards by @kittenchilly in #3240
  • Should switch refactor to facilitate switch prediction by @Pawkkie in #5466
  • Unwind TRAINER_CLASS macro by @SBird1337 in #5611
  • Refactors Absorb to use Moveend by @AlexOn1ine in #5670
    • For new absorbing moves an argument should be added in moves_info.h
  • Changes name of B_SCR_NAME_WITH_PREFIX by @AlexOn1ine in #5675

🧬 General 🧬

Added

  • Added performance counter by @hedara90 and @SBird1337 provided the actual code in #5284
  • Added debug build target by @u8-Salem in #4817
  • Added AUTO_SCROLL_TEXT and NUM_FRAMES_AUTO_SCROLL_DELAY by @pkmnsnfrn in #5054
  • Adds SAVE_TYPE_ERROR_SCREEN by @pkmnsnfrn in #5188
  • Move Relearner and Renaming From Summary Screen by @ravepossum in #5513
  • Automatic Line Breaks, somewhat even lines by @hedara90 and @AsparagusEduardo in #5689
    • Automatically insert line breaks into a string with BreakStringAutomatic.
    • This function does not modify strings with existing line breaks.
    • Remove existing line breaks from a string with StripLineBreaks.

Changed

  • Removed agbcc by @mrgriffin in #4994
  • Removed all instances of gBitTable[x] by @hedara90 in #5123
  • Converted Mechadoll text to COMPOUND_STRINGs by @fdeblasio in #5276
  • New terrain bgs by @TheTrueSadfish in #5162
  • Removed agbcc screenshots from .gitignore by @Bassoonian in #5538
  • Set default battle shadow to Gen3 by @hedara90 in #5632
    • Note: Trainerslides don’t work properly with Gen4 shadows.
  • Convert 3 variouses to callnatives by @AlexOn1ine in #5646

🗺️ Overworld 🗺️

Added

  • FRLG+ whiteout message by @cawtds in #4967
  • Dynamic Move Types in Summary Screen/Battle by @Galaxeeh in #5084
  • Adds OW_BERRY_IMMORTAL by @pkmnsnfrn in #5187
  • (Default Off) Item Description Headers by @ghoulslash in #4767
  • RTC-based wild encounters by @hjk321 in #5313
  • Added MB_X_Y_STAIR_WARP metatile behaviors by @pkmnsnfrn in #5278
  • Added Sideways Stairs by @ghoulslash in #4836
  • Added OW_UNION_DISABLE_CHECK and OW_FLAG_MOVE_UNION_ROOM_CHECK by @pkmnsnfrn in #5448
  • Adds new scripting macros to increase developer quality of life by @pkmnsnfrn in #5177
  • Added more later gen fishing mechanics by @kittenchilly in #5518

Changed

  • Created PokeNav COMPOUND_STRINGs by @fdeblasio in #4983
  • Added I_REPEL_INCLUDE_FAINTED config and behavior by @kittenchilly in #5239
  • RTC-based wild encounters follow up by @AlexOn1ine in #5328
  • Revert rtc based encounters by @AlexOn1ine in #5331
  • Made BuildColorMaps redundant by using static tables by @pkmnsnfrn in #5289
  • Added OW_AUTO_SIGNPOST and associated metatile behaviors by @pkmnsnfrn in #5044
  • Added support for overworld sprite gender differences + add all the sprites by @kittenchilly in #5394

Fixed

  • Added some null pointer checks by @tertu-m in #5130
  • Reset item flags on new game by @ghoulslash in #5363
  • Follower female fix by @hedara90 in #5475

🐉 Pokémon 🐉

Added

  • Added config to change Vivillon’s breeding form by @kittenchilly in #4813
  • Added back GBA sprites via config by @AsparagusEduardo and @AlexOn1ine for their help with script to migrate data from vanilla to our current gSpeciesInfo in #5206
  • Added config to disable gender differences by @AsparagusEduardo in #5595

Changed

  • Made perfect IV count into a granular setting by @AsparagusEduardo in #5115
  • Updated species defines by @pkmnsnfrn in #5075
  • Added support for overworld sprite gender differences + add all the sprites by @kittenchilly in #5394
  • Renamed folders and symbols to match species defines by @AsparagusEduardo in #5581
    • Burmy and Wormadam footprints were in a plant subfolder. They have been moved to the species root folder
    • Paldean Wooper’s subfolder was named wooper_paldean instead of just paldean. This has been corrected.
    • Zen Mode Galarian Darmanitan’s folder was located in darmanitan/galarian/zen_mode. This has been corrected to darmanitan/galar_zen, alongside Galarian Standard Mode’s darmanitan/galar_standard.
    • Also updated Ogerpon’s folders similarly.
    • Renamed SPECIES_PIKACHU_PARTNER_CAP to SPECIES_PIKACHU_PARTNER.
  • Changing EVO_NONE from 0xFFFE to 0 by @GhoulMage in #5547
    • There could be a case for out of bounds errors if arrays or iterations are happening where you’re using + 1 or - 1, as EVO_FRIENDSHIP used to be the first index although it started with 1.

Fixed

  • Follower female fix by @hedara90 in #5475
  • Fixed some gba sprites by @SubzeroEclipse in #5607

⚔️ Battle General ⚔️

Added

  • FRLG+ whiteout message by @cawtds in #4967
  • Added B_SHOW_TYPES and cleaned up IsDoubleBattle by @pkmnsnfrn in #5131
  • EV Caps and EV Items by @Flash1Lucky and @AlexOn1ine in #5269
  • Added in-battle shadows underneath all enemy battlers by @lhearachel in #5178
  • Added Gen 1 Crit Chance by @Pawkkie in #5439
  • Added battle flag that prevents running from wild Pokémon by @SarnPoke in #5502

Changed

  • Refactor Frontier Brains by @fdeblasio in #5027
  • Removed some hardcoding of move IDs + Gen4/5 Defog by @AsparagusEduardo in #5156
  • Convert 8 various to callnatives by @AsparagusEduardo in #5172
  • Anger Shell use saveattacker by @ghoulslash in #5409
  • Clean up Unseen Fist Check by @AlexOn1ine in #5420
  • Updated species defines by @pkmnsnfrn in #5075
  • Removes Crit Chance preproc by @AlexOn1ine in #5520
  • Update battle messages to Gen 5+ standards by @kittenchilly in #3240
  • More post-#3240 cleanup by @kittenchilly in #5593
  • Unwind TRAINER_CLASS macro by @SBird1337 in #5611
  • Removes redundant Decorate check by @AlexOn1ine in #5696
  • Changes target bit of Flower Shield by @AlexOn1ine in #5698

Fixed

  • Fixed a sprite issue with B_SHOW_TYPES by @pkmnsnfrn in #5157
  • Dynamic Move Display fixes by @Galaxeeh in #5251
  • Fixed a display issue with B_SHOW_TYPES by @pkmnsnfrn and @iriv24 in #5201
  • Fixed Gen 3 foreseen and Beat Up damage type by @hedara90 in #5323
  • Fixes Defog used by the wrong side when there is a Substitue and Screen by @AlexOn1ine in #5381
  • Fixes Hidden Power dynamic type bug by @AlexOn1ine in #5463
  • Display the correct shadow size when sending out a new Pokemon by @lhearachel in #5618
  • Fixed text wrap obtaining the incorrect glyph width by @AsparagusEduardo and @AlexOn1ine for their help verifying that the fix works with one of his custom strings in #5620
  • Improve line breaks/scrolls by @cawtds in #5641
  • Fixed Order Up + Tera Stellar breaking each other with Commander by @PhallenTree in #5667
  • Fixes wrong Id when AI chooses mon to switch in by @AlexOn1ine in #5684
  • Fixes Absorb regression caused by #5670 by @AlexOn1ine in #5688
  • Fixes heal blocked leeach seed in tests by @AlexOn1ine in #5700
  • Trainer class+name expansion fix for Battle Frontier by @hedara90 in #5699

🤹 Moves 🤹

Changed

  • Added Population Bomb animation by @kittenchilly in #5194
  • Move battle anim arrays to C by @cawtds in #5306
  • Grass/Water Pledge Swamp Animation + Sea of Fire animation tweak by @SonikkuA-DatH in #5325
  • New animations for many moves more details in description by @TheTrueSadfish in #5367
  • Use move effect for some moves instead of ids by @AlexOn1ine in #5433
  • Adds Commander and Order Up by @AlexOn1ine in #5246
  • Heart Swap Move Animation by @SonikkuA-DatH in #5460
  • Update shed_tail.c by @Bassoonian in #5494
  • Added Ion Deluge animation by @kittenchilly in #5467
  • Updated Wring Out effects to match Eruption effects by @AsparagusEduardo in #5549
    • Changed Wring Out/Crush Grip/Hard Press to use power instead of argument to determine its max power, just like how Eruption/Water Spout/Dragon Energy do it. Also:
    • Renamed EFFECT_VARY_POWER_BASED_ON_HP to EFFECT_POWER_BASED_ON_TARGET_HP
    • Renamed EFFECT_ERUPTION to EFFECT_POWER_BASED_ON_USER_HP
  • Refactors Absorb to use Moveend by @AlexOn1ine in #5670
    • For new absorbing moves an argument should be added in moves_info.h

Fixed

  • Dark Void, Clangorous Soulblaze, vortex animation fixes by @TheTrueSadfish in #5650

🎭 Abilities 🎭

Changed

  • Adds Commander and Order Up by @AlexOn1ine in #5246

🧶 Items 🧶

Added

  • Adds OW_BERRY_IMMORTAL by @pkmnsnfrn in #5187
  • Added functionality to Poké Flute and Town Map by @kittenchilly and @LOuroboros basically did the Town Map implementation in #5405
  • Decouple Poke Ball ids from item ids by @AlexOn1ine in #5560

Changed

  • Consolidated the values of Rotom’s moves and added Gen9 base form effect by @fdeblasio in #5186
  • Added I_REPEL_INCLUDE_FAINTED config and behavior by @kittenchilly in #5239

Fixed

  • Replace hardcoded flute check with consumability check by @Bassoonian in #5508

🤖 Battle AI 🤖

Added

  • Adds config to show target of ingame partner by @AlexOn1ine in #5307
  • Switch AI refactor + considers free switches by @Pawkkie in #5379
  • New AI flag for marking the two last Pokémon as Ace Pokémon by @GhoulMage in #5587

Changed

  • Chilly Reception AI by @kittenchilly in #5271
  • Shed Tail AI by @SarnPoke and @AlexOn1ine, @Pawkkie in #5275
  • More missing AI logic by @kittenchilly in #5279
  • Adds basic trainer and smart trainer flags by @AlexOn1ine in #5298
  • AI_FLAG_SETUP_FIRST_TURN rename and clarifications by @Pawkkie in #5310
  • Added Composite AI Flags to Docs by @Pawkkie in #5349
  • AI frostbite score fixes and improvements by @Pawkkie and @kittenchilly for the suggestion! in #5362
  • Switch AI hitsToKO considers one shot prevention by @Pawkkie in #5371
  • Adds CanEndureHit AI function by @AlexOn1ine in #5373
  • Switch AI hitsToKO considers Disguise by @Pawkkie in #5375
  • Added ShouldSwitch result to AiLogicData by @Pawkkie and @AlexOn1ine had the idea! in #5440
  • Removes duplicate code in AI functions by @AlexOn1ine in #5457
  • Unify GetBattlerAbility/TerrainAffected to remove duplicate ai function by @AlexOn1ine in #5497
  • ShouldSwitchIfGameStatePrompt Tests by @Pawkkie in #5462
  • AI_FLAG_ACE_POKEMON takes into account separate trainers by @GhoulMage and @/uvula on Discord noted the weird behaviour. in #5608
    • Fix for the AI not considering both trainers Ace Pokémons in double battles with AI_FLAG_ACE_POKEMON.
  • Moves that deal a Fixed amount don’t need AI handling by @AlexOn1ine in #5614
  • Combines CalculateMoveDamage arguments into a struct by @AlexOn1ine in #5570

Fixed

  • AI burn score fixes and improvements by @Pawkkie and @iriv24 and @AlexOn1ine in #5356
  • Improve AI’s Skill Swap handling in double battles by @Pawkkie in #5360
  • Refactor ShouldSwitchIfAllBadMoves by @Pawkkie in #5452
  • Should switch refactor to facilitate switch prediction by @Pawkkie in #5466
  • Fixes Switch in flag not restoring mons properly with test by @Pawkkie and @iriv24 for finding, @AlexOn1ine for fixing in #5746

🧹 Other Cleanup 🧹

  • Removed metadata in AIF files by @SombrAbsol in #4958
  • Removed gPaletteDecompressionBuffer and unused palette functions/vars by @DizzyEggg in #4841
  • Changes Evolution methods to enums by @AlexOn1ine in #4977
  • Doesn’t compile on some compilers by @AlexOn1ine in #5099
  • Update event.inc to accomodate new gDecompressionBuffer name by @Bassoonian in #5100
  • Created COMPOUND_STRINGs for default player names by @fdeblasio in #5037
  • Changed single-use berry blender strings to be COMPOUND_STRINGs by @fdeblasio in #4963
  • Made perfect IV count into a granular setting by @AsparagusEduardo in #5115
  • Dynamic move type clean up by @AlexOn1ine in #5132
  • Refactor Frontier Brains by @fdeblasio in #5027
  • Removed some hardcoding of move IDs + Gen4/5 Defog by @AsparagusEduardo in #5156
  • Teatime animations use B_WAIT_TIME_LONG by @AsparagusEduardo in #5173
  • Created PokeNav COMPOUND_STRINGs by @fdeblasio in #4983
  • Removed gBitTable usage again by @hedara90 in #5193
  • Removed support for the original LCG random number generator by @tertu-m in #5078
  • Deprecate MMBN Names by @pkmnsnfrn in #5240
  • Convert 8 various to callnatives by @AsparagusEduardo in #5172
  • Converted PC strings to COMPOUND_STRINGs by @fdeblasio in #5314
  • Cleaned up duplicate dynamic type functions by @AsparagusEduardo in #5338
  • Removes redundant moveTargetType ai function by @AlexOn1ine in #5354
  • Made BuildColorMaps redundant by using static tables by @pkmnsnfrn in #5289
  • Some strings were switched by @AlexOn1ine in #5374
  • Switch AI hitsToKO considers Disguise by @Pawkkie in #5375
  • Cleaned up a bit of code with GetBattlerPartyData by @AlexOn1ine in #5378
  • Minor Gem check optimazation by @AlexOn1ine in #5401
  • Simplify HP Logic by @AreaZR in #5403
  • Anger Shell use saveattacker by @ghoulslash in #5409
  • Converted berry and PokeBlock strings to COMPOUND_STRINGs by @fdeblasio in #5324
  • Merge item description branch history by @Bassoonian in #5419
  • Clean up Unseen Fist Check by @AlexOn1ine in #5420
  • Merge level_caps and ev_caps into one caps file by @kittenchilly in #5429
  • Removed trailing whitespace pass 10-2-2024 (Upcoming) by @kittenchilly in #5456
  • Fixed Commander test name by @Bassoonian in #5458
  • Updated species defines by @pkmnsnfrn in #5075
  • Adds padding in AiLogicData by @AlexOn1ine in #5468
  • Simplify BS_FAINTED_MULTIPLE_1 double battle logic in openpartyscreen by @ghoulslash in #5435
  • Removes duplicate code in AI functions by @AlexOn1ine in #5457
  • ShouldPivot type cleanup by @Pawkkie in #5441
  • Turn item hold effects into an enum by @Bassoonian in #5498
  • Unify GetBattlerAbility/TerrainAffected to remove duplicate ai function by @AlexOn1ine in #5497
  • Clean up Shedinja code by @Bassoonian in #5501
  • Clean up scrcmd PR by @Bassoonian in #5511
  • Removes Crit Chance preproc by @AlexOn1ine in #5520
  • Removed agbcc screenshots from gitignore by @Bassoonian in #5538
  • Removed unnecessary gBattlerAttacker usage by @AlexOn1ine in #5554
  • Removed remaining line breaks from #3240 + Prefix wrap fix by @AsparagusEduardo in #5556
  • More post-#3240 cleanup by @kittenchilly in #5593
  • Renamed folders and symbols to match species defines by @AsparagusEduardo in #5581
    • Also:
    • Burmy and Wormadam footprints were in a plant subfolder. They have been moved to the species root folder
    • Paldean Wooper’s subfolder was named wooper_paldean instead of just paldean. This has been corrected.
    • Zen Mode Galarian Darmanitan’s folder was located in darmanitan/galarian/zen_mode. This has been corrected to darmanitan/galar_zen, alongside Galarian Standard Mode’s darmanitan/galar_standard.
    • Also updated Ogerpon’s folders similarly.
    • Renamed SPECIES_PIKACHU_PARTNER_CAP to SPECIES_PIKACHU_PARTNER.
  • Minor BattleStruct clean up by @AlexOn1ine in #5585
  • Fixed a ball update oversight by @Bassoonian in #5609
  • AI_FLAG_ACE_POKEMON takes into account separate trainers by @GhoulMage and @/uvula on Discord noted the weird behaviour in #5608
    • Fix for the AI not considering both trainers Ace Pokémons in double battles with AI_FLAG_ACE_POKEMON.
  • Moves that deal a Fixed amount don’t need AI handling by @AlexOn1ine in #5614
  • Combines CalculateMoveDamage arguments into a struct by @AlexOn1ine in #5570
  • Follow up for #5570 by @AlexOn1ine in #5625
  • AI_CalcDamage clean up by @AlexOn1ine in #5629
  • Convert 3 variouses to callnatives by @AlexOn1ine in #5646
  • Convert gBattleStringsTable to COMPOUND_STRINGs by @AsparagusEduardo in #5649
  • Added merged placeholder text for trainer name with class by @kittenchilly in #5622
  • Cleans up Primal Reversion code by @AlexOn1ine in #5659
  • Critical Hit documentation and distorted match up struct switch by @AlexOn1ine in #5665
  • Changes name of B_SCR_NAME_WITH_PREFIX by @AlexOn1ine in #5675
  • Removes redundant Decorate check by @AlexOn1ine in #5696
  • Changes taget bit of Flower Shield by @AlexOn1ine in #5698
  • Changing EVO_NONE from 0xFFFE to 0 by @GhoulMage in #5547
    • There could be a case for out of bounds errors if arrays or iterations are happening where you’re using + 1 or - 1, as EVO_FRIENDSHIP used to be the first index although it started with 1.

🧪 Test Runner 🧪

Changed

  • Fixed Commander test name by @Bassoonian in #5458
  • ShouldSwitchIfGameStatePrompt Tests by @Pawkkie in #5462
  • Added various tests, add RNG_RANDOM_TARGET by @ghoulslash in #5438
  • Added Costar Tests, Download Test for Doubles by @ghoulslash in #5526
  • Updated Wring Out effects to match Eruption effects by @AsparagusEduardo in #5549
    • Changed Wring Out/Crush Grip/Hard Press to use power instead of argument to determine its max power, just like how Eruption/Water Spout/Dragon Energy do it. Also:
    • Renamed EFFECT_VARY_POWER_BASED_ON_HP to EFFECT_POWER_BASED_ON_TARGET_HP
    • Renamed EFFECT_ERUPTION to EFFECT_POWER_BASED_ON_USER_HP
  • Healer ability tests by @Pawkkie in #5559
  • Mark all tests as used by @mrgriffin in #5531

Fixed

  • Should switch refactor to facilitate switch prediction by @Pawkkie in #5466

📚 Documentation 📚

  • DoBattleIntro state documentation by @AsparagusEduardo and @ShinyDragonHunter in #5231
  • Deprecate MMBN Names by @pkmnsnfrn in #5240
  • AI_FLAG_SETUP_FIRST_TURN Rename and Clarifications by @Pawkkie in #5310
  • Added Composite AI Flags to Docs by @Pawkkie in #5349
  • Updated the new pokemon tutorial for 1.10 by @hedara90 in #5721
    • Some changes compared to previous.

New Contributors

  • @SombrAbsol made their first contribution in #4958
  • @Galaxeeh made their first contribution in #5084
  • @Flash1Lucky made their first contribution in #5269
  • @GhoulMage made their first contribution in #5547

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.9.4...expansion/1.10.0

Megaman Battle Network Style Names

Prior to 1.10, names in expansion that were too long for the game’s UIs were truncated to fit using the naming conventions from the Megaman Battle Network series.

These were removed as part of https://github.com/rh-hideout/pokeemerald-expansion/pull/5240. They are stored here for users that may want to refer back to them or restore them.

Table

AttributeMMBNOfficial
ItemPewtrCrnchesPewter Crunchies
ItemRageCandyBarRage Candy Bar
ItemLumioseGleteLumiose Galette
ItemShalourSableShalour Sable
ItemHealthFeatherHealth Feather
ItemMuscleFeatherMuscle Feather
ItemResistFeatherResist Feather
ItemGeniusFeatherGenius Feather
ItemCleverFeatherClever Feather
ItemSwiftFeatherSwift Feather
ItemAbilityCapsleAbility Capsule
ItemAbilityPatchAbility Patch
ItemAbilityPatchesAbility Patches
ItemExp.Candy XSExp. Candy XS
ItemExp.Candies XSExp. Candies XS
ItemExp.Candy SExp. Candy S
ItemExp.Candies SExp. Candies S
ItemExp.Candy MExp. Candy M
ItemExp.Candies MExp. Candies M
ItemExp.Candy LExp. Candy L
ItemExp.Candies LExp. Candies L
ItemExp.Candy XLExp. Candy XL
ItemExp.Candies XLExp. Candies XL
ItemDynamaxCandyDynamax Candy
ItemDynamaxCandiesDynamax Candies
ItemMaxMushroomsMax Mushrooms
ItemGoldBottlCapGold Bottle Cap
ItemPrettyFeatherPretty Feather
ItemStrngeSouvnrStrange Souvenir
ItemFosslzedBirdFossilized Bird
ItemFosslzedFishFossilized Fish
ItemFosslzedFishesFossilized Fishes
ItemFosslzedDrkeFossilized Drake
ItemFosslzedDinoFossilized Dino
ItemSurprseMulchSurprise Mulch
ItemYellwApricornYellow Apricorn
ItemGreenApricornGreen Apricorn
ItemWhiteApricornWhite Apricorn
ItemBlackApricornBlack Apricorn
ItemWishingPieceWishing Piece
ItemGalaricaTwigGalarica Twig
ItemGalaricaCuffGalarica Cuff
ItemGalrcaWreathGalarica Wreath
ItemGalrcaWreathesGalarica Wreathes
ItemStrwbrySweetStrawberry Sweet
ItemElectrcMemoryElectric Memory
ItemElectrcMemoriesElectric Memories
ItemFightngMemoryFighting Memory
ItemFightngMemoriesFighting Memories
ItemPsychicMemoryPsychic Memory
ItemPsychicMemoriesPsychic Memories
ItemRustedSwordRusted Sword
ItemRustedShieldRusted Shield
ItemCharizarditeXCharizardite X
ItemCharizarditeYCharizardite Y
ItemU-Necrozium ZUltranecrozium Z
ItemDeepSeaScaleDeep Sea Scale
ItemDeepSeaToothDeep Sea Tooth
ItemNever-MeltIceNever-Melt Ice
ItemWeaknssPolicyWeakness Policy
ItemWeaknssPoliciesWeakness Policies
ItemSafetyGogglesSafety Goggles
ItemAdrenalineOrbAdrenaline Orb
ItemTerainExtendrTerrain Extender
ItemProtectvePadsProtective Pads
ItemHeavy-DtyBtsHeavy-Duty Boots
ItemBlundrPolicyBlunder Policy
ItemBlundrPoliciesBlunder Policies
ItemUtltyUmbrllaUtility Umbrella
ItemCatchngCharmCatching Charm
ItemRotomCatalogRotom Catalog
ItemReinsOfUnityReins of Unity
ItemDowsing MCHNDowsing Machine
ItemAbilityShieldAbility Shield
ItemPunchingGlovePunching Glove
ItemAuspciousArmrAuspicious Armor
ItemBoosterEnergyBooster Energy
ItemBoosterEnergiesBooster Energies
ItemBigBmbooShootBig Bamboo Shoot
ItemGimighoulCoinGimmighoul Coin
ItemLeader’sCrestLeader’s Crest
ItemMaliciousArmrMalicious Armor
ItemScrllOfDrknssScroll of Darkness
ItemScrllsOfDrknssScrolls of Darkness
ItemScrollOfWatrsScroll of Waters
ItemScrollsOfWatrsScrolls of Waters
ItemTinyBmbooShotTiny Bamboo Shoot
ItemBug TeraShardBug Tera Shard
ItemDarkTeraShardDark Tera Shard
ItemDragnTeraShrdDragon Tera Shard
ItemEltrcTeraShrdElectric Tera Shard
ItemFairyTeraShrdFairy Tera Shard
ItemFghtngTerShrdFighting Tera Shard
ItemFireTeraShardFire Tera Shard
ItemFlyngTeraShrdFlying Tera Shard
ItemGhostTeraShrdGhost Tera Shard
ItemGrassTeraShrdGrass Tera Shard
ItemGrondTeraShrdGround Tera Shard
ItemIce TeraShardIce Tera Shard
ItemNormlTeraShrdNormal Tera Shard
ItemPoisnTeraShrdPoison Tera Shard
ItemPschcTeraShrdPsychic Tera Shard
ItemRockTeraShardRock Tera Shard
ItemSteelTeraShrdSteel Tera Shard
ItemWaterTeraShrdWater Tera Shard
ItemAdamantCrystlAdamant Crystal
ItemLustrousGlobeLustrous Globe
ItemBlackAuguriteBlack Augurite
ItemUnrmkblTeacupUnremarkable Teacup
ItemMstrpceTeacupMasterpiece Teacup
ItemCornrstneMaskCornerstone Mask
ItemWellsprngMaskWellspring Mask
ItemHrthflameMaskHearthflame Mask
ItemFrshStrtMochiFresh Start Mochi
ItemGlmmringCharmGlimmering Charm
ItemStllrTeraShrdStellar Tera Shard
ItemJublifeMuffinJubilife Muffin
ItemAuxPowerguardAux Powerguard
ItemChoiceDumplngChoice Dumpling
Item2xSpicedRadshTwice-Spiced Radish
MoveThunderPunchThunder Punch
MovePoisonPowderPoison Powder
MoveThunderShockThunder Shock
MoveSelfDestructSelf-Destruct
MoveHighJumpKickHigh Jump Kick
MoveDynamicPunchDynamic Punch
MoveDragonBreathDragon Breath
MoveExtremeSpeedExtreme Speed
MoveAncientPowerAncient Power
MoveSmellngSaltsSmelling Salts
MoveFeatherDanceFeather Dance
MoveGrassWhistleGrass Whistle
MovePhantomForcePhantom Force
MoveTrickOrTreatTrick-or-Treat
MoveParabolcChrgParabolic Charge
MoveForest’sCursForest’s Curse
MovePetalBlizzrdPetal Blizzard
MoveDisrmngVoiceDisarming Voice
MoveDrainingKissDraining Kiss
MoveCraftyShieldCrafty Shield
MoveFlowerShieldFlower Shield
MoveGrssyTerrainGrassy Terrain
MoveMistyTerrainMisty Terrain
MoveKing’sShieldKing’s Shield
MoveDiamondStormDiamond Storm
MoveSteamErptionSteam Eruption
MoveHyprspceHoleHyperspace Hole
MoveWatrShurikenWater Shuriken
MoveMysticalFireMystical Fire
MoveAromaticMistAromatic Mist
MoveEerieImpulseEerie Impulse
MoveMagneticFluxMagnetic Flux
MoveElctrcTrrainElectric Terrain
MoveDazzlngGleamDazzling Gleam
MoveBabyDollEyesBaby-Doll Eyes
MovePowerUpPunchPower-Up Punch
MoveOblivionWingOblivion Wing
MoveThousndArrwsThousand Arrows
MoveThousndWavesThousand Waves
MoveLightOfRuinLight Of Ruin
MovePrcipceBldesPrecipice Blades
MoveDragonAscentDragon Ascent
MoveHyprspceFuryHyperspace Fury
MoveFrstImpressnFirst Impression
MoveBanefulBunkrBaneful Bunker
MoveSpiritShacklSpirit Shackle
MoveDarkstLariatDarkest Lariat
MoveSparklngAriaSparkling Aria
MoveFloralHealngFloral Healing
MoveHighHorsepwrHigh Horsepower
MovePsychcTrrainPsychic Terrain
MoveRvlationDnceRevelation Dance
MoveCoreEnforcerCore Enforcer
MoveClngngScalesClanging Scales
MoveDragonHammerDragon Hammer
MovePsychicFangsPsychic Fangs
MoveStmpngTantrmStomping Tantrum
MovePrsmaticLasrPrismatic Laser
MoveSpectrlThiefSpectral Thief
MoveSnsteelStrkeSunsteel Strike
MoveMoongestBeamMoongeist Beam
MoveNatur’sMadnsNature’s Madness
MovePhotonGeyserPhoton Geyser
MoveSplishySplshSplishy Splash
MoveBouncyBubbleBouncy Bubble
MoveSparklySwirlSparkly Swirl
MoveVeeveeVolleyVeevee Volley
MoveDublIronBashDouble Iron Bash
MoveDynamxCannonDynamax Cannon
MoveFishiousRendFishious Rend
MoveClngrousSoulClangorous Soul
MoveBehemthBladeBehemoth Blade
MoveBehemothBashBehemoth Bash
MoveBreakngSwipeBreaking Swipe
MoveStrangeSteamStrange Steam
MoveFalsSurrendrFalse Surrender
MoveMeteorAssaltMeteor Assault
MoveExpandngForcExpanding Force
MoveShellSideArmShell Side Arm
MoveMstyExplsionMisty Explosion
MoveRisngVoltageRising Voltage
MoveTerrainPulseTerrain Pulse
MoveSkitterSmackSkitter Smack
MoveBrningJelosyBurning Jealousy
MoveCorrosiveGasCorrosive Gas
MoveDualWingbeatDual Wingbeat
MoveScorchngSndsScorching Sands
MoveJungleHealngJungle Healing
MoveSurgngStrkesSurging Strikes
MoveDragonEnergyDragon Energy
MoveFreezngGlareFreezing Glare
MoveThnderusKickThunderous Kick
MoveGlacialLanceGlacial Lance
MoveAstrlBarrageAstral Barrage
MovePsyshieldBshPsyshield Bash
MoveSprngtdeStrmSpringtide Storm
MoveMystcalPowerMystical Power
MoveMountainGaleMountain Gale
MoveVictoryDanceVictory Dance
MoveHeadlongRushHeadlong Rush
MoveBitterMaliceBitter Malice
MoveTripleArrowsTriple Arrows
MoveInfrnlParadeInfernal Parade
MoveCeaslessEdgeCeaseless Edge
MoveBlekwndStormBleakwind Storm
MoveWildbltStormWildbolt Storm
MoveSndsearStormSandsear Storm
MoveLunarBlessngLunar Blessing
MoveLastRespectsLast Respects
MoveSpicyExtractSpicy Extract
MovePoplatinBombPopulation Bomb
MoveRevivlBlesngRevival Blessing
MoveKowtowCleaveKowtow Cleave
MoveColisinCoursCollision Course
MoveElectroDriftElectro Drift
MoveChilReceptinChilly Reception
MoveChillingWatrChilling Water
MoveGigatonHammrGigaton Hammer
MoveBlazngTorqueBlazing Torque
MoveWickedTorqueWicked Torque
MoveNoxiusTorqueNoxious Torque
MoveCombatTorqueCombat Torque
MoveMagiclTorqueMagical Torque
MoveMatchaGotchaMatcha Gotcha
MoveTeraStarstrmTera Starstorm
MoveBurnngBulwrkBurning Bulwark
MoveMightyCleaveMighty Cleave
MoveTachyonCuttrTachyon Cutter
MoveAllurngVoiceAlluring Voice
MoveSuprcellSlamSupercell Slam
MovePsychicNoisePsychic Noise
MoveMalignntChanMalignant Chain
SpeciesDudunsprceDudunsparce
SpeciesCorvisquirCorvisquire
SpeciesCorviknighCorviknight
SpeciesBarraskewdBarraskewda
SpeciesCentiskorcCentiskorch
SpeciesPolteageisPolteageist
SpeciesStonjourneStonjourner
SpeciesMeowscaradMeowscarada
SpeciesSqawkabilySquawkabilly
SpeciesKilowatrelKilowattrel
SpeciesBrmblghastBrambleghast
SpeciesScreamTailScream Tail
SpeciesBruteBonetBrute Bonnet
SpeciesFluttrManeFlutter Mane
SpeciesSlithrWingSlither Wing
SpeciesSndyShocksSandy Shocks
SpeciesIronTreadsIron Treads
SpeciesIronBundleIron Bundle
SpeciesIronJugulsIron Jugulis
SpeciesIronThornsIron Thorns
SpeciesRoarngMoonRoaring Moon
SpeciesIronVliantIron Valiant
SpeciesWalkngWakeWalking Wake
SpeciesIronLeavesIron Leaves
SpeciesPtchageistPoltchageist
SpeciesFezndipitiFezandipiti
SpeciesGouginFireGouging Fire
SpeciesRagingBoltRaging Bolt
SpeciesIronBouldrIron Boulder
SpeciesCrabminablCrabominable
SpeciesBlacephalnBlacephalon
SpeciesBsculegionBasculegion
SpeciesFlechinderFletchinder
TypeFightFighting
TypeElectrElectric
TypePsychcPsychic
TypeStellrStellar

Version 1.9.4

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.9.4`.

🌋 IMPORTANT 🌋

  • This update integrates pret’s latest Makefile changes, which rearranges the entire file in order to speed up compilation times overall. If you did any changes to it (such as installing Poryscript) and are having issues resolving the conflicts, keep expansion’s version of Makefile and reapply your changes afterwards.

🧬 General 🧬

Fixed

  • Fixed alignment errors in EWRAM_INIT and friends when using u8, u16, etc. by @aronson in #5512
  • Update test LD script to respect 4 byte data section alignment by @aronson in #5517
  • Fixed Missing string_util.h include in mini_printf.c by @mrgriffin in #5572
  • Fixed unnecessary dependency scanning for test build and test rom names by @ravepossum in #5594
  • Fixed makefile: dependencies for map_group_count.h by @SBird1337 in #5648
    • Fixes an issue that caused the build to fail on updates to src/debug.c due to mismatched dependency.

🗺️ Overworld 🗺️

Changed

  • Followers sprite fixes by @Cafeei in #5669
  • Follower fixes, Melmetal, Patrat, Woobat by @hedara90 in #5685
  • Fixed Farfetch’d overworld sprite by @hedara90 in #5711

Fixed

  • Fixed Berry mutations always generating a Persim Berry by @Bassoonian in #5504

🐉 Pokémon 🐉

Changed

  • Changing EVO_NONE from 0xFFFE to 0 by @GhoulMage in #5547
    • There could be a case for out of bounds errors if arrays or iterations are happening where you’re using + 1 or - 1, as EVO_FRIENDSHIP used to be the first index although it started with 1.
  • PokeCommunity sprites batch (October) by @kittenchilly in #5655
  • Followers sprite fixes by @Cafeei in #5669
  • Follower fixes, Melmetal, Patrat, Woobat by @hedara90 in #5685
  • Fixed Farfetch’d overworld sprite by @hedara90 in #5711

Fixed

  • Fixed P_FRIENDSHIP_EVO_THRESHOLD not checking for Gen 8 by @kittenchilly in #5503
  • Fixed HGSS dex search printing wrong mon after selecting evos by @ravepossum in #5552
  • Fixed 64px uncompressed followers by @hedara90 in #5601
  • Deoxys Sprite/Animation Fixes by @SarnPoke in #5603
  • Fixes Aegislash not reverting back by @AlexOn1ine in #5734

⚔️ Battle General ⚔️

Changed

  • Fixed damage calc modifiers by @AlexOn1ine in #5604

Fixed

  • Fixed Shiny Pokemon not being shiny after transforming with a gimmick by @hedara90 in #5573
  • Handle showdowns apostrophe the same way as ASCII apostrophe by @cawtds in #5712
  • Fixes Misty Terrain displaying wrong message by @AlexOn1ine in #5742
  • Fixes Dynamax dynamic move type by @AlexOn1ine in #5739

🤹 Moves 🤹

Changed

  • Fixed damage calc modifiers by @AlexOn1ine in #5604
  • Updated ability popups for Skill Swap, Mummy/Lingering Aroma, Worry Seed, Simple Beam, fix Doodle/Role Play bugs by @PhallenTree in #5493

Fixed

  • Fixed Follow Me failing in Single Battles for Gen 6/7 config by @AsparagusEduardo in #5542
  • Fixed AnimTask_HorizontalShake uses for shaking screen in battle anims by @ghoulslash in #5562
  • Fixed weather genie move anims and Springtide Storm targets by @ravepossum in #5553
  • Fixes Magic Guard not preventing Salt Cure by @AlexOn1ine in #5583
  • Fixes Dragon Tail using the effect twice during a Parental Bond attack by @AlexOn1ine in #5630
  • Fixes Magic Coat message by @AlexOn1ine in #5645
  • Fixes Take heart by @AlexOn1ine in #5658
  • Fixed Floral Healing anim by @AlexOn1ine in #5733
  • Fixes Population Bomb / Triple Kick missing message by @AlexOn1ine in #5747
  • Changes Max Phantasm move anim script call by @AlexOn1ine in #5737
  • Fixes Partner targeting and Acupressure/Ally Switch interaction by @AlexOn1ine in #5446
  • Revival Blessing fixes + Using Lunar Blessing’s animation by @ghoulslash in #5490
  • Fixed curse + Protean interaction by @hedara90 in #5663
  • Added Minimize interaction to Supercell Slam by @hedara90 in #5713

🎭 Abilities 🎭

Changed

  • Fixed damage calc modifiers by @AlexOn1ine in #5604

Fixed

  • Adds tests and Costar fix from PR #5526 by @AlexOn1ine in #5529
  • Fixes Red Card / Eject Pack interaction with Emergency Exit by @AlexOn1ine in #5657
  • Fixed curse + Protean interaction by @hedara90 in #5663
  • Mimicry updates typing with RemoveAllTerrains() by @AERDU in #5666
  • Updated ability popups for Skill Swap, Mummy/Lingering Aroma, Worry Seed, Simple Beam, fix Doodle/Role Play bugs by @PhallenTree in #5493
  • Fixed curse + Protean interaction by @hedara90 in #5663
  • Fixes Ice Face regression by @AlexOn1ine in #5678
  • Fixes Neutralizing Gas crashes + adds missing interaction, Regenerator small fix by @PhallenTree in #5694

🧶 Items 🧶

Changed

  • Removes duplicate Booster Energy code by @AlexOn1ine in #5656

Fixed

  • Fixes Red Card / Eject Pack interaction with Emergency Exit by @AlexOn1ine in #5657
  • Fixes Red Card / Eject Pack interaction by @AlexOn1ine in #5724
  • Fixes gems triggering on confusion damage by @AlexOn1ine in #5723
  • Fixes Kee Maranga and Enigma Berry by @AlexOn1ine in #5727
  • Fixes Blunder Policy by @AlexOn1ine in #5722
  • Fixes Rusted Shield/Sword allowed to be Knocked Off from Zamazenta/Zacian by @iriv24 in #5750

🤖 Battle AI 🤖

Fixed

  • Fixed certain move data being cleared on turn end by @Pawkkie and @AlexOn1ine in #5488
  • Global is used instead of passed var by @AlexOn1ine in #5546
  • Fixes dynamicMoveType global not being reset during AI calcs by @AlexOn1ine in #5628

🧹 Other Cleanup 🧹

  • Remove one redundant call of SetAiLogicDataForTurn in DoBattleIntro by @AlexOn1ine in #5491
  • Cleanup extraneous function in battle_anim.h by @hedara90 in #5506
  • Add newline to move relearner string by @Bassoonian in #5523
  • Fixed 10,000,000 Volt Thunderbolt name by @AsparagusEduardo in #5533
  • Added constant to expansion inclusive copyright magic number by @pkmnsnfrn in #5413
  • Centralise AI Tests trainer name by @Bassoonian in #5532
  • Remove now outdated information from readme by @Bassoonian in #5548
  • Changing EVO_NONE from 0xFFFE to 0 by @GhoulMage in #5547
    • There could be a case for out of bounds errors if arrays or iterations are happening where you’re using + 1 or - 1, as EVO_FRIENDSHIP used to be the first index although it started with 1.
  • Shed Skin chance fix by @Pawkkie in #5558
  • Restore test file dependencies so they’re rebuilt properly by @ravepossum in #5617
  • Improve SEND_OUT error message; require Speed for all battlers by @mrgriffin in #5631
  • Removes duplicate Booster Energy code by @AlexOn1ine in #5656
  • Wrong assumtion in dauntless_shield.c by @AlexOn1ine in #5692

🧪 Test Runner 🧪

Added

  • Add curious medicine test by @ghoulslash in #5540
  • Tests: detect task leaks by @mrgriffin in #5528

Changed

  • Add text width tests for move, ability, item, and pokedex descriptions by @kittenchilly in #5505
  • Centralise AI Tests trainer name by @Bassoonian in #5532
  • Add basic Steam Engine, Guard Dog Tests by @ghoulslash in #5569
  • Fixed damage test by @GhoulMage and @mrgriffin for teaching me pokeemerald-expansion tests in #5574
  • Fallback memmem implementation by @mrgriffin in #5561
  • Hydra: Support %p in test summaries by @mrgriffin in #5626
  • Improve SEND_OUT error message; require Speed for all battlers by @mrgriffin in #5631
  • Check that PASSES_RANDOMLY affected a Random call by @mrgriffin in #5635
  • Wrong assumtion in dauntless_shield.c by @AlexOn1ine in #5692

Fixed

  • Update test LD script to respect 4 byte data section alignment by @aronson in #5517
  • Adds tests and Costar fix from PR #5526 by @AlexOn1ine in #5529
  • Fixed broken Starting Terrain test by @hedara90 in #5582

📚 Documentation 📚

  • Add changelog header in PR template to aid automation by @AsparagusEduardo in #5539
  • Added compressed OW mon VRAM notice in config file by @AsparagusEduardo in #5599
  • Update README.md to link to INSTALL.md by @Pawkkie in #5720
  • Fixes minor move desc errors by @AlexOn1ine in #5728

📦 Branch Synchronisation 📦

pret

  • 15th of October in #5527
    • Slight storage system documentation by @luckytyphlosion in pret#2024
    • Clean up defines lacking spaces by @Bassoonian in pret#2025
    • UB fix in battle_transition.c by @cawtds in pret#2007
    • preproc: support arbitrary expressions in enums by @mrgriffin in pret#2026
    • [Build System Rewrite] Refactored Makefile by @Icedude907 in pret#1950
    • Fixed incorrect point macros in contest_ai_script.inc by @NTx86 in pret#2028
    • [Build System Rewrite] Massive build speed improvement via scaninc changes by @Icedude907 in pret#1954
    • [Build System Rewrite] Improved audio rules by @Icedude907 in pret#1957
    • Update INSTALL.md to state that Windows 8 is no longer supported by Microsoft by @luciofstars in pret#2029
    • Update pull_request_template.md to include Discord username update by @luciofstars in pret#2030
    • remove ScriptContext_Enable from secret_base.h by @DizzyEggg in pret#2032
    • Remove gflib by @Kurausukun in pret#2033
    • Minor toolchain fixes by @GriffinRichards in pret#2031
    • Bugfix for cable car hikerGraphicsIds array by @Scyrous in pret#2039
    • Remove explicit symbol sizes in sym_common.txt by @GriffinRichards in pret#2038
    • Ignore mGBA screenshots by @Jaizu in pret#2041
    • Replaced copyright magic numbers in intro.c with constants by @pkmnsnfrn in pret#2035
    • Fixed typo: | should be || in Task_TryFieldPoisonWhiteOut by @AreaZR in pret#2044
    • [preproc] support C23 enum underlying type syntax by @mrgriffin in pret#2043
    • Fixed deleting files with dependency files by @mid-kid in pret#2045
    • Remove unnecessary looping for rule generation and unroll macros by @mid-kid in pret#2046
    • Get rid of common syms by @luckytyphlosion in pret#2040
    • Bugfix for cable car hikerGraphicsIds array by @Scyrous in pret#2039
    • UB fix in battle_transition.c by @cawtds in pret#2007
    • Fixed typo: | should be || in Task_TryFieldPoisonWhiteOut by @AreaZR in pret#2044
    • Get rid of common syms by @luckytyphlosion in pret#2040
    • Fixed incorrect point macros in contest_ai_script.inc by @NTx86 in pret#2028
  • 5th of November in #5644
    • Added define value for bard sound length by @fdeblasio in pret#2052
    • Silence ‘Nothing to be done for generated’ messages by @GriffinRichards in pret#2059
    • Lay out emerald version png horizontally by @GriffinRichards in pret#2062
  • 29 of November in #5736
    • Remove usage of gHeap in sSpritePalettes_ContestantsTurnBlinkEffect by @Lactozilla in pret#2064
    • BUGFIX: Fix Counter and Mirror Coat checking the wrong category by @surtr-games in pret#2066
    • Add TRY_DRAW_SPOT_PIXEL by @GriffinRichards in pret#2055
    • Added extra encoded character support by @AsparagusEduardo in pret#2050

merrp’s followers

  • Merrp merge (12th of October) by @Bassoonian in #5514
    • d80190fe105eee12bbf74ae29647ac909084d35c fix: Dig in Sealed Chamber no longer freezes follower.

New Contributors

  • @AERDU made their first contribution in #5666

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.9.3...expansion/1.9.4

Version 1.9.3

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.9.3`.

🌋 REFACTORS 🌋

📜 = Uses a migration script.

  • Converted settotemboost command to callnative in #5418
  • Removed unused RESOURCE_FLAG_TRACED in #5430
  • Changed MOVEEND_ defines to an enum in #5449

✨ Feature Branches ✨

merrp/aarant’s Followers

Fixed

  • Fixed Expansion-exclusive issue that caused trainers to not play their “pointing” animation when Followers were out during battle intro by @kittenchilly in #5406

⚔️ Battle General ⚔️

Changed

  • Improved Mega evolution animation to make it a little smoother by @kleenxfeu in #4816

Fixed

  • Fixed affection check for exp multiplier by @Bassoonian in #5421
  • Fixed multiple Primal Reversions not occurring if multiple battlers fainted on the previous turn by @PhallenTree in #5430

🤹 Moves 🤹

Added

  • Added missing B_AFTER_YOU_TURN_ORDER config by @PhallenTree in #5400
    • Gen 5-7: After You fails if the order remains the same after using After You.
    • Gen 8+: After You no longer fails if the turn order remains the same after using After You.
  • Added missing B_QUASH_TURN_ORDER config by @PhallenTree in #5400
    • Gen 5-7: If multiple Pokémon are affected by Quash, they move in the order they were affected by Quash.
    • Gen 8+: If multiple Pokémon are affected by Quash, they now move fastest to slowest.
  • Added missing updated B_UPDATED_CONVERSION_2 by @wiz1989 in #5453
    • Gens 2-4: Conversion 2 changes the user’s type to a type that is resistant/immune to the last move the user was hit by.
    • Gen 5+: Conversion 2 changes the user’s type to a type that resists the last move used by the selected target.

Fixed

  • Fixed Scale Shot corrupting the move used on the next turn by @AlexOn1ine in #5397
  • Fixed Growth’s description not being updated based on B_GROWTH_STAT_RAISE by @nescioquid in #5398
  • Fixed Quash not updating the battlers’ actions correctly by @PhallenTree in #5400
    • Cleanup by @PhallenTree in #5430
  • Fixed Snatched Swallow not recovering HP if the Snatcher is not under the effect of Stockpile (should still heal) by @PhallenTree in #5430
  • Fixed Counter users being damaged by Spiky Shield by @AlexOn1ine in #5402
  • Fixed Electrified Dragon Darts not correctly avoiding targets with ability immunity (Volt Absorb, Motor Drive) by @PhallenTree in #5430
  • Fixed Trace not activating a switch-in ability it traces (eg. Intimidate) by @PhallenTree in #5430
    • Removed unused RESOURCE_FLAG_TRACED.
  • Fixed recoil damage not triggering healing berries by @AlexOn1ine in #5449
    • Also changed MOVEEND_ defines to an enum.

🎭 Abilities 🎭

Fixed

  • Fixed Dancer activating even if the dance move is stolen by Snatch by @PhallenTree in #5430
  • Fixed Ability popup when multiple Pokémon faint at the same time by @PhallenTree in #5430
  • Multiple ability fixes by @PhallenTree in #5447
    • Fixed Protosynthesis/Quark Drive sometimes not activating ability popup despite still gaining the boost as they should.
    • Fixed Protosynthesis/Quark Drive activating on Transformed battlers.
    • Fixed Protosynthesis activating despite Cloud Nine being present on the field.
    • Fixed Quark Drive not activating if the battler is not grounded.
    • Fixed Protosynthesis/Quark Drive/Beast Boost stat raise priority when multiple stats are tied for the highest one.
      • Before: Attack, Defense, Speed, Special Attack, Special Defense.
      • After: Attack, Defense, Special Attack, Special Defense, Speed.

🧶 Items 🧶

Fixed

  • Fixed Ogerpon’s Masks not increasing the power of moves by 20% by @AlexOn1ine in #5391
  • Fixed Jubilife Muffin not working by @kittenchilly in #5444
  • Fixed duplicating flute bug in double battles by @ghoulslash in #5436

🤖 Battle AI 🤖

Fixed

  • Fixed Trick/Switcheroo giving AI score even if the opponent has no held item by @kittenchilly in #5412
  • Various AI fixes in AI_CalcMoveEffectScore by @ghoulslash in #5474
    • Missing break from EFFECT_ABSORB switch case.
    • Using last used move for Mirror Move instead of predicted move.

🧹 Other Cleanup 🧹

Changed

Fixed

  • Fixed potential uninitialized behavior in ChangeOrderTargetAfterAttacker by @AlexOn1ine in #5393
  • Fallback on default BW map pop-up theme to reduce potential for error by @ravepossum in #5392
  • Multiple typo fixes by @nescioquid in #5398
  • VS Seeker documentation fix by @Bassoonian in #5415

🧪 Test Runner 🧪

Added

  • Added missing After You and Quash tests by @PhallenTree in #5400

Changed

  • Improved Tangling Hair test to make sure that chained effects do not overwrite relevant battler IDs by @ghoulslash in #5423
  • Improved Full Heal item tests by @kittenchilly in #5444

Fixed

New Contributors

  • @nescioquid made their first contribution in #5398
  • @kleenxfeu made their first contribution in #4816
  • @wiz1989 made their first contribution in #5453

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.9.2...expansion/1.9.3

Version 1.9.2

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.9.2`.

🌋 REFACTORS 🌋

📜 = Uses a migration script.

  • Remove unused BattleScript_WindPowerActivatesEnd2 in #5257
  • Refactored in-battle disobedience to fix bug in #5245

💥 Hardlock/Softlock/Crash/Compiling fixes 💥

  • Fixed hardlock when Hyperspace Fury is used by Hoopa Unbound by @AlexOn1ine in #5237
  • Fixed compile error when OW_POKEMON_OBJECT_EVENTS is TRUE but P_HISUIAN_FORMS is FALSE around Basculin by @hjk321 in #5256
  • Fixed hardlock when the AI cannot choose moves due to its opponent having Wonder Guard by @Pawkkie and Wiz in #5317
  • Fixed multiple Pledge move hardlocks
    • Fixed potential hardlock when attempting to use Pledge moves on the same turn that the user would wake up by @PhallenTree in #5330
    • Fixed hardlock when the opponent’s combo doesn’t happen when cancelled by sleep by @hedara90 and @PhallenTree in #5339
    • Fixes hardlock when the opponent’s combo doesn’t happen when cancelled by freeze by @PhallenTree in #5340
    • Fixed hardlock when the opponent’s combo doesn’t happen when cancelled by Powder by @hedara90 in #5341

🧬 General 🧬

Fixed

  • Fixed loading into the wrong version of a map after saving in areas with multiple layouts by @hedara90 in #5347

🐉 Pokémon 🐉

Added

  • Added OVERWORLD_SET_ANIM macro to allow using custom animation tables for Overworld Pokémon by @hedara90 in #5309
    • Added asymetrical Farfetch’d sprites using a previously unused table from merrp’s followers branch.
  • Added unique sprites for overworld Pumpkaboo and Gourgeist forms by @hedara90 in #5390
  • Added missing Sirfetch’d competitive alias (SPECIES_SIRFETCH_D) by @cawtds in #5283
  • Added Paldean Wooper and Clodsire overworld sprites by @Cafeei in #5277
  • Added missing Gen 9 Overworld sprites by @Liamjd14 in #5304
  • Added missing overworld sprites by @Liamjd14 in #5336
    • New Sprites:
      • Oricorio Pom Pom/Pa’U/Sensu, Zygarde 10%/Complete and Original Color Magearna
        • Credits to: Princess-Phoenix, Larryturbo, Kidkatt, Zender1752 and SageDeoxys.
      • Black/White Kyurem
        • Credits to: Larryturbo.
      • Shaymin Sky and Therian Tornadus/Thundurus/Landorus
        • Credits to: @Liamjd14
    • Using their base form’s sprites
      • Totem Raticate/Mimikyu/Marowak and Partner Pikachu/Eevee
  • Added Added asymmetrical overworld sprites by @Liamjd14 in #5336
    • Slowbro (Galarian), Tinkatink, Tinkatuff, Tinkaton and Scovillain
    • Enabled in gSpeciesInfo by @Liamjd14 in #5385

Changed

  • Improved Garganacl and Naclstack battle sprites by using the ones from @CyanSMP64’s repo by @kittenchilly in #5142
  • Improved both shiny Indeedee by @Cafeei in #5285
  • Shiny Combusken now uses its Gen8+ palette by @Cafeei in #5333

Fixed

  • Reenabled unused female Indeedee overworld sprite by @Cafeei in #5285
  • Fixed G-Max Corviknight and Centiskorch’s expanded names by @PhallenTree in #5296
  • Fixed G-Max Cinderace back sprite by @hedara90 in #5295
  • Fixed Shiny Mothim’ by @Cafeei in #5333
  • Fixed multiple battle sprite issues by @kittenchilly in #5142
    • Sprite issues:
      • Bombirdier, Mega Absol/Aerodactyl/Latias/Latios/Salamence, Orthworm and Veluza.
    • Shiny issues:
      • Bombirdier, Kilowattrel, Landorus, Magearna, Mega Diancie/Medicham, Galarian Ponyta, Shroodle, Spidops and Wattrel.
  • Fixed multiple overworld Pokémon sprites - Part 1 by @Cafeei in #5241
    • “Blinking pixels”:
      • Dwebble, Krookodile, Servine, Throh and Vulpix.
    • Shiny Palettes
      • Crustle, Excadrill, Lillipup, Serperior, Servine, Sigilyph, Swoobat, Tranquil and Venipede.
    • Misc fixes:
      • Archen, Basculin, Blitzle, Crustle, Escavalier, Krokorok, Krookodile, Sawsbuck, secondary, Serperior, Snivy, Throh, Woobat, Zebstrika
  • Fixed multiple overworld Pokémon sprites - Part 2 by @Cafeei in #5333
    • Palette Fixes:
      • Shiny Riolu/Snover, Oshawott, Kabutops, Shieldon, Kingler and Groudon.
    • Fixed “Blinking pixels”:
      • Abomasnow, Aggron, Alakazam, Ariados, Articuno, Azumarill, Barboach, Bayleef, Bibarel, Blastoise, Celebi, Charmeleon, Cherrim, Chinchou, Cloyster, Corphish, Corsola, Crawdaunt, Cubone, Dewott, Doduo, Dusknoir, Electabuzz, Espeon, Exeggcute, Farfetch’d, Feraligatr, Flaafy, Flareon, Floatzel, Furret, Gastly, Girafarig, Giratina, Gligar, Gloom, Golbat, Grumpig, Hariyama, Heatran (just reduced), Hoppip, Jolteon, Jumpluff, Kricketot, Larvitar, Leafeon, Lileep, Lumineon, Luxio, Luxray, Machamp, Magneton, Mantine, Mantyke, Marowak, Meowth, Mesprit, Mew, Mewtwo, Mime Jr, Moltres, Numel, Oshawott, Phione, Pinsir, Politoed, Porygon-Z, Probopass, Quilava, Qwilfish, Rampardos, Rapidash, Regirock, Sceptile, Scizor, Seel, Shieldon, Shiftry, Slowking, Smoochum, Sneasel, Spheal, Steelix, Sudowoodo, Suicune, Swellow, Swinub, Tentacruel, Togekiss, Togepi, Vaporeon, Vibrava, Wartortle, Wooper, Yanma, Yanma, Yanmega, Zangoose, Zapdos, Zubat
    • Misc. Sprite Fixes: Dewott, Misdreavus, Oshawott, Torkoal and Victini.
  • Overworld sprite fixes by @Liamjd14 (with help from @hedara90 to solve conflicts) in #5334
    • Palette Fixes: Shieldon.
    • Misc. Sprite Fixes Torkoal.
    • “Blinking pixels”:
      • Ambipom, Armaldo, Crawdaunt, Crobat, Donphan, Flaaffy, Flygon, Grovyle, Hoppip, Igglybuff, Illumise, Jumpluff, Ledian, Ledyba, Mamoswine, Mantine, Marshtomp, Meganium, Mightyena, Miltank, Numel, Prinplup, Raikou, Roserade, Skarmory, Skiploom, Spinarak, Staraptor, Stunky, Torkoal, Wooper, Xatu, Yanma
  • Overworld Pokémon sprite changes by @Liamjd14 in #5336
    • Fixed “blinking pixels”: * Alolan Graveler/Golem/Alolan/Ninetales * Dawn Wings Necrozma * Hisuian Growlithe/Arcanine * Winter Sawsbuck
    • Added missing Shiny Palettes
      • Calyrex Ice/Shadow Rider, Origin Dialga/Palkia, White-Striped Basculin, Therian Enamorus and Low-Key Toxtricity.
    • Removed Gigantamax Low-Key Toxtricity using base Low-Key follower sprites.
    • Fixed Shiny palettes
      • Alolan Marowak/Raichu, Eternal Flower Floette, Flabébé (All), Galarian Ponyta/Rapidash
      • Typhlosion-Hisui follower shiny stomach color wrong - done
    • Other sprite/palette fixes
      • Alolan Exeggutor/Marowak/Persian/Raichu/Sandshrew, Hisuian Sligoo/Goodra and Winter Sawsbuck.

⚔️ Battle General ⚔️

Changed

  • Updated Damage Category icons to match Gen6+ colors by @kittenchilly in #5080

Fixed

  • Fixed Slateport Battle Tent/Battle Factory issues by @SarnPoke in #5281
    • Choosing the “SWAP” option no longer shows invalid Pokémon (“??????????”).
    • Reloading after choosing “REST” no longer resets the player’s challenge party to invalid Pokémon (“??????????”).
  • Fixed Starting Status happening Wild Battles from a previous Trainer Battle by @PhallenTree in #5248
  • Fixed bugged behavior caused by Z-Moves and disobedience by @hedara90 in #5245
  • Fixed Entry Hazards targeting wrong side of the field if the opponent fainted by @PhallenTree in #5262
  • Fixed being able to use multiple of the same Gimmick in Double Battles by @AgustinGDLV in #5235
  • Fixed Terastallization not granting immunity to Tar Shot by @AlexOn1ine in #5302
  • Fixed Cmd_trainerslidein/out using the incorrect function by @ghoulslash in #5326
    • Cleanup by @hedara90 in #5344

🤹 Moves 🤹

Added

  • Added Charge’s Gen 9 behavior via B_CHARGE config by @AlexOn1ine in #5274
  • Added Powder’s Gen 7+ behavior of not causing damage when under Heavy Rain via B_POWDER_RAIN by @PhallenTree in #5370

Fixed

  • Fixed move descriptions missing periods (Decorate, Collision Course, Electro Drift) by @Pawkkie and Kasen in #5221
  • Fixed Confide not being blocked by Crafty Shield interaction by @hedara90 in #5202
  • Fixed message for switch out moves by @kittenchilly in #5258
  • Fixed Ice Fang’s descriptions using the opposite of what they’re supposed to do based on B_USE_FROSTBITE by @laserXdolphin in #5273
  • Fixes to Instruct by @PhallenTree in #5262
    • Fixed Instruct bypassing AtkCanceler checks (Instruct allowed the target to act while asleep, flinched, etc.) and its interaction with First Turn Only moves (Fake Out, First Impression, Mat Block).
    • Fixed Instruct’s animation using the attacker and target of the called move.
  • Fixed Scale Shot’s effect not activating if the opponent fainted before all hits finished by @AlexOn1ine in #5292
  • Fixed Round not preserving turn order for non-Round users if there’s a switch out at the beginning of the turn by @AlexOn1ine in #5292
  • Fixed Max Moves ignoring absorbing abilities (+ test) by @PhallenTree in #5296
  • Fixed attack string for Max Moves not being printed if it’s blocked by Max Guard by @hedara90 in #5312
  • Fixed some Pledge move combo issues by @PhallenTree in #5330
    • Fixed Pledge move combos attempting to be executed multiple times in a turn, causing mons to decrement sleep timer multiple times during the turn or causing infinite loops.
  • Fixed potential issue with custom non-sound moves that use EFFECT_ATTACK_UP_USER_ALLY or EFFECT_PERISH_SONG being blocked by Soundproof anyway by @AlexOn1ine in #5301
  • Fixed Pledge combinations not being absorbed by absorption Abilities (Sap Sipper, Storm Drain, etc.) by @hedara90 in #5364
  • Fixed Toxic Thread decreasing speed by 2 stages instead of 1 by @AsparagusEduardo in #5369
  • Fixed Destiny Bond not working if the user was fainted by a multi-Hit move’s non-first hit by @AlexOn1ine in #5377
  • Fixed Powder interactions by @PhallenTree in #5370
    • Fixed Magic Guard not protecting against Powder’s secondary damage when using a Fire-type move.
    • Fixed Fire/Water Pledge combination being cancelled by Powder.
    • Fixed Fire Z-Moves not playing their animations and not granting their secondary effects when the user is under Powder’s effect
  • Fixed After You/Shell Trap not updating battlers’ actions correctly by @PhallenTree in #5384

🎭 Abilities 🎭

Fixed

  • Fixed weather abilities not activating when Cloud Nine user leaves the field by @AlexOn1ine in #5209
  • Fixed missing break for Poison Puppeteer’s code by @u8-Salem in #5243
  • Fixed Pokémon with Purifying Salt being poisoned by Toxic Spikes by @AlexOn1ine in #5252
  • Fixed Parental Bond not affecting Snore by @hedara90 in #5264
  • Fixed Tera Shift’s description by @AsparagusEduardo in #5351

🧶 Items 🧶

Fixed

  • Fixed berries missing their timing after passive damage by @AlexOn1ine in #5300
  • Fixed Micle Berry not increasing accuracy on the next turn by @AlexOn1ine in #5358

🤖 Battle AI 🤖

Changed

  • AI is encouraged to use “always crit” moves on partner with Anger Point by @SarnPoke in #5244

Fixed

  • Fixed AI not seeing the power of Max Moves by @AlexOn1ine in #5299
  • Fixed minor wrong order in AI_CalcDamage that made Nature Power not be considered for Z-Moves by @AlexOn1ine in #5155
  • Fixed AI not considering Tera Blast/Tera Storm by @AlexOn1ine in #5155
  • Fixed AI_IsMoveEffectInPlus reading the incorrect stat for secondary effects that reduce stats by 2 stages by @ghoulslash and @Pawkkie in #5366

🧹 Other Cleanup 🧹

Changed

  • Remove unused BattleScript_WindPowerActivatesEnd2 signature by @u8-Salem in #5257
  • Replaced all usages of tabs in C files with spaces by @hedara90 in #5261
  • Fixed missing breaks in two ENDTURN cases by @ghoulslash in #5350
  • ShouldSwitchIfWonderGuard cleanup by @Pawkkie in #5383

🧪 Test Runner 🧪

Added

  • Added missing Adaptability, Aerilate, Aftermath tests by @kittenchilly in #5242
  • Added missing Disguise tests by @hedara90 in #5249
  • Added some missing Instruct tests by @PhallenTree in #5262
  • Added missing Powder tests by @PhallenTree in #5370
  • Added ShouldSwitchIfWonderGuard AI tests by @Pawkkie in #5383

Changed

  • Moved ASSUMEs to inside GIVEN blocks to prevent them from being added correctly to the totals in the test summary by @AsparagusEduardo in #5308

📚 Documentation 📚

Fixed

  • Fixed test system documentation saying that make check TESTS="Spikes" could be done with single quotes instead of double quotes by @AsparagusEduardo in #5266

📦 Branch Synchronisation 📦

pret’s base pokeemerald

  • N/A

merrp/aarant’s followers

New Contributors

  • @laserXdolphin made their first contribution in #5273
  • @Liamjd14 made their first contribution in #5304

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.9.1...expansion/1.9.2

Version 1.9.1

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.9.1`.

🌋 REFACTORS 🌋

  • Removed ENDTURN_RETALIATE in #5182
  • Removed ENDTURN_WEATHER_FORM and allowedToChangeFormInWeather in #5171

🧬 General 🧬

Added

  • Move Relearner UI now displays move category by @kittenchilly in #5081

Fixed

  • Fixes wrong padding field in SpeciesInfo struct by @AlexOn1ine in #5139
  • Fixed specific tiles changing to PC tiles when using Box Link/Debug PC option by @cawtds in #5141

🐉 Pokémon 🐉

Fixed

  • Fixed stray transparent pixels in Urshifu sprites by @hedara90 in #5071
  • Fixed bufferspeciesname not working for species IDs over 1023 by @SBird1337 in #5088
  • Fixed overworld Pokémon breaking for species IDs above 1535 by @hedara90, @mrgriffin and @SarnPoke in #5179
  • Fixed overworld palettes for multiple species by @hedara90 in #5107
    • Dialga Origin (Normal and Shiny)
    • Palkia Origin (Normal and Shiny)
    • Giratina Origin (shiny palette fixed by @hedara90 in #5108)
    • Xerneas Neutral/Active (Normal and Shiny)
    • Enamorus Incarnate/Therian (Normal and Shiny)
  • Fixed/added missing Pokémon sprites and palettes by @Cafeei in #5126
    • Overworld:
      • Shiny Sneasler, Morelul, Bounsweet, Bruxish, Guzzlord, Regieleki, Zacian, Zamazenta
      • Hisuian Zorua sprite
      • Shiny Summer Sawsbuck
      • Shiny Galarian Yamask, Darumaka, Zigzagoon, Zapdos, Ponyta, Rapidash, Slowpoke, Farfetch’d, Weezing, Mr. Mime, Articuno, Moltres, Slowking, Stunfisk, Darmanitan
      • Shiny Hisuian Sneasel, Qwilfish, Samurott,
    • Battle sprites:
      • Shiny Sneasler, Cursola, Pincurchin, Runerigus
      • Shiny Galarian Yamask, Darumaka
  • Fixed Unown Overworld follower sprites by Sarn by @hedara90 in #5146

⚔️ Battle General ⚔️

Changed

  • Set new animation particles by default to off by @AlexOn1ine in #5161

Fixed

  • Fixed speed ties by @mrgriffin in #4780
    • Cleanup by @hedara90 in #5092
  • Fixed Defiant/Competitive not working after the battler enters the field with a Court Changed Sticky Web on its side of the field by @PhallenTree in #5093
  • Fixed trainerproc not properly parsing line markers, which caused erroring lines to be offset by @mrgriffin in #5122
  • Fixed initial Zigzagoon battle being able to use a Gimmick by @AlexOn1ine in #5129
  • Fixed incorrect rounding when maxHP is lower than 16 by @hedara90 in #5183
    • This caused these Pokémon to not be hurt by Sandstorm/Hail.
  • Fixes UB in Cmd_averagestats by @mrgriffin and @AlexOn1ine in #5191

🤹 Moves 🤹

Added

  • Added move animations for multiple moves by @TheTrueSadfish in #5159
    • Spin Out, Mortal Spin, Fillet Away, Flower Trick, Make It Rain, Shed Tail, Hyper Drill, Twin Beam, Comeuppance, Blood Moon, Fickle Beam, Thunder Clap, Hard Press, Dragon Cheer, Malignant Chain.
    • Purple chains by ogwon on Discord, beam by @TheTrueSadfish and livra on Discord.

Changed

  • Adjusted Raging Bull’s animation to include Brick Break’s wall break effect by @TheTrueSadfish in #5159

Fixed

  • Fixed non-grass Ivy Cudgel breaking battle UI by @hedara90 in #5117
  • Fixes Stomping Tantrum effect not doubling power in certain situations by @AlexOn1ine in #5140
  • Fixed Fickle Beam’s description by @PhallenTree in #5093
  • Fixed Revelation Dance interactions with Z-Move, Roost and typeless mons by @PhallenTree in #5133
  • Fixes Poltergeist missing its accuracy check by @AlexOn1ine in #5168
  • Fixed Fickle Beam not showing its message by @TheTrueSadfish in #5159
  • Fixed Retaliate not working correctly if the party member fainted via passive damage during end of turn by @hedara90 in #5182
  • Fixed Flame Burst’s passive damage being based off current HP rather than Max HP by @hedara90 in #5182
  • Fixed using Population Bomb with Loaded Dice printing garbage text by @kittenchilly in #5195

🎭 Abilities 🎭

Added

  • Added in-battle effect of Pickup by @PhallenTree in #5170

Fixed

  • Fixes Purifying Salt not halving damage for dynamic move types by @AlexOn1ine in #5145
  • Fixed Dancer-called moves not changing their type based on the new user by @PhallenTree in #5133
  • Fixed Ice Face not regenerating after switching in during Hail/Snow by @hedara90 in #5171
  • Fixed Wind Rider not activating when switched in while Tailwind is active on the user’s side of the field activation and tests by @PhallenTree in https://github.com/rh-hideout/pokeemerald-expansion/pull/5207

🧶 Items 🧶

Added

  • Added Dowsing Machine’s expanded name by @kittenchilly in #5134

Fixed

  • Fixes Booster Energy not increasing speed by @AlexOn1ine in #5167

🤖 Battle AI 🤖

Changed

  • Adjusted AI calculation for Triple Kick Effect by @AlexOn1ine in #5127

Fixed

  • Fix Switch AI Bug: AI never switching out when it could be OHKO’d by @Pawkkie in #5089
  • Adds missing AI checks for poltergeist by @AlexOn1ine in #5189

🧹 Other Cleanup 🧹

  • IsValidForBattle function formatting by @AlexOn1ine in #5085
  • Opportunist/Mirror Herb cleanup by @AlexOn1ine in #5120
    • Cleanup by @AlexOn1ine in #5158
  • Remove trailing whitespace (master) by @AsparagusEduardo in #5174

🧪 Test Runner 🧪

Added

Changed

  • Fixed G-Max Replenish not considering Gen 5+ Pickup by @PhallenTree in #5170

Fixed

  • Fixed RandomUniformExcept not being exclusive on the higher boundary by @PhallenTree in #5170

📚 Documentation 📚

  • Added guide to running documentation website locally by @AsparagusEduardo in #5059
  • How to docs and fixes to be added to the mdbook documentation site by @anrichtait in #5070
  • Improved 1.8 ⇒ 1.9 non-Competitive syntax migration instructions by @mrgriffin in #5079

📦 Branch Synchronisation 📦

pret’s base pokeemerald

  • 5th of August in #5098
    • Fixed bottom half of Mt. Pyre not being labeled in PokeNav by @fdeblasio in pret#2018
  • 7th of August in #5116
    • Changed type1 and type2 to be consistent by @pkmnsnfrn in pret#2021
  • 14th of August in #5165
    • Fix type for offset in MapConnection by @GriffinRichards in pret#2011

merrp/aarant’s followers

  • 7th of August in #5110
    • Fixed expanded OW IDs by @pkmnsnfrn in aarant#38
    • Fix two small text errors in follower dialogue by @Bassoonian in aarant#39

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.9.0...expansion/1.9.1

New Contributors

Version 1.9.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.9.0`.

🌋 REFACTORS 🌋

📜 = Has a migration script.

🧬 General 🧬

Added

Changed

Fixed

✨ Feature Branches ✨

merrp/aarant’s Followers

Changes from the original branch

  • Follower Pokémon can be enabled using the OW_FOLLOWERS_ENABLED config.
  • Pokémon NPCs can be added to a map independently from the Followers config. Keep in mind, this requires OW_POKEMON_OBJECT_EVENTS to be enabled in order to add the graphics to the ROM.
  • Moved original configs from include/constants/event_objects.h to include/config/overworld.h and renamed them:
    • OW_MON_BOBBING -> OW_FOLLOWERS_BOBBING
    • LARGE_OW_SUPPORT -> OW_LARGE_OW_SUPPORT
    • OW_MON_POKEBALLS -> OW_FOLLOWERS_POKEBALLS
  • Added follower Pokémon sprites from Gen 4-8
    • Credits to @Eemeliri and Gerben BSc
  • Moved OW_GFX_COMPRESS from include/global.h to include/config/overworld.h.
  • Added OW_SUBSTITUTE_PLACEHOLDER config to hide followers if they don’t have a follower sprite instead of using a placeholder Substitute sprite by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/4765
  • Follower graphics are shown in the Pokémon Sprite Visualizer.
  • Follower graphics have been moved to the respective species graphics folder instead of all being grouped in graphics/object_events/pics/pokemon.
    • Eg: graphics/object_events/pics/pokemon/abomasnow.png was moved to graphics/pokemon/abomasnow/follower.png.
  • Follower data has been moved to gSpeciesInfo
    • Their palettes are separate from the battle sprite palettes
      • Can be enabled using OW_FOLLOWERS_SHARE_PALETTE, but requires manual sprite adjustements. For now, it’s recommended to keep this FALSE. (They don’t use much space anyway)
  • Updated GetTypeEffectiveness used by follower messages to account for new abilities with type immunities.
  • Cleaned up code style to match pret/expansion’s.
  • Reverted Regi’s sprite to vanilla’s.
  • Follower PicTables use overworld_ascending_frames macro.
  • Removed unneeded calls to bufferspeciesname.
  • Removed MON_DATA_NATURE.
  • Removed debug functions like IsAccurateGBA.
  • Removed ScrCmd_callfunc to use callnatives instead

🐉 Pokémon 🐉

Added

Changed

⚔️ Battle General ⚔️

Added

Changed

Fixed

  • Fixed Dynamax data not clearing when a battler faints by @WillKolada in https://github.com/rh-hideout/pokeemerald-expansion/pull/4672
  • Multiple Z-Move fixes by @AgustinGDLV in https://github.com/rh-hideout/pokeemerald-expansion/pull/4449
    • Fixed Z-Moves not working in Link Battles, recorded battles and tests.
    • Fixed Z_EFFECT_ALL_STATS_UP functionality.
    • Fixed Z-Nature Power, Z-Copycat, Z-Me First, and Z-Sleep Talk incorrectly using a normal move and not a Z-Move, which had not been raised as an issue yet. (some of these were caught recently!)
    • Fixed Breakneck Blitz incorrectly being affected by -ate abilities, which had not been raised as an issue yet.
    • Fixed Instruct incorrectly not failing if the target last used a Z-Move, which had not been raised as an issue yet.
    • Fixed Guardian of Alola incorrectly doing 50% of the target’s HP instead of 75%.
  • Fixed Enemy Data not clearing at the end of battles by @ghoulslash in https://github.com/rh-hideout/pokeemerald-expansion/pull/4867

🤹 Moves 🤹

Added

Changed

  • EFFECT_TRIPLE_KICK’s base power uses the move’s strikeCount instead of a constant by @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4608
    • This allows users to create “Quadruple Kick” and similar moves.
  • Migrated move animation pointers to gMovesInfo by @cawtds in https://github.com/rh-hideout/pokeemerald-expansion/pull/4683
    • This removes the need for gBattleAnims_Moves which had potential ordering issues if not kept in line with move IDs.
      • If battleAnimScript is not defined for a move, it defaults to Tackle’s animation.
    • Migration script available in migration_scripts/battle_anim_moves_refactor.py

Fixed

🎭 Abilities 🎭

Added

Changed

Fixed

🧶 Items 🧶

Added

Changed

🤖 Battle AI 🤖

Added

Changed

Fixed

🧹 Other Cleanup 🧹

Changed

🧪 Test Runner 🧪

Added

Changed

Fixed

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.8.6...expansion/1.9.0

Version 1.8.6

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.8.6`.

🌋 REFACTORS 🌋

🧬 General 🧬

Fixed

🐉 Pokémon 🐉

Added

Changed

Fixed

⚔️ Battle General ⚔️

Fixed

  • Fixed Debug Menu not properly updating the corresponding flags + general cleanup by @kittenchilly in https://github.com/rh-hideout/pokeemerald-expansion/pull/4643
  • Fixed spread damage in double battles by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/5064
    • In double battles when B_POSITION_OPPONENT_LEFT fainted from the first hit of a spread move, the second hit dealt 100% of damage to B_POSITION_OPPONENT_RIGHT.
  • Removed unused Battle Script labels by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/4839

    • data/battle_scripts_1.s
      • BattleScript_OctolockTryLowerDef
      • BattleScript_OctolockTurnDmgPrintMsg
      • BattleScript_StuffCheeksEatBerry
      • BattleScript_StrengthSapTryHp and its contents.
      • BattleScript_PartingShotEnd and its contents.
      • BattleScript_RototillerAffected
      • BattleScript_AutotomizeDoAnim
      • BattleScript_TryTailwindAbilitiesLoop_Ret
      • BattleScript_HitFromAtkCanceler
      • BattleScript_EffectMultiHit
      • BattleScript_BattleScript_EffectParalyzeNoTypeCalc
      • BattleScript_EffectTeleportTryToRunAway
      • BattleScript_WindPowerActivates_Ret
      • BattleScript_CottonDownReturn
      • BattleScript_ActivateWeatherAbilities_Increment
      • BattleScript_IntimidateEnd
      • BattleScript_SupersweetSyrupEnd
      • BattleScript_ActivateTerrainEffects_Increment
      • BattleScript_GrassyTerrainHpChange
      • BattleScript_GrassyTerrainLoopEnd
      • BattleScript_AbilityNoSpecificStatLossPrint
      • BattleScript_ArenaNothingDecided
      • BattleScript_ExtremeEvoboostAtk
      • BattleScript_BerserkGeneRet_Anim
    • data/battle_scripts_2.s
      • BattleScript_PrintCaughtMonInfo
  • Opportunist/Mirror Herb Refactor by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4928

    • Multiple fixes:
      • Opportunist stacking multiple boosts in one turn from opposing mons.
      • Increasing the stat by the wrong amount when copying opposing boost (eg. +6 boosts).
      • Opportunist no longer has a message.
      • Opportunist only play animations once for every stat boost.
    • Changes:
      • switchInBattlerCounter replaces both switchInAbilitiesCounter and switchInItemsCounter.
      • Removed STRINGID_OPPORTUNISTCOPIED and sText_OpportunistCopied.
      • Altered TryDoEventsBeforeFirstTurn to use a state switch (gBattleStruct->eventsBeforeFirstTurnState)
        • FIRST_TURN_EVENTS_START.
        • FIRST_TURN_EVENTS_OVERWORLD_WEATHER.
        • FIRST_TURN_EVENTS_TERRAIN.
        • FIRST_TURN_EVENTS_STARTING_STATUS.
        • FIRST_TURN_EVENTS_TOTEM_BOOST.
        • FIRST_TURN_EVENTS_NEUTRALIZING_GAS.
        • FIRST_TURN_EVENTS_SWITCH_IN_ABILITIES.
        • FIRST_TURN_EVENTS_OPPORTUNIST_1.
        • FIRST_TURN_EVENTS_ITEM_EFFECTS.
        • FIRST_TURN_EVENTS_OPPORTUNIST_2.
        • FIRST_TURN_EVENTS_END.

🤹 Moves 🤹

Added

Fixed

🎭 Abilities 🎭

Fixed

🧶 Items 🧶

Fixed

🤖 Battle AI 🤖

Documentation

Fixed

🧹 Other Cleanup 🧹

Fixed

🧪 Test Runner 🧪

Added

Changed

Fixed

📦 Pret merges 📦

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.8.5...expansion/1.8.6

Version 1.8.5

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.8.5`.

🌋 IMPORTANT CHANGES AND REFACTORS 🌋

💥 Softlock/Crash fixes 💥

🧬 General 🧬

Added

Fixed

🐉 Pokémon 🐉

Changed

Fixed

⚔️ Battle General ⚔️

Fixed

🤹 Moves 🤹

Fixed

🎭 Abilities 🎭

Added

Fixed

🧶 Items 🧶

Changed

Fixed

🤖 Battle AI 🤖

Changed

Fixed

🧪 Test Runner 🧪

Added

Changed

  • Multiple changes by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/4682
    • Renamed some Baton Pass-related tests so that their prefix becomes Baton Pass.
      • Eg. Aqua Ring can be Baton Passed becomes Baton Pass passes Aqua Ring's effect.
    • Expanded Belch’s test to show that it doesn’t need to eat a berry before each use of the move.
    • Unconfirmed interactions added to the specific files.
    • Split EFFECT_RAGING_BULL from EFFECT_BRICK_BREAK’s file.
    • Moved Grassy Terrain/Earthquake test to Earthquake file.
  • Write new/Fix old tests for post-ko switch scenarios by @DizzyEggg in https://github.com/rh-hideout/pokeemerald-expansion/pull/4856

Fixed

📦 Pret merges 📦

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.8.4...expansion/1.8.5

Version 1.8.4

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.8.4`.

🌋 IMPORTANT CHANGES 🌋

Reverted Guillotine feature branch by @AsparagusEduardo:

  • This was a runtime decapitalization branch introduced silently in version 1.8.0. We didn’t properly announce as it was hastily merged and we were hoping that future versions of it would have fixed issues that we encountered after the merge. However, issues kept piling on and we felt the need to revert it as it was also silently breaking other features as well.
  • We will work on an alternate decapitalization option in the future.

💥 Softlock/Crash fixes 💥

🧬 General 🧬

Fixed

✨ Feature Branches ✨

TheXaman’s Debug Menu:

Fixed

SBird/Karathan’s Dynamic Multichoices:

Changed

TheXaman’s HGSS Pokédex Plus:

Fixed

  • Multiple evolution page fixes by @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4514
    • Fixed duplicate icons when 2 or more evolution methods share the same target species (eg. Magnezone evolution via Thunder Stone or Electromagnetic field).
    • Fixed arrow not loading when there are multiple evolution methods to the same target species that hadn’t been caught.
    • Fixed wonky D-Pad inconsistency when scrolling down.
    • Fixed regression from #3562 (1.7.0) that caused non-evolving Pokémon to not show their “X has no evolution” text.
      • Change from the original branch: The message no longer shows for Pokémon that are part of an evolutionary family, even if they don’t evolve themselves (eg. Venusaur).
  • Added failsafe for Egg Groups without text defined by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/4628

ghoulslash’s Saveblock Cleansing:

Changed

🐉 Pokémon 🐉

Added

Changed

Fixed

⚔️ Battle General ⚔️

Fixed

🤹 Moves 🤹

Changed

Fixed

🎭 Abilities 🎭

Fixed

🧶 Items 🧶

Added

Fixed

🤖 Battle AI 🤖

Changed

Fixed

🧹 Other Cleanup 🧹

Fixed

🧪 Test Runner 🧪

Added

Fixed

📦 Pret merges 📦

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.8.3...expansion/1.8.4

Version 1.8.3

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.8.3`.

💥 Softlock/Crash fixes 💥

🧬 General 🧬

Changed

Fixed

✨ Feature Branches ✨

TheXaman’s HGSS Pokédex Plus:

Fixed

🐉 Pokémon 🐉

Changed

Fixed

⚔️ Battle General ⚔️

Changed

Fixed

🤹 Moves 🤹

Fixed

🎭 Abilities 🎭

Changed

Fixed

🧶 Items 🧶

Fixed

🤖 Battle AI 🤖

Changed

🧪 Test Runner 🧪

Added

Changed

Fixed

  • Fixed AI test error messages by @mrgriffin in https://github.com/rh-hideout/pokeemerald-expansion/pull/4404
    • The error messages for EXPECT_MOVE and EXPECT_SWITCH were backwards, saying, e.g. Expected MOVE, got SWITCH when it should say Expected SWITCH, got MOVE.
  • Fixed typos in Embody Aspect tests by @kittenchilly in https://github.com/rh-hideout/pokeemerald-expansion/pull/4439
  • Fixed Battle Test organization by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/4504
    • Fixed Cud Chew’s file being in the move effect folder.
    • Fixed Cud Chew’s file name and test names (Cud Chuw).
    • Fixed Gastro Acid and Role Play’s files being in the ability folder.
    • Moved Recoil file to move flags folder.
    • Renamed White Herb’s file to restore_stats.c.
    • Renamed Techno Blast’s file to change_type_on_item.c.
    • semi_invulnerable_moves.c to semi_invulnerable.c.
    • two_turn_moves.c to two_turns_attack.c.
    • Combined Burn Up/Double Shock to a single file fail_if_not_arg_type.c
    • Added Spit Up/Swallow files that point Stockpile’s file.
    • Moved secondary effect files to their own folder.
    • Combinations of secondary effects moved to their own folder
    • Split hit_set_entry_hazards.c to separate files for Spikes/Stealth Rock.
    • Grouped Hex/Venoshock to the same file double_power_on_arg_status.c

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.8.2...expansion/1.8.3

Version 1.8.2

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.8.2`.

🌋 Important changes 🌋

  • Added check during compilation to make sure that the code is inside a git directory before building by @SBird1337 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4363
    • If you downloaded the code using the “Download ZIP” option on GitHub, you will not be able to update your expansion version or merge any other feature brances, which is why we added this check to make sure that users don’t fall into this trap.

💥 Softlock/Crash fixes 💥

🧬 General 🧬

Changed

Fixed

✨ Feature Branches ✨

TheXaman’s Debug Menu:

Fixed

TheXaman’s HGSS Pokédex Plus:

Changed

Fixed

🐉 Pokémon 🐉

Added

Changed

Fixed

⚔️ Battle General ⚔️

Fixed

🤹 Moves 🤹

Fixed

🎭 Abilities 🎭

Added

Fixed

🧶 Items 🧶

Fixed

🤖 Battle AI 🤖

Fixed

🧹 Other Cleanup 🧹

Added

Fixed

🧪 Test Runner 🧪

Added

📦 Pret merges 📦

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.8.1...expansion/1.8.2

Version 1.8.1

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.8.1`.

🌋 IMPORTANT CHANGES 🌋

🧬 General 🧬

Added

Changed

Fixed

🧹 Other Cleanup 🧹

Changed

Fixed

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.8.0...expansion/1.8.1

Version 1.8.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.8.0`.

🌋 IMPORTANT CHANGES 🌋

🧬 General 🧬

Added

Changed

Fixed

✨ Feature Branches ✨

Incorporated @SBird1337’s Dynamic Multichoices by @SBird1337 in https://github.com/rh-hideout/pokeemerald-expansion/pull/3826

  • This allows to set up custom multichoices much easier!
  • Allows you to control what options appear based custom conditions (such as them being based on what items you have currently, or even completely at random!).
  • Event callbacks can be added as well, to fully customize what happens with your multichoices.
    • Included there’s DYN_MULTICHOICE_CB_SHOW_ITEM, which shows icons of the items defined by your script.
  • Compatible with Poryscript.
  • For more information and how to use it, please visit the Pokécommunity thread.

Incorporated @ghoulslash’s Saveblock Cleansing branch by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/4113

  • Differences from the the standalone branch:
    • Moved configs to dedicated file (include/config/save.h).
      • Fixed comments to the proper amount of space saved.
    • Added FREE_MYSTERY_GIFT, saving 876 bytes in SaveBlock1.
    • Converted #ifndef configs to the config format the rest of expansion uses
    • Cleaned up the code and fixed to work on modern.

TheXaman’s Debug Menu:

Added

Changed

Fixed

🐉 Pokémon 🐉

Added

Changed

⚔️ Battle General ⚔️

Added

Changed

Fixed

🤹 Moves 🤹

Added

Changed

Fixed

🎭 Abilities 🎭

Added

Changed

Fixed

🧶 Items 🧶

Added

Changed

Fixed

🤖 Battle AI 🤖

Added

Changed

Fixed

🧹 Other Cleanup 🧹

🧪 Test Runner 🧪

Added

Changed

Fixed

📦 Pret merges 📦

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.7.4...expansion/1.8.0

Version 1.7.4

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.Y.Z`.

🧬 General 🧬

Fixed

🐉 Pokémon 🐉

Fixed

⚔️ Battle General ⚔️

Fixed

🤹 Moves 🤹

Fixed

🎭 Abilities 🎭

Added

Fixed

🧶 Items 🧶

Fixed

🧹 Other Cleanup 🧹

Changed

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.7.3...expansion/1.7.4

Version 1.7.3

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.7.3`.

🌋 IMPORTANT CHANGES 🌋

🧬 General 🧬

🐉 Pokémon 🐉

Changed

Fixed

⚔️ Battle General ⚔️

Fixed

🤹 Moves 🤹

Changed

Fixed

🎭 Abilities 🎭

Fixed

🧶 Items 🧶

Fixed

🤖 Battle AI 🤖

Fixed

🧪 Test Runner 🧪

Added

Changed

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.7.2...expansion/1.7.3

Version 1.7.2

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.7.2`.

🧬 General 🧬

Changed

Fixed

🐉 Pokémon 🐉

Added

Changed

  • Multiple Pokémon graphical improvements by @katykat5099 in https://github.com/rh-hideout/pokeemerald-expansion/pull/3805
    • Improved Tyrantrum’s back sprite.
    • Improved Zigzagoon and Linoone’s palette
    • Updated Gen 9 Pokémon icons to @CyanSMP64’s improvements
      • Annihilape
      • Arctibax and Baxcalibur
      • Bellibolt
      • Bramblin and Brambleghast
      • Cetoddle and Cetitan
      • Charcadet, Armarouge and Ceruledge.
      • Chi-Yu and Chien-Pao
      • Clodsire
      • Crocalor
      • Dolliv
      • Dudunsparce
      • Esparthra

Fixed

⚔️ Battle General ⚔️

Changed

Fixed

🤹 Moves 🤹

Fixed

🧶 Items 🧶

Fixed

🤖 Battle AI 🤖

Fixed

🧹 Other Cleanup 🧹

Fixed

🧪 Test Runner 🧪

Added

Changed

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.7.1...expansion/1.7.2

Version 1.7.1

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.7.1`.

🧬 General 🧬

Changed

Fixed

🐉 Pokémon 🐉

Fixed

🤹 Moves 🤹

Added

Fixed

🎭 Abilities 🎭

Fixed

🧶 Items 🧶

Fixed

🧹 Cleanup 🧹

🧪 Test Runner 🧪

Added

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.7.0...expansion/1.7.1

Version 1.7.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.7.0`.

🌋 IMPORTANT CHANGES 🌋

The Expansion now uses Modern compilers by default

🧬 General 🧬

Added

Changed

Fixed

🐉 Pokémon 🐉

Added

Changed

  • Species Simplifier™ (Parts 1, 2 and 3)
    • Moved most data from multiple arrays to new fields in gSpeciesInfo
      • gSpeciesNames array -> speciesName field.
      • gLevelUpLearnsets array -> levelUpLearnset field.
      • gTeachableLearnsets array -> teachableLearnset field.
      • gEvolutionTable array -> evolutions field.
      • gFormSpeciesIdTables array -> formSpeciesIdTable field.
      • gFormChangeTablePointers array -> formChangeTable field.
      • Refactored Cry tables to simplify the process of adding new cries.
        • Now there’s a single entry in the table per cry, and species are asigned cry IDs in gSpeciesInfo’s cryId field.
      • Graphical data now have their pointers in gSpeciesInfo (Sprites, palettes and animations)
        • Removed all files in src/data/pokemon_graphics/ with the exception of front_pic_anims.h.
          • gMonBackPicCoords array -> backPicSize field.
          • gMonBackPicTable array -> backPic field.
            • gMonBackPicTableFemale array -> backPicFemale field.
          • gMonFrontPicCoords array -> frontPicSize field.
          • gMonFrontPicTable array -> frontPic field.
            • gMonFrontPicTableFemale array -> frontPicFemale field.
          • gMonPaletteTableFemale array -> palette field.
            • gMonPaletteTableFemale array -> paletteFemale field.
          • gMonShinyPaletteTable array -> shinyPalette field.
            • gMonShinyPaletteTableFemale array -> shinyPaletteFemale field.
          • gEnemyMonElevation array -> enemyMonElevation field.
          • gMonIconPaletteIndices array -> iconPalIndex field.
            • gMonIconPaletteIndicesFemale array -> iconPalIndexFemale field.
        • Removed unused 2nd animations.
      • Dex Entries
        • Individual form information is visible in the HGSS Pokédex (Vanilla Dex TBD)
        • National Dex numbers are assigned to the species in gSpeciesInfo, removing the need of sSpeciesToHoennPokedexNum and sSpeciesToNationalPokedexNum arrays.
        • Height and Weight are now saved separately per form, so weight in battle is now more accurate.
          • Pokédex size page proportions are also separate.
        • Pokédex descriptions are now saved as compound strings in gSpeciesInfo and differ by form. Shared entries are at the top of src/data/pokemon/species_info.h.
    • Added toggles to disable specific family groups of species
      • Located in include/config/species_enabled.h.
        • Moved the original P_GEN_x_POKEMON configs to this file.
      • Options to disable groups of species:
        • Battle-gimmick forms (Megas, Primals, etc.)
        • Regional Forms (Includes evolutions of those species, such as Sirfetch’d)
        • Pikachu extra forms.
        • Cross-Generation Evolutions
          • Also added separate option to add cross-evolutions to the Regional Dex.
      • Generation 1-3 families can now be disabled.
      • Pokémon will not evolve into species that have been disabled.
      • Pokémon will produce offspring of species that have been disabled.
      • Pokémon will not change form into forms that have been disabled.
      • Fixes and cleanup
    • Grouped data by species family.
    • Converted species flags to gcc flags.
    • Converted P_UPDATED_STATS “ifdef blocks” to ternaries.
    • Added Mega Evolution hidden ability failsafes.
    • Separated gSpeciesInfo by Generation by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/3729
    • Fixes and cleanup
  • Updated P_UPDATED_ABILITIES Gen 9’s config for Piplup’s line, Gallade and Shiftry by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/3353
    • Shiftry’s 2nd regular ability was changed from Early Bird to Wind Rider.
    • Piplup, Prinplup and Empoleon’s Hidden abilities were changed from Defiant to Competitive.
    • Gallade was given Sharpness as a 2nd regular ability.
  • Updated Legends Arceus Pokémon data and Level Up learnsets to Scarlet/Violet’s by @kittenchilly in https://github.com/rh-hideout/pokeemerald-expansion/pull/3458
  • Applied missing uses of PLACEHOLDER_ANIM_SINGLE_FRAME by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/3562
  • Renamed PLACEHOLDER_TWO_FRAME_ANIMATION to PLACEHOLDER_ANIM_TWO_FRAMES by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/3562
  • Removed Old Unown Level Up Learnsets by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/3562
  • Added FORM_CHANGE_TIME_OF_DAY form change that automatically changes Form during times of day (used by Shaymin to revert to Land Forme at night) by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/1690
  • Added FORM_CHANGE_STATUS form change that triggers when they adquire status condition (used by Shaymin to revert to Land Forme when frozen) by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/3734
    • Currently it doesn’t:
      • Prevent Shaymin from changing into Sky Forme when frozen.
      • Change Form in the Battle Pike.
  • Evolutions now call for GetTimeOfDay instead of checking the times directly by @fdeblasio in https://github.com/rh-hideout/pokeemerald-expansion/pull/3369

Fixed

⚔️ Battle General ⚔️

Added

Changed

Fixed

🤹 Moves 🤹

Added

Changed

Fixed

🎭 Abilities 🎭

Added

Changed

Fixed

🧶 Items 🧶

Added

Changed

Fixed

🤖 Battle AI 🤖

  • Added AI Tests
    • By @DizzyEggg in https://github.com/rh-hideout/pokeemerald-expansion/pull/3361
      • AI prefers Bubble over Water Gun if it’s slower (both are power 40).
      • AI prefers Water Gun over Bubble if it knows that foe has Contrary.
      • AI prefers moves with better accuracy, but only if they both require the same number of hits to KO.
      • AI prefers moves which deal more damage instead of moves which are super-effective but deal less damage.
      • AI prefers Earthquake over Drill Run if both require the same number of hits to KO.
      • AI chooses the safest option to faint the target, taking into account accuracy and move effect.
      • AI won’t use ground type attacks against flying type Pokémon unless Gravity is in effect.
      • AI will not switch in a Pokémon which is slower and gets 1HKOed after fainting.
      • AI switches if Perish Song is about to kill.
      • AI won’t use a Weather changing move if partner already chose such move.
      • AI will not use Helping Hand if partner does not have any damage moves.
      • AI will not use a status move if partner already chose Helping Hand.
      • AI without any flags chooses moves at random.
    • By @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/3382
      • AI prefers a weaker moves over one with a downside effect if both require the same number of hits to KO.
      • AI prefers moves with the best possible score, chosen randomly if tied.
      • AI can choose a status move that boosts the attack by two.
    • By @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/3515
      • AI won’t use Solar Beam if there is no Sun up or the user is not holding Power Herb.
    • By @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/3583
      • AI chooses moves with secondary effect that have a 100% chance to trigger
    • Cleanup by @DizzyEggg in https://github.com/rh-hideout/pokeemerald-expansion/pull/3748
  • Smarter SwitchAI Mon Choices + HasBadOdds Switch Check by @Pawkkie in https://github.com/rh-hideout/pokeemerald-expansion/pull/3253
    • Use AI_FLAG_SMART_MON_CHOICES to enable smarter decisions when choosing which mon gets sent out
    • HasBadOdds expands AI_FLAG_SMART_SWITCHING to switch out in cases where a mon has a bad matchup and lots of HP remaining
  • Extend AI_FLAG_SMART_SWITCHING for Encore / hazards / lowered attacking stats + Tests by @Pawkkie in https://github.com/rh-hideout/pokeemerald-expansion/pull/3557

Changed

Fixed

🧹 Other Cleanup 🧹

🧪 Test Runner 🧪

Added

Changed

Fixed

📦 Pret merges 📦

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.6.2...expansion/1.7.0

Version 1.6.2

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.6.2`.

🌋 IMPORTANT CHANGES 🌋

Battle changes

  • Battler Types are now obtained via GetBattlerType instead of gBattleMons[battlerId].type1/2/3 to better consider Roost. Be sure to update your custom battle effects to account for this change.

🧬 General 🧬

Fixed

🐉 Pokémon 🐉

Changed

Fixed

🤹 Moves 🤹

Changed

Fixed

🎭 Abilities 🎭

Changed

Fixed

🧶 Items 🧶

Fixed

🧹 Cleanup 🧹

🧪 Test Runner 🧪

Added

Changed

Fixed

New Contributors

Full Changelog

https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.6.1...expansion/1.6.2

Version 1.6.1

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.6.1`.

CRITICAL FIX, please update to avoid the issues detailed down below:

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.6.0...expansion/1.6.1

Version 1.6.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.6.0`.

Added

General

Item Effects

Move Effects

Move Animations

Graphics

Changed

General

Graphical changes

Refactors

Move animations

Battle AI

Cleanup

Fixed

Softlocks

General

Graphics

Battle Mechanics

Test Runner

General

Tests added for:

Pret merges:

  • Pret merge (2023/08/31) by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/3268
    • VAR_TEMP aliases
    • TM and HM item constants by their move name without numbers.
    • Stat change documentation.
    • Factory Menu + Dome Tourney documentation.
    • Berry Fix Documentation.
    • Missing uses of DISPLAY_WIDTH and DISPLAY_HEIGHT.
    • Static assertion for Battle Palace Flags.
    • Static assertion for Rotating Gates.
    • Automatic increase of TEXT_BUFF_ARRAY_COUNT and POKEMON_NAME_BUFFER_SIZE.
    • Proper bravoTrainerTower documentation.
    • Birth Island Rock documentation.
    • 6 new bugfixes.
  • Pret merge (2023/09/26) by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/3347
    • Add include guards for assembly constants files
    • Add blockBoxRS field to BoxPokemon struct
    • Bugfix for abilities affecting wild encounter tables
      • Fixes a potential buffer overread in TryGetAbilityInfluencedWildMonIndex. The bug can occur if an electric type mon is in the first slots of a fishing encounter table and the player carries a mon with the ABILITY_STATIC ability. This never happens in the vanilla codebase.
    • Add missing constant usage in m4a_1

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.5.3...expansion/1.6.0

Version 1.5.3

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.5.3`.

CRITICAL FIX, please update to avoid the issues detailed down below:

  • Fixed memory corruption when handling trigger sprites by @SBird1337 in https://github.com/rh-hideout/pokeemerald-expansion/pull/3238
    • This had the posibility of manifesting in weird ways, like camera and music changes, NPC duplication and more. If you’ve had this issue in the past, we heavily recommend you update to this version of the expansion.
    • Thank you @Bassoonian for helping us pinpointing the issue.

image image

Fixed

Battle Mechanics

Test Runner

Changed

Fixed

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.5.2...expansion/1.5.3

Version 1.5.2

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.5.2`.

Changed

General

Refactors

Fixed

Softlocks

Graphics

Battle Mechanics

Battle AI

Pret merges:

Test Runner

Changed

Fixed

Tests added for:

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.5.1...expansion/1.5.2

Version 1.5.1

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.5.1`.

Changed

General

Fixed

General

Softlocks

Graphics

Battle Mechanics

Battle AI

Battle Tests

Added

Changed

  • Minor test changes by @mrgriffin in https://github.com/rh-hideout/pokeemerald-expansion/pull/3072
    • Regularizes the whitespace.
    • Removes unnecessary ;s after }s.
    • Parametrizes item_effect_restore_hp.c and uses I_HEALTH_RECOVERY everywhere.
    • Inlines uses of macros where I think it makes the test easier to follow.
    • Use 3-arg PASSES_RANDOMLY in the Snow + Blizzard test (improves performance).
    • More conservative unlink error reporting. Ctrl-C in make check should not complain about being unable to unlink ROMs which weren’t created yet.
    • Better names for the ROMs in /tmp.
    • Prints the test runner number in Hydra, making it easier to track down bugs involving state leaking from a test to the following tests.
    • Simplify TO_DO_BATTLE_TEST’s implementation.
    • Introduce a TearDownBattle function which was repeated twice.

Fixed

Latest pret commit:

https://github.com/pret/pokeemerald/commit/9c4a59f865360b7d6e0dede0e52812b897526588

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.5.0...expansion/1.5.1

Version 1.5.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.5.0`.

Added

General

Battle General

Move Effects

Item Effects

Battle AI

Tests

Changed

General

Graphical changes

Refactors

Cleanup

Fixed

General

Graphics

Battle Mechanics

Battle Animations

Battle AI

Pret merges

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.4.3...expansion/1.5.0

Version 1.4.3

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.4.3`.

Changed

Cleanup

Fixed

General

Battle Mechanics

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.4.2...expansion/1.4.3

Version 1.4.2

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.4.2`.

Fixed

General

Battle Mechanics

Battle AI

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.4.1...expansion/1.4.2

Version 1.4.1

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.4.1`.

CRITICAL FIX, please update to avoid the issues detailed down below:

  • Fixed electricity move animations causing softlocks with weird graphical results by @DizzyEggg in #2785

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.4.0...expansion/1.4.1

Version 1.4.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.4.0`.

Added

General

Moves

  • Generation IX Moves
    • Base move data by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/2467
    • New moves with existing effects:
      • Lumina Crash, Jet Punch, Ice Spinner, Triple Dive, Kowtow Cleave, Flower Trick, Torch Song, Aqua Step, Ruination, Pounce, Trailblaze, Chilling Water, Hyper Drill, Twin Beam, Armor Cannon, Bitter Blade, Comeuppance, Aqua Cutter, Blazing Torque, Noxious Torque, Combat Torque, Magical Torque
    • New move effects:
    • Missing move effects:
      • Tera Blast, Axe Kick, Last Respects, Order Up, Spicy Extract, Spin Out, Population Bomb, Glaive Rush, Revival Blessing, Salt Cure, Mortal Spin, Doodle, Fillet Away, Raging Bull, Make It Rain, Collision Course, Electro Drift, Shed Tail, Chilly Reception, Tidy Up, Snowscape, Rage Fist, Gigaton Hammer
  • Updated Gen 1-8 move effects to Gen 9 standards: by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/2467
    • LA moves with existing effects
      • Psyshield Bash, Raging Fury, Wave Crash, Chloroblast, Mountain Gale, Headlong Rush, Esper Wing, Shelter, Bitter Malice, Power Shift, Springtide Storm, Bleakwind Storm, Wildbolt Storm, Sandsear Storm
    • LA moves with new move effects
      • Mystical Power (EFFECT_SPECIAL_ATTACK_UP_HIT)
      • Victory Dance (EFFECT_VICTORY_DANCE)
    • PP adjustments.
      • (5 -> 10) Bleakwind Storm, Wildbolt Storm, Sandsear Storm
      • (10 -> 5) Recover, Soft-Boiled, Rest, Milk Drink, Slack Off, Roost, Shore Up
    • Power adjustments
      • (50 -> 90) Triple Arrows
      • (90 -> 120) Raging Fury
      • (120 -> 150) Wave Crash
      • (60 -> 80) Dire Claw
      • (100 -> 120) Headlong Rush
      • (60 -> 75) Bitter Malice
      • (75 -> 80) Esper Wing
      • (95 -> 100) Springtide Storm, Bleakwind Storm, Wildbolt Storm, Sandsear Storm
      • (80 -> 75) Wicked Blow
      • (70 -> 60) Grassy Glide
      • (130 -> 120) Glacial Lance
  • Implementing Teatime effect by @SonikkuA-DatH in https://github.com/rh-hideout/pokeemerald-expansion/pull/1956
  • Config for Gen 4’s Roost pure-Flying behavior (B_ROOST_PURE_FLYING) by @mrgriffin in https://github.com/rh-hideout/pokeemerald-expansion/pull/2530
  • Config for Gen 8 Howl’s effect by @DizzyEggg in https://github.com/rh-hideout/pokeemerald-expansion/pull/2700

Abilities

  • Generation IX Abilities
    • 28 of 31 abilities implemented by @LOuroboros in https://github.com/rh-hideout/pokeemerald-expansion/pull/2470
      • Lingering Aroma, Seed Sower, Thermal Exchange, Anger Shell, Purifying Salt, Well-Baked Body, Wind Rider, Rocky Payload, Wind Power, Electromorphosis, Protosynthesis, Quark Drive, Good as Gold, Vessel of Ruin, Sword of Ruin, Tablets of Ruin, Beads of Ruin, Orichalcum Pulse, Hadron Engine, Cud Chew, Sharpness, Supreme Overlord, Costar, Toxic Debris, Armor Tail, Earth Eater, Guard Dog and Mycelium Might
    • Not implemented yet:
      • Commander
      • Opportunist
      • Zero to Hero
  • Implemented Ice Face by @LOuroboros in https://github.com/rh-hideout/pokeemerald-expansion/pull/2255

Items

Changed

Graphical changes

Refactors

Cleanup

Other

Fixed

Softlocks

Graphics

Battle Mechanics

Move Animations

Battle AI

Other

Pret merges

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.3.0...expansion/1.4.0

Version 1.3.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.3.0`.

Added

Changed

Fixed

Pret merges

Cleanup

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.2.0...expansion/1.3.0

Version 1.2.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.2.0`.

Added

Changed

Fixed

Cleanup

Pret merges

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.1.1...expansion/1.2.0

Added

Changed

Fixed

Pret merges

Cleanup

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.1.0...expansion/1.2.0

Version 1.1.1

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.1.1`.

What’s Changed

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.1.0...expansion/1.1.1

Version 1.1.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.1.0`.

Added

Changed

Fixed

Pret merges

Cleanup

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.0.0...expansion/1.1.0

Version 1.0.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.0.0`.

BREAKING

ADDED

CHANGED

FIXES

PRET MERGES

CLEANUP

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/0.9.0...expansion/1.0.0

Version 0.9.0

## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/0.9.0`.

This version was labeled retroactively after our versioning scheme was decided, meaning the version number may be arbitrary.

ADDED

CHANGED

FIXES

PRET MERGES

CLEANUP

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/0.8.0...expansion/0.9.0

BREAKING

ADDED

CHANGED

FIXES

PRET MERGES

CLEANUP

New Contributors

Full Changelog: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/0.9.0...expansion/1.0.0

How to make an Expansion version

If you need instructions on how to release a new Expansion version, check out the enclosed instruction book. - AsparagusEduardo

1.- Autogenerating a changelog for the master branch.

Requires Write access to the repo.

If the changelog you’re making is for a minor version (Eg. 1.3.0), make sure to sync the upcoming branch with master before starting. Keep in mind that if there are unreleased changes in master, they should be made into a patch version released alongside minor version.

  • Go to https://github.com/rh-hideout/pokeemerald-expansion/releases.
  • Press the option “Draft a new release”.
  • Fill the following fields:
    • In “Choose a tag”, write the name of the tag for the desired release number.
      • Eg. for version 1.2.3, write expansion/1.2.3. It cannot be an existing tag.
    • In “Target” choose master.
    • In “Previous tag”, select the latest version released.
  • Press “Generate release notes”. This will fill the description with a list of PRs made to the master branch since the lastest release.
  • You may copy the contents to your editor of choice for step 2.
  • If the changelog you’re making is for a minor version (Eg. 1.3.0), proceed to step 1B, without closing the current window.

1B.- Autogenerating a changelog for the upcoming branch.

  • Delete the text and title generated in the site.
  • Change “Target” to upcoming.
  • Press “Generate release notes”. This will autogenerate the description with changes from both branches, as they’ve been merged.
  • Use a comparison tool to remove any shared PRs from master. (I use WinMerge for this).
    • Also remove any shared “New Contributor” entries.
  • You should now have a text that only contains PRs made to upcoming.

2.- Sorting PRs in the changelog

  • Copy the docs/changelogs/template.md file into a new file with the corresponding version for file and folder. Eg, for 1.2.3, you copy the file into docs/changelogs/1.2.x/1.2.3.md.
  • Use the following Regex to adapt all PR links into the format currently used:
    • Search
      in https://github\.com/rh-hideout/pokeemerald-expansion/pull/(\d+)
      
    • Replace
      in [#$1](https://github.com/rh-hideout/pokeemerald-expansion/pull/$1)
      
  • At the bottom of the template, replace the “____” in <!--Last PR: ____--> with the number of the last PR in your autogenerated changelog. This will help you keep track of any new PRs that are merged in before you’re finished with your changelog.
  • Sort the PRs by the categories present in the PR taking the following considerations:
    • Keep the language of the changelog as newbie friendly as possible, explaining how the PR affects them.
    • The format of the main line is the following:
      {{Description of the change}} by @{{GitHub user}} in {{PR link}}
      
    • If a PR reverted by a different PR, both should be removed.
      • If the reverted PR’s contents are then re-added it should be treated as if it’s the first time added, with all the proper documentation needed.
    • If a PR’s content fits into multiple categories, like fixing two unrelated Ability and Move effects, you may duplicate the PR line and put it in both categories, changing the description of it accordingly.
    • When refering to an element present in the code, always enclose them with ` to easily tell them apart. Eg:
      • “Converted settotemboost command to callnative
      • “Changed MOVEEND_ defines to an enum”
    • A PR’s technical changes that may conflict with user changes should have an entry in the “REFACTORS” section at the beginning of the changelog. Any of these changes that requires a migration script should also be marked as such by appending the corresponding emoji listed there. The section should include, but it’s not limited to:
      • Massive data format and/or structuring changes.
      • Converting defines to enums.
      • Renaming structs and/or their fields.
      • Removing enums/defines/structs.
    • For fixes:
      • Once on their respective categories, if a PR fixes multiple issues at once in that category, you may make a sublist of those issues to properly detail each one and avoid just writing “Fixed multiple ability issues” or an overly verbose sentence for the PR.
      • Try to fit the contents of a PR as a single sentence in past tense that.
      • DON’T write something like “Fixed Parental Bond”, as this doesn’t explain what was fixed in Parental Bond. Instead, write something like “Fixed Parental Bond not affecting Snore”.
    • For new configs:
      • Add the name of the config as part of the sentence, with subitems explaining what they do based on their generation if it’s a generational config. Eg:
        * Added missing `B_AFTER_YOU_TURN_ORDER` config by @PhallenTree in [#5400](https://github.com/rh-hideout/pokeemerald-expansion/pull/5400)
            * Gen 5-7: After You fails if the order remains the same after using After You.
            * Gen 8+: After You no longer fails if the turn order remains the same after using After You.
        
    • For other new features:
      • Explain how to use the feature completely, listing all its features as needed. For now, this is the only source of documentation for these features, so it’s important to be thorough.

3.- Preparing the code for the new version

  • Search for all non-changelog instances of the previous released version and update them to the newer version. As of writing, it’s these files:
    • README.md:
      -Based off RHH's pokeemerald-expansion 1.2.2 https://github.com/rh-hideout/pokeemerald-expansion/
      +Based off RHH's pokeemerald-expansion 1.2.3 https://github.com/rh-hideout/pokeemerald-expansion/
      
      -- Once you have your remote set up, run the command `git pull RHH expansion/X.Y.Z`, replacing X, Y and Z with the digits of the respective version you want to update to (eg, to update to 1.2.2, use `git pull RHH expansion/1.2.2`).
      +- Once you have your remote set up, run the command `git pull RHH expansion/X.Y.Z`, replacing X, Y and Z with the digits of the respective version you want to update to (eg, to update to 1.2.3, use `git pull RHH expansion/1.2.3`).
      
    • .github/ISSUE_TEMPLATE/*.yaml
      • Patch version:
        options:
        -   1.2.2 (Latest release)
        +   1.2.3 (Latest release)
            master (default, unreleased bugfixes)
            upcoming (Edge)
        +   1.2.2
            1.2.1
            1.2.0
        
      • Minor Version:
        options:
        -   1.2.2 (Latest release)
        +   1.2.3 (Latest release)
            master (default, unreleased bugfixes)
            upcoming (Edge)
        +   1.2.2
            1.2.1
            1.2.0
        -   1.1.6
        -   1.1.5
        -   1.1.4
        -   1.1.3
        -   1.1.2
        -   1.1.1
        -   1.1.0
        -   pre-1.1.0
        +   pre-1.2.0
        
    • docs/SUMMARY.md:
      • Patch version:
        [Changelog](./CHANGELOG.md)
            - [1.2.x]()
        +       - [Version 1.2.3](changelogs/1.2.x/1.2.3.md)
                - [Version 1.2.2](changelogs/1.2.x/1.2.2.md)
                - [Version 1.2.1](changelogs/1.2.x/1.2.1.md)
                - [Version 1.2.0](changelogs/1.2.x/1.2.0.md)
        
      • Minor version:
        [Changelog](./CHANGELOG.md)
        +   - [1.3.x]()
        +       - [Version 1.3.0](changelogs/1.3.x/1.3.0.md)
            - [1.2.x]()
                - [Version 1.2.2](changelogs/1.2.x/1.2.2.md)
                - [Version 1.2.1](changelogs/1.2.x/1.2.1.md)
                - [Version 1.2.0](changelogs/1.2.x/1.2.0.md)
        
    • include/constants/expansion.h:
      • The defines should already have the version we’re targetting as part of the previous changelog process.
        -// Last version: 1.2.2
        +// Last version: 1.2.3
            #define EXPANSION_VERSION_MAJOR 1
            #define EXPANSION_VERSION_MINOR 2
            #define EXPANSION_VERSION_PATCH 3
        
            // FALSE if this this version of Expansion is not a tagged commit, i.e.
            // it contains unreleased changes.
        -#define EXPANSION_TAGGED_RELEASE FALSE
        +#define EXPANSION_TAGGED_RELEASE TRUE
        

4.- Make a PR with the changes listed in Steps 2/3.

  • Also post the changelog for feedback from contributors and maintainers.
  • Once all feedback has been addresses, you may merge.

5.- Create the release on GitHub

  • Copy the contents of your manual changelog into the description of your release.
  • Modify the title to “Version {{version}}”, eg. “Version 1.2.3”
  • Be sure to have the “Set as the latest release” option set,
  • Press “Publish Release”.
  • This will create a new tag in the repo that users can pull from like they can with branches.

6.- Post-release handling

  • DON’T ACCEPT ANY NEW PRs YET. We have to prepare for the next cycle first.
  • Go to include/constants/expansion.h and merge the following changes to the repo (PR or direct commit, doesn’t matter much):
    • Patch version:
       // Last version: 1.2.3
          #define EXPANSION_VERSION_MAJOR 1
          #define EXPANSION_VERSION_MINOR 2
      -   #define EXPANSION_VERSION_PATCH 3
      +   #define EXPANSION_VERSION_PATCH 4
      
          // FALSE if this this version of Expansion is not a tagged commit, i.e.
          // it contains unreleased changes.
      -#define EXPANSION_TAGGED_RELEASE TRUE
      +#define EXPANSION_TAGGED_RELEASE FALSE
      

With this, the repo is ready again to receive new PRs.

Now you’re ready to make the announcements!

  • We tend to post on the following Discord Servers:

You can make a highlight of changes in the announcement itself, but it’s not needed. (I also like using Discord emotes to highlight certain features during announcements, but gain, it’s not needed).

Release Schedule and Process

Version Lifecycle

Minor Release (90 days to next Minor Release)

upcoming and master are synchronized. Minor Release should occur once every three months. Maintainers can vote to do extra Minor Releases for special cases, but this should be considered highly irregular.

Patch Release (60 / 30 days to the next Minor Release)

Releases that focus primarily on bugfixes or improvements to the test system. Patch Releases should occur AT LEAST once a month, but can be more frequent than that.

Big Feature Freeze (30 days to the next Minor Release)

PRs with the Github label type: big feature will NOT be merged until after the next Minor Release.

Merge Freeze (14 days to the next Minor Release)

Pull Requests that DO NOT have one of the following Github labels:

Sample Schedule

MajorMinorPatchTypeGoal Date
210MinorDec 1 2025
211PatchDec 31 2025
212PatchJan 30 2026
212Big Feature FreezeJan 30 2026
212Merge FreezeFeb 15 2026
213PatchMar 1 2026
220MinorMar 1 2026

What is a “Big Feature”?

  • If the original owner of the PR thinks a feature should be labeled a Big Feature, it is, no questions asked
  • If a reviewer thinks a PR is a Big Feature, then it is
  • If the two disagree, it can be discussed in a PR thread, and can ultimately be resolved with a Maintainer vote.

How To Identify a Big Feature

  • Big diffs: It’s easy for something to go unnoticed in review when it’s a tiny part of a massive diff.
  • High-impact: High-impact changes are harder to review because they often have consequences that aren’t obvious to the reviewer. We catch these consequences from users who use upcoming reporting them.
  • Subjective: Subjective changes are more likely to have differences of opinions between senate members.
  • Pervasive: The PR touches several different parts of the codebase or is involved in several different parts of the codebase, even if those elements are small.

Release Blocking and Milestones

When an issue or PR is assigned to a milestone on Github by a Maintainer, that means it is “Blocking”. If another Maintainer agrees with this, then that version cannot be released until that issue is resolved or PR is merged.

This designation should be reserved for instances where an existing feature on upcoming or master is broken and causing problems for users or players.

Blocking issues or PRs can be deferred to future releases but should be discussed with the Maintainers that assigned the designation in the first place.

If a version’s milestone does not have any issues or PRs assigned to it, that version should be released as close to the goal date as possible.

Document Purpose

This document is a guide for maintainers to account for all the reccomended steps before merging in a pull request.

Checklist

Is the branch’s theoretical functionality in scope?

If you’re not sure if a branch’s functionality is in scope, start a conversation on Discord to resolve.

Does the branch successfully compile?

From make clean, the branch should locally compile.

Do all CI tests pass?

Contributors are asked to make sure tests pass locally, but maintainers should at least wait for the CI to pass before merging.

Have you verified that the functionality works in game without any problems?

If functionality cannot be verified with an automated test, proof of an in game test is required. Do not be afraid to reach out to the contributor or the community to make sure something works in game as it should.

If the branch ports behavior from another Pokémon game, have you verified that the behavior functions as faithfully as possible?

We have always tried to make sure we can mimic the original functionality as closely as possible so as to avoid confusion with users and players. Do not be afraid to ask the contributor / community for proof if you cannot personally verify.

There are situations where this should and should not happen, and should be discussed with maintainers on a case by case basis.

If this branch changes a function that is expected to be modified by users, is there a migration script?

Not everything needs a migration script - if you’re unsure, start a discussion.

Should new functionality introduced by this branch be gated behind a config?

We don’t have a strict definition of when configs should be used, but you can start with

Why SHOULDN’T this be a config?

Are tests written for everything that can be tested?

If you’re not sure if something CAN be tested, start a discussion. Some contributors may not be capable of writing tests - we should guide them in #expansion-tests to do so.

If any new tests are KNOWN_FAILING, issues should be opened describing each of the KNOWN_FAILING tests and our understanding of why they fail.

Does the branch meet our config philosophy?

Does the branch meet our saves philosophy?

Does the submitted code follow the styleguide?

This applies to code that comes from other branches or games.

Is the pull request appropriately labeled?

Without labels, the CHANGELOG will not be properly formatted. For specifically the bugfix label, an additional label, detailing what area the bug exists in is required.

Is pokeemerald-expansion free from a merge freeze?

Our release schedule prevents us from merging Big Features and non-bugfixes within certain dates close to a release. Please use /release in the RHH Discord to clarify when these are occuring.

Merging

When a feature has passed all of the items on the checklist, it is ready to be merged. From GitHub’s interface, there are three different options for merging:

Squash and merge

This should be used for all PRs except when merging from either:

  • a publicly available feature branch from by the community OR
  • upcoming, master or pret/pokeemerald.

Create a merge commit

Use the “Create a merge commit” to preserve history if:

  • The branch is a publicly available feature branch from the community
  • It’s a upstream pret merge
  • It’s a master to upcoming merge
  • It’s a Release merge

Rebase and merge

We do not use this ever.

Document Purpose

This document is a guide for contributors and Senate to decide if a feature is within “scope” for pokeemerald-expansion. “Scope” in this case comprises a list of features and concepts that could be merged if an appropriate implementation is submitted. If a feature is not in scope, then it should not be merged. Even if an opened PR is within scope, this does not mean it will be merged, as acceptance criteria will often come down to the details of the implementation.

Definitions

  • Showdown Supported (SS): A core series game who’s metagame can be played on Showdown.
    • Includes every core series game except Pokémon Legends: Arceus.
    • Does not include spin-off games such as Pokémon Colosseum, Pokémon XD, Pokémon Trozei!, etc.
  • Base Expansion Version: “A .gba file built from an unmodified master or upcoming branch of pokeemerald-expansion.
  • Vanilla Emerald Version: A .gba file built from an unmodified master branch of pret’s pokeemerald.

Guidelines

A pull request meets the scope criteria if:

  • The feature does not belong to a category considered “not in scope” AND
  • The feature belongs to a category considered “in scope”

In Scope Categories

  1. SS Species: Adds Species that have appeared in a Showdown-supported title. Includes follower sprites for all defined species including battle-only ones (ie. Megas)
  2. SS Moves: Adds Moves and Move Animations that have appeared in a Showdown-supported title
  3. SS Abilities: Adds Abilities that have appeared in a Showdown-supported title
  4. SS Items: Adds Items that have appeared in a Showdown-supported title
  5. SS Gimmicks: Adds Gimmicks that have appeared in a Showdown-supported title (Dynamax, Mega Evolution, etc.)
  6. SS Battle Types: Adds Special Battle Types that have appeared in a Showdown-supported title (Triple battles, etc.)
  7. SS Battle Mechanics: Adds mechanical battle changes that have appeared in a Showdown-supported title, and allow developers to choose which generation suits them where applicable
  8. Battle AI Behaviour: Improvements towards the capability of a human competitive player, and unique or interesting behaviours otherwise
  9. Base Link Compatibility: The ability for two Base Expansion Version’s to connect, trade, and battle one another
  10. SS Overworld Features: Add overworld changes / additions from Showdown-supported Pokémon titles (followers, raids, sideways stairs, etc.)
  11. SS Menu Features: Add menu changes / additions from Showdown-supported Pokémon titles (type effectivness indicator, PC functions, etc.)
  12. Speed Up: Optimize code to run more efficiently, take up less space, and work better overall to improves the developer and / or player experience
  13. Compression: Reduces the size of graphic or sound assets, etc. Includes automatic compression
  14. Novel Experience: Adds a novel experience included in another Showdown Supported title (poffins, fishing minigames, etc.)
  15. Helper Features: Eases the addition or inclusion of any of the aforementioned, or facilitates developer ease of use

Not In Scope Categories

  1. Non-SS Species: Adds Species that have NOT appeared in a Showdown-supported title (Fakemon, CAP Pokémon, etc.)
  2. Non-SS Moves: Adds Moves and Move Animations that have NOT appeared in a Showdown-supported title
  3. Non-SS Abilities: Adds Abilities that have NOT appeared in a Showdown-supported title
  4. Non-SS Items: Adds Items that have NOT appeared in a Showdown-supported title
  5. Non-SS Gimmicks: Adds Gimmicks that have NOT appeared in a Showdown-supported title (Showdown’s Other Metagames, etc.)
  6. Non-SS Battle Types: Adds Special Battle Types that have NOT appeared in a Showdown-supported title
  7. Overworld Maps: Adds overworld maps from either Showdown-supported titles or non-Showdown-supported titles
  8. Duplicate UIs: Adds additional user interface that covers the same functionality of an existing feature (HGSS Pokédex, BW Summary Screen, etc.)
  9. Vanilla Link Compatibility: The ability for Base Expansion Version and Vanilla Emerald Version to connect, trade, and battle one another

Discussion Required Categories

Pull Requests that fall into this category are not in scope by default and should be brought up to maintainers, who will discuss and vote as to whether or not the feature is considered in scope. Considerations for acceptance may include invasiveness of implementation, popularity, ease of maintenance, etc.

  1. Developer Ease of Use: Lowers barrier of entry for developers to use existing behavior
  2. Fangame Features: Adds a popular feature from other fangames
  3. Popular Non-SS Features: Exceptions can be made for uniquely popular or requested features (Drowsy, PLA Legend Plate, etc.)
  4. External Program: External programs like poryscript, porymoves, etc.
  5. Intergenerational Feature Compatibility: Addresses limitations and issues resulting from including all generational behaviours in a GBA native title, and extrapolation of features no longer supported by GameFreak

Workflow for Proposed Feature Scope Discussion

For the contributor:

  • Make a thread for the feature on Discord
  • Describe how the feature fits into this scope document, and why you feel it should be considered
  • Optionally include either a draft PR or describe in some detail the proposed implementation. Non-mandatory, but implementation invasiveness, maintenance cost, etc. are major considerations, so use your judgement. The senate may ask for this information during discussion.

For the senate:

  • Make a senate thread for the discussion
  • Make and pin a two-week voting poll
  • Discuss, conclude, and cast votes before the two-week deadline
  • Inform contributor as to the results and reasons in their thread
  • Amend this scope document if necessary