281 lines
7.6 KiB
Go

package collections
import (
"fmt"
"eq2emu/internal/database"
)
// PlayerList manages collections for a specific player
type PlayerList struct {
CharacterID int32
collections map[int32]*Collection
db *database.Database
}
// NewPlayerList creates a new player collection list
func NewPlayerList(characterID int32, db *database.Database) *PlayerList {
return &PlayerList{
CharacterID: characterID,
collections: make(map[int32]*Collection),
db: db,
}
}
// AddCollection adds a collection to the player's list
func (pl *PlayerList) AddCollection(collection *Collection) bool {
if collection == nil {
return false
}
if _, exists := pl.collections[collection.GetID()]; exists {
return false // Already exists
}
pl.collections[collection.GetID()] = collection
return true
}
// GetCollection retrieves a collection by ID
func (pl *PlayerList) GetCollection(id int32) *Collection {
return pl.collections[id]
}
// RemoveCollection removes a collection from the player's list
func (pl *PlayerList) RemoveCollection(id int32) bool {
if _, exists := pl.collections[id]; exists {
delete(pl.collections, id)
return true
}
return false
}
// ClearCollections removes all collections from the player's list
func (pl *PlayerList) ClearCollections() {
pl.collections = make(map[int32]*Collection)
}
// Size returns the number of collections the player has
func (pl *PlayerList) Size() int {
return len(pl.collections)
}
// GetCollections returns all player collections
func (pl *PlayerList) GetCollections() map[int32]*Collection {
return pl.collections
}
// NeedsItem checks if any of the player's collections need the specified item
func (pl *PlayerList) NeedsItem(itemID int32) bool {
for _, collection := range pl.collections {
if collection.NeedsItem(itemID) {
return true
}
}
return false
}
// HasCollectionsToHandIn checks if the player has any collections ready to turn in
func (pl *PlayerList) HasCollectionsToHandIn() bool {
for _, collection := range pl.collections {
if collection.GetIsReadyToTurnIn() {
return true
}
}
return false
}
// GetCollectionsToHandIn returns all collections ready to turn in
func (pl *PlayerList) GetCollectionsToHandIn() []*Collection {
var readyCollections []*Collection
for _, collection := range pl.collections {
if collection.GetIsReadyToTurnIn() {
readyCollections = append(readyCollections, collection)
}
}
return readyCollections
}
// GetCompletedCollections returns all completed collections
func (pl *PlayerList) GetCompletedCollections() []*Collection {
var completedCollections []*Collection
for _, collection := range pl.collections {
if collection.Completed {
completedCollections = append(completedCollections, collection)
}
}
return completedCollections
}
// GetActiveCollections returns all non-completed collections
func (pl *PlayerList) GetActiveCollections() []*Collection {
var activeCollections []*Collection
for _, collection := range pl.collections {
if !collection.Completed {
activeCollections = append(activeCollections, collection)
}
}
return activeCollections
}
// LoadPlayerCollections loads all collections for the player from database
func (pl *PlayerList) LoadPlayerCollections(masterList *MasterList) error {
if pl.db == nil {
return fmt.Errorf("no database connection available")
}
// Clear existing collections
pl.ClearCollections()
// Load player's collection progress
query := `SELECT collection_id, completed FROM character_collections WHERE char_id = ?`
rows, err := pl.db.Query(query, pl.CharacterID)
if err != nil {
return fmt.Errorf("failed to load player collections: %w", err)
}
defer rows.Close()
for rows.Next() {
var collectionID int32
var completed bool
if err := rows.Scan(&collectionID, &completed); err != nil {
return fmt.Errorf("failed to scan player collection: %w", err)
}
// Get the master collection
masterCollection := masterList.GetCollection(collectionID)
if masterCollection == nil {
continue // Skip if collection doesn't exist in master list
}
// Create a copy for the player
playerCollection := masterCollection.Clone()
playerCollection.Completed = completed
// Load player's found items
itemQuery := `SELECT collection_item_id FROM character_collection_items WHERE char_id = ? AND collection_id = ?`
itemRows, err := pl.db.Query(itemQuery, pl.CharacterID, collectionID)
if err != nil {
return fmt.Errorf("failed to load player collection items: %w", err)
}
for itemRows.Next() {
var itemID int32
if err := itemRows.Scan(&itemID); err != nil {
itemRows.Close()
return fmt.Errorf("failed to scan player collection item: %w", err)
}
// Mark the item as found
if collectionItem := playerCollection.GetCollectionItemByItemID(itemID); collectionItem != nil {
collectionItem.Found = 1
}
}
itemRows.Close()
pl.AddCollection(playerCollection)
}
return nil
}
// SavePlayerCollection saves a player's collection progress
func (pl *PlayerList) SavePlayerCollection(collectionID int32) error {
if pl.db == nil {
return fmt.Errorf("no database connection available")
}
collection := pl.GetCollection(collectionID)
if collection == nil {
return fmt.Errorf("collection %d not found for player %d", collectionID, pl.CharacterID)
}
// Update or insert player collection record
_, err := pl.db.Exec(`
INSERT INTO character_collections (char_id, collection_id, completed)
VALUES (?, ?, ?)
ON CONFLICT(char_id, collection_id)
DO UPDATE SET completed = ?`,
pl.CharacterID, collectionID, collection.Completed, collection.Completed)
if err != nil {
return fmt.Errorf("failed to save player collection: %w", err)
}
// Delete existing found items and re-insert
_, err = pl.db.Exec(`DELETE FROM character_collection_items WHERE char_id = ? AND collection_id = ?`,
pl.CharacterID, collectionID)
if err != nil {
return fmt.Errorf("failed to delete old collection items: %w", err)
}
// Insert found items
for _, item := range collection.CollectionItems {
if item.Found != 0 {
_, err = pl.db.Exec(`
INSERT INTO character_collection_items (char_id, collection_id, collection_item_id)
VALUES (?, ?, ?)`,
pl.CharacterID, collectionID, item.ItemID)
if err != nil {
return fmt.Errorf("failed to save collection item: %w", err)
}
}
}
collection.SaveNeeded = false
return nil
}
// SaveAllCollections saves all player collections that need saving
func (pl *PlayerList) SaveAllCollections() error {
for collectionID, collection := range pl.collections {
if collection.SaveNeeded {
if err := pl.SavePlayerCollection(collectionID); err != nil {
return err
}
}
}
return nil
}
// GetStatistics returns statistics about the player's collections
func (pl *PlayerList) GetStatistics() map[string]any {
stats := make(map[string]any)
stats["total_collections"] = len(pl.collections)
completed := 0
readyToTurnIn := 0
totalItemsFound := 0
totalItemsNeeded := 0
for _, collection := range pl.collections {
if collection.Completed {
completed++
}
if collection.GetIsReadyToTurnIn() {
readyToTurnIn++
}
for _, item := range collection.CollectionItems {
if item.Found != 0 {
totalItemsFound++
} else {
totalItemsNeeded++
}
}
}
stats["completed_collections"] = completed
stats["ready_to_turn_in"] = readyToTurnIn
stats["active_collections"] = len(pl.collections) - completed
stats["total_items_found"] = totalItemsFound
stats["total_items_needed"] = totalItemsNeeded
if totalItemsFound+totalItemsNeeded > 0 {
stats["overall_progress"] = float64(totalItemsFound) / float64(totalItemsFound+totalItemsNeeded) * 100.0
} else {
stats["overall_progress"] = 0.0
}
return stats
}