capture the flag style plugin

This commit is contained in:
skkiesel 2017-11-06 21:01:31 -05:00
parent 5c1b1abbf1
commit 05fe7d5ecd
2 changed files with 308 additions and 0 deletions

View File

@ -12,6 +12,7 @@ import (
"github.com/velour/catbase/plugins/admin"
"github.com/velour/catbase/plugins/babbler"
"github.com/velour/catbase/plugins/beers"
"github.com/velour/catbase/plugins/capturetheflag"
"github.com/velour/catbase/plugins/counter"
"github.com/velour/catbase/plugins/dice"
"github.com/velour/catbase/plugins/emojifyme"
@ -69,6 +70,7 @@ func main() {
b.AddHandler("emojifyme", emojifyme.New(b))
b.AddHandler("twitch", twitch.New(b))
b.AddHandler("inventory", inventory.New(b))
b.AddHandler("capturetheflag", capturetheflag.New(b))
// catches anything left, will always return true
b.AddHandler("factoid", fact.New(b))

View File

@ -0,0 +1,306 @@
package capturetheflag
import (
"database/sql"
"fmt"
"log"
"math/rand"
"strings"
"time"
"github.com/jmoiron/sqlx"
"github.com/velour/catbase/bot"
"github.com/velour/catbase/bot/msg"
)
const (
TIMESTAMP = "2006-01-02 15:04:05"
)
type CaptureTheFlagPlugin struct {
Bot bot.Bot
db *sqlx.DB
}
type User struct {
UserId int64 `db:"id"`
UserName string `db:"user"`
}
type Flag struct {
FlagId int64 `db:"id"`
FlagName string `db:"flag"`
}
type Possession struct {
PossessionId int64 `db:"id"`
UserId int64 `db:"user"`
FlagId int64 `db:"flag"`
Active bool `db:"active"`
LastGrab int64 `db:"lastgrab"`
PossessionDuration int64 `db:"duration"`
}
// NewDicePlugin creates a new DicePlugin with the Plugin interface
func New(bot bot.Bot) *CaptureTheFlagPlugin {
rand.Seed(time.Now().Unix())
if _, err := bot.DB().Exec(`create table if not exists ctf_user (
id integer primary key,
user string
);`); err != nil {
log.Fatal(err)
}
if _, err := bot.DB().Exec(`create table if not exists ctf_flag (
id integer primary key,
flag string
);`); err != nil {
log.Fatal(err)
}
if _, err := bot.DB().Exec(`create table if not exists ctf_possession (
id integer primary key,
user integer,
flag integer,
active integer,
lastgrab integer,
duration integer
);`); err != nil {
log.Fatal(err)
}
return &CaptureTheFlagPlugin{
Bot: bot,
db: bot.DB(),
}
}
func (p *CaptureTheFlagPlugin) Message(message msg.Message) bool {
lowercase := strings.ToLower(message.Body)
tokens := strings.Fields(lowercase)
numTokens := len(tokens)
log.Println(lowercase)
if numTokens >= 2 && tokens[0] == "capture" {
log.Printf("%s trying to capture %s.", message.User.Name, strings.Join(tokens[1:], " "))
response, err := p.tryCapture(message.User.Name, strings.Join(tokens[1:], " "))
if err == nil {
log.Print("Capture success.")
log.Print(response)
p.Bot.SendMessage(message.Channel, response)
return true
} else {
log.Print("Capture failed.")
}
}
return false
}
func (p *CaptureTheFlagPlugin) Help(channel string, parts []string) {
p.Bot.SendMessage(channel, "There are flags. Capture them.")
}
func (p *CaptureTheFlagPlugin) Event(kind string, message msg.Message) bool {
return false
}
func (p *CaptureTheFlagPlugin) BotMessage(message msg.Message) bool {
return false
}
func (p *CaptureTheFlagPlugin) RegisterWeb() *string {
return nil
}
func (p *CaptureTheFlagPlugin) createUser(username string) (*User, error) {
res, err := p.db.Exec(`insert into ctf_user (user) values (?);`, username)
if err != nil {
log.Print(err)
return nil, err
}
id, err := res.LastInsertId()
if err != nil {
log.Print(err)
return nil, err
}
return &User{
UserId: id,
UserName: username,
}, nil
}
func (p *CaptureTheFlagPlugin) getOrCreateUser(username string) (*User, bool, error) {
var usr User
err := p.db.QueryRowx(`select * from ctf_user where user = ? LIMIT 1;`, username).StructScan(&usr)
if err != nil {
if err == sql.ErrNoRows {
usrPtr, err := p.createUser(username)
return usrPtr, true, err
}
log.Print(err)
return nil, false, err
}
return &usr, false, nil
}
func (p *CaptureTheFlagPlugin) getUserById(id int64) (*User, error) {
var usr User
err := p.db.QueryRowx(`select * from ctf_user where id = ? LIMIT 1;`, id).StructScan(&usr)
if err != nil {
log.Print(err)
return nil, err
}
return &usr, nil
}
func (p *CaptureTheFlagPlugin) createFlag(flagName string) (*Flag, error) {
res, err := p.db.Exec(`insert into ctf_flag (flag) values (?);`, flagName)
if err != nil {
log.Print(err)
return nil, err
}
id, err := res.LastInsertId()
if err != nil {
log.Print(err)
return nil, err
}
return &Flag{
FlagId: id,
FlagName: flagName,
}, nil
}
func (p *CaptureTheFlagPlugin) getOrCreateFlag(flagName string) (*Flag, bool, error) {
var flag Flag
err := p.db.QueryRowx(`select * from ctf_flag where flag = ? LIMIT 1;`, flagName).StructScan(&flag)
if err != nil {
if err == sql.ErrNoRows {
flagPtr, err := p.createFlag(flagName)
return flagPtr, true, err
}
log.Print(err)
return nil, false, err
}
return &flag, false, nil
}
func (p *CaptureTheFlagPlugin) transferActivePossession(pos *Possession, usr *User, flag *Flag) (string, error) {
extraTime := time.Now().Unix() - pos.LastGrab
newTime := extraTime + pos.PossessionDuration
_, err := p.db.Exec(`update ctf_possession set active = 0, duration = ? where id = ?;`, newTime, pos.PossessionId)
if err != nil {
log.Print(err)
return "", err
}
last, err := p.getUserById(pos.UserId)
if err != nil {
log.Print(err)
return "Flag possession dropped! (failed db query)", err
}
myPos, err := p.getPossession(usr, flag)
if err != nil {
log.Print(err)
return "Flag possession dropped! (failed db query)", err
}
if myPos == nil {
err = p.createFirstPossession(usr, flag)
if err != nil {
log.Print(err)
return "Flag possession dropped! (failed db query)", err
}
} else {
_, err = p.db.Exec(`update ctf_possession set active = 1, lastgrab = ? where id = ?;`, time.Now().Unix(), myPos.PossessionId)
if err != nil {
log.Print(err)
return "Flag possession dropped! (failed db query)", err
}
}
return fmt.Sprintf("%s now has '%s'. %s had it last for %d seconds (total %d seconds).", usr.UserName, flag.FlagName, last.UserName, extraTime, newTime), nil
}
func (p *CaptureTheFlagPlugin) createFirstPossession(usr *User, flag *Flag) error {
_, err := p.db.Exec(`insert into ctf_possession (user, flag, active, lastgrab, duration) values (?, ?, ?, ?, ?);`, usr.UserId, flag.FlagId,
true, time.Now().Unix(), 0)
if err != nil {
log.Print(err)
}
return err
}
func (p *CaptureTheFlagPlugin) getActivePossession(flag *Flag) (*Possession, error) {
var pos Possession
err := p.db.QueryRowx(`select * from ctf_possession where active = 1 and flag = ? LIMIT 1;`, flag.FlagId).StructScan(&pos)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
log.Print(err)
return nil, err
}
return &pos, nil
}
func (p *CaptureTheFlagPlugin) getPossession(usr *User, flag *Flag) (*Possession, error) {
var pos Possession
err := p.db.QueryRowx(`select * from ctf_possession where user = ? and flag = ? LIMIT 1;`, usr.UserId, flag.FlagId).StructScan(&pos)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
log.Print(err)
return nil, err
}
return &pos, nil
}
func (p *CaptureTheFlagPlugin) tryCapture(username, what string) (string, error) {
usr, _, err := p.getOrCreateUser(username)
if err != nil {
log.Print(err)
return "", err
}
flag, newFlag, err := p.getOrCreateFlag(what)
if err != nil {
log.Print(err)
return "", err
}
if !newFlag {
pos, err := p.getActivePossession(flag)
if err != nil {
log.Print(err)
return "", err
}
if pos == nil {
err = p.createFirstPossession(usr, flag)
if err != nil {
log.Print(err)
return "", err
}
return fmt.Sprintf("You now have '%s'", what), nil
} else if pos.UserId == usr.UserId {
return fmt.Sprintf("You already have '%s'", what), nil
}
response, err := p.transferActivePossession(pos, usr, flag)
if err != nil {
log.Print(err)
return "", err
}
return response, nil
} else {
err = p.createFirstPossession(usr, flag)
if err != nil {
log.Print(err)
return "", err
}
return fmt.Sprintf("You now have '%s'", what), nil
}
}