450 lines
11 KiB
Go
450 lines
11 KiB
Go
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"`
|
|
} |