@lotus-tree/fg-notation 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. package/README.md +80 -68
  2. package/babel.config.js +6 -6
  3. package/lib/img/credits.txt +3 -3
  4. package/lib/img/grabs/omegarugal.json +5 -0
  5. package/lib/img/grabs/omegarugal.png +0 -0
  6. package/lib/img/grabs/ralph.json +5 -0
  7. package/lib/img/grabs/ralph.png +0 -0
  8. package/lib/index.js +202 -19
  9. package/lib/info.json +32 -32
  10. package/package.json +28 -27
  11. package/src/img/credits.txt +3 -3
  12. package/src/img/grabs/omegarugal.json +5 -0
  13. package/src/img/grabs/omegarugal.png +0 -0
  14. package/src/img/grabs/ralph.json +5 -0
  15. package/src/img/grabs/ralph.png +0 -0
  16. package/src/index.js +302 -249
  17. package/src/info.json +32 -32
  18. package/dev/img/basic/+.png +0 -0
  19. package/dev/img/basic/1.png +0 -0
  20. package/dev/img/basic/12369.png +0 -0
  21. package/dev/img/basic/1237.png +0 -0
  22. package/dev/img/basic/1632143.png +0 -0
  23. package/dev/img/basic/2.png +0 -0
  24. package/dev/img/basic/21.png +0 -0
  25. package/dev/img/basic/214.png +0 -0
  26. package/dev/img/basic/21478.png +0 -0
  27. package/dev/img/basic/23.png +0 -0
  28. package/dev/img/basic/236.png +0 -0
  29. package/dev/img/basic/23698.png +0 -0
  30. package/dev/img/basic/28.png +0 -0
  31. package/dev/img/basic/3.png +0 -0
  32. package/dev/img/basic/32147.png +0 -0
  33. package/dev/img/basic/3219.png +0 -0
  34. package/dev/img/basic/341236.png +0 -0
  35. package/dev/img/basic/346.png +0 -0
  36. package/dev/img/basic/360.png +0 -0
  37. package/dev/img/basic/4.png +0 -0
  38. package/dev/img/basic/41236.png +0 -0
  39. package/dev/img/basic/421.png +0 -0
  40. package/dev/img/basic/46.png +0 -0
  41. package/dev/img/basic/4618346.png +0 -0
  42. package/dev/img/basic/47896.png +0 -0
  43. package/dev/img/basic/5.png +0 -0
  44. package/dev/img/basic/6.png +0 -0
  45. package/dev/img/basic/623.png +0 -0
  46. package/dev/img/basic/63214.png +0 -0
  47. package/dev/img/basic/64.png +0 -0
  48. package/dev/img/basic/6428.png +0 -0
  49. package/dev/img/basic/69874.png +0 -0
  50. package/dev/img/basic/7.png +0 -0
  51. package/dev/img/basic/7891.png +0 -0
  52. package/dev/img/basic/8.png +0 -0
  53. package/dev/img/basic/81237.png +0 -0
  54. package/dev/img/basic/82.png +0 -0
  55. package/dev/img/basic/87412.png +0 -0
  56. package/dev/img/basic/89632.png +0 -0
  57. package/dev/img/basic/9.png +0 -0
  58. package/dev/img/basic/[1].png +0 -0
  59. package/dev/img/basic/[2].png +0 -0
  60. package/dev/img/basic/[2]8.png +0 -0
  61. package/dev/img/basic/[3].png +0 -0
  62. package/dev/img/basic/[4].png +0 -0
  63. package/dev/img/basic/[6].png +0 -0
  64. package/dev/img/basic/[7].png +0 -0
  65. package/dev/img/basic/[8].png +0 -0
  66. package/dev/img/basic/[9].png +0 -0
  67. package/dev/img/basic/air.png +0 -0
  68. package/dev/img/basic/doubleforward.png +0 -0
  69. package/dev/img/credits.txt +0 -4
  70. package/dev/img/games/bb/a.png +0 -0
  71. package/dev/img/games/bb/b.png +0 -0
  72. package/dev/img/games/bb/c.png +0 -0
  73. package/dev/img/games/bb/d.png +0 -0
  74. package/dev/img/games/bbtag/a.png +0 -0
  75. package/dev/img/games/bbtag/b.png +0 -0
  76. package/dev/img/games/bbtag/c.png +0 -0
  77. package/dev/img/games/bbtag/d.png +0 -0
  78. package/dev/img/games/bbtag/p.png +0 -0
  79. package/dev/img/games/dbz/a1.png +0 -0
  80. package/dev/img/games/dbz/a2.png +0 -0
  81. package/dev/img/games/dbz/h.png +0 -0
  82. package/dev/img/games/dbz/l.png +0 -0
  83. package/dev/img/games/dbz/m.png +0 -0
  84. package/dev/img/games/dbz/s.png +0 -0
  85. package/dev/img/games/dnf/a.png +0 -0
  86. package/dev/img/games/dnf/as.png +0 -0
  87. package/dev/img/games/dnf/b.png +0 -0
  88. package/dev/img/games/dnf/g.png +0 -0
  89. package/dev/img/games/dnf/ms.png +0 -0
  90. package/dev/img/games/dnf/s.png +0 -0
  91. package/dev/img/games/gbf/g.png +0 -0
  92. package/dev/img/games/gbf/h.png +0 -0
  93. package/dev/img/games/gbf/l.png +0 -0
  94. package/dev/img/games/gbf/m.png +0 -0
  95. package/dev/img/games/gbf/s.png +0 -0
  96. package/dev/img/games/gg/d.png +0 -0
  97. package/dev/img/games/gg/hs.png +0 -0
  98. package/dev/img/games/gg/k.png +0 -0
  99. package/dev/img/games/gg/p.png +0 -0
  100. package/dev/img/games/gg/rc.png +0 -0
  101. package/dev/img/games/gg/s.png +0 -0
  102. package/dev/img/games/kof/a.png +0 -0
  103. package/dev/img/games/kof/b.png +0 -0
  104. package/dev/img/games/kof/c.png +0 -0
  105. package/dev/img/games/kof/d.png +0 -0
  106. package/dev/img/games/kof/max.png +0 -0
  107. package/dev/img/games/mk/1.png +0 -0
  108. package/dev/img/games/mk/2.png +0 -0
  109. package/dev/img/games/mk/3.png +0 -0
  110. package/dev/img/games/mk/4.png +0 -0
  111. package/dev/img/games/sc/[a].png +0 -0
  112. package/dev/img/games/sc/[b].png +0 -0
  113. package/dev/img/games/sc/[g].png +0 -0
  114. package/dev/img/games/sc/[k].png +0 -0
  115. package/dev/img/games/sc/a.png +0 -0
  116. package/dev/img/games/sc/b.png +0 -0
  117. package/dev/img/games/sc/g.png +0 -0
  118. package/dev/img/games/sc/k.png +0 -0
  119. package/dev/img/games/sf/hk.png +0 -0
  120. package/dev/img/games/sf/hp.png +0 -0
  121. package/dev/img/games/sf/j..png +0 -0
  122. package/dev/img/games/sf/lk.png +0 -0
  123. package/dev/img/games/sf/lp.png +0 -0
  124. package/dev/img/games/sf/max.png +0 -0
  125. package/dev/img/games/sf/mk.png +0 -0
  126. package/dev/img/games/sf/mp.png +0 -0
  127. package/dev/img/games/sf/tap.png +0 -0
  128. package/dev/img/games/sg/hk.png +0 -0
  129. package/dev/img/games/sg/hp.png +0 -0
  130. package/dev/img/games/sg/k.png +0 -0
  131. package/dev/img/games/sg/lk.png +0 -0
  132. package/dev/img/games/sg/lp.png +0 -0
  133. package/dev/img/games/sg/mk.png +0 -0
  134. package/dev/img/games/sg/mp.png +0 -0
  135. package/dev/img/games/sg/p.png +0 -0
  136. package/dev/img/games/tfh/a.png +0 -0
  137. package/dev/img/games/tfh/b.png +0 -0
  138. package/dev/img/games/tfh/c.png +0 -0
  139. package/dev/img/games/tfh/d.png +0 -0
  140. package/dev/img/games/tkn/1.png +0 -0
  141. package/dev/img/games/tkn/12.png +0 -0
  142. package/dev/img/games/tkn/1234.png +0 -0
  143. package/dev/img/games/tkn/13.png +0 -0
  144. package/dev/img/games/tkn/14.png +0 -0
  145. package/dev/img/games/tkn/2.png +0 -0
  146. package/dev/img/games/tkn/23.png +0 -0
  147. package/dev/img/games/tkn/24.png +0 -0
  148. package/dev/img/games/tkn/3.png +0 -0
  149. package/dev/img/games/tkn/34.png +0 -0
  150. package/dev/img/games/tkn/4.png +0 -0
  151. package/dev/img/games/tkn/b.png +0 -0
  152. package/dev/img/games/tkn/d-b.png +0 -0
  153. package/dev/img/games/tkn/d-f.png +0 -0
  154. package/dev/img/games/tkn/d.png +0 -0
  155. package/dev/img/games/tkn/f.png +0 -0
  156. package/dev/img/games/tkn/o.png +0 -0
  157. package/dev/img/games/tkn/u-b.png +0 -0
  158. package/dev/img/games/tkn/u-f.png +0 -0
  159. package/dev/img/games/tkn/u.png +0 -0
  160. package/dev/img/preview.png +0 -0
  161. package/dev/index.js +0 -563
  162. package/dev/info.json +0 -33
package/src/index.js CHANGED
@@ -1,249 +1,302 @@
1
- import sharp from 'sharp'
2
- import path from 'path'
3
- import glob from 'glob'
4
- import { DataTypes } from 'sequelize'
5
- import bent from 'bent'
6
-
7
- import { sizes, aliases, builtin } from './info.json'
8
-
9
- const getJSON = bent('json')
10
- const imgPath = path.join(__dirname, 'img')
11
- const basicInputs = new Map()
12
- const gameInputs = new Map()
13
-
14
- let glossary = {}
15
- let terms = []
16
-
17
- getGlossary()
18
- setInterval(getGlossary, 5 * 60 * 1000)
19
-
20
- async function getGlossary () {
21
- const result = await getJSON('https://glossary.infil.net/json/glossary.json')
22
- const tempG = {}
23
- const tempT = []
24
-
25
- result.forEach(i => {
26
- const term = i.term.toLowerCase()
27
- tempG[term] = i
28
- tempT.push(term)
29
- })
30
-
31
- glossary = tempG
32
- terms = tempT
33
- }
34
-
35
- glob.sync(path.join(imgPath, 'basic/**'), { nodir: true })
36
- .forEach(p => {
37
- const input = p.split('/').pop().replace('.png', '')
38
- basicInputs.set(input, p)
39
-
40
- const alias = aliases.inputs.basic[input]
41
- if (alias) {
42
- alias.forEach(i => {
43
- basicInputs.set(i, p)
44
- if (sizes[input]) sizes[i] = sizes[input]
45
- })
46
- }
47
- })
48
-
49
- glob.sync(path.join(imgPath, 'games/*'))
50
- .forEach(p => {
51
- const { base } = path.parse(path.relative(path.join(imgPath, 'games'), p))
52
- gameInputs.set(base, new Map())
53
-
54
- glob.sync(path.join(imgPath, 'games', base, '**'), { nodir: true })
55
- .forEach(input => {
56
- const { name } = path.parse(input)
57
- gameInputs.get(base).set(name, input)
58
- })
59
-
60
- const alias = aliases.inputs.games[base]
61
-
62
- if (alias) {
63
- for (const [a, s] of Object.entries(alias)) {
64
- gameInputs.get(base).set(a, s)
65
- }
66
- }
67
- })
68
-
69
- function solveInput (inputs, input) {
70
- if (inputs.has(input)) return isString(inputs.get(input)) ? [input] : inputs.get(input)
71
-
72
- for (let i = 0; i < input.length; i++) {
73
- const s1 = input.slice(0, 0 - i)
74
-
75
- if (inputs.has(s1)) {
76
- const result = inputs.get(s1)
77
- const remaining = solveInput(inputs, input.slice(0 - i))
78
-
79
- return isString(result) ? [s1, ...remaining] : [...result, ...remaining]
80
- }
81
- }
82
-
83
- throw new Error(`Cannot find "${input}" as a recognizable input`)
84
- }
85
-
86
- async function sendInput (inputs, result, message, caption) {
87
- const width = result.map(it => sizes[it] || 152).reduce((a, b) => a + b, 0)
88
- const images = []
89
- let left = 0
90
-
91
- result.forEach((it, index) => {
92
- const size = sizes[it] || 152
93
- images.push({ input: inputs.get(it), left, top: Math.floor((152 - size) / 2) })
94
- left += size
95
- })
96
-
97
- let canvas = sharp({ create: { width, height: 152, channels: 4, background: 'transparent' } })
98
- .png()
99
- .composite(images)
100
-
101
- canvas = await canvas.toBuffer()
102
-
103
- if (result.length < 12) canvas = await sharp(canvas).resize({ height: 55 }).png().toBuffer()
104
-
105
- return message.reply({ content: caption, files: [canvas] })
106
- }
107
-
108
- function checkGame (game) {
109
- return gameInputs.has(game) ? game : aliases.games[game]
110
- }
111
-
112
- function isString (x) {
113
- return Object.prototype.toString.call(x) === '[object String]'
114
- }
115
-
116
- export default {
117
- name: 'fg-notation',
118
- about: {
119
- name: 'FG Notation',
120
- value: '[Instructions and source code](https://lotus.chitowarlock.com/fgnotation)\n[Infil\'s Fighting Game Glossary](https://glossary.infil.net)\n[MagicianStuff\'s Fighthing Game notations emotes](https://twitter.com/MagicianStuff/status/1477931054484893697)'
121
- },
122
- intents: ['GUILD_MESSAGES'],
123
- partials: ['MESSAGE'],
124
-
125
- preload: sequelize => {
126
- sequelize.define('fginput', {
127
- guild: {
128
- type: DataTypes.STRING,
129
- primaryKey: true
130
- },
131
- name: {
132
- type: DataTypes.STRING,
133
- primaryKey: true
134
- },
135
- createdBy: DataTypes.STRING,
136
- game: DataTypes.STRING,
137
- caption: DataTypes.STRING,
138
- input: DataTypes.STRING
139
- })
140
- },
141
-
142
- events: {
143
- async messageCreate (global, message) {
144
- const { client, config, sequelize } = global
145
- if (message.author.id === client.user.id || !message.member) return
146
-
147
- const guildId = message.guildId
148
- const { prefix } = config[guildId]
149
-
150
- if (message.content.startsWith(prefix)) {
151
- const name = message.content.split(' ').pop().replace(prefix, '')
152
- const row = builtin[name] || (
153
- await sequelize.models.fginput.findOne({
154
- where: { guild: message.guild.id, name }
155
- })
156
- )
157
-
158
- if (row) {
159
- const inputs = new Map([...basicInputs, ...gameInputs.get(row.game)])
160
- sendInput(inputs, row.input.split(' '), message, row.caption)
161
- }
162
- }
163
- }
164
- },
165
-
166
- commands: {
167
- fgi: {
168
- usage: 'fgi [game] [inputs]',
169
- desc: 'Converts a list of inputs into an image',
170
- example: 'fgi sf 236P 214K',
171
- execute: async ({ param }, { message }) => {
172
- const [, gameInput, i1] = param
173
- if (!gameInput || !i1) return message.reply('Missing arguments. Example: >fgi sf 236P 214K')
174
-
175
- const game = checkGame(gameInput)
176
- if (!gameInputs.has(game)) return message.reply(`"${game}" is not a valid game. Available games: ${Array.from(gameInputs.keys()).join(' ')}`)
177
-
178
- try {
179
- const inputs = new Map([...basicInputs, ...gameInputs.get(game)])
180
- const result = param.slice(2).map(i => solveInput(inputs, i.toLowerCase())).flat()
181
-
182
- sendInput(inputs, result, message)
183
- } catch (err) {
184
- message.reply(err.message)
185
- }
186
- }
187
- },
188
- fgsave: {
189
- usage: 'fgsave [game] [name] [inputs]',
190
- desc: 'Saves a list of inputs into a command',
191
- example: 'fgi sf testName 236P 214K',
192
- execute: async ({ param, sequelize }, { message }) => {
193
- const [, gameInput, name, i1] = param
194
- if (!gameInput || !name || !i1) return message.reply('Missing arguments. Example: >fgi sf testName 236P 214K')
195
-
196
- const game = checkGame(gameInput)
197
- if (!gameInputs.has(game)) return message.reply(`"${game}" is not a valid game. Available games: ${Array.from(gameInputs.keys()).join(' ')}`)
198
-
199
- try {
200
- const inputs = new Map([...basicInputs, ...gameInputs.get(game)])
201
- const input = param.slice(3).map(i => solveInput(inputs, i.toLowerCase())).flat().join(' ')
202
-
203
- await sequelize.models.fginput.create({ guild: message.guild.id, name, createdBy: message.author.id, game, input })
204
-
205
- message.channel.send(`Saved command "${input}" as "${name}"`)
206
- } catch (err) {
207
- message.reply(err.message)
208
- }
209
- }
210
- },
211
- fgcaption: {
212
- usage: 'fgcaption [name] [caption]',
213
- desc: 'Adds a caption to a saved input command',
214
- example: 'fgcaption testName This is a caption',
215
- execute: async ({ param, sequelize }, { message }) => {
216
- const [, name, i1] = param
217
- if (!name || !i1) return message.reply('Missing arguments. Example: >fgi testName This is a caption')
218
-
219
- const row = await sequelize.models.fginput.findOne({
220
- where: { guild: message.guild.id, name }
221
- })
222
-
223
- if (!row) return message.reply(`"${name}" is not a saved input list`)
224
- row.caption = param.slice(2).join(' ')
225
- await row.save()
226
-
227
- message.channel.send(`Saved caption for input list "${name}"`)
228
- }
229
- },
230
- fgglossary: {
231
- usage: 'fgglossary [search term]',
232
- desc: 'Searches for a term on Infil\'s Glossary',
233
- example: 'fgglossary mexican uppercut',
234
- execute: async ({ param, sequelize }, { message }) => {
235
- const params = param.slice(1)
236
- if (params.length === 0) return message.reply('Missing search term. Example: >fgglossary mexican uppercut')
237
-
238
- const search = params.join(' ').toLowerCase()
239
- const result = terms.filter(i => i.includes(search))
240
- const url = `https://glossary.infil.net/?t=${params.join('%20').toLowerCase()}`
241
-
242
- if (result.length === 0) return message.reply(`Term "${search}" not found`)
243
- if (result.length === 1) return message.reply(`\`\`\`${glossary[result[0]].def}\`\`\`Source: <${url}>`)
244
-
245
- message.reply(`Multiple terms found: ${url}`)
246
- }
247
- }
248
- }
249
- }
1
+ import sharp from 'sharp'
2
+ import path from 'path'
3
+ import glob from 'glob'
4
+ import { DataTypes } from 'sequelize'
5
+ import bent from 'bent'
6
+ import axios from 'axios'
7
+
8
+ import { sizes, aliases, builtin } from './info.json'
9
+
10
+ const getJSON = bent('json')
11
+ const imgPath = path.join(__dirname, 'img')
12
+ const basicInputs = new Map()
13
+ const gameInputs = new Map()
14
+
15
+ let glossary = {}
16
+ let terms = []
17
+ const grabs = glob.sync(path.join(imgPath, 'grabs/**.png'))
18
+
19
+ getGlossary()
20
+ setInterval(getGlossary, 5 * 60 * 1000)
21
+
22
+ async function getGlossary () {
23
+ const result = await getJSON('https://glossary.infil.net/json/glossary.json')
24
+ const tempG = {}
25
+ const tempT = []
26
+
27
+ result.forEach(i => {
28
+ const term = i.term.toLowerCase()
29
+ tempG[term] = i
30
+ tempT.push(term)
31
+ })
32
+
33
+ glossary = tempG
34
+ terms = tempT
35
+ }
36
+
37
+ glob.sync(path.join(imgPath, 'basic/**'), { nodir: true })
38
+ .forEach(p => {
39
+ const input = p.split('/').pop().replace('.png', '')
40
+ basicInputs.set(input, p)
41
+
42
+ const alias = aliases.inputs.basic[input]
43
+ if (alias) {
44
+ alias.forEach(i => {
45
+ basicInputs.set(i, p)
46
+ if (sizes[input]) sizes[i] = sizes[input]
47
+ })
48
+ }
49
+ })
50
+
51
+ glob.sync(path.join(imgPath, 'games/*'))
52
+ .forEach(p => {
53
+ const { base } = path.parse(path.relative(path.join(imgPath, 'games'), p))
54
+ gameInputs.set(base, new Map())
55
+
56
+ glob.sync(path.join(imgPath, 'games', base, '**'), { nodir: true })
57
+ .forEach(input => {
58
+ const { name } = path.parse(input)
59
+ gameInputs.get(base).set(name, input)
60
+ })
61
+
62
+ const alias = aliases.inputs.games[base]
63
+
64
+ if (alias) {
65
+ for (const [a, s] of Object.entries(alias)) {
66
+ gameInputs.get(base).set(a, s)
67
+ }
68
+ }
69
+ })
70
+
71
+ function solveInput (inputs, input) {
72
+ if (inputs.has(input)) return isString(inputs.get(input)) ? [input] : inputs.get(input)
73
+
74
+ for (let i = 0; i < input.length; i++) {
75
+ const s1 = input.slice(0, 0 - i)
76
+
77
+ if (inputs.has(s1)) {
78
+ const result = inputs.get(s1)
79
+ const remaining = solveInput(inputs, input.slice(0 - i))
80
+
81
+ return isString(result) ? [s1, ...remaining] : [...result, ...remaining]
82
+ }
83
+ }
84
+
85
+ throw new Error(`Cannot find "${input}" as a recognizable input`)
86
+ }
87
+
88
+ async function sendInput (inputs, result, message, caption) {
89
+ const width = result.map(it => sizes[it] || 152).reduce((a, b) => a + b, 0)
90
+ const images = []
91
+ let left = 0
92
+
93
+ result.forEach((it, index) => {
94
+ const size = sizes[it] || 152
95
+ images.push({ input: inputs.get(it), left, top: Math.floor((152 - size) / 2) })
96
+ left += size
97
+ })
98
+
99
+ let canvas = sharp({ create: { width, height: 152, channels: 4, background: 'transparent' } })
100
+ .png()
101
+ .composite(images)
102
+
103
+ canvas = await canvas.toBuffer()
104
+
105
+ if (result.length < 12) canvas = await sharp(canvas).resize({ height: 55 }).png().toBuffer()
106
+
107
+ return message.reply({ content: caption, files: [canvas] })
108
+ }
109
+
110
+ function checkGame (game) {
111
+ return gameInputs.has(game) ? game : aliases.games[game]
112
+ }
113
+
114
+ function isString (x) {
115
+ return Object.prototype.toString.call(x) === '[object String]'
116
+ }
117
+
118
+ export default {
119
+ name: 'fg-notation',
120
+ about: {
121
+ name: 'FG Notation',
122
+ value: '[Instructions and source code](https://lotus.chitowarlock.com/fgnotation)\n[Infil\'s Fighting Game Glossary](https://glossary.infil.net)\n[MagicianStuff\'s Fighthing Game notations emotes](https://twitter.com/MagicianStuff/status/1477931054484893697)'
123
+ },
124
+ intents: ['GUILD_MESSAGES'],
125
+ partials: ['MESSAGE'],
126
+
127
+ preload: sequelize => {
128
+ sequelize.define('fginput', {
129
+ guild: {
130
+ type: DataTypes.STRING,
131
+ primaryKey: true
132
+ },
133
+ name: {
134
+ type: DataTypes.STRING,
135
+ primaryKey: true
136
+ },
137
+ createdBy: DataTypes.STRING,
138
+ game: DataTypes.STRING,
139
+ caption: DataTypes.STRING,
140
+ input: DataTypes.STRING
141
+ })
142
+ },
143
+
144
+ events: {
145
+ async messageCreate (global, message) {
146
+ const { client, config, sequelize } = global
147
+ if (message.author.id === client.user.id || !message.member) return
148
+
149
+ const guildId = message.guildId
150
+ const { prefix } = config[guildId]
151
+
152
+ if (message.content.startsWith(prefix)) {
153
+ const name = message.content.split(' ').pop().replace(prefix, '')
154
+ const row = builtin[name] || (
155
+ await sequelize.models.fginput.findOne({
156
+ where: { guild: message.guild.id, name }
157
+ })
158
+ )
159
+
160
+ if (row) {
161
+ const inputs = new Map([...basicInputs, ...gameInputs.get(row.game)])
162
+ sendInput(inputs, row.input.split(' '), message, row.caption)
163
+ }
164
+ }
165
+ }
166
+ },
167
+
168
+ commands: {
169
+ fgi: {
170
+ usage: 'fgi [game] [inputs]',
171
+ desc: 'Converts a list of inputs into an image',
172
+ example: 'fgi sf 236P 214K',
173
+ execute: async ({ param }, { message }) => {
174
+ const [, gameInput, i1] = param
175
+ if (!gameInput || !i1) return message.reply('Missing arguments. Example: >fgi sf 236P 214K')
176
+
177
+ const game = checkGame(gameInput)
178
+ if (!gameInputs.has(game)) return message.reply(`"${game}" is not a valid game. Available games: ${Array.from(gameInputs.keys()).join(' ')}`)
179
+
180
+ try {
181
+ const inputs = new Map([...basicInputs, ...gameInputs.get(game)])
182
+ const result = param.slice(2).map(i => solveInput(inputs, i.toLowerCase())).flat()
183
+
184
+ sendInput(inputs, result, message)
185
+ } catch (err) {
186
+ message.reply(err.message)
187
+ }
188
+ }
189
+ },
190
+ fgsave: {
191
+ usage: 'fgsave [game] [name] [inputs]',
192
+ desc: 'Saves a list of inputs into a command',
193
+ example: 'fgi sf testName 236P 214K',
194
+ execute: async ({ param, sequelize }, { message }) => {
195
+ const [, gameInput, name, i1] = param
196
+ if (!gameInput || !name || !i1) return message.reply('Missing arguments. Example: >fgi sf testName 236P 214K')
197
+
198
+ const game = checkGame(gameInput)
199
+ if (!gameInputs.has(game)) return message.reply(`"${game}" is not a valid game. Available games: ${Array.from(gameInputs.keys()).join(' ')}`)
200
+
201
+ try {
202
+ const inputs = new Map([...basicInputs, ...gameInputs.get(game)])
203
+ const input = param.slice(3).map(i => solveInput(inputs, i.toLowerCase())).flat().join(' ')
204
+
205
+ await sequelize.models.fginput.create({ guild: message.guild.id, name, createdBy: message.author.id, game, input })
206
+
207
+ message.channel.send(`Saved command "${input}" as "${name}"`)
208
+ } catch (err) {
209
+ message.reply(err.message)
210
+ }
211
+ }
212
+ },
213
+ fgcaption: {
214
+ usage: 'fgcaption [name] [caption]',
215
+ desc: 'Adds a caption to a saved input command',
216
+ example: 'fgcaption testName This is a caption',
217
+ execute: async ({ param, sequelize }, { message }) => {
218
+ const [, name, i1] = param
219
+ if (!name || !i1) return message.reply('Missing arguments. Example: >fgi testName This is a caption')
220
+
221
+ const row = await sequelize.models.fginput.findOne({
222
+ where: { guild: message.guild.id, name }
223
+ })
224
+
225
+ if (!row) return message.reply(`"${name}" is not a saved input list`)
226
+ row.caption = param.slice(2).join(' ')
227
+ await row.save()
228
+
229
+ message.channel.send(`Saved caption for input list "${name}"`)
230
+ }
231
+ },
232
+ fgglossary: {
233
+ usage: 'fgglossary [search term]',
234
+ desc: 'Searches for a term on Infil\'s Glossary',
235
+ example: 'fgglossary mexican uppercut',
236
+ execute: async ({ param, sequelize }, { message }) => {
237
+ const params = param.slice(1)
238
+ if (params.length === 0) return message.reply('Missing search term. Example: >fgglossary mexican uppercut')
239
+
240
+ const search = params.join(' ').toLowerCase()
241
+ const result = terms.filter(i => i.includes(search))
242
+ const url = `https://glossary.infil.net/?t=${params.join('%20').toLowerCase()}`
243
+
244
+ if (result.length === 0) return message.reply(`Term "${search}" not found`)
245
+ if (result.length === 1) return message.reply(`\`\`\`${glossary[result[0]].def}\`\`\`Source: <${url}>`)
246
+
247
+ message.reply(`Multiple terms found: ${url}`)
248
+ }
249
+ },
250
+ grab: {
251
+ usage: 'grab @user',
252
+ desc: 'Command grab someone',
253
+ example: 'grab @ChitoWarlock',
254
+ execute: async ({ param, sequelize }, { message }) => {
255
+ const { users: mentions } = message.mentions
256
+
257
+ if (mentions.size === 0) return message.reply('You forgot to mention who to grab')
258
+ if (mentions.size > 1) return message.reply('Cannot grab multiple enemies!')
259
+
260
+ const user = mentions.first()
261
+
262
+ const mainPath = grabs[getRandomInt(0, grabs.length - 1)]
263
+ const mainImage = await sharp(mainPath)
264
+ const options = await import(mainPath.replace('.png', '.json'))
265
+ const avatarImage = await sharp(await getBuffer(user.displayAvatarURL({ format: 'png' })))
266
+ .resize(options.resize)
267
+ .rotate(options.rotate, { background: { r: 0, g: 0, b: 0, alpha: 0 } })
268
+
269
+ const mainMetadata = await mainImage.metadata()
270
+ const { width, height } = mainMetadata
271
+
272
+ const canvas = await newCanvas(width, height)
273
+ .composite([
274
+ { input: await avatarImage.toBuffer(), ...options.composite },
275
+ { input: await mainImage.toBuffer() }
276
+ ])
277
+ .png().toBuffer()
278
+
279
+ message.reply({ files: [canvas] })
280
+ }
281
+ }
282
+ }
283
+ }
284
+
285
+ async function getBuffer (url) {
286
+ const input = (await axios({ url, responseType: 'arraybuffer' })).data
287
+ return input
288
+ }
289
+
290
+ function newCanvas (width, height) {
291
+ const channels = 4
292
+ const rgbaPixel = 0x00000000
293
+ const canvas = Buffer.alloc(width * height * channels, rgbaPixel)
294
+
295
+ return sharp(canvas, { raw: { width, height, channels } })
296
+ }
297
+
298
+ function getRandomInt (min, max) {
299
+ min = Math.ceil(min)
300
+ max = Math.floor(max)
301
+ return Math.floor(Math.random() * (max - min + 1)) + min
302
+ }
package/src/info.json CHANGED
@@ -1,33 +1,33 @@
1
- {
2
- "sizes": { "+": 55 },
3
-
4
- "builtin": {
5
- "37": {
6
- "game": "sf",
7
- "caption": "***LETS GO JUSTIN!***",
8
- "input": "6 6 6 6 6 6 6 >> 6 6 6 6 6 6 6 >> 8 6 j. hk >> 2 mk >> 623 mp >> 236 236 lk"
9
- }
10
- },
11
-
12
- "aliases": {
13
- "games": {
14
- "bbt": "bbtag",
15
- "db": "dbz"
16
- },
17
-
18
- "inputs": {
19
- "basic": {
20
- "doubleforward": [">>"]
21
- },
22
-
23
- "games": {
24
- "bbtag": {
25
- "throw": ["b","+","c"],
26
- "crb": ["d","+","p"],
27
- "airdash": ["a","+","b"],
28
- "reversal": ["a","+","d"]
29
- }
30
- }
31
- }
32
- }
1
+ {
2
+ "sizes": { "+": 55 },
3
+
4
+ "builtin": {
5
+ "37": {
6
+ "game": "sf",
7
+ "caption": "***LETS GO JUSTIN!***",
8
+ "input": "6 6 6 6 6 6 6 >> 6 6 6 6 6 6 6 >> 8 6 j. hk >> 2 mk >> 623 mp >> 236 236 lk"
9
+ }
10
+ },
11
+
12
+ "aliases": {
13
+ "games": {
14
+ "bbt": "bbtag",
15
+ "db": "dbz"
16
+ },
17
+
18
+ "inputs": {
19
+ "basic": {
20
+ "doubleforward": [">>"]
21
+ },
22
+
23
+ "games": {
24
+ "bbtag": {
25
+ "throw": ["b","+","c"],
26
+ "crb": ["d","+","p"],
27
+ "airdash": ["a","+","b"],
28
+ "reversal": ["a","+","d"]
29
+ }
30
+ }
31
+ }
32
+ }
33
33
  }
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file