Files
flopobot_v2/src/utils/caseOpening.js
2026-02-06 20:21:15 +01:00

197 lines
6.6 KiB
JavaScript

import * as skinService from "../services/skin.service.js";
import { skins } from "../game/state.js";
import { isChampionsSkin } from "./index.js";
export async function drawCaseContent(caseType = "standard", poolSize = 100) {
if (caseType === "esport") {
// Esport case: return all esport skins
try {
const dbSkins = await skinService.getAllAvailableSkins();
const esportSkins = [];
for (const s of skins.filter((s) => dbSkins.find((dbSkin) => dbSkin.displayName.includes("Classic (VCT") && dbSkin.uuid === s.uuid))) {
const dbSkin = await skinService.getSkin(s.uuid);
esportSkins.push({
...s,
tierColor: dbSkin?.tierColor,
});
}
return esportSkins;
} catch (e) {
console.log(e);
}
}
let tierWeights;
switch (caseType) {
case "standard":
tierWeights = {
"12683d76-48d7-84a3-4e09-6985794f0445": 50, // Select
"0cebb8be-46d7-c12a-d306-e9907bfc5a25": 30, // Deluxe
"60bca009-4182-7998-dee7-b8a2558dc369": 19, // Premium
"e046854e-406c-37f4-6607-19a9ba8426fc": 1, // Exclusive
"411e4a55-4e59-7757-41f0-86a53f101bb5": 0, // Ultra
};
break;
case "premium":
tierWeights = {
"12683d76-48d7-84a3-4e09-6985794f0445": 25, // Select
"0cebb8be-46d7-c12a-d306-e9907bfc5a25": 25, // Deluxe
"60bca009-4182-7998-dee7-b8a2558dc369": 40, // Premium
"e046854e-406c-37f4-6607-19a9ba8426fc": 8, // Exclusive
"411e4a55-4e59-7757-41f0-86a53f101bb5": 2, // Ultra
};
break;
case "ultra":
tierWeights = {
"12683d76-48d7-84a3-4e09-6985794f0445": 0, // Select
"0cebb8be-46d7-c12a-d306-e9907bfc5a25": 0, // Deluxe
"60bca009-4182-7998-dee7-b8a2558dc369": 33, // Premium
"e046854e-406c-37f4-6607-19a9ba8426fc": 33, // Exclusive
"411e4a55-4e59-7757-41f0-86a53f101bb5": 33, // Ultra
};
break;
default:
break;
}
try {
const dbSkins = await skinService.getAllAvailableSkins();
const filtered = skins
.filter((s) => dbSkins.find((dbSkin) => dbSkin.uuid === s.uuid))
.filter((s) => {
if (caseType === "ultra") {
return !(s.displayName.toLowerCase().includes("vct") && s.displayName.toLowerCase().includes("classic"))
} else {
return !s.displayName.toLowerCase().includes("vct");
}
})
.filter((s) => {
if (caseType === "ultra") {
return true
} else {
return isChampionsSkin(s.displayName) === false;
}
});
const weightedPool = [];
for (const s of filtered) {
const dbSkin = await skinService.getSkin(s.uuid);
const weight = tierWeights[s.contentTierUuid] ?? 0;
if (weight > 0) { // <--- CRITICAL: Remove 0 weight skins
weightedPool.push({
...s,
tierColor: dbSkin?.tierColor,
weight,
});
}
}
function weightedSample(arr, count) {
let totalWeight = arr.reduce((sum, x) => sum + x.weight, 0);
const list = [...arr];
const result = [];
// 2. Adjust count if the pool is smaller than requested
const actualCount = Math.min(count, list.length) ;
for (let i = 0; i < actualCount; i++) {
let r = Math.random() * totalWeight;
let running = 0;
let pickIndex = -1;
for (let j = 0; j < list.length; j++) {
running += list[j].weight;
// Changed to strictly less than for safer bounds,
// though filtering weight > 0 above is the primary fix.
if (r <= running) {
pickIndex = j;
break;
}
}
if (pickIndex < 0) pickIndex = list.length - 1;
const picked = list.splice(pickIndex, 1)[0];
result.push(picked);
totalWeight -= picked.weight;
if (totalWeight <= 0) break; // Stop if no more weight exists
}
return result;
}
return poolSize === -1 ? weightedPool : weightedSample(weightedPool, poolSize);
} catch (e) {
console.log(e);
}
}
export async function drawCaseSkin(caseContent) {
let randomSelectedSkinIndex;
let randomSelectedSkinUuid;
try {
randomSelectedSkinIndex = Math.floor(Math.random() * (caseContent.length - 1));
randomSelectedSkinUuid = caseContent[randomSelectedSkinIndex].uuid;
} catch (e) {
console.log(e);
throw new Error("Failed to draw a skin from the case content.");
}
const dbSkin = await skinService.getSkin(randomSelectedSkinUuid);
const randomSkinData = skins.find((skin) => skin.uuid === dbSkin.uuid);
if (!randomSkinData) {
throw new Error(`Could not find skin data for UUID: ${dbSkin.uuid}`);
}
// --- Randomize Level and Chroma ---
const randomLevel = Math.floor(Math.random() * randomSkinData.levels.length) + 1;
let randomChroma = 1;
if (randomLevel === randomSkinData.levels.length && randomSkinData.chromas.length > 1) {
// Ensure chroma is at least 1 and not greater than the number of chromas
randomChroma = Math.floor(Math.random() * randomSkinData.chromas.length) + 1;
}
// --- Calculate Price ---
const calculatePrice = () => {
let result = parseFloat(dbSkin.basePrice);
result *= 1 + randomLevel / Math.max(randomSkinData.levels.length, 2);
result *= 1 + randomChroma / 4;
return parseFloat(result.toFixed(0));
};
const finalPrice = calculatePrice();
return {
caseContent,
finalPrice,
randomLevel,
randomChroma,
randomSkinData,
randomSelectedSkinUuid,
randomSelectedSkinIndex,
};
}
export function getSkinUpgradeProbs(skin, skinData) {
const successProb =
(1 - (((skin.currentChroma + skin.currentLvl + skinData.chromas.length + skinData.levels.length) / 18) * (parseInt(skin.tierRank) / 4)))/1.5;
const destructionProb = ((skin.currentChroma + skinData.levels.length) / (skinData.chromas.length + skinData.levels.length)) * (parseInt(skin.tierRank) / 5) * 0.075;
const nextLvl = skin.currentLvl < skinData.levels.length ? skin.currentLvl + 1 : skin.currentLvl;
const nextChroma = skin.currentLvl === skinData.levels.length && skin.currentChroma < skinData.chromas.length ? skin.currentChroma + 1 : skin.currentChroma;
const calculateNextPrice = () => {
let result = parseFloat(skin.basePrice);
result *= 1 + nextLvl / Math.max(skinData.levels.length, 2);
result *= 1 + nextChroma / 4;
return parseFloat(result.toFixed(0));
};
const diff = calculateNextPrice() - parseFloat(skin.currentPrice);
const upgradePrice = Math.max(Math.floor(diff * 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 };
}