mirror of
https://github.com/cassoule/flopobot_v2.git
synced 2026-03-18 21:40:27 +01:00
197 lines
6.6 KiB
JavaScript
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 };
|
|
}
|