fix: 개인 턴 경계에 맞춰 입력기 연월을 표시한다

Ref처럼 장수와 월 실행 시각을 logical tick bucket으로 비교해 이미 실행된 장수만 다음 달부터 예약 턴을 표시한다. 12월 연도 전환과 Date-only fallback을 단위 테스트 및 production Chromium으로 검증한다.
This commit is contained in:
2026-08-21 17:17:23 +00:00
parent 5a6295f67a
commit 4c33c39506
5 changed files with 221 additions and 8 deletions
@@ -1,3 +1,5 @@
import { GAME_TICKS_PER_TURN } from '@sammo-ts/common';
export interface GeneralBasicStats {
leadership: number;
strength: number;
@@ -53,3 +55,41 @@ export const resolveRemainingMinutes = (
}
return Math.floor(Math.min(999, Math.max(0, (nextTurnMillis - lastExecuted.getTime()) / 60_000)));
};
export interface NextTurnMonthOffsetInput {
turnTime: Date;
turnTick?: bigint | number | null;
lastExecuted: Date | null;
lastTurnTick?: bigint | number | null;
turnSeconds: number;
}
const normalizeTick = (value: bigint | number | null | undefined): bigint | null => {
if (typeof value === 'bigint') return value;
if (typeof value === 'number' && Number.isSafeInteger(value)) return BigInt(value);
return null;
};
const turnBucket = (tick: bigint): bigint => {
const ticksPerTurn = BigInt(GAME_TICKS_PER_TURN);
const quotient = tick / ticksPerTurn;
return tick % ticksPerTurn < 0 ? quotient - 1n : quotient;
};
/**
* Ref Command.GetReservedCommand cuts both clocks to a gameplay-turn bucket.
* A general in the next bucket has already acted in the displayed world month,
* so the first reserved command belongs to the following month.
*/
export const resolveNextTurnMonthOffset = (input: NextTurnMonthOffsetInput): 0 | 1 => {
const turnTick = normalizeTick(input.turnTick);
const lastTurnTick = normalizeTick(input.lastTurnTick);
if (turnTick !== null && lastTurnTick !== null) {
return turnBucket(turnTick) > turnBucket(lastTurnTick) ? 1 : 0;
}
const turnTimeMs = input.turnTime.getTime();
const lastExecutedMs = input.lastExecuted?.getTime() ?? Number.NaN;
if (!Number.isFinite(turnTimeMs) || !Number.isFinite(lastExecutedMs) || input.turnSeconds <= 0) return 0;
return turnTimeMs >= lastExecutedMs + input.turnSeconds * 1_000 ? 1 : 0;
};