| # Pokemon Battle System Architecture Analysis | |
| ## Overview | |
| The Pokemon Emerald battle system is a complex, state-driven architecture that orchestrates combat between multiple Pokemon. Rather than being a single monolithic system, it's composed of several interconnected subsystems that handle different aspects of battle functionality. | |
| ## High-Level Architecture | |
| ### Core Components | |
| 1. **Battle State Machine** (`battle_main.c`) | |
| 2. **Battle Controllers** (`battle_controller_*.c` files) | |
| 3. **Animation System** (`battle_anim*.c` files) | |
| 4. **Script Engine** (`battle_script_commands.c`) | |
| 5. **User Interface** (`battle_interface.c`) | |
| 6. **Data Management** (Pokemon storage and battle state) | |
| ## 1. Battle State Management | |
| ### Main Battle Loop | |
| The battle system is built around a main function pointer (`gBattleMainFunc`) that controls the overall battle flow: | |
| ```c | |
| // Central battle state function pointer | |
| void (*gBattleMainFunc)(void); | |
| ``` | |
| ### Key State Variables | |
| - `gBattleStruct` - Central battle state container | |
| - `gBattleMons[MAX_BATTLERS_COUNT]` - Active Pokemon data | |
| - `gBattlerPositions[]` - Battler position tracking | |
| - `gBattleTypeFlags` - Battle mode flags (wild, trainer, double, etc.) | |
| gBattleStruct definition: | |
| ```c | |
| struct BattleStruct | |
| { | |
| u8 turnEffectsTracker; | |
| u8 turnEffectsBattlerId; | |
| u8 unused_0; | |
| u8 turnCountersTracker; | |
| u8 wrappedMove[MAX_BATTLERS_COUNT * 2]; // Leftover from Ruby's ewram access. | |
| u8 moveTarget[MAX_BATTLERS_COUNT]; | |
| u8 expGetterMonId; | |
| u8 unused_1; | |
| u8 wildVictorySong; | |
| u8 dynamicMoveType; | |
| u8 wrappedBy[MAX_BATTLERS_COUNT]; | |
| u16 assistPossibleMoves[PARTY_SIZE * MAX_MON_MOVES]; // Each of mons can know max 4 moves. | |
| u8 focusPunchBattlerId; | |
| u8 battlerPreventingSwitchout; | |
| u8 moneyMultiplier; | |
| u8 savedTurnActionNumber; | |
| u8 switchInAbilitiesCounter; | |
| u8 faintedActionsState; | |
| u8 faintedActionsBattlerId; | |
| u16 expValue; | |
| u8 scriptPartyIdx; // for printing the nickname | |
| u8 sentInPokes; | |
| bool8 selectionScriptFinished[MAX_BATTLERS_COUNT]; | |
| u8 battlerPartyIndexes[MAX_BATTLERS_COUNT]; | |
| u8 monToSwitchIntoId[MAX_BATTLERS_COUNT]; | |
| u8 battlerPartyOrders[MAX_BATTLERS_COUNT][PARTY_SIZE / 2]; | |
| u8 runTries; | |
| u8 caughtMonNick[POKEMON_NAME_LENGTH + 1]; | |
| u8 unused_2; | |
| u8 safariGoNearCounter; | |
| u8 safariPkblThrowCounter; | |
| u8 safariEscapeFactor; | |
| u8 safariCatchFactor; | |
| u8 linkBattleVsSpriteId_V; // The letter "V" | |
| u8 linkBattleVsSpriteId_S; // The letter "S" | |
| u8 formToChangeInto; | |
| u8 chosenMovePositions[MAX_BATTLERS_COUNT]; | |
| u8 stateIdAfterSelScript[MAX_BATTLERS_COUNT]; | |
| u8 unused_3[3]; | |
| u8 prevSelectedPartySlot; | |
| u8 unused_4[2]; | |
| u8 stringMoveType; | |
| u8 expGetterBattlerId; | |
| u8 unused_5; | |
| u8 absentBattlerFlags; | |
| u8 palaceFlags; // First 4 bits are "is <= 50% HP and not asleep" for each battler, last 4 bits are selected moves to pass to AI | |
| u8 field_93; // related to choosing pokemon? | |
| u8 wallyBattleState; | |
| u8 wallyMovesState; | |
| u8 wallyWaitFrames; | |
| u8 wallyMoveFrames; | |
| u8 lastTakenMove[MAX_BATTLERS_COUNT * 2 * 2]; // Last move that a battler was hit with. This field seems to erroneously take 16 bytes instead of 8. | |
| u16 hpOnSwitchout[NUM_BATTLE_SIDES]; | |
| u32 savedBattleTypeFlags; | |
| u8 abilityPreventingSwitchout; | |
| u8 hpScale; | |
| u8 synchronizeMoveEffect; | |
| bool8 anyMonHasTransformed; | |
| void (*savedCallback)(void); | |
| u16 usedHeldItems[MAX_BATTLERS_COUNT]; | |
| u8 chosenItem[MAX_BATTLERS_COUNT]; // why is this an u8? | |
| u8 AI_itemType[2]; | |
| u8 AI_itemFlags[2]; | |
| u16 choicedMove[MAX_BATTLERS_COUNT]; | |
| u16 changedItems[MAX_BATTLERS_COUNT]; | |
| u8 intimidateBattler; | |
| u8 switchInItemsCounter; | |
| u8 arenaTurnCounter; | |
| u8 turnSideTracker; | |
| u8 unused_6[3]; | |
| u8 givenExpMons; // Bits for enemy party's Pokémon that gave exp to player's party. | |
| u8 lastTakenMoveFrom[MAX_BATTLERS_COUNT * MAX_BATTLERS_COUNT * 2]; // a 3-D array [target][attacker][byte] | |
| u16 castformPalette[NUM_CASTFORM_FORMS][16]; | |
| union { | |
| struct LinkBattlerHeader linkBattlerHeader; | |
| u32 battleVideo[2]; | |
| } multiBuffer; | |
| u8 wishPerishSongState; | |
| u8 wishPerishSongBattlerId; | |
| bool8 overworldWeatherDone; | |
| u8 atkCancellerTracker; | |
| struct BattleTvMovePoints tvMovePoints; | |
| struct BattleTv tv; | |
| u8 unused_7[0x28]; | |
| u8 AI_monToSwitchIntoId[MAX_BATTLERS_COUNT]; | |
| s8 arenaMindPoints[2]; | |
| s8 arenaSkillPoints[2]; | |
| u16 arenaStartHp[2]; | |
| u8 arenaLostPlayerMons; // Bits for party member, lost as in referee's decision, not by fainting. | |
| u8 arenaLostOpponentMons; | |
| u8 alreadyStatusedMoveAttempt; // As bits for battlers; For example when using Thunder Wave on an already paralyzed Pokémon. | |
| }; | |
| ``` | |
| ### Battle Flow States | |
| The battle progresses through distinct phases: | |
| 1. **Initialization** - Setup battlers, load graphics | |
| 2. **Turn Selection** - Player/AI choose actions | |
| 3. **Action Resolution** - Execute moves in priority order | |
| 4. **Turn Cleanup** - Apply end-of-turn effects | |
| 5. **Battle End** - Victory/defeat/capture resolution | |
| ## 2. Controller Architecture | |
| ### Battler Controllers | |
| Each battler (player, opponent, partner, etc.) has its own controller that handles: | |
| - Input processing | |
| - Animation requests | |
| - Data updates | |
| - UI management | |
| ```c | |
| // Controller function pointer array | |
| void (*gBattlerControllerFuncs[MAX_BATTLERS_COUNT])(void); | |
| ``` | |
| ### Controller Types | |
| - **Player Controller** (`battle_controller_player.c`) - Human input | |
| - **Opponent Controller** (`battle_controller_opponent.c`) - AI decisions | |
| - **Link Controllers** - Network battlers | |
| - **Special Controllers** - Safari Zone, Wally, etc. | |
| ### Command System | |
| Controllers communicate via command buffers: | |
| ```c | |
| // Controller commands (simplified) | |
| CONTROLLER_GETMONDATA // Request Pokemon data | |
| CONTROLLER_CHOOSEACTION // Select battle action | |
| CONTROLLER_MOVEANIMATION // Play move animation | |
| CONTROLLER_HEALTHBARUPDATE // Update HP display | |
| ``` | |
| ## 3. Animation System | |
| ### Animation Pipeline | |
| Animations are script-driven and hierarchical: | |
| 1. **Move Animation Selection** - Choose appropriate animation | |
| 2. **Script Execution** - Run animation script commands | |
| 3. **Sprite Management** - Create/animate visual elements | |
| 4. **Audio Synchronization** - Play sound effects | |
| 5. **Cleanup** - Remove temporary sprites | |
| ### Animation Scripts | |
| Each move has an associated animation script: | |
| ```c | |
| const u8 *const gBattleAnims_Moves[]; | |
| ``` | |
| ### Animation Commands | |
| Scripts use specialized commands: | |
| - `loadspritegfx` - Load sprite graphics | |
| - `createsprite` - Create animated sprite | |
| - `playse` - Play sound effect | |
| - `delay` - Wait specified frames | |
| - `monbg` - Modify Pokemon background | |
| ### Visual Task System | |
| Complex animations use visual tasks for frame-by-frame control: | |
| ```c | |
| u8 gAnimVisualTaskCount; // Active visual task counter | |
| ``` | |
| ## 4. Pokemon Data Storage and Retrieval | |
| ### Battle Pokemon Structure | |
| Active Pokemon are stored in `gBattleMons[]`: | |
| ```c | |
| struct BattlePokemon { | |
| u16 species; | |
| u16 attack; | |
| u16 defense; | |
| u16 speed; | |
| u16 spAttack; | |
| u16 spDefense; | |
| u16 moves[MAX_MON_MOVES]; | |
| u32 hp; | |
| u8 level; | |
| u8 pp[MAX_MON_MOVES]; | |
| // ... status, abilities, etc. | |
| }; | |
| ``` | |
| ### Data Synchronization | |
| The system maintains consistency between: | |
| - **Party Data** - Full Pokemon in party array | |
| - **Battle Data** - Reduced battle-specific data | |
| - **Display Data** - UI representation | |
| ### Data Flow | |
| 1. **Load Phase** - Copy party data to battle structure | |
| 2. **Battle Phase** - Modify battle data only | |
| 3. **Update Phase** - Sync changes back to party | |
| ## 5. Menu Systems and Input Handling | |
| ### Action Selection Menu | |
| The main battle menu uses a state-driven approach: | |
| ```c | |
| static void PlayerHandleChooseAction(void) { | |
| // Present: Fight, Pokemon, Bag, Run options | |
| // Handle input and set action type | |
| } | |
| ``` | |
| ### Move Selection Interface | |
| Move selection involves: | |
| 1. **Display Moves** - Show available moves with PP | |
| 2. **Input Handling** - Process directional input | |
| 3. **Move Info** - Display type, power, accuracy | |
| 4. **Target Selection** - Choose targets for multi-target moves | |
| ### Menu State Management | |
| - Cursor position tracking | |
| - Input validation | |
| - Visual feedback (highlighting, animations) | |
| - Transition between menu levels | |
| ## 6. Action Processing and Effect Application | |
| ### Turn Order Resolution | |
| Actions are sorted by priority: | |
| 1. **Switch Pokemon** (highest priority) | |
| 2. **Use Items** | |
| 3. **Use Moves** (sorted by speed/priority) | |
| 4. **Flee** | |
| ### Move Execution Pipeline | |
| When a move is used: | |
| 1. **Validation** - Check if move can be used | |
| 2. **Target Selection** - Determine valid targets | |
| 3. **Script Execution** - Run move's battle script | |
| 4. **Animation** - Play visual/audio effects | |
| 5. **Damage Calculation** - Apply damage formulas | |
| 6. **Effect Application** - Apply status effects, stat changes | |
| 7. **Cleanup** - Update battle state | |
| ### Battle Script System | |
| Moves use script commands for effects: | |
| ```c | |
| static void Cmd_attackstring(void); // Display attack message | |
| static void Cmd_attackanimation(void); // Play attack animation | |
| static void Cmd_damagecalc(void); // Calculate damage | |
| static void Cmd_healthbarupdate(void); // Update HP bar | |
| ``` | |
| ### Gradual Information Delivery | |
| The system delivers information to players progressively: | |
| 1. **Action Announcement** - "Pokemon used Move!" | |
| 2. **Animation Phase** - Visual move animation | |
| 3. **Result Messages** - Effectiveness, critical hits | |
| 4. **Damage Application** - Gradual HP bar drain | |
| 5. **Status Updates** - Additional effects | |
| 6. **Turn Cleanup** - End-of-turn effects | |
| ## 7. Key Programming Patterns | |
| ### State Machine Architecture | |
| The battle system extensively uses function pointers for state management: | |
| ```c | |
| void (*gBattleMainFunc)(void); // Main battle state | |
| void (*gBattlerControllerFuncs[])(void); // Controller states | |
| void (*gAnimScriptCallback)(void); // Animation states | |
| ``` | |
| ### Command-Driven Controllers | |
| Controllers process commands via lookup tables: | |
| ```c | |
| static void (*const sPlayerBufferCommands[])(void) = { | |
| [CONTROLLER_GETMONDATA] = PlayerHandleGetMonData, | |
| [CONTROLLER_CHOOSEACTION] = PlayerHandleChooseAction, | |
| // ... | |
| }; | |
| ``` | |
| ### Script-Based Effects | |
| Both animations and move effects use bytecode scripts for flexibility: | |
| - Animation scripts control visual presentation | |
| - Battle scripts control game logic and effects | |
| ### Asynchronous Processing | |
| The system handles multiple concurrent operations: | |
| - Animations can run while processing user input | |
| - Multiple battlers can be in different states | |
| - Background tasks handle gradual effects (HP drain, etc.) | |
| ## 8. Memory Management | |
| ### Battle Resources Structure | |
| ```c | |
| struct BattleResources { | |
| struct SecretBase *secretBase; | |
| struct ResourceFlags *flags; | |
| struct BattleScriptsStack *battleScriptsStack; | |
| struct AI_ThinkingStruct *ai; | |
| struct BattleHistory *battleHistory; | |
| }; | |
| ``` | |
| ### Dynamic Allocation | |
| - Battle resources are allocated at battle start | |
| - Freed when battle ends | |
| - Sprites and animations use temporary allocation | |
| ## 9. Extension Points | |
| The architecture provides several extension mechanisms: | |
| - **New Move Effects** - Add scripts to move effect table | |
| - **Custom Animations** - Create new animation scripts | |
| - **Battle Types** - Add flags and specialized controllers | |
| - **AI Behaviors** - Extend AI decision trees | |
| ## Summary | |
| The Pokemon battle system demonstrates sophisticated game architecture through: | |
| 1. **Separation of Concerns** - Controllers, animations, scripts, and UI are distinct | |
| 2. **Data-Driven Design** - Moves, animations, and effects defined in data tables | |
| 3. **State Management** - Clear state machines for battle flow and individual components | |
| 4. **Asynchronous Processing** - Multiple concurrent operations with proper coordination | |
| 5. **Extensibility** - Modular design allows for easy addition of new content | |
| This architecture allows complex battle interactions while maintaining code organization and enabling the rich, interactive experience that defines Pokemon battles. | |