80 lines
4.5 KiB
TypeScript
80 lines
4.5 KiB
TypeScript
/** 战令配置计算,不处理金币、登录或其他模块的同步。 */
|
|
export const PASS_PERIOD = 30 * 24 * 60 * 60 * 1000;
|
|
export const PASS_PRODUCTS = { battlepass: 1800, battlepass_30: 3000, battlepass_12: 1200 };
|
|
const OLD_TOKENS = [1, 2, 2, 2, 2, 2, 2, 2, 2, ...Array(21).fill(4)];
|
|
export function passTier(stage: any): number { return stage && stage.tier === 30 ? 30 : stage && stage.activate ? 18 : 0; }
|
|
export function legacyExperience(stage: any): number {
|
|
const level = Math.max(1, Math.min(30, Number(stage.progressLevel) || 1));
|
|
return OLD_TOKENS.slice(0, level - 1).reduce((n, cost) => n + cost, 0) + Math.min(OLD_TOKENS[level - 1], Number(stage.progress) || 0);
|
|
}
|
|
export function normalizePass(stage: any, rows: any[]): any {
|
|
if (!stage || !Number(stage.time)) return stage;
|
|
stage = { ...stage, free: [...(stage.free || [])], passCheck: [...(stage.passCheck || [])] };
|
|
if (!Number.isFinite(stage.experience)) {
|
|
const level = Math.max(1, Math.min(30, Number(stage.progressLevel) || 1));
|
|
stage.experience = rows.slice(0, level - 1).reduce((n, row) => n + Number(row.token), 0)
|
|
+ Math.min(Number(rows[level - 1].token), Number(stage.progress) || 0);
|
|
}
|
|
let remaining = Math.max(0, stage.experience), unlocked = 0;
|
|
for (const row of rows) {
|
|
if (remaining < Number(row.token)) break;
|
|
remaining -= Number(row.token);
|
|
unlocked++;
|
|
}
|
|
stage.unlocked = unlocked;
|
|
// 保持旧界面“当前档 + 当前档经验”的表示,完成一档时显示满格。
|
|
const complete = remaining === 0 || unlocked === rows.length;
|
|
stage.progressLevel = Math.max(1, Math.min(rows.length, unlocked + (complete ? 0 : 1)));
|
|
stage.progress = complete ? Number(rows[stage.progressLevel - 1].token) : remaining;
|
|
for (const lane of ['free', 'passCheck']) for (let i = 0; i < unlocked; i++) {
|
|
if (stage[lane][i] !== 0) stage[lane][i] = 1;
|
|
}
|
|
return stage;
|
|
}
|
|
export function mergePassInfo(raw: any, extra: any, rows: any[], oldRows: any[] = rows): any {
|
|
if (!raw) return raw;
|
|
for (const key of [1, 2]) {
|
|
const old = raw[key];
|
|
if (!old || !Number(old.time)) continue;
|
|
const saved = extra && extra[String(old.time)];
|
|
if (saved) {
|
|
raw[key] = { ...saved, activate: !!old.activate || !!saved.activate,
|
|
experience: saved.experience + Math.max(0, legacyExperience(old) - (saved.legacyExperience || 0)) };
|
|
for (const lane of ['free', 'passCheck']) {
|
|
raw[key][lane] = [...(saved[lane] || [])];
|
|
for (let i = 0; i < Math.min(30, (old[lane] || []).length); i++) if (old[lane][i] === 0) raw[key][lane][i] = 0;
|
|
}
|
|
}
|
|
raw[key] = normalizePass(raw[key], key === 1 ? oldRows : rows);
|
|
}
|
|
return raw;
|
|
}
|
|
export function legacyPassInfo(pass: any, rows: any[], oldRows: any[] = rows): any {
|
|
const legacy: any = {};
|
|
for (const key of [1, 2]) {
|
|
const stage = pass[key];
|
|
if (!stage || !Number(stage.time)) { legacy[key] = stage; continue; }
|
|
const level = Math.max(1, Math.min(30, stage.progressLevel));
|
|
const row = (key === 1 ? oldRows : rows)[stage.progressLevel - 1];
|
|
const progress = stage.unlocked >= level ? OLD_TOKENS[level - 1] : Math.min(OLD_TOKENS[level - 1], Math.floor(stage.progress * OLD_TOKENS[level - 1] / Math.max(1, Number(row.token))));
|
|
legacy[key] = { time: stage.time, activate: passTier(stage) > 0, progressLevel: level, progress,
|
|
free: (stage.free || []).slice(0, 30), passCheck: (stage.passCheck || []).slice(0, 30) };
|
|
}
|
|
return legacy;
|
|
}
|
|
export function passBounds(stage: any, count: number) {
|
|
const tier = passTier(stage);
|
|
const generated = Math.min(count, tier === 30 ? Math.max(40, (stage.unlocked || 0) + 5) : 40);
|
|
// 正常滚动至可解锁范围的下一档,后续奖励供上拉预览。
|
|
const content = Math.min(generated, tier === 30 ? Math.max(36, (stage.unlocked || 0) + 1) : 36);
|
|
return { generated, content };
|
|
}
|
|
export function canClaimPass(stage: any, index: number, left: boolean): boolean {
|
|
// 1 表示已解锁待领取;换期重算的 unlocked 不能撤销存档中已有的领取资格。
|
|
return !!stage && index >= 0 && (stage[left ? 'free' : 'passCheck'] || [])[index] === 1
|
|
&& (index < 35 ? left || passTier(stage) >= 18 : passTier(stage) === 30);
|
|
}
|
|
export function hasPassReward(stage: any): boolean {
|
|
return !!stage && (stage.free || []).some((_, i) => canClaimPass(stage, i, true) || canClaimPass(stage, i, false));
|
|
}
|