Files
healer-man/server/boss-card-collections.mjs
T

57 lines
2.5 KiB
JavaScript

const BOSS_CARD_RARITIES = ["normal", "rare", "epic", "legendary"];
export function emptyBossCardCollection() {
return { counts: {}, lastClaims: {} };
}
/** Keep this normalization in step with src/game/bossCards.ts. */
export function normalizeBossCardCollection(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) return emptyBossCardCollection();
const raw = value;
const counts = Object.create(null);
if (raw.counts && typeof raw.counts === "object" && !Array.isArray(raw.counts)) {
for (const [key, candidate] of Object.entries(raw.counts)) {
if (!key || !candidate || typeof candidate !== "object" || Array.isArray(candidate)) continue;
const entry = {};
for (const rarity of BOSS_CARD_RARITIES) {
const count = candidate[rarity];
if (typeof count === "number" && Number.isFinite(count) && count >= 1) {
entry[rarity] = Math.min(Number.MAX_SAFE_INTEGER, Math.floor(count));
}
}
if (Object.keys(entry).length) counts[key] = entry;
}
}
const lastClaims = raw.lastClaims && typeof raw.lastClaims === "object" && !Array.isArray(raw.lastClaims)
? Object.fromEntries(Object.entries(raw.lastClaims).filter(([key, claim]) => key && typeof claim === "string"))
: {};
return { counts, lastClaims };
}
/** Max-reconcile copies of one account collection, matching source mergeBossCardCollections(..., "max"). */
export function mergeBossCardCollections(collections) {
const counts = Object.create(null);
const lastClaims = Object.create(null);
for (const value of collections) {
const collection = normalizeBossCardCollection(value);
for (const [bossKey, entry] of Object.entries(collection.counts)) {
const merged = counts[bossKey] ??= {};
for (const rarity of BOSS_CARD_RARITIES) {
const count = entry[rarity];
if (count === undefined) continue;
merged[rarity] = Math.max(merged[rarity] ?? 0, count);
}
}
for (const [spawnId, claim] of Object.entries(collection.lastClaims)) {
const previous = lastClaims[spawnId];
if (!previous) { lastClaims[spawnId] = claim; continue; }
if (/^\d+:/.test(previous) && /^\d+:/.test(claim)) {
const [previousTime, previousRevision] = previous.split(":").map(Number);
const [time, revision] = claim.split(":").map(Number);
if (time > previousTime || (time === previousTime && revision > previousRevision)) lastClaims[spawnId] = claim;
} else if (claim > previous) lastClaims[spawnId] = claim;
}
}
return { counts, lastClaims };
}