package classes import ( "strings" "sync" ) // Classes manages class information and lookups // Converted from C++ Classes class type Classes struct { // Class name to ID mapping (uppercase keys) classMap map[string]int8 // ID to display name mapping for friendly names displayNameMap map[int8]string // Thread safety mutex sync.RWMutex } // NewClasses creates a new classes manager with all EQ2 classes // Converted from C++ Classes::Classes constructor func NewClasses() *Classes { classes := &Classes{ classMap: make(map[string]int8), displayNameMap: make(map[int8]string), } classes.initializeClasses() return classes } // initializeClasses sets up all class mappings func (c *Classes) initializeClasses() { // Initialize class name to ID mappings (from C++ constructor) c.classMap[ClassNameCommoner] = ClassCommoner c.classMap[ClassNameFighter] = ClassFighter c.classMap[ClassNameWarrior] = ClassWarrior c.classMap[ClassNameGuardian] = ClassGuardian c.classMap[ClassNameBerserker] = ClassBerserker c.classMap[ClassNameBrawler] = ClassBrawler c.classMap[ClassNameMonk] = ClassMonk c.classMap[ClassNameBruiser] = ClassBruiser c.classMap[ClassNameCrusader] = ClassCrusader c.classMap[ClassNameShadowknight] = ClassShadowknight c.classMap[ClassNamePaladin] = ClassPaladin c.classMap[ClassNamePriest] = ClassPriest c.classMap[ClassNameCleric] = ClassCleric c.classMap[ClassNameTemplar] = ClassTemplar c.classMap[ClassNameInquisitor] = ClassInquisitor c.classMap[ClassNameDruid] = ClassDruid c.classMap[ClassNameWarden] = ClassWarden c.classMap[ClassNameFury] = ClassFury c.classMap[ClassNameShaman] = ClassShaman c.classMap[ClassNameMystic] = ClassMystic c.classMap[ClassNameDefiler] = ClassDefiler c.classMap[ClassNameMage] = ClassMage c.classMap[ClassNameSorcerer] = ClassSorcerer c.classMap[ClassNameWizard] = ClassWizard c.classMap[ClassNameWarlock] = ClassWarlock c.classMap[ClassNameEnchanter] = ClassEnchanter c.classMap[ClassNameIllusionist] = ClassIllusionist c.classMap[ClassNameCoercer] = ClassCoercer c.classMap[ClassNameSummoner] = ClassSummoner c.classMap[ClassNameConjuror] = ClassConjuror c.classMap[ClassNameNecromancer] = ClassNecromancer c.classMap[ClassNameScout] = ClassScout c.classMap[ClassNameRogue] = ClassRogue c.classMap[ClassNameSwashbuckler] = ClassSwashbuckler c.classMap[ClassNameBrigand] = ClassBrigand c.classMap[ClassNameBard] = ClassBard c.classMap[ClassNameTroubador] = ClassTroubador c.classMap[ClassNameDirge] = ClassDirge c.classMap[ClassNamePredator] = ClassPredator c.classMap[ClassNameRanger] = ClassRanger c.classMap[ClassNameAssassin] = ClassAssassin c.classMap[ClassNameAnimalist] = ClassAnimalist c.classMap[ClassNameBeastlord] = ClassBeastlord c.classMap[ClassNameShaper] = ClassShaper c.classMap[ClassNameChanneler] = ClassChanneler c.classMap[ClassNameArtisan] = ClassArtisan c.classMap[ClassNameCraftsman] = ClassCraftsman c.classMap[ClassNameProvisioner] = ClassProvisioner c.classMap[ClassNameWoodworker] = ClassWoodworker c.classMap[ClassNameCarpenter] = ClassCarpenter c.classMap[ClassNameOutfitter] = ClassOutfitter c.classMap[ClassNameArmorer] = ClassArmorer c.classMap[ClassNameWeaponsmith] = ClassWeaponsmith c.classMap[ClassNameTailor] = ClassTailor c.classMap[ClassNameScholar] = ClassScholar c.classMap[ClassNameJeweler] = ClassJeweler c.classMap[ClassNameSage] = ClassSage c.classMap[ClassNameAlchemist] = ClassAlchemist // Initialize display names c.displayNameMap[ClassCommoner] = DisplayNameCommoner c.displayNameMap[ClassFighter] = DisplayNameFighter c.displayNameMap[ClassWarrior] = DisplayNameWarrior c.displayNameMap[ClassGuardian] = DisplayNameGuardian c.displayNameMap[ClassBerserker] = DisplayNameBerserker c.displayNameMap[ClassBrawler] = DisplayNameBrawler c.displayNameMap[ClassMonk] = DisplayNameMonk c.displayNameMap[ClassBruiser] = DisplayNameBruiser c.displayNameMap[ClassCrusader] = DisplayNameCrusader c.displayNameMap[ClassShadowknight] = DisplayNameShadowknight c.displayNameMap[ClassPaladin] = DisplayNamePaladin c.displayNameMap[ClassPriest] = DisplayNamePriest c.displayNameMap[ClassCleric] = DisplayNameCleric c.displayNameMap[ClassTemplar] = DisplayNameTemplar c.displayNameMap[ClassInquisitor] = DisplayNameInquisitor c.displayNameMap[ClassDruid] = DisplayNameDruid c.displayNameMap[ClassWarden] = DisplayNameWarden c.displayNameMap[ClassFury] = DisplayNameFury c.displayNameMap[ClassShaman] = DisplayNameShaman c.displayNameMap[ClassMystic] = DisplayNameMystic c.displayNameMap[ClassDefiler] = DisplayNameDefiler c.displayNameMap[ClassMage] = DisplayNameMage c.displayNameMap[ClassSorcerer] = DisplayNameSorcerer c.displayNameMap[ClassWizard] = DisplayNameWizard c.displayNameMap[ClassWarlock] = DisplayNameWarlock c.displayNameMap[ClassEnchanter] = DisplayNameEnchanter c.displayNameMap[ClassIllusionist] = DisplayNameIllusionist c.displayNameMap[ClassCoercer] = DisplayNameCoercer c.displayNameMap[ClassSummoner] = DisplayNameSummoner c.displayNameMap[ClassConjuror] = DisplayNameConjuror c.displayNameMap[ClassNecromancer] = DisplayNameNecromancer c.displayNameMap[ClassScout] = DisplayNameScout c.displayNameMap[ClassRogue] = DisplayNameRogue c.displayNameMap[ClassSwashbuckler] = DisplayNameSwashbuckler c.displayNameMap[ClassBrigand] = DisplayNameBrigand c.displayNameMap[ClassBard] = DisplayNameBard c.displayNameMap[ClassTroubador] = DisplayNameTroubador c.displayNameMap[ClassDirge] = DisplayNameDirge c.displayNameMap[ClassPredator] = DisplayNamePredator c.displayNameMap[ClassRanger] = DisplayNameRanger c.displayNameMap[ClassAssassin] = DisplayNameAssassin c.displayNameMap[ClassAnimalist] = DisplayNameAnimalist c.displayNameMap[ClassBeastlord] = DisplayNameBeastlord c.displayNameMap[ClassShaper] = DisplayNameShaper c.displayNameMap[ClassChanneler] = DisplayNameChanneler c.displayNameMap[ClassArtisan] = DisplayNameArtisan c.displayNameMap[ClassCraftsman] = DisplayNameCraftsman c.displayNameMap[ClassProvisioner] = DisplayNameProvisioner c.displayNameMap[ClassWoodworker] = DisplayNameWoodworker c.displayNameMap[ClassCarpenter] = DisplayNameCarpenter c.displayNameMap[ClassOutfitter] = DisplayNameOutfitter c.displayNameMap[ClassArmorer] = DisplayNameArmorer c.displayNameMap[ClassWeaponsmith] = DisplayNameWeaponsmith c.displayNameMap[ClassTailor] = DisplayNameTailor c.displayNameMap[ClassScholar] = DisplayNameScholar c.displayNameMap[ClassJeweler] = DisplayNameJeweler c.displayNameMap[ClassSage] = DisplayNameSage c.displayNameMap[ClassAlchemist] = DisplayNameAlchemist } // GetClassID returns the class ID for a given class name // Converted from C++ Classes::GetClassID func (c *Classes) GetClassID(name string) int8 { c.mutex.RLock() defer c.mutex.RUnlock() className := strings.ToUpper(strings.TrimSpace(name)) if classID, exists := c.classMap[className]; exists { return classID } return -1 // Invalid class } // GetClassName returns the uppercase class name for a given ID // Converted from C++ Classes::GetClassName func (c *Classes) GetClassName(classID int8) string { c.mutex.RLock() defer c.mutex.RUnlock() // Search through class map to find the name for name, id := range c.classMap { if id == classID { return name } } return "" // Invalid class ID } // GetClassNameCase returns the friendly display name for a given class ID // Converted from C++ Classes::GetClassNameCase func (c *Classes) GetClassNameCase(classID int8) string { c.mutex.RLock() defer c.mutex.RUnlock() if displayName, exists := c.displayNameMap[classID]; exists { return displayName } return "" // Invalid class ID } // GetBaseClass returns the base class ID for a given class // Converted from C++ Classes::GetBaseClass func (c *Classes) GetBaseClass(classID int8) int8 { if classID >= ClassWarrior && classID <= ClassPaladin { return ClassFighter } if (classID >= ClassCleric && classID <= ClassDefiler) || (classID == ClassShaper || classID == ClassChanneler) { return ClassPriest } if classID >= ClassSorcerer && classID <= ClassNecromancer { return ClassMage } if classID >= ClassRogue && classID <= ClassBeastlord { return ClassScout } return ClassCommoner // Default for unknown classes } // GetSecondaryBaseClass returns the secondary base class ID for specialized classes // Converted from C++ Classes::GetSecondaryBaseClass func (c *Classes) GetSecondaryBaseClass(classID int8) int8 { switch classID { case ClassGuardian, ClassBerserker: return ClassWarrior case ClassMonk, ClassBruiser: return ClassBrawler case ClassShadowknight, ClassPaladin: return ClassCrusader case ClassTemplar, ClassInquisitor: return ClassCleric case ClassWarden, ClassFury: return ClassDruid case ClassMystic, ClassDefiler: return ClassShaman case ClassWizard, ClassWarlock: return ClassSorcerer case ClassIllusionist, ClassCoercer: return ClassEnchanter case ClassConjuror, ClassNecromancer: return ClassSummoner case ClassSwashbuckler, ClassBrigand: return ClassRogue case ClassTroubador, ClassDirge: return ClassBard case ClassRanger, ClassAssassin: return ClassPredator case ClassBeastlord: return ClassAnimalist case ClassChanneler: return ClassShaper } return ClassCommoner // Default for unknown classes } // GetTSBaseClass returns the tradeskill base class ID // Converted from C++ Classes::GetTSBaseClass func (c *Classes) GetTSBaseClass(classID int8) int8 { if classID+42 >= ClassArtisan { return ClassArtisan - 44 } return classID } // GetSecondaryTSBaseClass returns the secondary tradeskill base class ID // Converted from C++ Classes::GetSecondaryTSBaseClass func (c *Classes) 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 (c *Classes) IsValidClassID(classID int8) bool { return classID >= MinClassID && classID <= MaxClassID } // GetAllClasses returns all class IDs and their display names func (c *Classes) GetAllClasses() map[int8]string { c.mutex.RLock() defer c.mutex.RUnlock() result := make(map[int8]string) for classID, displayName := range c.displayNameMap { result[classID] = displayName } return result } // IsAdventureClass checks if a class is an adventure class func (c *Classes) IsAdventureClass(classID int8) bool { return classID >= ClassCommoner && classID <= ClassChanneler } // IsTradeskillClass checks if a class is a tradeskill class func (c *Classes) IsTradeskillClass(classID int8) bool { return classID >= ClassArtisan && classID <= ClassAlchemist } // GetClassType returns the type of class (adventure, tradeskill, etc.) func (c *Classes) GetClassType(classID int8) string { if c.IsAdventureClass(classID) { return ClassTypeAdventure } if c.IsTradeskillClass(classID) { return ClassTypeTradeskill } return ClassTypeSpecial } // GetClassCount returns the total number of classes func (c *Classes) GetClassCount() int { c.mutex.RLock() defer c.mutex.RUnlock() return len(c.displayNameMap) } // GetClassInfo returns comprehensive information about a class func (c *Classes) GetClassInfo(classID int8) map[string]any { c.mutex.RLock() defer c.mutex.RUnlock() info := make(map[string]any) if !c.IsValidClassID(classID) { info["valid"] = false return info } info["valid"] = true info["class_id"] = classID info["name"] = c.GetClassName(classID) info["display_name"] = c.GetClassNameCase(classID) info["base_class"] = c.GetBaseClass(classID) info["secondary_base_class"] = c.GetSecondaryBaseClass(classID) info["type"] = c.GetClassType(classID) info["is_adventure"] = c.IsAdventureClass(classID) info["is_tradeskill"] = c.IsTradeskillClass(classID) return info } // Global classes instance var globalClasses *Classes var initClassesOnce sync.Once // GetGlobalClasses returns the global classes manager (singleton) func GetGlobalClasses() *Classes { initClassesOnce.Do(func() { globalClasses = NewClasses() }) return globalClasses }