package quests import ( "fmt" "sync" ) // MasterQuestList manages all quests in the system type MasterQuestList struct { quests map[int32]*Quest mutex sync.RWMutex } // NewMasterQuestList creates a new master quest list func NewMasterQuestList() *MasterQuestList { return &MasterQuestList{ quests: make(map[int32]*Quest), } } // AddQuest adds a quest to the master list func (mql *MasterQuestList) AddQuest(questID int32, quest *Quest) error { if quest == nil { return fmt.Errorf("quest cannot be nil") } if questID != quest.ID { return fmt.Errorf("quest ID mismatch: provided %d, quest has %d", questID, quest.ID) } mql.mutex.Lock() defer mql.mutex.Unlock() if _, exists := mql.quests[questID]; exists { return fmt.Errorf("quest %d already exists", questID) } mql.quests[questID] = quest return nil } // GetQuest returns a quest by ID, optionally creating a copy func (mql *MasterQuestList) GetQuest(questID int32, copyQuest bool) *Quest { mql.mutex.RLock() defer mql.mutex.RUnlock() quest, exists := mql.quests[questID] if !exists { return nil } if copyQuest { return quest.Copy() } return quest } // RemoveQuest removes a quest from the master list func (mql *MasterQuestList) RemoveQuest(questID int32) bool { mql.mutex.Lock() defer mql.mutex.Unlock() if _, exists := mql.quests[questID]; exists { delete(mql.quests, questID) return true } return false } // HasQuest checks if a quest exists func (mql *MasterQuestList) HasQuest(questID int32) bool { mql.mutex.RLock() defer mql.mutex.RUnlock() _, exists := mql.quests[questID] return exists } // GetAllQuests returns a copy of all quests map func (mql *MasterQuestList) GetAllQuests() map[int32]*Quest { mql.mutex.RLock() defer mql.mutex.RUnlock() quests := make(map[int32]*Quest) for id, quest := range mql.quests { quests[id] = quest } return quests } // GetQuestsByLevel returns quests within a level range func (mql *MasterQuestList) GetQuestsByLevel(minLevel, maxLevel int8) []*Quest { mql.mutex.RLock() defer mql.mutex.RUnlock() var quests []*Quest for _, quest := range mql.quests { if quest.Level >= minLevel && quest.Level <= maxLevel { quests = append(quests, quest) } } return quests } // GetQuestsByType returns quests of a specific type func (mql *MasterQuestList) GetQuestsByType(questType string) []*Quest { mql.mutex.RLock() defer mql.mutex.RUnlock() var quests []*Quest for _, quest := range mql.quests { if quest.Type == questType { quests = append(quests, quest) } } return quests } // GetQuestsByZone returns quests in a specific zone func (mql *MasterQuestList) GetQuestsByZone(zone string) []*Quest { mql.mutex.RLock() defer mql.mutex.RUnlock() var quests []*Quest for _, quest := range mql.quests { if quest.Zone == zone { quests = append(quests, quest) } } return quests } // GetQuestsByGiver returns quests given by a specific NPC func (mql *MasterQuestList) GetQuestsByGiver(giverID int32) []*Quest { mql.mutex.RLock() defer mql.mutex.RUnlock() var quests []*Quest for _, quest := range mql.quests { if quest.QuestGiver == giverID { quests = append(quests, quest) } } return quests } // GetRepeatableQuests returns all repeatable quests func (mql *MasterQuestList) GetRepeatableQuests() []*Quest { mql.mutex.RLock() defer mql.mutex.RUnlock() var quests []*Quest for _, quest := range mql.quests { if quest.Repeatable { quests = append(quests, quest) } } return quests } // GetQuestCount returns the total number of quests func (mql *MasterQuestList) GetQuestCount() int { mql.mutex.RLock() defer mql.mutex.RUnlock() return len(mql.quests) } // Clear removes all quests func (mql *MasterQuestList) Clear() { mql.mutex.Lock() defer mql.mutex.Unlock() mql.quests = make(map[int32]*Quest) } // Reload clears and reloads all quests func (mql *MasterQuestList) Reload() { mql.Clear() // TODO: Implement quest reloading from database or files // This would typically involve: // 1. Loading quest data from database // 2. Creating Quest objects // 3. Adding them to the master list // For now, this is a placeholder fmt.Println("Quest reload requested - implementation pending") } // ValidateAllQuests validates all quests in the master list func (mql *MasterQuestList) ValidateAllQuests() []error { mql.mutex.RLock() defer mql.mutex.RUnlock() var errors []error for questID, quest := range mql.quests { if err := quest.ValidateQuest(); err != nil { errors = append(errors, fmt.Errorf("quest %d validation failed: %w", questID, err)) } } return errors } // GetQuestStatistics returns basic statistics about the quest system func (mql *MasterQuestList) GetQuestStatistics() *QuestStatistics { mql.mutex.RLock() defer mql.mutex.RUnlock() stats := &QuestStatistics{ TotalQuests: len(mql.quests), QuestsByType: make(map[string]int), QuestsByLevel: make(map[int8]int), RepeatableCount: 0, HiddenCount: 0, } for _, quest := range mql.quests { // Count by type stats.QuestsByType[quest.Type]++ // Count by level stats.QuestsByLevel[quest.Level]++ // Count special flags if quest.Repeatable { stats.RepeatableCount++ } if quest.Hidden { stats.HiddenCount++ } } return stats } // QuestStatistics contains statistical information about quests type QuestStatistics struct { TotalQuests int `json:"total_quests"` QuestsByType map[string]int `json:"quests_by_type"` QuestsByLevel map[int8]int `json:"quests_by_level"` RepeatableCount int `json:"repeatable_count"` HiddenCount int `json:"hidden_count"` } // QuestManager provides high-level quest management functionality type QuestManager struct { masterList *MasterQuestList playerQuests map[int32]map[int32]*Quest // playerID -> questID -> quest mutex sync.RWMutex } // NewQuestManager creates a new quest manager func NewQuestManager() *QuestManager { return &QuestManager{ masterList: NewMasterQuestList(), playerQuests: make(map[int32]map[int32]*Quest), } } // GetMasterList returns the master quest list func (qm *QuestManager) GetMasterList() *MasterQuestList { return qm.masterList } // GiveQuestToPlayer assigns a quest to a player func (qm *QuestManager) GiveQuestToPlayer(playerID, questID int32) (*Quest, error) { // Get quest from master list (copy it) quest := qm.masterList.GetQuest(questID, true) if quest == nil { return nil, fmt.Errorf("quest %d not found", questID) } qm.mutex.Lock() defer qm.mutex.Unlock() // Initialize player quest map if needed if qm.playerQuests[playerID] == nil { qm.playerQuests[playerID] = make(map[int32]*Quest) } // Check if player already has this quest if _, exists := qm.playerQuests[playerID][questID]; exists { return nil, fmt.Errorf("player %d already has quest %d", playerID, questID) } // Assign quest to player qm.playerQuests[playerID][questID] = quest return quest, nil } // RemoveQuestFromPlayer removes a quest from a player func (qm *QuestManager) RemoveQuestFromPlayer(playerID, questID int32) bool { qm.mutex.Lock() defer qm.mutex.Unlock() if playerQuests, exists := qm.playerQuests[playerID]; exists { if _, questExists := playerQuests[questID]; questExists { delete(playerQuests, questID) // Clean up empty player quest map if len(playerQuests) == 0 { delete(qm.playerQuests, playerID) } return true } } return false } // GetPlayerQuest returns a specific quest for a player func (qm *QuestManager) GetPlayerQuest(playerID, questID int32) *Quest { qm.mutex.RLock() defer qm.mutex.RUnlock() if playerQuests, exists := qm.playerQuests[playerID]; exists { return playerQuests[questID] } return nil } // GetPlayerQuests returns all quests for a player func (qm *QuestManager) GetPlayerQuests(playerID int32) map[int32]*Quest { qm.mutex.RLock() defer qm.mutex.RUnlock() if playerQuests, exists := qm.playerQuests[playerID]; exists { // Return a copy quests := make(map[int32]*Quest) for questID, quest := range playerQuests { quests[questID] = quest } return quests } return make(map[int32]*Quest) } // PlayerHasQuest checks if a player has a specific quest func (qm *QuestManager) PlayerHasQuest(playerID, questID int32) bool { return qm.GetPlayerQuest(playerID, questID) != nil } // GetPlayerQuestCount returns the number of quests a player has func (qm *QuestManager) GetPlayerQuestCount(playerID int32) int { qm.mutex.RLock() defer qm.mutex.RUnlock() if playerQuests, exists := qm.playerQuests[playerID]; exists { return len(playerQuests) } return 0 } // ClearPlayerQuests removes all quests from a player func (qm *QuestManager) ClearPlayerQuests(playerID int32) { qm.mutex.Lock() defer qm.mutex.Unlock() delete(qm.playerQuests, playerID) } // GetAllPlayerIDs returns all player IDs that have quests func (qm *QuestManager) GetAllPlayerIDs() []int32 { qm.mutex.RLock() defer qm.mutex.RUnlock() var playerIDs []int32 for playerID := range qm.playerQuests { playerIDs = append(playerIDs, playerID) } return playerIDs } // UpdatePlayerQuestProgress updates progress for a player's quest step func (qm *QuestManager) UpdatePlayerQuestProgress(playerID, questID, stepID, progress int32) bool { quest := qm.GetPlayerQuest(playerID, questID) if quest == nil { return false } return quest.AddStepProgress(stepID, progress) } // CompletePlayerQuestStep marks a quest step as complete for a player func (qm *QuestManager) CompletePlayerQuestStep(playerID, questID, stepID int32) bool { quest := qm.GetPlayerQuest(playerID, questID) if quest == nil { return false } return quest.SetStepComplete(stepID) } // IsPlayerQuestComplete checks if a player's quest is complete func (qm *QuestManager) IsPlayerQuestComplete(playerID, questID int32) bool { quest := qm.GetPlayerQuest(playerID, questID) if quest == nil { return false } return quest.GetCompleted() } // GetPlayerQuestStatistics returns statistics for a player's quests func (qm *QuestManager) GetPlayerQuestStatistics(playerID int32) *PlayerQuestStatistics { quests := qm.GetPlayerQuests(playerID) stats := &PlayerQuestStatistics{ TotalQuests: len(quests), CompletedQuests: 0, QuestsByType: make(map[string]int), QuestsByLevel: make(map[int8]int), } for _, quest := range quests { if quest.GetCompleted() { stats.CompletedQuests++ } stats.QuestsByType[quest.Type]++ stats.QuestsByLevel[quest.Level]++ } return stats } // PlayerQuestStatistics contains statistical information about a player's quests type PlayerQuestStatistics struct { TotalQuests int `json:"total_quests"` CompletedQuests int `json:"completed_quests"` QuestsByType map[string]int `json:"quests_by_type"` QuestsByLevel map[int8]int `json:"quests_by_level"` }