diff --git a/src/discord/commands/guild/d.levels.ts b/src/discord/commands/guild/d.levels.ts index cb6232255..871becdd2 100644 --- a/src/discord/commands/guild/d.levels.ts +++ b/src/discord/commands/guild/d.levels.ts @@ -331,7 +331,7 @@ export const dLevels: SlashCommand = { // Default Progress Bars Calculate // const progressText = levelData.TEXT.TOTAL.level_exp / levelData.TEXT.TOTAL.nextLevel; - const progressTotal = levelData.ALL.TOTAL.level_exp / levelData.TEXT.TOTAL.nextLevel; + const progressTotal = levelData.ALL.TOTAL.level_exp / levelData.ALL.TOTAL.nextLevel; const progressGeneral = levelData.TEXT.GENERAL ? levelData.TEXT.GENERAL.level_exp / levelData.TEXT.GENERAL.nextLevel : 0; @@ -790,27 +790,27 @@ export const dLevels: SlashCommand = { // Choose and Draw the Level Image let LevelImagePath = '' as string; - if (levelData.TEXT.TOTAL.level < 10) { + if (levelData.ALL.TOTAL.level <= 9) { LevelImagePath = 'badgeVip0'; - } else if (levelData.TEXT.TOTAL.level < 20) { + } else if (levelData.ALL.TOTAL.level <= 19) { LevelImagePath = 'badgeVip1'; - } else if (levelData.TEXT.TOTAL.level < 30) { + } else if (levelData.ALL.TOTAL.level <= 29) { LevelImagePath = 'badgeVip2'; - } else if (levelData.TEXT.TOTAL.level < 40) { + } else if (levelData.ALL.TOTAL.level <= 39) { LevelImagePath = 'badgeVip3'; - } else if (levelData.TEXT.TOTAL.level < 50) { + } else if (levelData.ALL.TOTAL.level <= 49) { LevelImagePath = 'badgeVip4'; - } else if (levelData.TEXT.TOTAL.level < 60) { + } else if (levelData.ALL.TOTAL.level <= 59) { LevelImagePath = 'badgeVip5'; - } else if (levelData.TEXT.TOTAL.level < 70) { + } else if (levelData.ALL.TOTAL.level <= 69) { LevelImagePath = 'badgeVip6'; - } else if (levelData.TEXT.TOTAL.level < 80) { + } else if (levelData.ALL.TOTAL.level <= 79) { LevelImagePath = 'badgeVip7'; - } else if (levelData.TEXT.TOTAL.level < 90) { + } else if (levelData.ALL.TOTAL.level <= 89) { LevelImagePath = 'badgeVip8'; - } else if (levelData.TEXT.TOTAL.level < 100) { + } else if (levelData.ALL.TOTAL.level <= 99) { LevelImagePath = 'badgeVip9'; - } else if (levelData.TEXT.TOTAL.level >= 100) { + } else if (levelData.ALL.TOTAL.level >= 100) { LevelImagePath = 'badgeVip10'; } const LevelImage = await Canvas.loadImage(await imageGet(LevelImagePath)); diff --git a/src/discord/commands/guild/d.profile.ts b/src/discord/commands/guild/d.profile.ts index d9ce5666f..4b7e17889 100644 --- a/src/discord/commands/guild/d.profile.ts +++ b/src/discord/commands/guild/d.profile.ts @@ -514,25 +514,25 @@ export const dProfile: SlashCommand = { // Choose and Draw the Level Image let LevelImagePath = '' as string; - if (totalTextData.level < 10) { + if (totalTextData.level <= 9) { LevelImagePath = 'badgeVip0'; - } else if (totalTextData.level < 20) { + } else if (totalTextData.level <= 19) { LevelImagePath = 'badgeVip1'; - } else if (totalTextData.level < 30) { + } else if (totalTextData.level <= 29) { LevelImagePath = 'badgeVip2'; - } else if (totalTextData.level < 40) { + } else if (totalTextData.level <= 39) { LevelImagePath = 'badgeVip3'; - } else if (totalTextData.level < 50) { + } else if (totalTextData.level <= 49) { LevelImagePath = 'badgeVip4'; - } else if (totalTextData.level < 60) { + } else if (totalTextData.level <= 59) { LevelImagePath = 'badgeVip5'; - } else if (totalTextData.level < 70) { + } else if (totalTextData.level <= 69) { LevelImagePath = 'badgeVip6'; - } else if (totalTextData.level < 80) { + } else if (totalTextData.level <= 79) { LevelImagePath = 'badgeVip7'; - } else if (totalTextData.level < 90) { + } else if (totalTextData.level <= 89) { LevelImagePath = 'badgeVip8'; - } else if (totalTextData.level < 100) { + } else if (totalTextData.level <= 99) { LevelImagePath = 'badgeVip9'; } else if (totalTextData.level >= 100) { LevelImagePath = 'badgeVip10'; @@ -681,7 +681,7 @@ export async function getProfilePreview(target: GuildMember, imagePath: string, context.restore(); } - context.drawImage(Icons, 5, -2, 913, 292); + context.drawImage(Icons, 0, 0); // Overly complicated avatar clip (STATUS CLIP COMMENTED OUT) context.save(); diff --git a/src/discord/commands/guild/d.rpg.ts b/src/discord/commands/guild/d.rpg.ts index a68518275..da1334809 100644 --- a/src/discord/commands/guild/d.rpg.ts +++ b/src/discord/commands/guild/d.rpg.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-restricted-syntax */ /* eslint-disable max-len */ import { Colors, @@ -37,7 +38,7 @@ import { embedTemplate } from '../../utils/embedTemplate'; import { getPersonaInfo, setPersonaInfo } from '../../../global/commands/g.rpg'; import commandContext from '../../utils/context'; import { - getUser, inventoryGet, inventorySet, personaSet, + getUser, inventoryGet, inventorySet, inventoryDel, personaSet, } from '../../../global/utils/knex'; import { Personas, RpgInventory } from '../../../global/@types/database'; import { imageGet } from '../../utils/imageGet'; @@ -86,57 +87,72 @@ 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', + // }, + // }, backgrounds: { - Geolines: { - label: 'Geolines', - value: 'Geolines', - description: 'Geolines', + AbstractTriangles: { + label: 'AbstractTriangles', + value: 'AbstractTriangles', + description: 'Background', quantity: 1, weight: 0, cost: 1000, equipped: false, consumable: false, effect: 'background', - effect_value: 'Geolines', + effect_value: 'AbstractTriangles', emoji: 'itemBackground', }, - Waves: { - label: 'Waves', - value: 'Waves', - description: 'Waves', + ArcadeCarpet: { + label: 'ArcadeCarpet', + value: 'ArcadeCarpet', + description: 'Background', quantity: 1, weight: 0, cost: 1000, equipped: false, consumable: false, effect: 'background', - effect_value: 'Waves', + effect_value: 'ArcadeCarpet', emoji: 'itemBackground', }, - LiquidMaze: { - label: 'LiquidMaze', - value: 'LiquidMaze', - description: 'LiquidMaze', + CircuitBoard: { + label: 'CircuitBoard', + value: 'CircuitBoard', + description: 'Background', quantity: 1, weight: 0, cost: 1000, equipped: false, consumable: false, effect: 'background', - effect_value: 'LiquidMaze', + effect_value: 'CircuitBoard', emoji: 'itemBackground', }, - Flow: { - label: 'Flow', - value: 'Flow', - description: 'Flow', + CoffeeSwirl: { + label: 'CoffeeSwirl', + value: 'CoffeeSwirl', + description: 'Background', quantity: 1, weight: 0, cost: 1000, equipped: false, consumable: false, effect: 'background', - effect_value: 'Flow', + effect_value: 'CoffeeSwirl', emoji: 'itemBackground', }, Concentric: { @@ -152,6 +168,19 @@ const items = { effect_value: 'Concentric', emoji: 'itemBackground', }, + Connected: { + label: 'Connected', + value: 'Connected', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'Connected', + emoji: 'itemBackground', + }, CubeTunnels: { label: 'CubeTunnels', value: 'CubeTunnels', @@ -165,6 +194,149 @@ const items = { effect_value: 'CubeTunnels', emoji: 'itemBackground', }, + DiamondChevron: { + label: 'DiamondChevron', + value: 'DiamondChevron', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'DiamondChevron', + emoji: 'itemBackground', + }, + Dissociating: { + label: 'Dissociating', + value: 'Dissociating', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'Dissociating', + emoji: 'itemBackground', + }, + DotnDash: { + label: 'DotnDash', + value: 'DotnDash', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'DotnDash', + emoji: 'itemBackground', + }, + Drunk: { + label: 'Drunk', + value: 'Drunk', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'Drunk', + emoji: 'itemBackground', + }, + Emoticons: { + label: 'Emoticons', + value: 'Emoticons', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'Emoticons', + emoji: 'itemBackground', + }, + Equations: { + label: 'Equations', + value: 'Equations', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'Equations', + emoji: 'itemBackground', + }, + Flow: { + label: 'Flow', + value: 'Flow', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'Flow', + emoji: 'itemBackground', + }, + Flowers: { + label: 'Flowers', + value: 'Flowers', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'Flowers', + emoji: 'itemBackground', + }, + Geolines: { + label: 'Geolines', + value: 'Geolines', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'Geolines', + emoji: 'itemBackground', + }, + Halftone: { + label: 'Halftone', + value: 'Halftone', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'Halftone', + emoji: 'itemBackground', + }, + High: { + label: 'High', + value: 'High', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'High', + emoji: 'itemBackground', + }, Leaves: { label: 'Leaves', value: 'Leaves', @@ -178,9 +350,9 @@ const items = { effect_value: 'Leaves', emoji: 'itemBackground', }, - SquareTwist: { - label: 'SquareTwist', - value: 'SquareTwist', + LineLeaves: { + label: 'LineLeaves', + value: 'LineLeaves', description: 'Background', quantity: 1, weight: 0, @@ -188,7 +360,46 @@ const items = { equipped: false, consumable: false, effect: 'background', - effect_value: 'SquareTwist', + effect_value: 'LineLeaves', + emoji: 'itemBackground', + }, + LiquidMaze: { + label: 'LiquidMaze', + value: 'LiquidMaze', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'LiquidMaze', + emoji: 'itemBackground', + }, + Memphis: { + label: 'Memphis', + value: 'Memphis', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'Memphis', + emoji: 'itemBackground', + }, + Mindsets: { + label: 'Mindsets', + value: 'Mindsets', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'Mindsets', emoji: 'itemBackground', }, Noise: { @@ -204,9 +415,9 @@ const items = { effect_value: 'Noise', emoji: 'itemBackground', }, - Squiggles: { - label: 'Squiggles', - value: 'Squiggles', + Paisley: { + label: 'Paisley', + value: 'Paisley', description: 'Background', quantity: 1, weight: 0, @@ -214,12 +425,12 @@ const items = { equipped: false, consumable: false, effect: 'background', - effect_value: 'Squiggles', + effect_value: 'Paisley', emoji: 'itemBackground', }, - TriangleOverlap: { - label: 'TriangleOverlap', - value: 'TriangleOverlap', + Paws: { + label: 'Paws', + value: 'Paws', description: 'Background', quantity: 1, weight: 0, @@ -227,12 +438,12 @@ const items = { equipped: false, consumable: false, effect: 'background', - effect_value: 'TriangleOverlap', + effect_value: 'Paws', emoji: 'itemBackground', }, - XandO: { - label: 'XandO', - value: 'XandO', + PixelCamo: { + label: 'PixelCamo', + value: 'PixelCamo', description: 'Background', quantity: 1, weight: 0, @@ -240,7 +451,33 @@ const items = { equipped: false, consumable: false, effect: 'background', - effect_value: 'XandO', + effect_value: 'PixelCamo', + emoji: 'itemBackground', + }, + Plaid: { + label: 'Plaid', + value: 'Plaid', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'Plaid', + emoji: 'itemBackground', + }, + Rolling: { + label: 'Rolling', + value: 'Rolling', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'Rolling', emoji: 'itemBackground', }, Safari: { @@ -256,9 +493,9 @@ const items = { effect_value: 'Safari', emoji: 'itemBackground', }, - LineLeaves: { - label: 'LineLeaves', - value: 'LineLeaves', + Sedated: { + label: 'Sedated', + value: 'Sedated', description: 'Background', quantity: 1, weight: 0, @@ -266,12 +503,12 @@ const items = { equipped: false, consumable: false, effect: 'background', - effect_value: 'LineLeaves', + effect_value: 'Sedated', emoji: 'itemBackground', }, - ArcadeCarpet: { - label: 'ArcadeCarpet', - value: 'ArcadeCarpet', + SpaceIcons: { + label: 'SpaceIcons', + value: 'SpaceIcons', description: 'Background', quantity: 1, weight: 0, @@ -279,12 +516,12 @@ const items = { equipped: false, consumable: false, effect: 'background', - effect_value: 'ArcadeCarpet', + effect_value: 'SpaceIcons', emoji: 'itemBackground', }, - Topography: { - label: 'Topography', - value: 'Topography', + Sprinkles: { + label: 'Sprinkles', + value: 'Sprinkles', description: 'Background', quantity: 1, weight: 0, @@ -292,12 +529,12 @@ const items = { equipped: false, consumable: false, effect: 'background', - effect_value: 'Topography', + effect_value: 'Sprinkles', emoji: 'itemBackground', }, - CoffeeSwirl: { - label: 'CoffeeSwirl', - value: 'CoffeeSwirl', + SquareTwist: { + label: 'SquareTwist', + value: 'SquareTwist', description: 'Background', quantity: 1, weight: 0, @@ -305,12 +542,12 @@ const items = { equipped: false, consumable: false, effect: 'background', - effect_value: 'CoffeeSwirl', + effect_value: 'SquareTwist', emoji: 'itemBackground', }, - SpaceIcons: { - label: 'SpaceIcons', - value: 'SpaceIcons', + Squiggles: { + label: 'Squiggles', + value: 'Squiggles', description: 'Background', quantity: 1, weight: 0, @@ -318,12 +555,12 @@ const items = { equipped: false, consumable: false, effect: 'background', - effect_value: 'SpaceIcons', + effect_value: 'Squiggles', emoji: 'itemBackground', }, - Plaid: { - label: 'Plaid', - value: 'Plaid', + Stimming: { + label: 'Stimming', + value: 'Stimming', description: 'Background', quantity: 1, weight: 0, @@ -331,12 +568,12 @@ const items = { equipped: false, consumable: false, effect: 'background', - effect_value: 'Plaid', + effect_value: 'Stimming', emoji: 'itemBackground', }, - Paisley: { - label: 'Paisley', - value: 'Paisley', + Topography: { + label: 'Topography', + value: 'Topography', description: 'Background', quantity: 1, weight: 0, @@ -344,12 +581,12 @@ const items = { equipped: false, consumable: false, effect: 'background', - effect_value: 'Paisley', + effect_value: 'Topography', emoji: 'itemBackground', }, - AbstractTriangles: { - label: 'AbstractTriangles', - value: 'AbstractTriangles', + TriangleOverlap: { + label: 'TriangleOverlap', + value: 'TriangleOverlap', description: 'Background', quantity: 1, weight: 0, @@ -357,12 +594,12 @@ const items = { equipped: false, consumable: false, effect: 'background', - effect_value: 'AbstractTriangles', + effect_value: 'TriangleOverlap', emoji: 'itemBackground', }, - Memphis: { - label: 'Memphis', - value: 'Memphis', + Tripping: { + label: 'Tripping', + value: 'Tripping', description: 'Background', quantity: 1, weight: 0, @@ -370,12 +607,12 @@ const items = { equipped: false, consumable: false, effect: 'background', - effect_value: 'Memphis', + effect_value: 'Tripping', emoji: 'itemBackground', }, - Connected: { - label: 'Connected', - value: 'Connected', + Waves: { + label: 'Waves', + value: 'Waves', description: 'Background', quantity: 1, weight: 0, @@ -383,7 +620,20 @@ const items = { equipped: false, consumable: false, effect: 'background', - effect_value: 'Connected', + effect_value: 'Waves', + emoji: 'itemBackground', + }, + XandO: { + label: 'XandO', + value: 'XandO', + description: 'Background', + quantity: 1, + weight: 0, + cost: 1000, + equipped: false, + consumable: false, + effect: 'background', + effect_value: 'XandO', emoji: 'itemBackground', }, }, @@ -972,24 +1222,27 @@ export async function rpgMarketInventory( ` : ''; - // Go through items.general and create a new object of items that the user doesn't have yet - const marketInventory = [...Object.values(items.general), ...Object.values(items.backgrounds)] - .map(item => { + interface MarketItem extends SelectMenuComponentOptionData { + category: string; + } + + // Go through items.general and items.backgrounds and create a new object of items that the user doesn't have yet + const marketInventory: MarketItem[] = []; + + for (const [category, categoryItems] of Object.entries(items)) { + for (const item of Object.values(categoryItems)) { if (!inventoryData.find(i => i.value === item.value)) { - // log.debug(F, `item: ${JSON.stringify(item, null, 2)}`); - // log.debug(F, `item.emoji: ${item.emoji}`); - // log.debug(F, `emojiGet(item.emoji): ${emojiGet(item.emoji)}`); - return { + marketInventory.push({ label: `${item.label} - ${item.cost} TT$`, value: item.value, description: `${item.description}`, emoji: emojiGet(item.emoji).id, - }; + category, + }); } - return null; - }) - .filter(item => item !== null) as SelectMenuComponentOptionData[]; - // log.debug(F, `generalOptions: ${JSON.stringify(marketInventory, null, 2)}`); + } + } + return { marketInventory, personaTokens: personaData.tokens, @@ -1007,19 +1260,6 @@ export async function rpgMarket( personaInventory, } = await rpgMarketInventory(interaction); - // log.debug(F, `marketInventory: ${JSON.stringify(marketInventory, null, 2)}`); - // log.debug(F, `personaTokens: ${personaTokens}`); - // log.debug(F, `personaInventory: ${JSON.stringify(personaInventory, null, 2)}`); - - // Create the market buttons - This is a select menu - const rowItems = new ActionRowBuilder() - .addComponents( - new StringSelectMenuBuilder() - .setCustomId(`rpgGeneralSelect,user:${interaction.user.id}`) - .setPlaceholder('Select an item to buy') - .setOptions(marketInventory), - - ); // This is the row of nav buttons. It starts with the town button. const rowMarket = new ActionRowBuilder() .addComponents( @@ -1028,12 +1268,39 @@ export async function rpgMarket( // Everyone gets the town button, but only people with purchased items get the items select menu const componentList = [rowMarket] as ActionRowBuilder[]; - // log.debug(F, `marketInventory.length: ${marketInventory.length}`); - // log.debug(F, `componentList: ${JSON.stringify(componentList, null, 2)}`); - if (marketInventory.length > 0) { componentList.unshift(rowItems); } + interface MarketItem extends SelectMenuComponentOptionData { + category: string; + } - // log.debug(F, `componentList: ${JSON.stringify(componentList, null, 2)}`); + // Group marketInventory items by their category property + const groups = (marketInventory as MarketItem[]).reduce((groupData: Record, item) => { + const { category } = item; + const newGroupData = { ...groupData }; + newGroupData[category] = newGroupData[category] ? [...newGroupData[category], item] : [item]; + return newGroupData; + }, {}); + + // For each group, split the group into chunks of 20 items each and create a new rowItems for each chunk + for (const [group, itemsData] of Object.entries(groups)) { + // Create chunks of 20 items each + const chunks = []; + for (let i = 0; i < itemsData.length; i += 25) { + chunks.push(itemsData.slice(i, i + 25)); + } + + // Create a new rowItems for each chunk + for (const [index, chunk] of chunks.entries()) { + const rowItems = new ActionRowBuilder() + .addComponents( + new StringSelectMenuBuilder() + .setCustomId(`rpgGeneralSelect,user:${interaction.user.id},group:${group},chunk:${index}`) + .setPlaceholder(`${group.charAt(0).toUpperCase() + group.slice(1)} Page ${index + 1}`) + .addOptions(chunk), + ); + componentList.push(rowItems); + } + } // The user has clicked the market button, send them the market embed return { @@ -1045,6 +1312,7 @@ export async function rpgMarket( 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) ***More items coming soon! Check back later.*** Wallet: ${personaTokens} tokens @@ -1068,10 +1336,23 @@ export async function rpgMarketChange( // Get the item the user selected let choice = '' as string; if (interaction.isButton()) { - const itemComponent = interaction.message.components[0].components[0]; - const selectedItem = (itemComponent as StringSelectMenuComponent).options.find( - (o:APISelectMenuOption) => o.default === true, - ); + // const itemComponent = interaction.message.components[0].components[0]; + let selectedItem: APISelectMenuOption | undefined; + for (const component of interaction.message.components) { + for (const subComponent of component.components) { + if (subComponent.type === ComponentType.SelectMenu) { + selectedItem = (subComponent as StringSelectMenuComponent).options.find( + (o:APISelectMenuOption) => o.default === true, + ); + if (selectedItem) { + break; + } + } + } + if (selectedItem) { + break; + } + } choice = selectedItem?.value ?? ''; } else if (interaction.isStringSelectMenu()) { [choice] = interaction.values; @@ -1080,10 +1361,9 @@ export async function rpgMarketChange( // log.debug(F, `choice: ${choice}`); // Get a list of marketInventory where the value does not equal the choice - const filteredItems = Object.values(marketInventory).filter(item => item.value !== choice); + // const filteredItems = Object.values(marketInventory).filter(item => item.value !== choice); const stringMenu = new StringSelectMenuBuilder() - .setOptions(filteredItems) .setCustomId(`rpgGeneralSelect,user:${interaction.user.id}`) .setPlaceholder('Select an item to buy'); @@ -1122,9 +1402,6 @@ export async function rpgMarketChange( // log.debug(F, `itemData (change): ${JSON.stringify(itemData, null, 2)}`); } - const rowItems = new ActionRowBuilder() - .addComponents(stringMenu); - const rowMarket = new ActionRowBuilder() .addComponents( customButton(`rpgTown,user:${interaction.user.id}`, 'Town', 'buttonTown', ButtonStyle.Primary), @@ -1141,10 +1418,39 @@ export async function rpgMarketChange( ); } - const components = stringMenu.options.length === 0 - ? [rowMarket] - : [rowItems, rowMarket]; + const components = [rowMarket] as ActionRowBuilder[]; + interface MarketItem extends SelectMenuComponentOptionData { + category: string; + } + + const groups = (marketInventory as MarketItem[]).reduce((groupData: Record, item) => { + const { category } = item; + const newGroupData = { ...groupData }; + newGroupData[category] = newGroupData[category] ? [...newGroupData[category], item] : [item]; + return newGroupData; + }, {}); + + // For each group, split the group into chunks of 25 items each and create a new rowItems for each chunk + for (const [group, itemsData] of Object.entries(groups)) { + // Create chunks of 25 items each + const chunks = []; + for (let i = 0; i < itemsData.length; i += 25) { + chunks.push(itemsData.slice(i, i + 25)); + } + + // Create a new rowItems for each chunk + for (const [index, chunk] of chunks.entries()) { + const rowItems = new ActionRowBuilder() + .addComponents( + new StringSelectMenuBuilder() + .setCustomId(`rpgGeneralSelect,user:${interaction.user.id},group:${group},chunk:${index}`) + .setPlaceholder(`${group.charAt(0).toUpperCase() + group.slice(1)} Page ${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() }) @@ -1153,6 +1459,7 @@ export async function rpgMarketChange( 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) ***More items coming soon! Check back later.*** Wallet: ${personaTokens} tokens @@ -1190,10 +1497,22 @@ export async function rpgMarketPreview( // log.debug(F, `personaData (Accept): ${JSON.stringify(personaData, null, 2)}`); // If the user confirms the information, save the persona information - const itemComponent = interaction.message.components[0].components[0]; - const selectedItem = (itemComponent as StringSelectMenuComponent).options.find( - (o:APISelectMenuOption) => o.default === true, - ); + let selectedItem: APISelectMenuOption | undefined; + for (const component of interaction.message.components) { + for (const subComponent of component.components) { + if (subComponent.type === ComponentType.SelectMenu) { + selectedItem = (subComponent as StringSelectMenuComponent).options.find( + (o:APISelectMenuOption) => o.default === true, + ); + if (selectedItem) { + break; + } + } + } + if (selectedItem) { + break; + } + } // log.debug(F, `selectedItem (accept): ${JSON.stringify(selectedItem, null, 2)}`); const allItems = [...Object.values(items.general), ...Object.values(items.backgrounds)]; @@ -1259,11 +1578,23 @@ export async function rpgMarketAccept( // log.debug(F, `personaData (Accept): ${JSON.stringify(personaData, null, 2)}`); // If the user confirms the information, save the persona information - const itemComponent = interaction.message.components[0].components[0]; - const selectedItem = (itemComponent as StringSelectMenuComponent).options.find( - (o:APISelectMenuOption) => o.default === true, - ); - // log.debug(F, `selectedItem (accept): ${JSON.stringify(selectedItem, null, 2)}`); + let selectedItem: APISelectMenuOption | undefined; + for (const component of interaction.message.components) { + for (const subComponent of component.components) { + if (subComponent.type === ComponentType.SelectMenu) { + selectedItem = (subComponent as StringSelectMenuComponent).options.find( + (o:APISelectMenuOption) => o.default === true, + ); + if (selectedItem) { + break; + } + } + } + if (selectedItem) { + break; + } + } + log.debug(F, `selectedItem (accept): ${JSON.stringify(selectedItem, null, 2)}`); const allItems = [...Object.values(items.general), ...Object.values(items.backgrounds)]; const itemData = allItems.find(item => item.value === selectedItem?.value) as { @@ -1387,6 +1718,8 @@ export async function rpgHomeInventory( label: `${item.label} - ${item.cost} TT$`, value: item.value, description: `${item.description}`, + cost: item.cost, + equipped: item.equipped, emoji: emojiGet(item.emoji).id, }; } @@ -1584,6 +1917,13 @@ export async function rpgHome( emoji: string; }; const chosenItem = homeInventory.find(item => item.value === defaultOption); + let sellPrice = 0; + const equipped = (inventoryData.find(item => item.value === chosenItem?.value)?.equipped as boolean); + let equippedButtonText = 'Equip'; + if (equipped) { + equippedButtonText = 'Equipped'; + } + if (chosenItem) { chosenItem.default = true; backgroundMenu.addOptions(chosenItem); @@ -1608,8 +1948,12 @@ export async function rpgHome( effect_value: string; emoji: string; }; + sellPrice = (allItems.find(item => item.value === chosenItem?.value)?.cost as number) / 4; + log.debug(F, `equipped: ${equipped}`); + log.debug(F, `sellPrice: ${sellPrice}`); // log.debug(F, `backgroundData (home change): ${JSON.stringify(backgroundData, null, 2)}`); } + log.debug(F, `chosenItem: ${JSON.stringify(chosenItem, null, 2)}`); // Set the item row const rowBackgrounds = new ActionRowBuilder() @@ -1671,9 +2015,18 @@ export async function rpgHome( customButton(`rpgTown,user:${interaction.user.id}`, 'Town', 'buttonTown', ButtonStyle.Primary), ); - if (chosenItem && (interaction.isStringSelectMenu() || interaction.isButton())) { + // if item is not equipped, show equip button + + if (chosenItem && (equipped === false)) { + 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(`rpgAccept,user:${interaction.user.id}`, 'Accept', 'buttonAccept', ButtonStyle.Success), + 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), ); } @@ -1841,8 +2194,8 @@ export async function rpgHomeAccept( log.error(F, `Item not found in inventory: ${JSON.stringify(chosenItem, null, 2)}`); } - // Un-equip all other items - const otherItems = inventoryData.filter(item => item.value !== selectedItem?.value); + // Un-equip all other backgrounds + const otherItems = inventoryData.filter(item => item.effect === 'background' && item.value !== selectedItem?.value); otherItems.forEach(item => { const newItem = item; newItem.equipped = false; @@ -1867,6 +2220,55 @@ export async function rpgHomeAccept( }; } +export async function rpgHomeDecline( + interaction: MessageComponentInteraction, +):Promise { + // Check get fresh persona data + const personaData = await getPersonaInfo(interaction.user.id); + const itemComponent = interaction.message.components[0].components[0]; + const selectedItem = (itemComponent as StringSelectMenuComponent).options.find( + (o:APISelectMenuOption) => o.default === true, + ); + + const inventoryData = await inventoryGet(personaData.id); + const chosenItem = inventoryData.find(item => item.value === selectedItem?.value); + if (chosenItem) { + chosenItem.equipped = false; + await inventorySet(chosenItem); + } + const { embeds, components, files } = await rpgHome(interaction, `**You have unequipped ${chosenItem?.label}.**\n`); + return { + embeds, + components, + files, + }; +} + +export async function rpgHomeSell( + interaction: MessageComponentInteraction, +):Promise { + // Check get fresh persona data + const personaData = await getPersonaInfo(interaction.user.id); + const inventoryData = await inventoryGet(personaData.id); + const itemComponent = interaction.message.components[0].components[0]; + const selectedItem = (itemComponent as StringSelectMenuComponent).options.find( + (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; + await inventoryDel(personaData.id, selectedItem?.value as string); + + personaData.tokens += sellPrice; + await personaSet(personaData); + log.debug(F, `itemName: ${JSON.stringify(itemName, null, 2)}`); + const { embeds, components, files } = await rpgHome(interaction, `**You have sold ${itemName} for ${sellPrice} TripTokens!**\n`); + return { + embeds, + components, + files, + }; +} + export async function rpgArcade( interaction: MessageComponentInteraction | ChatInputCommandInteraction, ):Promise { diff --git a/src/discord/events/buttonClick.ts b/src/discord/events/buttonClick.ts index 1dca82ad4..39942a46d 100644 --- a/src/discord/events/buttonClick.ts +++ b/src/discord/events/buttonClick.ts @@ -20,7 +20,7 @@ import { techHelpClick, techHelpClose, techHelpOwn } from '../utils/techHelp'; import { verifyButton } from '../utils/verifyButton'; import { buttonReactionRole } from '../commands/global/d.reactionRole'; import { - rpgArcade, rpgArcadeGame, rpgArcadeWager, rpgBounties, rpgHelp, rpgHome, rpgHomeAccept, rpgHomeNameChange, rpgMarket, rpgMarketAccept, rpgMarketPreview, rpgTown, rpgTrivia, + rpgArcade, rpgArcadeGame, rpgArcadeWager, rpgBounties, rpgHelp, rpgHome, rpgHomeAccept, rpgHomeDecline, rpgHomeSell, rpgHomeNameChange, rpgMarket, rpgMarketAccept, rpgMarketPreview, rpgTown, rpgTrivia, } from '../commands/guild/d.rpg'; import { helperButton } from '../commands/global/d.setup'; import { appealAccept, appealReject } from '../utils/appeal'; @@ -99,6 +99,8 @@ export async function buttonClick(interaction:ButtonInteraction, discordClient:C else if (interaction.customId.split(',')[0] === 'rpgGuild') await interaction.editReply(await rpgHome(interaction, '')); else if (interaction.customId.split(',')[0] === 'rpgName') await rpgHomeNameChange(interaction); else if (interaction.customId.split(',')[0] === 'rpgAccept') await interaction.editReply(await rpgHomeAccept(interaction)); + else if (interaction.customId.split(',')[0] === 'rpgDecline') await interaction.editReply(await rpgHomeDecline(interaction)); + else if (interaction.customId.split(',')[0] === 'rpgSell') await interaction.editReply(await rpgHomeSell(interaction)); else if (interaction.customId.split(',')[0] === 'rpgMarketBuy') await interaction.editReply(await rpgMarketAccept(interaction)); else if (interaction.customId.split(',')[0] === 'rpgMarketPreview') await interaction.editReply(await rpgMarketPreview(interaction)); else if (interaction.customId.split(',')[0] === 'rpgMarket') await interaction.editReply(await rpgMarket(interaction)); diff --git a/src/discord/utils/imageGet.ts b/src/discord/utils/imageGet.ts index bb934c71a..dc401c7cd 100644 --- a/src/discord/utils/imageGet.ts +++ b/src/discord/utils/imageGet.ts @@ -43,6 +43,9 @@ const imageDef = { campIconA: { path: `${assetsDirectory}/img/campIconA.png`, url: 'https://i.gyazo.com/62a9db6c42ca3c03cc892b28f5d8b367.png' }, cardIcons: { path: `${assetsDirectory}/img/cards/icons.png`, url: 'https://i.gyazo.com/1f33cc53c5102c3cbdb751368cb5059c.png' }, cardLevelIcons: { path: `${assetsDirectory}/img/cards/levelIcons.png`, url: 'https://i.gyazo.com/739f8b68658b9aeeedfb6d5aaf07dc68.png' }, + karmaScale: { path: `${assetsDirectory}/img/cards/karmaScale.png`, url: 'https://i.gyazo.com/8cf140f384aeb61bb2929cccf3d7a8c2.png' }, + karmaContainer: { path: `${assetsDirectory}/img/cards/karmaContainer.png`, url: 'https://i.gyazo.com/4b10b62f315e41d90ee99d6f70c14787.png' }, + karmaFill: { path: `${assetsDirectory}/img/cards/karmaFill.png`, url: 'https://i.gyazo.com/4a5aa5d098e09370e4a257c451c7aaf9.png' }, // cardBackground: { path: `${assetsDirectory}/img/cards/background.png`, url: 'https://i.gyazo.com/b7504ea55bd7935f97b286407a1bc259.png' }, // cardBirthdayOverlay: { path: `${assetsDirectory}/img/cards/birthdayOverlay.png`, url: 'https://i.gyazo.com/b7504ea55bd7935f97b286407a1bc259.png' }, // cardDefault: { path: `${assetsDirectory}/img/cards/default.png`, url: 'https://i.gyazo.com/b7504ea55bd7935f97b286407a1bc259.png' }, @@ -80,6 +83,23 @@ const imageDef = { AbstractTriangles: { path: `${assetsDirectory}/img/backgrounds/AbstractTriangles.png`, url: 'https://i.gyazo.com/41194844db3ad5929f919b3b8f922f9c.png' }, Memphis: { path: `${assetsDirectory}/img/backgrounds/Memphis.png`, url: 'https://i.gyazo.com/6b08f0dad9dcf36c458071496d6052d3.png' }, Connected: { path: `${assetsDirectory}/img/backgrounds/Connected.png`, url: 'https://i.gyazo.com/8a948ed8bff1f7377dbbd12d3c467d78.png' }, + CircuitBoard: { path: `${assetsDirectory}/img/backgrounds/CircuitBoard.png`, url: 'https://i.gyazo.com/4bbba848e8351342480563ab118dccaa.png' }, + Dissociating: { path: `${assetsDirectory}/img/backgrounds/Dissociating.png`, url: 'https://i.gyazo.com/969c0b7a31fc24fb0e4b3e07a0609e58.png' }, + DotnDash: { path: `${assetsDirectory}/img/backgrounds/DotnDash.png`, url: 'https://i.gyazo.com/01e6c58a9a5e7aa1723b7f1b353536aa.png' }, + Drunk: { path: `${assetsDirectory}/img/backgrounds/Drunk.png`, url: 'https://i.gyazo.com/b19df7b88170d8b9aea4e3755d17442a.png' }, + Halftone: { path: `${assetsDirectory}/img/backgrounds/Halftone.png`, url: 'https://i.gyazo.com/746492feb876d89b47b587a11c99cd7e.png' }, + High: { path: `${assetsDirectory}/img/backgrounds/High.png`, url: 'https://i.gyazo.com/ce784d66c81e190b3439b8057183d56b.png' }, + Mindsets: { path: `${assetsDirectory}/img/backgrounds/Mindsets.png`, url: 'https://i.gyazo.com/e57ca09564d15878eb3dd2fa5e8e7f46.png' }, + PixelCamo: { path: `${assetsDirectory}/img/backgrounds/PixelCamo.png`, url: 'https://i.gyazo.com/269728ae29ec5d8de62e697ed6b51580.png' }, + Rolling: { path: `${assetsDirectory}/img/backgrounds/Rolling.png`, url: 'https://i.gyazo.com/59e9fb8897bc2e8eeda1562d5cc1ec1b.png' }, + Sedated: { path: `${assetsDirectory}/img/backgrounds/Sedated.png`, url: 'https://i.gyazo.com/54f6b48bb33523b14b8b97960d14060f.png' }, + Sprinkles: { path: `${assetsDirectory}/img/backgrounds/Sprinkles.png`, url: 'https://i.gyazo.com/c7fda9a04850bfc504e2a9fe895045f6.png' }, + Stimming: { path: `${assetsDirectory}/img/backgrounds/Stimming.png`, url: 'https://i.gyazo.com/78c8675c2113502b8feb9f715b5279da.png' }, + Tripping: { path: `${assetsDirectory}/img/backgrounds/Tripping.png`, url: 'https://i.gyazo.com/4dc61d4745de62fea7a61188bb77c096.png' }, + Emoticons: { path: `${assetsDirectory}/img/backgrounds/Emoticons.png`, url: 'https://i.gyazo.com/898db3d481c303f4c38d74973d5e4a14.png' }, + Equations: { path: `${assetsDirectory}/img/backgrounds/Equations.png`, url: 'https://i.gyazo.com/561e9cd1ca3b02608c7f9e5f1908d6d9.png' }, + Flowers: { path: `${assetsDirectory}/img/backgrounds/Flowers.png`, url: 'https://i.gyazo.com/2e1d47f128305b2f12fe2c4bb7db75d2.png' }, + 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' }, } as { diff --git a/src/global/utils/knex.ts b/src/global/utils/knex.ts index f4794883b..5b30f01a0 100644 --- a/src/global/utils/knex.ts +++ b/src/global/utils/knex.ts @@ -1031,6 +1031,23 @@ export async function inventorySet( } } +export async function inventoryDel( + personaId:string, + value:string, +):Promise { +// log.debug(F, 'useractionsGet started'); + if (env.POSTGRES_DB_URL === undefined) return; + try { + await db('rpg_inventory') + .delete() + .where('persona_id', personaId) + .andWhere('value', value); + } catch (err) { + log.error(F, `Error deleting inventory: ${err}`); + log.error(F, `personaId: ${personaId} | value: ${value}`); + } +} + export async function countingGet( channelID:string, ):Promise {