diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..76adbe0c6a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,400 @@ +# 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