# 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](https://github.com/pret/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-hydra` for multi-process test execution ## Build Commands ### Standard Builds ```bash # 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 ```bash # 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 ```bash # Build for different games (though Emerald is the main target) make emerald # Default make firered # FireRed variant make leafgreen # LeafGreen variant ``` ### Build Options ```bash # 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_*.c` files (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 configuration - `pokemon.h` - Pokémon-related settings - `overworld.h` - Overworld feature toggles - `debug.h` - Debug menu settings - `ai.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 ### Example Code Style ```c 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) or `s32` (signed) - **Save block data**: Use smallest possible type - **EWRAM variables**: Use smallest possible type - **Booleans**: Use `bool8` or `bool32` from `types.h` ### Inline Configs When adding configurable features, check configs within normal control flow: ```c // 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`: ```c 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: ```c #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`: ```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`: ```c #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: ```c // 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 ```c #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 (`AgbMain` function) - `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 definitions - `src/data/items.h` - Item definitions - `src/data/species/` - Pokémon species data (split across multiple files) - `src/data/trainers.h` - Trainer definitions - `src/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 strings - `charmap.txt` - Character encoding map for preprocessor ## Development Workflow ### Branches - `master` - Stable branch with bugfixes - `upcoming` - Development branch for new features - `expansion/X.Y.Z` - Specific version tags ### Contributing Workflow 1. Create feature branch from `upcoming` (or `master` for bugfixes) 2. Make changes following style guide 3. Ensure tests pass: `make check` 4. Submit PR to appropriate branch ### Migration from pret/pokeemerald ```bash 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 ```c // 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](https://github.com/huderlem/porymap) - Map editor - [poryscript](https://github.com/huderlem/poryscript) - Scripting language - [porytiles](https://github.com/grunt-lucas/porytiles) - Tileset tool ## Common Issues 1. **"arm-none-eabi-gcc: command not found"**: Install devkitARM and ensure it's in PATH 2. **Tools not building**: Run `make tools` explicitly first 3. **Clean build recommended after config changes**: `make clean && make` 4. **PNG conversion errors**: Ensure `libpng` is installed and PNG files are valid