Added himbucks

This commit is contained in:
Atridad Lahiji 2024-11-05 00:19:36 -06:00
parent 6a55017624
commit 9a1b3723bc
Signed by: atridad
SSH key fingerprint: SHA256:LGomp8Opq0jz+7kbwNcdfTcuaLRb5Nh0k5AchDDb438
5 changed files with 209 additions and 4 deletions

42
command/himbucks.go Normal file
View 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
View 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
}

18
main.go
View file

@ -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),
"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 {

View file

@ -0,0 +1 @@
DROP TABLE IF EXISTS himbucks;

View 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)
);