280 lines
7.4 KiB
Go
280 lines
7.4 KiB
Go
package achievements
|
|
|
|
import (
|
|
"fmt"
|
|
"maps"
|
|
"time"
|
|
)
|
|
|
|
// PlayerList manages achievements for a specific player
|
|
type PlayerList struct {
|
|
achievements map[uint32]*Achievement
|
|
}
|
|
|
|
// PlayerUpdateList manages achievement updates/progress for a specific player
|
|
type PlayerUpdateList struct {
|
|
updates map[uint32]*Update
|
|
}
|
|
|
|
// NewPlayerList creates a new player achievement list
|
|
func NewPlayerList() *PlayerList {
|
|
return &PlayerList{
|
|
achievements: make(map[uint32]*Achievement),
|
|
}
|
|
}
|
|
|
|
// NewPlayerUpdateList creates a new player achievement update list
|
|
func NewPlayerUpdateList() *PlayerUpdateList {
|
|
return &PlayerUpdateList{
|
|
updates: make(map[uint32]*Update),
|
|
}
|
|
}
|
|
|
|
// AddAchievement adds an achievement to the player's list
|
|
// Returns false if achievement with same ID already exists
|
|
func (p *PlayerList) AddAchievement(achievement *Achievement) bool {
|
|
if achievement == nil {
|
|
return false
|
|
}
|
|
|
|
if _, exists := p.achievements[achievement.ID]; exists {
|
|
return false
|
|
}
|
|
|
|
p.achievements[achievement.ID] = achievement
|
|
return true
|
|
}
|
|
|
|
// GetAchievement retrieves an achievement by ID
|
|
// Returns nil if not found
|
|
func (p *PlayerList) GetAchievement(id uint32) *Achievement {
|
|
return p.achievements[id]
|
|
}
|
|
|
|
// GetAllAchievements returns all player achievements
|
|
func (p *PlayerList) GetAllAchievements() map[uint32]*Achievement {
|
|
result := make(map[uint32]*Achievement, len(p.achievements))
|
|
maps.Copy(result, p.achievements)
|
|
return result
|
|
}
|
|
|
|
// RemoveAchievement removes an achievement from the player's list
|
|
// Returns true if achievement was found and removed
|
|
func (p *PlayerList) RemoveAchievement(id uint32) bool {
|
|
if _, exists := p.achievements[id]; !exists {
|
|
return false
|
|
}
|
|
|
|
delete(p.achievements, id)
|
|
return true
|
|
}
|
|
|
|
// HasAchievement checks if player has a specific achievement
|
|
func (p *PlayerList) HasAchievement(id uint32) bool {
|
|
_, exists := p.achievements[id]
|
|
return exists
|
|
}
|
|
|
|
// Clear removes all achievements from the player's list
|
|
func (p *PlayerList) Clear() {
|
|
p.achievements = make(map[uint32]*Achievement)
|
|
}
|
|
|
|
// Size returns the number of achievements in the player's list
|
|
func (p *PlayerList) Size() int {
|
|
return len(p.achievements)
|
|
}
|
|
|
|
// GetAchievementsByCategory returns player achievements filtered by category
|
|
func (p *PlayerList) GetAchievementsByCategory(category string) []*Achievement {
|
|
var result []*Achievement
|
|
for _, achievement := range p.achievements {
|
|
if achievement.Category == category {
|
|
result = append(result, achievement)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// AddUpdate adds an achievement update to the player's list
|
|
// Returns false if update with same ID already exists
|
|
func (p *PlayerUpdateList) AddUpdate(update *Update) bool {
|
|
if update == nil {
|
|
return false
|
|
}
|
|
|
|
if _, exists := p.updates[update.ID]; exists {
|
|
return false
|
|
}
|
|
|
|
p.updates[update.ID] = update
|
|
return true
|
|
}
|
|
|
|
// GetUpdate retrieves an achievement update by ID
|
|
// Returns nil if not found
|
|
func (p *PlayerUpdateList) GetUpdate(id uint32) *Update {
|
|
return p.updates[id]
|
|
}
|
|
|
|
// GetAllUpdates returns all player achievement updates
|
|
func (p *PlayerUpdateList) GetAllUpdates() map[uint32]*Update {
|
|
result := make(map[uint32]*Update, len(p.updates))
|
|
maps.Copy(result, p.updates)
|
|
return result
|
|
}
|
|
|
|
// UpdateProgress updates or creates achievement progress
|
|
func (p *PlayerUpdateList) UpdateProgress(achievementID uint32, itemUpdate uint32) {
|
|
update := p.updates[achievementID]
|
|
if update == nil {
|
|
update = NewUpdate()
|
|
update.ID = achievementID
|
|
p.updates[achievementID] = update
|
|
}
|
|
|
|
// Add or update the progress item
|
|
found := false
|
|
for i := range update.UpdateItems {
|
|
if update.UpdateItems[i].AchievementID == achievementID {
|
|
update.UpdateItems[i].ItemUpdate = itemUpdate
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
update.AddUpdateItem(UpdateItem{
|
|
AchievementID: achievementID,
|
|
ItemUpdate: itemUpdate,
|
|
})
|
|
}
|
|
}
|
|
|
|
// CompleteAchievement marks an achievement as completed
|
|
func (p *PlayerUpdateList) CompleteAchievement(achievementID uint32) {
|
|
update := p.updates[achievementID]
|
|
if update == nil {
|
|
update = NewUpdate()
|
|
update.ID = achievementID
|
|
p.updates[achievementID] = update
|
|
}
|
|
update.CompletedDate = time.Now()
|
|
}
|
|
|
|
// IsCompleted checks if an achievement is completed
|
|
func (p *PlayerUpdateList) IsCompleted(achievementID uint32) bool {
|
|
update := p.updates[achievementID]
|
|
return update != nil && !update.CompletedDate.IsZero()
|
|
}
|
|
|
|
// GetCompletedDate returns the completion date for an achievement
|
|
// Returns zero time if not completed
|
|
func (p *PlayerUpdateList) GetCompletedDate(achievementID uint32) time.Time {
|
|
update := p.updates[achievementID]
|
|
if update == nil {
|
|
return time.Time{}
|
|
}
|
|
return update.CompletedDate
|
|
}
|
|
|
|
// GetProgress returns the current progress for an achievement
|
|
// Returns 0 if no progress found
|
|
func (p *PlayerUpdateList) GetProgress(achievementID uint32) uint32 {
|
|
update := p.updates[achievementID]
|
|
if update == nil || len(update.UpdateItems) == 0 {
|
|
return 0
|
|
}
|
|
|
|
// Return the first matching update item's progress
|
|
for _, item := range update.UpdateItems {
|
|
if item.AchievementID == achievementID {
|
|
return item.ItemUpdate
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// RemoveUpdate removes an achievement update from the player's list
|
|
// Returns true if update was found and removed
|
|
func (p *PlayerUpdateList) RemoveUpdate(id uint32) bool {
|
|
if _, exists := p.updates[id]; !exists {
|
|
return false
|
|
}
|
|
|
|
delete(p.updates, id)
|
|
return true
|
|
}
|
|
|
|
// Clear removes all updates from the player's list
|
|
func (p *PlayerUpdateList) Clear() {
|
|
p.updates = make(map[uint32]*Update)
|
|
}
|
|
|
|
// Size returns the number of updates in the player's list
|
|
func (p *PlayerUpdateList) Size() int {
|
|
return len(p.updates)
|
|
}
|
|
|
|
// GetCompletedAchievements returns all completed achievement IDs
|
|
func (p *PlayerUpdateList) GetCompletedAchievements() []uint32 {
|
|
var completed []uint32
|
|
for id, update := range p.updates {
|
|
if !update.CompletedDate.IsZero() {
|
|
completed = append(completed, id)
|
|
}
|
|
}
|
|
return completed
|
|
}
|
|
|
|
// GetInProgressAchievements returns all in-progress achievement IDs
|
|
func (p *PlayerUpdateList) GetInProgressAchievements() []uint32 {
|
|
var inProgress []uint32
|
|
for id, update := range p.updates {
|
|
if update.CompletedDate.IsZero() && len(update.UpdateItems) > 0 {
|
|
inProgress = append(inProgress, id)
|
|
}
|
|
}
|
|
return inProgress
|
|
}
|
|
|
|
// PlayerManager combines achievement list and update list for a player
|
|
type PlayerManager struct {
|
|
Achievements *PlayerList
|
|
Updates *PlayerUpdateList
|
|
}
|
|
|
|
// NewPlayerManager creates a new player manager
|
|
func NewPlayerManager() *PlayerManager {
|
|
return &PlayerManager{
|
|
Achievements: NewPlayerList(),
|
|
Updates: NewPlayerUpdateList(),
|
|
}
|
|
}
|
|
|
|
// CheckRequirements validates if player meets achievement requirements
|
|
// This is a basic implementation - extend as needed for specific game logic
|
|
func (pm *PlayerManager) CheckRequirements(achievement *Achievement) (bool, error) {
|
|
if achievement == nil {
|
|
return false, fmt.Errorf("achievement cannot be nil")
|
|
}
|
|
|
|
// Basic implementation - check if we have progress >= required quantity
|
|
progress := pm.Updates.GetProgress(achievement.ID)
|
|
return progress >= achievement.QtyRequired, nil
|
|
}
|
|
|
|
// GetCompletionStatus returns completion percentage for an achievement
|
|
func (pm *PlayerManager) GetCompletionStatus(achievement *Achievement) float64 {
|
|
if achievement == nil || achievement.QtyRequired == 0 {
|
|
return 0.0
|
|
}
|
|
|
|
progress := pm.Updates.GetProgress(achievement.ID)
|
|
if progress >= achievement.QtyRequired {
|
|
return 100.0
|
|
}
|
|
|
|
return (float64(progress) / float64(achievement.QtyRequired)) * 100.0
|
|
}
|