eq2go/internal/classes/integration.go

353 lines
10 KiB
Go

package classes
import (
"fmt"
)
// ClassAware interface for entities that have class information
type ClassAware interface {
GetClass() int8
SetClass(int8)
}
// EntityWithClass interface extends ClassAware with additional entity properties
type EntityWithClass interface {
ClassAware
GetID() int32
GetName() string
GetLevel() int8
}
// ClassIntegration provides class-related functionality for other systems
type ClassIntegration struct {
classes *Classes
utils *ClassUtils
}
// NewClassIntegration creates a new class integration helper
func NewClassIntegration() *ClassIntegration {
return &ClassIntegration{
classes: GetGlobalClasses(),
utils: NewClassUtils(),
}
}
// ValidateEntityClass validates an entity's class and provides detailed information
func (ci *ClassIntegration) ValidateEntityClass(entity ClassAware) (bool, string, map[string]any) {
classID := entity.GetClass()
if !ci.classes.IsValidClassID(classID) {
return false, fmt.Sprintf("Invalid class ID: %d", classID), nil
}
classInfo := ci.classes.GetClassInfo(classID)
return true, "Valid class", classInfo
}
// GetEntityClassInfo returns comprehensive class information for an entity
func (ci *ClassIntegration) GetEntityClassInfo(entity EntityWithClass) map[string]any {
info := make(map[string]any)
// Basic entity info
info["entity_id"] = entity.GetID()
info["entity_name"] = entity.GetName()
info["entity_level"] = entity.GetLevel()
// Class information
classID := entity.GetClass()
classInfo := ci.classes.GetClassInfo(classID)
info["class"] = classInfo
// Additional class-specific info
info["description"] = ci.utils.GetClassDescription(classID)
info["eq_class_name"] = ci.utils.GetEQClassName(classID, entity.GetLevel())
info["progression"] = ci.utils.GetClassProgression(classID)
info["aliases"] = ci.utils.GetClassAliases(classID)
info["is_base_class"] = ci.utils.IsBaseClass(classID)
info["is_secondary_base"] = ci.utils.IsSecondaryBaseClass(classID)
return info
}
// ChangeEntityClass changes an entity's class with validation
func (ci *ClassIntegration) ChangeEntityClass(entity ClassAware, newClassID int8) error {
if !ci.classes.IsValidClassID(newClassID) {
return fmt.Errorf("invalid class ID: %d", newClassID)
}
oldClassID := entity.GetClass()
// Validate the class transition
if valid, reason := ci.utils.ValidateClassTransition(oldClassID, newClassID); !valid {
return fmt.Errorf("class change not allowed: %s", reason)
}
// Perform the class change
entity.SetClass(newClassID)
return nil
}
// GetRandomClassForEntity returns a random class appropriate for an entity
func (ci *ClassIntegration) GetRandomClassForEntity(classType string) int8 {
return ci.utils.GetRandomClassByType(classType)
}
// CheckClassCompatibility checks if two entities' classes are compatible for grouping
func (ci *ClassIntegration) CheckClassCompatibility(entity1, entity2 ClassAware) bool {
class1 := entity1.GetClass()
class2 := entity2.GetClass()
if !ci.classes.IsValidClassID(class1) || !ci.classes.IsValidClassID(class2) {
return false
}
// Same class is always compatible
if class1 == class2 {
return true
}
// Check if they share the same base class (good for grouping)
// base1 := ci.classes.GetBaseClass(class1)
// base2 := ci.classes.GetBaseClass(class2)
// Different base classes can group together (provides diversity)
// Same base class provides synergy
return true // For now, all classes are compatible for grouping
}
// FormatEntityClass returns a formatted class name for an entity
func (ci *ClassIntegration) FormatEntityClass(entity EntityWithClass, format string) string {
classID := entity.GetClass()
level := entity.GetLevel()
switch format {
case "eq":
return ci.utils.GetEQClassName(classID, level)
default:
return ci.utils.FormatClassName(classID, format)
}
}
// GetEntityBaseClass returns an entity's base class
func (ci *ClassIntegration) GetEntityBaseClass(entity ClassAware) int8 {
classID := entity.GetClass()
return ci.classes.GetBaseClass(classID)
}
// GetEntitySecondaryBaseClass returns an entity's secondary base class
func (ci *ClassIntegration) GetEntitySecondaryBaseClass(entity ClassAware) int8 {
classID := entity.GetClass()
return ci.classes.GetSecondaryBaseClass(classID)
}
// IsEntityAdventureClass checks if an entity has an adventure class
func (ci *ClassIntegration) IsEntityAdventureClass(entity ClassAware) bool {
classID := entity.GetClass()
return ci.classes.IsAdventureClass(classID)
}
// IsEntityTradeskillClass checks if an entity has a tradeskill class
func (ci *ClassIntegration) IsEntityTradeskillClass(entity ClassAware) bool {
classID := entity.GetClass()
return ci.classes.IsTradeskillClass(classID)
}
// GetEntitiesByClass filters entities by class
func (ci *ClassIntegration) GetEntitiesByClass(entities []ClassAware, classID int8) []ClassAware {
result := make([]ClassAware, 0)
for _, entity := range entities {
if entity.GetClass() == classID {
result = append(result, entity)
}
}
return result
}
// GetEntitiesByBaseClass filters entities by base class
func (ci *ClassIntegration) GetEntitiesByBaseClass(entities []ClassAware, baseClassID int8) []ClassAware {
result := make([]ClassAware, 0)
for _, entity := range entities {
if ci.GetEntityBaseClass(entity) == baseClassID {
result = append(result, entity)
}
}
return result
}
// GetEntitiesByClassType filters entities by class type (adventure/tradeskill)
func (ci *ClassIntegration) GetEntitiesByClassType(entities []ClassAware, classType string) []ClassAware {
result := make([]ClassAware, 0)
for _, entity := range entities {
classID := entity.GetClass()
if ci.classes.GetClassType(classID) == classType {
result = append(result, entity)
}
}
return result
}
// ValidateClassForRace checks if a class/race combination is valid
func (ci *ClassIntegration) ValidateClassForRace(classID, raceID int8) (bool, string) {
if !ci.classes.IsValidClassID(classID) {
return false, "Invalid class"
}
// Use the utility function (which currently allows all combinations)
if ci.utils.ValidateClassForRace(classID, raceID) {
return true, ""
}
className := ci.classes.GetClassNameCase(classID)
return false, fmt.Sprintf("Class %s cannot be race %d", className, raceID)
}
// GetClassStartingStats returns the starting stats for a class
func (ci *ClassIntegration) GetClassStartingStats(classID int8) map[string]int16 {
// Base stats that all classes start with
baseStats := map[string]int16{
"strength": 50,
"stamina": 50,
"agility": 50,
"wisdom": 50,
"intelligence": 50,
}
// Apply class modifiers based on class type and role
switch ci.classes.GetBaseClass(classID) {
case ClassFighter:
baseStats["strength"] += 5
baseStats["stamina"] += 5
baseStats["intelligence"] -= 3
case ClassPriest:
baseStats["wisdom"] += 5
baseStats["intelligence"] += 3
baseStats["strength"] -= 2
case ClassMage:
baseStats["intelligence"] += 5
baseStats["wisdom"] += 3
baseStats["strength"] -= 3
baseStats["stamina"] -= 2
case ClassScout:
baseStats["agility"] += 5
baseStats["stamina"] += 3
baseStats["wisdom"] -= 2
}
// Fine-tune for specific secondary base classes
switch ci.classes.GetSecondaryBaseClass(classID) {
case ClassWarrior:
baseStats["strength"] += 2
baseStats["stamina"] += 2
case ClassBrawler:
baseStats["agility"] += 2
baseStats["strength"] += 1
case ClassCrusader:
baseStats["wisdom"] += 2
baseStats["strength"] += 1
case ClassCleric:
baseStats["wisdom"] += 3
case ClassDruid:
baseStats["wisdom"] += 2
baseStats["intelligence"] += 1
case ClassShaman:
baseStats["wisdom"] += 2
baseStats["stamina"] += 1
case ClassSorcerer:
baseStats["intelligence"] += 3
case ClassEnchanter:
baseStats["intelligence"] += 2
baseStats["agility"] += 1
case ClassSummoner:
baseStats["intelligence"] += 2
baseStats["wisdom"] += 1
case ClassRogue:
baseStats["agility"] += 3
case ClassBard:
baseStats["agility"] += 2
baseStats["intelligence"] += 1
case ClassPredator:
baseStats["agility"] += 2
baseStats["stamina"] += 1
}
return baseStats
}
// CreateClassSpecificEntity creates entity data with class-specific properties
func (ci *ClassIntegration) CreateClassSpecificEntity(classID int8) map[string]any {
if !ci.classes.IsValidClassID(classID) {
return nil
}
entityData := make(map[string]any)
// Basic class info
entityData["class_id"] = classID
entityData["class_name"] = ci.classes.GetClassNameCase(classID)
entityData["class_type"] = ci.classes.GetClassType(classID)
// Starting stats
entityData["starting_stats"] = ci.GetClassStartingStats(classID)
// Class progression
entityData["progression"] = ci.utils.GetClassProgression(classID)
// Class description
entityData["description"] = ci.utils.GetClassDescription(classID)
// Role information
entityData["base_class"] = ci.classes.GetBaseClass(classID)
entityData["secondary_base_class"] = ci.classes.GetSecondaryBaseClass(classID)
return entityData
}
// GetClassSelectionData returns data for class selection UI
func (ci *ClassIntegration) GetClassSelectionData() map[string]any {
data := make(map[string]any)
// All available adventure classes (exclude tradeskill for character creation)
allClasses := ci.classes.GetAllClasses()
adventureClasses := make([]map[string]any, 0)
for classID, displayName := range allClasses {
if ci.classes.IsAdventureClass(classID) {
classData := map[string]any{
"id": classID,
"name": displayName,
"type": ci.classes.GetClassType(classID),
"description": ci.utils.GetClassDescription(classID),
"base_class": ci.classes.GetBaseClass(classID),
"secondary_base_class": ci.classes.GetSecondaryBaseClass(classID),
"starting_stats": ci.GetClassStartingStats(classID),
"progression": ci.utils.GetClassProgression(classID),
"is_base_class": ci.utils.IsBaseClass(classID),
}
adventureClasses = append(adventureClasses, classData)
}
}
data["adventure_classes"] = adventureClasses
data["statistics"] = ci.utils.GetClassStatistics()
return data
}
// Global class integration instance
var globalClassIntegration *ClassIntegration
// GetGlobalClassIntegration returns the global class integration helper
func GetGlobalClassIntegration() *ClassIntegration {
if globalClassIntegration == nil {
globalClassIntegration = NewClassIntegration()
}
return globalClassIntegration
}