540 lines
18 KiB
Go
540 lines
18 KiB
Go
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)
|
|
} |