@lotus-tree/fg-notation 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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