fix: 이민족 첫 턴을 정지 시각에 맞춤

통일 대기 중 실시간 투영 시각이 새 이민족 첫 턴으로 새던 경로를 정지된 월 경계로 교정한다. 잘못 추가한 NPC 포상 비용 100배 변경도 되돌린다.
This commit is contained in:
2026-08-26 15:28:19 +00:00
parent 71b8eac8ee
commit 816762ab56
5 changed files with 29 additions and 49 deletions
@@ -290,7 +290,10 @@ const respondToRaiseInvader = async (options: {
month: state.currentMonth,
startyear: asNumber(state.meta.startYear, state.currentYear),
currentEventID: 0,
turnTime: now,
// Ref uses the frozen game_env.turntime while unification is paused.
// `now` is the realtime game projection and can be hours ahead after
// a long response wait, delaying every newly summoned invader turn.
turnTime: state.lastTurnTime,
},
event
);
+5 -6
View File
@@ -314,10 +314,9 @@ export class AutorunNationPolicy {
const stat = scenarioConfig.stat;
if (this.reqNpcWarGold === 0 || this.reqNpcWarRice === 0) {
const crewType = findCrewTypeById(unitSet, env.defaultCrewTypeId);
// Ref costWithTech() receives a troop count, not a leadership value.
// The policy funds four complete recruitments at the NPC stat cap.
const baseGold = crewType ? crewType.cost * getTechCost(tech, env.maxTechLevel) * stat.npcMax * 100 : 0;
const baseRice = crewType ? crewType.rice * getTechCost(tech, env.maxTechLevel) * stat.npcMax * 100 : 0;
// Ref costWithTech(tech, stat * 100) divides the troop count by 100.
const baseGold = crewType ? crewType.cost * getTechCost(tech, env.maxTechLevel) * stat.npcMax : 0;
const baseRice = crewType ? crewType.rice * getTechCost(tech, env.maxTechLevel) * stat.npcMax : 0;
if (this.reqNpcWarGold === 0) {
this.reqNpcWarGold = roundTo(baseGold * 4, -2);
}
@@ -328,8 +327,8 @@ export class AutorunNationPolicy {
if (this.reqHumanWarUrgentGold === 0 || this.reqHumanWarUrgentRice === 0) {
const crewType = findCrewTypeById(unitSet, env.defaultCrewTypeId);
const baseGold = crewType ? crewType.cost * getTechCost(tech, env.maxTechLevel) * stat.max * 100 : 0;
const baseRice = crewType ? crewType.rice * getTechCost(tech, env.maxTechLevel) * stat.max * 100 : 0;
const baseGold = crewType ? crewType.cost * getTechCost(tech, env.maxTechLevel) * stat.max : 0;
const baseRice = crewType ? crewType.rice * getTechCost(tech, env.maxTechLevel) * stat.max : 0;
if (this.reqHumanWarUrgentGold === 0) {
this.reqHumanWarUrgentGold = roundTo(baseGold * 6, -2);
}
@@ -157,6 +157,7 @@ export const createRaiseInvaderHandler = (options: {
world.updateWorldMeta({ isunited: 1, isUnited: 1 });
const totalGeneralCount = npcEachCount * invaderCities.length + world.listGenerals().length;
let creationTurnBase = environment.turnTime;
const maxGeneralsPerMinute =
options.maxGeneralsPerMinute ?? readNumber(world.getState().meta.maxGeneralsPerMinute, 1_000);
const currentTurnMinutes = world.getState().tickSeconds / 60;
@@ -166,6 +167,11 @@ export const createRaiseInvaderHandler = (options: {
);
if (nextTerm !== undefined) {
world.changeTurnTerm(nextTerm);
// Reprojection preserves the frozen monthly boundary by tick but
// changes its displayed Date. New generals must join that frozen
// boundary, not the realtime game clock that kept advancing while
// unification was waiting for a message response.
creationTurnBase = world.getState().lastTurnTime;
world.pushLog({
scope: LogScope.SYSTEM,
category: LogCategory.HISTORY,
@@ -348,7 +354,7 @@ export const createRaiseInvaderHandler = (options: {
reservedTurns: options.reservedTurns,
env: options.env,
rng,
environment,
environment: { ...environment, turnTime: creationTurnBase },
rawName: `${city.name}대왕`,
nationId,
cityId: city.id,
@@ -374,7 +380,7 @@ export const createRaiseInvaderHandler = (options: {
reservedTurns: options.reservedTurns,
env: options.env,
rng,
environment,
environment: { ...environment, turnTime: creationTurnBase },
rawName: `${city.name}장수${index}`,
nationId,
cityId: city.id,