forked from xiaq/fffbot
/
fffbot.go
187 lines (163 loc) · 4.07 KB
/
fffbot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
package main
import (
"bytes"
"fmt"
"io/ioutil"
"log"
"strings"
"github.com/xiaq/tg"
)
type commandMeta struct {
name string
method func(*Stake, []string, *tg.User) string
args string
description string
}
var commands = []commandMeta{
{"install", (*Stake).install, "p q ...", "把人捆♂绑到火刑柱上"},
{"add", (*Stake).add, "i j ...", "添加调料"},
{"ignite", (*Stake).ignite, "", "开始烧烧烧!"},
{"water", (*Stake).water, "", "灭火"},
{"status", (*Stake).status, "", "查询火刑柱状态"},
{"help", nil, "", "命令帮助"},
}
var commandMap map[string]*commandMeta
func (cm *commandMeta) help() string {
argsPart := ""
if cm.args != "" {
argsPart = " " + cm.args
}
return fmt.Sprintf("/fff %s%s: %s", cm.name, argsPart, cm.description)
}
var help string
func init() {
// Populate helpText
var buf bytes.Buffer
buf.WriteString("释放 FFF 团的怒火吧!")
for _, cm := range commands {
buf.WriteString("\n" + cm.help())
}
help = buf.String()
// Populate commandMap
commandMap = make(map[string]*commandMeta)
for i, cm := range commands {
commandMap[cm.name] = &commands[i]
}
}
type state int
const (
idle state = iota
installed
ignited
)
func makeString(things []string) string {
n := len(things)
switch n {
case 0:
return "啥都没有"
case 1:
return things[0]
default:
return strings.Join(things[0:n-1], "、") + " 和 " + things[n-1]
}
}
type Stake struct {
state state
people []string
peopleStr string
}
func (s *Stake) stateDesc() string {
switch s.state {
case idle:
return "火刑柱上现在什么都没有。"
case installed:
return fmt.Sprintf("火刑柱上现在绑着 %s。", s.peopleStr)
case ignited:
return fmt.Sprintf("%s 正在熊熊燃烧。", s.peopleStr)
default:
return fmt.Sprintf("火刑柱现在处在作者也不清楚的 %s 状态。", s.state)
}
}
func (s *Stake) install(people []string, from *tg.User) string {
if s.state != idle {
return s.stateDesc()
}
if len(people) == 0 {
return "至少要绑一个人。"
}
for i, p := range people {
people[i] = strings.TrimLeft(p, "@")
}
s.people = people
s.peopleStr = makeString(people)
s.state = installed
return fmt.Sprintf("%s 把 %s 绑到了火刑柱上。", from.DisplayName(), s.peopleStr)
}
func (s *Stake) add(things []string, from *tg.User) string {
if s.state != installed && s.state != ignited {
return s.stateDesc()
}
if len(things) == 0 {
return "请至少指定一种调料 - -b"
}
return fmt.Sprintf("%s 往火刑柱上加了 %s。",
from.DisplayName(), makeString(things))
}
func (s *Stake) ignite(args []string, from *tg.User) string {
if s.state != installed {
return s.stateDesc()
}
s.state = ignited
return fmt.Sprintf("%s 烧起来了!此处应有欢呼。", s.peopleStr)
}
func (s *Stake) water(args []string, from *tg.User) string {
if s.state != ignited {
return s.stateDesc()
}
s.state = idle
return fmt.Sprintf("%s 英勇地解救了 %s。", from.DisplayName(), s.peopleStr)
}
func (s *Stake) status(args []string, from *tg.User) string {
return s.stateDesc()
}
type FFFBot struct {
*tg.CommandBot
stakes map[int]*Stake
}
func (b *FFFBot) handleFFF(_ *tg.CommandBot, text string, msg *tg.Message) {
cmd, args := tg.Split(text, ' ')
log.Println("fff", cmd, args)
chatID := msg.Chat.ID
if b.stakes[chatID] == nil {
b.stakes[chatID] = &Stake{}
}
var reply string
if cmd == "" {
cmd = "status"
}
cm, ok := commandMap[cmd]
if cmd == "help" || !ok {
reply = help
} else {
argList := strings.Split(args, " ")
log.Println(cmd, cm.method, msg.From)
reply = cm.method(b.stakes[chatID], argList, msg.From)
}
b.Get("/sendMessage", tg.Query{
"chat_id": msg.Chat.ID,
"text": reply,
}, nil)
}
func NewFFFBot(name, token string) *FFFBot {
b := &FFFBot{tg.NewCommandBot(name, token), make(map[int]*Stake)}
b.OnCommand("fff", b.handleFFF)
return b
}
func main() {
buf, err := ioutil.ReadFile("token.txt")
if err != nil {
log.Fatalf("cannot read token file: %s", err)
}
token := strings.TrimSpace(string(buf))
NewFFFBot("xiaqsbot", token).Main()
}