Heroic Opportunities System
The Heroic Opportunities (HO) system implements EverQuest II's cooperative combat mechanic where players coordinate ability usage to complete beneficial spell effects.
Overview
Heroic Opportunities are multi-stage cooperative encounters that require precise timing and coordination. The system consists of two main phases:
- Starter Chain Phase: Players use abilities in sequence to complete a starter chain
- Wheel Phase: Players complete abilities on a randomized wheel within a time limit
Architecture
Core Components
HeroicOPStarter
Represents starter chains that initiate heroic opportunities:
- Class Restrictions: Specific classes can initiate specific starters
- Ability Sequence: Up to 6 abilities that must be used in order
- Completion Marker: Special marker (0xFFFF) indicates chain completion
HeroicOPWheel
Represents the wheel phase with ability completion requirements:
- Order Types: Unordered (any sequence) vs Ordered (specific sequence)
- Shift Capability: Ability to change to different wheel once per HO
- Completion Spell: Spell cast when wheel is successfully completed
- Chance Weighting: Probability factor for random wheel selection
HeroicOP
Active HO instance with state management:
- Multi-phase State: Tracks progression through starter → wheel → completion
- Timer Management: Precise timing controls for wheel phase
- Participant Tracking: Manages all players involved in the HO
- Progress Validation: Ensures abilities match current requirements
System Flow
Player Uses Starter Ability
↓
System Loads Available Starters for Class
↓
Eliminate Non-matching Starters
↓
Starter Complete? → Yes → Select Random Wheel
↓ ↓
No Start Wheel Phase Timer
↓ ↓
Continue Starter Chain Players Complete Abilities
↓ ↓
More Starters? → No → HO Fails All Complete? → Yes → Cast Spell
↓
No → Timer Expired? → Yes → HO Fails
Database Schema
heroic_ops Table
Stores both starters and wheels with type discrimination:
CREATE TABLE heroic_ops (
id INTEGER NOT NULL,
ho_type TEXT CHECK(ho_type IN ('Starter', 'Wheel')),
starter_class INTEGER, -- For starters: class restriction
starter_icon INTEGER, -- For starters: initiating icon
starter_link_id INTEGER, -- For wheels: associated starter ID
chain_order INTEGER, -- For wheels: order requirement
shift_icon INTEGER, -- For wheels: shift ability icon
spell_id INTEGER, -- For wheels: completion spell
chance REAL, -- For wheels: selection probability
ability1-6 INTEGER, -- Ability icons
name TEXT,
description TEXT
);
heroic_op_instances Table
Tracks active HO instances:
CREATE TABLE heroic_op_instances (
id INTEGER PRIMARY KEY,
encounter_id INTEGER,
starter_id INTEGER,
wheel_id INTEGER,
state INTEGER,
countered_1-6 INTEGER, -- Completion status per ability
shift_used INTEGER,
time_remaining INTEGER,
-- ... additional fields
);
Key Features
Multi-Class Initiation
- Specific classes can initiate specific starter chains
- Universal starters (class 0) available to all classes
- Class validation ensures proper HO eligibility
Dynamic Wheel Selection
- Random selection from available wheels per starter
- Weighted probability based on chance values
- Prevents predictable HO patterns
Wheel Shifting
- One-time ability to change wheels during wheel phase
- Timing Restrictions: Only before progress (unordered) or at start (ordered)
- Strategic Element: Allows adaptation to group composition
Precise Timing
- Configurable wheel phase timers (default 10 seconds)
- Millisecond precision for fair completion windows
- Automatic cleanup of expired HOs
Order Enforcement
- Unordered Wheels: Any ability can be completed in any sequence
- Ordered Wheels: Abilities must be completed in specific order
- Validation: System prevents invalid ability usage
Usage Examples
Starting a Heroic Opportunity
// Initialize HO manager
manager := NewHeroicOPManager(masterList, database, clientManager, encounterManager, playerManager)
manager.Initialize(ctx, config)
// Start HO for encounter
ho, err := manager.StartHeroicOpportunity(ctx, encounterID, initiatorCharacterID)
if err != nil {
return fmt.Errorf("failed to start HO: %w", err)
}
Processing Player Abilities
// Player uses ability during HO
err := manager.ProcessAbility(ctx, ho.ID, characterID, abilityIcon)
if err != nil {
// Ability not allowed or HO in wrong state
return err
}
// Check if HO completed
if ho.IsComplete() {
// Completion spell will be cast automatically
log.Printf("HO completed by character %d", ho.CompletedBy)
}
Timer Management
// Update all active HO timers (called periodically)
manager.UpdateTimers(ctx, deltaMilliseconds)
// Expired HOs are automatically failed and cleaned up
Client Communication
Packet Types
- HO Start: Initial HO initiation notification
- HO Update: Wheel phase updates with ability icons
- HO Progress: Real-time completion progress
- HO Timer: Timer countdown updates
- HO Complete: Success/failure notification
- HO Shift: Wheel change notification
Real-time Updates
- Participants receive immediate feedback on ability usage
- Progress updates show completion status
- Timer updates maintain urgency during wheel phase
Configuration
System Parameters
config := &HeroicOPConfig{
DefaultWheelTimer: 10000, // 10 seconds in milliseconds
MaxConcurrentHOs: 3, // Per encounter
EnableLogging: true,
EnableStatistics: true,
EnableShifting: true,
RequireClassMatch: true,
}
Performance Tuning
- Concurrent HOs: Limit simultaneous HOs per encounter
- Cleanup Intervals: Regular removal of expired instances
- Database Batching: Efficient event logging
- Memory Management: Instance pooling for high-traffic servers
Integration Points
Spell System Integration
- Completion spells cast through spell manager
- Spell validation and effect application
- Integration with existing spell mechanics
Encounter System Integration
- HO availability tied to active encounters
- Participant validation through encounter membership
- Encounter end triggers HO cleanup
Player System Integration
- Class validation for starter eligibility
- Ability validation for wheel completion
- Player state checking (online, in combat, etc.)
Error Handling
Common Error Scenarios
- Invalid State: Ability used when HO not in correct phase
- Timer Expired: Wheel phase timeout
- Ability Not Allowed: Ability doesn't match current requirements
- Shift Already Used: Attempting multiple shifts
- Player Not in Encounter: Participant validation failure
Recovery Mechanisms
- Automatic HO failure on unrecoverable errors
- Client notification of error conditions
- Logging for debugging and analysis
- Graceful degradation when components unavailable
Thread Safety
All core components use proper Go concurrency patterns:
- RWMutex Protection: Reader-writer locks for shared data
- Atomic Operations: Lock-free operations where possible
- Context Cancellation: Proper cleanup on shutdown
- Channel Communication: Safe inter-goroutine messaging
Performance Considerations
Memory Management
- Object pooling for frequently created instances
- Efficient cleanup of expired HOs
- Bounded history retention
Database Optimization
- Indexed queries for fast lookups
- Batch operations for event logging
- Connection pooling for concurrent access
Network Efficiency
- Minimal packet sizes for real-time updates
- Client version-specific optimizations
- Broadcast optimization for group updates
Testing
Unit Tests
- Individual component validation
- State machine testing
- Error condition handling
- Concurrent access patterns
Integration Tests
- Full HO lifecycle scenarios
- Multi-player coordination
- Database persistence validation
- Client communication verification
Future Enhancements
Planned Features
- Lua Scripting: Custom HO behaviors
- Advanced Statistics: Detailed analytics
- Dynamic Difficulty: Adaptive timer adjustments
- Guild Coordination: Guild-wide HO tracking
Scalability Improvements
- Clustering Support: Multi-server HO coordination
- Caching Layer: Redis integration for high-traffic
- Async Processing: Background HO processing
- Load Balancing: Distribution across game servers
Conversion Notes
This Go implementation maintains full compatibility with the original C++ EQ2EMu system while modernizing the architecture:
- Thread Safety: Proper Go concurrency patterns
- Error Handling: Comprehensive error wrapping
- Context Usage: Cancellation and timeout support
- Interface Design: Modular, testable components
- Database Integration: Modern query patterns
All original functionality has been preserved, including complex mechanics like wheel shifting, ordered/unordered completion, and precise timing requirements.