fix command-specific failure log parity

This commit is contained in:
2026-07-26 20:59:19 +00:00
parent 7676a3eee3
commit 3d5fff3687
12 changed files with 161 additions and 10 deletions
+7 -1
View File
@@ -1,4 +1,4 @@
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
import type { GeneralActionOutcome, GeneralActionResolveContext } from './engine.js';
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
@@ -16,6 +16,12 @@ export interface GeneralActionDefinition<
// 커맨드 입력 단계에서 최소 조건만 평가할 때 사용한다.
buildMinConstraints?(ctx: ConstraintContext, args: Args): Constraint[];
buildConstraints(ctx: ConstraintContext, args: Args): Constraint[];
formatConstraintFailure?(
reason: string,
ctx: ConstraintContext,
args: Args,
view: StateView
): string | null;
// NationCommand::addTermStack()/setNextAvailable() 호환 실행 메타데이터.
getPreReqTurn?(context: Context, args: Args): number;
getPostReqTurn?(context: Context, args: Args): number;
@@ -0,0 +1,31 @@
import { JosaUtil } from '@sammo-ts/common';
import type { City, General } from '@sammo-ts/logic/domain/entities.js';
import type { StateView } from '@sammo-ts/logic/constraints/types.js';
export const formatDestCityConstraintFailure = (
reason: string,
commandName: string,
destCityId: number,
view: StateView,
relation: 'direction' | 'location'
): string | null => {
const city = view.get({ kind: 'destCity', id: destCityId }) as City | null;
if (!city) {
return null;
}
const particle = relation === 'direction' ? JosaUtil.pick(city.name, '로') : '에';
return `${reason} <G><b>${city.name}</b></>${particle} ${commandName} 실패.`;
};
export const formatDestGeneralConstraintFailure = (
reason: string,
commandName: string,
destGeneralId: number,
view: StateView
): string | null => {
const general = view.get({ kind: 'destGeneral', id: destGeneralId }) as General | null;
if (!general) {
return null;
}
return `${reason} <Y>${general.name}</> ${commandName} 실패.`;
};
@@ -1,5 +1,5 @@
import type { General, GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
import { notSameDestCity, nearCity, reqGeneralGold, reqGeneralRice } from '@sammo-ts/logic/constraints/presets.js';
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
import type {
@@ -18,6 +18,7 @@ import type { GeneralTurnCommandSpec } from './index.js';
import type { MapDefinition } from '@sammo-ts/logic/world/types.js';
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
import { normalizeLegacyIntegerArg, parseArgsWithSchema } from '../parseArgs.js';
import { formatDestCityConstraintFailure } from '../constraintFailure.js';
export interface ForcedMoveResolveContext<
TriggerState extends GeneralTriggerState = GeneralTriggerState,
@@ -173,6 +174,15 @@ export class ActionDefinition<
];
}
formatConstraintFailure(
reason: string,
_ctx: ConstraintContext,
args: ForcedMoveArgs,
view: StateView
): string | null {
return formatDestCityConstraintFailure(reason, this.name, args.destCityId, view, 'direction');
}
resolve(context: ForcedMoveResolveContext<TriggerState>, args: ForcedMoveArgs): GeneralActionOutcome<TriggerState> {
return this.resolver.resolve(context, args);
}
@@ -1,5 +1,5 @@
import type { General, GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
import {
notSameDestCity,
nearCity,
@@ -23,6 +23,7 @@ import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js'
import type { GeneralTurnCommandSpec } from './index.js';
import type { MapDefinition } from '@sammo-ts/logic/world/types.js';
import { parseArgsWithSchema } from '../parseArgs.js';
import { formatDestCityConstraintFailure } from '../constraintFailure.js';
export interface MoveResolveContext<
TriggerState extends GeneralTriggerState = GeneralTriggerState,
@@ -152,6 +153,15 @@ export class ActionDefinition<
];
}
formatConstraintFailure(
reason: string,
_ctx: ConstraintContext,
args: MoveArgs,
view: StateView
): string | null {
return formatDestCityConstraintFailure(reason, this.name, args.destCityId, view, 'direction');
}
resolve(context: MoveResolveContext<TriggerState>, args: MoveArgs): GeneralActionOutcome<TriggerState> {
return this.resolver.resolve(context, args);
}
@@ -1,5 +1,5 @@
import type { City, General, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
import {
notOccupiedDestCity,
reqGeneralGold,
@@ -22,6 +22,7 @@ import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/ac
import type { GeneralTurnCommandSpec } from './index.js';
import type { MapDefinition, UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
import { parseArgsWithSchema } from '../parseArgs.js';
import { formatDestCityConstraintFailure } from '../constraintFailure.js';
export interface SpyResolveContext<
TriggerState extends GeneralTriggerState = GeneralTriggerState,
@@ -316,6 +317,15 @@ export class ActionDefinition<
return [notOccupiedDestCity(), reqGeneralGold(() => cost), reqGeneralRice(() => cost)];
}
formatConstraintFailure(
reason: string,
_ctx: ConstraintContext,
args: SpyArgs,
view: StateView
): string | null {
return formatDestCityConstraintFailure(reason, this.name, args.destCityId, view, 'location');
}
resolve(context: GeneralActionResolveContext<TriggerState>, args: SpyArgs): GeneralActionOutcome<TriggerState> {
return this.resolver.resolve(context, args);
}
@@ -36,6 +36,7 @@ import { increaseMetaNumber, simpleSerialize } from '@sammo-ts/logic/war/utils.j
import type { MapDefinition, UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
import { formatDestCityConstraintFailure } from '../constraintFailure.js';
import {
buildWarAftermathConfig,
buildWarConfig,
@@ -304,6 +305,15 @@ export class ActionDefinition<
];
}
formatConstraintFailure(
reason: string,
_ctx: ConstraintContext,
args: DispatchArgs,
view: StateView
): string | null {
return formatDestCityConstraintFailure(reason, this.name, args.destCityId, view, 'direction');
}
resolve(context: DispatchResolveContext<TriggerState>, args: DispatchArgs): GeneralActionOutcome<TriggerState> {
void args;
const attackerCity = context.city;
@@ -1,6 +1,6 @@
import type { RandomGenerator } from '@sammo-ts/common';
import type { City, General, GeneralMeta, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
import {
disallowDiplomacyBetweenStatus,
notBeNeutral,
@@ -35,6 +35,7 @@ import { clamp } from 'es-toolkit';
import { parseArgsWithSchema } from '../parseArgs.js';
import { consumeSuccessfulStrategyItem } from './strategyItemConsumption.js';
import { searchDistance } from '@sammo-ts/logic/world/distance.js';
import { formatDestCityConstraintFailure } from '../constraintFailure.js';
export interface FireAttackEnvironment {
develCost: number;
@@ -436,6 +437,15 @@ export class ActionDefinition<
];
}
formatConstraintFailure(
reason: string,
_ctx: ConstraintContext,
args: FireAttackArgs,
view: StateView
): string | null {
return formatDestCityConstraintFailure(reason, this.name, args.destCityId, view, 'location');
}
resolve(context: FireAttackResolveContext<TriggerState>, args: FireAttackArgs): GeneralActionOutcome<TriggerState> {
return this.resolver.resolve(context, args);
}
@@ -1,5 +1,5 @@
import type { City, General, GeneralMeta, GeneralTriggerState, TriggerValue } from '@sammo-ts/logic/domain/entities.js';
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
import {
beChief,
existsDestGeneral,
@@ -26,6 +26,7 @@ import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js'
import type { NationTurnCommandSpec } from './index.js';
import { z } from 'zod';
import { normalizeLegacyIntegerArg, parseArgsWithSchema } from '../parseArgs.js';
import { formatDestGeneralConstraintFailure } from '../constraintFailure.js';
const ARGS_SCHEMA = z.object({
destGeneralId: z.preprocess(normalizeLegacyIntegerArg, z.number().int()),
@@ -176,6 +177,15 @@ export class ActionDefinition<
];
}
formatConstraintFailure(
reason: string,
_ctx: ConstraintContext,
args: AssignmentArgs,
view: StateView
): string | null {
return formatDestGeneralConstraintFailure(reason, this.name, args.destGeneralId, view);
}
resolve(context: AssignmentResolveContext<TriggerState>, args: AssignmentArgs): GeneralActionOutcome<TriggerState> {
return this.resolver.resolve(context, args);
}
+1 -1
View File
@@ -121,7 +121,7 @@ export const occupiedDestCity = (): Constraint => ({
if (destCity.nationId === baseNationId) {
return allow();
}
return { kind: 'deny', reason: '아국이 아닙니다.' };
return { kind: 'deny', reason: '대상 도시가 아국이 아닙니다.' };
},
});