Georg Pfuetzenreuter
7ec49a9769
Print only a single message instead of one per winner to reduce chat clutter. Skip cashout to users who won less than the possible cashout value as limited by the division value to avoid congratulating someone who only gets 0. Abort should a regression cause the logic to process an empty set of finishers to prevent unexpected behavior. Signed-off-by: Georg Pfuetzenreuter <mail@georg-pfuetzenreuter.net>
127 lines
4.2 KiB
Go
127 lines
4.2 KiB
Go
package wat
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/go-irc/irc"
|
|
)
|
|
|
|
type BotGameConfig map[string][]string
|
|
|
|
type WatIntegrationConfig struct {
|
|
BotHosts []string
|
|
BotGames BotGameConfig
|
|
}
|
|
|
|
type WatIntegration struct {
|
|
bot *WatBot
|
|
db *WatDb
|
|
c *WatIntegrationConfig
|
|
}
|
|
|
|
func NewWatIntegration(bot *WatBot, db *WatDb, c *WatIntegrationConfig) *WatIntegration {
|
|
return &WatIntegration{bot, db, c}
|
|
}
|
|
|
|
func (w *WatIntegration) Bot(m *irc.Message) (bool, []string) {
|
|
isBot := w.bot.Allowed(m.Prefix.Host, w.c.BotHosts)
|
|
var games []string
|
|
if isBot {
|
|
for b, g := range w.c.BotGames {
|
|
if b == m.Prefix.Name {
|
|
games = g
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return isBot, games
|
|
}
|
|
|
|
func (w *WatIntegration) HandleIntegration(m *irc.Message, msgargs []string) bool {
|
|
isBot, games := w.Bot(m)
|
|
if isBot {
|
|
// handles a message "Top finishers: (nick1: 1300) (nick2: 1200)" from an authorized Jeopardy game bot
|
|
if msgargs[0] == "Top" && msgargs[1] == "finishers:" && w.bot.Allowed("jeopardy", games) {
|
|
w.Jeopardy(m, msgargs)
|
|
return true
|
|
}
|
|
}
|
|
// not an authorized bot or no integration matched the given message
|
|
return false
|
|
}
|
|
|
|
func (w *WatIntegration) Jeopardy(m *irc.Message, msgargs []string) {
|
|
// hey, I avoided regex!
|
|
// 1. Starts parsing an array of message arguments containing "Top finishers: (nick1: 1000) (nick2: 2000)", where
|
|
// the "($nick: $value)" pairs can contain arbitrary nicknames + integer values and can repeat one to any amount of times
|
|
// 2. Join the array on spaces to a string, but skip the first two elements to remove "Top" and "finishers:"
|
|
// 3. Replace ") (" in the string with ";" - the semicolon is chosen as a temporary delimiter because it does not conflict with any other characters in the message
|
|
// 4. Replace ": " in the string with ":"
|
|
// 5. Replace "(" in the string with "" (relevant for the first nick/value pair)
|
|
// 6. Replace ")" in the string with "" (relevant for the last nick/value pair)
|
|
// 7. Now, we have a string like "nick1:1000;nick2:2000" - split it back into an array on ";"
|
|
// 8. The result is an array like "[nick1:1000, nick2:2000]"
|
|
finisherPrizes := strings.Split(strings.Replace(strings.Replace(strings.Replace(strings.Replace(strings.Join(msgargs[2:], " "), ") (", ";", -1), ": ", ":", -1), "(", "", 1), ")", "", 1), ";")
|
|
fmt.Printf("Processing Jeopardy: %s\n", finisherPrizes)
|
|
var msg string
|
|
var many bool
|
|
fiprcount := len(finisherPrizes)
|
|
cashoutcount := 0
|
|
// only a single winner
|
|
if fiprcount == 1 {
|
|
msg = "smartass %s :) gave u %d"
|
|
many = false
|
|
// multiple winners
|
|
} else if fiprcount > 1 {
|
|
msg = "gang of smartasses :) gave %s %d"
|
|
many = true
|
|
// no winners (should never get here)
|
|
} else {
|
|
fmt.Printf("Empty finishers, aborting Jeopardy processing")
|
|
return
|
|
}
|
|
// iterate over the "$nick:$value" string elements
|
|
for _, pair := range finisherPrizes {
|
|
// turn the string element into an array, where the first entry is the nickname, and the second the value
|
|
nameCoinPair := strings.Split(pair, ":")
|
|
coins, err := strconv.ParseUint(nameCoinPair[1], 10, 64)
|
|
if err != nil {
|
|
fmt.Printf("Invalid coins, cannot process pair for cashout: %s.\n", nameCoinPair)
|
|
continue
|
|
}
|
|
name := nameCoinPair[0]
|
|
// Jeopardy prizes are quite a lot of $$$, make it a bit more sane
|
|
coins = coins / 40
|
|
if coins == 0 {
|
|
continue
|
|
}
|
|
cashoutcount += 1
|
|
// name = we assume the Jeopardy player name to match a Watbot player name
|
|
// host = we could use some WHO logic to find the host, but assuming nickname lookup to be sufficient here
|
|
// create = based on the above, maybe rather not create Watbot players based on only a nick?
|
|
// but it expects someone to have played with Watbot before to be eligible for Jeopardy cashout ..
|
|
player := w.db.User(name, "", false)
|
|
if player.Nick == "" {
|
|
fmt.Printf("Player %s does not exist in Watbot, skipping cashout.\n", name)
|
|
continue
|
|
}
|
|
// fill previous format placeholders
|
|
msg = fmt.Sprintf(msg, player.Nick, coins)
|
|
if many {
|
|
// append additional ones for filling in the next loop iteration
|
|
msg = msg + ", %s %d"
|
|
}
|
|
player.Coins += coins
|
|
w.db.Update(player)
|
|
}
|
|
if many {
|
|
// remove format placeholders from last loop iteration
|
|
msg = strings.Replace(msg, ", %s %d", ".", 1)
|
|
}
|
|
if cashoutcount > 0 {
|
|
w.bot.reply(m, msg)
|
|
}
|
|
}
|