302 lines
10 KiB
Go

package achievements
import (
"eq2emu/internal/database"
"fmt"
"time"
)
// LoadAllAchievements loads all achievements from database into master list
func LoadAllAchievements(db *database.DB, masterList *MasterList) error {
query := `SELECT achievement_id, title, uncompleted_text, completed_text,
category, expansion, icon, point_value, qty_req, hide_achievement,
unknown3a, unknown3b FROM achievements`
err := db.Query(query, func(row *database.Row) error {
achievement := NewAchievement()
achievement.ID = uint32(row.Int(0))
achievement.Title = row.Text(1)
achievement.UncompletedText = row.Text(2)
achievement.CompletedText = row.Text(3)
achievement.Category = row.Text(4)
achievement.Expansion = row.Text(5)
achievement.Icon = uint16(row.Int(6))
achievement.PointValue = uint32(row.Int(7))
achievement.QtyRequired = uint32(row.Int(8))
achievement.Hide = row.Bool(9)
achievement.Unknown3A = uint32(row.Int(10))
achievement.Unknown3B = uint32(row.Int(11))
// Load requirements and rewards
if err := loadAchievementRequirements(db, achievement); err != nil {
return fmt.Errorf("failed to load requirements for achievement %d: %w", achievement.ID, err)
}
if err := loadAchievementRewards(db, achievement); err != nil {
return fmt.Errorf("failed to load rewards for achievement %d: %w", achievement.ID, err)
}
if !masterList.AddAchievement(achievement) {
return fmt.Errorf("duplicate achievement ID: %d", achievement.ID)
}
return nil
})
return err
}
// loadAchievementRequirements loads requirements for a specific achievement
func loadAchievementRequirements(db *database.DB, achievement *Achievement) error {
query := `SELECT achievement_id, name, qty_req
FROM achievements_requirements
WHERE achievement_id = ?`
return db.Query(query, func(row *database.Row) error {
req := Requirement{
AchievementID: uint32(row.Int(0)),
Name: row.Text(1),
QtyRequired: uint32(row.Int(2)),
}
achievement.AddRequirement(req)
return nil
}, achievement.ID)
}
// loadAchievementRewards loads rewards for a specific achievement
func loadAchievementRewards(db *database.DB, achievement *Achievement) error {
query := `SELECT achievement_id, reward
FROM achievements_rewards
WHERE achievement_id = ?`
return db.Query(query, func(row *database.Row) error {
reward := Reward{
AchievementID: uint32(row.Int(0)),
Reward: row.Text(1),
}
achievement.AddReward(reward)
return nil
}, achievement.ID)
}
// LoadPlayerAchievements loads player achievements from database
func LoadPlayerAchievements(db *database.DB, playerID uint32, playerList *PlayerList) error {
query := `SELECT achievement_id, title, uncompleted_text, completed_text,
category, expansion, icon, point_value, qty_req, hide_achievement,
unknown3a, unknown3b FROM achievements`
err := db.Query(query, func(row *database.Row) error {
achievement := NewAchievement()
achievement.ID = uint32(row.Int(0))
achievement.Title = row.Text(1)
achievement.UncompletedText = row.Text(2)
achievement.CompletedText = row.Text(3)
achievement.Category = row.Text(4)
achievement.Expansion = row.Text(5)
achievement.Icon = uint16(row.Int(6))
achievement.PointValue = uint32(row.Int(7))
achievement.QtyRequired = uint32(row.Int(8))
achievement.Hide = row.Bool(9)
achievement.Unknown3A = uint32(row.Int(10))
achievement.Unknown3B = uint32(row.Int(11))
// Load requirements and rewards
if err := loadAchievementRequirements(db, achievement); err != nil {
return fmt.Errorf("failed to load requirements: %w", err)
}
if err := loadAchievementRewards(db, achievement); err != nil {
return fmt.Errorf("failed to load rewards: %w", err)
}
if !playerList.AddAchievement(achievement) {
return fmt.Errorf("duplicate achievement ID: %d", achievement.ID)
}
return nil
})
return err
}
// LoadPlayerAchievementUpdates loads player achievement progress from database
func LoadPlayerAchievementUpdates(db *database.DB, playerID uint32, updateList *PlayerUpdateList) error {
query := `SELECT char_id, achievement_id, completed_date
FROM character_achievements
WHERE char_id = ?`
return db.Query(query, func(row *database.Row) error {
update := NewUpdate()
update.ID = uint32(row.Int(1))
// Convert completed_date from Unix timestamp
if !row.IsNull(2) {
timestamp := row.Int64(2)
update.CompletedDate = time.Unix(timestamp, 0)
}
// Load update items
if err := loadPlayerAchievementUpdateItems(db, playerID, update); err != nil {
return fmt.Errorf("failed to load update items: %w", err)
}
if !updateList.AddUpdate(update) {
return fmt.Errorf("duplicate achievement update ID: %d", update.ID)
}
return nil
}, playerID)
}
// loadPlayerAchievementUpdateItems loads progress items for an achievement update
func loadPlayerAchievementUpdateItems(db *database.DB, playerID uint32, update *Update) error {
query := `SELECT achievement_id, items
FROM character_achievements_items
WHERE char_id = ? AND achievement_id = ?`
return db.Query(query, func(row *database.Row) error {
item := UpdateItem{
AchievementID: uint32(row.Int(0)),
ItemUpdate: uint32(row.Int(1)),
}
update.AddUpdateItem(item)
return nil
}, playerID, update.ID)
}
// SavePlayerAchievementUpdate saves or updates player achievement progress
func SavePlayerAchievementUpdate(db *database.DB, playerID uint32, update *Update) error {
return db.Transaction(func(tx *database.DB) error {
// Save or update main achievement record
query := `INSERT OR REPLACE INTO character_achievements
(char_id, achievement_id, completed_date) VALUES (?, ?, ?)`
var completedDate *int64
if !update.CompletedDate.IsZero() {
timestamp := update.CompletedDate.Unix()
completedDate = &timestamp
}
if err := tx.Exec(query, playerID, update.ID, completedDate); err != nil {
return fmt.Errorf("failed to save achievement update: %w", err)
}
// Delete existing update items
deleteQuery := `DELETE FROM character_achievements_items
WHERE char_id = ? AND achievement_id = ?`
if err := tx.Exec(deleteQuery, playerID, update.ID); err != nil {
return fmt.Errorf("failed to delete old update items: %w", err)
}
// Insert new update items
itemQuery := `INSERT INTO character_achievements_items
(char_id, achievement_id, items) VALUES (?, ?, ?)`
for _, item := range update.UpdateItems {
if err := tx.Exec(itemQuery, playerID, item.AchievementID, item.ItemUpdate); err != nil {
return fmt.Errorf("failed to save update item: %w", err)
}
}
return nil
})
}
// DeletePlayerAchievementUpdate removes player achievement progress from database
func DeletePlayerAchievementUpdate(db *database.DB, playerID uint32, achievementID uint32) error {
return db.Transaction(func(tx *database.DB) error {
// Delete main achievement record
query := `DELETE FROM character_achievements
WHERE char_id = ? AND achievement_id = ?`
if err := tx.Exec(query, playerID, achievementID); err != nil {
return fmt.Errorf("failed to delete achievement update: %w", err)
}
// Delete update items
itemQuery := `DELETE FROM character_achievements_items
WHERE char_id = ? AND achievement_id = ?`
if err := tx.Exec(itemQuery, playerID, achievementID); err != nil {
return fmt.Errorf("failed to delete update items: %w", err)
}
return nil
})
}
// SaveAchievement saves or updates an achievement in the database
func SaveAchievement(db *database.DB, achievement *Achievement) error {
return db.Transaction(func(tx *database.DB) error {
// Save main achievement record
query := `INSERT OR REPLACE INTO achievements
(achievement_id, title, uncompleted_text, completed_text,
category, expansion, icon, point_value, qty_req,
hide_achievement, unknown3a, unknown3b)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
if err := tx.Exec(query, achievement.ID, achievement.Title,
achievement.UncompletedText, achievement.CompletedText,
achievement.Category, achievement.Expansion, achievement.Icon,
achievement.PointValue, achievement.QtyRequired, achievement.Hide,
achievement.Unknown3A, achievement.Unknown3B); err != nil {
return fmt.Errorf("failed to save achievement: %w", err)
}
// Delete existing requirements and rewards
if err := tx.Exec("DELETE FROM achievements_requirements WHERE achievement_id = ?", achievement.ID); err != nil {
return fmt.Errorf("failed to delete old requirements: %w", err)
}
if err := tx.Exec("DELETE FROM achievements_rewards WHERE achievement_id = ?", achievement.ID); err != nil {
return fmt.Errorf("failed to delete old rewards: %w", err)
}
// Insert requirements
reqQuery := `INSERT INTO achievements_requirements
(achievement_id, name, qty_req) VALUES (?, ?, ?)`
for _, req := range achievement.Requirements {
if err := tx.Exec(reqQuery, req.AchievementID, req.Name, req.QtyRequired); err != nil {
return fmt.Errorf("failed to save requirement: %w", err)
}
}
// Insert rewards
rewardQuery := `INSERT INTO achievements_rewards
(achievement_id, reward) VALUES (?, ?)`
for _, reward := range achievement.Rewards {
if err := tx.Exec(rewardQuery, reward.AchievementID, reward.Reward); err != nil {
return fmt.Errorf("failed to save reward: %w", err)
}
}
return nil
})
}
// DeleteAchievement removes an achievement and all related records from database
func DeleteAchievement(db *database.DB, achievementID uint32) error {
return db.Transaction(func(tx *database.DB) error {
// Delete main achievement
if err := tx.Exec("DELETE FROM achievements WHERE achievement_id = ?", achievementID); err != nil {
return fmt.Errorf("failed to delete achievement: %w", err)
}
// Delete requirements
if err := tx.Exec("DELETE FROM achievements_requirements WHERE achievement_id = ?", achievementID); err != nil {
return fmt.Errorf("failed to delete requirements: %w", err)
}
// Delete rewards
if err := tx.Exec("DELETE FROM achievements_rewards WHERE achievement_id = ?", achievementID); err != nil {
return fmt.Errorf("failed to delete rewards: %w", err)
}
// Delete player progress (optional - might want to preserve history)
if err := tx.Exec("DELETE FROM character_achievements WHERE achievement_id = ?", achievementID); err != nil {
return fmt.Errorf("failed to delete player achievements: %w", err)
}
if err := tx.Exec("DELETE FROM character_achievements_items WHERE achievement_id = ?", achievementID); err != nil {
return fmt.Errorf("failed to delete player achievement items: %w", err)
}
return nil
})
}