135 lines
3.2 KiB
Go
135 lines
3.2 KiB
Go
package level
|
|
|
|
import (
|
|
"context"
|
|
"math/rand"
|
|
"time"
|
|
|
|
"velox-bot/internal/db/repos/levelrepo"
|
|
)
|
|
|
|
type SettingsProvider interface {
|
|
IsLevelSystemEnabled(ctx context.Context, guildID int64) (bool, error)
|
|
GetLevelupChannelID(ctx context.Context, guildID int64) (int64, bool, error)
|
|
GetRoleRewardForLevel(ctx context.Context, guildID int64, level int) (roleID int64, ok bool, err error)
|
|
SetLevelUpChannel(ctx context.Context, guildID int64, channelID int64) error
|
|
SetLevelUpMessage(ctx context.Context, guildID int64, message string) error
|
|
GetLevelUpMessage(ctx context.Context, guildID int64) (string, error)
|
|
}
|
|
|
|
type Result struct {
|
|
LeveledUp bool
|
|
NewLevel int
|
|
RoleRewardID int64 // 0 if none
|
|
LevelupMessage string // you can fill this later
|
|
LevelupChannel int64 // 0 means "use current channel"
|
|
UpdatedXP int64
|
|
UpdatedLevel int
|
|
}
|
|
|
|
type Service struct {
|
|
levels *levelrepo.Repo
|
|
settings SettingsProvider
|
|
rand *rand.Rand
|
|
}
|
|
|
|
func New(levels *levelrepo.Repo, settings SettingsProvider) *Service {
|
|
return &Service{
|
|
levels: levels,
|
|
settings: settings,
|
|
rand: rand.New(rand.NewSource(time.Now().UnixNano())),
|
|
}
|
|
}
|
|
|
|
// HandleMessage mirrors your Python gain_xp behavior, minus Discord specifics.
|
|
func (s *Service) HandleMessage(ctx context.Context, guildID, userID int64) (*Result, error) {
|
|
enabled, err := s.settings.IsLevelSystemEnabled(ctx, guildID)
|
|
if err != nil || !enabled {
|
|
return &Result{LeveledUp: false}, err
|
|
}
|
|
|
|
lvl, err := s.levels.GetLevel(ctx, guildID, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// XP gain rules
|
|
shouldGainXP := false
|
|
if lvl.Level < 5 {
|
|
shouldGainXP = true
|
|
} else {
|
|
// random.randint(1, level//4) == 1
|
|
div := lvl.Level / 4
|
|
if div < 1 {
|
|
div = 1
|
|
}
|
|
if s.rand.Intn(div)+1 == 1 {
|
|
shouldGainXP = true
|
|
}
|
|
}
|
|
|
|
if !shouldGainXP {
|
|
return &Result{
|
|
LeveledUp: false,
|
|
UpdatedXP: lvl.XP,
|
|
UpdatedLevel: lvl.Level,
|
|
}, nil
|
|
}
|
|
|
|
// This assumes your setXp() adds some fixed XP per hit; adapt amount as needed.
|
|
xpPerMessage := s.rand.Intn(3) + 1
|
|
lvl.XP += int64(xpPerMessage)
|
|
|
|
res := &Result{
|
|
LeveledUp: false,
|
|
UpdatedXP: lvl.XP,
|
|
UpdatedLevel: lvl.Level,
|
|
}
|
|
|
|
// Level-up rule: if xp >= 100 -> level++
|
|
if lvl.XP >= 100 {
|
|
lvl.Level++
|
|
lvl.XP = 0 // or keep overflow, depending on Python behavior
|
|
|
|
res.LeveledUp = true
|
|
res.NewLevel = lvl.Level
|
|
res.UpdatedXP = lvl.XP
|
|
res.UpdatedLevel = lvl.Level
|
|
|
|
roleID, ok, err := s.settings.GetRoleRewardForLevel(ctx, guildID, lvl.Level)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if ok {
|
|
res.RoleRewardID = roleID
|
|
}
|
|
|
|
chID, ok, err := s.settings.GetLevelupChannelID(ctx, guildID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if ok {
|
|
res.LevelupChannel = chID
|
|
}
|
|
}
|
|
|
|
// Persist
|
|
if err := s.levels.UpsertLevel(ctx, lvl); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (s *Service) SetLevel(ctx context.Context, guildID, userID int64, level int) error {
|
|
return s.levels.SetLevel(ctx, guildID, userID, level)
|
|
}
|
|
|
|
func (s *Service) GetLevel(ctx context.Context, guildID, userID int64) (*levelrepo.Level, error) {
|
|
return s.levels.GetLevel(ctx, guildID, userID)
|
|
}
|
|
|
|
func (s *Service) TopLevels(ctx context.Context, guildID int64, limit int) ([]*levelrepo.Level, error) {
|
|
return s.levels.TopLevels(ctx, guildID, limit)
|
|
}
|