Files
worktimeBot/internal/domain/rpg.go
db123 d15ed46066 fix: resolve go vet error and dayStart logic in ComputeDailyTotals
- 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
2026-06-25 09:54:22 +03:30

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
}