158 lines
4.6 KiB
Go
158 lines
4.6 KiB
Go
package alt_advancement
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"eq2emu/internal/common"
|
|
)
|
|
|
|
// MasterList manages the global list of all alternate advancements
|
|
type MasterList struct {
|
|
*common.MasterList[int32, *AltAdvancement]
|
|
}
|
|
|
|
// NewMasterList creates a new master alternate advancement list
|
|
func NewMasterList() *MasterList {
|
|
return &MasterList{
|
|
MasterList: common.NewMasterList[int32, *AltAdvancement](),
|
|
}
|
|
}
|
|
|
|
// AddAltAdvancement adds an alternate advancement to the master list
|
|
// Returns false if AA with same ID already exists
|
|
func (m *MasterList) AddAltAdvancement(aa *AltAdvancement) bool {
|
|
if aa == nil {
|
|
return false
|
|
}
|
|
return m.MasterList.Add(aa)
|
|
}
|
|
|
|
// GetAltAdvancement retrieves an alternate advancement by node ID
|
|
// Returns nil if not found
|
|
func (m *MasterList) GetAltAdvancement(nodeID int32) *AltAdvancement {
|
|
return m.MasterList.Get(nodeID)
|
|
}
|
|
|
|
// GetAltAdvancementClone retrieves a cloned copy of an alternate advancement by node ID
|
|
// Returns nil if not found. Safe for modification without affecting master list
|
|
func (m *MasterList) GetAltAdvancementClone(nodeID int32) *AltAdvancement {
|
|
aa := m.MasterList.Get(nodeID)
|
|
if aa == nil {
|
|
return nil
|
|
}
|
|
return aa.Clone()
|
|
}
|
|
|
|
// GetAllAltAdvancements returns a map of all alternate advancements (read-only access)
|
|
// The returned map should not be modified
|
|
func (m *MasterList) GetAllAltAdvancements() map[int32]*AltAdvancement {
|
|
return m.MasterList.GetAll()
|
|
}
|
|
|
|
// GetAltAdvancementsByGroup returns alternate advancements filtered by group/tab
|
|
func (m *MasterList) GetAltAdvancementsByGroup(group int8) []*AltAdvancement {
|
|
return m.MasterList.Filter(func(aa *AltAdvancement) bool {
|
|
return aa.Group == group
|
|
})
|
|
}
|
|
|
|
// GetAltAdvancementsByClass returns alternate advancements filtered by class requirement
|
|
func (m *MasterList) GetAltAdvancementsByClass(classID int8) []*AltAdvancement {
|
|
return m.MasterList.Filter(func(aa *AltAdvancement) bool {
|
|
return aa.ClassReq == 0 || aa.ClassReq == classID
|
|
})
|
|
}
|
|
|
|
// GetAltAdvancementsByLevel returns alternate advancements available at a specific level
|
|
func (m *MasterList) GetAltAdvancementsByLevel(level int8) []*AltAdvancement {
|
|
return m.MasterList.Filter(func(aa *AltAdvancement) bool {
|
|
return aa.MinLevel <= level
|
|
})
|
|
}
|
|
|
|
// RemoveAltAdvancement removes an alternate advancement from the master list
|
|
// Returns true if AA was found and removed
|
|
func (m *MasterList) RemoveAltAdvancement(nodeID int32) bool {
|
|
return m.MasterList.Remove(nodeID)
|
|
}
|
|
|
|
// UpdateAltAdvancement updates an existing alternate advancement
|
|
// Returns error if AA doesn't exist
|
|
func (m *MasterList) UpdateAltAdvancement(aa *AltAdvancement) error {
|
|
if aa == nil {
|
|
return fmt.Errorf("alternate advancement cannot be nil")
|
|
}
|
|
return m.MasterList.Update(aa)
|
|
}
|
|
|
|
// GetGroups returns all unique groups/tabs that have alternate advancements
|
|
func (m *MasterList) GetGroups() []int8 {
|
|
groups := make(map[int8]bool)
|
|
|
|
m.MasterList.ForEach(func(_ int32, aa *AltAdvancement) {
|
|
groups[aa.Group] = true
|
|
})
|
|
|
|
result := make([]int8, 0, len(groups))
|
|
for group := range groups {
|
|
result = append(result, group)
|
|
}
|
|
return result
|
|
}
|
|
|
|
// GetClasses returns all unique classes that have alternate advancements
|
|
func (m *MasterList) GetClasses() []int8 {
|
|
classes := make(map[int8]bool)
|
|
|
|
m.MasterList.ForEach(func(_ int32, aa *AltAdvancement) {
|
|
if aa.ClassReq > 0 {
|
|
classes[aa.ClassReq] = true
|
|
}
|
|
})
|
|
|
|
result := make([]int8, 0, len(classes))
|
|
for class := range classes {
|
|
result = append(result, class)
|
|
}
|
|
return result
|
|
}
|
|
|
|
// ValidateAll validates all alternate advancements in the master list
|
|
func (m *MasterList) ValidateAll() []error {
|
|
var errors []error
|
|
|
|
m.MasterList.ForEach(func(nodeID int32, aa *AltAdvancement) {
|
|
if !aa.IsValid() {
|
|
errors = append(errors, fmt.Errorf("invalid AA data: node_id=%d", nodeID))
|
|
}
|
|
|
|
// Validate prerequisites
|
|
if aa.RankPrereqID > 0 {
|
|
prereq := m.MasterList.Get(aa.RankPrereqID)
|
|
if prereq == nil {
|
|
errors = append(errors, fmt.Errorf("AA %d has invalid prerequisite node ID %d", nodeID, aa.RankPrereqID))
|
|
}
|
|
}
|
|
|
|
// Validate positioning
|
|
if aa.Col < MIN_AA_COL || aa.Col > MAX_AA_COL {
|
|
errors = append(errors, fmt.Errorf("AA %d has invalid column %d", nodeID, aa.Col))
|
|
}
|
|
|
|
if aa.Row < MIN_AA_ROW || aa.Row > MAX_AA_ROW {
|
|
errors = append(errors, fmt.Errorf("AA %d has invalid row %d", nodeID, aa.Row))
|
|
}
|
|
|
|
// Validate costs and ranks
|
|
if aa.RankCost < MIN_RANK_COST || aa.RankCost > MAX_RANK_COST {
|
|
errors = append(errors, fmt.Errorf("AA %d has invalid rank cost %d", nodeID, aa.RankCost))
|
|
}
|
|
|
|
if aa.MaxRank < MIN_MAX_RANK || aa.MaxRank > MAX_MAX_RANK {
|
|
errors = append(errors, fmt.Errorf("AA %d has invalid max rank %d", nodeID, aa.MaxRank))
|
|
}
|
|
})
|
|
|
|
return errors
|
|
}
|