diff --git a/README.md b/README.md index 6069adb2..c3478ab4 100644 --- a/README.md +++ b/README.md @@ -268,7 +268,7 @@ in the appropriate channel's topic to use it. ## Commands -Total: 561 +Total: 560 ### Utility: @@ -695,7 +695,6 @@ Total: 561 * **wild-pokemon:** Draws an image or a user's avatar over a wild Pokémon appearance. * **you-died:** Sends a "You Died" screen over an image or a user's avatar. * **yu-gi-oh-gen:** Draws an image or a user's avatar on a Yu-Gi-Oh! Trading Card with the text of your choice. -* **yu-gi-oh-token:** Draws an image or a user's avatar over a blank Yu-Gi-Oh! Token card. * **zero-dialogue:** Sends a text box from Megaman Zero with the quote of your choice. ### Avatar Manipulation: @@ -1043,8 +1042,6 @@ here. * cow-say (API) - [Creative Certificates](https://www.creativecertificates.com/) * certificate ([Image](https://www.creativecertificates.com/award-certificate-templates/)) -- [cylgom](https://www.deviantart.com/cylgom) - * yu-gi-oh-gen ([Card Base Template](https://www.deviantart.com/cylgom/art/Yu-GI-Oh-ultra-faithful-monster-card-template-728814822)) - [DaFont](https://www.dafont.com/) * whos-that-pokemon ([Pokemon Solid Font](https://www.dafont.com/pokemon.font)) * whos-that-pokemon-cry ([Pokemon Solid Font](https://www.dafont.com/pokemon.font)) @@ -1236,7 +1233,7 @@ here. - [iCrawl](https://github.com/iCrawl) * butt ([Code, Concept](https://github.com/iCrawl/Tohru/blob/master/src/commands/fun/butts.js)) - [icycatelf](https://www.deviantart.com/icycatelf) - * yu-gi-oh-gen ([Level Star Image](https://www.deviantart.com/icycatelf/art/Level-Star-Template-PSD-607344453)) + * yu-gi-oh-gen ([Level/Rank Star Image](https://www.deviantart.com/icycatelf/art/Level-Star-Template-PSD-607344453)) - [iFunny](https://ifunny.co/) * ifunny (Logo) - [Illumination](http://www.illumination.com/) @@ -1335,7 +1332,6 @@ here. - [Konami](https://www.konami.com/en/) * yu-gi-oh ([Original "Yu-Gi-Oh!" Game](https://www.yugioh-card.com/en/)) * yu-gi-oh-gen ([Images, Original "Yu-Gi-Oh!" Game](https://www.yugioh-card.com/en/)) - * yu-gi-oh-token ([Image, Original "Yu-Gi-Oh!" Game](https://www.yugioh-card.com/en/)) - [KONOSUBA -God's blessing on this wonderful world!](http://konosuba.com/) * axis-cult (Original Anime) * axis-cult-sign-up (Original Anime) @@ -1632,6 +1628,8 @@ here. * undertale ([Pixelated Wingdings Font](https://fontstruct.com/fontstructions/show/1218140/pixelated-wingdings)) - [SinKillerJ Tachikawa](https://www.deviantart.com/sinkillerj) * steam-card ([Template](https://www.deviantart.com/sinkillerj/art/Steam-Trading-Card-Template-GIMP-372156984)) +- [sl777123](https://www.deviantart.com/sl777123) + * yu-gi-oh-gen ([Card Base Templates](https://www.deviantart.com/sl777123/art/Normals-711959461)) - [SmileBASIC Source](https://smilebasicsource.com/) * smilebasic ([API](https://smilebasicsource.com/page?pid=1360)) - [SMWiki](http://www.smwiki.net/) diff --git a/assets/images/yu-gi-oh-gen/atrs/spell.png b/assets/images/yu-gi-oh-gen/atrs/spell.png new file mode 100644 index 00000000..a6385056 Binary files /dev/null and b/assets/images/yu-gi-oh-gen/atrs/spell.png differ diff --git a/assets/images/yu-gi-oh-gen/atrs/trap.png b/assets/images/yu-gi-oh-gen/atrs/trap.png new file mode 100644 index 00000000..b8849566 Binary files /dev/null and b/assets/images/yu-gi-oh-gen/atrs/trap.png differ diff --git a/assets/images/yu-gi-oh-gen/base.png b/assets/images/yu-gi-oh-gen/base.png deleted file mode 100644 index d281b915..00000000 Binary files a/assets/images/yu-gi-oh-gen/base.png and /dev/null differ diff --git a/assets/images/yu-gi-oh-gen/bases/effect.png b/assets/images/yu-gi-oh-gen/bases/effect.png new file mode 100644 index 00000000..fddc2525 Binary files /dev/null and b/assets/images/yu-gi-oh-gen/bases/effect.png differ diff --git a/assets/images/yu-gi-oh-gen/bases/fusion.png b/assets/images/yu-gi-oh-gen/bases/fusion.png new file mode 100644 index 00000000..4e8a5849 Binary files /dev/null and b/assets/images/yu-gi-oh-gen/bases/fusion.png differ diff --git a/assets/images/yu-gi-oh-gen/bases/link.png b/assets/images/yu-gi-oh-gen/bases/link.png new file mode 100644 index 00000000..f5296129 Binary files /dev/null and b/assets/images/yu-gi-oh-gen/bases/link.png differ diff --git a/assets/images/yu-gi-oh-gen/bases/normal.png b/assets/images/yu-gi-oh-gen/bases/normal.png new file mode 100644 index 00000000..4b8a35b8 Binary files /dev/null and b/assets/images/yu-gi-oh-gen/bases/normal.png differ diff --git a/assets/images/yu-gi-oh-gen/bases/ritual.png b/assets/images/yu-gi-oh-gen/bases/ritual.png new file mode 100644 index 00000000..c135c93f Binary files /dev/null and b/assets/images/yu-gi-oh-gen/bases/ritual.png differ diff --git a/assets/images/yu-gi-oh-gen/bases/spell.png b/assets/images/yu-gi-oh-gen/bases/spell.png new file mode 100644 index 00000000..4ed33e80 Binary files /dev/null and b/assets/images/yu-gi-oh-gen/bases/spell.png differ diff --git a/assets/images/yu-gi-oh-gen/bases/synchro.png b/assets/images/yu-gi-oh-gen/bases/synchro.png new file mode 100644 index 00000000..03b706bb Binary files /dev/null and b/assets/images/yu-gi-oh-gen/bases/synchro.png differ diff --git a/assets/images/yu-gi-oh-gen/bases/token.png b/assets/images/yu-gi-oh-gen/bases/token.png new file mode 100644 index 00000000..ddf30e88 Binary files /dev/null and b/assets/images/yu-gi-oh-gen/bases/token.png differ diff --git a/assets/images/yu-gi-oh-gen/bases/trap.png b/assets/images/yu-gi-oh-gen/bases/trap.png new file mode 100644 index 00000000..a561db60 Binary files /dev/null and b/assets/images/yu-gi-oh-gen/bases/trap.png differ diff --git a/assets/images/yu-gi-oh-gen/bases/xyz.png b/assets/images/yu-gi-oh-gen/bases/xyz.png new file mode 100644 index 00000000..0c4a64cb Binary files /dev/null and b/assets/images/yu-gi-oh-gen/bases/xyz.png differ diff --git a/assets/images/yu-gi-oh-gen/line.png b/assets/images/yu-gi-oh-gen/line.png deleted file mode 100644 index b7455d13..00000000 Binary files a/assets/images/yu-gi-oh-gen/line.png and /dev/null differ diff --git a/assets/images/yu-gi-oh-gen/rank.png b/assets/images/yu-gi-oh-gen/rank.png new file mode 100644 index 00000000..e1cc6f87 Binary files /dev/null and b/assets/images/yu-gi-oh-gen/rank.png differ diff --git a/assets/images/yu-gi-oh-token.png b/assets/images/yu-gi-oh-token.png deleted file mode 100644 index 71aa29a2..00000000 Binary files a/assets/images/yu-gi-oh-token.png and /dev/null differ diff --git a/commands/edit-image/yu-gi-oh-gen.js b/commands/edit-image/yu-gi-oh-gen.js index e6dc89d7..542cfbb4 100644 --- a/commands/edit-image/yu-gi-oh-gen.js +++ b/commands/edit-image/yu-gi-oh-gen.js @@ -2,8 +2,10 @@ const Command = require('../../structures/Command'); const { createCanvas, loadImage, registerFont } = require('canvas'); const request = require('node-superfetch'); const path = require('path'); -const { list } = require('../../util/Util'); +const { list, firstUpperCase } = require('../../util/Util'); const { wrapText } = require('../../util/Canvas'); +const types = ['monster', 'spell', 'trap']; +const monsterTypes = ['normal', 'effect', 'fusion', 'synchro', 'xyz', 'link', 'token']; const atrs = ['dark', 'divine', 'earth', 'fire', 'laugh', 'light', 'water', 'wind']; registerFont(path.join(__dirname, '..', '..', 'assets', 'fonts', 'Matrix Book.ttf'), { family: 'Matrix Book' }); registerFont(path.join(__dirname, '..', '..', 'assets', 'fonts', 'Matrix Small Caps.ttf'), { family: 'Matrix' }); @@ -33,15 +35,15 @@ module.exports = class YuGiOhGenCommand extends Command { reasonURL: 'https://www.yugioh-card.com/en/' }, { - name: 'cylgom', - url: 'https://www.deviantart.com/cylgom', - reason: 'Card Base Template', - reasonURL: 'https://www.deviantart.com/cylgom/art/Yu-GI-Oh-ultra-faithful-monster-card-template-728814822' + name: 'sl777123', + url: 'https://www.deviantart.com/sl777123', + reason: 'Card Base Templates', + reasonURL: 'https://www.deviantart.com/sl777123/art/Normals-711959461' }, { name: 'icycatelf', url: 'https://www.deviantart.com/icycatelf', - reason: 'Level Star Image', + reason: 'Level/Rank Star Image', reasonURL: 'https://www.deviantart.com/icycatelf/art/Level-Star-Template-PSD-607344453' }, { @@ -53,51 +55,13 @@ module.exports = class YuGiOhGenCommand extends Command { } ], args: [ - { - key: 'name', - prompt: 'What do you want the card to be named?', - type: 'string', - max: 50 - }, - { - key: 'attribute', - prompt: `What attribute should the card be? Either ${list(atrs, 'or')}.`, - type: 'string', - oneOf: atrs, - parse: attribute => attribute.toLowerCase() - }, - { - key: 'effect', - prompt: 'What should the card\'s effect be?', - type: 'string' - }, { key: 'type', - prompt: 'What type should the card be?', + prompt: `What type of card do you want to make? Either ${list(types, 'or')}.`, type: 'string', - max: 25 - }, - { - key: 'level', - prompt: 'What level should the card be?', - type: 'integer', - min: 1, - max: 12 - }, - { - key: 'attack', - prompt: 'How much attack should the card have?', - type: 'integer', - min: 0, - max: 9999 - }, - { - key: 'defense', - prompt: 'How much defense should the card have?', - type: 'integer', - min: 0, - max: 9999 - }, + oneOf: types, + parse: type => type.toLowerCase() + } { key: 'image', prompt: 'What image would you like to edit?', @@ -108,50 +72,185 @@ module.exports = class YuGiOhGenCommand extends Command { }); } - async run(msg, { name, attribute, effect, type, level, attack, defense, image }) { + async run(msg, { type, image }) { const id = Math.floor(Math.random() * 100000000); const setID = Math.floor(Math.random() * 1000); try { - const base = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'yu-gi-oh-gen', 'base.png')); + const monsterType = await this.determineMonsterType(msg, type); + if (!monsterType) return msg.say('Aborted card creation.'); + const name = await this.determineName(msg); + if (!name) return msg.say('Aborted card creation.'); + const attribute = await this.determineAttribute(msg, type); + if (!attribute) return msg.say('Aborted card creation.'); + const species = await this.determineType(msg, type); + if (!species) return msg.say('Aborted card creation.'); + const effect = await this.determineEffect(msg, monsterType); + if (!effect) return msg.say('Aborted card creation.'); + const level = await this.determineLevel(msg, type, monsterType); + if (!level) return msg.say('Aborted card creation.'); + const atk = await this.determineAttack(msg, type); + if (!atk) return msg.say('Aborted card creation.'); + const def = await this.determineDefense(msg, type, monsterType); + if (!def) return msg.say('Aborted card creation.'); + const base = await loadImage( + path.join(__dirname, '..', '..', 'assets', 'images', 'yu-gi-oh-gen', 'bases', `${monsterType}.png`) + ); const atr = await loadImage( path.join(__dirname, '..', '..', 'assets', 'images', 'yu-gi-oh-gen', 'atrs', `${attribute}.png`) ); - const levelI = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'yu-gi-oh-gen', 'level.png')); - const line = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'yu-gi-oh-gen', 'line.png')); const { body } = await request.get(image); const data = await loadImage(body); const canvas = createCanvas(base.width, base.height); const ctx = canvas.getContext('2d'); ctx.fillStyle = 'white'; ctx.fillRect(0, 0, base.width, base.height); - const height = 590 / data.width; - ctx.drawImage(data, 109, 241, 590, data.height * height); + const height = 617 / data.width; + ctx.drawImage(data, 98, 217, 617, data.height * height); ctx.drawImage(base, 0, 0); - ctx.drawImage(atr, 669, 61, 77, 77); - for (let i = 0; i < level; i++) { - const levelX = 676 - (50 * i) - (5 * i); - ctx.drawImage(levelI, levelX, 160, 50, 50); + ctx.drawImage(atr, 686, 55 + (monsterType === 'link' ? 4 : 0), 70, 70); + if (level > 0) { + const levelToUse = monsterType === 'xyz' ? 'rank' : 'level'; + const levelI = await loadImage( + path.join(__dirname, '..', '..', 'assets', 'images', 'yu-gi-oh-gen', `${levelToUse}.png`) + ); + for (let i = 0; i < level; i++) { + let levelX; + if (monsterType === 'xyz') levelX = 76 + (50 * i) + (5 * i); + else levelX = 686 - (50 * i) - (5 * i); + ctx.drawImage(levelI, levelX, 141, 50, 50); + } } ctx.font = '14px Noto'; ctx.fillStyle = 'black'; ctx.textBaseline = 'top'; ctx.font = '87px Matrix'; - ctx.fillText(name, 74, 64, 585); - ctx.font = '27px Matrix Book'; - const wrappedEffect = await wrapText(ctx, effect, 660); - ctx.fillText(wrappedEffect.join('\n'), 78, 925); + ctx.fillText(name, 55, 65, 620); ctx.font = '31px Stone Serif Small Caps'; - ctx.fillText(`[ ${type} / Effect ]`, 77, 889); + if (type === 'monster') { + let typeStr = `[ ${firstUpperCase(species)} / ${firstUpperCase(monsterType)}`; + if (monsterType !== 'normal' && monsterType !== 'effect' && monsterType !== 'token') { + typeStr += ' / Effect'; + } + typeStr += ' ]'; + ctx.fillText(typeStr, 60, 894); + ctx.font = '22px Stone Serif'; + ctx.fillText(atk, 514, 1081); + ctx.fillText(def, monsterType === 'link' ? 722 : 675, 1081); + } + ctx.font = '27px Matrix Book'; + const wrappedEffect = await wrapText(ctx, effect, 690); + ctx.fillText(wrappedEffect.join('\n'), 78, 925 - (type === 'monster' ? 0 : 31)); ctx.font = '22px Stone Serif'; - ctx.fillText(id.toString().padStart(8, '0'), 37, 1128); - ctx.fillText(`XIAO-EN${setID.toString().padStart(3, '0')}`, 572, 850); - ctx.font = '30px Stone Serif'; - ctx.fillText(`ATK/${attack}`, 419, 1076); - ctx.fillText(`DEF/${defense}`, 578, 1076); - ctx.drawImage(line, 80, 1073); + ctx.fillText(id.toString().padStart(8, '0'), 43, 1128); + ctx.fillText(`XIAO-EN${setID.toString().padStart(3, '0')}`, 589, 859); return msg.say({ files: [{ attachment: canvas.toBuffer(), name: 'yu-gi-oh-gen.png' }] }); } catch (err) { return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); } } + + async determineMonsterType(msg, type) { + if (type !== 'monster') return type; + await msg.reply(`What kind of monster do you want to make? Either ${list(monsterTypes, 'or')}.`); + const filter = res => res.author.id === msg.author.id && monsterTypes.includes(res.content.toLowerCase()); + const msgs = await msg.channel.awaitMessages(filter, { + max: 1, + time: 60000 + }); + if (!msgs.size) return null; + return msgs.first().content.toLowerCase(); + } + + async determineName(msg) { + await msg.reply('What name should your card have?'); + const msgs = await msg.channel.awaitMessages(res => res.author.id === msg.author.id, { + max: 1, + time: 60000 + }); + if (!msgs.size) return null; + return msgs.first().content; + } + + async determineAttribute(msg, type) { + if (type !== 'monster') return type; + await msg.reply(`What attribute should your monster be? Either ${list(atrs, 'or')}.`); + const filter = res => res.author.id === msg.author.id && atrs.includes(res.content.toLowerCase()); + const msgs = await msg.channel.awaitMessages(filter, { + max: 1, + time: 60000 + }); + if (!msgs.size) return null; + return msgs.first().content.toLowerCase(); + } + + async determineType(msg, type) { + if (type !== 'monster') return type; + await msg.reply('What type should your monster be? For example, "Dragon".'); + const msgs = await msg.channel.awaitMessages(res => res.author.id === msg.author.id, { + max: 1, + time: 60000 + }); + if (!msgs.size) return null; + return msgs.first().content; + } + + async determineEffect(msg, monsterType) { + if (monsterType === 'token') return 'This card can be used as any Token.'; + await msg.reply('What effect should your card have?'); + const msgs = await msg.channel.awaitMessages(res => res.author.id === msg.author.id, { + max: 1, + time: 60000 + }); + if (!msgs.size) return null; + return msgs.first().content; + } + + async determineLevel(msg, type, monsterType) { + if (type !== 'monster' || monsterType === 'link') return 0; + await msg.reply(`What ${monsterType === 'xyz' ? 'rank' : 'level'} should your monster be? From 1-12.`); + const filter = res => { + if (res.author.id !== msg.author.id) return false; + const int = Number.parseInt(res.content, 10); + return int >= 1 && int <= 12; + } + const msgs = await msg.channel.awaitMessages(filter, { + max: 1, + time: 60000 + }); + if (!msgs.size) return null; + return msgs.first().content; + } + + async determineAttack(msg, type) { + if (type !== 'monster') return 0; + await msg.reply('How much attack should your monster have? From 0-9999.'); + const filter = res => { + if (res.author.id !== msg.author.id) return false; + const int = Number.parseInt(res.content, 10); + return int >= 0 && int <= 9999; + } + const msgs = await msg.channel.awaitMessages(filter, { + max: 1, + time: 60000 + }); + if (!msgs.size) return null; + return msgs.first().content; + } + + async determineDefense(msg, type, monsterType) { + if (type !== 'monster') return 0; + if (monsterType === 'link') await msg.reply('What link rating should your monster have? From 0-8.'); + else await msg.reply('How much defense should your monster have? From 0-9999.'); + const filter = res => { + if (res.author.id !== msg.author.id) return false; + const int = Number.parseInt(res.content, 10); + return int >= 0 && int <= monsterType === 'link' ? 8 : 9999; + } + const msgs = await msg.channel.awaitMessages(filter, { + max: 1, + time: 60000 + }); + if (!msgs.size) return null; + return msgs.first().content; + } }; diff --git a/commands/edit-image/yu-gi-oh-token.js b/commands/edit-image/yu-gi-oh-token.js deleted file mode 100644 index 6bfbb971..00000000 --- a/commands/edit-image/yu-gi-oh-token.js +++ /dev/null @@ -1,55 +0,0 @@ -const Command = require('../../structures/Command'); -const { createCanvas, loadImage } = require('canvas'); -const request = require('node-superfetch'); -const path = require('path'); - -module.exports = class YuGiOhTokenCommand extends Command { - constructor(client) { - super(client, { - name: 'yu-gi-oh-token', - aliases: ['ygo-token'], - group: 'edit-image', - memberName: 'yu-gi-oh-token', - description: 'Draws an image or a user\'s avatar over a blank Yu-Gi-Oh! Token card.', - throttling: { - usages: 1, - duration: 10 - }, - clientPermissions: ['ATTACH_FILES'], - credit: [ - { - name: 'Konami', - url: 'https://www.konami.com/en/', - reason: 'Image, Original "Yu-Gi-Oh!" Game', - reasonURL: 'https://www.yugioh-card.com/en/' - } - ], - args: [ - { - key: 'image', - prompt: 'What image would you like to edit?', - type: 'image', - default: msg => msg.author.displayAvatarURL({ format: 'png', size: 512 }) - } - ] - }); - } - - async run(msg, { image }) { - try { - const base = await loadImage(path.join(__dirname, '..', '..', 'assets', 'images', 'yu-gi-oh-token.png')); - const { body } = await request.get(image); - const data = await loadImage(body); - const canvas = createCanvas(base.width, base.height); - const ctx = canvas.getContext('2d'); - ctx.fillStyle = 'white'; - ctx.fillRect(0, 0, base.width, base.height); - const height = 294 / data.width; - ctx.drawImage(data, 45, 102, 294, data.height * height); - ctx.drawImage(base, 0, 0); - return msg.say({ files: [{ attachment: canvas.toBuffer(), name: 'yu-gi-oh-token.png' }] }); - } catch (err) { - return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); - } - } -}; diff --git a/package.json b/package.json index e4914a65..b7e98649 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xiao", - "version": "119.46.0", + "version": "120.0.0", "description": "Your personal server companion.", "main": "Xiao.js", "scripts": {