eq2go/internal/classes/classes.go

367 lines
12 KiB
Go

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
}