import { UIID } from '../game/ConfigRes'; import { ConstNumType } from '../game/GameDataEnums'; import { DailyWinStats } from './DailyWinStats'; import { RankDataManager } from './RankDataManager'; /** * 每日俸禄:仅用「待领星级 + 待领胜场 + 快照日期」驱动弹窗与领取。 * - 当日战斗累计待领(尚无待领时首胜新建);快照日期标为今日,当日不弹 * - 已有跨日未领待领则保留不覆盖、不继续累加(隔日不上线到第 N 天仍有效) * - 跨天且待领为空时写入昨日星级与胜场(快照日期标为昨日) * - 除账号首日外,每日首登进 Home 且快照早于今日、胜场 > 0 → 弹 PopEmolument * - 领取后清空 */ export class EmolumentDataManager { /** 本进程是否已尝试过自动弹俸禄窗(防 MainUI / 大厅重复弹) */ private static _autoPopAttempted = false; /** * 跨天:待领为空时写入昨日星级与胜场;已有待领不覆盖(含隔日未上线)。 * 新号 / 清档首登、从未战斗的玩家不写入(避免默认 1 星误弹俸禄)。 */ static onCrossDay(): void { if (this.hasPending()) { return; } if (gg.data.IsFirstLogin) { return; } if (!this._hasBattleRecord()) { return; } const stars = RankDataManager.getPlayerRankStars(); const wins = DailyWinStats.getYesterdayWins(); if (!(stars > 0)) return; this._writePending(stars, wins, this._yesterdayKey()); } /** 是否存在待领俸禄(以星级字段为准) */ static hasPending(): boolean { return this.getSnapStars() > 0; } /** 当日首次登录是否应自动弹俸禄窗 */ static shouldPopOnFirstLoginToday(): boolean { return this.shouldPopOnHomeEnter(); } /** * Home 进入时是否应弹俸禄窗: * 非账号首日 + 每日首登 + 待领可领 + 胜场 > 0 + 快照日期早于今日;GM 待弹除外。 */ static shouldPopOnHomeEnter(): boolean { if (Number(gg.data.doc.gmAwaitEmolumentPop) === 1) return this.canClaim(); if (gg.data.IsFirstLogin) return false; if (!gg.data.IsFirstLoginToday) return false; if (!this.canClaim()) return false; if (!(this.getSnapWins() > 0)) return false; return this._isSnapReadyToPop(); } /** 是否可领取俸禄 */ static canClaim(): boolean { return this.hasPending(); } /** Home 就绪:满足条件时弹 PopEmolument */ static tryPopPanelIfNeeded(): void { if (this._autoPopAttempted) return; if (!this.shouldPopOnHomeEnter()) return; this._autoPopAttempted = true; gg.data.doc.gmAwaitEmolumentPop = 0; gg.data.saveLocal(); void gg.ui.popPanel(UIID.PopEmolument); } /** 待领星级(总星数,0=无) */ static getSnapStars(): number { return Math.max(0, Math.floor(Number(gg.data.doc.emolumentSnapStars) || 0)); } /** 待领胜场 */ static getSnapWins(): number { return Math.max(0, Math.floor(Number(gg.data.doc.emolumentSnapWins) || 0)); } /** 段位表 Rank.reward 金币(道具 id|数量) */ static getRankTierGold(stars?: number): number { const totalStars = Math.max(1, Math.floor(Number(stars ?? this.getSnapStars()) || 0)); return RankDataManager.parseRankTierMoneyReward(totalStars); } /** 胜场奖励金币(Const 26 进度 + Const 27 系数,向下取整) */ static calcWinRewardGold(wins?: number): number { const w = Math.max(0, Math.floor(Number(wins ?? this.getSnapWins()) || 0)); if (w <= 0) return 0; const thresholds = gg.data.table.getConstArray(ConstNumType.DailyWinProgress); const coefs = gg.data.table.getConstArray(ConstNumType.DailyWinRewardCoef); const t1 = Math.floor(Number(thresholds[0]) || 0); const t2 = Math.floor(Number(thresholds[1]) || 0); const c1 = Number(coefs[0]) || 0; const c2 = Number(coefs[1]) || 0; if (!(t1 > 0) || !(c1 > 0)) { console.warn('[Emolument] Const 26/27 配置无效', thresholds, coefs); return 0; } if (!(t2 > t1)) { console.warn('[Emolument] Const 26 第二档须大于第一档', t1, t2); return 0; } if (!(c2 > 0)) { console.warn('[Emolument] Const 27 第二系数无效', coefs); return 0; } if (w < t1) { return Math.floor(w * c1); } const cappedWins = w > t2 ? t2 : w; return Math.floor(t1 * c1 + (cappedWins - t1) * c2); } /** * 战斗结算后同步待领:须本局传星才新建待领;仅「当日快照」继续累加,跨日未领快照冻结。 * @param starsChanged 本局是否已传星(RankDataManager.applyBattleResult 为 true) */ static syncAfterBattle(playerWin: boolean, starsChanged: boolean): void { const stars = RankDataManager.getPlayerRankStars(); if (!(stars > 0)) return; const today = DailyWinStats.todayKey(); if (!this.hasPending()) { if (!playerWin || !starsChanged) return; this._writePending(stars, 1, today); return; } if (this._getSnapDate() !== today) { return; } if (starsChanged) { gg.data.doc.emolumentSnapStars = stars; } if (playerWin) { gg.data.doc.emolumentSnapWins = this.getSnapWins() + 1; } } /** 领取俸禄:段位金币 + 胜场金币入账,成功后清空两字段 */ static claim(): number | null { if (!this.canClaim()) return null; const rankGold = this.getRankTierGold(); const winGold = this.calcWinRewardGold(); const total = rankGold + winGold; if (total > 0) { gg.data.addMoney(total); } this._clearPending(); gg.data.saveLocal(); return total; } static async ensureTable(): Promise { await RankDataManager.ensureTable(); } /** * GM:写入俸禄待领快照(日期标昨日)、标今日首次登录并重置自动弹窗(重新进 Home 弹 PopEmolument)。 * @returns 是否写入有效待领(stars > 0) */ static gmPrepareFirstLoginPopTest(stars: number, wins: number): boolean { const snapStars = Math.max(0, Math.floor(Number(stars) || 0)); const snapWins = Math.max(0, Math.floor(Number(wins) || 0)); if (!(snapStars > 0)) { console.warn('[Emolument] GM 待领星级须 > 0'); return false; } this._writePending(snapStars, snapWins, this._yesterdayKey()); this._autoPopAttempted = false; gg.data.IsFirstLoginToday = true; gg.data.doc.gmAwaitEmolumentPop = 1; return true; } /** 快照是否已到可弹日(日期早于今日;旧档无日期视为可弹) */ private static _isSnapReadyToPop(): boolean { const snapDate = this._getSnapDate(); if (!snapDate) return true; return snapDate !== DailyWinStats.todayKey(); } /** 待领快照日期 YYYYMMDD */ private static _getSnapDate(): string { return String(gg.data.doc.emolumentSnapDate ?? '').trim(); } /** 昨日日期键 YYYYMMDD */ private static _yesterdayKey(): string { const d = new Date(gg.data.getCurentTime2()); d.setDate(d.getDate() - 1); 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 _hasBattleRecord(): boolean { const wins = Math.max(0, Math.floor(Number(gg.data.doc.matchWinCount) || 0)); const loses = Math.max(0, Math.floor(Number(gg.data.doc.matchLoseCount) || 0)); return wins + loses > 0; } /** 写入待领星级、胜场与快照日期 */ private static _writePending(stars: number, wins: number, date: string): void { gg.data.doc.emolumentSnapStars = Math.max(0, Math.floor(Number(stars) || 0)); gg.data.doc.emolumentSnapWins = Math.max(0, Math.floor(Number(wins) || 0)); gg.data.doc.emolumentSnapDate = String(date ?? '').trim(); } /** 领取后清空待领 */ private static _clearPending(): void { gg.data.doc.emolumentSnapStars = 0; gg.data.doc.emolumentSnapWins = 0; gg.data.doc.emolumentSnapDate = ''; } }