eq2go/internal/quests/interfaces.go

476 lines
14 KiB
Go

package quests
// Player interface defines the required player functionality for quest system
type Player interface {
// Basic player information
GetID() int32
GetName() string
GetLevel() int8
GetTSLevel() int8
GetClass() int8
GetTSClass() int8
GetRace() int8
// Client interface for packet sending
GetClient() Client
// Quest-related player methods
GetQuest(questID int32) *Quest
HasQuest(questID int32) bool
HasQuestBeenCompleted(questID int32) bool
AddQuest(quest *Quest) error
RemoveQuest(questID int32) bool
// Position and zone information
GetX() float32
GetY() float32
GetZ() float32
GetZoneID() int32
// Faction information
GetFactionValue(factionID int32) int32
// Experience and rewards
AddCoins(amount int64)
AddExp(amount int32)
AddTSExp(amount int32)
AddStatusPoints(amount int32)
// Inventory management
GetPlayerItemList() ItemList
// Arrow color calculation (difficulty indication)
GetArrowColor(level int8) int8
GetTSArrowColor(level int8) int8
}
// Client interface defines client functionality needed for quest system
type Client interface {
// Basic client information
GetVersion() int16
GetNameCRC() int32
GetPlayer() Player
// Packet sending
QueuePacket(packet Packet)
SimpleMessage(color int32, message string)
// Quest-specific client methods
SendQuestJournalUpdate(quest *Quest, forceUpdate bool)
PopulateQuestRewardItems(items *[]Item, packet PacketStruct, arrayName ...string)
}
// Spawn interface defines spawn functionality needed for quest system
type Spawn interface {
// Basic spawn information
GetID() int32
GetDatabaseID() int32
GetName() string
GetRace() int8
GetModelType() int16
// Position information
GetX() float32
GetY() float32
GetZ() float32
GetZoneID() int32
}
// Spell interface defines spell functionality needed for quest system
type Spell interface {
GetSpellID() int32
GetName() string
}
// Item interface defines item functionality needed for quest system
type Item interface {
GetItemID() int32
GetName() string
GetIcon(version int16) int32
GetDetails() ItemDetails
GetStackCount() int32
}
// ItemDetails interface defines item detail functionality
type ItemDetails interface {
GetItemID() int32
GetUniqueID() int32
GetCount() int32
}
// ItemList interface defines item list functionality
type ItemList interface {
GetItemFromID(itemID int32, count int32) Item
}
// Packet interface defines packet functionality
type Packet interface {
// Packet data methods (placeholder)
Serialize() []byte
}
// PacketStruct interface defines packet structure functionality
type PacketStruct interface {
// Packet building methods
SetDataByName(name string, value interface{}, index ...int)
SetArrayLengthByName(name string, length int)
SetArrayDataByName(name string, value interface{}, index int)
SetSubArrayLengthByName(name string, length int, index int)
SetSubArrayDataByName(name string, value interface{}, index1, index2 int)
SetSubstructArrayDataByName(substruct, name string, value interface{}, index int)
SetItemArrayDataByName(name string, item Item, player Player, index int, flag ...int)
Serialize() Packet
GetVersion() int16
}
// QuestOfferer interface defines NPCs that can offer quests
type QuestOfferer interface {
Spawn
GetOfferedQuests() []int32
CanOfferQuest(questID int32, player Player) bool
OfferQuest(questID int32, player Player) error
}
// QuestReceiver interface defines NPCs that can receive completed quests
type QuestReceiver interface {
Spawn
GetAcceptedQuests() []int32
CanAcceptQuest(questID int32, player Player) bool
AcceptCompletedQuest(questID int32, player Player) error
}
// QuestValidator interface defines quest validation functionality
type QuestValidator interface {
ValidatePrerequisites(quest *Quest, player Player) error
ValidateQuestCompletion(quest *Quest, player Player) error
ValidateQuestSharing(quest *Quest, sharer, receiver Player) error
}
// QuestRewardProcessor interface defines quest reward processing
type QuestRewardProcessor interface {
ProcessQuestRewards(quest *Quest, player Player) error
CalculateRewards(quest *Quest, player Player) *QuestRewards
GiveRewards(rewards *QuestRewards, player Player) error
}
// QuestRewards contains calculated quest rewards
type QuestRewards struct {
Coins int64 `json:"coins"`
Experience int32 `json:"experience"`
TSExperience int32 `json:"ts_experience"`
StatusPoints int32 `json:"status_points"`
Items []Item `json:"items"`
FactionRewards map[int32]int32 `json:"faction_rewards"`
}
// QuestEventHandler interface defines quest event handling
type QuestEventHandler interface {
OnQuestStarted(quest *Quest, player Player)
OnQuestStepCompleted(quest *Quest, step *QuestStep, player Player)
OnQuestCompleted(quest *Quest, player Player)
OnQuestFailed(quest *Quest, step *QuestStep, player Player)
OnQuestAbandoned(quest *Quest, player Player)
OnQuestShared(quest *Quest, sharer, receiver Player)
}
// Database interface defines database operations for quest system
type Database interface {
// Quest CRUD operations
LoadQuest(questID int32) (*Quest, error)
SaveQuest(quest *Quest) error
DeleteQuest(questID int32) error
LoadAllQuests() ([]*Quest, error)
// Player quest operations
LoadPlayerQuests(playerID int32) ([]*Quest, error)
SavePlayerQuest(playerID int32, quest *Quest) error
DeletePlayerQuest(playerID, questID int32) error
MarkQuestCompleted(playerID, questID int32) error
IsQuestCompleted(playerID, questID int32) bool
// Quest step operations
SaveQuestStepProgress(playerID, questID, stepID int32, progress int32) error
LoadQuestStepProgress(playerID, questID, stepID int32) (int32, error)
}
// Logger interface defines logging functionality for quest system
type Logger interface {
LogInfo(message string, args ...interface{})
LogError(message string, args ...interface{})
LogDebug(message string, args ...interface{})
LogWarning(message string, args ...interface{})
}
// Configuration interface defines quest system configuration
type Configuration interface {
GetMaxPlayerQuests() int
GetQuestSharingEnabled() bool
GetQuestFailureEnabled() bool
GetQuestTimersEnabled() bool
GetXPBonusMultiplier() float64
GetCoinBonusMultiplier() float64
GetStatusBonusMultiplier() float64
}
// QuestSystemAdapter provides integration with other game systems
type QuestSystemAdapter struct {
questManager *QuestManager
validator QuestValidator
rewardProcessor QuestRewardProcessor
eventHandler QuestEventHandler
database Database
logger Logger
config Configuration
}
// NewQuestSystemAdapter creates a new quest system adapter
func NewQuestSystemAdapter(questManager *QuestManager, validator QuestValidator, rewardProcessor QuestRewardProcessor, eventHandler QuestEventHandler, database Database, logger Logger, config Configuration) *QuestSystemAdapter {
return &QuestSystemAdapter{
questManager: questManager,
validator: validator,
rewardProcessor: rewardProcessor,
eventHandler: eventHandler,
database: database,
logger: logger,
config: config,
}
}
// StartQuest handles starting a new quest for a player
func (qsa *QuestSystemAdapter) StartQuest(questID int32, player Player) error {
// Get quest from master list
quest := qsa.questManager.GetMasterList().GetQuest(questID, true)
if quest == nil {
return fmt.Errorf("quest %d not found", questID)
}
// Validate prerequisites
if qsa.validator != nil {
if err := qsa.validator.ValidatePrerequisites(quest, player); err != nil {
return fmt.Errorf("quest prerequisites not met: %w", err)
}
}
// Check if player can accept more quests
if qsa.config != nil {
maxQuests := qsa.config.GetMaxPlayerQuests()
if maxQuests > 0 && qsa.questManager.GetPlayerQuestCount(player.GetID()) >= maxQuests {
return fmt.Errorf("player has too many active quests")
}
}
// Give quest to player
_, err := qsa.questManager.GiveQuestToPlayer(player.GetID(), questID)
if err != nil {
return err
}
// Save to database
if qsa.database != nil {
if err := qsa.database.SavePlayerQuest(player.GetID(), quest); err != nil {
qsa.logger.LogError("Failed to save player quest to database: %v", err)
}
}
// Trigger event
if qsa.eventHandler != nil {
qsa.eventHandler.OnQuestStarted(quest, player)
}
// Log
if qsa.logger != nil {
qsa.logger.LogInfo("Player %s (%d) started quest %s (%d)", player.GetName(), player.GetID(), quest.Name, questID)
}
return nil
}
// CompleteQuest handles completing a quest for a player
func (qsa *QuestSystemAdapter) CompleteQuest(questID int32, player Player) error {
// Get player's quest
quest := qsa.questManager.GetPlayerQuest(player.GetID(), questID)
if quest == nil {
return fmt.Errorf("player does not have quest %d", questID)
}
// Validate completion
if qsa.validator != nil {
if err := qsa.validator.ValidateQuestCompletion(quest, player); err != nil {
return fmt.Errorf("quest completion validation failed: %w", err)
}
}
// Check if quest is actually complete
if !quest.GetCompleted() {
return fmt.Errorf("quest is not complete")
}
// Process rewards
if qsa.rewardProcessor != nil {
if err := qsa.rewardProcessor.ProcessQuestRewards(quest, player); err != nil {
qsa.logger.LogError("Failed to process quest rewards: %v", err)
return fmt.Errorf("failed to process quest rewards: %w", err)
}
}
// Mark as completed in database
if qsa.database != nil {
if err := qsa.database.MarkQuestCompleted(player.GetID(), questID); err != nil {
qsa.logger.LogError("Failed to mark quest as completed in database: %v", err)
}
}
// Remove from active quests if not repeatable
if !quest.IsRepeatable() {
qsa.questManager.RemoveQuestFromPlayer(player.GetID(), questID)
}
// Trigger event
if qsa.eventHandler != nil {
qsa.eventHandler.OnQuestCompleted(quest, player)
}
// Log
if qsa.logger != nil {
qsa.logger.LogInfo("Player %s (%d) completed quest %s (%d)", player.GetName(), player.GetID(), quest.Name, questID)
}
return nil
}
// UpdateQuestProgress handles updating quest step progress
func (qsa *QuestSystemAdapter) UpdateQuestProgress(questID, stepID, progress int32, player Player) error {
// Get player's quest
quest := qsa.questManager.GetPlayerQuest(player.GetID(), questID)
if quest == nil {
return fmt.Errorf("player does not have quest %d", questID)
}
// Update progress
if !quest.AddStepProgress(stepID, progress) {
return fmt.Errorf("failed to update quest step progress")
}
// Check if step is now complete
step := quest.GetQuestStep(stepID)
if step != nil && step.Complete() {
// Execute complete action if exists
if quest.HasCompleteAction(stepID) {
if err := quest.ExecuteCompleteAction(stepID); err != nil {
qsa.logger.LogError("Failed to execute quest step complete action: %v", err)
}
}
// Trigger event
if qsa.eventHandler != nil {
qsa.eventHandler.OnQuestStepCompleted(quest, step, player)
}
// Log
if qsa.logger != nil {
qsa.logger.LogInfo("Player %s (%d) completed step %d of quest %s (%d)", player.GetName(), player.GetID(), stepID, quest.Name, questID)
}
}
// Save progress to database
if qsa.database != nil {
if err := qsa.database.SaveQuestStepProgress(player.GetID(), questID, stepID, step.GetStepProgress()); err != nil {
qsa.logger.LogError("Failed to save quest step progress to database: %v", err)
}
}
return nil
}
// AbandonQuest handles abandoning a quest
func (qsa *QuestSystemAdapter) AbandonQuest(questID int32, player Player) error {
// Get player's quest
quest := qsa.questManager.GetPlayerQuest(player.GetID(), questID)
if quest == nil {
return fmt.Errorf("player does not have quest %d", questID)
}
// Check if quest can be abandoned
if !quest.CanDeleteQuest {
return fmt.Errorf("quest cannot be abandoned")
}
// Remove from player
if !qsa.questManager.RemoveQuestFromPlayer(player.GetID(), questID) {
return fmt.Errorf("failed to remove quest from player")
}
// Remove from database
if qsa.database != nil {
if err := qsa.database.DeletePlayerQuest(player.GetID(), questID); err != nil {
qsa.logger.LogError("Failed to delete player quest from database: %v", err)
}
}
// Trigger event
if qsa.eventHandler != nil {
qsa.eventHandler.OnQuestAbandoned(quest, player)
}
// Log
if qsa.logger != nil {
qsa.logger.LogInfo("Player %s (%d) abandoned quest %s (%d)", player.GetName(), player.GetID(), quest.Name, questID)
}
return nil
}
// ShareQuest handles sharing a quest between players
func (qsa *QuestSystemAdapter) ShareQuest(questID int32, sharer, receiver Player) error {
if !qsa.config.GetQuestSharingEnabled() {
return fmt.Errorf("quest sharing is disabled")
}
// Get sharer's quest
quest := qsa.questManager.GetPlayerQuest(sharer.GetID(), questID)
if quest == nil {
return fmt.Errorf("sharer does not have quest %d", questID)
}
// Validate sharing
if qsa.validator != nil {
if err := qsa.validator.ValidateQuestSharing(quest, sharer, receiver); err != nil {
return fmt.Errorf("quest sharing validation failed: %w", err)
}
}
// Check if receiver can accept more quests
if qsa.config != nil {
maxQuests := qsa.config.GetMaxPlayerQuests()
if maxQuests > 0 && qsa.questManager.GetPlayerQuestCount(receiver.GetID()) >= maxQuests {
return fmt.Errorf("receiver has too many active quests")
}
}
// Give quest to receiver
_, err := qsa.questManager.GiveQuestToPlayer(receiver.GetID(), questID)
if err != nil {
return fmt.Errorf("failed to give quest to receiver: %w", err)
}
// Save to database
if qsa.database != nil {
receiverQuest := qsa.questManager.GetPlayerQuest(receiver.GetID(), questID)
if err := qsa.database.SavePlayerQuest(receiver.GetID(), receiverQuest); err != nil {
qsa.logger.LogError("Failed to save shared quest to database: %v", err)
}
}
// Trigger event
if qsa.eventHandler != nil {
qsa.eventHandler.OnQuestShared(quest, sharer, receiver)
}
// Log
if qsa.logger != nil {
qsa.logger.LogInfo("Player %s (%d) shared quest %s (%d) with %s (%d)",
sharer.GetName(), sharer.GetID(), quest.Name, questID, receiver.GetName(), receiver.GetID())
}
return nil
}