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 }