feat: 커맨드 로그 메시지 개선 및 불필요한 항목 제거

This commit is contained in:
2026-02-05 12:33:55 +00:00
parent db1082ecb1
commit 39935404bc
20 changed files with 105 additions and 93 deletions
@@ -115,6 +115,10 @@ export class ActionDefinition<
category: LogCategory.USER,
format: LogFormat.PLAIN,
});
context.addLog(`<D><b>${args.nationName}</b></>${josaUl} 건국하였습니다.`, {
category: LogCategory.ACTION,
format: LogFormat.MONTH,
});
context.addLog(`${general.name}${josaYi} ${city?.name}에 국가를 건설하였습니다.`, {
category: LogCategory.ACTION,
format: LogFormat.MONTH,
@@ -13,6 +13,7 @@ import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js'
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
import type { GeneralTurnCommandSpec } from './index.js';
import { JosaUtil } from '@sammo-ts/common';
export interface TechResearchArgs {}
@@ -79,7 +80,10 @@ export class ActionDefinition<
nation.meta = { ...nation.meta, tech: nextTech };
general.gold = Math.max(0, general.gold - costGold);
context.addLog(`${ACTION_NAME}로 기술이 ${applied} 상승했습니다.`);
const logName = ACTION_NAME.replace(' ', '');
const josaUl = JosaUtil.pick(logName, '을');
const scoreText = applied.toLocaleString();
context.addLog(`${logName}${josaUl} 하여 <C>${scoreText}</> 상승했습니다.`);
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
return { effects: [] };
@@ -133,10 +133,7 @@ export class ActionDefinition<
const baseScore = Math.round((general.crew * general.train * general.atmos) / 20 / 10000);
const score = baseScore * multiplier;
const armTypeName = resolveArmTypeName(context.unitSet, crewType.armType);
const logPrefix = pick === 'success' ? '단련이 일취월장하여' : pick === 'fail' ? '단련이 지지부진하여' : '';
const logText = logPrefix
? `${logPrefix} ${armTypeName} 숙련도가 ${score} 향상되었습니다.`
: `${armTypeName} 숙련도가 ${score} 향상되었습니다.`;
const scoreText = score.toLocaleString();
const dexKey = `dex${crewType.armType}`;
const nextDex = getMetaNumber(general.meta, dexKey, 0) + score;
@@ -156,7 +153,17 @@ export class ActionDefinition<
general.gold = Math.max(0, general.gold - cost);
general.rice = Math.max(0, general.rice - cost);
context.addLog(logText);
if (pick === 'success') {
context.addLog(
`단련이 <S>일취월장</>하여 ${armTypeName} 숙련도가 <C>${scoreText}</> 향상되었습니다.`
);
} else if (pick === 'fail') {
context.addLog(
`단련이 <span class='ev_failed'>지지부진</span>하여 ${armTypeName} 숙련도가 <C>${scoreText}</> 향상되었습니다.`
);
} else {
context.addLog(`${armTypeName} 숙련도가 <C>${scoreText}</> 향상되었습니다.`);
}
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
return { effects: [] };
@@ -123,6 +123,12 @@ export class ActionResolver<
category: LogCategory.ACTION,
});
if (!ctx.nation) {
ctx.addLog(`<Y>${destGeneral.name}</>에게 등용 권유 서신을 보내지 못했습니다. 국가 정보가 없습니다.`, {
category: LogCategory.ACTION,
});
}
effects.push(
createLogEffect(
`<Y>${general.name}</>(${ctx.nation?.name ?? '재야'})로 부터 등용 권유 서신이 도착했습니다.`,
@@ -1,4 +1,5 @@
import type { RandomGenerator } from '@sammo-ts/common';
import { JosaUtil } from '@sammo-ts/common';
import type { City, General, GeneralMeta, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext, RequirementKey, StateView } from '@sammo-ts/logic/constraints/types.js';
import {
@@ -253,9 +254,18 @@ export class ActionResolver<
? { ...metaWithStatExp, max_domestic_critical: result.score }
: { ...metaWithStatExp, max_domestic_critical: 0 };
const pickLabel = result.pick === 'success' ? '성공' : result.pick === 'fail' ? '실패' : '완료';
const logMessage = `${ACTION_NAME} ${pickLabel}: +${Math.round(result.score)}`;
context.addLog(logMessage);
const scoreText = Math.round(result.score).toLocaleString();
const logName = ACTION_NAME.replace(' ', '');
const josaUl = JosaUtil.pick(logName, '을');
if (result.pick === 'fail') {
context.addLog(
`${logName}${josaUl} <span class='ev_failed'>실패</span>하여 <C>${scoreText}</> 상승했습니다.`
);
} else if (result.pick === 'success') {
context.addLog(`${logName}${josaUl} <S>성공</>하여 <C>${scoreText}</> 상승했습니다.`);
} else {
context.addLog(`${logName}${josaUl} 하여 <C>${scoreText}</> 상승했습니다.`);
}
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
return { effects: [] };
@@ -40,12 +40,10 @@ export class ActionDefinition<
const maxPop = city.populationMax;
const nextPop = clamp(currentPop + crew, 0, maxPop);
const addedPop = nextPop - currentPop;
general.crew = 0;
city.population = nextPop;
context.addLog(`병사들을 소집해제하여 인구가 ${addedPop} 증가했습니다.`);
context.addLog(`병사들을 <R>소집해제</>하였습니다.`);
return { effects: [] };
}
@@ -357,7 +357,9 @@ export class ActionResolver<
const nameObjJosa = JosaUtil.pick(name, '을');
const nameSubjJosa = JosaUtil.pick(name, '이');
context.addLog(`인재 <Y>${name}</>${nameObjJosa} 발견했습니다.`, {
const recruitVerb = randomRangeInt(context.rng, 0, 1) === 0 ? '발견' : '등용';
const nameRa = JosaUtil.pick(name, '라');
context.addLog(`<Y>${name}</>${nameRa}는 <C>인재</>를 ${recruitVerb}하였습니다!`, {
category: LogCategory.ACTION,
format: LogFormat.MONTH,
});
@@ -55,7 +55,8 @@ export class ActionDefinition<
context: GeneralActionResolveContext<TriggerState>,
args: AppointmentArgs
): GeneralActionOutcome<TriggerState> {
context.addLog(`${ACTION_NAME}을 신청했습니다. (국가 ${args.destNationId})`, {
const destNationName = context.nation?.name ?? `${args.destNationId}`;
context.addLog(`<D>${destNationName}</>에 임관했습니다.`, {
category: LogCategory.ACTION,
format: LogFormat.MONTH,
});
@@ -15,6 +15,7 @@ import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/action
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
import { clamp } from 'es-toolkit';
import type { GeneralTurnCommandSpec } from './index.js';
import { JosaUtil } from '@sammo-ts/common';
export interface SettlementArgs {}
@@ -68,7 +69,10 @@ export class ActionDefinition<
city.population = nextValue;
general.rice = Math.max(0, general.rice - costRice);
context.addLog(`인구가 ${nextValue - current} 증가했습니다.`);
const scoreText = (nextValue - current).toLocaleString();
const logName = this.name.replace(' ', '');
const josaUl = JosaUtil.pick(logName, '을');
context.addLog(`${logName}${josaUl} 하여 주민이 <C>${scoreText}</>명 증가했습니다.`);
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: '정착 장려' });
return { effects: [] };
@@ -1,4 +1,5 @@
import type { RandomGenerator } from '@sammo-ts/common';
import { JosaUtil } from '@sammo-ts/common';
import type { City, General, GeneralMeta, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext, RequirementKey } from '@sammo-ts/logic/constraints/types.js';
import {
@@ -165,7 +166,10 @@ export class ActionDefinition<
general.dedication += result.dedication;
general.meta = { ...addMetaNumber(general.meta, STAT_EXP_KEY, 1), max_domestic_critical: 0 };
context.addLog(`민심이 ${result.trustDelta.toFixed(1)} 상승했습니다.`);
const scoreText = result.trustDelta.toFixed(1);
const logName = ACTION_NAME.replace(' ', '');
const josaUl = JosaUtil.pick(logName, '을');
context.addLog(`${logName}${josaUl} 하여 <C>${scoreText}</> 상승했습니다.`);
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
return { effects: [] };
}
@@ -350,9 +350,7 @@ export class ActionResolver<
let nextCrew = general.crew;
let nextTrain = general.train;
let nextAtmos = general.atmos;
let logMessage = '';
const crewLabel = `${crewType.name} ${appliedCrew}`;
const crewLabel = `${crewType.name} <C>${appliedCrew.toLocaleString()}</>명`;
if (crewType.id === general.crewTypeId && general.crew > 0) {
nextCrew = general.crew + appliedCrew;
nextTrain = Math.round(
@@ -361,13 +359,13 @@ export class ActionResolver<
nextAtmos = Math.round(
(general.crew * general.atmos + appliedCrew * setAtmos) / (general.crew + appliedCrew)
);
logMessage = `${crewLabel} 추가 ${ACTION_NAME}했습니다.`;
context.addLog(`${crewLabel} 추가${ACTION_NAME}했습니다.`);
} else {
nextCrewTypeId = crewType.id;
nextCrew = appliedCrew;
nextTrain = Math.round(setTrain);
nextAtmos = Math.round(setAtmos);
logMessage = `${crewLabel} ${ACTION_NAME}했습니다.`;
context.addLog(`${crewLabel} ${ACTION_NAME}했습니다.`);
}
const nextGold = Math.max(0, general.gold - plan.gold);
@@ -392,7 +390,6 @@ export class ActionResolver<
general.dedication += dedGain;
general.meta = addMetaNumber(general.meta, 'leadership_exp', 1);
context.addLog(logMessage);
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
return { effects: [] };
@@ -348,11 +348,12 @@ export class ActionDefinition<
} else {
const targetName = finalTargetCity.name;
const josaRoTarget = JosaUtil.pick(targetName, '로');
const josaUl = JosaUtil.pick(destCity.name, '을');
context.addLog(
`가까운 경로에 적군 도시가 없습니다. <G><b>${destCity.name}</b></>${josaRo} 이동합니다.`
);
context.addLog(
`<G><b>${targetName}</b></>${josaRoTarget} 가는 도중 <G><b>${destCity.name}</b></> 거치기로 합니다.`
`<G><b>${targetName}</b></>${josaRoTarget} 가는 도중 <G><b>${destCity.name}</b></>${josaUl} 거치기로 합니다.`
);
}
return {
@@ -86,6 +86,7 @@ export class ActionDefinition<
const josaYi = JosaUtil.pick(generalName, '이');
const josaYiNation = JosaUtil.pick(newNationName, '이');
const josaRo = JosaUtil.pick(newNationName, '로');
const effects: Array<GeneralActionEffect<TriggerState>> = [
createNationPatchEffect(
@@ -99,14 +100,14 @@ export class ActionDefinition<
nation.id
),
// Global Action Log
createLogEffect(`<Y>${generalName}</>${josaYi} 국호를 <D><b>${newNationName}</b></>로 변경하였습니다.`, {
createLogEffect(`<Y>${generalName}</>${josaYi} 국호를 <D><b>${newNationName}</b></>${josaRo} 변경합니다.`, {
scope: LogScope.SYSTEM,
category: LogCategory.ACTION,
format: LogFormat.PLAIN,
}),
// Global History Log
createLogEffect(
`<S><b>【${ACTION_NAME}】</b></><D><b>${oldNationName}</b></>${josaYiNation} 국호를 <D><b>${newNationName}</b></>로 변경하였습니다.`,
`<S><b>【${ACTION_NAME}】</b></><D><b>${oldNationName}</b></>${josaYiNation} 국호를 <D><b>${newNationName}</b></>${josaRo} 변경합니다.`,
{
scope: LogScope.SYSTEM,
category: LogCategory.HISTORY,
@@ -114,14 +115,14 @@ export class ActionDefinition<
}
),
// Actor Nation History Log
createLogEffect(`<Y>${generalName}</>${josaYi} 국호를 <D><b>${newNationName}</b></>로 변경하였습니다.`, {
createLogEffect(`<Y>${generalName}</>${josaYi} 국호를 <D><b>${newNationName}</b></>${josaRo} 변경`, {
scope: LogScope.NATION,
nationId: nation.id,
category: LogCategory.HISTORY,
format: LogFormat.YEAR_MONTH,
}),
// General Action Log
createLogEffect(`국호를 <D><b>${newNationName}</b></>로 변경하였습니다.`, {
createLogEffect(`국호를 <D><b>${newNationName}</b></>${josaRo} 변경합니다.`, {
scope: LogScope.GENERAL,
category: LogCategory.ACTION,
format: LogFormat.MONTH,
@@ -117,6 +117,7 @@ export class ActionDefinition<
const amountText = actualAmount.toLocaleString();
const josaUl = JosaUtil.pick(amountText, '을');
const destGeneralName = destGeneral.name;
const effects: Array<GeneralActionEffect<TriggerState>> = [
createGeneralPatchEffect(
@@ -132,7 +133,7 @@ export class ActionDefinition<
nation.id
),
// Actor General Action Log
createLogEffect(`<Y>${destGeneral.name}</>에게서 ${resName} <C>${amountText}</>${josaUl} 몰수했습니다.`, {
createLogEffect(`<Y>${destGeneralName}</>에게서 ${resName} <C>${amountText}</>${josaUl} 몰수했습니다.`, {
scope: LogScope.GENERAL,
category: LogCategory.ACTION,
format: LogFormat.MONTH,
@@ -12,6 +12,7 @@ import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
import { createLogEffect } from '@sammo-ts/logic/actions/engine.js';
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
import { JosaUtil } from '@sammo-ts/common';
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
import type { NationTurnCommandSpec } from './index.js';
@@ -119,9 +120,12 @@ export class ActionDefinition<
_context: GeneralActionResolveContext<TriggerState>,
args: NonAggressionProposalArgs
): GeneralActionOutcome<TriggerState> {
const destNationName =
(_context as { destNation?: { name?: string } }).destNation?.name ?? `국가${args.destNationId}`;
const josaRo = JosaUtil.pick(destNationName, '로');
return {
effects: [
createLogEffect(`${ACTION_NAME}을 준비했습니다. (국가 ${args.destNationId})`, {
createLogEffect(`<D><b>${destNationName}</b></>${josaRo} 불가침 제의 서신을 보냈습니다.`, {
scope: LogScope.GENERAL,
category: LogCategory.ACTION,
format: LogFormat.MONTH,
@@ -12,6 +12,7 @@ import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
import { createLogEffect } from '@sammo-ts/logic/actions/engine.js';
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
import { JosaUtil } from '@sammo-ts/common';
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
import type { NationTurnCommandSpec } from './index.js';
@@ -59,9 +60,12 @@ export class ActionDefinition<
_context: GeneralActionResolveContext<TriggerState>,
args: NonAggressionCancelProposalArgs
): GeneralActionOutcome<TriggerState> {
const destNationName =
(_context as { destNation?: { name?: string } }).destNation?.name ?? `국가${args.destNationId}`;
const josaRo = JosaUtil.pick(destNationName, '로');
return {
effects: [
createLogEffect(`${ACTION_NAME}을 준비했습니다. (국가 ${args.destNationId})`, {
createLogEffect(`<D><b>${destNationName}</b></>${josaRo} 불가침 파기 제의 서신을 보냈습니다.`, {
scope: LogScope.GENERAL,
category: LogCategory.ACTION,
format: LogFormat.MONTH,
@@ -133,7 +133,7 @@ export class ActionResolver<
const amountJosa = JosaUtil.pick(amountText, '을');
effects.push(
createLogEffect(`${label} ${amountText}${amountJosa} 포상으로 받았습니다.`, {
createLogEffect(`${label} <C>${amountText}</>${amountJosa} 포상으로 받았습니다.`, {
scope: LogScope.GENERAL,
category: LogCategory.ACTION,
generalId: context.destGeneral.id,
@@ -141,11 +141,14 @@ export class ActionResolver<
})
);
effects.push(
createLogEffect(`<Y>${context.destGeneral.name}</>에게 ${label} ${amountText}${amountJosa} 수여했습니다.`, {
createLogEffect(
`<Y>${context.destGeneral.name}</>에게 ${label} <C>${amountText}</>${amountJosa} 수여했습니다.`,
{
scope: LogScope.GENERAL,
category: LogCategory.ACTION,
format: LogFormat.MONTH,
})
}
)
);
return { effects };