mirror of
https://github.com/cassoule/flopobot_v2.git
synced 2026-01-18 16:37:40 +01:00
feat: skins upgrade
This commit is contained in:
@@ -17,6 +17,13 @@ import { getUserInventory } from "../../database/index.js";
|
||||
* @param {string} interactionId - The unique ID of the interaction.
|
||||
*/
|
||||
export async function handleInventoryCommand(req, res, client, interactionId) {
|
||||
return res.send({
|
||||
type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
|
||||
data: {
|
||||
content: `La commande /inventory est désactivée. Tu peux consulter ton inventaire sur FlopoSite.`,
|
||||
flags: InteractionResponseFlags.EPHEMERAL,
|
||||
},
|
||||
});
|
||||
const { member, guild_id, token, data } = req.body;
|
||||
const commandUserId = member.user.id;
|
||||
// User can specify another member, otherwise it defaults to themself
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
updateUserCoins,
|
||||
} from "../../database/index.js";
|
||||
import { client } from "../client.js";
|
||||
import { drawCaseContent, drawCaseSkin } from "../../utils/caseOpening.js";
|
||||
import { drawCaseContent, drawCaseSkin, getDummySkinUpgradeProbs } from "../../utils/caseOpening.js";
|
||||
|
||||
// Constants for the AI rate limiter
|
||||
const MAX_REQUESTS_PER_INTERVAL = parseInt(process.env.MAX_REQUESTS || "5");
|
||||
@@ -196,6 +196,28 @@ async function handleAdminCommands(message) {
|
||||
const [command, ...args] = message.content.split(" ");
|
||||
|
||||
switch (command) {
|
||||
case "?sp":
|
||||
let msgText = ""
|
||||
for (let skinTierRank = 1; skinTierRank <= 4; skinTierRank++) {
|
||||
msgText += `\n--- Tier Rank: ${skinTierRank} ---\n`;
|
||||
let skinMaxLevels = 4;
|
||||
let skinMaxChromas = 4;
|
||||
for (let skinLevel = 1; skinLevel < skinMaxLevels; skinLevel++) {
|
||||
msgText += (`Levels: ${skinLevel}/${skinMaxLevels}, MaxChromas: ${1}/${skinMaxChromas} - `);
|
||||
msgText += (`${getDummySkinUpgradeProbs(skinLevel, 1, skinTierRank, skinMaxLevels, skinMaxChromas, 15).successProb.toFixed(4)}, `);
|
||||
msgText += (`${getDummySkinUpgradeProbs(skinLevel, 1, skinTierRank, skinMaxLevels, skinMaxChromas, 15).destructionProb.toFixed(4)}, `);
|
||||
msgText += (`${getDummySkinUpgradeProbs(skinLevel, 1, skinTierRank, skinMaxLevels, skinMaxChromas, 15).upgradePrice}\n`);
|
||||
}
|
||||
for (let skinChroma = 1; skinChroma < skinMaxChromas; skinChroma++) {
|
||||
msgText += (`Levels: ${skinMaxLevels}/${skinMaxLevels}, MaxChromas: ${skinChroma}/${skinMaxChromas} - `);
|
||||
msgText += (`${getDummySkinUpgradeProbs(skinMaxLevels, skinChroma, skinTierRank, skinMaxLevels, skinMaxChromas, 15).successProb.toFixed(4)}, `);
|
||||
msgText += (`${getDummySkinUpgradeProbs(skinMaxLevels, skinChroma, skinTierRank, skinMaxLevels, skinMaxChromas, 15).destructionProb.toFixed(4)}, `);
|
||||
msgText += (`${getDummySkinUpgradeProbs(skinMaxLevels, skinChroma, skinTierRank, skinMaxLevels, skinMaxChromas, 15).upgradePrice}\n`);
|
||||
}
|
||||
message.reply(msgText);
|
||||
msgText = "";
|
||||
}
|
||||
break;
|
||||
case "?v":
|
||||
console.log("Active Polls:", activePolls);
|
||||
break;
|
||||
@@ -331,6 +353,7 @@ async function handleAdminCommands(message) {
|
||||
console.log(e);
|
||||
message.reply(`Error during case test: ${e.message}`);
|
||||
}
|
||||
break;
|
||||
case `${prefix}:refund-skins`:
|
||||
try {
|
||||
const DBskins = getAllSkins.all();
|
||||
|
||||
@@ -34,7 +34,7 @@ import { DiscordRequest } from "../../api/discord.js";
|
||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
|
||||
import { emitDataUpdated, socketEmit } from "../socket.js";
|
||||
import { handleCaseOpening } from "../../utils/marketNotifs.js";
|
||||
import { drawCaseContent, drawCaseSkin } from "../../utils/caseOpening.js";
|
||||
import { drawCaseContent, drawCaseSkin, getSkinUpgradeProbs } from "../../utils/caseOpening.js";
|
||||
|
||||
// Create a new router instance
|
||||
const router = express.Router();
|
||||
@@ -123,13 +123,13 @@ export function apiRoutes(client, io) {
|
||||
let caseTypeVal;
|
||||
switch (caseType) {
|
||||
case "standard":
|
||||
caseTypeVal = 500;
|
||||
caseTypeVal = 1000;
|
||||
break;
|
||||
case "premium":
|
||||
caseTypeVal = 750;
|
||||
caseTypeVal = 2000;
|
||||
break;
|
||||
case "ultra":
|
||||
caseTypeVal = 1000;
|
||||
caseTypeVal = 4000;
|
||||
break;
|
||||
default:
|
||||
return res.status(400).json({ error: "Invalid case type." });
|
||||
@@ -166,7 +166,7 @@ export function apiRoutes(client, io) {
|
||||
});
|
||||
|
||||
console.log(
|
||||
`[${Date.now()}] ${userId} opened a ${caseType} Valorant case and received skin ${result.randomSelectedSkinUuid}`,
|
||||
`${commandUser.username} opened a ${caseType} Valorant case and received skin ${result.randomSelectedSkinUuid}`,
|
||||
);
|
||||
const updatedSkin = getSkin.get(result.randomSkinData.uuid);
|
||||
await handleCaseOpening(caseType, userId, result.randomSelectedSkinUuid, client);
|
||||
@@ -214,6 +214,112 @@ export function apiRoutes(client, io) {
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/skin-upgrade/:uuid/fetch", (req, res) => {
|
||||
try {
|
||||
const skin = getSkin.get(req.params.uuid);
|
||||
const skinData = skins.find((s) => s.uuid === skin.uuid);
|
||||
const { successProb, destructionProb, upgradePrice } = getSkinUpgradeProbs(skin, skinData);
|
||||
|
||||
const segments = [
|
||||
{ id: 'SUCCEEDED', color: '5865f2', percent: successProb, label: 'Réussie' },
|
||||
{ id: 'DESTRUCTED', color: 'f26558', percent: destructionProb, label: 'Détruit' },
|
||||
{ id: 'NONE', color: '18181818', percent: 1 - successProb - destructionProb, label: 'Échec' },
|
||||
]
|
||||
|
||||
res.json({ segments, upgradePrice });
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
res.status(500).json({ error: "Failed to fetch skin upgrade." });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/skin-upgrade/:uuid", async (req, res) => {
|
||||
const { userId } = req.body;
|
||||
try {
|
||||
const skin = getSkin.get(req.params.uuid);
|
||||
const skinData = skins.find((s) => s.uuid === skin.uuid);
|
||||
if (
|
||||
!skinData ||
|
||||
(skin.currentLvl >= skinData.levels.length && skin.currentChroma >= skinData.chromas.length)
|
||||
) {
|
||||
return res.status(403).json({ error: "Skin is already maxed out or invalid skin." });
|
||||
}
|
||||
if (skin.user_id !== userId) {
|
||||
return res.status(403).json({ error: "User does not own this skin." });
|
||||
}
|
||||
const upgradePrice = Math.floor(parseFloat(skin.maxPrice) / 10);
|
||||
|
||||
const commandUser = getUser.get(userId);
|
||||
if (!commandUser) {
|
||||
return res.status(404).json({ error: "User not found." });
|
||||
}
|
||||
if (commandUser.coins < upgradePrice) {
|
||||
return res.status(403).json({ error: `Pas assez de FlopoCoins (${upgradePrice} requis).` });
|
||||
}
|
||||
|
||||
insertLog.run({
|
||||
id: `${userId}-${Date.now()}`,
|
||||
user_id: userId,
|
||||
action: "VALO_SKIN_UPGRADE",
|
||||
target_user_id: null,
|
||||
coins_amount: -upgradePrice,
|
||||
user_new_amount: commandUser.coins - upgradePrice,
|
||||
});
|
||||
updateUserCoins.run({
|
||||
id: userId,
|
||||
coins: commandUser.coins - upgradePrice,
|
||||
});
|
||||
|
||||
let succeeded = false;
|
||||
let destructed = false;
|
||||
const { successProb, destructionProb } = getSkinUpgradeProbs(skin, skinData);
|
||||
const roll = Math.random();
|
||||
if (roll < destructionProb) {
|
||||
destructed = true;
|
||||
} else if (roll < successProb + destructionProb) {
|
||||
succeeded = true;
|
||||
}
|
||||
|
||||
if (succeeded) {
|
||||
const isLevelUpgrade = skin.currentLvl < skinData.levels.length;
|
||||
if (isLevelUpgrade) {
|
||||
skin.currentLvl++;
|
||||
} else {
|
||||
skin.currentChroma++;
|
||||
}
|
||||
const calculatePrice = () => {
|
||||
let result = parseFloat(skin.basePrice);
|
||||
result *= 1 + skin.currentLvl / Math.max(skinData.levels.length, 2);
|
||||
result *= 1 + skin.currentChroma / 4;
|
||||
return parseFloat(result.toFixed(0));
|
||||
};
|
||||
skin.currentPrice = calculatePrice();
|
||||
|
||||
updateSkin.run({
|
||||
uuid: skin.uuid,
|
||||
user_id: skin.user_id,
|
||||
currentLvl: skin.currentLvl,
|
||||
currentChroma: skin.currentChroma,
|
||||
currentPrice: skin.currentPrice,
|
||||
});
|
||||
} else if (destructed) {
|
||||
updateSkin.run({
|
||||
uuid: skin.uuid,
|
||||
user_id: null,
|
||||
currentLvl: null,
|
||||
currentChroma: null,
|
||||
currentPrice: null,
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`${commandUser.username} attempted to upgrade skin ${skin.uuid} - ${succeeded ? "SUCCEEDED" : destructed ? "DESTRUCTED" : "FAILED"}`);
|
||||
res.json({ wonId: succeeded ? "SUCCEEDED" : destructed ? "DESTRUCTED" : "NONE" });
|
||||
} catch (error) {
|
||||
console.error("Error fetching skin upgrade:", error);
|
||||
res.status(500).json({ error: "Failed to fetch skin upgrade." });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/users/by-elo", (req, res) => {
|
||||
try {
|
||||
const users = getUsersByElo.all();
|
||||
|
||||
@@ -127,3 +127,19 @@ export function drawCaseSkin(caseContent) {
|
||||
randomSelectedSkinIndex,
|
||||
};
|
||||
}
|
||||
|
||||
export function getSkinUpgradeProbs(skin, skinData) {
|
||||
const successProb =
|
||||
(1 - (((skin.currentChroma + skin.currentLvl + skinData.chromas.length + skinData.levels.length) / 18) * (parseInt(skin.tierRank) / 4)))/2;
|
||||
const destructionProb = ((skin.currentChroma + skinData.levels.length) / (skinData.chromas.length + skinData.levels.length)) * (parseInt(skin.tierRank) / 5) * 0.075;
|
||||
const upgradePrice = Math.max(Math.floor(parseFloat(skin.currentPrice) * (1 - successProb)), 1);
|
||||
return { successProb, destructionProb, upgradePrice };
|
||||
}
|
||||
|
||||
export function getDummySkinUpgradeProbs(skinLevel, skinChroma, skinTierRank, skinMaxLevels, skinMaxChromas, skinMaxPrice) {
|
||||
const successProb =
|
||||
1 - (((skinChroma + skinLevel + (skinMaxChromas + skinMaxLevels)) / 18) * (parseInt(skinTierRank) / 4));
|
||||
const destructionProb = ((skinChroma + skinMaxLevels) / (skinMaxChromas + skinMaxLevels)) * (parseInt(skinTierRank) / 5) * 0.1;
|
||||
const upgradePrice = Math.max(Math.floor((parseFloat(skinMaxPrice) * (1 - successProb))), 1);
|
||||
return { successProb, destructionProb, upgradePrice };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user