This commit is contained in:
gpatruno
2026-07-18 16:26:08 +02:00
parent 49c444e8b9
commit 2614d679c8
85 changed files with 8074 additions and 710 deletions
+89
View File
@@ -0,0 +1,89 @@
/** Base simultaneous opens at key 1 (x10). Each +1 key adds +1 open until x20, then continues +1 per key. */
export const BASE_MAX_OPENS = 10;
/** Keys 110 → next key always costs this many opens. */
export const OPENS_PER_KEY_EARLY = 100;
/** From key 11 onward: cost = OPENS_PER_KEY_EARLY × (keys - 9). */
export const ESCALATION_KEY_THRESHOLD = 11;
export function maxOpensForKeys(keys) {
const k = Math.max(1, keys);
return k + (BASE_MAX_OPENS - 1);
}
export function opensRequiredForNextKey(keys, keyOpenReduction = 0) {
const k = Math.max(1, keys);
const base =
k < ESCALATION_KEY_THRESHOLD
? OPENS_PER_KEY_EARLY
: OPENS_PER_KEY_EARLY * (k - (ESCALATION_KEY_THRESHOLD - 2));
const reduction = Math.max(0, Number(keyOpenReduction) || 0);
return Math.max(1, base - reduction);
}
export function serializeKeyProgress(progress, keyOpenReduction = 0) {
const keys = progress?.keys ?? 1;
const opensSinceLastKey = progress?.opensSinceLastKey ?? 0;
const totalOpens = progress?.totalOpens ?? 0;
const opensRequired = opensRequiredForNextKey(keys, keyOpenReduction);
return {
keys,
maxOpens: maxOpensForKeys(keys),
opensSinceLastKey,
opensRequired,
totalOpens,
};
}
/**
* Apply opens to progress state. Returns updated fields + keysGained.
*/
export function applyOpens(progress, count, keyOpenReduction = 0) {
let keys = Math.max(1, progress.keys ?? 1);
let opensSinceLastKey = progress.opensSinceLastKey ?? 0;
let totalOpens = progress.totalOpens ?? 0;
let keysGained = 0;
opensSinceLastKey += count;
totalOpens += count;
while (opensSinceLastKey >= opensRequiredForNextKey(keys, keyOpenReduction)) {
opensSinceLastKey -= opensRequiredForNextKey(keys, keyOpenReduction);
keys += 1;
keysGained += 1;
}
return { keys, opensSinceLastKey, totalOpens, keysGained };
}
/**
* Rebuild keys/opensSinceLastKey from a lifetime open count (backfill).
* Prestige reduction is ignored here — backfill uses base costs.
*/
export function progressFromTotalOpens(totalOpens) {
let keys = 1;
let remaining = totalOpens;
while (remaining >= opensRequiredForNextKey(keys, 0)) {
remaining -= opensRequiredForNextKey(keys, 0);
keys += 1;
}
return {
keys,
opensSinceLastKey: remaining,
totalOpens,
};
}
export async function getOrCreateProgress(tx, userId, caseId) {
const existing = await tx.caseKeyProgress.findUnique({
where: { userId_caseId: { userId, caseId } },
});
if (existing) return existing;
return tx.caseKeyProgress.create({
data: { userId, caseId, keys: 1, opensSinceLastKey: 0, totalOpens: 0 },
});
}