-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspecialcmds.go
297 lines (236 loc) · 7.18 KB
/
specialcmds.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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
package main
import (
"db"
"math"
"math/rand"
"strconv"
"time"
"github.com/andersfylling/disgord"
"github.com/andersfylling/snowflake/v5"
)
// This file implements special features, such as custom commands and ranking
// -- Custom commands --
// helpers
func getGuildCustomCommandsFields(DID db.Division) ([]*disgord.EmbedField, error) {
cmds, err := getCustomCommands(DID)
if err != nil {
return nil, err
}
if len(cmds) > 25 { // discord embed cap
return []*disgord.EmbedField{
{
Name: "_ _\nThe server's number of commands exceeds discord's embed field cap of 25. Use \"@TRAS commands view\" instead.",
Value: "_ _",
},
}, nil
}
newEmbedFields := []*disgord.EmbedField{}
for i := 0; i < len(cmds); i++ { // generative embeds
newEmbedFields = append(newEmbedFields, &disgord.EmbedField{
Name: "_ _\n@TRAS " + cmds[i].Key,
Value: "I respond " + cmds[i].Val,
})
}
if len(newEmbedFields) == 0 { // no embeds on server
newEmbedFields = append(newEmbedFields, &disgord.EmbedField{
Name: "_ _\nNo custom commands are currently on this server",
Value: "_ _",
})
}
return newEmbedFields, nil
}
func getCustomCommands(div db.Division) ([]*db.CustomCommand, error) {
divData, err := DBConn.GetDivsion(div)
if err != nil {
return nil, err
}
return divData.Cmds, nil
}
// handlers
func handleViewCustomCommands(msg *disgord.Message, s *disgord.Session) {
div := getDivision(msg)
cmds, err := getCustomCommands(div)
if err != nil {
msgerr(err, msg, s)
return
}
respArr := []string{"**__ Commands List:__** \n"}
c := 0
for _, cc := range cmds {
entry := "- \"" + cc.Key + "\", returns: \"" + cc.Val + "\""
if len(respArr[c]+entry+"\n") > 2000 { // if too large to fit in single message
c++
respArr = append(respArr, entry) // expand array
} else {
respArr[c] += entry + "\n"
}
}
baseReact(msg, s, "👍")
for _, v := range respArr {
baseDMReply(msg, s, v, nil)
}
}
func handleSetCustomCommand(msg *disgord.Message, s *disgord.Session, key string, value string) {
div := getDivision(msg)
_, err := DBConn.SetCustomCommand(key, value, div)
if err != nil {
msgerr(err, msg, s)
return
}
baseReply(msg, s, "Command \""+key+"\" set successfully!")
}
func handleDeleteCustomCommand(msg *disgord.Message, s *disgord.Session, key string) {
div := getDivision(msg)
err := DBConn.RemoveCustomCommand(key, div)
if err != nil {
msgerr(err, msg, s)
return
}
baseReply(msg, s, "Command \""+key+"\" removed successfully!")
}
// parser
func parseCustomCommand(msg *disgord.Message, s *disgord.Session, arg string) bool {
div := getDivision(msg)
cmds, err := getCustomCommands(div)
if err != nil {
msgerr(err, msg, s) // msgerr is warranted here because we know that they at least pinged the bot
return false
}
for _, cc := range cmds {
if arg == cc.Key {
baseReply(msg, s, cc.Val)
return true
// break
}
}
return false
}
// -- Ranking --
// helpers
// func baseAttentionScore(timeDiff time.Duration) float64 {
// x := timeDiff.Seconds()
// score := math.Max(0, (-1.0/125.0)*(600-180*x+math.Pow(x, 2))*math.Min(1, 10.0/math.Abs(-45+x)))
// return score
// }
func calcNewMemberProgress(msg *disgord.Message) (int64, error) {
if msg.MentionEveryone {
// never adds score if it mentions everyone
return 0, nil
}
div := getDivision(msg)
rankMem, err := DBConn.GetRankMember(msg.Author.ID, div)
if err != nil {
return 0, err
}
// base attention score is based on time between messages.
// I played around in desmos for a while and found the equation I liked,
// then I asked wolframalpha to simplify it.
tsDiff := msg.Timestamp.Time.Sub(rankMem.LastMsgTs).Seconds()
score := math.Max(0, (-1.0/125.0)*(600-180*tsDiff+math.Pow(tsDiff, 2))*math.Min(1, 10.0/math.Abs(-45+tsDiff)))
if msg.MessageReference != nil { // replying to someone else
score *= 2
if tsDiff > 3.3 { // prevent gaming spam filter with message reference
// this inflates base score since you are
// extrememly likely to be "attentive" to what
// you responded to regardless of time difference
score += 10
}
}
if msg.ChannelID != snowflake.Snowflake(rankMem.LastChanID) { // not on the same channel
score *= 0.5
}
if 3 > len(msg.Mentions) && len(msg.Mentions) > 0 {
if msg.Mentions[0].ID != msg.Author.ID && ((len(msg.Mentions) > 1 && msg.Mentions[1].ID != msg.Author.ID) || len(msg.Mentions) < 2) { // not mentioning self
score *= 1.1 // if there is 1 or 2 mentions, increase the score slightly
}
}
newProg := int64(score) + rankMem.Progress
return newProg, nil
}
func updateMemberProgress(msg *disgord.Message) error {
//calculate
newProg, err := calcNewMemberProgress(msg)
if err != nil {
// Because this runs on every message, returning an error would be a nuisance in the event
// of a repeating failure. As such, it is only logged.
logmsgerr(msg, err)
return err
}
div := getDivision(msg)
DBConn.SetRankMemberProgress(msg, msg.Author.ID, div, newProg)
return nil
}
func getDiceStatus(msg *disgord.Message) (bool, error) {
div := getDivision(msg)
data, err := DBConn.GetDivsion(div)
if err != nil {
return false, err
}
return data.Dice, nil
}
func toggleDiceStatus(msg *disgord.Message) (bool, error) {
curStat, err := getDiceStatus(msg)
if err != nil {
return false, err
}
err = DBConn.SetDiceAvailability(getDivision(msg), !curStat) // flip status
if err != nil {
return false, err
}
return !curStat, nil
}
func forceSetUserRank(msg *disgord.Message, uID disgord.Snowflake, newProgress int64) error {
err := DBConn.SetRankMemberProgress(msg, uID, getDivision(msg), newProgress)
return err
}
// handlers
func diceRollResponse(msg *disgord.Message, s *disgord.Session) {
// Sets your progress to a random value within 100 levels
rand.Seed(time.Now().UnixNano())
newLevel := rand.Float64() * 100
newProgress := int64(math.Pow(float64(newLevel), 2))
err := forceSetUserRank(msg, msg.Author.ID, newProgress)
if err != nil {
msgerr(err, msg, s)
return
}
// Modified from commands.go/getUserRankInfo
levelStr := strconv.Itoa(int(newLevel))
progStr := strconv.Itoa(int(newProgress))
nextMilestone := strconv.Itoa(int(math.Pow(math.Floor(newLevel)+1, 2)))
baseReply(msg, s, "Dice rolled! Your stats are now:\n"+
"Level:"+levelStr+"\n"+"Progress:"+progStr+"/"+nextMilestone)
}
// -- Random Speak --
// helpers
type RandSpeakData struct {
status bool
LastRandSpeak time.Time
}
func getRandSpeakInfo(msg *disgord.Message) (*RandSpeakData, error) {
div := getDivision(msg)
data, err := DBConn.GetDivsion(div)
if err != nil {
return nil, err
}
return &RandSpeakData{
status: data.RandSpeak,
LastRandSpeak: data.LastRandSpeak,
}, nil
}
func executeRandSpeakRoll(msg *disgord.Message, s *disgord.Session) error {
rsdata, err := getRandSpeakInfo(msg)
if err != nil {
return err
}
if !rsdata.status {
// randomSpeak disabled
return nil
}
probabilityWeight := -math.Pow(math.E, float64(time.Now().Unix()-rsdata.LastRandSpeak.Unix())*(-1/60.0)) + 1
if GRand.Float64()*25 < probabilityWeight { // max odds 1 in 25, min odds 0 (immediately after last randSpeak)
DBConn.SetLastRandomSpeakTime(getDivision(msg), time.Now())
randSpeakGenerateResponse(msg, s, "")
}
return nil
}