package classes import ( "strings" "sync" ) // Class represents a character class with all its properties type Class struct { ID int8 `json:"id"` Name string `json:"name"` // Uppercase name (WARRIOR) DisplayName string `json:"display_name"` // Friendly name (Warrior) BaseClass int8 `json:"base_class"` // Primary archetype SecondaryBaseClass int8 `json:"secondary_base"` // Secondary archetype ClassType string `json:"type"` // adventure/tradeskill/special IsAdventure bool `json:"is_adventure"` IsTradeskill bool `json:"is_tradeskill"` } // GetID returns the class ID func (c *Class) GetID() int8 { return c.ID } // GetName returns the uppercase class name (C++ API compatibility) func (c *Class) GetName() string { return c.Name } // GetDisplayName returns the friendly display name func (c *Class) GetDisplayName() string { return c.DisplayName } // GetBaseClass returns the base archetype (C++ API compatibility) func (c *Class) GetBaseClass() int8 { return c.BaseClass } // GetSecondaryBaseClass returns the secondary archetype (C++ API compatibility) func (c *Class) GetSecondaryBaseClass() int8 { return c.SecondaryBaseClass } // IsValid returns true if the class ID is valid func (c *Class) IsValid() bool { return c.ID >= MinClassID && c.ID <= MaxClassID } // Manager provides centralized class management with caching and lookup optimization type Manager struct { classes map[int8]*Class // ID -> Class nameToID map[string]int8 // Uppercase name -> ID displayNameMap map[int8]string // ID -> Display name mutex sync.RWMutex // Statistics stats struct { ClassesLoaded int32 LookupsPerformed int32 CacheHits int32 CacheMisses int32 } } // NewManager creates a new class manager func NewManager() *Manager { manager := &Manager{ classes: make(map[int8]*Class), nameToID: make(map[string]int8), displayNameMap: make(map[int8]string), } // Initialize with all classes manager.initializeClasses() return manager } // initializeClasses populates the manager with all class data func (m *Manager) initializeClasses() { m.mutex.Lock() defer m.mutex.Unlock() // Define all classes with their properties classDefinitions := []struct { id int8 name string displayName string baseClass int8 secondaryBase int8 classType string isAdventure bool isTradeskill bool }{ // Base classes {ClassCommoner, "COMMONER", "Commoner", ClassCommoner, ClassCommoner, ClassTypeAdventure, true, false}, {ClassFighter, "FIGHTER", "Fighter", ClassFighter, ClassCommoner, ClassTypeAdventure, true, false}, {ClassPriest, "PRIEST", "Priest", ClassPriest, ClassCommoner, ClassTypeAdventure, true, false}, {ClassMage, "MAGE", "Mage", ClassMage, ClassCommoner, ClassTypeAdventure, true, false}, {ClassScout, "SCOUT", "Scout", ClassScout, ClassCommoner, ClassTypeAdventure, true, false}, // Fighter subclasses {ClassWarrior, "WARRIOR", "Warrior", ClassFighter, ClassCommoner, ClassTypeAdventure, true, false}, {ClassGuardian, "GUARDIAN", "Guardian", ClassFighter, ClassWarrior, ClassTypeAdventure, true, false}, {ClassBerserker, "BERSERKER", "Berserker", ClassFighter, ClassWarrior, ClassTypeAdventure, true, false}, {ClassBrawler, "BRAWLER", "Brawler", ClassFighter, ClassCommoner, ClassTypeAdventure, true, false}, {ClassMonk, "MONK", "Monk", ClassFighter, ClassBrawler, ClassTypeAdventure, true, false}, {ClassBruiser, "BRUISER", "Bruiser", ClassFighter, ClassBrawler, ClassTypeAdventure, true, false}, {ClassCrusader, "CRUSADER", "Crusader", ClassFighter, ClassCommoner, ClassTypeAdventure, true, false}, {ClassShadowknight, "SHADOWKNIGHT", "Shadowknight", ClassFighter, ClassCrusader, ClassTypeAdventure, true, false}, {ClassPaladin, "PALADIN", "Paladin", ClassFighter, ClassCrusader, ClassTypeAdventure, true, false}, // Priest subclasses {ClassCleric, "CLERIC", "Cleric", ClassPriest, ClassCommoner, ClassTypeAdventure, true, false}, {ClassTemplar, "TEMPLAR", "Templar", ClassPriest, ClassCleric, ClassTypeAdventure, true, false}, {ClassInquisitor, "INQUISITOR", "Inquisitor", ClassPriest, ClassCleric, ClassTypeAdventure, true, false}, {ClassDruid, "DRUID", "Druid", ClassPriest, ClassCommoner, ClassTypeAdventure, true, false}, {ClassWarden, "WARDEN", "Warden", ClassPriest, ClassDruid, ClassTypeAdventure, true, false}, {ClassFury, "FURY", "Fury", ClassPriest, ClassDruid, ClassTypeAdventure, true, false}, {ClassShaman, "SHAMAN", "Shaman", ClassPriest, ClassCommoner, ClassTypeAdventure, true, false}, {ClassMystic, "MYSTIC", "Mystic", ClassPriest, ClassShaman, ClassTypeAdventure, true, false}, {ClassDefiler, "DEFILER", "Defiler", ClassPriest, ClassShaman, ClassTypeAdventure, true, false}, // Mage subclasses {ClassSorcerer, "SORCERER", "Sorcerer", ClassMage, ClassCommoner, ClassTypeAdventure, true, false}, {ClassWizard, "WIZARD", "Wizard", ClassMage, ClassSorcerer, ClassTypeAdventure, true, false}, {ClassWarlock, "WARLOCK", "Warlock", ClassMage, ClassSorcerer, ClassTypeAdventure, true, false}, {ClassEnchanter, "ENCHANTER", "Enchanter", ClassMage, ClassCommoner, ClassTypeAdventure, true, false}, {ClassIllusionist, "ILLUSIONIST", "Illusionist", ClassMage, ClassEnchanter, ClassTypeAdventure, true, false}, {ClassCoercer, "COERCER", "Coercer", ClassMage, ClassEnchanter, ClassTypeAdventure, true, false}, {ClassSummoner, "SUMMONER", "Summoner", ClassMage, ClassCommoner, ClassTypeAdventure, true, false}, {ClassConjuror, "CONJUROR", "Conjuror", ClassMage, ClassSummoner, ClassTypeAdventure, true, false}, {ClassNecromancer, "NECROMANCER", "Necromancer", ClassMage, ClassSummoner, ClassTypeAdventure, true, false}, // Scout subclasses {ClassRogue, "ROGUE", "Rogue", ClassScout, ClassCommoner, ClassTypeAdventure, true, false}, {ClassSwashbuckler, "SWASHBUCKLER", "Swashbuckler", ClassScout, ClassRogue, ClassTypeAdventure, true, false}, {ClassBrigand, "BRIGAND", "Brigand", ClassScout, ClassRogue, ClassTypeAdventure, true, false}, {ClassBard, "BARD", "Bard", ClassScout, ClassCommoner, ClassTypeAdventure, true, false}, {ClassTroubador, "TROUBADOR", "Troubador", ClassScout, ClassBard, ClassTypeAdventure, true, false}, {ClassDirge, "DIRGE", "Dirge", ClassScout, ClassBard, ClassTypeAdventure, true, false}, {ClassPredator, "PREDATOR", "Predator", ClassScout, ClassCommoner, ClassTypeAdventure, true, false}, {ClassRanger, "RANGER", "Ranger", ClassScout, ClassPredator, ClassTypeAdventure, true, false}, {ClassAssassin, "ASSASSIN", "Assassin", ClassScout, ClassPredator, ClassTypeAdventure, true, false}, {ClassAnimalist, "ANIMALIST", "Animalist", ClassScout, ClassCommoner, ClassTypeAdventure, true, false}, {ClassBeastlord, "BEASTLORD", "Beastlord", ClassScout, ClassAnimalist, ClassTypeAdventure, true, false}, // Special classes {ClassShaper, "SHAPER", "Shaper", ClassPriest, ClassCommoner, ClassTypeAdventure, true, false}, {ClassChanneler, "CHANNELER", "Channeler", ClassPriest, ClassShaper, ClassTypeAdventure, true, false}, // Tradeskill classes {ClassArtisan, "ARTISAN", "Artisan", ClassArtisan, ClassCommoner, ClassTypeTradeskill, false, true}, {ClassCraftsman, "CRAFTSMAN", "Craftsman", ClassArtisan, ClassCommoner, ClassTypeTradeskill, false, true}, {ClassProvisioner, "PROVISIONER", "Provisioner", ClassArtisan, ClassCraftsman, ClassTypeTradeskill, false, true}, {ClassWoodworker, "WOODWORKER", "Woodworker", ClassArtisan, ClassCraftsman, ClassTypeTradeskill, false, true}, {ClassCarpenter, "CARPENTER", "Carpenter", ClassArtisan, ClassCraftsman, ClassTypeTradeskill, false, true}, {ClassOutfitter, "OUTFITTER", "Outfitter", ClassArtisan, ClassCommoner, ClassTypeTradeskill, false, true}, {ClassArmorer, "ARMORER", "Armorer", ClassArtisan, ClassOutfitter, ClassTypeTradeskill, false, true}, {ClassWeaponsmith, "WEAPONSMITH", "Weaponsmith", ClassArtisan, ClassOutfitter, ClassTypeTradeskill, false, true}, {ClassTailor, "TAILOR", "Tailor", ClassArtisan, ClassOutfitter, ClassTypeTradeskill, false, true}, {ClassScholar, "SCHOLAR", "Scholar", ClassArtisan, ClassCommoner, ClassTypeTradeskill, false, true}, {ClassJeweler, "JEWELER", "Jeweler", ClassArtisan, ClassScholar, ClassTypeTradeskill, false, true}, {ClassSage, "SAGE", "Sage", ClassArtisan, ClassScholar, ClassTypeTradeskill, false, true}, {ClassAlchemist, "ALCHEMIST", "Alchemist", ClassArtisan, ClassScholar, ClassTypeTradeskill, false, true}, } // Create and store class objects for _, def := range classDefinitions { class := &Class{ ID: def.id, Name: def.name, DisplayName: def.displayName, BaseClass: def.baseClass, SecondaryBaseClass: def.secondaryBase, ClassType: def.classType, IsAdventure: def.isAdventure, IsTradeskill: def.isTradeskill, } m.classes[def.id] = class m.nameToID[def.name] = def.id m.displayNameMap[def.id] = def.displayName } m.stats.ClassesLoaded = int32(len(classDefinitions)) } // GetClass gets class by ID func (m *Manager) GetClass(classID int8) *Class { m.mutex.RLock() defer m.mutex.RUnlock() m.stats.LookupsPerformed++ if class, exists := m.classes[classID]; exists { m.stats.CacheHits++ return class } m.stats.CacheMisses++ return nil } // GetClassID returns the class ID for a given class name (C++ API compatibility) func (m *Manager) GetClassID(name string) int8 { m.mutex.RLock() defer m.mutex.RUnlock() m.stats.LookupsPerformed++ className := strings.ToUpper(strings.TrimSpace(name)) if classID, exists := m.nameToID[className]; exists { m.stats.CacheHits++ return classID } m.stats.CacheMisses++ return -1 // Invalid class } // GetClassName returns the uppercase class name for a given ID (C++ API compatibility) func (m *Manager) GetClassName(classID int8) string { m.mutex.RLock() defer m.mutex.RUnlock() m.stats.LookupsPerformed++ if class := m.classes[classID]; class != nil { m.stats.CacheHits++ return class.Name } m.stats.CacheMisses++ return "" // Invalid class ID } // GetClassNameCase returns the friendly display name for a given class ID (C++ API compatibility) func (m *Manager) GetClassNameCase(classID int8) string { m.mutex.RLock() defer m.mutex.RUnlock() m.stats.LookupsPerformed++ if displayName, exists := m.displayNameMap[classID]; exists { m.stats.CacheHits++ return displayName } m.stats.CacheMisses++ return "" // Invalid class ID } // GetBaseClass returns the base class ID for a given class (C++ API compatibility) func (m *Manager) GetBaseClass(classID int8) int8 { m.mutex.RLock() defer m.mutex.RUnlock() m.stats.LookupsPerformed++ if class := m.classes[classID]; class != nil { m.stats.CacheHits++ return class.BaseClass } m.stats.CacheMisses++ return ClassCommoner // Default for unknown classes } // GetSecondaryBaseClass returns the secondary base class ID (C++ API compatibility) func (m *Manager) GetSecondaryBaseClass(classID int8) int8 { m.mutex.RLock() defer m.mutex.RUnlock() m.stats.LookupsPerformed++ if class := m.classes[classID]; class != nil { m.stats.CacheHits++ return class.SecondaryBaseClass } m.stats.CacheMisses++ return ClassCommoner // Default for unknown classes } // GetTSBaseClass returns the tradeskill base class ID (C++ API compatibility) func (m *Manager) GetTSBaseClass(classID int8) int8 { // This function maps tradeskill class IDs to their base tradeskill progression levels // The C++ code uses offset of 42 between adventure and tradeskill class systems if classID+42 >= ClassArtisan { return ClassArtisan - 44 // Returns 1 (base artisan level) } return classID // For non-tradeskill classes, return as-is } // GetSecondaryTSBaseClass returns the secondary tradeskill base class ID (C++ API compatibility) func (m *Manager) GetSecondaryTSBaseClass(classID int8) int8 { ret := classID + 42 if ret == ClassArtisan { return ClassArtisan - 44 } else if ret >= ClassCraftsman && ret < ClassOutfitter { return ClassCraftsman - 44 } else if ret >= ClassOutfitter && ret < ClassScholar { return ClassOutfitter - 44 } else if ret >= ClassScholar { return ClassScholar - 44 } return classID } // IsValidClassID checks if a class ID is valid func (m *Manager) IsValidClassID(classID int8) bool { return classID >= MinClassID && classID <= MaxClassID } // IsAdventureClass checks if a class is an adventure class func (m *Manager) IsAdventureClass(classID int8) bool { if class := m.GetClass(classID); class != nil { return class.IsAdventure } return false } // IsTradeskillClass checks if a class is a tradeskill class func (m *Manager) IsTradeskillClass(classID int8) bool { if class := m.GetClass(classID); class != nil { return class.IsTradeskill } return false } // GetClassType returns the type of class (adventure, tradeskill, etc.) func (m *Manager) GetClassType(classID int8) string { if class := m.GetClass(classID); class != nil { return class.ClassType } return ClassTypeSpecial } // GetAllClasses returns all class IDs and their display names func (m *Manager) GetAllClasses() map[int8]string { m.mutex.RLock() defer m.mutex.RUnlock() result := make(map[int8]string) for classID, displayName := range m.displayNameMap { result[classID] = displayName } return result } // GetClassInfo returns comprehensive information about a class func (m *Manager) GetClassInfo(classID int8) map[string]any { class := m.GetClass(classID) info := make(map[string]any) if class == nil { info["valid"] = false return info } info["valid"] = true info["class_id"] = class.ID info["name"] = class.Name info["display_name"] = class.DisplayName info["base_class"] = class.BaseClass info["secondary_base_class"] = class.SecondaryBaseClass info["type"] = class.ClassType info["is_adventure"] = class.IsAdventure info["is_tradeskill"] = class.IsTradeskill return info } // GetClassHierarchy returns the full class hierarchy for a given class func (m *Manager) GetClassHierarchy(classID int8) []int8 { class := m.GetClass(classID) if class == nil { return nil } hierarchy := []int8{classID} // Add secondary base class if it exists if class.SecondaryBaseClass != ClassCommoner && class.SecondaryBaseClass != classID { hierarchy = append(hierarchy, class.SecondaryBaseClass) } // Add base class if class.BaseClass != ClassCommoner && class.BaseClass != classID { // Check if base is already in hierarchy (from secondary) found := false for _, id := range hierarchy { if id == class.BaseClass { found = true break } } if !found { hierarchy = append(hierarchy, class.BaseClass) } } // Always add Commoner as the root if classID != ClassCommoner { hierarchy = append(hierarchy, ClassCommoner) } return hierarchy } // IsSameArchetype checks if two classes share the same base archetype func (m *Manager) IsSameArchetype(classID1, classID2 int8) bool { class1 := m.GetClass(classID1) class2 := m.GetClass(classID2) if class1 == nil || class2 == nil { return false } return class1.BaseClass == class2.BaseClass } // GetArchetypeClasses returns all classes of a given archetype func (m *Manager) GetArchetypeClasses(archetypeID int8) []int8 { m.mutex.RLock() defer m.mutex.RUnlock() var classes []int8 for classID, class := range m.classes { if class.BaseClass == archetypeID { classes = append(classes, classID) } } return classes } // GetStatistics returns current manager statistics func (m *Manager) GetStatistics() map[string]interface{} { m.mutex.RLock() defer m.mutex.RUnlock() return map[string]interface{}{ "classes_loaded": m.stats.ClassesLoaded, "lookups_performed": m.stats.LookupsPerformed, "cache_hits": m.stats.CacheHits, "cache_misses": m.stats.CacheMisses, "total_classes": int32(len(m.classes)), "adventure_classes": m.countClassesByType(ClassTypeAdventure), "tradeskill_classes": m.countClassesByType(ClassTypeTradeskill), } } // countClassesByType counts classes of a specific type func (m *Manager) countClassesByType(classType string) int32 { count := int32(0) for _, class := range m.classes { if class.ClassType == classType { count++ } } return count } // Global manager instance var globalManager *Manager // InitializeManager initializes the global class manager func InitializeManager() { globalManager = NewManager() } // GetManager returns the global class manager func GetManager() *Manager { if globalManager == nil { InitializeManager() } return globalManager } // Global functions for C++ API compatibility func GetClassID(name string) int8 { return GetManager().GetClassID(name) } func GetClassName(classID int8) string { return GetManager().GetClassName(classID) } func GetClassNameCase(classID int8) string { return GetManager().GetClassNameCase(classID) } func GetBaseClass(classID int8) int8 { return GetManager().GetBaseClass(classID) } func GetSecondaryBaseClass(classID int8) int8 { return GetManager().GetSecondaryBaseClass(classID) } func GetTSBaseClass(classID int8) int8 { return GetManager().GetTSBaseClass(classID) } func GetSecondaryTSBaseClass(classID int8) int8 { return GetManager().GetSecondaryTSBaseClass(classID) } func IsValidClassID(classID int8) bool { return GetManager().IsValidClassID(classID) } func IsAdventureClass(classID int8) bool { return GetManager().IsAdventureClass(classID) } func IsTradeskillClass(classID int8) bool { return GetManager().IsTradeskillClass(classID) } func GetClassType(classID int8) string { return GetManager().GetClassType(classID) } func GetAllClasses() map[int8]string { return GetManager().GetAllClasses() } func GetClassInfo(classID int8) map[string]any { return GetManager().GetClassInfo(classID) } func GetClassHierarchy(classID int8) []int8 { return GetManager().GetClassHierarchy(classID) } func IsSameArchetype(classID1, classID2 int8) bool { return GetManager().IsSameArchetype(classID1, classID2) } func GetArchetypeClasses(archetypeID int8) []int8 { return GetManager().GetArchetypeClasses(archetypeID) }