package wat import ( "crypto/rand" "fmt" "math/big" "strconv" "strings" "time" "github.com/go-irc/irc" ) type WatGame struct { bot *WatBot db *WatDb me Player commands map[string](func(*Player, []string) string) aliases map[string](func(*Player, []string) string) lifeCommands map[string](func(*Player, []string) string) simpleCommands []string roid map[string]int } var currency = "watcoin" var currencys = "watcoins" var unconscious = "wat, your hands fumble and fail you. try resting, weakling." func NewWatGame(bot *WatBot, db *WatDb) *WatGame { g := WatGame{bot, db, Player{}, nil, nil, nil, nil, map[string]int{}} g.me = g.db.User(bot.Nick, "", true) g.commands = map[string](func(*Player, []string) string){ //"wat": g.megaWat, "steroid": g.Steroid, "watch": g.Watch, "coins": g.Balance, "send": g.Send, "rest": g.Rest, "leech": g.Leech, "roll": g.Roll, "dice": g.Dice, "mine": g.Mine, "bankrupt": g.Bankrupt, "heal": g.Heal, } g.aliases = map[string](func(*Player, []string) string){ "sleep": g.Rest, "flip": g.Roll, } g.lifeCommands = map[string](func(*Player, []string) string){ "riot": g.Riot, "bench": g.Bench, "steal": g.Steal, "frame": g.Frame, "punch": g.Punch, } g.simpleCommands = []string{ "ping", "strongest", "healthiest", "losers", "richest", "bankruptest", } return &g } func (g *WatGame) Msg(m *irc.Message, player *Player, fields []string) { command := strings.ToLower(fields[0]) reply := "" if g.commands[command] != nil { reply = g.commands[command](player, fields) } else if g.aliases[command] != nil { reply = g.aliases[command](player, fields) } else { // one liners switch strings.ToLower(command) { case "ping": reply = ",beef" case "help": reply = g.help() case "strongest": reply = fmt.Sprintf("stronk: %s", g.Strongest()) case "healthiest": reply = fmt.Sprintf("healthy: %s", g.Healthiest()) case "losers": reply = fmt.Sprintf("%s losers: %s", currency, g.TopLost()) case "richest": reply = fmt.Sprintf("%s holders: %s", currency, g.TopTen()) case "bankruptest": reply = fmt.Sprintf("times bankrupt: %s", g.Bankrupest()) case "source": reply = "https://git.circuitco.de/self/watbot" } } if g.lifeCommands[command] != nil { if !player.Conscious() { reply = unconscious } else { reply = g.lifeCommands[command](player, fields) } } g.bot.reply(m, reply) } func (g *WatGame) help() string { ret := "" for cmd, _ := range g.commands { if len(ret) > 0 { ret += ", " } ret += cmd } ret += strings.Join(g.simpleCommands, ", ") for cmd, _ := range g.lifeCommands { if len(ret) > 0 { ret += ", " } ret += cmd } return ret } func (g *WatGame) RandInt(max int64) uint64 { i, _ := rand.Int(rand.Reader, big.NewInt(max)) return i.Uint64() } func (g *WatGame) Heal(player *Player, fields []string) string { multiplier := int64(30) if len(fields) < 3 { return "#heal - sacrifice your money to me, peasant! i might heal someone!" } target, e := g.GetTarget("", fields[1]) if e != "" { return e } a, err := g.Int(fields[2]) if err != nil { return err.Error() } if a > player.Coins { return "u poor lol" } amount := int64(a) if amount < multiplier { return fmt.Sprintf("too cheap lol at least %d", multiplier) } target.Health += amount / multiplier player.Coins -= a if target.Nick == player.Nick { target.Coins -= a g.db.Update(target) } else { g.db.Update(target, player) } fmtStr := "%s throws %d on the dirt. %s picks it up and waves their hand across %s, healing them. %s now has %d health." return fmt.Sprintf(fmtStr, player.Nick, amount, g.bot.Nick, target.Nick, target.Nick, target.Health) } func (g *WatGame) Dice(player *Player, fields []string) string { roll := uint64(6) if len(fields) > 1 { i, e := g.Int(fields[1]) if e == nil { roll = i } } answer := g.RandInt(int64(roll)) + 1 return fmt.Sprintf("1d%d - %d", roll, answer) } type PositiveError struct{} type ParseIntError struct { original string } func (e PositiveError) Error() string { return "i don't do negative numbers lol" } func (e ParseIntError) Error() string { return fmt.Sprintf("wat kinda number is %s", e.original) } func (g *WatGame) Int(str string) (uint64, error) { i, e := strconv.ParseUint(str, 10, 64) if i < 0 { return 0, PositiveError{} } if e != nil { e = ParseIntError{str} } return i, e } func (g *WatGame) Roll(player *Player, fields []string) string { if len(fields) < 2 { return fmt.Sprintf("roll <%s> pls - u must score < 50 if u want 2 win. u can also pick the dice size", currency) } amount, e := g.Int(fields[1]) if e != nil { return e.Error() } dieSize := int64(100) if len(fields) >= 3 { userDieSize, e := g.Int(fields[2]) if e == nil && userDieSize >= 2 { dieSize = int64(userDieSize) } } lotteryNum := int64(-1) if dieSize > 100 { lotteryNum = int64(g.RandInt(dieSize)) + 1 } if amount > player.Coins { return "wat? brokeass" } n := int64(g.RandInt(dieSize)) + 1 ret := fmt.Sprintf("%s rolls the %d sided die... %d! ", player.Nick, dieSize, n) if n == lotteryNum { player.Coins += player.Coins ret += fmt.Sprintf("You won the wattery! Your bet was ignored, but your bank balance was doubled!") } else if n < dieSize/2 { player.Coins += amount ret += fmt.Sprintf("You win! ◕ ◡ ◕ total: %d %s", player.Coins, currency) } else { player.LoseCoins(amount) g.me.Coins += amount g.db.Update(g.me) ret += fmt.Sprintf("You lose! ≧ヮ≦ %d %s left...", player.Coins, currency) } g.db.Update(player) return ret } func (g *WatGame) Bankrupt(player *Player, fields []string) string { if player.Coins > 10 { return fmt.Sprintf("hmm, with %d %s, you're too rich. go get poor.", player.Coins, currency) } minTime := int64(7200) if !g.CanAct(player, Action_Bankrupt, minTime) { return "pity is only valid once every 2 hours" } player.Coins += 50 player.Bankrupcy += 1 g.db.Act(player, Action_Bankrupt) g.db.Update(player) return fmt.Sprintf("here's some pity money. you've been bankrupt %d times.", player.Bankrupcy) } func (g *WatGame) Punch(player *Player, fields []string) string { if len(fields) < 2 { return "punch pls" } target, err := g.GetTarget(player.Nick, fields[1]) if err != "" { return err } if !target.Conscious() { return "wat? you're punching someone who is already unconscious. u crazy?" } chance := g.RandInt(6) + 1 dmg := g.RandInt(6) + 1 ret := fmt.Sprintf("%s rolls a d6... %s ", player.Nick, player.Nick) dmg += uint64(player.Level(player.Anarchy)) if chance > 3 { ret += fmt.Sprintf("hits %s for %d points of damage! ", target.Nick, dmg) target.Health -= int64(dmg) g.db.Update(target) if target.Health <= 0 { ret += target.Nick + " has fallen unconscious." } else { ret += fmt.Sprintf("%s has %dHP left", target.Nick, target.Health) } } else { ret += fmt.Sprintf("fumbles, and punches themselves in confusion! %d self-damage. ", dmg) player.Health -= int64(dmg * 2) player.Anarchy -= 1 if player.Health <= 0 { ret += player.Nick + " has fallen unconscious." } else { ret += fmt.Sprintf("%s has %dHP left", player.Nick, player.Health) } g.db.Update(player) } return ret } func (g *WatGame) Frame(player *Player, fields []string) string { if len(fields) < 3 { return fmt.Sprintf("frame <%s> - d6 roll. Sneaky? You force the target to pay me. Clumsy? You pay a fine to the target and myself.", currency) } amount, e := g.Int(fields[2]) if e != nil { return e.Error() } 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 := g.RandInt(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 frame %s for a minor crime. They pay me %d.", target.Nick, amount) player.Anarchy += 1 target.Coins -= amount } else { ret += fmt.Sprintf("You were caught and pay them %d. %s gets the rest.", (amount / 2), g.bot.Nick) player.LoseCoins(amount) target.Coins += amount / 2 g.me.Coins += amount / 2 g.db.Update(g.me) } g.db.Update(player, target) return ret } func (g *WatGame) Steal(player *Player, fields []string) string { if len(fields) < 3 { return fmt.Sprintf("steal <%s> - d6 roll. If you fail, you pay double the %s to %s", currency, currency, g.bot.Nick) } amount, e := g.Int(fields[2]) if e != nil { return e.Error() } if player.Coins < amount*2 { return "wat? you need double what ur trying 2 steal or you'll go bankrupt..." } target, err := g.GetTarget(player.Nick, fields[1]) if target == nil { return err } if target.Coins < amount { return fmt.Sprintf("wat? %s is poor and doesn't have that much to steal. (%d %s)", target.Nick, target.Coins, currency) } n := g.RandInt(6) + 1 ret := fmt.Sprintf("%s is trying to steal %d %s from %s... ", player.Nick, amount, currency, target.Nick) if n < 3 { ret += "You did it! 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.LoseCoins(amount * 2) g.me.Coins += amount * 2 g.db.Update(g.me) } g.db.Update(player) return ret } func (g *WatGame) GetTarget(player, target string) (*Player, string) { t := g.db.User(strings.ToLower(target), "", false) if t.Nick == "" { return nil, "Who? wat?" } if t.Nick == player { return nil, "You can't do that to yourself, silly." } return &t, "" } func (g *WatGame) Leech(player *Player, fields []string) string { divisor := uint64(10) if len(fields) < 3 { return fmt.Sprintf("leech <%s> - using your wealth, you steal the life force of another player", currency) } amount, er := g.Int(fields[2]) if amount < divisor { return fmt.Sprintf("wat? its %d %s for 1 hp", divisor, currency) } if player.Coins < amount || er != nil { return "wat great fortune do you think you have? poor wats shouldn't be doing this, wat a waste..." } target, err := g.GetTarget(player.Nick, fields[1]) if err != "" { return err } r := g.RandInt(10) + 1 reply := fmt.Sprintf("You muster your wealth and feed it to %s. ", g.bot.Nick) hpDown := amount / divisor player.Coins -= amount if r < 5 { target.Health -= int64(hpDown) player.Health += int64(hpDown) player.Anarchy += 1 reply += fmt.Sprintf("The deal is done, you took %d HP from %s. They now have %d HP, you have %d.", hpDown, target.Nick, target.Health, player.Health) g.db.Update(target, player) } else { reply += "The gods do not smile upon you this waturday. Your money vanishes and nothing happens." } return reply } func (g *WatGame) Rest(player *Player, fields []string) string { minRest := int64(43200) delta := time.Now().Unix() - player.LastRested ret := "" if player.LastRested == 0 { ret = "you've never slept before - you sleep so well, your injuries are cured and your health is restored to 10" player.Health = 10 player.LastRested = time.Now().Unix() g.db.Update(player) } else if delta < minRest { ret = fmt.Sprintf("wat were you thinking, sleeping at a time like this (%d until next rest)", minRest-delta) } else { value := g.RandInt(10) + 1 if player.Health < -5 { player.Health = 1 ret = fmt.Sprintf("wow ur beat up. i pity u, ur health is now 1.") } else { player.Health += int64(value) ret = fmt.Sprintf("wat a nap - have back a random amount of hitpoints (this time it's %d, you've got %d hp)", value, player.Health) } player.LastRested = time.Now().Unix() g.db.Update(player) } return ret } func (g *WatGame) CanAct(player *Player, action ActionType, minTime int64) bool { delta := g.db.LastActed(player, action) if minTime != 0 && delta != 0 && time.Now().Unix()-delta < minTime { return false } return true } func (g *WatGame) Bench(player *Player, fields []string) string { minTime := int64(115200) if !g.CanAct(player, Action_Lift, minTime) { return "you're tired. no more lifting for now." } weight := g.RandInt(370) + 50 reps := g.RandInt(10) value := int64(0) reply := fmt.Sprintf("%s benches %dwatts for %d reps, ", player.Nick, weight, reps) if weight < 150 { reply += "do u even lift bro?" return reply } else if weight < 250 { value = 1 } else if weight < 420 { value = 2 } else if weight == 420 { value = 10 reply += "four twenty blaze it bro! " } if g.roid[player.Nick] != 0 { delete(g.roid, player.Nick) success := g.RandInt(2) if success != 0 { player.Health = 0 player.Anarchy -= 10 g.db.Act(player, Action_Lift) g.db.Update(player) return fmt.Sprintf("%s tried to lift %d but halfway through their %d reps, their heart literally exploded from steroid use. They are now unconscious.", player.Nick, weight, reps) } else { reply += fmt.Sprintf("roid rage increased the effectiveness! ") value *= 2 } } g.db.Act(player, Action_Lift) player.Anarchy += value g.db.Update(player) reply += fmt.Sprintf("ur %d stronger lol", value) return reply } func (g *WatGame) Riot(player *Player, fields []string) string { if !g.CanAct(player, Action_Riot, int64((48 * time.Hour).Seconds())) { return "Planning a riot takes time and the right circumstances. Be prepared. (nothing happens)" } r := g.RandInt(100) reply := "" if r > 40 { player.Anarchy += 3 reply = fmt.Sprintf("%s has successfully smashed the state! The brogeoise have been toppled. You feel stronger...", player.Nick) } else { player.Health -= 3 reply = fmt.Sprintf("The proletariat have been hunted down by the secret police and had their faces smashed in! Your rebellion fails and you lose 3HP.") } g.db.Act(player, Action_Riot) g.db.Update(player) return reply } func (g *WatGame) Send(player *Player, fields []string) string { if len(fields) < 3 { return fmt.Sprintf("You forgot somethin'. send <%s>", currency) } amount, err := g.Int(fields[2]) if err != nil { return err.Error() } if amount > player.Coins { return "wat? you're too poor!" } target, str := g.GetTarget(player.Nick, fields[1]) if target == nil { return str } player.Coins -= amount target.Coins += amount g.db.Update(player, target) return fmt.Sprintf("%s sent %s %d %s. %s has %d %s, %s has %d %s", player.Nick, target.Nick, amount, currency, player.Nick, player.Coins, currency, target.Nick, target.Coins, currency) } func (g *WatGame) Mine(player *Player, _ []string) string { delta := uint64(time.Now().Unix() - player.LastMined) minDelta := uint64(600) if delta < minDelta { return fmt.Sprintf("wat? 2 soon. u earn more when u wait long (%d)", delta) } value := uint64(0) if delta < 36000 { value = delta / minDelta } else if delta < 86400 { value = 25 } else if delta < 2592000 { value = 50 } else { value = 1000 } msg := "" if player.LastMined == 0 { msg = fmt.Sprintf("u forgot ur pickaxe but it's okay i'll give you one in %d", minDelta) value = 0 } else { player.Coins += value msg = fmt.Sprintf("%s mined %d %s for %d and has %d %s", player.Nick, value, currency, delta, player.Coins, currency) } player.LastMined = time.Now().Unix() g.db.Update(player) return msg } func (g *WatGame) Steroid(player *Player, fields []string) string { if g.roid[player.Nick] != 0 { return "Taking more than the recommended amount of steroids is, well, not recommended." } g.roid[player.Nick] = 1 return fmt.Sprintf("%s has eaten anabolic steroids. While they're good for building strength, it's dangerous to lift heavy weights. I hope you know what you're doing...", player.Nick) } func (g *WatGame) Watch(player *Player, fields []string) string { if len(fields) > 1 { maybePlayer, err := g.GetTarget("", fields[1]) if err != "" { return err } player = maybePlayer } return fmt.Sprintf("%s's Strength: %d (%d) / Coins: %d / Health: %d", player.Nick, player.Level(player.Anarchy), player.Anarchy, player.Coins, player.Health) } func (g *WatGame) Balance(player *Player, fields []string) string { balStr := "%s's %s balance: %d. Mining time credit: %d. Total lost: %d. Bankrupt %d times." balPlayer := player if len(fields) > 1 { var err string balPlayer, err = g.GetTarget("", fields[1]) if err != "" { return err } } return fmt.Sprintf(balStr, balPlayer.Nick, currency, balPlayer.Coins, time.Now().Unix()-balPlayer.LastMined, balPlayer.CoinsLost, balPlayer.Bankrupcy) } func (g *WatGame) Strongest() string { players := g.db.Strongest() ret := "" for _, p := range players { ret += PrintTwo(p.Nick, uint64(p.Anarchy)) } return ret } func (g *WatGame) Healthiest() string { players := g.db.Healthiest() ret := "" for _, p := range players { ret += PrintTwo(p.Nick, uint64(p.Health)) } return ret } func (g *WatGame) TopLost() string { players := g.db.TopLost() ret := "" for _, p := range players { ret += PrintTwo(p.Nick, p.CoinsLost) } return ret } func (g *WatGame) Bankrupest() string { players := g.db.Bankruptest() ret := "" for _, p := range players { ret += fmt.Sprintf("%s (%d) ", CleanNick(p.Nick), p.Bankrupcy) } return ret } 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 uint64) string { return fmt.Sprintf("%s (%d) ", CleanNick(nick), value) } func (g *WatGame) megaWat(player *Player, _ []string) string { mega := g.RandInt(1000000) + 1 kilo := g.RandInt(1000) + 1 ten := g.RandInt(100) + 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) } if ten == 10 { player.Coins += 10 reply = fmt.Sprintf("%s won the regular wattery. This one only pays 10 %s.", player.Nick, currency) } player.Watting += 1 g.db.Update(player) return reply }