pokeemmo/AGENTS.md
cloyir 22856a2941
Some checks failed
CI / build (push) Has been cancelled
CI / docs_validate (push) Has been cancelled
CI / allcontributors (push) Has been cancelled
Docs / deploy (push) Has been cancelled
用Kimi Code生成了AGENTS.md
2026-03-04 02:13:13 +08:00

401 lines
12 KiB
Markdown

# 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