451 lines
14 KiB
Go
451 lines
14 KiB
Go
package classes
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"strings"
|
|
)
|
|
|
|
// ClassUtils provides utility functions for class operations
|
|
type ClassUtils struct {
|
|
classes *Classes
|
|
}
|
|
|
|
// NewClassUtils creates a new class utilities instance
|
|
func NewClassUtils() *ClassUtils {
|
|
return &ClassUtils{
|
|
classes: GetGlobalClasses(),
|
|
}
|
|
}
|
|
|
|
// ParseClassName attempts to parse a class name from various input formats
|
|
func (cu *ClassUtils) ParseClassName(input string) int8 {
|
|
if input == "" {
|
|
return -1
|
|
}
|
|
|
|
// Try direct lookup first
|
|
classID := cu.classes.GetClassID(input)
|
|
if classID != -1 {
|
|
return classID
|
|
}
|
|
|
|
// Try with common variations
|
|
variations := []string{
|
|
strings.ToUpper(input),
|
|
strings.ReplaceAll(strings.ToUpper(input), " ", ""),
|
|
strings.ReplaceAll(strings.ToUpper(input), "_", ""),
|
|
strings.ReplaceAll(strings.ToUpper(input), "-", ""),
|
|
}
|
|
|
|
for _, variation := range variations {
|
|
if classID := cu.classes.GetClassID(variation); classID != -1 {
|
|
return classID
|
|
}
|
|
}
|
|
|
|
// Try matching against friendly names (case insensitive)
|
|
inputLower := strings.ToLower(input)
|
|
allClasses := cu.classes.GetAllClasses()
|
|
for classID, displayName := range allClasses {
|
|
if strings.ToLower(displayName) == inputLower {
|
|
return classID
|
|
}
|
|
}
|
|
|
|
return -1 // Not found
|
|
}
|
|
|
|
// FormatClassName returns a properly formatted class name
|
|
func (cu *ClassUtils) FormatClassName(classID int8, format string) string {
|
|
switch strings.ToLower(format) {
|
|
case "display", "friendly", "proper":
|
|
return cu.classes.GetClassNameCase(classID)
|
|
case "upper", "uppercase":
|
|
return cu.classes.GetClassName(classID)
|
|
case "lower", "lowercase":
|
|
return strings.ToLower(cu.classes.GetClassName(classID))
|
|
default:
|
|
return cu.classes.GetClassNameCase(classID) // Default to friendly name
|
|
}
|
|
}
|
|
|
|
// GetRandomClassByType returns a random class of the specified type
|
|
func (cu *ClassUtils) GetRandomClassByType(classType string) int8 {
|
|
allClasses := cu.classes.GetAllClasses()
|
|
validClasses := make([]int8, 0)
|
|
|
|
for classID := range allClasses {
|
|
if cu.classes.GetClassType(classID) == classType {
|
|
validClasses = append(validClasses, classID)
|
|
}
|
|
}
|
|
|
|
if len(validClasses) == 0 {
|
|
return DefaultClassID
|
|
}
|
|
|
|
return validClasses[rand.Intn(len(validClasses))]
|
|
}
|
|
|
|
// GetRandomAdventureClass returns a random adventure class
|
|
func (cu *ClassUtils) GetRandomAdventureClass() int8 {
|
|
return cu.GetRandomClassByType(ClassTypeAdventure)
|
|
}
|
|
|
|
// GetRandomTradeskillClass returns a random tradeskill class
|
|
func (cu *ClassUtils) GetRandomTradeskillClass() int8 {
|
|
return cu.GetRandomClassByType(ClassTypeTradeskill)
|
|
}
|
|
|
|
// ValidateClassForRace checks if a class is valid for a specific race
|
|
// This is a placeholder for future race-class restrictions
|
|
func (cu *ClassUtils) ValidateClassForRace(classID, raceID int8) bool {
|
|
// TODO: Implement race-class restrictions when race system is available
|
|
// For now, all classes can be all races
|
|
return cu.classes.IsValidClassID(classID)
|
|
}
|
|
|
|
// GetClassDescription returns a description of the class
|
|
func (cu *ClassUtils) GetClassDescription(classID int8) string {
|
|
// This would typically come from a database or configuration
|
|
// For now, provide basic descriptions based on class
|
|
|
|
switch classID {
|
|
case ClassCommoner:
|
|
return "A starting class for all characters before choosing their path."
|
|
case ClassFighter:
|
|
return "Warriors who excel in melee combat and defense."
|
|
case ClassWarrior:
|
|
return "Masters of weapons and armor, the ultimate melee combatants."
|
|
case ClassGuardian:
|
|
return "Defensive warriors who protect their allies with shield and sword."
|
|
case ClassBerserker:
|
|
return "Rage-fueled fighters who sacrifice defense for devastating attacks."
|
|
case ClassBrawler:
|
|
return "Hand-to-hand combat specialists who fight with fists and focus."
|
|
case ClassMonk:
|
|
return "Disciplined fighters who use martial arts and inner peace."
|
|
case ClassBruiser:
|
|
return "Brutal brawlers who overwhelm enemies with raw power."
|
|
case ClassCrusader:
|
|
return "Holy warriors who blend combat prowess with divine magic."
|
|
case ClassShadowknight:
|
|
return "Dark knights who wield unholy magic alongside martial skill."
|
|
case ClassPaladin:
|
|
return "Champions of good who protect the innocent with sword and spell."
|
|
case ClassPriest:
|
|
return "Divine casters who channel the power of the gods."
|
|
case ClassCleric:
|
|
return "Healers and supporters who keep their allies alive and fighting."
|
|
case ClassTemplar:
|
|
return "Protective priests who shield allies from harm."
|
|
case ClassInquisitor:
|
|
return "Militant clerics who combine healing with righteous fury."
|
|
case ClassDruid:
|
|
return "Nature priests who harness the power of the natural world."
|
|
case ClassWarden:
|
|
return "Protective druids who shield allies with nature's blessing."
|
|
case ClassFury:
|
|
return "Destructive druids who unleash nature's wrath upon enemies."
|
|
case ClassShaman:
|
|
return "Spirit-workers who commune with ancestors and totems."
|
|
case ClassMystic:
|
|
return "Supportive shamans who provide wards and spiritual guidance."
|
|
case ClassDefiler:
|
|
return "Dark shamans who corrupt and weaken their enemies."
|
|
case ClassMage:
|
|
return "Wielders of arcane magic who bend reality to their will."
|
|
case ClassSorcerer:
|
|
return "Destructive mages who specialize in damaging spells."
|
|
case ClassWizard:
|
|
return "Scholarly sorcerers who master the elements."
|
|
case ClassWarlock:
|
|
return "Dark sorcerers who deal in forbidden magic."
|
|
case ClassEnchanter:
|
|
return "Mind-controlling mages who manipulate enemies and allies."
|
|
case ClassIllusionist:
|
|
return "Deceptive enchanters who confuse and misdirect."
|
|
case ClassCoercer:
|
|
return "Dominating enchanters who force enemies to obey."
|
|
case ClassSummoner:
|
|
return "Mages who call forth creatures to fight for them."
|
|
case ClassConjuror:
|
|
return "Elemental summoners who command earth and air."
|
|
case ClassNecromancer:
|
|
return "Death mages who raise undead minions and drain life."
|
|
case ClassScout:
|
|
return "Agile fighters who rely on speed and cunning."
|
|
case ClassRogue:
|
|
return "Stealthy combatants who strike from the shadows."
|
|
case ClassSwashbuckler:
|
|
return "Dashing rogues who fight with finesse and flair."
|
|
case ClassBrigand:
|
|
return "Brutal rogues who prefer dirty fighting tactics."
|
|
case ClassBard:
|
|
return "Musical combatants who inspire allies and demoralize foes."
|
|
case ClassTroubador:
|
|
return "Supportive bards who strengthen their allies."
|
|
case ClassDirge:
|
|
return "Dark bards who weaken enemies with haunting melodies."
|
|
case ClassPredator:
|
|
return "Hunters who excel at tracking and ranged combat."
|
|
case ClassRanger:
|
|
return "Nature-loving predators who protect the wilderness."
|
|
case ClassAssassin:
|
|
return "Deadly predators who eliminate targets with precision."
|
|
case ClassAnimalist:
|
|
return "Beast masters who fight alongside animal companions."
|
|
case ClassBeastlord:
|
|
return "Animalists who have formed powerful bonds with their pets."
|
|
case ClassShaper:
|
|
return "Mystic priests who manipulate spiritual energy."
|
|
case ClassChanneler:
|
|
return "Shapers who focus spiritual power through channeling."
|
|
case ClassArtisan:
|
|
return "Crafters who create useful items for adventurers."
|
|
case ClassCraftsman:
|
|
return "Specialized artisans who work with physical materials."
|
|
case ClassProvisioner:
|
|
return "Food and drink specialists who create consumables."
|
|
case ClassWoodworker:
|
|
return "Crafters who work with wood to create furniture and tools."
|
|
case ClassCarpenter:
|
|
return "Master woodworkers who create complex wooden items."
|
|
case ClassOutfitter:
|
|
return "Equipment crafters who create armor and weapons."
|
|
case ClassArmorer:
|
|
return "Specialists in creating protective armor."
|
|
case ClassWeaponsmith:
|
|
return "Masters of weapon crafting and enhancement."
|
|
case ClassTailor:
|
|
return "Cloth workers who create clothing and soft armor."
|
|
case ClassScholar:
|
|
return "Academic crafters who create magical and scholarly items."
|
|
case ClassJeweler:
|
|
return "Specialists in creating jewelry and accessories."
|
|
case ClassSage:
|
|
return "Book and scroll crafters who preserve knowledge."
|
|
case ClassAlchemist:
|
|
return "Potion makers who brew magical elixirs and potions."
|
|
default:
|
|
return "An unknown class with mysterious abilities."
|
|
}
|
|
}
|
|
|
|
// GetClassProgression returns the class progression path
|
|
func (cu *ClassUtils) GetClassProgression(classID int8) []int8 {
|
|
progression := make([]int8, 0)
|
|
|
|
// Always start with Commoner (except for Commoner itself)
|
|
if classID != ClassCommoner {
|
|
progression = append(progression, ClassCommoner)
|
|
}
|
|
|
|
// Add base class if different from current
|
|
baseClass := cu.classes.GetBaseClass(classID)
|
|
if baseClass != classID && baseClass != ClassCommoner {
|
|
progression = append(progression, baseClass)
|
|
}
|
|
|
|
// Add secondary base class if different
|
|
secondaryBase := cu.classes.GetSecondaryBaseClass(classID)
|
|
if secondaryBase != classID && secondaryBase != baseClass && secondaryBase != ClassCommoner {
|
|
progression = append(progression, secondaryBase)
|
|
}
|
|
|
|
// Add the final class
|
|
progression = append(progression, classID)
|
|
|
|
return progression
|
|
}
|
|
|
|
// GetClasssByBaseClass returns all classes that belong to a base class
|
|
func (cu *ClassUtils) GetClasssByBaseClass(baseClassID int8) []int8 {
|
|
result := make([]int8, 0)
|
|
allClasses := cu.classes.GetAllClasses()
|
|
|
|
for classID := range allClasses {
|
|
if cu.classes.GetBaseClass(classID) == baseClassID {
|
|
result = append(result, classID)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// GetClassesBySecondaryBase returns all classes that belong to a secondary base class
|
|
func (cu *ClassUtils) GetClassesBySecondaryBase(secondaryBaseID int8) []int8 {
|
|
result := make([]int8, 0)
|
|
allClasses := cu.classes.GetAllClasses()
|
|
|
|
for classID := range allClasses {
|
|
if cu.classes.GetSecondaryBaseClass(classID) == secondaryBaseID {
|
|
result = append(result, classID)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// GetClassesByPattern returns classes matching a name pattern
|
|
func (cu *ClassUtils) GetClassesByPattern(pattern string) []int8 {
|
|
pattern = strings.ToLower(pattern)
|
|
result := make([]int8, 0)
|
|
|
|
allClasses := cu.classes.GetAllClasses()
|
|
for classID, displayName := range allClasses {
|
|
if strings.Contains(strings.ToLower(displayName), pattern) {
|
|
result = append(result, classID)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// ValidateClassTransition checks if a class change is allowed
|
|
func (cu *ClassUtils) ValidateClassTransition(fromClassID, toClassID int8) (bool, string) {
|
|
if !cu.classes.IsValidClassID(fromClassID) {
|
|
return false, "Invalid source class"
|
|
}
|
|
|
|
if !cu.classes.IsValidClassID(toClassID) {
|
|
return false, "Invalid target class"
|
|
}
|
|
|
|
if fromClassID == toClassID {
|
|
return false, "Cannot change to the same class"
|
|
}
|
|
|
|
// Basic progression validation - can only advance, not go backward
|
|
fromProgression := cu.GetClassProgression(fromClassID)
|
|
toProgression := cu.GetClassProgression(toClassID)
|
|
|
|
// Check if the target class is a valid advancement
|
|
if len(toProgression) <= len(fromProgression) {
|
|
return false, "Cannot regress to a lower tier class"
|
|
}
|
|
|
|
// Check if the progressions are compatible (share the same base path)
|
|
for i := 0; i < len(fromProgression); i++ {
|
|
if i >= len(toProgression) || fromProgression[i] != toProgression[i] {
|
|
return false, "Incompatible class progression paths"
|
|
}
|
|
}
|
|
|
|
return true, ""
|
|
}
|
|
|
|
// GetClassAliases returns common aliases for a class
|
|
func (cu *ClassUtils) GetClassAliases(classID int8) []string {
|
|
aliases := make([]string, 0)
|
|
|
|
switch classID {
|
|
case ClassShadowknight:
|
|
aliases = append(aliases, "SK", "Shadow Knight", "Dark Knight")
|
|
case ClassSwashbuckler:
|
|
aliases = append(aliases, "Swash", "Swashy")
|
|
case ClassTroubador:
|
|
aliases = append(aliases, "Troub", "Troubadour")
|
|
case ClassIllusionist:
|
|
aliases = append(aliases, "Illy", "Illusion")
|
|
case ClassConjuror:
|
|
aliases = append(aliases, "Conj", "Conjurer")
|
|
case ClassNecromancer:
|
|
aliases = append(aliases, "Necro", "Nec")
|
|
case ClassBeastlord:
|
|
aliases = append(aliases, "BL", "Beast Lord")
|
|
case ClassWeaponsmith:
|
|
aliases = append(aliases, "WS", "Weapon Smith")
|
|
}
|
|
|
|
// Always include the official names
|
|
aliases = append(aliases, cu.classes.GetClassName(classID))
|
|
aliases = append(aliases, cu.classes.GetClassNameCase(classID))
|
|
|
|
return aliases
|
|
}
|
|
|
|
// GetClassStatistics returns statistics about the class system
|
|
func (cu *ClassUtils) GetClassStatistics() map[string]interface{} {
|
|
stats := make(map[string]interface{})
|
|
|
|
allClasses := cu.classes.GetAllClasses()
|
|
stats["total_classes"] = len(allClasses)
|
|
|
|
adventureCount := 0
|
|
tradeskillCount := 0
|
|
specialCount := 0
|
|
|
|
for classID := range allClasses {
|
|
switch cu.classes.GetClassType(classID) {
|
|
case ClassTypeAdventure:
|
|
adventureCount++
|
|
case ClassTypeTradeskill:
|
|
tradeskillCount++
|
|
default:
|
|
specialCount++
|
|
}
|
|
}
|
|
|
|
stats["adventure_classes"] = adventureCount
|
|
stats["tradeskill_classes"] = tradeskillCount
|
|
stats["special_classes"] = specialCount
|
|
|
|
// Base class distribution
|
|
baseClassDistribution := make(map[string][]string)
|
|
for classID, displayName := range allClasses {
|
|
if cu.classes.IsAdventureClass(classID) {
|
|
baseClassID := cu.classes.GetBaseClass(classID)
|
|
baseClassName := cu.classes.GetClassNameCase(baseClassID)
|
|
baseClassDistribution[baseClassName] = append(baseClassDistribution[baseClassName], displayName)
|
|
}
|
|
}
|
|
stats["base_class_distribution"] = baseClassDistribution
|
|
|
|
return stats
|
|
}
|
|
|
|
// FormatClassList returns a formatted string of class names
|
|
func (cu *ClassUtils) FormatClassList(classIDs []int8, separator string) string {
|
|
if len(classIDs) == 0 {
|
|
return ""
|
|
}
|
|
|
|
names := make([]string, len(classIDs))
|
|
for i, classID := range classIDs {
|
|
names[i] = cu.classes.GetClassNameCase(classID)
|
|
}
|
|
|
|
return strings.Join(names, separator)
|
|
}
|
|
|
|
// GetEQClassName returns the EQ-style class name for a given class and level
|
|
// This is a placeholder for the original C++ GetEQClassName functionality
|
|
func (cu *ClassUtils) GetEQClassName(classID int8, level int8) string {
|
|
// TODO: Implement level-based class names when level system is available
|
|
// For now, just return the display name
|
|
return cu.classes.GetClassNameCase(classID)
|
|
}
|
|
|
|
// GetStartingClass returns the appropriate starting class for character creation
|
|
func (cu *ClassUtils) GetStartingClass() int8 {
|
|
return ClassCommoner
|
|
}
|
|
|
|
// IsBaseClass checks if a class is a base class (Fighter, Priest, Mage, Scout)
|
|
func (cu *ClassUtils) IsBaseClass(classID int8) bool {
|
|
return classID == ClassFighter || classID == ClassPriest || classID == ClassMage || classID == ClassScout
|
|
}
|
|
|
|
// IsSecondaryBaseClass checks if a class is a secondary base class
|
|
func (cu *ClassUtils) IsSecondaryBaseClass(classID int8) bool {
|
|
// Check if any class has this as their secondary base
|
|
allClasses := cu.classes.GetAllClasses()
|
|
for checkClassID := range allClasses {
|
|
if cu.classes.GetSecondaryBaseClass(checkClassID) == classID && checkClassID != classID {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
} |