2017-09-29 04:58:21 +00:00
|
|
|
// © 2016 the CatBase Authors under the WTFPL license. See AUTHORS for the list of authors.
|
|
|
|
|
|
|
|
// Package inventory contains the plugin that allows the bot to pad messages
|
|
|
|
// See the bucket RFC inventory: http://wiki.xkcd.com/irc/Bucket_inventory
|
|
|
|
package inventory
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
|
2019-03-07 16:35:42 +00:00
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
|
2017-09-29 04:58:21 +00:00
|
|
|
"github.com/jmoiron/sqlx"
|
|
|
|
"github.com/velour/catbase/bot"
|
|
|
|
"github.com/velour/catbase/bot/msg"
|
|
|
|
"github.com/velour/catbase/config"
|
|
|
|
)
|
|
|
|
|
|
|
|
type InventoryPlugin struct {
|
|
|
|
*sqlx.DB
|
2021-02-05 16:19:39 +00:00
|
|
|
bot bot.Bot
|
|
|
|
config *config.Config
|
|
|
|
handlers bot.HandlerTable
|
2017-09-29 04:58:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// New creates a new InventoryPlugin with the Plugin interface
|
2019-02-05 19:41:38 +00:00
|
|
|
func New(b bot.Bot) *InventoryPlugin {
|
|
|
|
config := b.Config()
|
2017-09-29 04:58:21 +00:00
|
|
|
|
2019-02-05 19:41:38 +00:00
|
|
|
p := &InventoryPlugin{
|
|
|
|
DB: b.DB(),
|
|
|
|
bot: b,
|
2017-09-29 04:58:21 +00:00
|
|
|
config: config,
|
|
|
|
}
|
|
|
|
|
2019-02-05 19:41:38 +00:00
|
|
|
b.RegisterFilter("$item", p.itemFilter)
|
|
|
|
b.RegisterFilter("$giveitem", p.giveItemFilter)
|
2017-09-29 04:58:21 +00:00
|
|
|
|
2021-02-05 16:19:39 +00:00
|
|
|
p.DB.MustExec(`create table if not exists inventory (
|
2017-09-29 04:58:21 +00:00
|
|
|
item string primary key
|
|
|
|
);`)
|
|
|
|
|
2021-02-05 16:19:39 +00:00
|
|
|
p.register()
|
2019-02-05 19:41:38 +00:00
|
|
|
|
|
|
|
return p
|
2017-09-29 04:58:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *InventoryPlugin) giveItemFilter(input string) string {
|
|
|
|
for strings.Contains(input, "$giveitem") {
|
|
|
|
item := p.random()
|
|
|
|
input = strings.Replace(input, "$giveitem", item, 1)
|
|
|
|
p.remove(item)
|
|
|
|
}
|
|
|
|
return input
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *InventoryPlugin) itemFilter(input string) string {
|
|
|
|
for strings.Contains(input, "$item") {
|
|
|
|
input = strings.Replace(input, "$item", p.random(), 1)
|
|
|
|
}
|
|
|
|
return input
|
|
|
|
}
|
|
|
|
|
2021-02-05 16:19:39 +00:00
|
|
|
func (p *InventoryPlugin) register() {
|
|
|
|
nick := p.config.Get("nick", "bot")
|
|
|
|
|
|
|
|
p.handlers = append(p.handlers, bot.HandlerSpec{Kind: bot.Message, IsCmd: true,
|
|
|
|
Regex: regexp.MustCompile(`inventory`),
|
|
|
|
Handler: func(r bot.Request) bool {
|
2017-09-29 04:58:21 +00:00
|
|
|
items := p.getAll()
|
|
|
|
say := "I'm not holding anything"
|
|
|
|
if len(items) > 0 {
|
2019-03-07 16:35:42 +00:00
|
|
|
log.Debug().Msgf("I think I have more than 0 items: %+v, len(items)=%d", items, len(items))
|
2017-09-29 04:58:21 +00:00
|
|
|
say = fmt.Sprintf("I'm currently holding %s", strings.Join(items, ", "))
|
|
|
|
}
|
2021-02-05 16:19:39 +00:00
|
|
|
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, say)
|
2017-09-29 04:58:21 +00:00
|
|
|
return true
|
2021-02-05 16:19:39 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
h := func(r bot.Request) bool {
|
|
|
|
log.Debug().Msgf("Adding item: %s", r.Values["item"])
|
|
|
|
return p.addItem(r.Conn, r.Msg, r.Values["item"])
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, r := range []*regexp.Regexp{
|
|
|
|
regexp.MustCompile(`(?i)^take this (?P<item>.+)$`),
|
|
|
|
regexp.MustCompile(`(?i)^have a (?P<item>.+)$`),
|
|
|
|
} {
|
|
|
|
p.handlers = append(p.handlers, bot.HandlerSpec{Kind: bot.Message, IsCmd: false,
|
|
|
|
Regex: r,
|
|
|
|
Handler: h})
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, r := range []*regexp.Regexp{
|
|
|
|
regexp.MustCompile(fmt.Sprintf(`(?i)^puts (?P<item>\S+) in %s$`, nick)),
|
|
|
|
regexp.MustCompile(fmt.Sprintf("(?i)^gives %s (?P<item>.+)$", nick)),
|
|
|
|
regexp.MustCompile(fmt.Sprintf(`(?i)^gives (?P<item>\S+) to %s$`, nick)),
|
|
|
|
} {
|
|
|
|
p.handlers = append(p.handlers, bot.HandlerSpec{Kind: bot.Action, IsCmd: false,
|
|
|
|
Regex: r,
|
|
|
|
Handler: h})
|
|
|
|
}
|
|
|
|
|
|
|
|
p.bot.RegisterTable(p, p.handlers)
|
2017-09-29 04:58:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *InventoryPlugin) removeRandom() string {
|
|
|
|
var name string
|
|
|
|
err := p.QueryRow(`select item from inventory order by random() limit 1`).Scan(
|
|
|
|
&name,
|
|
|
|
)
|
|
|
|
if err != nil {
|
2019-03-07 16:35:42 +00:00
|
|
|
log.Error().Err(err).Msgf("Error finding random entry")
|
2017-09-29 04:58:21 +00:00
|
|
|
return "IAMERROR"
|
|
|
|
}
|
|
|
|
_, err = p.Exec(`delete from inventory where item=?`, name)
|
|
|
|
if err != nil {
|
2019-03-07 16:35:42 +00:00
|
|
|
log.Error().Err(err).Msgf("Error finding random entry")
|
2017-09-29 04:58:21 +00:00
|
|
|
return "IAMERROR"
|
|
|
|
}
|
|
|
|
return name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *InventoryPlugin) count() int {
|
|
|
|
var output int
|
|
|
|
err := p.QueryRow(`select count(*) as count from inventory`).Scan(&output)
|
|
|
|
if err != nil {
|
2019-03-07 16:35:42 +00:00
|
|
|
log.Error().Err(err).Msg("Error checking for item")
|
2017-09-29 04:58:21 +00:00
|
|
|
return -1
|
|
|
|
}
|
|
|
|
return output
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *InventoryPlugin) random() string {
|
|
|
|
var name string
|
|
|
|
err := p.QueryRow(`select item from inventory order by random() limit 1`).Scan(
|
|
|
|
&name,
|
|
|
|
)
|
|
|
|
if err != nil {
|
2019-03-07 16:35:42 +00:00
|
|
|
log.Error().Err(err).Msg("Error finding random entry")
|
2017-09-29 04:58:21 +00:00
|
|
|
return "IAMERROR"
|
|
|
|
}
|
|
|
|
return name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *InventoryPlugin) getAll() []string {
|
|
|
|
rows, err := p.Queryx(`select item from inventory`)
|
|
|
|
if err != nil {
|
2019-03-07 16:35:42 +00:00
|
|
|
log.Error().Err(err).Msg("Error getting all items")
|
2017-09-29 04:58:21 +00:00
|
|
|
return []string{}
|
|
|
|
}
|
|
|
|
output := []string{}
|
|
|
|
for rows.Next() {
|
|
|
|
var item string
|
|
|
|
rows.Scan(&item)
|
|
|
|
output = append(output, item)
|
|
|
|
}
|
|
|
|
rows.Close()
|
|
|
|
return output
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *InventoryPlugin) exists(i string) bool {
|
|
|
|
var output int
|
|
|
|
err := p.QueryRow(`select count(*) as count from inventory where item=?`, i).Scan(&output)
|
|
|
|
if err != nil {
|
2019-03-07 16:35:42 +00:00
|
|
|
log.Error().Err(err).Msg("Error checking for item")
|
2017-09-29 04:58:21 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
return output > 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *InventoryPlugin) remove(i string) {
|
|
|
|
_, err := p.Exec(`delete from inventory where item=?`, i)
|
|
|
|
if err != nil {
|
2019-03-07 16:35:42 +00:00
|
|
|
log.Error().Msg("Error inserting new inventory item")
|
2017-09-29 04:58:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-27 23:21:53 +00:00
|
|
|
func (p *InventoryPlugin) addItem(c bot.Connector, m msg.Message, i string) bool {
|
2017-09-29 04:58:21 +00:00
|
|
|
if p.exists(i) {
|
2019-05-27 23:21:53 +00:00
|
|
|
p.bot.Send(c, bot.Message, m.Channel, fmt.Sprintf("I already have %s.", i))
|
2017-09-29 04:58:21 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
var removed string
|
2019-01-22 00:16:57 +00:00
|
|
|
max := p.config.GetInt("inventory.max", 10)
|
2019-01-21 19:24:03 +00:00
|
|
|
if p.count() > max {
|
2017-09-29 04:58:21 +00:00
|
|
|
removed = p.removeRandom()
|
|
|
|
}
|
|
|
|
_, err := p.Exec(`INSERT INTO inventory (item) values (?)`, i)
|
|
|
|
if err != nil {
|
2019-03-07 16:35:42 +00:00
|
|
|
log.Error().Err(err).Msg("Error inserting new inventory item")
|
2017-09-29 04:58:21 +00:00
|
|
|
}
|
|
|
|
if removed != "" {
|
2019-05-27 23:21:53 +00:00
|
|
|
p.bot.Send(c, bot.Action, m.Channel, fmt.Sprintf("dropped %s and took %s from %s", removed, i, m.User.Name))
|
2017-09-29 04:58:21 +00:00
|
|
|
} else {
|
2019-05-27 23:21:53 +00:00
|
|
|
p.bot.Send(c, bot.Action, m.Channel, fmt.Sprintf("takes %s from %s", i, m.User.Name))
|
2017-09-29 04:58:21 +00:00
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|