forked from phenom/healer-man
57 lines
2.5 KiB
JavaScript
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 };
|
|
}
|