simply-xp 1.1.0 → 1.1.5-beta
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.
- package/README.md +8 -25
- package/index.d.ts +66 -1
- package/package.json +1 -2
- package/simplyxp.js +31 -837
- package/{Fonts → src/Fonts}/Poppins-Regular.ttf +0 -0
- package/{Fonts → src/Fonts}/Poppins-SemiBold.ttf +0 -0
- package/src/addLevel.js +71 -0
- package/src/addXP.js +112 -0
- package/src/charts.js +83 -0
- package/src/connect.js +20 -0
- package/src/create.js +28 -0
- package/src/fetch.js +74 -0
- package/src/leaderboard.js +70 -0
- package/src/lvlRole.js +54 -0
- package/{models → src/models}/level.js +1 -1
- package/{models → src/models}/lvlrole.js +0 -0
- package/src/rank.js +285 -0
- package/src/reset.js +28 -0
- package/src/roleSetup.js +124 -0
- package/src/setLevel.js +71 -0
- package/src/setXP.js +51 -0
package/simplyxp.js
CHANGED
|
@@ -1,837 +1,31 @@
|
|
|
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
|
-
if (!guildID) throw new Error('[XP] User ID was not provided.')
|
|
33
|
-
|
|
34
|
-
let uzer = await levels.findOne({ user: userID, guild: guildID })
|
|
35
|
-
|
|
36
|
-
if (uzer) return false
|
|
37
|
-
|
|
38
|
-
const newuser = new levels({
|
|
39
|
-
user: userID,
|
|
40
|
-
guild: guildID
|
|
41
|
-
})
|
|
42
|
-
await newuser
|
|
43
|
-
.save()
|
|
44
|
-
.catch((e) => console.log(`[XP] Failed to save new use to database`))
|
|
45
|
-
|
|
46
|
-
return true
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* @param {string} userID
|
|
51
|
-
* @param {string} guildID
|
|
52
|
-
* @param {string} xp
|
|
53
|
-
*/
|
|
54
|
-
|
|
55
|
-
async function addXP(message, userID, guildID, xp) {
|
|
56
|
-
if (!userID) throw new Error('[XP] User ID was not provided.')
|
|
57
|
-
|
|
58
|
-
if (!guildID) throw new Error('[XP] Guild ID was not provided.')
|
|
59
|
-
|
|
60
|
-
if (!xp) throw new Error('[XP] XP amount is not provided.')
|
|
61
|
-
|
|
62
|
-
let { client } = message
|
|
63
|
-
|
|
64
|
-
let min
|
|
65
|
-
let max
|
|
66
|
-
if (xp.min) {
|
|
67
|
-
if (!xp.max)
|
|
68
|
-
throw new Error(
|
|
69
|
-
'[XP] XP min amount is provided but max amount is not provided.'
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
min = Number(xp.min)
|
|
73
|
-
|
|
74
|
-
if (Number(xp.min).toString() === 'NaN')
|
|
75
|
-
throw new Error('[XP] XP amount (min) is not a number.')
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (xp.max) {
|
|
79
|
-
if (!xp.min)
|
|
80
|
-
throw new Error(
|
|
81
|
-
'[XP] XP max amount is provided but min amount is not provided.'
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
max = Number(xp.max)
|
|
85
|
-
|
|
86
|
-
if (Number(xp.max).toString() === 'NaN')
|
|
87
|
-
throw new Error('[XP] XP amount (max) is not a number.')
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (xp.min && xp.max) {
|
|
91
|
-
let randomNumber = Math.floor(Math.random() * (max - min) + min)
|
|
92
|
-
|
|
93
|
-
xp = randomNumber
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const user = await levels.findOne({ user: userID, guild: guildID })
|
|
97
|
-
|
|
98
|
-
let lvl = Math.floor(0.1 * Math.sqrt(xp))
|
|
99
|
-
|
|
100
|
-
if (!user) {
|
|
101
|
-
const newUser = new levels({
|
|
102
|
-
user: userID,
|
|
103
|
-
guild: guildID,
|
|
104
|
-
xp: xp,
|
|
105
|
-
level: lvl
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
await newUser
|
|
109
|
-
.save()
|
|
110
|
-
.catch((e) => console.log(`[XP] Failed to save new user to database`))
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
level: 0,
|
|
114
|
-
exp: 0
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
let level1 = user.level
|
|
118
|
-
|
|
119
|
-
user.xp += parseInt(xp, 10)
|
|
120
|
-
user.level = Math.floor(0.1 * Math.sqrt(user.xp))
|
|
121
|
-
|
|
122
|
-
await user
|
|
123
|
-
.save()
|
|
124
|
-
.catch((e) =>
|
|
125
|
-
console.log(`[XP] Failed to add XP | User: ${userID} | Err: ${e}`)
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
let level = user.level
|
|
129
|
-
|
|
130
|
-
xp = user.xp
|
|
131
|
-
|
|
132
|
-
if (user.xp === 0 || Math.sign(user.xp) === -1) {
|
|
133
|
-
xp = 0
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (level1 !== level) {
|
|
137
|
-
let data = {
|
|
138
|
-
xp,
|
|
139
|
-
level,
|
|
140
|
-
userID,
|
|
141
|
-
guildID
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
client.emit('levelUp', message, data)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return {
|
|
148
|
-
level,
|
|
149
|
-
xp
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* @param {string} userID
|
|
155
|
-
* @param {string} guildID
|
|
156
|
-
* @param {string} xp
|
|
157
|
-
*/
|
|
158
|
-
|
|
159
|
-
async function setXP(userID, guildID, xp) {
|
|
160
|
-
if (!userID) throw new Error('[XP] User ID was not provided.')
|
|
161
|
-
|
|
162
|
-
if (!guildID) throw new Error('[XP] Guild ID was not provided.')
|
|
163
|
-
|
|
164
|
-
if (!xp) throw new Error('[XP] XP amount is not provided.')
|
|
165
|
-
|
|
166
|
-
if (Number(xp).toString() === 'NaN')
|
|
167
|
-
throw new Error('[XP] XP amount is not a number.')
|
|
168
|
-
|
|
169
|
-
const user = await levels.findOne({ user: userID, guild: guildID })
|
|
170
|
-
|
|
171
|
-
let lvl = Math.floor(0.1 * Math.sqrt(xp))
|
|
172
|
-
|
|
173
|
-
if (!user) {
|
|
174
|
-
const newUser = new levels({
|
|
175
|
-
user: userID,
|
|
176
|
-
guild: guildID,
|
|
177
|
-
xp: xp,
|
|
178
|
-
level: lvl
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
await newUser
|
|
182
|
-
.save()
|
|
183
|
-
.catch((e) => console.log(`[XP] Failed to save new use to database`))
|
|
184
|
-
|
|
185
|
-
return {
|
|
186
|
-
xp: 0
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
user.xp = xp
|
|
190
|
-
user.level = Math.floor(0.1 * Math.sqrt(user.xp))
|
|
191
|
-
|
|
192
|
-
await user
|
|
193
|
-
.save()
|
|
194
|
-
.catch((e) =>
|
|
195
|
-
console.log(`[XP] Failed to set XP | User: ${userID} | Err: ${e}`)
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
return { xp }
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* @param {Discord.Client} client
|
|
203
|
-
* @param {string} guildID
|
|
204
|
-
*/
|
|
205
|
-
|
|
206
|
-
async function leaderboard(client, guildID) {
|
|
207
|
-
if (!guildID) throw new Error('[XP] Guild ID was not provided.')
|
|
208
|
-
|
|
209
|
-
let g = client.guilds.cache.get(guildID)
|
|
210
|
-
|
|
211
|
-
let wo = g.members.cache.size
|
|
212
|
-
|
|
213
|
-
var lead = await levels
|
|
214
|
-
.find({
|
|
215
|
-
guild: guildID
|
|
216
|
-
})
|
|
217
|
-
.sort([['xp', 'descending']])
|
|
218
|
-
.exec()
|
|
219
|
-
|
|
220
|
-
let leaderboard = lead.slice(0, wo)
|
|
221
|
-
|
|
222
|
-
const led = []
|
|
223
|
-
|
|
224
|
-
function shortener(count) {
|
|
225
|
-
const COUNT_ABBRS = ['', 'k', 'M', 'T']
|
|
226
|
-
|
|
227
|
-
const i = 0 === count ? count : Math.floor(Math.log(count) / Math.log(1000))
|
|
228
|
-
let result = parseFloat((count / Math.pow(1000, i)).toFixed(2))
|
|
229
|
-
result += `${COUNT_ABBRS[i]}`
|
|
230
|
-
return result
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
leaderboard.map((key) => {
|
|
234
|
-
let user = g.members.cache.get(key.user)
|
|
235
|
-
|
|
236
|
-
let shortXP = shortener(key.xp)
|
|
237
|
-
|
|
238
|
-
if (!user) return
|
|
239
|
-
|
|
240
|
-
led.push({
|
|
241
|
-
guildID: key.guild,
|
|
242
|
-
userID: key.user,
|
|
243
|
-
xp: key.xp,
|
|
244
|
-
shortxp: shortXP,
|
|
245
|
-
level: key.level,
|
|
246
|
-
position:
|
|
247
|
-
leaderboard.findIndex(
|
|
248
|
-
(i) => i.guild === key.guild && i.user === key.user
|
|
249
|
-
) + 1,
|
|
250
|
-
username: user.user.username,
|
|
251
|
-
tag: user.user.tag
|
|
252
|
-
})
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
return led
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* @param {string} userID
|
|
260
|
-
* @param {string} guildID
|
|
261
|
-
*/
|
|
262
|
-
|
|
263
|
-
async function fetch(userID, guildID) {
|
|
264
|
-
if (!userID) throw new Error('[XP] User ID was not provided.')
|
|
265
|
-
|
|
266
|
-
if (!guildID) throw new Error('[XP] Guild ID was not provided.')
|
|
267
|
-
|
|
268
|
-
let user = await levels.findOne({
|
|
269
|
-
user: userID,
|
|
270
|
-
guild: guildID
|
|
271
|
-
})
|
|
272
|
-
if (!user) {
|
|
273
|
-
user = new levels({
|
|
274
|
-
user: userID,
|
|
275
|
-
guild: guildID,
|
|
276
|
-
xp: 0,
|
|
277
|
-
level: 0
|
|
278
|
-
})
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
const leaderboard = await levels
|
|
282
|
-
.find({
|
|
283
|
-
guild: guildID
|
|
284
|
-
})
|
|
285
|
-
.sort([['xp', 'descending']])
|
|
286
|
-
.exec()
|
|
287
|
-
|
|
288
|
-
if (user === null)
|
|
289
|
-
return {
|
|
290
|
-
level: 0,
|
|
291
|
-
xp: 0,
|
|
292
|
-
reqxp: 100,
|
|
293
|
-
rank: leaderboard.findIndex((i) => i.user === userID) + 1,
|
|
294
|
-
shortxp: 0,
|
|
295
|
-
shortreq: 100
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
user.position = leaderboard.findIndex((i) => i.user === userID) + 1
|
|
299
|
-
|
|
300
|
-
let targetxp = user.level + 1
|
|
301
|
-
|
|
302
|
-
let target = targetxp * targetxp * 100
|
|
303
|
-
|
|
304
|
-
function shortener(count) {
|
|
305
|
-
const COUNT_ABBRS = ['', 'k', 'M', 'T']
|
|
306
|
-
|
|
307
|
-
const i = 0 === count ? count : Math.floor(Math.log(count) / Math.log(1000))
|
|
308
|
-
let result = parseFloat((count / Math.pow(1000, i)).toFixed(2))
|
|
309
|
-
result += `${COUNT_ABBRS[i]}`
|
|
310
|
-
return result
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
let shortXP = shortener(user.xp)
|
|
314
|
-
|
|
315
|
-
let shortReqXP = shortener(target)
|
|
316
|
-
|
|
317
|
-
return {
|
|
318
|
-
level: user.level,
|
|
319
|
-
xp: user.xp,
|
|
320
|
-
reqxp: target,
|
|
321
|
-
rank: user.position,
|
|
322
|
-
shortxp: shortXP,
|
|
323
|
-
shortreq: shortReqXP
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* @param {Discord.Message} message
|
|
329
|
-
* @param {import('./index').chartsOptions} options
|
|
330
|
-
*/
|
|
331
|
-
|
|
332
|
-
async function charts(message, options = []) {
|
|
333
|
-
let { client } = message
|
|
334
|
-
const ChartJSImage = require('chart.js-image')
|
|
335
|
-
|
|
336
|
-
let post = Number(options.position) || 5
|
|
337
|
-
|
|
338
|
-
let uzer = []
|
|
339
|
-
let xxp = []
|
|
340
|
-
await leaderboard(client, message.guild.id).then((lead) => {
|
|
341
|
-
lead.forEach((m) => {
|
|
342
|
-
if (m.position <= post) {
|
|
343
|
-
xxp.push(m.xp)
|
|
344
|
-
uzer.push(m.tag)
|
|
345
|
-
}
|
|
346
|
-
})
|
|
347
|
-
})
|
|
348
|
-
|
|
349
|
-
const line_chart = ChartJSImage()
|
|
350
|
-
.chart({
|
|
351
|
-
type: options.type || 'bar',
|
|
352
|
-
data: {
|
|
353
|
-
labels: uzer,
|
|
354
|
-
datasets: [
|
|
355
|
-
{
|
|
356
|
-
label: 'Leaderboards',
|
|
357
|
-
data: xxp,
|
|
358
|
-
backgroundColor: [
|
|
359
|
-
'rgba(255, 99, 132, 0.5)',
|
|
360
|
-
'rgba(255, 159, 64, 0.5)',
|
|
361
|
-
'rgba(255, 205, 86, 0.5)',
|
|
362
|
-
'rgba(75, 192, 192, 0.5)',
|
|
363
|
-
'rgba(54, 162, 235, 0.5)',
|
|
364
|
-
'rgba(153, 102, 255, 0.5)',
|
|
365
|
-
'rgb(201, 203, 207, 0.5)'
|
|
366
|
-
],
|
|
367
|
-
borderColor: [
|
|
368
|
-
'rgb(255, 99, 132)',
|
|
369
|
-
'rgb(255, 159, 64)',
|
|
370
|
-
'rgb(255, 205, 86)',
|
|
371
|
-
'rgb(75, 192, 192)',
|
|
372
|
-
'rgb(54, 162, 235)',
|
|
373
|
-
'rgb(153, 102, 255)',
|
|
374
|
-
'rgb(201, 203, 207)'
|
|
375
|
-
],
|
|
376
|
-
borderWidth: 2
|
|
377
|
-
}
|
|
378
|
-
]
|
|
379
|
-
},
|
|
380
|
-
options: {
|
|
381
|
-
plugins: {
|
|
382
|
-
legend: {
|
|
383
|
-
labels: {
|
|
384
|
-
font: {
|
|
385
|
-
family: 'Courier New'
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
},
|
|
390
|
-
title: {
|
|
391
|
-
display: true,
|
|
392
|
-
text: 'XP Datasheet'
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
})
|
|
396
|
-
.backgroundColor(options.background || '#2F3136')
|
|
397
|
-
.width(940) // 500px
|
|
398
|
-
.height(520) // 300px
|
|
399
|
-
|
|
400
|
-
const attachment = new Discord.MessageAttachment(
|
|
401
|
-
line_chart.toURL(),
|
|
402
|
-
`chart.png`
|
|
403
|
-
)
|
|
404
|
-
return attachment
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* @param {Discord.Message} message
|
|
409
|
-
* @param {string} userID
|
|
410
|
-
* @param {string} guildID
|
|
411
|
-
* @param {import('./index').rankOptions} options
|
|
412
|
-
*/
|
|
413
|
-
|
|
414
|
-
async function rank(message, userID, guildID, options = []) {
|
|
415
|
-
if (!userID) throw new Error('[XP] User ID was not provided.')
|
|
416
|
-
|
|
417
|
-
if (!guildID) throw new Error('[XP] Guild ID was not provided.')
|
|
418
|
-
|
|
419
|
-
const user = await levels.findOne({
|
|
420
|
-
user: userID,
|
|
421
|
-
guild: guildID
|
|
422
|
-
})
|
|
423
|
-
if (!user) return false
|
|
424
|
-
|
|
425
|
-
const leaderboard = await levels
|
|
426
|
-
.find({
|
|
427
|
-
guild: guildID
|
|
428
|
-
})
|
|
429
|
-
.sort([['xp', 'descending']])
|
|
430
|
-
.exec()
|
|
431
|
-
|
|
432
|
-
user.position = leaderboard.findIndex((i) => i.user === userID) + 1
|
|
433
|
-
|
|
434
|
-
let targetxp = user.level + 1
|
|
435
|
-
|
|
436
|
-
let target = targetxp * targetxp * 100
|
|
437
|
-
|
|
438
|
-
return rankCard(message, {
|
|
439
|
-
level: user.level,
|
|
440
|
-
currentXP: user.xp,
|
|
441
|
-
neededXP: target,
|
|
442
|
-
rank: user.position,
|
|
443
|
-
background: options.background,
|
|
444
|
-
color: options.color,
|
|
445
|
-
member: message.guild.members.cache.get(userID)?.user
|
|
446
|
-
})
|
|
447
|
-
|
|
448
|
-
async function rankCard(message, options = []) {
|
|
449
|
-
try {
|
|
450
|
-
const Canvas = require('canvas')
|
|
451
|
-
const { registerFont } = require('canvas')
|
|
452
|
-
registerFont(join(__dirname, 'Fonts', 'Poppins-SemiBold.ttf'), {
|
|
453
|
-
family: 'Poppins-Regular'
|
|
454
|
-
})
|
|
455
|
-
registerFont(join(__dirname, 'Fonts', 'Poppins-SemiBold.ttf'), {
|
|
456
|
-
family: 'Poppins-Bold'
|
|
457
|
-
})
|
|
458
|
-
|
|
459
|
-
function shortener(count) {
|
|
460
|
-
const COUNT_ABBRS = ['', 'k', 'M', 'T']
|
|
461
|
-
|
|
462
|
-
const i =
|
|
463
|
-
0 === count ? count : Math.floor(Math.log(count) / Math.log(1000))
|
|
464
|
-
let result = parseFloat((count / Math.pow(1000, i)).toFixed(2))
|
|
465
|
-
result += `${COUNT_ABBRS[i]}`
|
|
466
|
-
return result
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
const member = options.member
|
|
470
|
-
|
|
471
|
-
const canvas = Canvas.createCanvas(1080, 400),
|
|
472
|
-
ctx = canvas.getContext('2d')
|
|
473
|
-
|
|
474
|
-
const name = member.tag
|
|
475
|
-
const noSymbols = (string) => string.replace(/[\u007f-\uffff]/g, '')
|
|
476
|
-
|
|
477
|
-
let BackgroundRadius = '20',
|
|
478
|
-
BackGroundImg =
|
|
479
|
-
options.background ||
|
|
480
|
-
'https://media.discordapp.net/attachments/868506665102762034/876750913866461185/photo-1579546929518-9e396f3cc809.png?width=640&height=427',
|
|
481
|
-
AttachmentName = 'rank.png',
|
|
482
|
-
Username = noSymbols(name),
|
|
483
|
-
AvatarRoundRadius = '50',
|
|
484
|
-
DrawLayerColor = '#000000',
|
|
485
|
-
DrawLayerOpacity = '0.4',
|
|
486
|
-
BoxColor = options.color || '#096DD1',
|
|
487
|
-
LevelBarFill = '#ffffff',
|
|
488
|
-
LevelBarBackground = '#ffffff',
|
|
489
|
-
Rank = options.rank,
|
|
490
|
-
TextEXP = shortener(options.currentXP) + ' xp',
|
|
491
|
-
LvlText = `Level ${shortener(options.level)}`,
|
|
492
|
-
BarRadius = '20',
|
|
493
|
-
TextXpNeded = '{current}/{needed}',
|
|
494
|
-
CurrentXP = options.currentXP,
|
|
495
|
-
NeededXP = options.neededXP
|
|
496
|
-
|
|
497
|
-
ctx.beginPath()
|
|
498
|
-
ctx.moveTo(0 + Number(BackgroundRadius), 0)
|
|
499
|
-
ctx.lineTo(0 + 1080 - Number(BackgroundRadius), 0)
|
|
500
|
-
ctx.quadraticCurveTo(0 + 1080, 0, 0 + 1080, 0 + Number(BackgroundRadius))
|
|
501
|
-
ctx.lineTo(0 + 1080, 0 + 400 - Number(BackgroundRadius))
|
|
502
|
-
ctx.quadraticCurveTo(
|
|
503
|
-
0 + 1080,
|
|
504
|
-
0 + 400,
|
|
505
|
-
0 + 1080 - Number(BackgroundRadius),
|
|
506
|
-
0 + 400
|
|
507
|
-
)
|
|
508
|
-
|
|
509
|
-
ctx.lineTo(0 + Number(BackgroundRadius), 0 + 400)
|
|
510
|
-
ctx.quadraticCurveTo(0, 0 + 400, 0, 0 + 400 - Number(BackgroundRadius))
|
|
511
|
-
ctx.lineTo(0, 0 + Number(BackgroundRadius))
|
|
512
|
-
ctx.quadraticCurveTo(0, 0, 0 + Number(BackgroundRadius), 0)
|
|
513
|
-
ctx.closePath()
|
|
514
|
-
ctx.clip()
|
|
515
|
-
ctx.fillStyle = '#000000'
|
|
516
|
-
ctx.fillRect(0, 0, 1080, 400)
|
|
517
|
-
let background = await Canvas.loadImage(BackGroundImg)
|
|
518
|
-
ctx.globalAlpha = 0.7
|
|
519
|
-
ctx.drawImage(background, 0, 0, 1080, 400)
|
|
520
|
-
ctx.restore()
|
|
521
|
-
|
|
522
|
-
ctx.fillStyle = DrawLayerColor
|
|
523
|
-
ctx.globalAlpha = DrawLayerOpacity
|
|
524
|
-
ctx.fillRect(40, 0, 240, canvas.height)
|
|
525
|
-
ctx.globalAlpha = 1
|
|
526
|
-
|
|
527
|
-
function RoundedBox(ctx, x, y, width, height, radius) {
|
|
528
|
-
ctx.beginPath()
|
|
529
|
-
ctx.moveTo(x + radius, y)
|
|
530
|
-
ctx.lineTo(x + width - radius, y)
|
|
531
|
-
ctx.quadraticCurveTo(x + width, y, x + width, y + radius)
|
|
532
|
-
ctx.lineTo(x + width, y + height - radius)
|
|
533
|
-
ctx.quadraticCurveTo(
|
|
534
|
-
x + width,
|
|
535
|
-
y + height,
|
|
536
|
-
x + width - radius,
|
|
537
|
-
y + height
|
|
538
|
-
)
|
|
539
|
-
ctx.lineTo(x + radius, y + height)
|
|
540
|
-
ctx.quadraticCurveTo(x, y + height, x, y + height - radius)
|
|
541
|
-
ctx.lineTo(x, y + radius)
|
|
542
|
-
ctx.quadraticCurveTo(x, y, x + radius, y)
|
|
543
|
-
ctx.closePath()
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
let avatar = await Canvas.loadImage(
|
|
547
|
-
member.displayAvatarURL({ dynamic: true, format: 'png' })
|
|
548
|
-
)
|
|
549
|
-
ctx.save()
|
|
550
|
-
RoundedBox(ctx, 40 + 30, 30, 180, 180, Number(AvatarRoundRadius))
|
|
551
|
-
ctx.strokeStyle = BoxColor
|
|
552
|
-
ctx.lineWidth = '10'
|
|
553
|
-
ctx.stroke()
|
|
554
|
-
ctx.clip()
|
|
555
|
-
ctx.drawImage(avatar, 40 + 30, 30, 180, 180)
|
|
556
|
-
ctx.restore()
|
|
557
|
-
|
|
558
|
-
ctx.save()
|
|
559
|
-
RoundedBox(ctx, 40 + 30, 30 + 180 + 30 + 50 + 30, 180, 50, 20)
|
|
560
|
-
ctx.strokeStyle = '#BFC85A22'
|
|
561
|
-
ctx.stroke()
|
|
562
|
-
ctx.clip()
|
|
563
|
-
ctx.fillStyle = BoxColor
|
|
564
|
-
ctx.globalAlpha = '1'
|
|
565
|
-
ctx.fillRect(40 + 30, 30 + 180 + 30 + 50 + 30, 180, 50)
|
|
566
|
-
ctx.globalAlpha = 1
|
|
567
|
-
ctx.fillStyle = '#ffffff'
|
|
568
|
-
ctx.font = '32px "Poppins-Bold"'
|
|
569
|
-
ctx.textAlign = 'center'
|
|
570
|
-
ctx.fillText(TextEXP, 40 + 30 + 180 / 2, 30 + 180 + 30 + 30 + 50 + 38)
|
|
571
|
-
ctx.restore()
|
|
572
|
-
|
|
573
|
-
ctx.save()
|
|
574
|
-
RoundedBox(ctx, 40 + 30, 30 + 180 + 30, 180, 50, 20)
|
|
575
|
-
ctx.strokeStyle = '#BFC85A22'
|
|
576
|
-
ctx.stroke()
|
|
577
|
-
ctx.clip()
|
|
578
|
-
ctx.fillStyle = BoxColor
|
|
579
|
-
ctx.globalAlpha = '1'
|
|
580
|
-
ctx.fillRect(40 + 30, 30 + 180 + 30, 180, 50, 50)
|
|
581
|
-
ctx.globalAlpha = 1
|
|
582
|
-
ctx.fillStyle = '#ffffff'
|
|
583
|
-
ctx.font = '32px "Poppins-Bold"'
|
|
584
|
-
ctx.textAlign = 'center'
|
|
585
|
-
ctx.fillText(LvlText, 40 + 30 + 180 / 2, 30 + 180 + 30 + 38)
|
|
586
|
-
ctx.restore()
|
|
587
|
-
|
|
588
|
-
ctx.save()
|
|
589
|
-
ctx.textAlign = 'left'
|
|
590
|
-
ctx.fillStyle = '#ffffff'
|
|
591
|
-
ctx.shadowColor = '#000000'
|
|
592
|
-
ctx.shadowBlur = 15
|
|
593
|
-
ctx.shadowOffsetX = 1
|
|
594
|
-
ctx.shadowOffsetY = 1
|
|
595
|
-
ctx.font = '39px "Poppins-Bold"'
|
|
596
|
-
ctx.fillText(Username, 390, 80)
|
|
597
|
-
ctx.restore()
|
|
598
|
-
|
|
599
|
-
ctx.save()
|
|
600
|
-
ctx.textAlign = 'right'
|
|
601
|
-
ctx.fillStyle = '#ffffff'
|
|
602
|
-
ctx.shadowColor = '#000000'
|
|
603
|
-
ctx.shadowBlur = 15
|
|
604
|
-
ctx.shadowOffsetX = 1
|
|
605
|
-
ctx.shadowOffsetY = 1
|
|
606
|
-
ctx.font = '55px "Poppins-Bold"'
|
|
607
|
-
ctx.fillText('#' + Rank, canvas.width - 50 - 5, 80)
|
|
608
|
-
ctx.restore()
|
|
609
|
-
|
|
610
|
-
ctx.save()
|
|
611
|
-
RoundedBox(ctx, 390, 305, 660, 70, Number(20))
|
|
612
|
-
ctx.strokeStyle = '#BFC85A22'
|
|
613
|
-
ctx.stroke()
|
|
614
|
-
ctx.clip()
|
|
615
|
-
ctx.fillStyle = '#ffffff'
|
|
616
|
-
ctx.font = '45px "Poppins-Bold"'
|
|
617
|
-
ctx.fillText(message.guild.name, 75 + 450, 355)
|
|
618
|
-
ctx.globalAlpha = '0.2'
|
|
619
|
-
ctx.fillRect(390, 305, 660, 70)
|
|
620
|
-
ctx.restore()
|
|
621
|
-
|
|
622
|
-
ctx.save()
|
|
623
|
-
RoundedBox(ctx, 390, 145, 660, 50, Number(BarRadius))
|
|
624
|
-
ctx.strokeStyle = '#BFC85A22'
|
|
625
|
-
ctx.stroke()
|
|
626
|
-
ctx.clip()
|
|
627
|
-
ctx.fillStyle = LevelBarBackground
|
|
628
|
-
ctx.globalAlpha = '0.2'
|
|
629
|
-
ctx.fillRect(390, 145, 660, 50, 50)
|
|
630
|
-
ctx.restore()
|
|
631
|
-
|
|
632
|
-
const percent = (100 * CurrentXP) / NeededXP
|
|
633
|
-
const progress = (percent * 660) / 100
|
|
634
|
-
|
|
635
|
-
ctx.save()
|
|
636
|
-
RoundedBox(ctx, 390, 145, progress, 50, Number(BarRadius))
|
|
637
|
-
ctx.strokeStyle = '#BFC85A22'
|
|
638
|
-
ctx.stroke()
|
|
639
|
-
ctx.clip()
|
|
640
|
-
ctx.fillStyle = LevelBarFill
|
|
641
|
-
ctx.globalAlpha = '0.5'
|
|
642
|
-
ctx.fillRect(390, 145, progress, 50, 50)
|
|
643
|
-
ctx.restore()
|
|
644
|
-
|
|
645
|
-
ctx.save()
|
|
646
|
-
ctx.textAlign = 'left'
|
|
647
|
-
ctx.fillStyle = '#ffffff'
|
|
648
|
-
ctx.globalAlpha = '0.8'
|
|
649
|
-
ctx.font = '30px "Poppins-Bold"'
|
|
650
|
-
ctx.fillText('Next Level: ' + shortener(NeededXP) + ' xp', 390, 230)
|
|
651
|
-
ctx.restore()
|
|
652
|
-
|
|
653
|
-
const latestXP = Number(CurrentXP) - Number(NeededXP)
|
|
654
|
-
const textXPEdited = TextXpNeded.replace(/{needed}/g, shortener(NeededXP))
|
|
655
|
-
.replace(/{current}/g, shortener(CurrentXP))
|
|
656
|
-
.replace(/{latest}/g, latestXP)
|
|
657
|
-
ctx.textAlign = 'center'
|
|
658
|
-
ctx.fillStyle = '#474747'
|
|
659
|
-
ctx.globalAlpha = 1
|
|
660
|
-
ctx.font = '30px "Poppins-Bold"'
|
|
661
|
-
ctx.fillText(textXPEdited, 730, 180)
|
|
662
|
-
|
|
663
|
-
const attachment = new Discord.MessageAttachment(
|
|
664
|
-
canvas.toBuffer(),
|
|
665
|
-
AttachmentName
|
|
666
|
-
)
|
|
667
|
-
|
|
668
|
-
return attachment
|
|
669
|
-
} catch (err) {
|
|
670
|
-
console.log(`[XP] Error Occured. | rankCard | Error: ${err.stack}`)
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
class roleSetup {
|
|
676
|
-
/**
|
|
677
|
-
* @param {Discord.Client} client
|
|
678
|
-
* @param {string} guildID
|
|
679
|
-
* @param {import('./index').lvladdOptions} options
|
|
680
|
-
*/
|
|
681
|
-
|
|
682
|
-
static async add(client, guildID, options = []) {
|
|
683
|
-
let rol = await lrole.findOne({
|
|
684
|
-
gid: guildID,
|
|
685
|
-
lvlrole: {
|
|
686
|
-
lvl: options.level,
|
|
687
|
-
role: options.role
|
|
688
|
-
}
|
|
689
|
-
})
|
|
690
|
-
|
|
691
|
-
let g = client.guilds.cache.get(guildID)
|
|
692
|
-
|
|
693
|
-
let roll = g.roles.cache.find((r) => r.id === options.role)
|
|
694
|
-
|
|
695
|
-
if (roll) {
|
|
696
|
-
if (rol) throw new Error('Level Already Exist. Use delete')
|
|
697
|
-
else if (!rol) {
|
|
698
|
-
let newrol = new lrole({
|
|
699
|
-
gid: guildID,
|
|
700
|
-
lvlrole: {
|
|
701
|
-
lvl: options.level,
|
|
702
|
-
role: options.role
|
|
703
|
-
}
|
|
704
|
-
})
|
|
705
|
-
|
|
706
|
-
await newrol
|
|
707
|
-
.save()
|
|
708
|
-
.catch((e) =>
|
|
709
|
-
console.log(`[XP] Failed to remove lvlrole to database | ${e}`)
|
|
710
|
-
)
|
|
711
|
-
|
|
712
|
-
return 'Added the role to levelRole'
|
|
713
|
-
}
|
|
714
|
-
} else {
|
|
715
|
-
throw new Error(
|
|
716
|
-
'Role ID is invalid. | ' +
|
|
717
|
-
`Guild ID: ${guildID} | Role ID: ${options.role}`
|
|
718
|
-
)
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
/**
|
|
723
|
-
* @param {Discord.Client} client
|
|
724
|
-
* @param {string} guildID
|
|
725
|
-
* @param {import('./index').lvlremoveOptions} options
|
|
726
|
-
*/
|
|
727
|
-
|
|
728
|
-
static async remove(client, guildID, options = []) {
|
|
729
|
-
let rol = await lrole.find({
|
|
730
|
-
gid: guildID
|
|
731
|
-
})
|
|
732
|
-
|
|
733
|
-
for (let i = 0; rol.length > i; i++) {
|
|
734
|
-
for (let o = 0; rol[i].lvlrole.length > o; o++) {
|
|
735
|
-
if (rol[i].lvlrole[o].lvl === options.level) {
|
|
736
|
-
let yikes = await lrole.findOneAndUpdate(
|
|
737
|
-
{
|
|
738
|
-
gid: guildID
|
|
739
|
-
},
|
|
740
|
-
{
|
|
741
|
-
$pull: { lvlrole: { lvl: options.level } }
|
|
742
|
-
}
|
|
743
|
-
)
|
|
744
|
-
|
|
745
|
-
await yikes
|
|
746
|
-
.save()
|
|
747
|
-
.catch((e) =>
|
|
748
|
-
console.log(`[XP] Failed to remove lvlrole to database | ${e}`)
|
|
749
|
-
)
|
|
750
|
-
|
|
751
|
-
return 'Deleting the role from levelRole'
|
|
752
|
-
} else if (o + 1 === rol[i].lvlrole.length) {
|
|
753
|
-
if (rol[i].lvlrole[o].lvl === options.level) {
|
|
754
|
-
let yikes = await lrole.findOneAndUpdate(
|
|
755
|
-
{
|
|
756
|
-
gid: guildID
|
|
757
|
-
},
|
|
758
|
-
{
|
|
759
|
-
$pull: { lvlrole: { lvl: options.level } }
|
|
760
|
-
}
|
|
761
|
-
)
|
|
762
|
-
|
|
763
|
-
await yikes
|
|
764
|
-
.save()
|
|
765
|
-
.catch((e) =>
|
|
766
|
-
console.log(`[XP] Failed to remove lvlrole to database | ${e}`)
|
|
767
|
-
)
|
|
768
|
-
|
|
769
|
-
return 'Deleting the role from levelRole'
|
|
770
|
-
} else throw new Error('Level Role with this level not found')
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
/**
|
|
778
|
-
* @param {Discord.Message} message
|
|
779
|
-
* @param {string} userID
|
|
780
|
-
* @param {string} guildID
|
|
781
|
-
*/
|
|
782
|
-
|
|
783
|
-
async function lvlRole(message, userID, guildID) {
|
|
784
|
-
let e = await lrole.find({
|
|
785
|
-
gid: guildID
|
|
786
|
-
})
|
|
787
|
-
|
|
788
|
-
if (!e) return
|
|
789
|
-
|
|
790
|
-
let user = await levels.findOne({
|
|
791
|
-
user: userID,
|
|
792
|
-
guild: guildID
|
|
793
|
-
})
|
|
794
|
-
if (!user) {
|
|
795
|
-
const newuser = new levels({
|
|
796
|
-
user: userID,
|
|
797
|
-
guild: guildID
|
|
798
|
-
})
|
|
799
|
-
|
|
800
|
-
await newuser
|
|
801
|
-
.save()
|
|
802
|
-
.catch((e) => console.log(`[XP] Failed to save new user to database`))
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
e.forEach((ee) => {
|
|
806
|
-
ee = ee.lvlrole
|
|
807
|
-
|
|
808
|
-
ee.forEach((xd) => {
|
|
809
|
-
if (user && user.level >= Number(xd.lvl)) {
|
|
810
|
-
let u = message.guild.members.cache.get(userID)
|
|
811
|
-
|
|
812
|
-
let real = message.guild.roles.cache.find((r) => r.id === xd.role)
|
|
813
|
-
if (!real) return
|
|
814
|
-
else {
|
|
815
|
-
u.roles.add(real).catch((err) => {
|
|
816
|
-
message.channel.send(
|
|
817
|
-
'[XP] ERROR: Role is higher than me. `MISSING_PERMISSIONS`'
|
|
818
|
-
)
|
|
819
|
-
})
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
})
|
|
823
|
-
})
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
module.exports = {
|
|
827
|
-
connect: connect,
|
|
828
|
-
create: create,
|
|
829
|
-
charts: charts,
|
|
830
|
-
addXP: addXP,
|
|
831
|
-
rank: rank,
|
|
832
|
-
fetch: fetch,
|
|
833
|
-
setXP: setXP,
|
|
834
|
-
leaderboard: leaderboard,
|
|
835
|
-
roleSetup: roleSetup,
|
|
836
|
-
lvlRole: lvlRole
|
|
837
|
-
}
|
|
1
|
+
try {
|
|
2
|
+
require('discord.js')
|
|
3
|
+
} catch (e) {
|
|
4
|
+
throw new Error('Discord.JS is required for this package to run')
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
module.exports.roleSetup = require('./src/roleSetup')
|
|
8
|
+
|
|
9
|
+
module.exports.addLevel = require('./src/addLevel')
|
|
10
|
+
|
|
11
|
+
module.exports.addXP = require('./src/addXP')
|
|
12
|
+
|
|
13
|
+
module.exports.charts = require('./src/charts')
|
|
14
|
+
|
|
15
|
+
module.exports.connect = require('./src/connect')
|
|
16
|
+
|
|
17
|
+
module.exports.create = require('./src/create')
|
|
18
|
+
|
|
19
|
+
module.exports.fetch = require('./src/fetch')
|
|
20
|
+
|
|
21
|
+
module.exports.leaderboard = require('./src/leaderboard')
|
|
22
|
+
|
|
23
|
+
module.exports.lvlRole = require('./src/lvlRole')
|
|
24
|
+
|
|
25
|
+
module.exports.rank = require('./src/rank')
|
|
26
|
+
|
|
27
|
+
module.exports.setLevel = require('./src/setLevel')
|
|
28
|
+
|
|
29
|
+
module.exports.setXP = require('./src/setXP')
|
|
30
|
+
|
|
31
|
+
module.exports.reset = require('./src/reset')
|