From 85055e89fff81dcb1fd42487935eaa1d2cccc495 Mon Sep 17 00:00:00 2001 From: Milo Date: Thu, 24 Apr 2025 14:22:07 +0200 Subject: [PATCH 1/2] APO first tests --- index.js | 13 ++++++++++++- utils.js | 25 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 5be4383..641ba42 100644 --- a/index.js +++ b/index.js @@ -14,7 +14,9 @@ import { //getOnlineUsersWithRole, formatTime, gork, - getRandomHydrateText + getRandomHydrateText, + getAPOUsers, + postAPOBuy } from './utils.js'; import { getShuffledOptions, getResult } from './game.js'; import { Client, GatewayIntentBits, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } from 'discord.js'; @@ -506,6 +508,14 @@ client.on('messageCreate', async (message) => { message.channel.send(`${content}`) .catch(console.error); } + else if (message.content.toLowerCase().startsWith('?u')) { + console.log(await getAPOUsers()) + } + else if (message.content.toLowerCase().startsWith('?b')) { + const amount = message.content.replace('?b ', '') + console.log(amount) + console.log(await postAPOBuy('650338922874011648', amount)) + } }); // Once bot is ready @@ -544,6 +554,7 @@ client.once('ready', async () => { const randomMinute = Math.floor(Math.random() * 60); const randomHour = Math.floor(Math.random() * (18 - 8 + 1)) + 8; todaysHydrateCron = `${randomMinute} ${randomHour} * * *` + console.log(todaysHydrateCron) const guild = await client.guilds.fetch(process.env.GUILD_ID); const roleId = process.env.VOTING_ROLE_ID; // Set this in your .env file diff --git a/utils.js b/utils.js index f42ae32..7747c83 100644 --- a/utils.js +++ b/utils.js @@ -162,4 +162,29 @@ export async function gork(messageHistory) { } else { return "Pas d'IA" } +} + +export async function getAPOUsers() { + const fetchUrl = process.env.APO_BASE_URL + '/users?serverId=' + (process.env.T12_GUILD_ID ?? process.env.GUILD_ID) + console.log(fetchUrl) + return await fetch(fetchUrl) + .then(response => { + if (!response.ok) { + throw new Error('Error fetching APO users') + } + return response.json() + }) + .catch(error => { + console.error('There was a problem with the fetch operation:', error); + }); +} + +export async function postAPOBuy(userId, amount) { + const fetchUrl = process.env.APO_BASE_URL + '/buy?serverId=' + (process.env.T12_GUILD_ID ?? process.env.GUILD_ID) + '&userId=' + userId + '&amount=' + amount + console.log(fetchUrl) + return await fetch(fetchUrl, { + method: 'POST', + }) + .then(response => response.status + ': ' + response.statusText + ' - ' + response.ok) + .catch(error => console.log('Post error:', error)) } \ No newline at end of file From ba419100c0e3293e2f3d1a52b19ca53a5a66b651 Mon Sep 17 00:00:00 2001 From: milo Date: Thu, 24 Apr 2025 21:27:45 +0200 Subject: [PATCH 2/2] skins upgrade --- commands.js | 2 +- index.js | 386 ++++++++++++++++++++++++++++++++++++++++++++--- init_database.js | 2 +- utils.js | 2 +- 4 files changed, 368 insertions(+), 24 deletions(-) diff --git a/commands.js b/commands.js index 1118ece..7cd6bae 100644 --- a/commands.js +++ b/commands.js @@ -85,7 +85,7 @@ const TIMEOUT_COMMAND = { // Valorant const VALORANT_COMMAND = { name: 'valorant', - description: 'Ouvrir une caisse valorant', + description: `Ouvrir une caisse valorant (${process.env.VALO_PRICE}€)`, type: 1, integration_types: [0, 1], contexts: [0, 2], diff --git a/index.js b/index.js index 641ba42..9f1d6c1 100644 --- a/index.js +++ b/index.js @@ -904,10 +904,13 @@ app.post('/interactions', verifyKeyMiddleware(process.env.PUBLIC_KEY), async fun userId: userId, page: 0, amount: invSkins.length, + reqBodyId: req.body.id, endpoint: `webhooks/${process.env.APP_ID}/${req.body.token}/messages/@original`, timestamp: Date.now(), }; + console.log(activeInventories[id].reqBodyId); + if (invSkins.length === 0) { return res.send({ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, @@ -943,6 +946,30 @@ app.post('/interactions', verifyKeyMiddleware(process.env.PUBLIC_KEY), async fun return trueSkin.displayIcon }; + let components = [ + { + type: MessageComponentTypes.BUTTON, + custom_id: `prev_page_${req.body.id}`, + label: '⏮️ Préc.', + style: ButtonStyleTypes.SECONDARY, + }, + { + type: MessageComponentTypes.BUTTON, + custom_id: `next_page_${req.body.id}`, + label: 'Suiv. ⏭️', + style: ButtonStyleTypes.SECONDARY, + }, + ] + + if ((invSkins[0].currentLvl < trueSkin.levels.length || invSkins[0].currentChroma < trueSkin.chromas.length) && akhy === userId) { + components.push({ + type: MessageComponentTypes.BUTTON, + custom_id: `upgrade_${req.body.id}`, + label: `Upgrade ⏫`, + style: ButtonStyleTypes.PRIMARY, + }) + } + return res.send({ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, data: { @@ -961,20 +988,7 @@ app.post('/interactions', verifyKeyMiddleware(process.env.PUBLIC_KEY), async fun components: [ { type: MessageComponentTypes.ACTION_ROW, - components: [ - { - type: MessageComponentTypes.BUTTON, - custom_id: `prev_page_${req.body.id}`, - label: '⏮️ Préc.', - style: ButtonStyleTypes.SECONDARY, - }, - { - type: MessageComponentTypes.BUTTON, - custom_id: `next_page_${req.body.id}`, - label: 'Suiv. ⏭️', - style: ButtonStyleTypes.SECONDARY, - }, - ], + components: components, }, ], }, @@ -982,6 +996,18 @@ app.post('/interactions', verifyKeyMiddleware(process.env.PUBLIC_KEY), async fun } if (name === 'valorant') { + const buyResponse = await postAPOBuy(req.body.member.user.id, process.env.VALO_PRICE ?? 150) + + if (buyResponse.status === 500 || buyResponse.ok === false) { + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Tu n'as pas assez d'argent...`, + flags: InteractionResponseFlags.EPHEMERAL, + } + }); + } + // First, send the initial response immediately const initialEmbed = new EmbedBuilder() .setTitle(`\t`) @@ -1019,15 +1045,13 @@ app.post('/interactions', verifyKeyMiddleware(process.env.PUBLIC_KEY), async fun // Generate random level and chroma const randomLevel = Math.floor(Math.random() * randomSkin.levels.length + 1); - const randomChroma = randomLevel === randomSkin.levels.length + let randomChroma = randomLevel === randomSkin.levels.length ? Math.floor(Math.random() * randomSkin.chromas.length + 1) : 1; - + if (randomChroma === randomSkin.chromas.length && randomSkin.chromas.length >= 2) randomChroma-- const selectedLevel = randomSkin.levels[randomLevel - 1] const selectedChroma = randomSkin.chromas[randomChroma - 1] - //TODO : add currentLevel, currentChroma (null by default then set when opening) so I can calculate the real price in inventory - // console.log(randomSkin.chromas) // console.log(randomIndex) @@ -1179,7 +1203,7 @@ app.post('/interactions', verifyKeyMiddleware(process.env.PUBLIC_KEY), async fun } catch (err) { console.error('Error editing message:', err); } - }, 5500); + }, 5000); return; } @@ -1662,6 +1686,23 @@ app.post('/interactions', verifyKeyMiddleware(process.env.PUBLIC_KEY), async fun return trueSkin.displayIcon }; + let components = req.body.message.components; + + if ((invSkins[activeInventories[invId].page].currentLvl < trueSkin.levels.length || invSkins[activeInventories[invId].page].currentChroma < trueSkin.chromas.length) && activeInventories[invId].akhyId === activeInventories[invId].userId) { + if (components[0].components.length === 2) { + components[0].components.push({ + type: MessageComponentTypes.BUTTON, + custom_id: `upgrade_${activeInventories[invId].reqBodyId}`, + label: `Upgrade ⏫`, + style: ButtonStyleTypes.PRIMARY, + }) + } + } else { + if (components[0].components.length === 3) { + components[0].components.pop() + } + } + try { await DiscordRequest( activeInventories[invId].endpoint, @@ -1680,7 +1721,7 @@ app.post('/interactions', verifyKeyMiddleware(process.env.PUBLIC_KEY), async fun } }, ], - components: req.body.message.components, + components: components, }, } ); @@ -1782,6 +1823,23 @@ app.post('/interactions', verifyKeyMiddleware(process.env.PUBLIC_KEY), async fun return trueSkin.displayIcon }; + let components = req.body.message.components; + + if ((invSkins[activeInventories[invId].page].currentLvl < trueSkin.levels.length || invSkins[activeInventories[invId].page].currentChroma < trueSkin.chromas.length) && activeInventories[invId].akhyId === activeInventories[invId].userId) { + if (components[0].components.length === 2) { + components[0].components.push({ + type: MessageComponentTypes.BUTTON, + custom_id: `upgrade_${activeInventories[invId].reqBodyId}`, + label: `Upgrade ⏫`, + style: ButtonStyleTypes.PRIMARY, + }) + } + } else { + if (components[0].components.length === 3) { + components[0].components.pop() + } + } + try { await DiscordRequest( activeInventories[invId].endpoint, @@ -1800,7 +1858,7 @@ app.post('/interactions', verifyKeyMiddleware(process.env.PUBLIC_KEY), async fun } }, ], - components: req.body.message.components, + components: components, }, } ); @@ -1811,6 +1869,292 @@ app.post('/interactions', verifyKeyMiddleware(process.env.PUBLIC_KEY), async fun type: InteractionResponseType.DEFERRED_UPDATE_MESSAGE, }); } + else if (componentId.startsWith('upgrade_')) { + let invId = componentId.replace('upgrade_', '') + const context = req.body.context + const userId = context === 0 ? req.body.member.user.id : req.body.user.id + + const guild = await client.guilds.fetch(req.body.guild.id) + if (!activeInventories[invId]) { + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Oups, cet inventaire n'est plus actif.\nRelance la commande pour avoir un nouvel inventaire interactif`, + flags: InteractionResponseFlags.EPHEMERAL, + }, + }); + } + const completeAkhy = await guild.members.fetch(activeInventories[invId].akhyId) + + const invSkins = getUserInventory.all({user_id: activeInventories[invId].akhyId}) + + if (!activeInventories[invId] || activeInventories[invId].userId !== req.body.member.user.id) { + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Tu n'est pas à l'origine de cette commande /inventory`, + flags: InteractionResponseFlags.EPHEMERAL, + }, + }); + } + + console.log(`upgrade price : ${invSkins[activeInventories[invId].page].maxPrice/8}`) + const buyResponse = await postAPOBuy(req.body.member.user.id, process.env.VALO_UPGRADE_PRICE ?? invSkins[activeInventories[invId].page].maxPrice/8) + + if (buyResponse.status === 500 || buyResponse.ok === false) { + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Tu n'as pas assez d'argent...`, + flags: InteractionResponseFlags.EPHEMERAL, + } + }); + } + + const skin = invSkins[activeInventories[invId].page]; + const trueSkin = skins.find((s) => s.uuid === invSkins[activeInventories[invId].page].uuid); + + const lvlNb = trueSkin.levels.length + const chromaNb = trueSkin.chromas.length + const tierRank = trueSkin.tierRank + const currentLvl = skin.currentLvl + const currentChroma = skin.currentChroma + + let succeeded = false + + if (currentLvl < lvlNb) { + let prob = (currentLvl/lvlNb) + if (tierRank) prob *= ((tierRank+1)/4)+.1 + let rand = Math.random() + console.log(`lvl upgrade prob : ${prob} | ${rand}`) + succeeded = rand >= prob + //amélioration du lvl + if (succeeded) { + let newLvl = skin.currentLvl + 1 + const price = () => { + let res = skin.basePrice; + + res *= (1 + (newLvl / Math.max(trueSkin.levels.length, 2))) + res *= (1 + (skin.currentChroma / 4)) + + return res.toFixed(2); + } + try { + await updateSkin.run({ + uuid: skin.uuid, + user_id: skin.user_id, + currentLvl: newLvl, + currentChroma: skin.currentChroma, + currentPrice: price() + }); + } catch (e) { + console.log('Database error', e); + } + } + } + else if (currentChroma < chromaNb) { + let prob = (currentChroma/chromaNb) + if (tierRank) prob *= ((tierRank+1)/4)+.1 + let rand = Math.random() + console.log(`lvl upgrade prob : ${prob} | ${rand}`) + succeeded = rand >= prob + //amélioration du chroma + if (succeeded) { + let newChroma = skin.currentChroma + 1 + const price = () => { + let res = skin.basePrice; + + res *= (1 + (skin.currentLvl / Math.max(trueSkin.levels.length, 2))) + res *= (1 + (newChroma / 4)) + + return res.toFixed(2); + } + try { + await updateSkin.run({ + uuid: skin.uuid, + user_id: skin.user_id, + currentLvl: skin.currentLvl, + currentChroma: newChroma, + currentPrice: price() + }); + } catch (e) { + console.log('Database error', e); + } + } + } else { + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Ce skin n'est pas améliorable`, + flags: InteractionResponseFlags.EPHEMERAL, + }, + }); + } + + // gif + const initialEmbed = new EmbedBuilder() + .setTitle(`Amélioration en cours...`) + .setImage('https://media.tenor.com/HD8nVN2QP9MAAAAC/thoughts-think.gif') + .setColor(0xF2F3F3); + + // Send the initial response and store the reply object + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { embeds: [initialEmbed] } + }); + + // then result + setTimeout(async () => { + // Prepare the final embed + let updatedSkin = await getSkin.get(trueSkin.uuid) + const randomLevel = updatedSkin.currentLvl + const randomChroma = updatedSkin.currentChroma + const selectedChroma = trueSkin.chromas[randomChroma-1] + + // Helper functions (unchanged from your original code) + const videoUrl = () => { + let res; + if (randomLevel === trueSkin.levels.length) { + if (randomChroma === 1) { + res = trueSkin.levels[trueSkin.levels.length - 1].streamedVideo ?? trueSkin.chromas[0].streamedVideo + } else { + res = trueSkin.chromas[randomChroma-1].streamedVideo + } + } else { + res = trueSkin.levels[randomLevel-1].streamedVideo + } + return res; + }; + const imageUrl = () => { + let res; + if (randomLevel === trueSkin.levels.length) { + if (randomChroma === 1) { + res = trueSkin.chromas[0].displayIcon + + } else { + res = trueSkin.chromas[randomChroma-1].fullRender ?? trueSkin.chromas[randomChroma-1].displayIcon + } + } else if (randomLevel === 1) { + res = trueSkin.levels[0].displayIcon ?? trueSkin.chromas[0].fullRender + } else if (randomLevel === 2 || randomLevel === 3) { + res = trueSkin.displayIcon + } + if (res) return res; + console.log('default') + return trueSkin.displayIcon + }; + const chromaName = () => { + if (randomChroma >= 2) { + const name = selectedChroma.displayName.replace(/[\r\n]+/g, '').replace(trueSkin.displayName, '') + const match = name.match(/variante\s+[1-4]\s+([^)]+)/) + const result = match ? match[2] : null; + if (match) { + return match[1].trim() + } else { + return name + } + } + if (randomChroma === 1) { + return 'Base' + } + return '' + }; + const lvlText = () => { + let res = "" + if (randomLevel >= 1) { + res += '1️⃣ ' + } + if (randomLevel >= 2) { + res += '2️⃣ ' + } + if (randomLevel >= 3) { + res += '3️⃣ ' + } + if (randomLevel >= 4) { + res += '4️⃣ ' + } + if (randomLevel >= 5) { + res += '5️⃣ ' + } + for (let i = 0; i < trueSkin.levels.length - randomLevel; i++) { + res += '◾ ' + } + return res + } + const chromaText = () => { + let res = "" + for (let i = 1; i <= trueSkin.chromas.length; i++) { + res += randomChroma === i ? '💠 ' : '◾ ' + } + return res + } + + // Build the final embed + let finalEmbed; + if (succeeded) { + finalEmbed = new EmbedBuilder() + .setTitle(`L'amélioration a réussi ! 🎉`) + .setFields([ + { name: '', value: `${updatedSkin.displayName} | ${chromaName()}`, inline: false }, + { name: '', value: `**Lvl** | ${lvlText()}`, inline: true }, + { name: '', value: `**Chroma** | ${chromaText()}`, inline: true }, + { name: '', value: `**Prix** | ${updatedSkin.currentPrice} <:vp:1362964205808128122>`, inline: true }, + ]) + .setDescription(updatedSkin.tierText) + .setImage(imageUrl()) + .setColor(0x00FF00); + } + else { + finalEmbed = new EmbedBuilder() + .setTitle(`L'amélioration a râté... ❌`) + .setFields([ + { name: '', value: `${updatedSkin.displayName} | ${chromaName()}`, inline: false }, + ]) + .setDescription(updatedSkin.tierText) + .setImage(imageUrl()) + .setColor(0xFF0000); + } + + + // Prepare components if video exists + const video = videoUrl(); + const components = []; + + if (!succeeded) { + components.push(new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setLabel('Réessayer 🔄️') + .setStyle(ButtonStyle.Primary) + .setCustomId(`upgrade_${activeInventories[invId].reqBodyId}`) + )) + } else if (video) { + components.push( + new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setLabel('🎬 Aperçu vidéo') + .setStyle(ButtonStyle.Link) + .setURL(video) + ) + ); + } + + // Edit the original message + try { + await DiscordRequest( + `webhooks/${process.env.APP_ID}/${req.body.token}/messages/@original`, + { + method: 'PATCH', + body: { + embeds: [finalEmbed], + components: components + } + } + ); + } catch (err) { + console.error('Error editing message:', err); + } + }, 500); + } else if (componentId.startsWith('prev_search_page')) { let searchId = componentId.replace('prev_search_page_', ''); const context = req.body.context; diff --git a/init_database.js b/init_database.js index 9eda3d4..84e84e2 100644 --- a/init_database.js +++ b/init_database.js @@ -44,7 +44,7 @@ export const updateSkin = flopoDB.prepare('UPDATE skins SET user_id = @user_id, export const getSkin = flopoDB.prepare('SELECT * FROM skins WHERE uuid = ?'); export const getAllSkins = flopoDB.prepare('SELECT * FROM skins ORDER BY maxPrice DESC'); export const getAllAvailableSkins = flopoDB.prepare('SELECT * FROM skins WHERE user_id IS NULL'); -export const getUserInventory = flopoDB.prepare('SELECT * FROM skins WHERE user_id = @user_id'); +export const getUserInventory = flopoDB.prepare('SELECT * FROM skins WHERE user_id = @user_id ORDER BY currentPrice DESC'); export const getTopSkins = flopoDB.prepare('SELECT * FROM skins ORDER BY maxPrice DESC LIMIT 10'); export const insertManyUsers = flopoDB.transaction(async (users) => { diff --git a/utils.js b/utils.js index 7747c83..366f30b 100644 --- a/utils.js +++ b/utils.js @@ -185,6 +185,6 @@ export async function postAPOBuy(userId, amount) { return await fetch(fetchUrl, { method: 'POST', }) - .then(response => response.status + ': ' + response.statusText + ' - ' + response.ok) + .then(response => response) .catch(error => console.log('Post error:', error)) } \ No newline at end of file