89 lines
2.5 KiB
Go
89 lines
2.5 KiB
Go
package economy
|
||
|
||
import (
|
||
"context"
|
||
"database/sql"
|
||
)
|
||
|
||
// RankEntry یک ردیف از جدولِ رتبهبندی.
|
||
type RankEntry struct {
|
||
Rank int `json:"rank"`
|
||
Name string `json:"name"`
|
||
Avatar string `json:"avatar"`
|
||
RankPoints int64 `json:"rank_points"`
|
||
Tier string `json:"tier"`
|
||
}
|
||
|
||
// AwardRank امتیازِ رتبه را پس از یک بازیِ رتبهبندی بهروزرسانی میکند.
|
||
// برنده +reward، بازنده −reward/2 (کفِ صفر). برای میزِ غیرِرتبهبندی بیاثر است.
|
||
func (s *Service) AwardRank(ctx context.Context, userID int64, reward int, won bool) error {
|
||
if reward <= 0 {
|
||
return nil
|
||
}
|
||
delta := reward
|
||
if !won {
|
||
delta = -(reward / 2)
|
||
}
|
||
_, err := s.db.ExecContext(ctx,
|
||
`UPDATE users SET rank_points = MAX(0, rank_points + ?) WHERE id = ?`,
|
||
delta, userID)
|
||
return err
|
||
}
|
||
|
||
// Leaderboard فهرستِ برترین بازیکنان بر اساس امتیازِ رتبه را برمیگرداند.
|
||
func (s *Service) Leaderboard(ctx context.Context, limit int) ([]RankEntry, error) {
|
||
if limit <= 0 || limit > 100 {
|
||
limit = 50
|
||
}
|
||
rows, err := s.db.QueryContext(ctx,
|
||
`SELECT first_name, avatar, rank_points FROM users
|
||
WHERE rank_points > 0 ORDER BY rank_points DESC LIMIT ?`, limit)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
defer rows.Close()
|
||
out := make([]RankEntry, 0, limit)
|
||
rank := 0
|
||
for rows.Next() {
|
||
var name, avatar sql.NullString
|
||
var pts int64
|
||
if err := rows.Scan(&name, &avatar, &pts); err != nil {
|
||
return nil, err
|
||
}
|
||
rank++
|
||
tier, _ := RankTier(pts)
|
||
nm := name.String
|
||
if nm == "" {
|
||
nm = "بازیکن"
|
||
}
|
||
out = append(out, RankEntry{
|
||
Rank: rank, Name: nm, Avatar: avatar.String, RankPoints: pts, Tier: tier,
|
||
})
|
||
}
|
||
return out, rows.Err()
|
||
}
|
||
|
||
// ResetSeason امتیازِ رتبهی همهی کاربران را صفر کرده و شمارهی فصل را زیاد میکند.
|
||
func (s *Service) ResetSeason(ctx context.Context) error {
|
||
tx, err := s.db.BeginTx(ctx, nil)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer tx.Rollback()
|
||
if _, err := tx.ExecContext(ctx, `UPDATE users SET rank_points = 0`); err != nil {
|
||
return err
|
||
}
|
||
if _, err := tx.ExecContext(ctx,
|
||
`UPDATE app_settings SET value = value + 1 WHERE key = 'season'`); err != nil {
|
||
return err
|
||
}
|
||
return tx.Commit()
|
||
}
|
||
|
||
// Season شمارهی فصلِ جاری را برمیگرداند.
|
||
func (s *Service) Season(ctx context.Context) int {
|
||
var v int
|
||
_ = s.db.QueryRowContext(ctx, `SELECT value FROM app_settings WHERE key = 'season'`).Scan(&v)
|
||
return v
|
||
}
|