eq2go/internal/skills/manager.go

284 lines
7.9 KiB
Go

package skills
import (
"fmt"
"sync"
)
// Manager provides high-level management of the skills system
type Manager struct {
masterSkillList *MasterSkillList
mutex sync.RWMutex
// Statistics
totalSkillUps int64
skillUpsByType map[int32]int64 // Skill type -> count
skillUpsBySkill map[int32]int64 // Skill ID -> count
playersWithSkills int64
}
// NewManager creates a new skills manager
func NewManager() *Manager {
return &Manager{
masterSkillList: NewMasterSkillList(),
skillUpsByType: make(map[int32]int64),
skillUpsBySkill: make(map[int32]int64),
}
}
// Initialize loads skills data (placeholder for database loading)
func (m *Manager) Initialize() error {
// TODO: Load skills from database when database system is integrated
// This would typically load all skills from a skills table
return nil
}
// GetMasterSkillList returns the master skill list
func (m *Manager) GetMasterSkillList() *MasterSkillList {
return m.masterSkillList
}
// AddSkillToMaster adds a skill to the master list
func (m *Manager) AddSkillToMaster(skill *Skill) {
m.masterSkillList.AddSkill(skill)
}
// GetSkill returns a skill from the master list by ID
func (m *Manager) GetSkill(skillID int32) *Skill {
return m.masterSkillList.GetSkill(skillID)
}
// GetSkillByName returns a skill from the master list by name
func (m *Manager) GetSkillByName(skillName string) *Skill {
return m.masterSkillList.GetSkillByName(skillName)
}
// CreatePlayerSkillList creates a new player skill list
func (m *Manager) CreatePlayerSkillList() *PlayerSkillList {
m.mutex.Lock()
m.playersWithSkills++
m.mutex.Unlock()
return NewPlayerSkillList()
}
// RecordSkillUp records a skill increase for statistics
func (m *Manager) RecordSkillUp(skillID int32, skillType int32) {
m.mutex.Lock()
defer m.mutex.Unlock()
m.totalSkillUps++
m.skillUpsByType[skillType]++
m.skillUpsBySkill[skillID]++
}
// GetStatistics returns skill system statistics
func (m *Manager) GetStatistics() map[string]any {
m.mutex.RLock()
defer m.mutex.RUnlock()
stats := make(map[string]any)
stats["total_skill_ups"] = m.totalSkillUps
stats["players_with_skills"] = m.playersWithSkills
stats["total_skills_in_master"] = m.masterSkillList.GetSkillCount()
// Copy skill type statistics
typeStats := make(map[int32]int64)
for skillType, count := range m.skillUpsByType {
typeStats[skillType] = count
}
stats["skill_ups_by_type"] = typeStats
// Copy individual skill statistics
skillStats := make(map[int32]int64)
for skillID, count := range m.skillUpsBySkill {
skillStats[skillID] = count
}
stats["skill_ups_by_skill"] = skillStats
return stats
}
// ResetStatistics resets all statistics
func (m *Manager) ResetStatistics() {
m.mutex.Lock()
defer m.mutex.Unlock()
m.totalSkillUps = 0
m.playersWithSkills = 0
m.skillUpsByType = make(map[int32]int64)
m.skillUpsBySkill = make(map[int32]int64)
}
// GetSkillsByType returns all skills of a specific type
func (m *Manager) GetSkillsByType(skillType int32) []*Skill {
return m.masterSkillList.GetSkillsByType(skillType)
}
// GetSkillTypeCount returns the number of skills of a specific type
func (m *Manager) GetSkillTypeCount(skillType int32) int {
skills := m.GetSkillsByType(skillType)
return len(skills)
}
// GetSkillUpCount returns the total number of skill ups for a skill
func (m *Manager) GetSkillUpCount(skillID int32) int64 {
m.mutex.RLock()
defer m.mutex.RUnlock()
return m.skillUpsBySkill[skillID]
}
// GetSkillTypeUpCount returns the total number of skill ups for a skill type
func (m *Manager) GetSkillTypeUpCount(skillType int32) int64 {
m.mutex.RLock()
defer m.mutex.RUnlock()
return m.skillUpsByType[skillType]
}
// ValidateSkillData validates that all skills in the master list are properly configured
func (m *Manager) ValidateSkillData() []string {
skills := m.masterSkillList.GetAllSkills()
issues := make([]string, 0)
if len(skills) == 0 {
issues = append(issues, "No skills configured in master list")
return issues
}
for skillID, skill := range skills {
if skill == nil {
issues = append(issues, fmt.Sprintf("Skill ID %d is nil", skillID))
continue
}
if skill.SkillID != skillID {
issues = append(issues, fmt.Sprintf("Skill %d has mismatched ID: %d", skillID, skill.SkillID))
}
if skill.Name.Data == "" {
issues = append(issues, fmt.Sprintf("Skill %d has empty name", skillID))
}
if skill.SkillType == 0 {
issues = append(issues, fmt.Sprintf("Skill %d (%s) has no skill type", skillID, skill.Name.Data))
}
if skill.MaxVal < 0 {
issues = append(issues, fmt.Sprintf("Skill %d (%s) has negative max value: %d", skillID, skill.Name.Data, skill.MaxVal))
}
if skill.CurrentVal < 0 {
issues = append(issues, fmt.Sprintf("Skill %d (%s) has negative current value: %d", skillID, skill.Name.Data, skill.CurrentVal))
}
if skill.CurrentVal > skill.MaxVal {
issues = append(issues, fmt.Sprintf("Skill %d (%s) has current value (%d) greater than max value (%d)",
skillID, skill.Name.Data, skill.CurrentVal, skill.MaxVal))
}
}
return issues
}
// ProcessCommand handles skill-related commands
func (m *Manager) ProcessCommand(command string, args []string) (string, error) {
switch command {
case "stats":
return m.handleStatsCommand(args)
case "validate":
return m.handleValidateCommand(args)
case "list":
return m.handleListCommand(args)
case "info":
return m.handleInfoCommand(args)
default:
return "", fmt.Errorf("unknown skills command: %s", command)
}
}
// handleStatsCommand shows skill system statistics
func (m *Manager) handleStatsCommand(args []string) (string, error) {
stats := m.GetStatistics()
result := "Skills System Statistics:\n"
result += fmt.Sprintf("Total Skills in Master List: %d\n", stats["total_skills_in_master"])
result += fmt.Sprintf("Players with Skills: %d\n", stats["players_with_skills"])
result += fmt.Sprintf("Total Skill Ups: %d\n", stats["total_skill_ups"])
return result, nil
}
// handleValidateCommand validates skill data
func (m *Manager) handleValidateCommand(args []string) (string, error) {
issues := m.ValidateSkillData()
if len(issues) == 0 {
return "All skill data is valid.", nil
}
result := fmt.Sprintf("Found %d issues with skill data:\n", len(issues))
for i, issue := range issues {
result += fmt.Sprintf("%d. %s\n", i+1, issue)
}
return result, nil
}
// handleListCommand lists skills
func (m *Manager) handleListCommand(args []string) (string, error) {
skills := m.masterSkillList.GetAllSkills()
if len(skills) == 0 {
return "No skills configured.", nil
}
result := fmt.Sprintf("Skills (%d):\n", len(skills))
count := 0
for _, skill := range skills {
if count >= 20 { // Limit output
result += "... (and more)\n"
break
}
result += fmt.Sprintf(" %d: %s (Type: %d)\n", skill.SkillID, skill.Name.Data, skill.SkillType)
count++
}
return result, nil
}
// handleInfoCommand shows information about a specific skill
func (m *Manager) handleInfoCommand(args []string) (string, error) {
if len(args) == 0 {
return "", fmt.Errorf("skill name or ID required")
}
skillName := args[0]
skill := m.GetSkillByName(skillName)
if skill == nil {
return fmt.Sprintf("Skill '%s' not found.", skillName), nil
}
result := fmt.Sprintf("Skill Information:\n")
result += fmt.Sprintf("ID: %d\n", skill.SkillID)
result += fmt.Sprintf("Name: %s\n", skill.Name.Data)
result += fmt.Sprintf("Short Name: %s\n", skill.ShortName.Data)
result += fmt.Sprintf("Type: %d\n", skill.SkillType)
result += fmt.Sprintf("Description: %s\n", skill.Description.Data)
result += fmt.Sprintf("Max Value: %d\n", skill.MaxVal)
result += fmt.Sprintf("Current Value: %d\n", skill.CurrentVal)
result += fmt.Sprintf("Active: %t\n", skill.ActiveSkill)
upCount := m.GetSkillUpCount(skill.SkillID)
result += fmt.Sprintf("Total Skill Ups Recorded: %d\n", upCount)
return result, nil
}
// Shutdown gracefully shuts down the manager
func (m *Manager) Shutdown() {
// Nothing to clean up currently, but placeholder for future cleanup
}