summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoralex2018-10-21 12:57:23 +0100
committeralex2018-10-21 13:04:35 +0100
commit61b84d9fd997d61f4e5bb6adc63a2310036a242e (patch)
treee15d066c7ac3ea61785018b37da8dcaae26c03e5
parent55bc749f896c25adb57125fd168a1e3ccfc0cd48 (diff)
downloadwatbot-61b84d9fd997d61f4e5bb6adc63a2310036a242e.tar.gz
watbot-61b84d9fd997d61f4e5bb6adc63a2310036a242e.tar.bz2
watbot-61b84d9fd997d61f4e5bb6adc63a2310036a242e.zip
Reimplemented python bot in golang, skipped a few features
-rwxr-xr-xcount2
-rw-r--r--main.go23
-rw-r--r--osrc/watbot_db.py2
-rw-r--r--wat/bot.go90
-rw-r--r--wat/db.go94
-rw-r--r--wat/game.go298
6 files changed, 500 insertions, 9 deletions
diff --git a/count b/count
new file mode 100755
index 0000000..5955d4b
--- /dev/null
+++ b/count
@@ -0,0 +1,2 @@
+wc -l osrc/watbot_*.py
+wc -l *.go wat/*.go
diff --git a/main.go b/main.go
index e9cb530..dd7ec6f 100644
--- a/main.go
+++ b/main.go
@@ -2,21 +2,28 @@ package main
import "fmt"
import "github.com/go-irc/irc"
-import flag"github.com/namsral/flag"
+import "github.com/namsral/flag"
+import "crypto/tls"
-func testHandler(c *irc.Client, m *irc.Message) {
- fmt.Println("Client: %+v", c)
-}
+import "git.circuitco.de/self/watbot/wat"
func main() {
pass := flag.String("pass", "", "password")
flag.Parse()
config := irc.ClientConfig {
- Nick: "wat",
+ Nick: "watt",
Pass: *pass,
- User: "wat",
+ User: "wat/tripsit",
Name: "wat",
- Handler: irc.HandlerFunc(testHandler),
}
- fmt.Printf("Hello world %+v\n", config)
+ tcpConf := &tls.Config{
+ InsecureSkipVerify: true,
+ }
+ conn, err := tls.Dial("tcp", "127.0.0.1:9696", tcpConf)
+ if err != nil {
+ fmt.Println("err " + err.Error())
+ return
+ }
+ wwat := wat.NewWatBot(&config, conn)
+ wwat.Run()
}
diff --git a/osrc/watbot_db.py b/osrc/watbot_db.py
index 6759c3b..837eaf9 100644
--- a/osrc/watbot_db.py
+++ b/osrc/watbot_db.py
@@ -31,7 +31,7 @@ class WatbotDB:
" timestamp integer,"
" balance integer,"
" log text,"
- " foreign key(nickname) references coins(nickname)"
+ " foreign key(nickname) references players(nickname)"
")"
)
diff --git a/wat/bot.go b/wat/bot.go
new file mode 100644
index 0000000..170f77e
--- /dev/null
+++ b/wat/bot.go
@@ -0,0 +1,90 @@
+package wat
+
+import (
+ "github.com/go-irc/irc"
+ "crypto/tls"
+ "fmt"
+ "strings"
+)
+
+type WatBot struct {
+ client *irc.Client
+ conn *tls.Conn
+ game *WatGame
+ Db *WatDb
+ Nick string
+}
+
+func NewWatBot(config *irc.ClientConfig, serverConn *tls.Conn) *WatBot {
+ wat := WatBot{conn:serverConn, Nick:config.Nick}
+ wat.Db = NewWatDb()
+ wat.game = NewWatGame(&wat, wat.Db)
+ config.Handler = irc.HandlerFunc(wat.HandleIrcMsg)
+ wat.client = irc.NewClient(wat.conn, *config)
+ return &wat
+}
+
+func CleanNick(nick string) string {
+ return string(nick[0])+"\u200c"+nick[1:]
+}
+
+func (w *WatBot) HandleIrcMsg(c *irc.Client, m *irc.Message) {
+ fmt.Println(m)
+ switch cmd := m.Command; cmd {
+ case "PING":
+ w.write("PONG", m.Params[0])
+ case "PRIVMSG":
+ w.Msg(m)
+ }
+}
+
+func (w *WatBot) Msg(m *irc.Message) {
+ if m.Params[0] == w.Nick && m.Prefix.Host == "tripsit/operator/hibs" {
+ if "join" == m.Params[1] {
+ w.write("JOIN", "##wat")
+ }
+ }
+ if strings.Contains(m.Prefix.Host, "tripsit") && m.Params[0] == "##wat" {
+ args := strings.FieldsFunc(m.Params[1], func(c rune) bool {return c == ' '})
+ if len(args) < 1 && args[0] != "wat" && args[0][0] != '#' {
+ return
+ }
+ if args[0][0] == '#' {
+ args[0] = args[0][1:]
+ }
+ user := strings.ToLower(m.Prefix.Name)
+ player := w.Db.User(user, m.Prefix.Host, true)
+ w.game.Msg(m, &player, args)
+ }
+}
+
+func (w *WatBot) Run() {
+ defer w.conn.Close()
+ err := w.client.Run()
+ if err != nil {
+ fmt.Println(err.Error())
+ }
+}
+
+func (w *WatBot) say(dest, msg string) {
+ if len(msg) == 0 {
+ return
+ }
+ fmt.Printf("MSG %s: %s\n", dest, msg)
+ w.write("PRIVMSG", dest, msg)
+}
+
+func (w *WatBot) reply(s *irc.Message, r string) {
+ sender := s.Params[0]
+ if sender == w.Nick {
+ sender = s.Prefix.Name
+ }
+ w.say(sender, r)
+}
+
+func (w *WatBot) write(cmd string, params ...string) {
+ w.client.WriteMessage(&irc.Message{
+ Command: cmd,
+ Params: params,
+ })
+}
diff --git a/wat/db.go b/wat/db.go
new file mode 100644
index 0000000..81f111b
--- /dev/null
+++ b/wat/db.go
@@ -0,0 +1,94 @@
+package wat
+
+import (
+ "time"
+ "github.com/jinzhu/gorm"
+ _"github.com/jinzhu/gorm/dialects/sqlite"
+)
+import "fmt"
+
+type Player struct {
+ gorm.Model
+ Nick string
+ Host string
+ Watting int64
+ Anarchy int64
+ Trickery int64
+ Coins int64
+ Health int64
+ LastMined int64
+ LastRested int64
+}
+
+func (p *Player) Conscious() bool {
+ return true
+}
+
+func (p *Player) Level(xp int64) int64 {
+ if xp < 100 {
+ return xp/10
+ } else if xp < 900 {
+ return 10 + (xp/100)
+ } else {
+ return 99
+ }
+}
+
+type Ledger struct {
+ PlayerId uint `gorm:"primary_key"`
+ Time int64
+ Balance int64
+ Log string
+}
+
+type Item struct {
+ PlayerId uint
+ Name string `gorm:"primary_key"`
+ Price int64
+}
+
+type PlayerItem struct {
+ PlayerId uint
+ ItemId int
+ Count int
+}
+
+type WatDb struct {
+ db *gorm.DB
+}
+
+func NewWatDb() *WatDb {
+ w := WatDb{}
+ var err error
+ w.db, err = gorm.Open("sqlite3", "wat.db")
+ if err != nil {
+ panic(err)
+ }
+ w.db.AutoMigrate(&Player{}, &Ledger{}, &Item{}, &PlayerItem{})
+ return &w
+}
+
+func (w *WatDb) User(nick, host string, create bool) Player {
+ var player Player
+ // Try and get a user
+ if err := w.db.First(&player, "nick = ? or host = ?", nick, host).Error; err != nil && create {
+ fmt.Printf("Creating user: %s\n", err.Error())
+ // No user, make another
+ player.Nick = nick
+ player.Host = host
+ w.db.Create(&player)
+ w.db.First(&player, "nick = ? or host = ?", nick, host)
+ w.db.Create(&Ledger{player.Model.ID, time.Now().Unix(), 0, "creation"})
+ }
+ return player
+}
+
+func (w *WatDb) Update(upd interface{}) {
+ w.db.Save(upd)
+}
+
+func (w *WatDb) TopTen() []Player {
+ var user = make([]Player, 10)
+ w.db.Limit(10).Find(&user)
+ return user
+}
diff --git a/wat/game.go b/wat/game.go
new file mode 100644
index 0000000..306bb93
--- /dev/null
+++ b/wat/game.go
@@ -0,0 +1,298 @@
+package wat
+
+import (
+ "fmt"
+ "time"
+ "strings"
+ "strconv"
+ "math/rand"
+ "github.com/go-irc/irc"
+)
+
+type WatGame struct {
+ bot *WatBot
+ db *WatDb
+}
+
+func NewWatGame(bot *WatBot, db *WatDb) *WatGame {
+ return &WatGame{bot, db}
+}
+
+var currency = "watcoin"
+var currencys = "watcoins"
+var unconscious = "wat, you're too weak for that."
+var helpText = fmt.Sprintf("balance <nick>, watch <nick>, inventory <nick>, topten, mine, send <nick> <%s>, roll <%s>, steal <nick> <%s>, frame <nick> <%s>, punch <nick>", currency, currency, currency, currency)
+var rules = "A new account is created with 5 hours time credit. Mining exchanges time credit for %s: 1-10h: 1 p/h; >10h: 10 p/h; >1 day: 50 p/h; >1 month: 1000 p/h."
+// missing
+// invent, create, give inventory
+
+func (g *WatGame) Msg(m *irc.Message, player *Player, fields []string) {
+ reply := ""
+ switch strings.ToLower(fields[0]) {
+ case "wat":
+ reply = g.megaWat(player)
+ case "rules":
+ reply = rules
+ case "watch":
+ reply = fmt.Sprintf("Watting: %d (%d) / Anarchy: %d (%d) / Trickery: %d (%d) / Coins %d Health: %d", player.Level(player.Watting), player.Watting, player.Level(player.Anarchy), player.Anarchy, player.Trickery, player.Trickery, player.Coins, player.Health)
+ case "help":
+ reply = helpText
+ case "topten":
+ reply = fmt.Sprintf("%s holders: %s", currency, g.TopTen())
+ case "balance":
+ reply = g.Balance(player, fields)
+ case "mine":
+ reply = g.Mine(player)
+ case "send":
+ reply = g.Send(player, fields)
+ }
+ if reply == "" {
+ // Nothing was handled. Maybe this is an action that requires consciousness.
+ if !player.Conscious() {
+ reply = unconscious
+ } else {
+ reply = g.WokeMsg(m, player, fields)
+ }
+ }
+ g.bot.reply(m, reply)
+}
+
+func (g *WatGame) WokeMsg(m *irc.Message, player *Player, fields []string) string {
+ reply := ""
+ switch strings.ToLower(fields[0]) {
+ case "steal":
+ reply = g.Steal(player, fields)
+ case "frame":
+ reply = g.Frame(player, fields)
+ case "punch":
+ reply = g.Punch(player, fields)
+ case "roll":
+ reply = g.Roll(player, fields)
+ }
+ return reply
+}
+
+func (g *WatGame) Roll(player *Player, fields []string) string {
+ if len(fields) < 2 {
+ return fmt.Sprintf("roll <%s> pls", currency)
+ }
+ amount, e := strconv.ParseInt(fields[1], 10, 64)
+ if e != nil {
+ return "wat kinda numba is that"
+ }
+ if amount > player.Coins {
+ return "wat? brokeass"
+ }
+ n := rand.Int63n(100)+1
+ ret := fmt.Sprintf("%s rolls a d100 (<50 wins): It's a %d! ", player.Nick, n)
+ if n < 50 {
+ player.Coins -= amount
+ ret += fmt.Sprintf("You win! Your new balance is %d", player.Coins)
+ } else {
+ player.Coins -= amount
+ ret += fmt.Sprintf("You lose! Your new balance is %d", player.Coins)
+ }
+ g.db.Update(player)
+ return ret
+}
+
+func (g *WatGame) Punch(player *Player, fields []string) string {
+ if len(fields) < 2 {
+ return "punch <target> pls"
+ }
+ target, err := g.GetTarget(player.Nick, fields[1])
+ if err != "" {
+ return err
+ }
+ chance := rand.Int63n(6)+1
+ dmg := rand.Int63n(6)+1
+ ret := fmt.Sprintf("%s rolls a d6 to punch %s: It's a %d! %s ", player.Nick, target.Nick, chance, player.Nick)
+ if chance <3 {
+ dmg += player.Anarchy
+ ret += fmt.Sprintf("hits for %d points of damage!", dmg)
+ target.Health -= dmg
+ g.db.Update(target)
+ } else {
+ dmg += target.Anarchy
+ ret += fmt.Sprintf("misses miserably! %s punches back for %d damage! ", target.Nick, dmg)
+ player.Health -= dmg
+ if player.Health <= 0 {
+ ret += player.Nick + " has fallen unconscious."
+ }
+ g.db.Update(player)
+ }
+ return ret
+}
+
+func (g *WatGame) Frame(player *Player, fields []string) string {
+ if len(fields) < 3 {
+ return fmt.Sprintf("frame <nick> <%s> - d6 roll. If < 3, you force the target to pay me. Otherwise, you pay a fine to the target and myself.", currency)
+ }
+ amount, e := strconv.ParseInt(fields[2], 10, 64)
+ if amount <= 0 || e != nil {
+ return "wat kinda number is "+fields[2]+"?"
+ }
+ if player.Coins < amount {
+ return "wat? you too poor for that."
+ }
+ target, err := g.GetTarget(player.Nick, fields[1])
+ if err != "" {
+ return err
+ }
+ if target.Coins < amount {
+ return fmt.Sprintf("wat? %s is too poor for this.", target.Nick)
+ }
+ n := rand.Int63n(6)+1
+ ret := fmt.Sprintf("%s rolls a d6 to frame %s with %d %s: It's a %d! (<3 wins). ", player.Nick, target.Nick, amount, currency, n)
+ if n < 3 {
+ ret += fmt.Sprintf("You win! They pay me %d.", amount)
+ player.Anarchy += 1
+ target.Coins -= amount
+ // bot gets coins
+ } else {
+ ret += fmt.Sprintf("You were caught and pay them %d, throwing away the rest.", (amount/2))
+ player.Coins -= amount
+ target.Coins += amount/2
+// target.Coins += amount/2
+ }
+ g.db.Update(player)
+ g.db.Update(target)
+ return ret
+}
+
+func (g *WatGame) Steal(player *Player, fields []string) string {
+ if len(fields) < 3 {
+ return fmt.Sprintf("steal <nick> <%s> - d6 roll. If < 3, you steal the %s. Otherwise, you pay double the %s to %s", currency, currency, currency, g.bot.Nick)
+ }
+ amount, e := strconv.ParseInt(fields[2], 10, 64)
+ if amount <= 0 || e != nil {
+ return "wat kinda number is "+fields[2]+"?"
+ }
+ if player.Coins < amount*2 {
+ return "wat? You'd go bankrupt if they steal back..."
+ }
+ target, err := g.GetTarget(player.Nick, fields[1])
+ if target == nil {
+ return err
+ }
+ if target.Coins < amount {
+// return fmt.Sprintf("wat? %s is a poor fuck and doesn't have that much to steal.", target.Nick)
+ }
+ n := rand.Int63n(6)+1
+ ret := fmt.Sprintf("%s rolls a d6 to steal %d %s from %s... It's %d! (<3 wins) ", player.Nick, amount, currency, target.Nick, n)
+ if n < 3 {
+ ret += "You win! Sneaky bastard!"
+ player.Coins += amount
+ player.Anarchy += 1
+ target.Coins -= amount
+ g.db.Update(target)
+ } else {
+ ret += fmt.Sprintf("You were caught and I took %d %s from your pocket.", (amount*2), currency)
+ player.Coins -= amount*2
+ }
+ g.db.Update(player)
+ return ret
+}
+
+func (g *WatGame) GetTarget(player, target string) (*Player, string) {
+ t := g.db.User(target, "", false)
+ if t.Nick == "" {
+ return nil, "Who?"
+ }
+ if t.Nick == player {
+ return nil, "You can't do that to yourself, dummy."
+ }
+ return &t, ""
+}
+
+func (g *WatGame) Send(player *Player, fields []string) string {
+ if len(fields) < 3 {
+ return fmt.Sprintf("You forgot somethin'. send <nick> <%s>", currency)
+ }
+ amount, err := strconv.Atoi(fields[2])
+ if err != nil {
+ return fields[2] + " is not an integer, wat?"
+ }
+ if int64(amount) > player.Coins {
+ return "wat? you poor fuck, you don't have enough!"
+ }
+ target, str := g.GetTarget(player.Nick, fields[1])
+ if target == nil {
+ return str
+ }
+ player.Coins -= int64(amount)
+ target.Coins += int64(amount)
+ g.db.Update(player)
+ g.db.Update(target)
+ return fmt.Sprintf("%s sent %s %d %s", player.Nick, target.Nick, amount, currency)
+}
+
+func (g *WatGame) Mine(player *Player) string {
+ delta := time.Now().Unix() - player.LastMined
+ if delta < 1800 {
+ return fmt.Sprintf("wat? 2 soon (%d)", delta)
+ }
+ value := int64(0)
+ if delta < 36000 {
+ value = delta/1800
+ } else if delta < 86400 {
+ value = 10
+ } else if delta < 2592000 {
+ value = 50
+ } else {
+ value = 1000
+ }
+ msg := ""
+ if player.LastMined == 0 {
+ msg = "with wat? you go to get a pickaxe"
+ value = 0
+ } else {
+ msg = fmt.Sprintf("%s mined %d %s for %d and has %d %s", player.Nick, value, currency, delta, player.Coins, currency)
+ }
+ player.Coins += value
+ player.LastMined = time.Now().Unix()
+ g.db.Update(player)
+ return msg
+}
+
+func (g *WatGame) Balance(player *Player, fields []string) string {
+ balStr := "%s's %s balance: %d. Mining time credit: %d."
+ balPlayer := *player
+ if len(fields) > 1 {
+ balPlayer = g.db.User(fields[1], "", false)
+ if balPlayer.Nick == "" {
+ return "Who?"
+ }
+ }
+ return fmt.Sprintf(balStr, balPlayer.Nick, currency, balPlayer.Coins, balPlayer.LastMined)
+}
+
+func (g *WatGame) TopTen() string {
+ players := g.db.TopTen()
+ ret := ""
+ for _, p := range players {
+ ret += PrintTwo(p.Nick, p.Coins)
+ }
+ return ret
+}
+
+func PrintTwo(nick string, value int64) string {
+ return fmt.Sprintf("%s (%d) ", CleanNick(nick), value)
+}
+
+func (g *WatGame) megaWat(player *Player) string {
+ mega := rand.Int63n(1000000)+1
+ kilo := rand.Int63n(1000)+1
+ reply := ""
+ if mega == 23 {
+ player.Coins += 1000000
+ reply = fmt.Sprintf("OMGWATWATWAT!!!! %s has won the MegaWat lottery and gains 1000000 %s!", player.Nick, currency)
+ }
+ if kilo == 5 {
+ player.Coins += 1000
+ reply = fmt.Sprintf("OMGWAT! %s has won the KiloWat lottery and gains 1000 %s!", player.Nick, currency)
+ }
+ player.Watting += 1
+ g.db.Update(player)
+ return reply
+}