# Alternate Advancement System The alternate advancement system (`internal/alt_advancement`) provides comprehensive character progression beyond normal leveling for the EQ2Go server emulator. This system is converted from the original C++ EQ2EMu AltAdvancement implementation with modern Go concurrency patterns and clean architecture principles. ## Overview The alternate advancement (AA) system manages character progression through specialized skill trees including: - **Class Trees**: Class-specific advancement paths - **Subclass Trees**: Subclass-specific specializations - **Heroic Trees**: Heroic advancement from Destiny of Velious - **Shadows Trees**: Shadow-based abilities from Shadows of Luclin - **Tradeskill Trees**: Tradeskill-focused advancement - **Prestige Trees**: Prestigious advancement paths - **Dragon Trees**: Dragon-themed advancement - **Far Seas Trees**: Far Seas trading company advancement ## Architecture ### Core Components **MasterAAList** - Global repository of all AA definitions with fast lookup capabilities **MasterAANodeList** - Tree node configurations mapping classes to AA trees **AAManager** - Central management system for all AA operations **AAPlayerState** - Individual player AA progression and template management **DatabaseImpl** - Database operations for persistent AA data ### Key Files - `types.go` - Core data structures and type definitions - `constants.go` - All AA system constants, tab definitions, and limits - `master_list.go` - MasterAAList and MasterAANodeList implementations - `manager.go` - Central AAManager with player state management - `database.go` - Database operations and persistence - `interfaces.go` - System integration interfaces and adapters - `README.md` - This documentation ## System Initialization ```go // Create AA manager with configuration config := alt_advancement.DefaultAAManagerConfig() config.EnableCaching = true config.DatabaseEnabled = true aaManager := alt_advancement.NewAAManager(config) // Set up database integration database := alt_advancement.NewDatabaseImpl(db, masterAAList, masterNodeList, logger) aaManager.SetDatabase(database) // Start the system err := aaManager.Start() if err != nil { log.Fatalf("Failed to start AA system: %v", err) } ``` ## AA Data Management ```go // Load all AA data from database err := aaManager.LoadAAData() if err != nil { log.Printf("Failed to load AA data: %v", err) } // Get specific AA by node ID aaData, err := aaManager.GetAA(nodeID) if err != nil { log.Printf("AA not found: %v", err) } // Get AAs for a specific class classAAs, err := aaManager.GetAAsByClass(classID) fmt.Printf("Found %d AAs for class %d\n", len(classAAs), classID) // Get AAs for a specific tab/group tabAAs, err := aaManager.GetAAsByGroup(alt_advancement.AA_CLASS) fmt.Printf("Class tab has %d AAs\n", len(tabAAs)) ``` ## Player AA Management ```go // Load player's AA data characterID := int32(12345) playerState, err := aaManager.LoadPlayerAA(characterID) if err != nil { log.Printf("Failed to load player AA: %v", err) } // Get player's AA point totals totalPoints, spentPoints, availablePoints, err := aaManager.GetAAPoints(characterID) fmt.Printf("Player has %d total, %d spent, %d available AA points\n", totalPoints, spentPoints, availablePoints) // Award AA points to player err = aaManager.AwardAAPoints(characterID, 10, "Level up bonus") if err != nil { log.Printf("Failed to award AA points: %v", err) } ``` ## AA Purchasing System ```go // Purchase an AA for a player nodeID := int32(1001) targetRank := int8(1) err := aaManager.PurchaseAA(characterID, nodeID, targetRank) if err != nil { log.Printf("AA purchase failed: %v", err) } else { fmt.Println("AA purchased successfully!") } // Refund an AA err = aaManager.RefundAA(characterID, nodeID) if err != nil { log.Printf("AA refund failed: %v", err) } // Check available AAs for a tab availableAAs, err := aaManager.GetAvailableAAs(characterID, alt_advancement.AA_CLASS) fmt.Printf("Player can purchase %d AAs in class tab\n", len(availableAAs)) ``` ## AA Templates System ```go // Change active AA template templateID := int8(alt_advancement.AA_TEMPLATE_PERSONAL_1) err := aaManager.ChangeAATemplate(characterID, templateID) if err != nil { log.Printf("Template change failed: %v", err) } // Save custom AA template err = aaManager.SaveAATemplate(characterID, templateID, "My Build") if err != nil { log.Printf("Template save failed: %v", err) } // Get all templates for player templates, err := aaManager.GetAATemplates(characterID) if err != nil { log.Printf("Failed to get templates: %v", err) } else { for id, template := range templates { fmt.Printf("Template %d: %s (%d entries)\n", id, template.Name, len(template.Entries)) } } ``` ## AA Data Structures ### AltAdvanceData - Individual AA Definition ```go type AltAdvanceData struct { SpellID int32 // Associated spell ID NodeID int32 // Unique node identifier Name string // Display name Description string // AA description Group int8 // Tab/group (AA_CLASS, AA_SUBCLASS, etc.) Col int8 // Column position in tree Row int8 // Row position in tree Icon int16 // Display icon ID RankCost int8 // Cost per rank MaxRank int8 // Maximum achievable rank MinLevel int8 // Minimum character level RankPrereqID int32 // Prerequisite AA node ID RankPrereq int8 // Required rank in prerequisite ClassReq int8 // Required class (0 = all classes) // ... additional fields } ``` ### AAPlayerState - Player AA Progression ```go type AAPlayerState struct { CharacterID int32 // Character identifier TotalPoints int32 // Total AA points earned SpentPoints int32 // Total AA points spent AvailablePoints int32 // Available AA points for spending BankedPoints int32 // Banked AA points ActiveTemplate int8 // Currently active template Templates map[int8]*AATemplate // All templates Tabs map[int8]*AATab // Tab states AAProgress map[int32]*PlayerAAData // AA progression by node ID // ... synchronization and metadata } ``` ## AA Tab System The system supports 10 different AA tabs: ```go // AA tab constants const ( AA_CLASS = 0 // Class-specific abilities AA_SUBCLASS = 1 // Subclass specializations AA_SHADOW = 2 // Shadow abilities AA_HEROIC = 3 // Heroic advancement AA_TRADESKILL = 4 // Tradeskill abilities AA_PRESTIGE = 5 // Prestige advancement AA_TRADESKILL_PRESTIGE = 6 // Tradeskill prestige AA_DRAGON = 7 // Dragon abilities AA_DRAGONCLASS = 8 // Dragon class abilities AA_FARSEAS = 9 // Far Seas abilities ) // Get maximum AA points for each tab maxClassAA := alt_advancement.GetMaxAAForTab(alt_advancement.AA_CLASS) // 100 maxHeroicAA := alt_advancement.GetMaxAAForTab(alt_advancement.AA_HEROIC) // 50 ``` ## Database Integration ```go // Custom database implementation type MyAADatabase struct { db *sql.DB } func (db *MyAADatabase) LoadAltAdvancements() error { // Load AA definitions from database return nil } func (db *MyAADatabase) LoadPlayerAA(characterID int32) (*AAPlayerState, error) { // Load player AA data from database return nil, nil } func (db *MyAADatabase) SavePlayerAA(playerState *AAPlayerState) error { // Save player AA data to database return nil } // Set database implementation aaManager.SetDatabase(&MyAADatabase{db: myDB}) ``` ## Event Handling ```go // Custom event handler type MyAAEventHandler struct{} func (h *MyAAEventHandler) OnAAPurchased(characterID int32, nodeID int32, newRank int8, pointsSpent int32) error { fmt.Printf("Player %d purchased AA %d rank %d for %d points\n", characterID, nodeID, newRank, pointsSpent) return nil } func (h *MyAAEventHandler) OnAATemplateChanged(characterID int32, oldTemplate, newTemplate int8) error { fmt.Printf("Player %d changed template from %d to %d\n", characterID, oldTemplate, newTemplate) return nil } func (h *MyAAEventHandler) OnPlayerAAPointsChanged(characterID int32, oldPoints, newPoints int32) error { fmt.Printf("Player %d AA points changed from %d to %d\n", characterID, oldPoints, newPoints) return nil } // Register event handler aaManager.SetEventHandler(&MyAAEventHandler{}) ``` ## Validation System ```go // Custom validator type MyAAValidator struct{} func (v *MyAAValidator) ValidateAAPurchase(playerState *AAPlayerState, nodeID int32, targetRank int8) error { // Check if player has enough points if playerState.AvailablePoints < int32(targetRank) { return fmt.Errorf("insufficient AA points") } // Check prerequisites // ... validation logic return nil } func (v *MyAAValidator) ValidatePlayerLevel(playerState *AAPlayerState, aaData *AltAdvanceData) error { // Check minimum level requirement // ... validation logic return nil } // Set validator aaManager.SetValidator(&MyAAValidator{}) ``` ## Statistics and Monitoring ```go // Get system statistics stats := aaManager.GetSystemStats() fmt.Printf("Total AAs loaded: %d\n", stats.TotalAAsLoaded) fmt.Printf("Active players: %d\n", stats.ActivePlayers) fmt.Printf("Total purchases: %d\n", stats.TotalAAPurchases) fmt.Printf("Average points spent: %.1f\n", stats.AveragePointsSpent) // Get player-specific statistics playerStats := aaManager.GetPlayerStats(characterID) fmt.Printf("Player stats: %+v\n", playerStats) // Get database statistics (if database supports it) if db, ok := aaManager.database.(*DatabaseImpl); ok { dbStats, err := db.GetAAStatistics() if err == nil { fmt.Printf("Database stats: %+v\n", dbStats) } } ``` ## Configuration Options ```go // Configure the AA system config := alt_advancement.AAManagerConfig{ EnableAASystem: true, EnableCaching: true, EnableValidation: true, EnableLogging: false, AAPointsPerLevel: 2, MaxBankedPoints: 30, EnableAABanking: true, CacheSize: 10000, UpdateInterval: 1 * time.Second, BatchSize: 100, DatabaseEnabled: true, AutoSave: true, SaveInterval: 5 * time.Minute, } aaManager.SetConfig(config) ``` ## Caching System ```go // Enable caching for better performance cache := alt_advancement.NewSimpleAACache(1000) aaManager.SetCache(cache) // Get cache statistics cacheStats := cache.GetStats() fmt.Printf("Cache hits: %d, misses: %d\n", cacheStats["hits"], cacheStats["misses"]) ``` ## Packet Handling Integration ```go // Custom packet handler type MyAAPacketHandler struct{} func (ph *MyAAPacketHandler) GetAAListPacket(client interface{}) ([]byte, error) { // Build AA list packet for client return []byte{}, nil } func (ph *MyAAPacketHandler) SendAAUpdate(client interface{}, playerState *AAPlayerState) error { // Send AA update to client return nil } func (ph *MyAAPacketHandler) HandleAAPurchase(client interface{}, nodeID int32, rank int8) error { // Handle AA purchase from client return nil } // Set packet handler aaManager.SetPacketHandler(&MyAAPacketHandler{}) ``` ## Advanced Usage ### Custom AA Trees ```go // Create custom AA data customAA := &alt_advancement.AltAdvanceData{ SpellID: 2001, NodeID: 2001, Name: "Custom Ability", Description: "A custom AA ability", Group: alt_advancement.AA_CLASS, Col: 1, Row: 1, Icon: 100, RankCost: 1, MaxRank: 5, MinLevel: 20, ClassReq: 1, // Fighter only } // Add to master list err := masterAAList.AddAltAdvancement(customAA) if err != nil { log.Printf("Failed to add custom AA: %v", err) } ``` ### Bulk Operations ```go // Award AA points to multiple players playerIDs := []int32{1001, 1002, 1003} for _, playerID := range playerIDs { err := aaManager.AwardAAPoints(playerID, 5, "Server event bonus") if err != nil { log.Printf("Failed to award points to player %d: %v", playerID, err) } } // Batch save player states for _, playerID := range playerIDs { err := aaManager.SavePlayerAA(playerID) if err != nil { log.Printf("Failed to save player %d AA data: %v", playerID, err) } } ``` ## Thread Safety All AA operations are thread-safe using appropriate synchronization: - **RWMutex** for read-heavy operations (AA lookups, player state access) - **Atomic operations** for simple counters and flags - **Proper lock ordering** to prevent deadlocks - **Background goroutines** for periodic processing and auto-save - **Channel-based communication** for event handling ## Performance Considerations - **Efficient data structures** with hash maps for O(1) lookups - **Caching system** to reduce database queries - **Batch processing** for bulk operations - **Background processing** to avoid blocking gameplay - **Statistics collection** with minimal overhead - **Memory-efficient storage** with proper cleanup ## Integration with Other Systems The AA system integrates with: - **Player System** - Player-specific AA progression and point management - **Spell System** - AA abilities are linked to spells - **Class System** - Class-specific AA trees and requirements - **Level System** - Level-based AA point awards and prerequisites - **Database System** - Persistent storage of AA data and player progress - **Client System** - AA UI updates and purchase handling - **Achievement System** - AA milestones and progression tracking ## Migration from C++ This Go implementation maintains compatibility with the original C++ EQ2EMu AA system while providing: - **Modern concurrency** with goroutines and channels - **Better error handling** with Go's error interface - **Cleaner architecture** with interface-based design - **Improved maintainability** with package organization - **Enhanced testing** capabilities - **Type safety** with Go's type system - **Memory management** with Go's garbage collector ## TODO Items The conversion includes areas for future implementation: - **Complete packet handling** for all client communication - **Advanced validation** for complex AA prerequisites - **Lua scripting integration** for custom AA behaviors - **Web administration interface** for AA management - **Performance optimizations** for large-scale deployments - **Advanced caching strategies** with TTL and eviction policies - **Metrics and monitoring** integration with external systems - **AA import/export** functionality for configuration management ## Usage Examples See the code examples throughout this documentation for detailed usage patterns. The system is designed to be used alongside the existing EQ2Go server infrastructure with proper initialization and configuration. The AA system provides a solid foundation for character progression mechanics while maintaining the flexibility to extend and customize behavior through the comprehensive interface system.