12 KiB
12 KiB
AGENTS.md - AI Coding Agent Guide for pokeemerald-expansion
Project Overview
pokeemerald-expansion is a comprehensive GBA ROM hack base for creating Pokémon ROM hacks, built on top of pret's pokeemerald decompilation project. It is not a playable game on its own but provides developers with a toolkit featuring hundreds of features from various core series Pokémon games.
- Target Platform: Game Boy Advance (ARM7TDMI processor)
- Primary Language: C (C17 standard) with ARM assembly
- Build System: GNU Make with devkitARM toolchain
- Repository: https://github.com/rh-hideout/pokeemerald-expansion
- Community: ROM Hacking Hideout (RHH) Discord
Technology Stack
Compiler & Toolchain
- Compiler:
arm-none-eabi-gcc(devkitARM recommended) - Architecture: ARMv4T (ARM7TDMI)
- ABI: APCS-GNU
- Optimization:
-O2(default),-Og(debug), LTO supported for release
Build Tools (in tools/ directory)
| Tool | Purpose |
|---|---|
gbagfx |
Convert PNG/PAL to GBA graphics formats (1bpp, 4bpp, 8bpp, gbapal) |
mid2agb |
Convert MIDI files to GBA sound format |
wav2agb |
Convert WAV files to GBA sound format |
mapjson |
Process map data from JSON to assembly |
jsonproc |
JSON preprocessor for data files |
trainerproc |
Process trainer data from .party files |
preproc |
Preprocessor with character map support |
scaninc |
Dependency scanner for includes |
ramscrgen |
Generate RAM linker script sections |
gbafix |
Fix GBA ROM header |
patchelf |
Patch ELF files for testing |
compresSmol |
Compression tool for graphics |
Testing Framework
- Test Runner: Custom framework running on mGBA emulator
- Test Location:
test/directory - Test Command:
make check - Parallel Testing: Uses
mgba-rom-test-hydrafor multi-process test execution
Build Commands
Standard Builds
# Default build (produces pokeemerald.gba)
make
# Parallel build (recommended)
make -j$(nproc)
# Release build (optimized, NDEBUG enabled)
make release
# Debug build (with debug symbols, -Og optimization)
make debug
# Clean build artifacts
make clean
# Clean without cleaning tools
make tidy
Testing Commands
# Run all tests
make check
# Run specific test file
make check TESTS=test/pokemon.c
# Run tests matching pattern
make check TESTS="Pokemon*"
Game Variants
# Build for different games (though Emerald is the main target)
make emerald # Default
make firered # FireRed variant
make leafgreen # LeafGreen variant
Build Options
# Enable Link Time Optimization (set in config.mk)
make release
# Disable LTO
make RELEASE=1 LTO=0
# Keep intermediate files
make KEEP_TEMPS=1
# Static analysis
make ANALYZE=1
Code Organization
Directory Structure
├── src/ # C source files (350+ files)
│ ├── data/ # Data definitions (moves, items, species, etc.)
│ └── ... # Game logic organized by feature
├── include/ # Header files (280+ files)
│ ├── config/ # Configuration headers (19 config files)
│ └── constants/ # Constant definitions
├── asm/ # Assembly files (mostly macros)
├── data/ # Assembly data files, maps, scripts
│ ├── maps/ # Map data (520+ maps)
│ ├── layouts/ # Map layouts
│ └── scripts/ # Event scripts
├── graphics/ # Graphics assets (sprites, backgrounds, etc.)
├── sound/ # Audio data and songs
├── test/ # Test files
├── tools/ # Build tools (C programs)
├── constants/ # Assembly constants
├── libagbsyscall/ # GBA system call library
├── docs/ # Documentation
└── migration_scripts/ # Scripts for migrating from other versions
Key Source Directories
src/ - Main Source Code
Organized by functionality:
- Battle System:
battle_*.cfiles (battle logic, AI, animations, controllers) - Overworld:
overworld.c,field_*.c(movement, effects, weather) - Pokémon:
pokemon.c,evolution_scene.c,daycare.c - UI:
menu.c,text.c,window.c,list_menu.c - Save/Load:
save.c,load_save.c - Audio:
sound.c,m4a.c,m4a_tables.c
include/config/ - Configuration Headers
Critical files for feature toggles:
general.h- General settings, generation constants (GEN_1 through GEN_9)battle.h- Battle mechanics configurationpokemon.h- Pokémon-related settingsoverworld.h- Overworld feature togglesdebug.h- Debug menu settingsai.h- Battle AI configuration
Coding Style Guidelines
Naming Conventions
| Type | Convention | Example |
|---|---|---|
| Functions | PascalCase | void ProcessBattleActions(void) |
| Structs | PascalCase | struct BattlePokemon |
| Variables/Fields | camelCase | int currentHp |
| Global Variables | g + PascalCase | extern s32 gBattleMons |
| Static Variables | s + PascalCase | static u8 sMyCounter |
| Macros/Constants | CAPS_WITH_UNDERSCORES | #define MAX_LEVEL 100 |
| Enums | CAPS_WITH_UNDERSCORES | enum Gimmick { GIMMICK_NONE, ... } |
Code Formatting
- Indentation: 4 spaces (no tabs for C/H files)
- Assembly/Scripts: Use tabs
- Braces: Opening brace on new line
- Switch statements: Cases left-aligned with switch block
- Comments:
- Use
//for single-line comments (capitalized, end with period) - Use
/* */for block comments explaining WHY, not WHAT
- Use
Example Code Style
void ProcessBattleActions(void)
{
u32 i;
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].hp == 0)
continue;
HandleTurnActionSelectionState(i);
}
}
switch (gBattleTypeFlags)
{
case BATTLE_TYPE_TRAINER:
SetTrainerBattleData();
break;
case BATTLE_TYPE_WILD:
SetWildBattleData();
break;
}
Data Types
- General numbers: Use
u32(unsigned) ors32(signed) - Save block data: Use smallest possible type
- EWRAM variables: Use smallest possible type
- Booleans: Use
bool8orbool32fromtypes.h
Inline Configs
When adding configurable features, check configs within normal control flow:
// Correct
void SetDifficulty(u32 level)
{
if (!B_VAR_DIFFICULTY)
return;
// ...
}
// Incorrect (using #ifdef)
#ifdef B_VAR_DIFFICULTY
// This bypasses normal control flow
#endif
Testing System
Test Macros
Located in include/test/test.h:
TEST("My test name")
{
// Test code here
EXPECT(condition);
EXPECT_EQ(a, b);
EXPECT_NE(a, b);
EXPECT_LT(a, b);
}
ASSUMPTIONS
{
// Pre-test assumptions
ASSUME(gSpeciesInfo[SPECIES_PIKACHU].baseHP > 0);
}
Test Features
- PARAMETRIZE: Run test multiple times with different parameters
- KNOWN_FAILING: Mark tests that are expected to fail
- KNOWN_LEAKING: Mark tests with known memory leaks
- BENCHMARK: Performance testing macros
- SET_RNG: Control random number generation for reproducibility
Writing Tests
Tests go in test/ directory as .c files:
#include "global.h"
#include "test/test.h"
#include "battle_test.h"
TEST("Pokemon creation works")
{
struct Pokemon mon;
CreateMon(&mon, SPECIES_PIKACHU, 50, 0, FALSE, 0, OT_ID_RANDOM, 0);
EXPECT_EQ(GetMonData(&mon, MON_DATA_LEVEL), 50);
}
Battle Tests
Special battle testing framework in test/test_runner_battle.c:
SINGLE_BATTLE_TEST("Thunderbolt deals damage")
{
GIVEN {
PLAYER(SPECIES_PIKACHU) { Moves(MOVE_THUNDERBOLT); }
OPPONENT(SPECIES_CHARMANDER);
} WHEN {
TURN { MOVE(player, MOVE_THUNDERBOLT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDERBOLT, player);
HP_BAR(opponent);
}
}
Configuration System
Generation Constants
In include/config/general.h:
#define GEN_1 0
#define GEN_2 1
#define GEN_3 2
#define GEN_4 3
#define GEN_5 4
#define GEN_6 5
#define GEN_7 6
#define GEN_8 7
#define GEN_9 8
#define GEN_LATEST GEN_9
Feature Configuration Pattern
Most features use config defines that can be set to specific generations:
// In include/config/battle.h
#define B_CRIT_CHANCE GEN_7 // Gen7+ critical hit chance
#define B_EXP_CATCH GEN_7 // Gen7+ exp on catch
#define B_TRAINER_EXP_MULTIPLIER GEN_7 // Gen7+ trainer EXP multiplier
Boolean Configs
#define B_FLAG_FORCE_SHINY 0 // If set, all wild Pokémon are shiny
#define B_FLAG_NO_WILD_ENCOUNTERS 0 // If set, disables wild encounters
Important Files and Locations
Entry Points
src/main.c- Main entry point (AgbMainfunction)src/crt0.s- C runtime initialization (assembly)ld_script_modern.ld- Linker script defining memory layout
Key Data Files
src/data/moves_info.h- Move definitionssrc/data/items.h- Item definitionssrc/data/species/- Pokémon species data (split across multiple files)src/data/trainers.h- Trainer definitionssrc/data/wild_encounters.json- Wild encounter data (processed to .h)
Graphics Processing
graphics_file_rules.mk- Rules for converting PNG to GBA formats- Graphics converted automatically during build:
.png→.4bpp(4-bit per pixel tiles).png→.8bpp(8-bit per pixel tiles).pal→.gbapal(palette files)
String/Text
src/strings.c- In-game text stringscharmap.txt- Character encoding map for preprocessor
Development Workflow
Branches
master- Stable branch with bugfixesupcoming- Development branch for new featuresexpansion/X.Y.Z- Specific version tags
Contributing Workflow
- Create feature branch from
upcoming(ormasterfor bugfixes) - Make changes following style guide
- Ensure tests pass:
make check - Submit PR to appropriate branch
Migration from pret/pokeemerald
git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion
git pull RHH master # or upcoming
Memory Layout
Defined in ld_script_modern.ld:
- EWRAM: 0x2000000 - 0x2040000 (256 KB, external work RAM)
- IWRAM: 0x3000000 - 0x3008000 (32 KB, internal work RAM, faster)
- ROM: 0x8000000 - 0x8200000 (32 MB maximum)
Variable Placement
// External work RAM (slower, larger)
EWRAM_DATA u32 gLargeArray[1000];
// Internal work RAM (faster, limited)
IWRAM_DATA u32 gFastVariable;
// Common data (preserved across soft reset)
COMMON_DATA u32 gPersistentData;
Security Considerations
Save File Safety
- New features that modify save structures must be gated behind configs
- Default configs should not break existing saves
- Test save compatibility when modifying save-related code
Buffer Safety
- Use sized string functions when available
- Be cautious with
VarGet()and script buffers - Validate array bounds, especially with user-controlled values
Useful Resources
- Documentation: https://rh-hideout.github.io/pokeemerald-expansion/
- Discord: https://discord.gg/6CzjAG6GZk (RHH Server)
- ** pret/pokeemerald**: https://github.com/pret/pokeemerald (upstream)
- Related Tools:
- porymap - Map editor
- poryscript - Scripting language
- porytiles - Tileset tool
Common Issues
- "arm-none-eabi-gcc: command not found": Install devkitARM and ensure it's in PATH
- Tools not building: Run
make toolsexplicitly first - Clean build recommended after config changes:
make clean && make - PNG conversion errors: Ensure
libpngis installed and PNG files are valid