|
# Defining Attacks in pokeemerald |
|
|
|
This document analyzes how pokeemerald defines battle actions (moves/attacks) and their effects, providing a clear system architecture for implementing similar battle mechanics in Pokemon-style games. |
|
|
|
## Architecture Overview |
|
|
|
pokeemerald uses a **multi-layered, data-driven approach** to define attacks: |
|
|
|
1. **Move Constants** - Unique IDs for each move |
|
2. **Move Data Structure** - Statistical properties and effect assignments |
|
3. **Effect Constants** - Categorization of move behaviors |
|
4. **Battle Scripts** - Implementation logic for each effect |
|
5. **Script Commands** - Low-level operations for battle mechanics |
|
|
|
## Layer 1: Move Constants (`include/constants/moves.h`) |
|
|
|
Each move gets a unique constant identifier: |
|
|
|
```c |
|
#define MOVE_NONE 0 |
|
#define MOVE_POUND 1 |
|
#define MOVE_KARATE_CHOP 2 |
|
#define MOVE_DOUBLE_SLAP 3 |
|
// ... continues for all moves |
|
``` |
|
|
|
**Key Benefits:** |
|
- Type-safe move references throughout codebase |
|
- Easy to add new moves without conflicts |
|
- Clear naming convention |
|
|
|
## Layer 2: Move Data Structure (`src/data/battle_moves.h`) |
|
|
|
Each move is defined using the `BattleMove` struct: |
|
|
|
```c |
|
[MOVE_POUND] = { |
|
.effect = EFFECT_HIT, // What the move does |
|
.power = 40, // Base damage |
|
.type = TYPE_NORMAL, // Move type (Normal, Fire, etc.) |
|
.accuracy = 100, // Hit chance (0-100) |
|
.pp = 35, // Power Points (usage count) |
|
.secondaryEffectChance = 0, // Chance of secondary effect |
|
.target = MOVE_TARGET_SELECTED, // Who can be targeted |
|
.priority = 0, // Move speed priority |
|
.flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, |
|
}, |
|
``` |
|
|
|
**Key Features:** |
|
- **Separation of Concerns**: Stats vs. behavior logic |
|
- **Flag System**: Modular properties (contact, protection, etc.) |
|
- **Secondary Effects**: Built-in chance system for additional effects |
|
- **Targeting System**: Flexible target selection |
|
|
|
## Layer 3: Effect Constants (`include/constants/battle_move_effects.h`) |
|
|
|
Effects categorize move behaviors into reusable types: |
|
|
|
```c |
|
#define EFFECT_HIT 0 // Basic damage |
|
#define EFFECT_SLEEP 1 // Status effect |
|
#define EFFECT_POISON_HIT 2 // Damage + poison |
|
#define EFFECT_ABSORB 3 // Drain HP |
|
#define EFFECT_BURN_HIT 4 // Damage + burn |
|
#define EFFECT_MULTI_HIT 29 // Multiple strikes |
|
#define EFFECT_HIGH_CRITICAL 43 // Increased crit chance |
|
// ... 200+ different effects |
|
``` |
|
|
|
**Benefits:** |
|
- **Reusability**: Multiple moves can share the same effect |
|
- **Extensibility**: New effects can be added without changing existing moves |
|
- **Organization**: Related behaviors grouped together |
|
|
|
## Layer 4: Battle Scripts (`data/battle_scripts_1.s`) |
|
|
|
Each effect maps to a battle script that defines the actual implementation: |
|
|
|
```assembly |
|
gBattleScriptsForMoveEffects:: |
|
.4byte BattleScript_EffectHit @ EFFECT_HIT |
|
.4byte BattleScript_EffectSleep @ EFFECT_SLEEP |
|
.4byte BattleScript_EffectPoisonHit @ EFFECT_POISON_HIT |
|
// ... maps all effects to their scripts |
|
``` |
|
|
|
### Example Battle Scripts: |
|
|
|
**Basic Hit:** |
|
```assembly |
|
BattleScript_EffectHit:: |
|
attackcanceler # Check if attack can proceed |
|
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE |
|
attackstring # Display move name |
|
ppreduce # Consume PP |
|
critcalc # Calculate critical hits |
|
damagecalc # Calculate damage |
|
typecalc # Apply type effectiveness |
|
adjustnormaldamage # Apply damage modifications |
|
attackanimation # Play visual effects |
|
waitanimation # Wait for animation |
|
effectivenesssound # Play sound effects |
|
# ... continues with damage application |
|
``` |
|
|
|
**Poison Hit (Damage + Status):** |
|
```assembly |
|
BattleScript_EffectPoisonHit:: |
|
setmoveeffect MOVE_EFFECT_POISON # Set secondary effect |
|
goto BattleScript_EffectHit # Use standard hit logic |
|
``` |
|
|
|
**Multi-Hit:** |
|
```assembly |
|
BattleScript_EffectMultiHit:: |
|
attackcanceler |
|
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE |
|
attackstring |
|
ppreduce |
|
setmultihitcounter 0 # Initialize hit counter |
|
initmultihitstring # Setup hit count display |
|
BattleScript_MultiHitLoop:: |
|
jumpifhasnohp BS_ATTACKER, BattleScript_MultiHitEnd |
|
jumpifhasnohp BS_TARGET, BattleScript_MultiHitPrintStrings |
|
# ... hit logic with loop control |
|
``` |
|
|
|
## Layer 5: Script Commands (`src/battle_script_commands.c`) |
|
|
|
Low-level commands that scripts use: |
|
|
|
- **Flow Control**: `jumpif*`, `goto`, `call`, `return` |
|
- **Battle Mechanics**: `accuracycheck`, `critcalc`, `damagecalc` |
|
- **Status Effects**: `setmoveeffect`, `seteffectprimary` |
|
- **Animation**: `attackanimation`, `waitanimation` |
|
- **State Management**: `attackcanceler`, `movevaluescleanup` |
|
|
|
## Complex Effect Patterns |
|
|
|
### 1. **Composite Effects** (Hit + Status) |
|
```c |
|
// Move data specifies base effect |
|
.effect = EFFECT_BURN_HIT, |
|
|
|
// Script combines damage with status |
|
BattleScript_EffectBurnHit:: |
|
setmoveeffect MOVE_EFFECT_BURN # Add burn chance |
|
goto BattleScript_EffectHit # Execute standard damage |
|
``` |
|
|
|
### 2. **Multi-Stage Effects** (Charging moves) |
|
```c |
|
// Sky Attack: charge turn, then hit |
|
.effect = EFFECT_SKY_ATTACK, |
|
|
|
BattleScript_EffectSkyAttack:: |
|
jumpifstatus2 BS_ATTACKER, STATUS2_MULTIPLETURNS, BattleScript_TwoTurnMovesSecondTurn |
|
jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_NO_ATTACKSTRING, BattleScript_TwoTurnMovesSecondTurn |
|
# First turn: charge up |
|
# Second turn: attack |
|
``` |
|
|
|
### 3. **Variable Effects** (Power/behavior changes) |
|
```c |
|
// Moves that change behavior based on conditions |
|
jumpifnotmove MOVE_SURF, BattleScript_HitFromAtkCanceler |
|
jumpifnostatus3 BS_TARGET, STATUS3_UNDERWATER, BattleScript_HitFromAtkCanceler |
|
orword gHitMarker, HITMARKER_IGNORE_UNDERWATER |
|
setbyte sDMG_MULTIPLIER, 2 # Double damage underwater |
|
``` |
|
|
|
## Key Design Principles |
|
|
|
### 1. **Separation of Data and Logic** |
|
- Move stats (power, accuracy, PP) separate from behavior logic |
|
- Enables easy balancing without code changes |
|
- Clear data-driven approach |
|
|
|
### 2. **Effect Reusability** |
|
- Many moves share the same effect type |
|
- New moves can reuse existing effects |
|
- Reduces code duplication |
|
|
|
### 3. **Modular Flag System** |
|
```c |
|
.flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED |
|
``` |
|
- Each flag represents an independent property |
|
- Easy to combine properties |
|
- Consistent interaction rules |
|
|
|
### 4. **Script-Based Flexibility** |
|
- Complex logic implemented in battle scripts |
|
- Scripts can call other scripts (`goto`, `call`) |
|
- Allows for sophisticated move interactions |
|
|
|
### 5. **Centralized Effect Handling** |
|
- All effect implementations in one location |
|
- Easy to debug and maintain |
|
- Consistent patterns across similar effects |
|
|
|
## Implementation Recommendations |
|
|
|
For a Pokemon-style battle system: |
|
|
|
### 1. **Start with Core Structure** |
|
```c |
|
struct Move { |
|
u16 effect; // Links to effect implementation |
|
u8 power; // Base damage |
|
u8 type; // Element type |
|
u8 accuracy; // Hit chance |
|
u8 pp; // Usage count |
|
u8 secondaryChance; // Secondary effect probability |
|
u8 target; // Targeting rules |
|
s8 priority; // Speed priority |
|
u32 flags; // Behavior flags |
|
}; |
|
``` |
|
|
|
### 2. **Define Effect Categories** |
|
- Start with basic effects (HIT, SLEEP, POISON_HIT, ABSORB) |
|
- Add complex effects as needed |
|
- Group related effects together |
|
|
|
### 3. **Implement Script System** |
|
- Use command-based scripts for flexibility |
|
- Implement basic commands first (damage, accuracy, animation) |
|
- Add advanced commands for complex interactions |
|
|
|
### 4. **Use Flag-Based Properties** |
|
```c |
|
#define FLAG_CONTACT (1 << 0) |
|
#define FLAG_PROTECTABLE (1 << 1) |
|
#define FLAG_REFLECTABLE (1 << 2) |
|
#define FLAG_KINGS_ROCK (1 << 3) |
|
``` |
|
|
|
### 5. **Design for Extensibility** |
|
- Keep effect constants sequential for easy addition |
|
- Use lookup tables for effect-to-script mapping |
|
- Design script commands to be composable |
|
|
|
## Special Effects Implementation |
|
|
|
### Status Effects |
|
```c |
|
// In move data: |
|
.effect = EFFECT_POISON_HIT, |
|
.secondaryEffectChance = 30, |
|
|
|
// In script: |
|
setmoveeffect MOVE_EFFECT_POISON // What status to apply |
|
goto BattleScript_EffectHit // How to apply it |
|
``` |
|
|
|
### Multi-Hit Moves |
|
```c |
|
// Requires special counter management |
|
setmultihitcounter 0 // Initialize |
|
BattleScript_MultiHitLoop:: // Loop label |
|
// Hit logic here |
|
decrementmultihit // Reduce counter |
|
jumpifnotdone BattleScript_MultiHitLoop // Continue if more hits |
|
``` |
|
|
|
### Priority System |
|
```c |
|
// In move data: |
|
.priority = 1, // +1 priority (Quick Attack) |
|
.priority = -6, // -6 priority (Counter) |
|
|
|
// Processed during move selection phase |
|
``` |
|
|
|
This architecture allows for clean separation between move definitions, their statistical properties, and their complex behavioral implementations, making it easy to add new moves while maintaining code organization and reusability. |