(Feat): Initial Commit, Termdoku
This commit is contained in:
162
internal/achievements/achievements.go
Normal file
162
internal/achievements/achievements.go
Normal file
@@ -0,0 +1,162 @@
|
||||
package achievements
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type Achievement struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Icon string `json:"icon"`
|
||||
Unlocked bool `json:"unlocked"`
|
||||
Progress int `json:"progress"`
|
||||
Target int `json:"target"`
|
||||
}
|
||||
|
||||
type Manager struct {
|
||||
Achievements map[string]*Achievement `json:"achievements"`
|
||||
NewUnlocks []string `json:"-"`
|
||||
}
|
||||
|
||||
func New() *Manager {
|
||||
return &Manager{
|
||||
Achievements: map[string]*Achievement{
|
||||
"first_win": {
|
||||
ID: "first_win",
|
||||
Name: "First Victory",
|
||||
Description: "Complete your first puzzle",
|
||||
Icon: "🏆",
|
||||
Target: 1,
|
||||
},
|
||||
"speed_demon": {
|
||||
ID: "speed_demon",
|
||||
Name: "Speed Demon",
|
||||
Description: "Complete an Easy puzzle in under 3 minutes",
|
||||
Icon: "⚡",
|
||||
Target: 1,
|
||||
},
|
||||
"perfectionist": {
|
||||
ID: "perfectionist",
|
||||
Name: "Perfectionist",
|
||||
Description: "Complete a puzzle without using hints",
|
||||
Icon: "💎",
|
||||
Target: 1,
|
||||
},
|
||||
"streak_master": {
|
||||
ID: "streak_master",
|
||||
Name: "Streak Master",
|
||||
Description: "Achieve a 5-day streak",
|
||||
Icon: "🔥",
|
||||
Target: 5,
|
||||
},
|
||||
"century": {
|
||||
ID: "century",
|
||||
Name: "Century Club",
|
||||
Description: "Complete 100 puzzles",
|
||||
Icon: "💯",
|
||||
Target: 100,
|
||||
},
|
||||
"lunatic_legend": {
|
||||
ID: "lunatic_legend",
|
||||
Name: "Lunatic Legend",
|
||||
Description: "Complete 10 Lunatic puzzles",
|
||||
Icon: "🌙",
|
||||
Target: 10,
|
||||
},
|
||||
"daily_devotee": {
|
||||
ID: "daily_devotee",
|
||||
Name: "Daily Devotee",
|
||||
Description: "Complete 30 daily puzzles",
|
||||
Icon: "📅",
|
||||
Target: 30,
|
||||
},
|
||||
"no_mistakes": {
|
||||
ID: "no_mistakes",
|
||||
Name: "Flawless",
|
||||
Description: "Complete a Hard puzzle without auto-check",
|
||||
Icon: "✨",
|
||||
Target: 1,
|
||||
},
|
||||
},
|
||||
NewUnlocks: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
func path() (string, error) {
|
||||
h, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(h, ".termdoku", "achievements.json"), nil
|
||||
}
|
||||
|
||||
func Load() (*Manager, error) {
|
||||
m := New()
|
||||
p, err := path()
|
||||
if err != nil {
|
||||
return m, err
|
||||
}
|
||||
b, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return m, nil
|
||||
}
|
||||
return m, err
|
||||
}
|
||||
if err := json.Unmarshal(b, m); err != nil {
|
||||
return m, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func Save(m *Manager) error {
|
||||
p, err := path()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.MarshalIndent(m, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(p, data, 0o644)
|
||||
}
|
||||
|
||||
func (m *Manager) CheckAndUnlock(id string, progress int) bool {
|
||||
if ach, ok := m.Achievements[id]; ok {
|
||||
if !ach.Unlocked {
|
||||
ach.Progress = progress
|
||||
if ach.Progress >= ach.Target {
|
||||
ach.Unlocked = true
|
||||
m.NewUnlocks = append(m.NewUnlocks, id)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Manager) GetUnlockedCount() int {
|
||||
count := 0
|
||||
for _, ach := range m.Achievements {
|
||||
if ach.Unlocked {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func (m *Manager) GetTotalCount() int {
|
||||
return len(m.Achievements)
|
||||
}
|
||||
|
||||
func (m *Manager) ClearNewUnlocks() {
|
||||
m.NewUnlocks = []string{}
|
||||
}
|
||||
Reference in New Issue
Block a user