- Fix 'string(d)' int-to-rune conversion in rpg_test.go by using fmt.Sprintf - Fix ComputeDailyTotals dayStart logic: initial state should be StateWorking when dayStart > 0, correctly counting work from dayStart to first out event - Update README project structure to reflect new domain/handler/repo layout - Implement missing achievements: rpg_pioneer (on RPG enable) and salary_setter (on first rate set) - Add tryUnlockAchievement helper to Handler
77 lines
1.5 KiB
Go
77 lines
1.5 KiB
Go
package domain
|
|
|
|
import "time"
|
|
|
|
// XpForLevel returns the total XP required to reach level n.
|
|
func XpForLevel(n int) int64 {
|
|
return int64(n) * int64(n+1) * XPCurveMultiplier
|
|
}
|
|
|
|
// LevelForXP returns the level for a given total XP amount.
|
|
func LevelForXP(xp int64) int {
|
|
l := 1
|
|
for XpForLevel(l) <= xp {
|
|
l++
|
|
}
|
|
return l - 1
|
|
}
|
|
|
|
// XpForWorkSeconds calculates XP earned for a given amount of work.
|
|
func XpForWorkSeconds(sec int64) int64 {
|
|
return sec
|
|
}
|
|
|
|
// StreakBonus returns bonus XP for maintaining a streak.
|
|
func StreakBonus(streak int) int64 {
|
|
b := int64(streak) * XPCurveMultiplier
|
|
if b > StreakBonusCap {
|
|
b = StreakBonusCap
|
|
}
|
|
return b
|
|
}
|
|
|
|
// ComputeStreakFromDates computes current and longest streak from a sorted list of date strings.
|
|
func ComputeStreakFromDates(dates []string, today string) (current, longest int) {
|
|
if len(dates) == 0 {
|
|
return 0, 0
|
|
}
|
|
|
|
dateSet := make(map[string]struct{}, len(dates))
|
|
for _, d := range dates {
|
|
dateSet[d] = struct{}{}
|
|
}
|
|
|
|
if _, ok := dateSet[today]; ok {
|
|
current = 1
|
|
for i := 1; ; i++ {
|
|
t, _ := time.Parse(DateLayout, today)
|
|
prev := t.AddDate(0, 0, -i).Format(DateLayout)
|
|
if _, ok := dateSet[prev]; ok {
|
|
current++
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
longest = 0
|
|
run := 1
|
|
for i := 1; i < len(dates); i++ {
|
|
prev, _ := time.Parse(DateLayout, dates[i-1])
|
|
curr, _ := time.Parse(DateLayout, dates[i])
|
|
if curr.Sub(prev).Hours() == 24 {
|
|
run++
|
|
} else {
|
|
if run > longest {
|
|
longest = run
|
|
}
|
|
run = 1
|
|
}
|
|
}
|
|
if run > longest {
|
|
longest = run
|
|
}
|
|
|
|
return current, longest
|
|
}
|