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.
232 lines
8.5 KiB
232 lines
8.5 KiB
|
3 weeks ago
|
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<void> {
|
||
|
|
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 = '';
|
||
|
|
}
|
||
|
|
}
|