Added ✨himbucks✨
This commit is contained in:
parent
6a55017624
commit
9a1b3723bc
5 changed files with 209 additions and 4 deletions
42
command/himbucks.go
Normal file
42
command/himbucks.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"himbot/lib"
|
||||
"strings"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
func BalanceCommand(s *discordgo.Session, i *discordgo.InteractionCreate) (string, error) {
|
||||
user, err := lib.GetUser(i)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
balance, err := lib.GetBalance(user.ID, i.GuildID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("You have %d himbucks!", balance), nil
|
||||
}
|
||||
|
||||
func LeaderboardCommand(s *discordgo.Session, i *discordgo.InteractionCreate) (string, error) {
|
||||
entries, err := lib.GetLeaderboard(i.GuildID, 10)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(entries) == 0 {
|
||||
return "No himbucks earned yet!", nil
|
||||
}
|
||||
|
||||
var sb strings.Builder
|
||||
sb.WriteString("🏆 Himbucks Leaderboard 🏆\n\n")
|
||||
for idx, entry := range entries {
|
||||
sb.WriteString(fmt.Sprintf("%d. %s: %d himbucks\n", idx+1, entry.Username, entry.Balance))
|
||||
}
|
||||
|
||||
return sb.String(), nil
|
||||
}
|
136
lib/himbucks.go
Normal file
136
lib/himbucks.go
Normal file
|
@ -0,0 +1,136 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
const (
|
||||
HimbucksPerReward = 10
|
||||
MessageCountThreshold = 5
|
||||
CooldownPeriod = time.Minute
|
||||
)
|
||||
|
||||
type HimbucksEntry struct {
|
||||
Username string
|
||||
Balance int
|
||||
MessageCount int
|
||||
}
|
||||
|
||||
func GetOrCreateHimbucksEntry(userID int, guildID string) error {
|
||||
_, err := DBClient.Exec(`
|
||||
INSERT INTO himbucks (user_id, guild_id, balance, message_count)
|
||||
VALUES (?, ?, 0, 0)
|
||||
ON CONFLICT (user_id, guild_id) DO NOTHING`,
|
||||
userID, guildID)
|
||||
return err
|
||||
}
|
||||
|
||||
func ProcessMessage(s *discordgo.Session, m *discordgo.MessageCreate) error {
|
||||
// Ignore bot messages
|
||||
if m.Author.Bot {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get user from database
|
||||
var userID int
|
||||
err := DBClient.QueryRow("SELECT id FROM users WHERE discord_id = ?", m.Author.ID).Scan(&userID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get user: %w", err)
|
||||
}
|
||||
|
||||
// Ensure himbucks entry exists
|
||||
err = GetOrCreateHimbucksEntry(userID, m.GuildID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create himbucks entry: %w", err)
|
||||
}
|
||||
|
||||
// Update message count and check for rewards
|
||||
tx, err := DBClient.Begin()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start transaction: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
var messageCount int
|
||||
var lastEarnedAt sql.NullTime
|
||||
|
||||
err = tx.QueryRow(`
|
||||
SELECT message_count, last_earned_at
|
||||
FROM himbucks
|
||||
WHERE user_id = ? AND guild_id = ?`,
|
||||
userID, m.GuildID).Scan(&messageCount, &lastEarnedAt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get message count: %w", err)
|
||||
}
|
||||
|
||||
messageCount++
|
||||
shouldReward := messageCount >= MessageCountThreshold &&
|
||||
(!lastEarnedAt.Valid || time.Since(lastEarnedAt.Time) >= CooldownPeriod)
|
||||
|
||||
if shouldReward {
|
||||
_, err = tx.Exec(`
|
||||
UPDATE himbucks
|
||||
SET balance = balance + ?, message_count = 0, last_earned_at = CURRENT_TIMESTAMP
|
||||
WHERE user_id = ? AND guild_id = ?`,
|
||||
HimbucksPerReward, userID, m.GuildID)
|
||||
} else {
|
||||
_, err = tx.Exec(`
|
||||
UPDATE himbucks
|
||||
SET message_count = ?
|
||||
WHERE user_id = ? AND guild_id = ?`,
|
||||
messageCount, userID, m.GuildID)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update himbucks: %w", err)
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func GetBalance(discordID, guildID string) (int, error) {
|
||||
var balance int
|
||||
err := DBClient.QueryRow(`
|
||||
SELECT h.balance
|
||||
FROM himbucks h
|
||||
JOIN users u ON h.user_id = u.id
|
||||
WHERE u.discord_id = ? AND h.guild_id = ?`,
|
||||
discordID, guildID).Scan(&balance)
|
||||
if err == sql.ErrNoRows {
|
||||
return 0, nil
|
||||
}
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get balance: %w", err)
|
||||
}
|
||||
return balance, nil
|
||||
}
|
||||
|
||||
func GetLeaderboard(guildID string, limit int) ([]HimbucksEntry, error) {
|
||||
rows, err := DBClient.Query(`
|
||||
SELECT u.username, h.balance, h.message_count
|
||||
FROM himbucks h
|
||||
JOIN users u ON h.user_id = u.id
|
||||
WHERE h.guild_id = ?
|
||||
ORDER BY h.balance DESC
|
||||
LIMIT ?`,
|
||||
guildID, limit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get leaderboard: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var entries []HimbucksEntry
|
||||
for rows.Next() {
|
||||
var entry HimbucksEntry
|
||||
err := rows.Scan(&entry.Username, &entry.Balance, &entry.MessageCount)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to scan leaderboard entry: %w", err)
|
||||
}
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
return entries, nil
|
||||
}
|
24
main.go
24
main.go
|
@ -43,12 +43,22 @@ var (
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "balance",
|
||||
Description: "Check your himbucks balance",
|
||||
},
|
||||
{
|
||||
Name: "leaderboard",
|
||||
Description: "View the himbucks leaderboard",
|
||||
},
|
||||
}
|
||||
|
||||
commandHandlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){
|
||||
"ping": lib.HandleCommand("ping", 5*time.Second, command.PingCommand),
|
||||
"hs": lib.HandleCommand("hs", 10*time.Second, command.HsCommand),
|
||||
"markov": lib.HandleCommand("markov", 30*time.Second, command.MarkovCommand),
|
||||
"ping": lib.HandleCommand("ping", 5*time.Second, command.PingCommand),
|
||||
"hs": lib.HandleCommand("hs", 10*time.Second, command.HsCommand),
|
||||
"markov": lib.HandleCommand("markov", 30*time.Second, command.MarkovCommand),
|
||||
"balance": lib.HandleCommand("balance", 5*time.Second, command.BalanceCommand),
|
||||
"leaderboard": lib.HandleCommand("leaderboard", 5*time.Second, command.LeaderboardCommand),
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -74,7 +84,13 @@ func main() {
|
|||
dg.AddHandler(ready)
|
||||
dg.AddHandler(interactionCreate)
|
||||
|
||||
dg.Identify.Intents = discordgo.IntentsGuilds
|
||||
dg.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
if err := lib.ProcessMessage(s, m); err != nil {
|
||||
log.Printf("Error processing message for himbucks: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
dg.Identify.Intents = discordgo.IntentsGuilds | discordgo.IntentsGuildMessages
|
||||
|
||||
err = dg.Open()
|
||||
if err != nil {
|
||||
|
|
1
migrations/000003_create_himbucks_table.down.sql
Normal file
1
migrations/000003_create_himbucks_table.down.sql
Normal file
|
@ -0,0 +1 @@
|
|||
DROP TABLE IF EXISTS himbucks;
|
10
migrations/000003_create_himbucks_table.up.sql
Normal file
10
migrations/000003_create_himbucks_table.up.sql
Normal file
|
@ -0,0 +1,10 @@
|
|||
CREATE TABLE IF NOT EXISTS himbucks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL,
|
||||
guild_id TEXT NOT NULL,
|
||||
balance INTEGER DEFAULT 0,
|
||||
message_count INTEGER DEFAULT 0,
|
||||
last_earned_at DATETIME,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id),
|
||||
UNIQUE(user_id, guild_id)
|
||||
);
|
Loading…
Add table
Reference in a new issue