feat: leveling system
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user