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:
- Move Constants - Unique IDs for each move
- Move Data Structure - Statistical properties and effect assignments
- Effect Constants - Categorization of move behaviors
- Battle Scripts - Implementation logic for each effect
- Script Commands - Low-level operations for battle mechanics
Layer 1: Move Constants (include/constants/moves.h
)
Each move gets a unique constant identifier:
#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:
[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:
#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:
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:
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):
BattleScript_EffectPoisonHit::
setmoveeffect MOVE_EFFECT_POISON # Set secondary effect
goto BattleScript_EffectHit # Use standard hit logic
Multi-Hit:
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)
// 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)
// 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)
// 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
.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
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
#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
// 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
// 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
// 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.