diff --git a/src/discord/commands/global/d.mushroom_info.ts b/src/discord/commands/global/d.mushroom_info.ts index 11bda8384..7c943521b 100644 --- a/src/discord/commands/global/d.mushroom_info.ts +++ b/src/discord/commands/global/d.mushroom_info.ts @@ -11,7 +11,7 @@ import { SlashCommand } from '../../@types/commandDef'; import { embedTemplate } from '../../utils/embedTemplate'; // import mushroomInfo from '../../../global/commands/g.mushroomInfo'; import commandContext from '../../utils/context'; -import { imageGet } from '../../utils/imageGet'; +import getAsset from '../../utils/getAsset'; const F = f(__filename); @@ -28,7 +28,7 @@ async function mushroomPageOneEmbed() { For more information check out [the source](${source}) and [this article](${article}).`) .setImage('attachment://mushroomInfoA.png')], - files: [new AttachmentBuilder(await imageGet('mushroomInfoA'))], + files: [new AttachmentBuilder(await getAsset('mushroomInfoA'))], components: [new ActionRowBuilder().addComponents( new ButtonBuilder() @@ -48,7 +48,7 @@ async function mushroomPageTwoEmbed() { For more information check out [the source](${source}) and [this article](${article}).`) .setImage('attachment://mushroomInfoB.png')], - files: [new AttachmentBuilder(await imageGet('mushroomInfoB'))], + files: [new AttachmentBuilder(await getAsset('mushroomInfoB'))], components: [new ActionRowBuilder().addComponents( new ButtonBuilder() diff --git a/src/discord/commands/guild/d.levels.ts b/src/discord/commands/guild/d.levels.ts index 871becdd2..1e168d0ee 100644 --- a/src/discord/commands/guild/d.levels.ts +++ b/src/discord/commands/guild/d.levels.ts @@ -12,15 +12,10 @@ import { levels } from '../../../global/commands/g.levels'; import { profile, ProfileData } from '../../../global/commands/g.profile'; import { getPersonaInfo } from '../../../global/commands/g.rpg'; import { inventoryGet } from '../../../global/utils/knex'; -import { imageGet } from '../../utils/imageGet'; +import getAsset from '../../utils/getAsset'; import commandContext from '../../utils/context'; import { numFormatter, numFormatterVoice } from './d.profile'; import { Personas } from '../../../global/@types/database'; -// import { expForNextLevel, getTotalLevel } from '../../../global/utils/experience'; -// import { inventoryGet } from '../../../global/utils/knex'; -// import { imageGet } from '../../utils/imageGet'; - -// import { getTotalLevel } from '../../../global/utils/experience'; const F = f(__filename); @@ -240,16 +235,16 @@ export const dLevels: SlashCommand = { // Get the levels of the user await levels(target.id), // Load Images - await Canvas.loadImage(await imageGet('cardLevelIcons')), + await Canvas.loadImage(await getAsset('cardLevelIcons')), await Canvas.loadImage(target.user.displayAvatarURL({ extension: 'jpg' })), - await Canvas.loadImage(await imageGet('teamtripsitIcon')), - await Canvas.loadImage(await imageGet('premiumIcon')), - await Canvas.loadImage(await imageGet('boosterIcon')), - await Canvas.loadImage(await imageGet('legacyIcon')), - await Canvas.loadImage(await imageGet('voiceBar')), - await Canvas.loadImage(await imageGet('tripsitterBar')), - await Canvas.loadImage(await imageGet('developerBar')), - await Canvas.loadImage(await imageGet('teamtripsitBar')), + await Canvas.loadImage(await getAsset('teamtripsitIcon')), + await Canvas.loadImage(await getAsset('premiumIcon')), + await Canvas.loadImage(await getAsset('boosterIcon')), + await Canvas.loadImage(await getAsset('legacyIcon')), + await Canvas.loadImage(await getAsset('voiceBar')), + await Canvas.loadImage(await getAsset('tripsitterBar')), + await Canvas.loadImage(await getAsset('developerBar')), + await Canvas.loadImage(await getAsset('teamtripsitBar')), ]); const profileData = values[1].status === 'fulfilled' ? values[1].value : {} as ProfileData; @@ -516,16 +511,17 @@ export const dLevels: SlashCommand = { // Purchased Background // Check get fresh persona data // log.debug(F, `personaData home (Change) ${JSON.stringify(personaData, null, 2)}`); - + let userFont = 'futura'; if (personaData) { // Get the existing inventory data const inventoryData = await inventoryGet(personaData.id); // log.debug(F, `Persona home inventory (change): ${JSON.stringify(inventoryData, null, 2)}`); const equippedBackground = inventoryData.find(item => item.equipped === true && item.effect === 'background'); + const equippedFont = inventoryData.find(item => item.equipped === true && item.effect === 'font'); // log.debug(F, `equippedBackground: ${JSON.stringify(equippedBackground, null, 2)} `); if (equippedBackground) { - const imagePath = await imageGet(equippedBackground.value); + const imagePath = await getAsset(equippedBackground.value); const Background = await Canvas.loadImage(imagePath); context.save(); context.globalCompositeOperation = 'lighter'; @@ -537,6 +533,10 @@ export const dLevels: SlashCommand = { context.drawImage(Background, 0, 0); context.restore(); } + if (equippedFont) { + await getAsset(equippedFont.value); + userFont = equippedFont.value; + } } // Overly complicated avatar clip @@ -608,14 +608,16 @@ export const dLevels: SlashCommand = { const usernameContext = canvas.getContext('2d'); do { fontSize -= 2; - usernameContext.font = `${fontSize}px futura`; + usernameContext.font = `${fontSize}px ${userFont}`; } while (usernameContext.measureText(text).width > 530); return usernameContext.font; }; // Username Text // Temporary code for user flairs + const filteredDisplayName = target.displayName.replace(/[^A-Za-z0-9]/g, ''); context.fillStyle = textColor; + context.font = `40px ${userFont}`; context.textAlign = 'left'; const flair = null; let usernameHeight = 76; @@ -630,8 +632,8 @@ export const dLevels: SlashCommand = { context.textBaseline = 'bottom'; } fontSize = 40; - context.font = applyUsername(canvasObj, `${target.displayName}`); - context.fillText(`${target.displayName}`, 146, usernameHeight); + context.font = applyUsername(canvasObj, `${filteredDisplayName}`); + context.fillText(`${filteredDisplayName}`, 146, usernameHeight); // Progress Bars Draw context.fillStyle = barColor; @@ -813,7 +815,7 @@ export const dLevels: SlashCommand = { } else if (levelData.ALL.TOTAL.level >= 100) { LevelImagePath = 'badgeVip10'; } - const LevelImage = await Canvas.loadImage(await imageGet(LevelImagePath)); + const LevelImage = await Canvas.loadImage(await getAsset(LevelImagePath)); context.drawImage(LevelImage, 97, 181, 58, 58); // Process The Entire Card and Send it to Discord diff --git a/src/discord/commands/guild/d.profile.ts b/src/discord/commands/guild/d.profile.ts index 4b7e17889..fe44f8c79 100644 --- a/src/discord/commands/guild/d.profile.ts +++ b/src/discord/commands/guild/d.profile.ts @@ -12,9 +12,12 @@ import commandContext from '../../utils/context'; import { expForNextLevel, getTotalLevel } from '../../../global/utils/experience'; import { getPersonaInfo } from '../../../global/commands/g.rpg'; import { inventoryGet } from '../../../global/utils/knex'; -import { imageGet } from '../../utils/imageGet'; +import getAsset from '../../utils/getAsset'; import { Personas } from '../../../global/@types/database'; +// ??? TO BE MOVED TO A DEDICATED FILE, OR IMAGEGET.TS ??? +// Load external fonts from web + const F = f(__filename); Canvas.GlobalFonts.registerFromPath( @@ -32,17 +35,6 @@ export function numFormatter(num:number):string { return num.toFixed(0); } -// Username Text Resize to fit -export function applyUsername(canvas:Canvas.Canvas, text:string) { - const usernameContext = canvas.getContext('2d'); - let fontSize = 40; - do { - fontSize -= 2; - usernameContext.font = `${fontSize}px futura`; - } while (usernameContext.measureText(text).width > 530); // LARGER LENGTH LIMIT WHILE CAMP ICON ISN'T ENABLED (DEFAULT IS 380) - return usernameContext.font; -} - // Number Formatter Voice export function numFormatterVoice(num:number):string { if (num > 999 && num < 1000000) { @@ -211,17 +203,17 @@ export const dProfile: SlashCommand = { // Check get fresh persona data await getPersonaInfo(target.user.id), // Load Icon Images - await Canvas.loadImage(await imageGet('cardIcons')), + await Canvas.loadImage(await getAsset('cardIcons')), // Get the status icon // await Canvas.loadImage(await imageGet(`icon_${target.presence?.status ?? 'offline'}`)), // Get the avatar image await Canvas.loadImage(target.user.displayAvatarURL({ extension: 'jpg' })), // Get the birthday card overlay - await Canvas.loadImage(await imageGet('cardBirthday')), - await Canvas.loadImage(await imageGet('teamtripsitIcon')), - await Canvas.loadImage(await imageGet('premiumIcon')), - await Canvas.loadImage(await imageGet('boosterIcon')), - await Canvas.loadImage(await imageGet('legacyIcon')), + await Canvas.loadImage(await getAsset('cardBirthday')), + await Canvas.loadImage(await getAsset('teamtripsitIcon')), + await Canvas.loadImage(await getAsset('premiumIcon')), + await Canvas.loadImage(await getAsset('boosterIcon')), + await Canvas.loadImage(await getAsset('legacyIcon')), ]); const profileData = values[0].status === 'fulfilled' ? values[0].value : {} as ProfileData; @@ -338,16 +330,17 @@ export const dProfile: SlashCommand = { // WIP: Purchased Background // log.debug(F, `personaData home (Change) ${JSON.stringify(personaData, null, 2)}`); - + let userFont = 'futura'; if (personaData) { // Get the existing inventory data const inventoryData = await inventoryGet(personaData.id); // log.debug(F, `Persona home inventory (change): ${JSON.stringify(inventoryData, null, 2)}`); const equippedBackground = inventoryData.find(item => item.equipped === true && item.effect === 'background'); + const equippedFont = inventoryData.find(item => item.equipped === true && item.effect === 'font'); // log.debug(F, `equippedBackground: ${JSON.stringify(equippedBackground, null, 2)} `); if (equippedBackground) { - const imagePath = await imageGet(equippedBackground.value); + const imagePath = await getAsset(equippedBackground.value); const Background = await Canvas.loadImage(imagePath); context.save(); context.globalCompositeOperation = 'lighter'; @@ -359,6 +352,10 @@ export const dProfile: SlashCommand = { context.drawImage(Background, 0, 0); context.restore(); } + if (equippedFont) { + await getAsset(equippedFont.value); + userFont = equippedFont.value; + } } context.drawImage(Icons, 0, 0); @@ -445,11 +442,24 @@ export const dProfile: SlashCommand = { // WIP: Check to see if a user has bought a title in the shop // If so, move Username Text up so the title can fit underneath + // Username Text Resize to fit + let fontSize = 40; + const applyUsername = (canvas:Canvas.Canvas, text:string) => { + const usernameContext = canvas.getContext('2d'); + do { + fontSize -= 2; + usernameContext.font = `${fontSize}px ${userFont}`; + } while (usernameContext.measureText(text).width > 530); + return usernameContext.font; + }; + // Username Text - context.font = applyUsername(canvasObj, `${target.displayName}`); + const filteredDisplayName = target.displayName.replace(/[^A-Za-z0-9]/g, ''); + context.font = `40px ${userFont}`; context.fillStyle = textColor; context.textBaseline = 'middle'; - context.fillText(`${target.displayName}`, 146, 76); + context.font = applyUsername(canvasObj, `${filteredDisplayName}`); + context.fillText(`${filteredDisplayName}`, 146, 76); // User Timezone context.font = '25px futura'; @@ -538,7 +548,7 @@ export const dProfile: SlashCommand = { LevelImagePath = 'badgeVip10'; } // log.debug(F, `LevelImagePath: ${LevelImagePath}`); - const LevelImage = await Canvas.loadImage(await imageGet(LevelImagePath)); + const LevelImage = await Canvas.loadImage(await getAsset(LevelImagePath)); context.drawImage(LevelImage, 758, 57); // Level Bar Circle BG @@ -595,7 +605,7 @@ export const dProfile: SlashCommand = { }, }; -export async function getProfilePreview(target: GuildMember, imagePath: string, option: string): Promise { +export async function getProfilePreview(target: GuildMember, option: string, imagePath?: string, fontName?: string): Promise { const values = await Promise.allSettled([ // Get the target's profile data from the database @@ -604,7 +614,7 @@ export async function getProfilePreview(target: GuildMember, imagePath: string, // await getPersonaInfo(target.user.id), // Load Icon Images - await Canvas.loadImage(await imageGet('cardIcons')), + await Canvas.loadImage(await getAsset('cardIcons')), // Get the status icon // await Canvas.loadImage(await imageGet(`icon_${target.presence?.status ?? 'offline'}`)), // Get the avatar image @@ -612,7 +622,6 @@ export async function getProfilePreview(target: GuildMember, imagePath: string, // Get the birthday card overlay // await Canvas.loadImage(await imageGet('cardBirthday')), ]); - // const profileData = values[0].status === 'fulfilled' ? values[0].value : {} as ProfileData; // const [personaData] = values[1].status === 'fulfilled' ? values[1].value : []; const Icons = values[0].status === 'fulfilled' ? values[0].value : {} as Canvas.Image; @@ -668,7 +677,7 @@ export async function getProfilePreview(target: GuildMember, imagePath: string, // const equippedBackground = inventoryData.find(item => item.equipped === true && item.effect === 'background'); - if (option === 'background') { + if (option === 'background' && imagePath) { const Background = await Canvas.loadImage(imagePath.toString()); context.save(); context.globalCompositeOperation = 'lighter'; @@ -705,19 +714,34 @@ export async function getProfilePreview(target: GuildMember, imagePath: string, // WIP: Check to see if a user has bought a title in the shop // If so, move Username Text up so the title can fit underneath - + let userFont = 'futura'; + if (option === 'font' && fontName) { + await getAsset(fontName); + userFont = fontName; + } + const filteredDisplayName = target.displayName.replace(/[^A-Za-z0-9]/g, ''); // Username Text - context.font = applyUsername(canvasObj, `${target.displayName}`); + let fontSize = 40; + // eslint-disable-next-line sonarjs/no-identical-functions + const applyUsername = (canvas:Canvas.Canvas, text:string) => { + const usernameContext = canvas.getContext('2d'); + do { + fontSize -= 2; + usernameContext.font = `${fontSize}px ${userFont}`; + } while (usernameContext.measureText(text).width > 530); + return usernameContext.font; + }; + context.font = applyUsername(canvasObj, `${filteredDisplayName}`); context.fillStyle = textColor; if (option === 'profileTitle') { context.textBaseline = 'bottom'; - context.fillText(`${target.displayName}`, 146, 76); + context.fillText(`${filteredDisplayName}`, 146, 76); context.font = '30px futura'; context.textBaseline = 'top'; context.fillText('Your Custom Title Here', 146, 86); } else { context.textBaseline = 'middle'; - context.fillText(`${target.displayName}`, 146, 76); + context.fillText(`${filteredDisplayName}`, 146, 76); } /* User Timezone diff --git a/src/discord/commands/guild/d.rpg.ts b/src/discord/commands/guild/d.rpg.ts index da1334809..a6b5470e3 100644 --- a/src/discord/commands/guild/d.rpg.ts +++ b/src/discord/commands/guild/d.rpg.ts @@ -41,12 +41,15 @@ import { getUser, inventoryGet, inventorySet, inventoryDel, personaSet, } from '../../../global/utils/knex'; import { Personas, RpgInventory } from '../../../global/@types/database'; -import { imageGet } from '../../utils/imageGet'; +import getAsset from '../../utils/getAsset'; import { customButton } from '../../utils/emoji'; import { getProfilePreview } from './d.profile'; const Trivia = require('trivia-api'); +const tripSitProfileImage = 'tripsit-profile-image.png'; +const tripSitProfileImageAttachment = 'attachment://tripsit-profile-image.png'; + const F = f(__filename); // Value in milliseconds (1000 * 60 * 1 = 1 minute) @@ -60,6 +63,19 @@ const timesUp = 'Time\'s up!'; const items = { general: { + // giftcard: { + // label: 'Gift Card', + // value: 'giftcard', + // description: 'A gift card to gift to someone else', + // quantity: 1, + // weight: 0, + // cost: 0, + // equipped: false, + // consumable: false, + // effect: 'tokens', + // effect_value: '100', + // emoji: 'buttonBetHuge', + // }, // testkit: { // label: 'TestKit', // value: 'testkit', @@ -87,24 +103,219 @@ const items = { // emoji: 'itemBonus', // }, }, - // fonts: { - // Arial: { - // label: 'Arial', - // value: 'Arial', - // description: 'Font', - // quantity: 1, - // weight: 0, - // cost: 500, - // equipped: false, - // consumable: false, - // effect: 'font', - // effect_value: 'Arial', - // emoji: 'itemBackground', - // }, - // }, + fonts: { + AbrilFatFace: { + label: 'Abril Fat Face', + value: 'AbrilFatFace', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'AbrilFatFace', + emoji: 'itemFont', + }, + Acme: { + label: 'Acme', + value: 'Acme', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'Acme', + emoji: 'itemFont', + }, + Agbalumo: { + label: 'Agbalumo', + value: 'Agbalumo', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'Agbalumo', + emoji: 'itemFont', + }, + AudioWide: { + label: 'Audio ide', + value: 'AudioWide', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'AudioWide', + emoji: 'itemFont', + }, + BlackOpsOne: { + label: 'Black Ops One', + value: 'BlackOpsOne', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'BlackOpsOne', + emoji: 'itemFont', + }, + CabinSketch: { + label: 'Cabin Sketch', + value: 'CabinSketch', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'CabinSketch', + emoji: 'itemFont', + }, + Creepster: { + label: 'Creepster', + value: 'Creepster', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'Creepster', + emoji: 'itemFont', + }, + FontdinerSwanky: { + label: 'Fontdiner Swanky', + value: 'FontdinerSwanky', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'FontdinerSwanky', + emoji: 'itemFont', + }, + IndieFlower: { + label: 'Indie Flower', + value: 'IndieFlower', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'IndieFlower', + emoji: 'itemFont', + }, + LilitaOne: { + label: 'Lilita One', + value: 'LilitaOne', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'LilitaOne', + emoji: 'itemFont', + }, + Lobster: { + label: 'Lobster', + value: 'Lobster', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'Lobster', + emoji: 'itemFont', + }, + PressStart2P: { + label: 'Press Start 2P', + value: 'PressStart2P', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'PressStart2P', + emoji: 'itemFont', + }, + Rye: { + label: 'Rye', + value: 'Rye', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'Rye', + emoji: 'itemFont', + }, + Satisfy: { + label: 'Satisfy', + value: 'Satisfy', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'Satisfy', + emoji: 'itemFont', + }, + SpecialElite: { + label: 'Special Elite', + value: 'SpecialElite', + description: 'Font', + quantity: 1, + weight: 0, + cost: 700, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'SpecialElite', + emoji: 'itemFont', + }, + Barcode: { + label: 'Barcode', + value: 'Barcode', + description: 'Font', + quantity: 1, + weight: 0, + cost: 7500, + equipped: false, + consumable: false, + effect: 'font', + effect_value: 'Barcode', + emoji: 'itemFont', + }, + }, backgrounds: { AbstractTriangles: { - label: 'AbstractTriangles', + label: 'Abstract Triangles', value: 'AbstractTriangles', description: 'Background', quantity: 1, @@ -117,7 +328,7 @@ const items = { emoji: 'itemBackground', }, ArcadeCarpet: { - label: 'ArcadeCarpet', + label: 'Arcade Carpet', value: 'ArcadeCarpet', description: 'Background', quantity: 1, @@ -130,7 +341,7 @@ const items = { emoji: 'itemBackground', }, CircuitBoard: { - label: 'CircuitBoard', + label: 'Circuit Board', value: 'CircuitBoard', description: 'Background', quantity: 1, @@ -143,7 +354,7 @@ const items = { emoji: 'itemBackground', }, CoffeeSwirl: { - label: 'CoffeeSwirl', + label: 'Coffee Swirl', value: 'CoffeeSwirl', description: 'Background', quantity: 1, @@ -182,7 +393,7 @@ const items = { emoji: 'itemBackground', }, CubeTunnels: { - label: 'CubeTunnels', + label: 'Cube Tunnels', value: 'CubeTunnels', description: 'Background', quantity: 1, @@ -195,7 +406,7 @@ const items = { emoji: 'itemBackground', }, DiamondChevron: { - label: 'DiamondChevron', + label: 'Diamond Chevron', value: 'DiamondChevron', description: 'Background', quantity: 1, @@ -221,7 +432,7 @@ const items = { emoji: 'itemBackground', }, DotnDash: { - label: 'DotnDash', + label: 'Dot n Dash', value: 'DotnDash', description: 'Background', quantity: 1, @@ -351,7 +562,7 @@ const items = { emoji: 'itemBackground', }, LineLeaves: { - label: 'LineLeaves', + label: 'Line Leaves', value: 'LineLeaves', description: 'Background', quantity: 1, @@ -364,7 +575,7 @@ const items = { emoji: 'itemBackground', }, LiquidMaze: { - label: 'LiquidMaze', + label: 'Liquid Maze', value: 'LiquidMaze', description: 'Background', quantity: 1, @@ -442,7 +653,7 @@ const items = { emoji: 'itemBackground', }, PixelCamo: { - label: 'PixelCamo', + label: 'Pixel Camo', value: 'PixelCamo', description: 'Background', quantity: 1, @@ -507,7 +718,7 @@ const items = { emoji: 'itemBackground', }, SpaceIcons: { - label: 'SpaceIcons', + label: 'Space Icons', value: 'SpaceIcons', description: 'Background', quantity: 1, @@ -533,7 +744,7 @@ const items = { emoji: 'itemBackground', }, SquareTwist: { - label: 'SquareTwist', + label: 'Square Twist', value: 'SquareTwist', description: 'Background', quantity: 1, @@ -585,7 +796,7 @@ const items = { emoji: 'itemBackground', }, TriangleOverlap: { - label: 'TriangleOverlap', + label: 'Triangle Overlap', value: 'TriangleOverlap', description: 'Background', quantity: 1, @@ -1035,12 +1246,12 @@ export async function rpgBounties( const contracts = { quest: { success: { - title: `${emojiGet('buttonQuest')} Quest Success`, + title: `${emojiGet('buttonQuest')} Quest Success (Hourly)`, description: stripIndents`${rand(text.quest)}`, color: Colors.Green, }, fail: { - title: `${emojiGet('buttonQuest')} Quest Fail`, + title: `${emojiGet('buttonQuest')} Quest Fail (Hourly)`, description: stripIndents` There are no more quests available at the moment. New quests are posted every hour! `, @@ -1049,12 +1260,12 @@ export async function rpgBounties( }, dungeon: { success: { - title: `${emojiGet('buttonDungeon')} Dungeon Success`, + title: `${emojiGet('buttonDungeon')} Dungeon Success (Daily)`, description: stripIndents`${rand(text.dungeon)}`, color: Colors.Green, }, fail: { - title: `${emojiGet('buttonDungeon')} Dungeon Fail`, + title: `${emojiGet('buttonDungeon')} Dungeon Fail (Daily)`, description: stripIndents` You already cleared a dungeon today, you're still tired and need to prepare. `, @@ -1063,14 +1274,14 @@ export async function rpgBounties( }, raid: { success: { - title: `${emojiGet('buttonRaid')} Raid Success`, + title: `${emojiGet('buttonRaid')} Raid Success (Weekly)`, description: stripIndents` You stormed into Moonbear's office, rustle their jimmies and stole {tokens} TripTokens! `, color: Colors.Green, }, fail: { - title: `${emojiGet('buttonRaid')} Raid Fail`, + title: `${emojiGet('buttonRaid')} Raid Fail (Weekly)`, description: stripIndents` You've already raided Moonbear's office this week, give them a break! `, @@ -1136,7 +1347,7 @@ export async function rpgBounties( .setTitle(contracts[command].fail.title) .setDescription(stripIndents`${contracts[command].fail.description} You can try again ${time(resetTime, 'R')} - Wallet: ${personaData.tokens} tokens`) + ${emojiGet('buttonBetSmall')} **Wallet:** ${personaData.tokens}`) .setColor(contracts[command].fail.color)], components: [rowBounties], }; @@ -1180,7 +1391,7 @@ export async function rpgBounties( .setTitle(contracts[command].success.title) .setDescription(stripIndents`${contracts[command].success.description.replace('{tokens}', tokens.toString())} You can try again ${time(resetTime, 'R')}. - Wallet: ${personaData.tokens} tokens`) + ${emojiGet('buttonBetSmall')} **Wallet:** ${personaData.tokens}`) .setColor(contracts[command].success.color)], components: [rowBounties], }; @@ -1205,6 +1416,8 @@ export async function rpgMarketInventory( marketInventory:SelectMenuComponentOptionData[]; personaTokens:number; personaInventory:string; + personaDiscounts:string; + personaDiscount:number; }> { // Check get fresh persona data const personaData = await getPersonaInfo(interaction.user.id); @@ -1213,11 +1426,41 @@ export async function rpgMarketInventory( const inventoryData = await inventoryGet(personaData.id); // log.debug(F, `Persona inventory: ${JSON.stringify(inventoryData, null, 2)}`); + // Get a string display of the user's discounts + // Check if they have the Premium Member role + // Define the discount types + const discountTypes = [ + { + roleId: env.ROLE_PREMIUM, discount: 0.2, name: 'Premium Member', amount: '20%', + }, + { + roleId: env.ROLE_BOOSTER, discount: 0.1, name: 'Server Booster', amount: '10%', + }, + // Add more discount types here + ]; + + let discount = 0; + let discountString = ''; + const member = await interaction.guild?.members.fetch(interaction.user.id); + + // Iterate over the discount types + for (const discountType of discountTypes) { + if (member?.roles.cache.has(discountType.roleId)) { + discount += discountType.discount; + discountString += `**${discountType.name}** - ${discountType.amount} off\n`; + } + } + + // Add the "Discounts" heading if there are any discounts + if (discountString) { + discountString = `${emojiGet('itemDiscount')} **Discounts**\n${discountString}`; + } + // Get a string display of the user's inventory const inventoryList = inventoryData.map(item => `**${item.label}** - ${item.description}`).join('\n'); const inventoryString = inventoryData.length > 0 ? stripIndents` - ${emojiGet('itemInventory')} **Inventory** + ${emojiGet('itemInventory')} **Inventory (${inventoryData.length}/20)** ${inventoryList} ` : ''; @@ -1233,7 +1476,7 @@ export async function rpgMarketInventory( for (const item of Object.values(categoryItems)) { if (!inventoryData.find(i => i.value === item.value)) { marketInventory.push({ - label: `${item.label} - ${item.cost} TT$`, + label: `${item.label} - ${(item.cost - (discount * item.cost))} TT$`, value: item.value, description: `${item.description}`, emoji: emojiGet(item.emoji).id, @@ -1247,6 +1490,8 @@ export async function rpgMarketInventory( marketInventory, personaTokens: personaData.tokens, personaInventory: inventoryString, + personaDiscounts: discountString, + personaDiscount: discount, }; } @@ -1258,6 +1503,7 @@ export async function rpgMarket( marketInventory, personaTokens, personaInventory, + personaDiscounts, } = await rpgMarketInventory(interaction); // This is the row of nav buttons. It starts with the town button. @@ -1295,7 +1541,7 @@ export async function rpgMarket( .addComponents( new StringSelectMenuBuilder() .setCustomId(`rpgGeneralSelect,user:${interaction.user.id},group:${group},chunk:${index}`) - .setPlaceholder(`${group.charAt(0).toUpperCase() + group.slice(1)} Page ${index + 1}`) + .setPlaceholder(chunks.length === 1 ? `${group.charAt(0).toUpperCase() + group.slice(1)}` : `${group.charAt(0).toUpperCase() + group.slice(1)} ${index + 1}`) .addOptions(chunk), ); componentList.push(rowItems); @@ -1311,12 +1557,13 @@ export async function rpgMarket( .setDescription(stripIndents` You are in the local market, you can buy some items to help you on your journey. - ${emojiGet('itemBackground')} ***Backgrounds*** can be used to personalize your /profile and /levels. - [Click here to see all backgrounds.](https://drive.google.com/drive/folders/1F1s0uQt0nGDCCaVANVdrEQKwameo8eHI?usp=drive_link) + ${emojiGet('itemFont')} ***Fonts*** change the font of your /profile username + ${emojiGet('itemBackground')} ***Backgrounds*** change the background of your /profile + ***More items coming soon! Check back later.*** - Wallet: ${personaTokens} tokens - + ${emojiGet('buttonBetSmall')} **Wallet:** ${personaTokens} + ${personaDiscounts ? `\n${personaDiscounts}` : ''} ${personaInventory}`) .setColor(Colors.Gold)], components: componentList, @@ -1331,6 +1578,7 @@ export async function rpgMarketChange( marketInventory, personaTokens, personaInventory, + personaDiscounts, } = await rpgMarketInventory(interaction); // Get the item the user selected @@ -1385,7 +1633,7 @@ export async function rpgMarketChange( if (chosenItem) { chosenItem.default = true; stringMenu.addOptions(chosenItem); - const allItems = [...Object.values(items.general), ...Object.values(items.backgrounds)]; + const allItems = [...Object.values(items.general), ...Object.values(items.fonts), ...Object.values(items.backgrounds)]; itemData = allItems.find(item => item.value === chosenItem?.value) as { label: string; value: string; @@ -1407,12 +1655,7 @@ export async function rpgMarketChange( customButton(`rpgTown,user:${interaction.user.id}`, 'Town', 'buttonTown', ButtonStyle.Primary), ); - if (chosenItem && itemData.effect === 'background') { - rowMarket.addComponents( - customButton(`rpgMarketBuy,user:${interaction.user.id}`, 'Buy', 'buttonBuy', ButtonStyle.Success).setLabel(`Buy ${chosenItem.label}`), - customButton(`rpgMarketPreview,user:${interaction.user.id}`, 'Preview', 'buttonPreview', ButtonStyle.Secondary), - ); - } else if (chosenItem) { + if (chosenItem) { rowMarket.addComponents( customButton(`rpgMarketBuy,user:${interaction.user.id}`, 'Buy', 'buttonBuy', ButtonStyle.Success).setLabel(`Buy ${chosenItem.label}`), ); @@ -1445,12 +1688,13 @@ export async function rpgMarketChange( .addComponents( new StringSelectMenuBuilder() .setCustomId(`rpgGeneralSelect,user:${interaction.user.id},group:${group},chunk:${index}`) - .setPlaceholder(`${group.charAt(0).toUpperCase() + group.slice(1)} Page ${index + 1}`) + .setPlaceholder(chunks.length === 1 ? `${group.charAt(0).toUpperCase() + group.slice(1)}` : `${group.charAt(0).toUpperCase() + group.slice(1)} ${index + 1}`) .addOptions(chunk), ); components.push(rowItems); } } + const embed = embedTemplate() .setAuthor(null) .setFooter({ text: `${(interaction.member as GuildMember).displayName}'s TripSit RPG (BETA)`, iconURL: (interaction.member as GuildMember).user.displayAvatarURL() }) @@ -1458,21 +1702,36 @@ export async function rpgMarketChange( .setDescription(stripIndents` You are in the local market, you can buy some items to help you on your journey. - ${emojiGet('itemBackground')} ***Backgrounds*** can be used to personalize your /profile and /levels. - [Click here to see all backgrounds.](https://drive.google.com/drive/folders/1F1s0uQt0nGDCCaVANVdrEQKwameo8eHI?usp=drive_link) + ${emojiGet('itemFont')} ***Fonts*** change the font of your /profile username + ${emojiGet('itemBackground')} ***Backgrounds*** change the background of your /profile + ***More items coming soon! Check back later.*** - Wallet: ${personaTokens} tokens - + ${emojiGet('buttonBetSmall')} **Wallet:** ${personaTokens} + ${personaDiscounts ? `\n${personaDiscounts}` : ''} ${personaInventory}`) .setColor(Colors.Gold); const imageFiles = [] as AttachmentBuilder[]; + // if the option is a background, run profile preview as the embed image if (itemData && itemData.effect === 'background') { - const imagePath = await imageGet(itemData.effect_value); - // log.debug(F, `imagePath: ${imagePath}`); - imageFiles.push(new AttachmentBuilder(imagePath)); - embed.setImage(`attachment://${itemData.effect_value}.png`); + const imagePath = await getAsset(itemData.effect_value); + const target = interaction.member as GuildMember; + const option = 'background'; + const previewImage = await getProfilePreview(target, option, imagePath); + const attachment = new AttachmentBuilder(previewImage, { name: tripSitProfileImage }); + imageFiles.push(attachment); + embed.setImage(tripSitProfileImageAttachment); + } + // if the option is a font, run profile preview as the embed image + if (itemData && itemData.effect === 'font') { + const target = interaction.member as GuildMember; + const fontName = itemData.effect_value; + const option = 'font'; + const previewImage = await getProfilePreview(target, option, undefined, fontName); + const attachment = new AttachmentBuilder(previewImage, { name: tripSitProfileImage }); + imageFiles.push(attachment); + embed.setImage(tripSitProfileImageAttachment); } return { @@ -1515,7 +1774,7 @@ export async function rpgMarketPreview( } // log.debug(F, `selectedItem (accept): ${JSON.stringify(selectedItem, null, 2)}`); - const allItems = [...Object.values(items.general), ...Object.values(items.backgrounds)]; + const allItems = [...Object.values(items.general), ...Object.values(items.fonts), ...Object.values(items.backgrounds)]; const itemData = allItems.find(item => item.value === selectedItem?.value) as { label: string; value: string; @@ -1547,13 +1806,22 @@ export async function rpgMarketPreview( const imageFiles = [] as AttachmentBuilder[]; if (itemData && itemData.effect === 'background') { - const imagePath = await imageGet(itemData.effect_value); + const imagePath = await getAsset(itemData.effect_value); const target = interaction.member as GuildMember; const option = 'background'; - const previewImage = await getProfilePreview(target, imagePath, option); - const attachment = new AttachmentBuilder(previewImage, { name: 'tripsit-profile-image.png' }); + const previewImage = await getProfilePreview(target, option, imagePath); + const attachment = new AttachmentBuilder(previewImage, { name: tripSitProfileImage }); + imageFiles.push(attachment); + embed.setImage(tripSitProfileImageAttachment); + } else if (itemData && itemData.effect === 'font') { + const target = interaction.member as GuildMember; + const fontName = itemData.effect_value; + const option = 'font'; + const previewImage = await getProfilePreview(target, option, undefined, fontName); + const attachment = new AttachmentBuilder(previewImage, { name: tripSitProfileImage }); imageFiles.push(attachment); - embed.setImage('attachment://tripsit-profile-image.png'); + embed.setImage(tripSitProfileImageAttachment); + log.debug(F, `font: ${fontName}`); } return { @@ -1596,7 +1864,7 @@ export async function rpgMarketAccept( } log.debug(F, `selectedItem (accept): ${JSON.stringify(selectedItem, null, 2)}`); - const allItems = [...Object.values(items.general), ...Object.values(items.backgrounds)]; + const allItems = [...Object.values(items.general), ...Object.values(items.fonts), ...Object.values(items.backgrounds)]; const itemData = allItems.find(item => item.value === selectedItem?.value) as { label: string; value: string; @@ -1612,8 +1880,39 @@ export async function rpgMarketAccept( }; // log.debug(F, `itemData (accept): ${JSON.stringify(itemData, null, 2)}`); + // Check that the user has less than 25 items in their inventory + const inventoryData = await inventoryGet(personaData.id); + if (inventoryData.length >= 20) { + const { embeds, components } = await rpgMarketChange(interaction); + + // This grossness takes the APIEmbed object, turns it into a JSON object, and pulls the description + const { description } = JSON.parse(JSON.stringify((embeds as APIEmbed[])[0])); + + const embed = embedTemplate() + .setAuthor(null) + .setFooter({ text: `${(interaction.member as GuildMember).displayName}'s TripSit RPG (BETA)`, iconURL: (interaction.member as GuildMember).user.displayAvatarURL() }) + .setTitle(`${emojiGet('buttonMarket')} Market`) + .setDescription(stripIndents`**You cannot buy this item because your inventory is full. Sell some items from your home inventory to make room!** + + ${description}`) + .setColor(Colors.Red); + const imageFiles = [] as AttachmentBuilder[]; + + return { + embeds: [embed], + components, + files: imageFiles, + }; + } + + const { + personaDiscount, + } = await rpgMarketInventory(interaction); + + const itemCost = (itemData.cost - (itemData.cost * personaDiscount)); + // Check if the user has enough tokens to buy the item - if (personaData.tokens < itemData.cost) { + if (personaData.tokens < itemCost) { // log.debug(F, 'Not enough tokens to buy item'); const { embeds, components } = await rpgMarketChange(interaction); @@ -1631,7 +1930,7 @@ export async function rpgMarketAccept( .setColor(Colors.Red); const imageFiles = [] as AttachmentBuilder[]; if (itemData.effect === 'background') { - const imagePath = await imageGet(itemData.effect_value); + const imagePath = await getAsset(itemData.effect_value); // log.debug(F, `imagePath: ${imagePath}`); imageFiles.push(new AttachmentBuilder(imagePath)); embed.setImage(`attachment://${itemData.effect_value}.png`); @@ -1644,7 +1943,7 @@ export async function rpgMarketAccept( }; } - personaData.tokens -= itemData.cost; + personaData.tokens -= itemCost; await personaSet(personaData); // Add the item to the user's inventory @@ -1676,9 +1975,9 @@ export async function rpgMarketAccept( .setAuthor(null) .setFooter({ text: `${(interaction.member as GuildMember).displayName}'s TripSit RPG (BETA)`, iconURL: (interaction.member as GuildMember).user.displayAvatarURL() }) .setTitle(`${emojiGet('buttonMarket')} Market`) - .setDescription(stripIndents`**You have purchased ${itemData.label} for ${itemData.cost} TripTokens. + .setDescription(stripIndents`**You have purchased ${itemData.label} for ${itemCost} TripTokens. - IT was sent to your Home, where you will need to equip it!** + Your item has been delivered to your Home, where you will need to equip it!** ${description}`) .setColor(Colors.Green)], @@ -1705,17 +2004,17 @@ export async function rpgHomeInventory( const inventoryList = inventoryData.map(item => `**${item.label}** - ${item.description}`).join('\n'); const inventoryString = inventoryData.length > 0 ? stripIndents` - ${emojiGet('itemInventory')} **Inventory** + ${emojiGet('itemInventory')} **Inventory (${inventoryData.length}/20)** ${inventoryList} ` : ''; // Go through items.general and create a new object of items that the user doesn't have yet - const homeInventory = [...Object.values(items.backgrounds)] + const homeInventory = [...Object.values(items.fonts), ...Object.values(items.backgrounds)] .map(item => { if (inventoryData.find(i => i.value === item.value)) { return { - label: `${item.label} - ${item.cost} TT$`, + label: `${item.label} - ${(item.cost / 4)} TT$`, value: item.value, description: `${item.description}`, cost: item.cost, @@ -1899,7 +2198,7 @@ export async function rpgHome( // Reset the options menu to be empty const backgroundMenu = new StringSelectMenuBuilder() .setCustomId(`rpgBackgroundSelect,user:${interaction.user.id}`) - .setPlaceholder('Select a background to use.') + .setPlaceholder('Select an item to use') .setOptions(filteredItems); // Get the item the user chose and display that as the default option @@ -1929,7 +2228,7 @@ export async function rpgHome( backgroundMenu.addOptions(chosenItem); // log.debug(F, `items.backgrounds: ${JSON.stringify(items.backgrounds, null, 2)}`); // convert the emoji property into an emoji using emojiGet - const allItems = [...Object.values(items.backgrounds)].map(item => { + const allItems = [...Object.values(items.fonts), ...Object.values(items.backgrounds)].map(item => { const newItem = item; newItem.emoji = `<:${emojiGet('itemBackground').identifier}>`; return item; @@ -1972,7 +2271,7 @@ export async function rpgHome( You can equip an item by selecting it from the menu below. - Wallet: ${personaTokens} tokens + ${emojiGet('buttonBetSmall')} **Wallet:** ${personaTokens} ${personaInventory} `) @@ -1980,32 +2279,30 @@ export async function rpgHome( // If the select item has the 'background' effect, add the image to the embed const files = [] as AttachmentBuilder[]; - if (equippedBackground) { - if ((interaction as ButtonInteraction).customId && (interaction as ButtonInteraction).customId.split(',')[0] === 'rpgHomePreview') { - const imagePath = await imageGet(backgroundData.effect_value); - const target = interaction.member as GuildMember; - const option = 'background'; - const previewImage = await getProfilePreview(target, imagePath, option); - const attachment = new AttachmentBuilder(previewImage, { name: 'tripsit-profile-image.png' }); - files.push(attachment); - embed.setImage('attachment://tripsit-profile-image.png'); - } else { - const imagePath = await imageGet(equippedBackground.value); - // log.debug(F, `Equipped background imagePath: ${imagePath}`); - files.push(new AttachmentBuilder(imagePath)); - embed.setThumbnail(`attachment://${equippedBackground.value}.png`); - // log.debug(F, 'Set thumbnail!'); - } - } if (interaction.isStringSelectMenu() && backgroundData && backgroundData.effect === 'background') { - const imagePath = await imageGet(backgroundData.effect_value); - // log.debug(F, `imagePath: ${imagePath}`); - files.push(new AttachmentBuilder(imagePath)); - embed.setImage(`attachment://${backgroundData.effect_value}.png`); + const imagePath = await getAsset(backgroundData.effect_value); + const target = interaction.member as GuildMember; + const option = 'background'; + const previewImage = await getProfilePreview(target, option, imagePath); + const attachment = new AttachmentBuilder(previewImage, { name: tripSitProfileImage }); + files.push(attachment); + embed.setImage(tripSitProfileImageAttachment); // log.debug(F, 'Set image!'); } + // If the select item has the 'font' effect, add the image to the embed + if (interaction.isStringSelectMenu() && backgroundData && backgroundData.effect === 'font') { + const target = interaction.member as GuildMember; + const fontName = backgroundData.effect_value; + const option = 'font'; + const previewImage = await getProfilePreview(target, option, undefined, fontName); + const attachment = new AttachmentBuilder(previewImage, { name: tripSitProfileImage }); + files.push(attachment); + embed.setImage(tripSitProfileImageAttachment); + log.debug(F, `font: ${fontName}`); + } + // Build out the home navigation buttons const rowHome = new ActionRowBuilder() .addComponents( @@ -2021,13 +2318,11 @@ export async function rpgHome( rowHome.addComponents( customButton(`rpgAccept,user:${interaction.user.id}`, `${equippedButtonText}`, 'buttonAccept', ButtonStyle.Success).setDisabled(equipped), customButton(`rpgSell,user:${interaction.user.id}`, `Sell +${sellPrice} TT$`, 'buttonBetHuge', ButtonStyle.Danger), - customButton(`rpgHomePreview,user:${interaction.user.id}`, 'Preview', 'buttonPreview', ButtonStyle.Secondary), ); } else if (chosenItem && (equipped === true)) { // else show unequip button rowHome.addComponents( customButton(`rpgDecline,user:${interaction.user.id}`, 'Unequip', 'buttonQuit', ButtonStyle.Danger), customButton(`rpgSell,user:${interaction.user.id}`, `Sell +${sellPrice} TT$`, 'buttonBetHuge', ButtonStyle.Danger), - customButton(`rpgHomePreview,user:${interaction.user.id}`, 'Preview', 'buttonPreview', ButtonStyle.Secondary), ); } @@ -2185,6 +2480,8 @@ export async function rpgHomeAccept( // Find the selectedItem in the inventoryData const chosenItem = inventoryData.find(item => item.value === selectedItem?.value); + // Find the item type from inventoryData + const itemType = inventoryData.find(item => item.value === selectedItem?.value)?.effect; // Equip the item if (chosenItem) { @@ -2195,7 +2492,15 @@ export async function rpgHomeAccept( } // Un-equip all other backgrounds - const otherItems = inventoryData.filter(item => item.effect === 'background' && item.value !== selectedItem?.value); + // const otherItems = inventoryData.filter(item => item.effect === 'background' && item.value !== selectedItem?.value); + // otherItems.forEach(item => { + // const newItem = item; + // newItem.equipped = false; + // inventorySet(newItem); + // }); + + // Un-equip all other items of the same category + const otherItems = inventoryData.filter(item => item.effect === itemType && item.value !== selectedItem?.value); otherItems.forEach(item => { const newItem = item; newItem.equipped = false; @@ -2255,7 +2560,7 @@ export async function rpgHomeSell( (o:APISelectMenuOption) => o.default === true, ); const itemName = inventoryData.find(item => item.value === selectedItem?.value)?.label; - const sellPrice = Math.floor(Object.values(items.backgrounds).find(item => item.value === selectedItem?.value)?.cost as number) / 4; + const sellPrice = ((inventoryData.find(item => item.value === selectedItem?.value)?.cost as number) / 4); await inventoryDel(personaData.id, selectedItem?.value as string); personaData.tokens += sellPrice; @@ -2573,7 +2878,7 @@ export async function rpgArcadeGame( .setDescription(stripIndents` **You can't start a game without first placing a bet!** - Wallet: ${personaData.tokens} tokens + ${emojiGet('buttonBetSmall')} **Wallet:** ${personaData.tokens} `) .setColor(Colors.Gold)], components, @@ -2629,7 +2934,7 @@ export async function rpgArcadeGame( **You won ${payout} tokens!** *${BetOutcomeMessage}* - Wallet: ${personaData.tokens} tokens + ${emojiGet('buttonBetSmall')} **Wallet:** ${personaData.tokens} `) .setColor(Colors.Gold)], components, @@ -2655,7 +2960,7 @@ export async function rpgArcadeGame( **You lost ${currentBet} tokens!** *${BetOutcomeMessage}* - Wallet: ${personaData.tokens} tokens + ${emojiGet('buttonBetSmall')} **Wallet:** ${personaData.tokens} `) .setColor(Colors.Grey)], components, @@ -2674,7 +2979,7 @@ export async function rpgArcadeGame( .setDescription(stripIndents`${message ?? ''} You are betting ${currentBet} tokens. - Wallet: ${personaData.tokens} tokens + ${emojiGet('buttonBetSmall')} **Wallet:** ${personaData.tokens} `) .setColor(Colors.Green)], components, @@ -2691,7 +2996,7 @@ export async function rpgArcadeGame( ${instructions} - Wallet: ${personaData.tokens} tokens + ${emojiGet('buttonBetSmall')} **Wallet:** ${personaData.tokens} `) .setColor(Colors.Green)], components, @@ -3145,7 +3450,7 @@ export async function rpgTrivia( *${scoreMessage}* Earned: **${payout} tokens**${bonusMessage} - Wallet: ${(personaData.tokens)} tokens + ${emojiGet('buttonBetSmall')} **Wallet:** ${personaData.tokens} `, ) .setFooter({ text: `${(interaction.member as GuildMember).displayName}'s TripSit RPG (BETA)`, iconURL: (interaction.member as GuildMember).user.displayAvatarURL() }); // eslint-disable-line max-len @@ -3183,7 +3488,7 @@ export async function rpgTrivia( *${gameQuitMessage}* Earned: **${payout} tokens**${bonusMessage} - Wallet: ${(personaData.tokens)} tokens + ${emojiGet('buttonBetSmall')} **Wallet:** ${personaData.tokens} `, ) .setFooter({ text: `${(interaction.member as GuildMember).displayName}'s TripSit RPG (BETA)`, iconURL: (interaction.member as GuildMember).user.displayAvatarURL() }); // eslint-disable-line max-len @@ -3220,7 +3525,7 @@ export async function rpgTrivia( *${timeOutMessage}* Earned: **${payout} tokens**${bonusMessage} - Wallet: ${(personaData.tokens)} tokens + ${emojiGet('buttonBetSmall')} **Wallet:** ${personaData.tokens} `, ) .setFooter({ text: `${(interaction.member as GuildMember).displayName}'s TripSit RPG (BETA)`, iconURL: (interaction.member as GuildMember).user.displayAvatarURL() }); // eslint-disable-line max-len diff --git a/src/discord/utils/imageGet.ts b/src/discord/utils/getAsset.ts similarity index 82% rename from src/discord/utils/imageGet.ts rename to src/discord/utils/getAsset.ts index dc401c7cd..271587f2c 100644 --- a/src/discord/utils/imageGet.ts +++ b/src/discord/utils/getAsset.ts @@ -3,6 +3,7 @@ import fs from 'fs'; import fp from 'path'; import axios from 'axios'; +import Canvas from '@napi-rs/canvas'; // import { // Client, // } from 'discord.js'; @@ -12,9 +13,7 @@ const F = f(__filename); // "get the path to this folder, and then join with /assets" const assetsDirectory = fp.join(fp.dirname(__dirname), 'assets'); -export default imageGet; - -const imageDef = { +const assetDef = { nasal_spray_dosage: { path: `${assetsDirectory}/img/nasal_spray_dosage.png`, url: 'https://user-images.githubusercontent.com/1836049/218758611-c84f1e34-0f5b-43ac-90da-bd89b028f131.png' }, icon_online: { path: `${assetsDirectory}/img/icons/online.png`, url: 'https://i.gyazo.com/cd7b9e018d4818e4b6588cab5d5b019d.png' }, icon_offline: { path: `${assetsDirectory}/img/icons/offline.png`, url: 'https://i.gyazo.com/b2b1bf7d91acdb4ccc72dfde3d7075fc.png' }, @@ -102,13 +101,29 @@ const imageDef = { Paws: { path: `${assetsDirectory}/img/backgrounds/Paws.png`, url: 'https://i.gyazo.com/83b9f275af87372edc610da449220a4c.png' }, mushroomInfoA: { path: `${assetsDirectory}/img/mushroomInfoA.png`, url: 'https://i.gyazo.com/233df47085a0ac5493d8378111512b3d.png' }, mushroomInfoB: { path: `${assetsDirectory}/img/mushroomInfoB.png`, url: 'https://i.gyazo.com/2aae45e843da99867b82e9b1ad07d22b.png' }, + Acme: { path: `${assetsDirectory}/font/Acme.woff2`, url: 'https://fonts.gstatic.com/s/acme/v25/RrQfboBx-C5_XxrBbg.woff2' }, + Agbalumo: { path: `${assetsDirectory}/font/Agbalumo.woff2`, url: 'https://fonts.gstatic.com/s/agbalumo/v2/55xvey5uMdT2N37KZfMCgLg.woff2' }, + Lobster: { path: `${assetsDirectory}/font/Lobster.woff2`, url: 'https://fonts.gstatic.com/s/lobster/v30/neILzCirqoswsqX9zoKmMw.woff2' }, + AbrilFatFace: { path: `${assetsDirectory}/font/AbrilFatFace.woff2`, url: 'https://fonts.gstatic.com/s/abrilfatface/v23/zOL64pLDlL1D99S8g8PtiKchq-dmjQ.woff2' }, + Satisfy: { path: `${assetsDirectory}/font/Satisfy.woff2`, url: 'https://fonts.gstatic.com/s/satisfy/v21/rP2Hp2yn6lkG50LoCZOIHQ.woff2' }, + IndieFlower: { path: `${assetsDirectory}/font/IndieFlower.woff2`, url: 'https://fonts.gstatic.com/s/indieflower/v21/m8JVjfNVeKWVnh3QMuKkFcZVaUuH.woff2' }, + BlackOpsOne: { path: `${assetsDirectory}/font/BlackOpsOne.woff2`, url: 'https://fonts.gstatic.com/s/blackopsone/v20/qWcsB6-ypo7xBdr6Xshe96H3aDvbtw.woff2' }, + LilitaOne: { path: `${assetsDirectory}/font/LilitaOne.woff2`, url: 'https://fonts.gstatic.com/s/lilitaone/v15/i7dPIFZ9Zz-WBtRtedDbYEF8RQ.woff2' }, + PressStart2P: { path: `${assetsDirectory}/font/PressStart2P.woff2`, url: 'https://fonts.gstatic.com/s/pressstart2p/v15/e3t4euO8T-267oIAQAu6jDQyK3nVivM.woff2' }, + Creepster: { path: `${assetsDirectory}/font/Creepster.woff2`, url: 'https://fonts.gstatic.com/s/creepster/v13/AlZy_zVUqJz4yMrniH4Rcn35.woff2' }, + SpecialElite: { path: `${assetsDirectory}/font/SpecialElite.woff2`, url: 'https://fonts.gstatic.com/s/specialelite/v18/XLYgIZbkc4JPUL5CVArUVL0ntnAOSA.woff2' }, + AudioWide: { path: `${assetsDirectory}/font/AudioWide.woff2`, url: 'https://fonts.gstatic.com/s/audiowide/v20/l7gdbjpo0cum0ckerWCdlg_O.woff2' }, + CabinSketch: { path: `${assetsDirectory}/font/CabinSketch.woff2`, url: 'https://fonts.gstatic.com/s/cabinsketch/v21/QGY2z_kZZAGCONcK2A4bGOj0I_1Y5tjz.woff2' }, + Rye: { path: `${assetsDirectory}/font/Rye.woff2`, url: 'https://fonts.gstatic.com/s/rye/v15/r05XGLJT86YzEZ7t.woff2' }, + FontdinerSwanky: { path: `${assetsDirectory}/font/FontdinerSwanky.woff2`, url: 'https://fonts.gstatic.com/s/fontdinerswanky/v23/ijwOs4XgRNsiaI5-hcVb4hQgMvCD0uYVKw.woff2' }, + Barcode: { path: `${assetsDirectory}/font/Barcode.woff2`, url: 'https://fonts.gstatic.com/s/librebarcode39/v21/-nFnOHM08vwC6h8Li1eQnP_AHzI2G_Bx0g.woff2' }, } as { [key: string]: { path: string; url: string; }; }; -export async function downloadImage( +export async function downloadAsset( url:string, filepath:string, ):Promise { @@ -140,22 +155,25 @@ export async function downloadImage( }); } -export async function imageGet( - imageName: string, +export default async function getAsset( + assetName: string, ): Promise { // This function will use imageName to look up the data in the imageDef object // It will use that information and check the path to see if the imageName exists at that location // If it does not exist, it will download it from the internet and save it to that location // Either way, it will return a working path to the image - const { path, url } = imageDef[imageName]; + const { path, url } = assetDef[assetName]; // log.debug(F, `Checking ${path}`); if (!fs.existsSync(path)) { // log.debug(F, `Downloading ${url} to ${path}`); - await downloadImage(url, path); - // log.debug(F, `Downloaded ${url} to ${path}`); + await downloadAsset(url, path); + + // If it's a font, register it to canvas + if (path.includes('.woff2')) { + Canvas.GlobalFonts.registerFromPath(path, assetName); + log.debug(F, `Registered ${assetName} to canvas`); + } } - // else { - // log.debug(F, `Found ${path}`); - // } + return path; } diff --git a/src/discord/utils/messageCommand.ts b/src/discord/utils/messageCommand.ts index 2e885c7f5..bb7229996 100644 --- a/src/discord/utils/messageCommand.ts +++ b/src/discord/utils/messageCommand.ts @@ -7,9 +7,12 @@ import { EmbedBuilder, } from 'discord.js'; import { stripIndents } from 'common-tags'; +import { PrismaClient } from '@prisma/client'; import { sleep } from '../commands/guild/d.bottest'; import { discordAiChat } from '../commands/guild/d.ai'; +const db = new PrismaClient({ log: ['error'] }); + // import log from '../../global/utils/log'; // import {parse} from 'path'; const F = f(__filename); // eslint-disable-line @@ -167,6 +170,50 @@ give people a chance to answer 😄 If no one answers in 5 minutes you can try a // If the bot was mentioned // log.debug(F, `Bot was mentioned in ${message.guild.name}!`); // eslint-disable-line + if (await isBotOwner(message) && message.content.toLowerCase().includes('tokens') && message.content.toLowerCase().includes('give')) { + // use regex to find the number in the message.cleanContent + const amount = parseInt(message.cleanContent.match(/(\d+)/)?.[0] ?? '0', 10); + + const recipients = message.mentions.users; + + recipients.forEach(async recipient => { + if (recipient.bot) return; + + const recipientMember = await message.guild?.members.fetch(recipient.id); + + if (!recipientMember) { + await message.channel.send('The user you mentioned is not a member of this guild!'); + return; + } + + const userData = await db.users.upsert({ + where: { discord_id: recipient.id }, + create: { discord_id: recipient.id }, + update: {}, + }); + + const personaData = await db.personas.upsert({ + where: { user_id: userData.id }, + create: { + user_id: userData.id, + tokens: amount, + }, + update: { + tokens: { + increment: amount, + }, + }, + }); + log.debug(F, `Gave ${amount} tokens to ${recipientMember.displayName}!`); + + await message.channel.send(stripIndents`Gave ${amount} tokens to ${recipientMember.displayName}! + + They now have ${personaData.tokens} tokens!`); + }); + + return; + } + if (await isBotOwner(message) && message.content.toLowerCase().includes('phoenix')) { const phoenixMessage = await message.channel.send('Phoenix protocol initiated... '); await sleep(1000);