@lotus-tree/fg-notation 1.1.3 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. package/README.md +80 -67
  2. package/babel.config.js +6 -6
  3. package/lib/img/basic/+.png +0 -0
  4. package/lib/img/credits.txt +3 -3
  5. package/lib/img/games/bbtag/a.png +0 -0
  6. package/lib/img/games/bbtag/b.png +0 -0
  7. package/lib/img/games/bbtag/c.png +0 -0
  8. package/lib/img/games/bbtag/d.png +0 -0
  9. package/lib/img/games/bbtag/p.png +0 -0
  10. package/lib/img/grabs/omegarugal.json +5 -0
  11. package/lib/img/grabs/omegarugal.png +0 -0
  12. package/lib/img/grabs/ralph.json +5 -0
  13. package/lib/img/grabs/ralph.png +0 -0
  14. package/lib/index.js +324 -70
  15. package/lib/info.json +33 -0
  16. package/package.json +28 -25
  17. package/src/img/basic/+.png +0 -0
  18. package/src/img/credits.txt +3 -3
  19. package/src/img/games/bbtag/a.png +0 -0
  20. package/src/img/games/bbtag/b.png +0 -0
  21. package/src/img/games/bbtag/c.png +0 -0
  22. package/src/img/games/bbtag/d.png +0 -0
  23. package/src/img/games/bbtag/p.png +0 -0
  24. package/src/img/grabs/omegarugal.json +5 -0
  25. package/src/img/grabs/omegarugal.png +0 -0
  26. package/src/img/grabs/ralph.json +5 -0
  27. package/src/img/grabs/ralph.png +0 -0
  28. package/src/index.js +302 -200
  29. package/src/info.json +33 -0
  30. package/dev/img/basic/1.png +0 -0
  31. package/dev/img/basic/12369.png +0 -0
  32. package/dev/img/basic/1237.png +0 -0
  33. package/dev/img/basic/1632143.png +0 -0
  34. package/dev/img/basic/2.png +0 -0
  35. package/dev/img/basic/21.png +0 -0
  36. package/dev/img/basic/214.png +0 -0
  37. package/dev/img/basic/21478.png +0 -0
  38. package/dev/img/basic/23.png +0 -0
  39. package/dev/img/basic/236.png +0 -0
  40. package/dev/img/basic/23698.png +0 -0
  41. package/dev/img/basic/28.png +0 -0
  42. package/dev/img/basic/3.png +0 -0
  43. package/dev/img/basic/32147.png +0 -0
  44. package/dev/img/basic/3219.png +0 -0
  45. package/dev/img/basic/341236.png +0 -0
  46. package/dev/img/basic/346.png +0 -0
  47. package/dev/img/basic/360.png +0 -0
  48. package/dev/img/basic/4.png +0 -0
  49. package/dev/img/basic/41236.png +0 -0
  50. package/dev/img/basic/421.png +0 -0
  51. package/dev/img/basic/46.png +0 -0
  52. package/dev/img/basic/4618346.png +0 -0
  53. package/dev/img/basic/47896.png +0 -0
  54. package/dev/img/basic/5.png +0 -0
  55. package/dev/img/basic/6.png +0 -0
  56. package/dev/img/basic/623.png +0 -0
  57. package/dev/img/basic/63214.png +0 -0
  58. package/dev/img/basic/64.png +0 -0
  59. package/dev/img/basic/6428.png +0 -0
  60. package/dev/img/basic/69874.png +0 -0
  61. package/dev/img/basic/7.png +0 -0
  62. package/dev/img/basic/7891.png +0 -0
  63. package/dev/img/basic/8.png +0 -0
  64. package/dev/img/basic/81237.png +0 -0
  65. package/dev/img/basic/82.png +0 -0
  66. package/dev/img/basic/87412.png +0 -0
  67. package/dev/img/basic/89632.png +0 -0
  68. package/dev/img/basic/9.png +0 -0
  69. package/dev/img/basic/[1].png +0 -0
  70. package/dev/img/basic/[2].png +0 -0
  71. package/dev/img/basic/[2]8.png +0 -0
  72. package/dev/img/basic/[3].png +0 -0
  73. package/dev/img/basic/[4].png +0 -0
  74. package/dev/img/basic/[6].png +0 -0
  75. package/dev/img/basic/[7].png +0 -0
  76. package/dev/img/basic/[8].png +0 -0
  77. package/dev/img/basic/[9].png +0 -0
  78. package/dev/img/basic/air.png +0 -0
  79. package/dev/img/basic/doubleforward.png +0 -0
  80. package/dev/img/credits.txt +0 -4
  81. package/dev/img/games/bb/a.png +0 -0
  82. package/dev/img/games/bb/b.png +0 -0
  83. package/dev/img/games/bb/c.png +0 -0
  84. package/dev/img/games/bb/d.png +0 -0
  85. package/dev/img/games/dbz/a1.png +0 -0
  86. package/dev/img/games/dbz/a2.png +0 -0
  87. package/dev/img/games/dbz/h.png +0 -0
  88. package/dev/img/games/dbz/l.png +0 -0
  89. package/dev/img/games/dbz/m.png +0 -0
  90. package/dev/img/games/dbz/s.png +0 -0
  91. package/dev/img/games/dnf/a.png +0 -0
  92. package/dev/img/games/dnf/as.png +0 -0
  93. package/dev/img/games/dnf/b.png +0 -0
  94. package/dev/img/games/dnf/g.png +0 -0
  95. package/dev/img/games/dnf/ms.png +0 -0
  96. package/dev/img/games/dnf/s.png +0 -0
  97. package/dev/img/games/gbf/g.png +0 -0
  98. package/dev/img/games/gbf/h.png +0 -0
  99. package/dev/img/games/gbf/l.png +0 -0
  100. package/dev/img/games/gbf/m.png +0 -0
  101. package/dev/img/games/gbf/s.png +0 -0
  102. package/dev/img/games/gg/d.png +0 -0
  103. package/dev/img/games/gg/hs.png +0 -0
  104. package/dev/img/games/gg/k.png +0 -0
  105. package/dev/img/games/gg/p.png +0 -0
  106. package/dev/img/games/gg/rc.png +0 -0
  107. package/dev/img/games/gg/s.png +0 -0
  108. package/dev/img/games/kof/a.png +0 -0
  109. package/dev/img/games/kof/b.png +0 -0
  110. package/dev/img/games/kof/c.png +0 -0
  111. package/dev/img/games/kof/d.png +0 -0
  112. package/dev/img/games/kof/max.png +0 -0
  113. package/dev/img/games/mk/1.png +0 -0
  114. package/dev/img/games/mk/2.png +0 -0
  115. package/dev/img/games/mk/3.png +0 -0
  116. package/dev/img/games/mk/4.png +0 -0
  117. package/dev/img/games/sc/[a].png +0 -0
  118. package/dev/img/games/sc/[b].png +0 -0
  119. package/dev/img/games/sc/[g].png +0 -0
  120. package/dev/img/games/sc/[k].png +0 -0
  121. package/dev/img/games/sc/a.png +0 -0
  122. package/dev/img/games/sc/b.png +0 -0
  123. package/dev/img/games/sc/g.png +0 -0
  124. package/dev/img/games/sc/k.png +0 -0
  125. package/dev/img/games/sf/hk.png +0 -0
  126. package/dev/img/games/sf/hp.png +0 -0
  127. package/dev/img/games/sf/j..png +0 -0
  128. package/dev/img/games/sf/lk.png +0 -0
  129. package/dev/img/games/sf/lp.png +0 -0
  130. package/dev/img/games/sf/max.png +0 -0
  131. package/dev/img/games/sf/mk.png +0 -0
  132. package/dev/img/games/sf/mp.png +0 -0
  133. package/dev/img/games/sf/tap.png +0 -0
  134. package/dev/img/games/sg/hk.png +0 -0
  135. package/dev/img/games/sg/hp.png +0 -0
  136. package/dev/img/games/sg/k.png +0 -0
  137. package/dev/img/games/sg/lk.png +0 -0
  138. package/dev/img/games/sg/lp.png +0 -0
  139. package/dev/img/games/sg/mk.png +0 -0
  140. package/dev/img/games/sg/mp.png +0 -0
  141. package/dev/img/games/sg/p.png +0 -0
  142. package/dev/img/games/tfh/a.png +0 -0
  143. package/dev/img/games/tfh/b.png +0 -0
  144. package/dev/img/games/tfh/c.png +0 -0
  145. package/dev/img/games/tfh/d.png +0 -0
  146. package/dev/img/games/tkn/1.png +0 -0
  147. package/dev/img/games/tkn/12.png +0 -0
  148. package/dev/img/games/tkn/1234.png +0 -0
  149. package/dev/img/games/tkn/13.png +0 -0
  150. package/dev/img/games/tkn/14.png +0 -0
  151. package/dev/img/games/tkn/2.png +0 -0
  152. package/dev/img/games/tkn/23.png +0 -0
  153. package/dev/img/games/tkn/24.png +0 -0
  154. package/dev/img/games/tkn/3.png +0 -0
  155. package/dev/img/games/tkn/34.png +0 -0
  156. package/dev/img/games/tkn/4.png +0 -0
  157. package/dev/img/games/tkn/b.png +0 -0
  158. package/dev/img/games/tkn/d-b.png +0 -0
  159. package/dev/img/games/tkn/d-f.png +0 -0
  160. package/dev/img/games/tkn/d.png +0 -0
  161. package/dev/img/games/tkn/f.png +0 -0
  162. package/dev/img/games/tkn/o.png +0 -0
  163. package/dev/img/games/tkn/u-b.png +0 -0
  164. package/dev/img/games/tkn/u-f.png +0 -0
  165. package/dev/img/games/tkn/u.png +0 -0
  166. package/dev/img/preview.png +0 -0
  167. package/dev/index.js +0 -491
Binary file
Binary file
@@ -0,0 +1,5 @@
1
+ {
2
+ "resize":{"width":213, "height": 213},
3
+ "rotate": -33,
4
+ "composite": { "top": 50, "left": 35 }
5
+ }
Binary file
@@ -0,0 +1,5 @@
1
+ {
2
+ "resize":{"width":282, "height": 195},
3
+ "rotate": -90,
4
+ "composite": { "top": 600, "left": 270 }
5
+ }
Binary file
package/src/index.js CHANGED
@@ -1,200 +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
- const getJSON = bent('json')
8
- const imgPath = path.join(__dirname, 'img')
9
- const basicInputs = new Map()
10
- const gameInputs = new Map()
11
-
12
- let glossary = {}
13
- let terms = []
14
-
15
- getGlossary()
16
- setInterval(getGlossary, 5 * 60 * 1000)
17
-
18
- async function getGlossary () {
19
- const result = await getJSON('https://glossary.infil.net/json/glossary.json')
20
- const tempG = {}
21
- const tempT = []
22
-
23
- result.forEach(i => {
24
- const term = i.term.toLowerCase()
25
- tempG[term] = i
26
- tempT.push(term)
27
- })
28
-
29
- glossary = tempG
30
- terms = tempT
31
- }
32
-
33
- glob.sync(path.join(imgPath, 'basic/**'), { nodir: true })
34
- .forEach(p => {
35
- const input = p.split('/').pop().replace('.png', '')
36
- basicInputs.set(input, p)
37
- })
38
-
39
- basicInputs.set('>>', path.join(imgPath, 'basic/doubleforward.png'))
40
-
41
- glob.sync(path.join(imgPath, 'games/**'), { nodir: true })
42
- .forEach(p => {
43
- const { dir, name } = path.parse(path.relative(path.join(imgPath, 'games'), p))
44
-
45
- if (!gameInputs.has(dir)) gameInputs.set(dir, new Map())
46
- gameInputs.get(dir).set(name, p)
47
- })
48
-
49
- function solveInput (inputs, input) {
50
- if (inputs.has(input)) return [input]
51
-
52
- for (let i = 0; i < input.length; i++) {
53
- const s1 = input.slice(0, 0 - i)
54
- if (inputs.has(s1)) return [s1, ...solveInput(inputs, input.slice(0 - i))]
55
- }
56
-
57
- throw new Error(`Cannot find "${input}" as a recognizable input`)
58
- }
59
-
60
- async function sendInput (inputs, result, message, caption) {
61
- const canvas = await sharp({ create: { width: 152 * result.length, height: 152, channels: 4, background: 'transparent' } })
62
- .composite(result.map((it, index) =>
63
- ({ input: inputs.get(it), left: index * 152, top: 0, width: 152, height: 152 })
64
- ))
65
- .png()
66
- .toBuffer()
67
-
68
- return message.reply({ content: caption, files: [canvas] })
69
- }
70
-
71
- const builtin = {
72
- 37: {
73
- game: 'sf',
74
- caption: '***LETS GO JUSTIN!***',
75
- 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'
76
- }
77
- }
78
-
79
- export default {
80
- name: 'fg-notation',
81
- about: {
82
- name: 'FG Notation',
83
- 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)'
84
- },
85
- intents: ['GUILD_MESSAGES'],
86
- partials: ['MESSAGE'],
87
-
88
- preload: sequelize => {
89
- sequelize.define('fginput', {
90
- guild: {
91
- type: DataTypes.STRING,
92
- primaryKey: true
93
- },
94
- name: {
95
- type: DataTypes.STRING,
96
- primaryKey: true
97
- },
98
- createdBy: DataTypes.STRING,
99
- game: DataTypes.STRING,
100
- caption: DataTypes.STRING,
101
- input: DataTypes.STRING
102
- })
103
- },
104
-
105
- events: {
106
- async messageCreate (global, message) {
107
- const { client, config, sequelize } = global
108
- if (message.author.id === client.user.id || !message.member) return
109
-
110
- const guildId = message.guildId
111
- const { prefix } = config[guildId]
112
-
113
- if (message.content.startsWith(prefix)) {
114
- const name = message.content.split(' ').pop().replace(prefix, '')
115
- const row = builtin[name] || (
116
- await sequelize.models.fginput.findOne({
117
- where: { guild: message.guild.id, name }
118
- })
119
- )
120
-
121
- if (row) {
122
- const inputs = new Map([...basicInputs, ...gameInputs.get(row.game)])
123
- sendInput(inputs, row.input.split(' '), message, row.caption)
124
- }
125
- }
126
- }
127
- },
128
-
129
- commands: {
130
- fgi: {
131
- usage: 'fgi [game] [inputs]',
132
- desc: 'Converts a list of inputs into an image',
133
- example: 'fgi sf 236P 214K',
134
- execute: async ({ param }, { message }) => {
135
- const [, game, i1] = param
136
- if (!game || !i1) return message.reply('Missing arguments. Example: >fgi sf 236P 214K')
137
- if (!gameInputs.has(game)) return message.reply(`"${game}" is not a valid game. Available games: ${Array.from(gameInputs.keys()).join(' ')}`)
138
-
139
- const inputs = new Map([...basicInputs, ...gameInputs.get(game)])
140
- const result = param.slice(2).map(i => solveInput(inputs, i.toLowerCase())).flat()
141
-
142
- sendInput(inputs, result, message)
143
- }
144
- },
145
- fgsave: {
146
- usage: 'fgsave [game] [name] [inputs]',
147
- desc: 'Saves a list of inputs into a command',
148
- example: 'fgi sf testName 236P 214K',
149
- execute: async ({ param, sequelize }, { message }) => {
150
- const [, game, name, i1] = param
151
- if (!game || !name || !i1) return message.reply('Missing arguments. Example: >fgi sf testName 236P 214K')
152
- if (!gameInputs.has(game)) return message.reply(`"${game}" is not a valid game. Available games: ${Array.from(gameInputs.keys()).join(' ')}`)
153
-
154
- const inputs = new Map([...basicInputs, ...gameInputs.get(game)])
155
- const input = param.slice(3).map(i => solveInput(inputs, i.toLowerCase())).flat().join(' ')
156
-
157
- await sequelize.models.fginput.create({ guild: message.guild.id, name, createdBy: message.author.id, game, input })
158
-
159
- message.channel.send(`Saved command "${input}" as "${name}"`)
160
- }
161
- },
162
- fgcaption: {
163
- usage: 'fgcaption [name] [caption]',
164
- desc: 'Adds a caption to a saved input command',
165
- example: 'fgcaption testName This is a caption',
166
- execute: async ({ param, sequelize }, { message }) => {
167
- const [, name, i1] = param
168
- if (!name || !i1) return message.reply('Missing arguments. Example: >fgi testName This is a caption')
169
-
170
- const row = await sequelize.models.fginput.findOne({
171
- where: { guild: message.guild.id, name }
172
- })
173
-
174
- if (!row) return message.reply(`"${name}" is not a saved input list`)
175
- row.caption = param.slice(2).join(' ')
176
- await row.save()
177
-
178
- message.channel.send(`Saved caption for input list "${name}"`)
179
- }
180
- },
181
- fgglossary: {
182
- usage: 'fgglossary [search term]',
183
- desc: 'Searches for a term on Infil\'s Glossary',
184
- example: 'fgglossary mexican uppercut',
185
- execute: async ({ param, sequelize }, { message }) => {
186
- const params = param.slice(1)
187
- if (params.length === 0) return message.reply('Missing search term. Example: >fgglossary mexican uppercut')
188
-
189
- const search = params.join(' ').toLowerCase()
190
- const result = terms.filter(i => i.includes(search))
191
- const url = `https://glossary.infil.net/?t=${params.join('%20').toLowerCase()}`
192
-
193
- if (result.length === 0) return message.reply(`Term "${search}" not found`)
194
- if (result.length === 1) return message.reply(`\`\`\`${glossary[result[0]].def}\`\`\`Source: <${url}>`)
195
-
196
- message.reply(`Multiple terms found: ${url}`)
197
- }
198
- }
199
- }
200
- }
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 ADDED
@@ -0,0 +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
+ }
33
+ }
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file