You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
AdLike2048/assets/script/manager/DailyRankDataManager.ts

190 lines
7.2 KiB

3 weeks ago
import { TableNames } from '../game/ConfigTableData';
import { ItemData } from '../game/ConfigProjectData';
import { OtherDataType } from '../game/GameDataEnums';
import { RankDataManager } from './RankDataManager';
type RankSnapDoc = { date: string; rank: number };
type SalaryDoc = { date: string; claimRank: number; claimed: boolean };
/**
* 省榜每日俸禄(Daily_Rank 表):
* - 领取奖励按「昨日」省榜名次(DailyRankProvinceSnap 快照)
* - 每日仅可领取一次
*/
export class DailyRankDataManager {
static async ensureTable(): Promise<void> {
await gg.data.table.ensureTableLoaded(TableNames.Daily_Rank);
}
static getAllList(): ITableDaily_Rank[] {
return gg.data.table.getTableList<ITableDaily_Rank>(TableNames.Daily_Rank) ?? [];
}
/** 拉取省榜后写入当日快照:YYYYMMDD|rank */
static recordProvinceBoardRank(rank: number): void {
this.ensureToday();
const today = this._todayKey();
const r = Math.max(0, Math.floor(Number(rank) || 0));
gg.data.setStringData(OtherDataType.DailyRankProvinceSnap, `${today}|${r}`);
gg.data.saveLocal();
}
/** 今日可领俸禄对应的省榜名次(= 昨日快照名次,0=不可领) */
static getClaimBoardRank(): number {
this.ensureToday();
const doc = this._parseSalaryDoc();
return doc.date === this._todayKey() ? doc.claimRank : 0;
}
/** 读档 / 跨天后刷新:用昨日快照生成本日可领名次 */
static ensureToday(): void {
const today = this._todayKey();
const salary = this._parseSalaryDoc();
if (salary.date === today) return;
const yesterday = this._yesterdayKey(today);
const snap = this._parseSnapDoc();
const claimRank = (snap.date === yesterday && snap.rank > 0) ? snap.rank : 0;
this._saveSalaryDoc(today, claimRank, false);
}
/** 配表最后一档 rank[1]:超出则不显示领取 */
static getMaxRewardBoardRank(): number {
const list = this.getAllList();
if (list.length <= 0) return 0;
const last = list[list.length - 1];
const range = last?.rank;
if (!range || range.length < 2) return 0;
return Math.max(0, Math.floor(Number(range[1]) || 0));
}
/** 省榜名次是否在 Daily_Rank 任一区间内 */
static isBoardRankInRewardRange(boardRank: number): boolean {
const r = Math.floor(Number(boardRank) || 0);
if (r <= 0) return false;
const max = this.getMaxRewardBoardRank();
if (max <= 0) return false;
return r <= max;
}
/** 按省榜名次匹配 Daily_Rank 行 */
static findRowByBoardRank(boardRank: number): ITableDaily_Rank | null {
const r = Math.floor(Number(boardRank) || 0);
if (r <= 0) return null;
for (const row of this.getAllList()) {
const range = row?.rank;
if (!range || range.length < 2) continue;
const min = Math.floor(Number(range[0]) || 0);
const max = Math.floor(Number(range[1]) || 0);
if (r >= min && r <= max) return row;
}
return null;
}
static isClaimedToday(): boolean {
this.ensureToday();
const doc = this._parseSalaryDoc();
return doc.date === this._todayKey() && doc.claimed;
}
static canClaimDailySalary(boardRank?: number): boolean {
this.ensureToday();
const rank = boardRank === undefined ? this.getClaimBoardRank() : boardRank;
if (!this.isBoardRankInRewardRange(rank)) return false;
if (this.isClaimedToday()) return false;
const row = this.findRowByBoardRank(rank);
return this.parseDailyRankRewards(row).length > 0;
}
/** Daily_Rank.reward_rank → ItemData(与签到一致:2=成品 equip) */
static parseDailyRankRewards(row: ITableDaily_Rank | null | undefined): ItemData[] {
const list: ItemData[] = [];
for (const g of RankDataManager.parseRewardRank(row?.reward_rank)) {
if (g.type === 2) {
if (!gg.equip.getEquip(g.id)) continue;
const item = new ItemData(g.id, g.num);
item.isEquip = true;
list.push(item);
} else {
const conf = gg.data.table.getItemData(g.id);
if (!conf) continue;
list.push(new ItemData(g.id, g.num, conf));
}
}
return list;
}
/** 领取今日省榜俸禄(按昨日名次);成功返回奖励列表 */
static claimDailySalary(boardRank?: number): ItemData[] | null {
this.ensureToday();
const rank = boardRank === undefined ? this.getClaimBoardRank() : boardRank;
if (!this.canClaimDailySalary(rank)) return null;
const row = this.findRowByBoardRank(rank);
const items = this.parseDailyRankRewards(row);
if (items.length <= 0) return null;
this._saveSalaryDoc(this._todayKey(), rank, true);
gg.data.saveLocal();
return items;
}
static onCrossDay(): void {
this.ensureToday();
}
private static _parseSnapDoc(): RankSnapDoc {
const raw = String(gg.data.getStringData(OtherDataType.DailyRankProvinceSnap) ?? '').trim();
if (!raw) return { date: '', rank: 0 };
const sep = raw.indexOf('|');
if (sep < 0) return { date: '', rank: 0 };
return {
date: raw.slice(0, sep),
rank: Math.max(0, Math.floor(Number(raw.slice(sep + 1)) || 0)),
};
}
private static _parseSalaryDoc(): SalaryDoc {
const raw = String(gg.data.getStringData(OtherDataType.DailyRankSalary) ?? '').trim();
if (!raw) return { date: '', claimRank: 0, claimed: false };
const parts = raw.split('|');
if (parts.length >= 3) {
return {
date: parts[0],
claimRank: Math.max(0, Math.floor(Number(parts[1]) || 0)),
claimed: parts[2] === '1',
};
}
// 旧档兼容:仅 0/1,视为需按新规则重建
return { date: '', claimRank: 0, claimed: false };
}
private static _saveSalaryDoc(date: string, claimRank: number, claimed: boolean): void {
const rank = Math.max(0, Math.floor(Number(claimRank) || 0));
gg.data.setStringData(
OtherDataType.DailyRankSalary,
`${date}|${rank}|${claimed ? 1 : 0}`,
);
}
private static _todayKey(): string {
const d = new Date(gg.data.getCurentTime2());
const y = d.getFullYear();
const m = `${d.getMonth() + 1}`.padStart(2, '0');
const day = `${d.getDate()}`.padStart(2, '0');
return `${y}${m}${day}`;
}
private static _yesterdayKey(fromToday: string): string {
const y = Number(fromToday.slice(0, 4)) || 0;
const m = Number(fromToday.slice(4, 6)) || 1;
const d = Number(fromToday.slice(6, 8)) || 1;
const dt = new Date(y, m - 1, d);
dt.setDate(dt.getDate() - 1);
const yy = dt.getFullYear();
const mm = `${dt.getMonth() + 1}`.padStart(2, '0');
const dd = `${dt.getDate()}`.padStart(2, '0');
return `${yy}${mm}${dd}`;
}
}