feat: eslint 적용 및 관련 코드 일괄 수정
This commit is contained in:
@@ -1,8 +1,4 @@
|
||||
import type {
|
||||
General,
|
||||
GeneralTriggerState,
|
||||
Nation,
|
||||
} from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { General, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import {
|
||||
allowDiplomacyWithTerm,
|
||||
@@ -11,10 +7,7 @@ import {
|
||||
existsDestNation,
|
||||
occupiedCity,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import {
|
||||
GeneralActionPipeline,
|
||||
type GeneralActionModule,
|
||||
} from '@sammo-ts/logic/triggers/general-action.js';
|
||||
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type {
|
||||
GeneralActionEffect,
|
||||
@@ -22,10 +15,7 @@ import type {
|
||||
GeneralActionResolveContext,
|
||||
GeneralActionResolver,
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
import {
|
||||
createDiplomacyPatchEffect,
|
||||
createLogEffect,
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
import { createDiplomacyPatchEffect, createLogEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
@@ -38,7 +28,7 @@ export interface RaidArgs {
|
||||
}
|
||||
|
||||
export interface RaidResolveContext<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> extends GeneralActionResolveContext<TriggerState> {
|
||||
destNation: Nation;
|
||||
diplomacy: { state: number; term: number };
|
||||
@@ -62,9 +52,7 @@ const parseNationId = (raw: unknown): number | null => {
|
||||
};
|
||||
|
||||
// 급습 쿨타임 계산을 담당한다.
|
||||
export class CommandResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> {
|
||||
export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
||||
|
||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>) {
|
||||
@@ -72,20 +60,13 @@ export class CommandResolver<
|
||||
}
|
||||
|
||||
getGlobalDelay(context: RaidResolveContext<TriggerState>): number {
|
||||
return Math.round(
|
||||
this.pipeline.onCalcStrategic(
|
||||
context,
|
||||
ACTION_NAME,
|
||||
'globalDelay',
|
||||
DEFAULT_GLOBAL_DELAY
|
||||
)
|
||||
);
|
||||
return Math.round(this.pipeline.onCalcStrategic(context, ACTION_NAME, 'globalDelay', DEFAULT_GLOBAL_DELAY));
|
||||
}
|
||||
}
|
||||
|
||||
// 급습 실행 결과를 계산한다.
|
||||
export class ActionResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionResolver<TriggerState, RaidArgs> {
|
||||
readonly key = 'che_급습';
|
||||
private readonly command: CommandResolver<TriggerState>;
|
||||
@@ -94,10 +75,7 @@ export class ActionResolver<
|
||||
this.command = new CommandResolver(modules);
|
||||
}
|
||||
|
||||
resolve(
|
||||
context: RaidResolveContext<TriggerState>,
|
||||
_args: RaidArgs
|
||||
): GeneralActionOutcome<TriggerState> {
|
||||
resolve(context: RaidResolveContext<TriggerState>, _args: RaidArgs): GeneralActionOutcome<TriggerState> {
|
||||
void _args;
|
||||
const { general, nation } = context;
|
||||
const generalName = general.name;
|
||||
@@ -111,29 +89,18 @@ export class ActionResolver<
|
||||
general.dedication += EXP_DED_GAIN;
|
||||
|
||||
context.addLog(`${ACTION_NAME} 발동!`, { format: LogFormat.MONTH });
|
||||
context.addLog(
|
||||
`<D><b>${destNationName}</b></>에 <M>${ACTION_NAME}</>${actionJosa} 발동`,
|
||||
{
|
||||
category: LogCategory.HISTORY,
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
}
|
||||
);
|
||||
context.addLog(`<D><b>${destNationName}</b></>에 <M>${ACTION_NAME}</>${actionJosa} 발동`, {
|
||||
category: LogCategory.HISTORY,
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
});
|
||||
|
||||
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
||||
createDiplomacyPatchEffect(
|
||||
general.nationId,
|
||||
context.destNation.id,
|
||||
{
|
||||
term: context.diplomacy.term - TERM_REDUCE,
|
||||
}
|
||||
),
|
||||
createDiplomacyPatchEffect(
|
||||
context.destNation.id,
|
||||
general.nationId,
|
||||
{
|
||||
term: context.reverseDiplomacy.term - TERM_REDUCE,
|
||||
}
|
||||
),
|
||||
createDiplomacyPatchEffect(general.nationId, context.destNation.id, {
|
||||
term: context.diplomacy.term - TERM_REDUCE,
|
||||
}),
|
||||
createDiplomacyPatchEffect(context.destNation.id, general.nationId, {
|
||||
term: context.reverseDiplomacy.term - TERM_REDUCE,
|
||||
}),
|
||||
];
|
||||
|
||||
for (const target of context.friendlyGenerals) {
|
||||
@@ -195,12 +162,8 @@ export class ActionResolver<
|
||||
|
||||
// 급습 실행을 위한 정의/제약을 구성한다.
|
||||
export class ActionDefinition<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> implements GeneralActionDefinition<
|
||||
TriggerState,
|
||||
RaidArgs,
|
||||
RaidResolveContext<TriggerState>
|
||||
> {
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionDefinition<TriggerState, RaidArgs, RaidResolveContext<TriggerState>> {
|
||||
public readonly key = 'che_급습';
|
||||
public readonly name = ACTION_NAME;
|
||||
private readonly resolver: ActionResolver<TriggerState>;
|
||||
@@ -225,19 +188,12 @@ export class ActionDefinition<
|
||||
occupiedCity(),
|
||||
beChief(),
|
||||
existsDestNation(),
|
||||
allowDiplomacyWithTerm(
|
||||
1,
|
||||
12,
|
||||
'선포 12개월 이상인 상대국에만 가능합니다.'
|
||||
),
|
||||
allowDiplomacyWithTerm(1, 12, '선포 12개월 이상인 상대국에만 가능합니다.'),
|
||||
availableStrategicCommand(),
|
||||
];
|
||||
}
|
||||
|
||||
resolve(
|
||||
context: RaidResolveContext<TriggerState>,
|
||||
args: RaidArgs
|
||||
): GeneralActionOutcome<TriggerState> {
|
||||
resolve(context: RaidResolveContext<TriggerState>, args: RaidArgs): GeneralActionOutcome<TriggerState> {
|
||||
return this.resolver.resolve(context, args);
|
||||
}
|
||||
}
|
||||
@@ -263,12 +219,8 @@ export const actionContextBuilder: ActionContextBuilder = (base, options) => {
|
||||
worldRef.getDiplomacyEntry(destNationId, base.general.nationId) ??
|
||||
buildDefaultDiplomacy(destNationId, base.general.nationId);
|
||||
const generals = worldRef.listGenerals();
|
||||
const friendlyGenerals = generals.filter(
|
||||
(general) => general.nationId === base.general.nationId
|
||||
);
|
||||
const destNationGenerals = generals.filter(
|
||||
(general) => general.nationId === destNationId
|
||||
);
|
||||
const friendlyGenerals = generals.filter((general) => general.nationId === base.general.nationId);
|
||||
const destNationGenerals = generals.filter((general) => general.nationId === destNationId);
|
||||
return {
|
||||
...base,
|
||||
destNation,
|
||||
@@ -284,6 +236,5 @@ export const commandSpec: NationTurnCommandSpec = {
|
||||
category: '외교',
|
||||
reqArg: true,
|
||||
args: { destNationId: 0 },
|
||||
createDefinition: (env: TurnCommandEnv) =>
|
||||
new ActionDefinition(env.generalActionModules ?? []),
|
||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.generalActionModules ?? []),
|
||||
};
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
import type {
|
||||
City,
|
||||
General,
|
||||
GeneralTriggerState,
|
||||
TriggerValue,
|
||||
} from '@sammo-ts/logic/domain/entities.js';
|
||||
import type {
|
||||
Constraint,
|
||||
ConstraintContext,
|
||||
} from '@sammo-ts/logic/constraints/types.js';
|
||||
import type { City, General, GeneralTriggerState, TriggerValue } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import {
|
||||
alwaysFail,
|
||||
beChief,
|
||||
@@ -40,7 +32,7 @@ export interface AssignmentArgs {
|
||||
}
|
||||
|
||||
export interface AssignmentResolveContext<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> extends GeneralActionResolveContext<TriggerState> {
|
||||
destGeneral: General<TriggerState>;
|
||||
destCity: City;
|
||||
@@ -57,17 +49,14 @@ export interface AssignmentEnvironment {
|
||||
|
||||
const ACTION_NAME = '발령';
|
||||
|
||||
const joinYearMonth = (year: number, month: number): number =>
|
||||
year * 12 + month - 1;
|
||||
const joinYearMonth = (year: number, month: number): number => year * 12 + month - 1;
|
||||
|
||||
const cutTurn = (time: Date, turnTermMinutes: number): number => {
|
||||
const turnMs = turnTermMinutes * 60 * 1000;
|
||||
return Math.floor(time.getTime() / turnMs);
|
||||
};
|
||||
|
||||
const resolveLastAssignment = (
|
||||
context: AssignmentResolveContext
|
||||
): number => {
|
||||
const resolveLastAssignment = (context: AssignmentResolveContext): number => {
|
||||
let yearMonth = joinYearMonth(context.currentYear, context.currentMonth);
|
||||
const term = context.turnTermMinutes;
|
||||
const srcTime = context.generalTurnTime;
|
||||
@@ -91,7 +80,7 @@ const addMetaValue = (
|
||||
|
||||
// 발령 결과를 계산한다.
|
||||
export class ActionResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionResolver<TriggerState, AssignmentArgs> {
|
||||
readonly key = 'che_발령';
|
||||
private readonly env: AssignmentEnvironment;
|
||||
@@ -107,9 +96,7 @@ export class ActionResolver<
|
||||
void _args;
|
||||
const destGeneral = context.destGeneral;
|
||||
const destCity = context.destCity;
|
||||
const cityName = this.env.formatCityName
|
||||
? this.env.formatCityName(destCity)
|
||||
: destCity.name;
|
||||
const cityName = this.env.formatCityName ? this.env.formatCityName(destCity) : destCity.name;
|
||||
const cityJosa = JosaUtil.pick(cityName, '로');
|
||||
const generalJosa = JosaUtil.pick(destGeneral.name, '을');
|
||||
const yearMonth = resolveLastAssignment(context);
|
||||
@@ -125,15 +112,12 @@ export class ActionResolver<
|
||||
];
|
||||
|
||||
effects.push(
|
||||
createLogEffect(
|
||||
`<Y>${context.general.name}</>에 의해 <G><b>${cityName}</b></>${cityJosa} 발령됐습니다.`,
|
||||
{
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
generalId: destGeneral.id,
|
||||
format: LogFormat.MONTH,
|
||||
}
|
||||
)
|
||||
createLogEffect(`<Y>${context.general.name}</>에 의해 <G><b>${cityName}</b></>${cityJosa} 발령됐습니다.`, {
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
generalId: destGeneral.id,
|
||||
format: LogFormat.MONTH,
|
||||
})
|
||||
);
|
||||
effects.push(
|
||||
createLogEffect(
|
||||
@@ -151,12 +135,8 @@ export class ActionResolver<
|
||||
}
|
||||
|
||||
export class ActionDefinition<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> implements GeneralActionDefinition<
|
||||
TriggerState,
|
||||
AssignmentArgs,
|
||||
AssignmentResolveContext<TriggerState>
|
||||
> {
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionDefinition<TriggerState, AssignmentArgs, AssignmentResolveContext<TriggerState>> {
|
||||
public readonly key = 'che_발령';
|
||||
public readonly name = ACTION_NAME;
|
||||
private readonly resolver: ActionResolver<TriggerState>;
|
||||
@@ -185,10 +165,7 @@ export class ActionDefinition<
|
||||
};
|
||||
}
|
||||
|
||||
buildConstraints(
|
||||
ctx: ConstraintContext,
|
||||
_args: AssignmentArgs
|
||||
): Constraint[] {
|
||||
buildConstraints(ctx: ConstraintContext, _args: AssignmentArgs): Constraint[] {
|
||||
void _args;
|
||||
if (ctx.destGeneralId === ctx.actorId) {
|
||||
return [alwaysFail('본인입니다')];
|
||||
@@ -205,10 +182,7 @@ export class ActionDefinition<
|
||||
];
|
||||
}
|
||||
|
||||
resolve(
|
||||
context: AssignmentResolveContext<TriggerState>,
|
||||
args: AssignmentArgs
|
||||
): GeneralActionOutcome<TriggerState> {
|
||||
resolve(context: AssignmentResolveContext<TriggerState>, args: AssignmentArgs): GeneralActionOutcome<TriggerState> {
|
||||
return this.resolver.resolve(context, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import type {
|
||||
City,
|
||||
General,
|
||||
GeneralTriggerState,
|
||||
} from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { City, General, GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import {
|
||||
availableStrategicCommand,
|
||||
@@ -10,10 +6,7 @@ import {
|
||||
occupiedCity,
|
||||
occupiedDestCity,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import {
|
||||
GeneralActionPipeline,
|
||||
type GeneralActionModule,
|
||||
} from '@sammo-ts/logic/triggers/general-action.js';
|
||||
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type {
|
||||
GeneralActionEffect,
|
||||
@@ -33,7 +26,7 @@ export interface MobilizePeopleArgs {
|
||||
}
|
||||
|
||||
export interface MobilizePeopleResolveContext<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> extends GeneralActionResolveContext<TriggerState> {
|
||||
destCity: City;
|
||||
friendlyGenerals: Array<General<TriggerState>>;
|
||||
@@ -54,9 +47,7 @@ const parseCityId = (raw: unknown): number | null => {
|
||||
};
|
||||
|
||||
// 백성동원 쿨타임 계산을 담당한다.
|
||||
export class CommandResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> {
|
||||
export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
||||
|
||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>) {
|
||||
@@ -64,20 +55,13 @@ export class CommandResolver<
|
||||
}
|
||||
|
||||
getGlobalDelay(context: MobilizePeopleResolveContext<TriggerState>): number {
|
||||
return Math.round(
|
||||
this.pipeline.onCalcStrategic(
|
||||
context,
|
||||
ACTION_NAME,
|
||||
'globalDelay',
|
||||
DEFAULT_GLOBAL_DELAY
|
||||
)
|
||||
);
|
||||
return Math.round(this.pipeline.onCalcStrategic(context, ACTION_NAME, 'globalDelay', DEFAULT_GLOBAL_DELAY));
|
||||
}
|
||||
}
|
||||
|
||||
// 백성동원 실행 결과를 계산한다.
|
||||
export class ActionResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionResolver<TriggerState, MobilizePeopleArgs> {
|
||||
readonly key = 'che_백성동원';
|
||||
private readonly command: CommandResolver<TriggerState>;
|
||||
@@ -101,13 +85,10 @@ export class ActionResolver<
|
||||
general.dedication += EXP_DED_GAIN;
|
||||
|
||||
context.addLog(`${ACTION_NAME} 발동!`, { format: LogFormat.MONTH });
|
||||
context.addLog(
|
||||
`<G><b>${cityName}</b></>에 <M>${ACTION_NAME}</>을 발동`,
|
||||
{
|
||||
category: LogCategory.HISTORY,
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
}
|
||||
);
|
||||
context.addLog(`<G><b>${cityName}</b></>에 <M>${ACTION_NAME}</>을 발동`, {
|
||||
category: LogCategory.HISTORY,
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
});
|
||||
|
||||
const effects: Array<GeneralActionEffect<TriggerState>> = [];
|
||||
|
||||
@@ -125,14 +106,8 @@ export class ActionResolver<
|
||||
);
|
||||
}
|
||||
|
||||
const nextDefence = Math.max(
|
||||
context.destCity.defence,
|
||||
context.destCity.defenceMax * DEFENCE_RATE
|
||||
);
|
||||
const nextWall = Math.max(
|
||||
context.destCity.wall,
|
||||
context.destCity.wallMax * DEFENCE_RATE
|
||||
);
|
||||
const nextDefence = Math.max(context.destCity.defence, context.destCity.defenceMax * DEFENCE_RATE);
|
||||
const nextWall = Math.max(context.destCity.wall, context.destCity.wallMax * DEFENCE_RATE);
|
||||
effects.push(
|
||||
createCityPatchEffect(
|
||||
{
|
||||
@@ -165,12 +140,8 @@ export class ActionResolver<
|
||||
|
||||
// 백성동원 실행을 위한 정의/제약을 구성한다.
|
||||
export class ActionDefinition<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> implements GeneralActionDefinition<
|
||||
TriggerState,
|
||||
MobilizePeopleArgs,
|
||||
MobilizePeopleResolveContext<TriggerState>
|
||||
> {
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionDefinition<TriggerState, MobilizePeopleArgs, MobilizePeopleResolveContext<TriggerState>> {
|
||||
public readonly key = 'che_백성동원';
|
||||
public readonly name = ACTION_NAME;
|
||||
private readonly resolver: ActionResolver<TriggerState>;
|
||||
@@ -188,18 +159,10 @@ export class ActionDefinition<
|
||||
return { destCityId };
|
||||
}
|
||||
|
||||
buildConstraints(
|
||||
_ctx: ConstraintContext,
|
||||
_args: MobilizePeopleArgs
|
||||
): Constraint[] {
|
||||
buildConstraints(_ctx: ConstraintContext, _args: MobilizePeopleArgs): Constraint[] {
|
||||
void _ctx;
|
||||
void _args;
|
||||
return [
|
||||
occupiedCity(),
|
||||
beChief(),
|
||||
occupiedDestCity(),
|
||||
availableStrategicCommand(),
|
||||
];
|
||||
return [occupiedCity(), beChief(), occupiedDestCity(), availableStrategicCommand()];
|
||||
}
|
||||
|
||||
resolve(
|
||||
@@ -224,9 +187,7 @@ export const actionContextBuilder: ActionContextBuilder = (base, options) => {
|
||||
if (!destCity) {
|
||||
return null;
|
||||
}
|
||||
const friendlyGenerals = worldRef
|
||||
.listGenerals()
|
||||
.filter((general) => general.nationId === base.general.nationId);
|
||||
const friendlyGenerals = worldRef.listGenerals().filter((general) => general.nationId === base.general.nationId);
|
||||
return {
|
||||
...base,
|
||||
destCity,
|
||||
@@ -239,6 +200,5 @@ export const commandSpec: NationTurnCommandSpec = {
|
||||
category: '전략',
|
||||
reqArg: true,
|
||||
args: { destCityId: 0 },
|
||||
createDefinition: (env: TurnCommandEnv) =>
|
||||
new ActionDefinition(env.generalActionModules ?? []),
|
||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.generalActionModules ?? []),
|
||||
};
|
||||
|
||||
@@ -1,11 +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 { General, GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import {
|
||||
alwaysFail,
|
||||
beChief,
|
||||
@@ -19,10 +13,7 @@ import type {
|
||||
GeneralActionOutcome,
|
||||
GeneralActionResolveContext,
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
import {
|
||||
createGeneralPatchEffect,
|
||||
createLogEffect,
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
import { createGeneralPatchEffect, createLogEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||
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';
|
||||
@@ -34,7 +25,7 @@ export interface TroopKickArgs {
|
||||
}
|
||||
|
||||
export interface TroopKickResolveContext<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> extends GeneralActionResolveContext<TriggerState> {
|
||||
destGeneral: General<TriggerState>;
|
||||
}
|
||||
@@ -42,12 +33,8 @@ export interface TroopKickResolveContext<
|
||||
const ACTION_NAME = '부대 탈퇴 지시';
|
||||
|
||||
export class ActionDefinition<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> implements GeneralActionDefinition<
|
||||
TriggerState,
|
||||
TroopKickArgs,
|
||||
TroopKickResolveContext<TriggerState>
|
||||
> {
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionDefinition<TriggerState, TroopKickArgs, TroopKickResolveContext<TriggerState>> {
|
||||
public readonly key = 'che_부대탈퇴지시';
|
||||
public readonly name = ACTION_NAME;
|
||||
|
||||
@@ -65,25 +52,14 @@ export class ActionDefinition<
|
||||
return { destGeneralId: data.destGeneralId };
|
||||
}
|
||||
|
||||
buildConstraints(
|
||||
ctx: ConstraintContext,
|
||||
_args: TroopKickArgs
|
||||
): Constraint[] {
|
||||
buildConstraints(ctx: ConstraintContext, _args: TroopKickArgs): Constraint[] {
|
||||
if (ctx.destGeneralId !== undefined && ctx.destGeneralId === ctx.actorId) {
|
||||
return [alwaysFail('본인입니다')];
|
||||
}
|
||||
return [
|
||||
notBeNeutral(),
|
||||
beChief(),
|
||||
existsDestGeneral(),
|
||||
friendlyDestGeneral(),
|
||||
];
|
||||
return [notBeNeutral(), beChief(), existsDestGeneral(), friendlyDestGeneral()];
|
||||
}
|
||||
|
||||
resolve(
|
||||
context: TroopKickResolveContext<TriggerState>,
|
||||
_args: TroopKickArgs
|
||||
): GeneralActionOutcome<TriggerState> {
|
||||
resolve(context: TroopKickResolveContext<TriggerState>, _args: TroopKickArgs): GeneralActionOutcome<TriggerState> {
|
||||
const general = context.general;
|
||||
const destGeneral = context.destGeneral;
|
||||
const destGeneralName = destGeneral.name;
|
||||
@@ -91,46 +67,31 @@ export class ActionDefinition<
|
||||
const effects: Array<GeneralActionEffect<TriggerState>> = [];
|
||||
|
||||
if (destGeneral.troopId === 0) {
|
||||
context.addLog(
|
||||
`<Y>${destGeneralName}</>${josaUn} 부대원이 아닙니다.`
|
||||
);
|
||||
context.addLog(`<Y>${destGeneralName}</>${josaUn} 부대원이 아닙니다.`);
|
||||
return { effects };
|
||||
}
|
||||
|
||||
if (destGeneral.troopId === destGeneral.id) {
|
||||
context.addLog(
|
||||
`<Y>${destGeneralName}</>${josaUn} 부대장입니다.`
|
||||
);
|
||||
context.addLog(`<Y>${destGeneralName}</>${josaUn} 부대장입니다.`);
|
||||
return { effects };
|
||||
}
|
||||
|
||||
effects.push(
|
||||
createGeneralPatchEffect(
|
||||
{ troopId: 0 } as Partial<General<TriggerState>>,
|
||||
destGeneral.id
|
||||
)
|
||||
);
|
||||
effects.push(createGeneralPatchEffect({ troopId: 0 } as Partial<General<TriggerState>>, destGeneral.id));
|
||||
|
||||
effects.push(
|
||||
createLogEffect(
|
||||
`<Y>${destGeneralName}</>에게 부대 탈퇴를 지시했습니다.`,
|
||||
{
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.MONTH,
|
||||
}
|
||||
)
|
||||
createLogEffect(`<Y>${destGeneralName}</>에게 부대 탈퇴를 지시했습니다.`, {
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.MONTH,
|
||||
})
|
||||
);
|
||||
effects.push(
|
||||
createLogEffect(
|
||||
`<Y>${general.name}</>에게 부대 탈퇴를 지시 받았습니다.`,
|
||||
{
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.PLAIN,
|
||||
generalId: destGeneral.id,
|
||||
}
|
||||
)
|
||||
createLogEffect(`<Y>${general.name}</>에게 부대 탈퇴를 지시 받았습니다.`, {
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.PLAIN,
|
||||
generalId: destGeneral.id,
|
||||
})
|
||||
);
|
||||
|
||||
return { effects };
|
||||
|
||||
@@ -9,10 +9,7 @@ import {
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import { allow, unknownOrDeny } from '@sammo-ts/logic/constraints/helpers.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type {
|
||||
GeneralActionOutcome,
|
||||
GeneralActionResolveContext,
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
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 type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
@@ -50,8 +47,7 @@ const parseMonth = (raw: unknown): number | null => {
|
||||
return month >= 1 && month <= 12 ? month : null;
|
||||
};
|
||||
|
||||
const resolveMonthIndex = (year: number, month: number): number =>
|
||||
year * 12 + month - 1;
|
||||
const resolveMonthIndex = (year: number, month: number): number => year * 12 + month - 1;
|
||||
|
||||
const requireMinimumTerm = (minMonths: number): Constraint => ({
|
||||
name: 'RequireNonAggressionMinimumTerm',
|
||||
@@ -65,8 +61,7 @@ const requireMinimumTerm = (minMonths: number): Constraint => ({
|
||||
const yearValue = typeof ctx.args.year === 'number' ? ctx.args.year : null;
|
||||
const monthValue = typeof ctx.args.month === 'number' ? ctx.args.month : null;
|
||||
const envYearValue = typeof ctx.env.year === 'number' ? ctx.env.year : null;
|
||||
const envMonthValue =
|
||||
typeof ctx.env.month === 'number' ? ctx.env.month : null;
|
||||
const envMonthValue = typeof ctx.env.month === 'number' ? ctx.env.month : null;
|
||||
const missing = [];
|
||||
|
||||
if (yearValue === null) {
|
||||
@@ -106,7 +101,7 @@ const requireMinimumTerm = (minMonths: number): Constraint => ({
|
||||
|
||||
// 불가침 제의를 처리하는 국가 커맨드.
|
||||
export class ActionDefinition<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionDefinition<TriggerState, NonAggressionProposalArgs> {
|
||||
public readonly key = 'che_불가침제의';
|
||||
public readonly name = ACTION_NAME;
|
||||
@@ -126,10 +121,7 @@ export class ActionDefinition<
|
||||
return { destNationId, year, month };
|
||||
}
|
||||
|
||||
buildConstraints(
|
||||
_ctx: ConstraintContext,
|
||||
_args: NonAggressionProposalArgs
|
||||
): Constraint[] {
|
||||
buildConstraints(_ctx: ConstraintContext, _args: NonAggressionProposalArgs): Constraint[] {
|
||||
return [
|
||||
beChief(),
|
||||
notBeNeutral(),
|
||||
@@ -149,14 +141,11 @@ export class ActionDefinition<
|
||||
): GeneralActionOutcome<TriggerState> {
|
||||
return {
|
||||
effects: [
|
||||
createLogEffect(
|
||||
`${ACTION_NAME}을 준비했습니다. (국가 ${args.destNationId})`,
|
||||
{
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.MONTH,
|
||||
}
|
||||
),
|
||||
createLogEffect(`${ACTION_NAME}을 준비했습니다. (국가 ${args.destNationId})`, {
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.MONTH,
|
||||
}),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,10 +9,7 @@ import {
|
||||
suppliedCity,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type {
|
||||
GeneralActionOutcome,
|
||||
GeneralActionResolveContext,
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
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 type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
@@ -35,10 +32,8 @@ const parseNationId = (raw: unknown): number | null => {
|
||||
|
||||
// 불가침 파기 제의를 처리하는 국가 커맨드.
|
||||
export class ActionDefinition<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> implements
|
||||
GeneralActionDefinition<TriggerState, NonAggressionCancelProposalArgs>
|
||||
{
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionDefinition<TriggerState, NonAggressionCancelProposalArgs> {
|
||||
public readonly key = 'che_불가침파기제의';
|
||||
public readonly name = ACTION_NAME;
|
||||
|
||||
@@ -51,20 +46,14 @@ export class ActionDefinition<
|
||||
return { destNationId };
|
||||
}
|
||||
|
||||
buildConstraints(
|
||||
_ctx: ConstraintContext,
|
||||
_args: NonAggressionCancelProposalArgs
|
||||
): Constraint[] {
|
||||
buildConstraints(_ctx: ConstraintContext, _args: NonAggressionCancelProposalArgs): Constraint[] {
|
||||
return [
|
||||
beChief(),
|
||||
notBeNeutral(),
|
||||
occupiedCity(),
|
||||
suppliedCity(),
|
||||
existsDestNation(),
|
||||
allowDiplomacyBetweenStatus(
|
||||
[DIPLOMACY_NON_AGGRESSION],
|
||||
'불가침 중인 상대국에게만 가능합니다.'
|
||||
),
|
||||
allowDiplomacyBetweenStatus([DIPLOMACY_NON_AGGRESSION], '불가침 중인 상대국에게만 가능합니다.'),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -74,14 +63,11 @@ export class ActionDefinition<
|
||||
): GeneralActionOutcome<TriggerState> {
|
||||
return {
|
||||
effects: [
|
||||
createLogEffect(
|
||||
`${ACTION_NAME}을 준비했습니다. (국가 ${args.destNationId})`,
|
||||
{
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.MONTH,
|
||||
}
|
||||
),
|
||||
createLogEffect(`${ACTION_NAME}을 준비했습니다. (국가 ${args.destNationId})`, {
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.MONTH,
|
||||
}),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,10 +9,7 @@ import {
|
||||
suppliedCity,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type {
|
||||
GeneralActionOutcome,
|
||||
GeneralActionResolveContext,
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
import { createDiplomacyPatchEffect, createLogEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
@@ -36,7 +33,7 @@ const parseNationId = (raw: unknown): number | null => {
|
||||
};
|
||||
|
||||
export class ActionDefinition<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionDefinition<TriggerState, DeclareWarArgs> {
|
||||
public readonly key = 'che_선전포고';
|
||||
public readonly name = ACTION_NAME;
|
||||
@@ -73,14 +70,11 @@ export class ActionDefinition<
|
||||
if (nationId === undefined || nationId <= 0) {
|
||||
return {
|
||||
effects: [
|
||||
createLogEffect(
|
||||
`${ACTION_NAME}을 준비했지만 국가 정보가 없습니다.`,
|
||||
{
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.MONTH,
|
||||
}
|
||||
),
|
||||
createLogEffect(`${ACTION_NAME}을 준비했지만 국가 정보가 없습니다.`, {
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.MONTH,
|
||||
}),
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -94,14 +88,11 @@ export class ActionDefinition<
|
||||
state: DIPLOMACY_DECLARE,
|
||||
term: DECLARE_TERM,
|
||||
}),
|
||||
createLogEffect(
|
||||
`${ACTION_NAME}을 실행했습니다. (국가 ${args.destNationId})`,
|
||||
{
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.MONTH,
|
||||
}
|
||||
),
|
||||
createLogEffect(`${ACTION_NAME}을 실행했습니다. (국가 ${args.destNationId})`, {
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.MONTH,
|
||||
}),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import type {
|
||||
City,
|
||||
General,
|
||||
GeneralTriggerState,
|
||||
Nation,
|
||||
} from '@sammo-ts/logic/domain/entities.js';
|
||||
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 {
|
||||
allowDiplomacyBetweenStatus,
|
||||
@@ -13,10 +8,7 @@ import {
|
||||
notOccupiedDestCity,
|
||||
occupiedCity,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import {
|
||||
GeneralActionPipeline,
|
||||
type GeneralActionModule,
|
||||
} from '@sammo-ts/logic/triggers/general-action.js';
|
||||
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type {
|
||||
GeneralActionEffect,
|
||||
@@ -36,7 +28,7 @@ export interface FloodArgs {
|
||||
}
|
||||
|
||||
export interface FloodResolveContext<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> extends GeneralActionResolveContext<TriggerState> {
|
||||
destCity: City;
|
||||
destNation: Nation | null;
|
||||
@@ -59,9 +51,7 @@ const parseCityId = (raw: unknown): number | null => {
|
||||
};
|
||||
|
||||
// 수몰 쿨타임 계산을 담당한다.
|
||||
export class CommandResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> {
|
||||
export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
||||
|
||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>) {
|
||||
@@ -69,20 +59,13 @@ export class CommandResolver<
|
||||
}
|
||||
|
||||
getGlobalDelay(context: FloodResolveContext<TriggerState>): number {
|
||||
return Math.round(
|
||||
this.pipeline.onCalcStrategic(
|
||||
context,
|
||||
ACTION_NAME,
|
||||
'globalDelay',
|
||||
DEFAULT_GLOBAL_DELAY
|
||||
)
|
||||
);
|
||||
return Math.round(this.pipeline.onCalcStrategic(context, ACTION_NAME, 'globalDelay', DEFAULT_GLOBAL_DELAY));
|
||||
}
|
||||
}
|
||||
|
||||
// 수몰 실행 결과를 계산한다.
|
||||
export class ActionResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionResolver<TriggerState, FloodArgs> {
|
||||
readonly key = 'che_수몰';
|
||||
private readonly command: CommandResolver<TriggerState>;
|
||||
@@ -91,10 +74,7 @@ export class ActionResolver<
|
||||
this.command = new CommandResolver(modules);
|
||||
}
|
||||
|
||||
resolve(
|
||||
context: FloodResolveContext<TriggerState>,
|
||||
_args: FloodArgs
|
||||
): GeneralActionOutcome<TriggerState> {
|
||||
resolve(context: FloodResolveContext<TriggerState>, _args: FloodArgs): GeneralActionOutcome<TriggerState> {
|
||||
void _args;
|
||||
const { general, nation } = context;
|
||||
const generalName = general.name;
|
||||
@@ -107,13 +87,10 @@ export class ActionResolver<
|
||||
general.dedication += EXP_DED_GAIN;
|
||||
|
||||
context.addLog(`${ACTION_NAME} 발동!`, { format: LogFormat.MONTH });
|
||||
context.addLog(
|
||||
`<G><b>${cityName}</b></>에 <M>${ACTION_NAME}</>을 발동`,
|
||||
{
|
||||
category: LogCategory.HISTORY,
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
}
|
||||
);
|
||||
context.addLog(`<G><b>${cityName}</b></>에 <M>${ACTION_NAME}</>을 발동`, {
|
||||
category: LogCategory.HISTORY,
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
});
|
||||
|
||||
const effects: Array<GeneralActionEffect<TriggerState>> = [];
|
||||
|
||||
@@ -188,12 +165,8 @@ export class ActionResolver<
|
||||
|
||||
// 수몰 실행을 위한 정의/제약을 구성한다.
|
||||
export class ActionDefinition<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> implements GeneralActionDefinition<
|
||||
TriggerState,
|
||||
FloodArgs,
|
||||
FloodResolveContext<TriggerState>
|
||||
> {
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionDefinition<TriggerState, FloodArgs, FloodResolveContext<TriggerState>> {
|
||||
public readonly key = 'che_수몰';
|
||||
public readonly name = ACTION_NAME;
|
||||
private readonly resolver: ActionResolver<TriggerState>;
|
||||
@@ -211,10 +184,7 @@ export class ActionDefinition<
|
||||
return { destCityId };
|
||||
}
|
||||
|
||||
buildConstraints(
|
||||
_ctx: ConstraintContext,
|
||||
_args: FloodArgs
|
||||
): Constraint[] {
|
||||
buildConstraints(_ctx: ConstraintContext, _args: FloodArgs): Constraint[] {
|
||||
void _ctx;
|
||||
void _args;
|
||||
return [
|
||||
@@ -227,10 +197,7 @@ export class ActionDefinition<
|
||||
];
|
||||
}
|
||||
|
||||
resolve(
|
||||
context: FloodResolveContext<TriggerState>,
|
||||
args: FloodArgs
|
||||
): GeneralActionOutcome<TriggerState> {
|
||||
resolve(context: FloodResolveContext<TriggerState>, args: FloodArgs): GeneralActionOutcome<TriggerState> {
|
||||
return this.resolver.resolve(context, args);
|
||||
}
|
||||
}
|
||||
@@ -251,12 +218,8 @@ export const actionContextBuilder: ActionContextBuilder = (base, options) => {
|
||||
}
|
||||
const destNation = worldRef.getNationById(destCity.nationId);
|
||||
const generals = worldRef.listGenerals();
|
||||
const friendlyGenerals = generals.filter(
|
||||
(general) => general.nationId === base.general.nationId
|
||||
);
|
||||
const destNationGenerals = generals.filter(
|
||||
(general) => general.nationId === destCity.nationId
|
||||
);
|
||||
const friendlyGenerals = generals.filter((general) => general.nationId === base.general.nationId);
|
||||
const destNationGenerals = generals.filter((general) => general.nationId === destCity.nationId);
|
||||
return {
|
||||
...base,
|
||||
destCity,
|
||||
@@ -271,6 +234,5 @@ export const commandSpec: NationTurnCommandSpec = {
|
||||
category: '전략',
|
||||
reqArg: true,
|
||||
args: { destCityId: 0 },
|
||||
createDefinition: (env: TurnCommandEnv) =>
|
||||
new ActionDefinition(env.generalActionModules ?? []),
|
||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.generalActionModules ?? []),
|
||||
};
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
import type { RandomGenerator } from '@sammo-ts/common';
|
||||
import type {
|
||||
GeneralTriggerState,
|
||||
StatBlock,
|
||||
TriggerValue,
|
||||
} from '@sammo-ts/logic/domain/entities.js';
|
||||
import type {
|
||||
Constraint,
|
||||
ConstraintContext,
|
||||
} from '@sammo-ts/logic/constraints/types.js';
|
||||
import type { GeneralTriggerState, StatBlock, TriggerValue } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import {
|
||||
availableStrategicCommand,
|
||||
beChief,
|
||||
@@ -15,10 +8,7 @@ import {
|
||||
notOpeningPart,
|
||||
occupiedCity,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import {
|
||||
GeneralActionPipeline,
|
||||
type GeneralActionModule,
|
||||
} from '@sammo-ts/logic/triggers/general-action.js';
|
||||
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type {
|
||||
GeneralActionEffect,
|
||||
@@ -26,9 +16,7 @@ import type {
|
||||
GeneralActionResolveContext,
|
||||
GeneralActionResolver,
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
import {
|
||||
createGeneralAddEffect,
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
import { createGeneralAddEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||
import { buildRecruitmentGeneral } from '@sammo-ts/logic/actions/turn/general/recruitment.js';
|
||||
import { JosaUtil } from '@sammo-ts/common';
|
||||
@@ -55,7 +43,7 @@ export interface VolunteerRecruitCandidate {
|
||||
}
|
||||
|
||||
export interface VolunteerRecruitResolveContext<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> extends GeneralActionResolveContext<TriggerState> {
|
||||
currentYear: number;
|
||||
startYear: number;
|
||||
@@ -83,10 +71,7 @@ export interface VolunteerRecruitEnvironment {
|
||||
killTurnMin?: number;
|
||||
killTurnMax?: number;
|
||||
decorateName?: (name: string, npcState: number) => string;
|
||||
pickCandidate?: (
|
||||
context: VolunteerRecruitResolveContext,
|
||||
rng: RandomGenerator
|
||||
) => VolunteerRecruitCandidate | null;
|
||||
pickCandidate?: (context: VolunteerRecruitResolveContext, rng: RandomGenerator) => VolunteerRecruitCandidate | null;
|
||||
buildStats?: (
|
||||
context: VolunteerRecruitResolveContext,
|
||||
rng: RandomGenerator,
|
||||
@@ -117,19 +102,12 @@ const addMetaValue = (
|
||||
meta[key] = value;
|
||||
};
|
||||
|
||||
const readMetaNumber = (
|
||||
meta: Record<string, TriggerValue>,
|
||||
key: string
|
||||
): number | null => {
|
||||
const readMetaNumber = (meta: Record<string, TriggerValue>, key: string): number | null => {
|
||||
const value = meta[key];
|
||||
return typeof value === 'number' ? value : null;
|
||||
};
|
||||
|
||||
const randomRangeInt = (
|
||||
rng: RandomGenerator,
|
||||
min: number,
|
||||
max: number
|
||||
): number => rng.nextInt(min, max + 1);
|
||||
const randomRangeInt = (rng: RandomGenerator, min: number, max: number): number => rng.nextInt(min, max + 1);
|
||||
|
||||
const resolveRelYear = (ctx: ConstraintContext): number => {
|
||||
const relYear = ctx.env.relYear;
|
||||
@@ -173,8 +151,7 @@ const resolveStats = (
|
||||
if (env.buildStats) {
|
||||
return env.buildStats(context, rng, candidate);
|
||||
}
|
||||
const fallback =
|
||||
context.nationAverageStats ?? context.general.stats;
|
||||
const fallback = context.nationAverageStats ?? context.general.stats;
|
||||
return {
|
||||
leadership: candidate.stats?.leadership ?? fallback.leadership,
|
||||
strength: candidate.stats?.strength ?? fallback.strength,
|
||||
@@ -183,9 +160,7 @@ const resolveStats = (
|
||||
};
|
||||
|
||||
// 의병모집 쿨타임/인원 계산을 제공한다.
|
||||
export class CommandResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> {
|
||||
export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
||||
private readonly env: VolunteerRecruitEnvironment;
|
||||
|
||||
@@ -197,34 +172,15 @@ export class CommandResolver<
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
getPostDelay(
|
||||
context: VolunteerRecruitResolveContext<TriggerState>,
|
||||
gennum: number
|
||||
): number {
|
||||
getPostDelay(context: VolunteerRecruitResolveContext<TriggerState>, gennum: number): number {
|
||||
const fitted = Math.max(gennum, this.env.initialNationGenLimit);
|
||||
const base = Math.round(Math.sqrt(fitted * 10) * 10);
|
||||
return Math.round(
|
||||
this.pipeline.onCalcStrategic(
|
||||
context,
|
||||
ACTION_NAME,
|
||||
'delay',
|
||||
base
|
||||
)
|
||||
);
|
||||
return Math.round(this.pipeline.onCalcStrategic(context, ACTION_NAME, 'delay', base));
|
||||
}
|
||||
|
||||
getGlobalDelay(
|
||||
context: VolunteerRecruitResolveContext<TriggerState>
|
||||
): number {
|
||||
getGlobalDelay(context: VolunteerRecruitResolveContext<TriggerState>): number {
|
||||
const base = this.env.globalDelayBase ?? DEFAULT_GLOBAL_DELAY;
|
||||
return Math.round(
|
||||
this.pipeline.onCalcStrategic(
|
||||
context,
|
||||
ACTION_NAME,
|
||||
'globalDelay',
|
||||
base
|
||||
)
|
||||
);
|
||||
return Math.round(this.pipeline.onCalcStrategic(context, ACTION_NAME, 'globalDelay', base));
|
||||
}
|
||||
|
||||
getCreateCount(avgNationGenCount: number): number {
|
||||
@@ -236,7 +192,7 @@ export class CommandResolver<
|
||||
|
||||
// 의병모집 실행 결과를 계산한다.
|
||||
export class ActionResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionResolver<TriggerState, VolunteerRecruitArgs> {
|
||||
readonly key = 'che_의병모집';
|
||||
private readonly env: VolunteerRecruitEnvironment;
|
||||
@@ -275,35 +231,24 @@ export class ActionResolver<
|
||||
const generalName = general.name;
|
||||
const generalJosa = JosaUtil.pick(generalName, '이');
|
||||
const actionJosa = JosaUtil.pick(ACTION_NAME, '을');
|
||||
context.addLog(
|
||||
`<Y>${generalName}</>${generalJosa} <M>${ACTION_NAME}</>${actionJosa} 발동했습니다.`,
|
||||
{
|
||||
scope: LogScope.NATION,
|
||||
category: LogCategory.HISTORY,
|
||||
nationId: nation.id,
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
}
|
||||
);
|
||||
context.addLog(`<Y>${generalName}</>${generalJosa} <M>${ACTION_NAME}</>${actionJosa} 발동했습니다.`, {
|
||||
scope: LogScope.NATION,
|
||||
category: LogCategory.HISTORY,
|
||||
nationId: nation.id,
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
});
|
||||
}
|
||||
|
||||
const avgNationGen =
|
||||
Number.isFinite(context.averageNationGeneralCount)
|
||||
? context.averageNationGeneralCount
|
||||
: 0;
|
||||
const createCount = Math.max(
|
||||
0,
|
||||
this.command.getCreateCount(avgNationGen)
|
||||
);
|
||||
const gennumValue = nation
|
||||
? readMetaNumber(nation.meta, 'gennum')
|
||||
: null;
|
||||
const avgNationGen = Number.isFinite(context.averageNationGeneralCount) ? context.averageNationGeneralCount : 0;
|
||||
const createCount = Math.max(0, this.command.getCreateCount(avgNationGen));
|
||||
const gennumValue = nation ? readMetaNumber(nation.meta, 'gennum') : null;
|
||||
const currentGennum = gennumValue ?? 0;
|
||||
const nextGennum = currentGennum + createCount;
|
||||
const globalDelay = this.command.getGlobalDelay(context);
|
||||
|
||||
if (nation) {
|
||||
nation.meta = {
|
||||
...nation.meta as object,
|
||||
...(nation.meta as object),
|
||||
gennum: nextGennum,
|
||||
strategic_cmd_limit: globalDelay,
|
||||
};
|
||||
@@ -318,20 +263,11 @@ export class ActionResolver<
|
||||
|
||||
for (let idx = 0; idx < createCount; idx += 1) {
|
||||
const newGeneralId = context.createGeneralId();
|
||||
const candidate =
|
||||
resolveCandidate(context, context.rng, this.env) ??
|
||||
{ name: `NPC_${newGeneralId}` };
|
||||
const name = this.env.decorateName
|
||||
? this.env.decorateName(candidate.name, NPC_TYPE)
|
||||
: candidate.name;
|
||||
const candidate = resolveCandidate(context, context.rng, this.env) ?? { name: `NPC_${newGeneralId}` };
|
||||
const name = this.env.decorateName ? this.env.decorateName(candidate.name, NPC_TYPE) : candidate.name;
|
||||
const birthYear = context.currentYear - baseAge;
|
||||
const deathYear = context.currentYear + deathYears;
|
||||
const stats = resolveStats(
|
||||
context,
|
||||
context.rng,
|
||||
this.env,
|
||||
candidate
|
||||
);
|
||||
const stats = resolveStats(context, context.rng, this.env, candidate);
|
||||
const meta: Record<string, TriggerValue> = {
|
||||
npcType: NPC_TYPE,
|
||||
crewTypeId: this.env.defaultCrewTypeId,
|
||||
@@ -342,11 +278,7 @@ export class ActionResolver<
|
||||
addMetaValue(meta, 'deathYear', deathYear);
|
||||
addMetaValue(meta, 'specAge', DEFAULT_SPEC_AGE);
|
||||
addMetaValue(meta, 'specAge2', DEFAULT_SPEC_AGE);
|
||||
addMetaValue(
|
||||
meta,
|
||||
'killturn',
|
||||
randomRangeInt(context.rng, killTurnMin, killTurnMax)
|
||||
);
|
||||
addMetaValue(meta, 'killturn', randomRangeInt(context.rng, killTurnMin, killTurnMax));
|
||||
addMetaValue(meta, 'text', candidate.text ?? null);
|
||||
|
||||
const newGeneral = buildRecruitmentGeneral<TriggerState>({
|
||||
@@ -378,12 +310,8 @@ export class ActionResolver<
|
||||
}
|
||||
|
||||
export class ActionDefinition<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> implements GeneralActionDefinition<
|
||||
TriggerState,
|
||||
VolunteerRecruitArgs,
|
||||
VolunteerRecruitResolveContext<TriggerState>
|
||||
> {
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionDefinition<TriggerState, VolunteerRecruitArgs, VolunteerRecruitResolveContext<TriggerState>> {
|
||||
public readonly key = 'che_의병모집';
|
||||
public readonly name = ACTION_NAME;
|
||||
private readonly resolver: ActionResolver<TriggerState>;
|
||||
@@ -402,10 +330,7 @@ export class ActionDefinition<
|
||||
return {};
|
||||
}
|
||||
|
||||
buildConstraints(
|
||||
ctx: ConstraintContext,
|
||||
_args: VolunteerRecruitArgs
|
||||
): Constraint[] {
|
||||
buildConstraints(ctx: ConstraintContext, _args: VolunteerRecruitArgs): Constraint[] {
|
||||
void _args;
|
||||
const relYear = resolveRelYear(ctx);
|
||||
return [
|
||||
@@ -427,17 +352,12 @@ export class ActionDefinition<
|
||||
|
||||
// 예약 턴 실행에 필요한 국가 평균 정보를 구성한다.
|
||||
export const actionContextBuilder: ActionContextBuilder = (base, options) => {
|
||||
const nationSummary = buildNationSummary(
|
||||
options.worldRef,
|
||||
base.general.nationId
|
||||
);
|
||||
const nationSummary = buildNationSummary(options.worldRef, base.general.nationId);
|
||||
return {
|
||||
...base,
|
||||
currentYear: options.world.currentYear,
|
||||
startYear: resolveStartYear(options.world, options.scenarioMeta),
|
||||
averageNationGeneralCount: buildAverageNationGeneralCount(
|
||||
options.worldRef
|
||||
),
|
||||
averageNationGeneralCount: buildAverageNationGeneralCount(options.worldRef),
|
||||
nationAverageStats: nationSummary.averageStats,
|
||||
nationAverageExperience: nationSummary.averageExperience,
|
||||
nationAverageDedication: nationSummary.averageDedication,
|
||||
@@ -450,6 +370,5 @@ export const commandSpec: NationTurnCommandSpec = {
|
||||
category: '전략',
|
||||
reqArg: false,
|
||||
args: {},
|
||||
createDefinition: (env: TurnCommandEnv) =>
|
||||
new ActionDefinition(env.generalActionModules ?? [], env),
|
||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.generalActionModules ?? [], env),
|
||||
};
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import type {
|
||||
General,
|
||||
GeneralTriggerState,
|
||||
Nation,
|
||||
} from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { General, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import {
|
||||
allowDiplomacyBetweenStatus,
|
||||
@@ -11,10 +7,7 @@ import {
|
||||
existsDestNation,
|
||||
occupiedCity,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import {
|
||||
GeneralActionPipeline,
|
||||
type GeneralActionModule,
|
||||
} from '@sammo-ts/logic/triggers/general-action.js';
|
||||
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type {
|
||||
GeneralActionEffect,
|
||||
@@ -22,17 +15,11 @@ import type {
|
||||
GeneralActionResolveContext,
|
||||
GeneralActionResolver,
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
import {
|
||||
createDiplomacyPatchEffect,
|
||||
createLogEffect,
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
import { createDiplomacyPatchEffect, createLogEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import {
|
||||
buildDefaultDiplomacy,
|
||||
DIPLOMACY_STATE,
|
||||
} from '../../../diplomacy/index.js';
|
||||
import { buildDefaultDiplomacy, DIPLOMACY_STATE } from '../../../diplomacy/index.js';
|
||||
import { JosaUtil } from '@sammo-ts/common';
|
||||
import type { NationTurnCommandSpec } from './index.js';
|
||||
|
||||
@@ -41,7 +28,7 @@ export interface DegradeRelationsArgs {
|
||||
}
|
||||
|
||||
export interface DegradeRelationsResolveContext<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> extends GeneralActionResolveContext<TriggerState> {
|
||||
destNation: Nation;
|
||||
diplomacy: { state: number; term: number };
|
||||
@@ -63,13 +50,10 @@ const parseNationId = (raw: unknown): number | null => {
|
||||
return value > 0 ? value : null;
|
||||
};
|
||||
|
||||
const resolveNextTerm = (state: number, term: number): number =>
|
||||
state === DIPLOMACY_STATE.WAR ? 3 : term + 3;
|
||||
const resolveNextTerm = (state: number, term: number): number => (state === DIPLOMACY_STATE.WAR ? 3 : term + 3);
|
||||
|
||||
// 이호경식 쿨타임 계산을 담당한다.
|
||||
export class CommandResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> {
|
||||
export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
||||
|
||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>) {
|
||||
@@ -77,20 +61,13 @@ export class CommandResolver<
|
||||
}
|
||||
|
||||
getGlobalDelay(context: DegradeRelationsResolveContext<TriggerState>): number {
|
||||
return Math.round(
|
||||
this.pipeline.onCalcStrategic(
|
||||
context,
|
||||
ACTION_NAME,
|
||||
'globalDelay',
|
||||
DEFAULT_GLOBAL_DELAY
|
||||
)
|
||||
);
|
||||
return Math.round(this.pipeline.onCalcStrategic(context, ACTION_NAME, 'globalDelay', DEFAULT_GLOBAL_DELAY));
|
||||
}
|
||||
}
|
||||
|
||||
// 이호경식 실행 결과를 계산한다.
|
||||
export class ActionResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionResolver<TriggerState, DegradeRelationsArgs> {
|
||||
readonly key = 'che_이호경식';
|
||||
private readonly command: CommandResolver<TriggerState>;
|
||||
@@ -117,37 +94,20 @@ export class ActionResolver<
|
||||
general.dedication += EXP_DED_GAIN;
|
||||
|
||||
context.addLog(`${ACTION_NAME} 발동!`, { format: LogFormat.MONTH });
|
||||
context.addLog(
|
||||
`<D><b>${destNationName}</b></>에 <M>${ACTION_NAME}</>${actionJosa} 발동`,
|
||||
{
|
||||
category: LogCategory.HISTORY,
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
}
|
||||
);
|
||||
context.addLog(`<D><b>${destNationName}</b></>에 <M>${ACTION_NAME}</>${actionJosa} 발동`, {
|
||||
category: LogCategory.HISTORY,
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
});
|
||||
|
||||
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
||||
createDiplomacyPatchEffect(
|
||||
general.nationId,
|
||||
context.destNation.id,
|
||||
{
|
||||
state: DIPLOMACY_STATE.DECLARATION,
|
||||
term: resolveNextTerm(
|
||||
context.diplomacy.state,
|
||||
context.diplomacy.term
|
||||
),
|
||||
}
|
||||
),
|
||||
createDiplomacyPatchEffect(
|
||||
context.destNation.id,
|
||||
general.nationId,
|
||||
{
|
||||
state: DIPLOMACY_STATE.DECLARATION,
|
||||
term: resolveNextTerm(
|
||||
context.reverseDiplomacy.state,
|
||||
context.reverseDiplomacy.term
|
||||
),
|
||||
}
|
||||
),
|
||||
createDiplomacyPatchEffect(general.nationId, context.destNation.id, {
|
||||
state: DIPLOMACY_STATE.DECLARATION,
|
||||
term: resolveNextTerm(context.diplomacy.state, context.diplomacy.term),
|
||||
}),
|
||||
createDiplomacyPatchEffect(context.destNation.id, general.nationId, {
|
||||
state: DIPLOMACY_STATE.DECLARATION,
|
||||
term: resolveNextTerm(context.reverseDiplomacy.state, context.reverseDiplomacy.term),
|
||||
}),
|
||||
];
|
||||
|
||||
for (const target of context.friendlyGenerals) {
|
||||
@@ -209,12 +169,8 @@ export class ActionResolver<
|
||||
|
||||
// 이호경식 실행을 위한 정의/제약을 구성한다.
|
||||
export class ActionDefinition<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> implements GeneralActionDefinition<
|
||||
TriggerState,
|
||||
DegradeRelationsArgs,
|
||||
DegradeRelationsResolveContext<TriggerState>
|
||||
> {
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionDefinition<TriggerState, DegradeRelationsArgs, DegradeRelationsResolveContext<TriggerState>> {
|
||||
public readonly key = 'che_이호경식';
|
||||
public readonly name = ACTION_NAME;
|
||||
private readonly resolver: ActionResolver<TriggerState>;
|
||||
@@ -232,20 +188,14 @@ export class ActionDefinition<
|
||||
return { destNationId };
|
||||
}
|
||||
|
||||
buildConstraints(
|
||||
_ctx: ConstraintContext,
|
||||
_args: DegradeRelationsArgs
|
||||
): Constraint[] {
|
||||
buildConstraints(_ctx: ConstraintContext, _args: DegradeRelationsArgs): Constraint[] {
|
||||
void _ctx;
|
||||
void _args;
|
||||
return [
|
||||
occupiedCity(),
|
||||
beChief(),
|
||||
existsDestNation(),
|
||||
allowDiplomacyBetweenStatus(
|
||||
[0, 1],
|
||||
'선포, 전쟁중인 상대국에게만 가능합니다.'
|
||||
),
|
||||
allowDiplomacyBetweenStatus([0, 1], '선포, 전쟁중인 상대국에게만 가능합니다.'),
|
||||
availableStrategicCommand(),
|
||||
];
|
||||
}
|
||||
@@ -279,12 +229,8 @@ export const actionContextBuilder: ActionContextBuilder = (base, options) => {
|
||||
worldRef.getDiplomacyEntry(destNationId, base.general.nationId) ??
|
||||
buildDefaultDiplomacy(destNationId, base.general.nationId);
|
||||
const generals = worldRef.listGenerals();
|
||||
const friendlyGenerals = generals.filter(
|
||||
(general) => general.nationId === base.general.nationId
|
||||
);
|
||||
const destNationGenerals = generals.filter(
|
||||
(general) => general.nationId === destNationId
|
||||
);
|
||||
const friendlyGenerals = generals.filter((general) => general.nationId === base.general.nationId);
|
||||
const destNationGenerals = generals.filter((general) => general.nationId === destNationId);
|
||||
return {
|
||||
...base,
|
||||
destNation,
|
||||
@@ -300,6 +246,5 @@ export const commandSpec: NationTurnCommandSpec = {
|
||||
category: '외교',
|
||||
reqArg: true,
|
||||
args: { destNationId: 0 },
|
||||
createDefinition: (env: TurnCommandEnv) =>
|
||||
new ActionDefinition(env.generalActionModules ?? []),
|
||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.generalActionModules ?? []),
|
||||
};
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
import type {
|
||||
General,
|
||||
GeneralTriggerState,
|
||||
Nation,
|
||||
} from '@sammo-ts/logic/domain/entities.js';
|
||||
import type {
|
||||
Constraint,
|
||||
ConstraintContext,
|
||||
RequirementKey,
|
||||
StateView,
|
||||
} from '@sammo-ts/logic/constraints/types.js';
|
||||
import type { General, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext, RequirementKey, StateView } from '@sammo-ts/logic/constraints/types.js';
|
||||
import {
|
||||
alwaysFail,
|
||||
beChief,
|
||||
@@ -27,11 +18,7 @@ import type {
|
||||
GeneralActionResolveContext,
|
||||
GeneralActionResolver,
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
import {
|
||||
createGeneralPatchEffect,
|
||||
createLogEffect,
|
||||
createNationPatchEffect,
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
import { createGeneralPatchEffect, createLogEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import type { NationTurnCommandSpec } from './index.js';
|
||||
@@ -46,7 +33,7 @@ export interface AwardArgs {
|
||||
}
|
||||
|
||||
export interface AwardResolveContext<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> extends GeneralActionResolveContext<TriggerState> {
|
||||
destGeneral: General<TriggerState>;
|
||||
}
|
||||
@@ -63,16 +50,11 @@ const ACTION_NAME = '포상';
|
||||
const DEFAULT_MIN_AMOUNT = 100;
|
||||
const DEFAULT_AMOUNT_UNIT = 100;
|
||||
|
||||
const roundToUnit = (value: number, unit: number): number =>
|
||||
Math.round(value / unit) * unit;
|
||||
const roundToUnit = (value: number, unit: number): number => Math.round(value / unit) * unit;
|
||||
|
||||
const formatNumber = (value: number): string =>
|
||||
value.toLocaleString('en-US');
|
||||
const formatNumber = (value: number): string => value.toLocaleString('en-US');
|
||||
|
||||
const normalizeAmount = (
|
||||
amount: number,
|
||||
env: AwardEnvironment
|
||||
): number => {
|
||||
const normalizeAmount = (amount: number, env: AwardEnvironment): number => {
|
||||
const unit = env.amountUnit ?? DEFAULT_AMOUNT_UNIT;
|
||||
const min = env.minAmount ?? DEFAULT_MIN_AMOUNT;
|
||||
const max = env.maxAmount;
|
||||
@@ -108,7 +90,7 @@ export class CommandResolver {
|
||||
|
||||
// 포상 결과를 계산한다.
|
||||
export class ActionResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionResolver<TriggerState, AwardArgs> {
|
||||
readonly key = 'che_포상';
|
||||
private readonly env: AwardEnvironment;
|
||||
@@ -119,10 +101,7 @@ export class ActionResolver<
|
||||
this.command = new CommandResolver(env);
|
||||
}
|
||||
|
||||
resolve(
|
||||
context: AwardResolveContext<TriggerState>,
|
||||
args: AwardArgs
|
||||
): GeneralActionOutcome<TriggerState> {
|
||||
resolve(context: AwardResolveContext<TriggerState>, args: AwardArgs): GeneralActionOutcome<TriggerState> {
|
||||
const nation = context.nation;
|
||||
if (!nation) {
|
||||
return { effects: [] };
|
||||
@@ -130,11 +109,7 @@ export class ActionResolver<
|
||||
const { key, label } = resolveNationResource(nation, args.isGold);
|
||||
const base = args.isGold ? this.env.baseGold : this.env.baseRice;
|
||||
const available = Math.max(nation[key] - base, 0);
|
||||
const amount = clamp(
|
||||
this.command.normalizeAmount(args.amount),
|
||||
0,
|
||||
available
|
||||
);
|
||||
const amount = clamp(this.command.normalizeAmount(args.amount), 0, available);
|
||||
if (amount <= 0) {
|
||||
return { effects: [] };
|
||||
}
|
||||
@@ -142,37 +117,32 @@ export class ActionResolver<
|
||||
const amountText = formatNumber(amount);
|
||||
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
||||
createGeneralPatchEffect(
|
||||
{ [key]: context.destGeneral[key] + amount } as Partial<
|
||||
General<TriggerState>
|
||||
>,
|
||||
{ [key]: context.destGeneral[key] + amount } as Partial<General<TriggerState>>,
|
||||
context.destGeneral.id
|
||||
),
|
||||
createNationPatchEffect({
|
||||
[key]: nation[key] - amount,
|
||||
} as Partial<Nation>, nation.id),
|
||||
createNationPatchEffect(
|
||||
{
|
||||
[key]: nation[key] - amount,
|
||||
} as Partial<Nation>,
|
||||
nation.id
|
||||
),
|
||||
];
|
||||
|
||||
const amountJosa = JosaUtil.pick(amountText, '을');
|
||||
effects.push(
|
||||
createLogEffect(
|
||||
`${label} ${amountText}${amountJosa} 포상으로 받았습니다.`,
|
||||
{
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
generalId: context.destGeneral.id,
|
||||
format: LogFormat.PLAIN,
|
||||
}
|
||||
)
|
||||
createLogEffect(`${label} ${amountText}${amountJosa} 포상으로 받았습니다.`, {
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
generalId: context.destGeneral.id,
|
||||
format: LogFormat.PLAIN,
|
||||
})
|
||||
);
|
||||
effects.push(
|
||||
createLogEffect(
|
||||
`<Y>${context.destGeneral.name}</>에게 ${label} ${amountText}${amountJosa} 수여했습니다.`,
|
||||
{
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.MONTH,
|
||||
}
|
||||
)
|
||||
createLogEffect(`<Y>${context.destGeneral.name}</>에게 ${label} ${amountText}${amountJosa} 수여했습니다.`, {
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.MONTH,
|
||||
})
|
||||
);
|
||||
|
||||
return { effects };
|
||||
@@ -180,12 +150,8 @@ export class ActionResolver<
|
||||
}
|
||||
|
||||
export class ActionDefinition<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> implements GeneralActionDefinition<
|
||||
TriggerState,
|
||||
AwardArgs,
|
||||
AwardResolveContext<TriggerState>
|
||||
> {
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionDefinition<TriggerState, AwardArgs, AwardResolveContext<TriggerState>> {
|
||||
public readonly key = 'che_포상';
|
||||
public readonly name = ACTION_NAME;
|
||||
private readonly command: CommandResolver;
|
||||
@@ -225,10 +191,7 @@ export class ActionDefinition<
|
||||
};
|
||||
}
|
||||
|
||||
buildConstraints(
|
||||
ctx: ConstraintContext,
|
||||
args: AwardArgs
|
||||
): Constraint[] {
|
||||
buildConstraints(ctx: ConstraintContext, args: AwardArgs): Constraint[] {
|
||||
const requirements: RequirementKey[] = [];
|
||||
if (ctx.cityId !== undefined) {
|
||||
requirements.push({ kind: 'city', id: ctx.cityId });
|
||||
@@ -262,10 +225,7 @@ export class ActionDefinition<
|
||||
];
|
||||
}
|
||||
|
||||
resolve(
|
||||
context: AwardResolveContext<TriggerState>,
|
||||
args: AwardArgs
|
||||
): GeneralActionOutcome<TriggerState> {
|
||||
resolve(context: AwardResolveContext<TriggerState>, args: AwardArgs): GeneralActionOutcome<TriggerState> {
|
||||
return this.resolver.resolve(context, args);
|
||||
}
|
||||
}
|
||||
@@ -293,9 +253,7 @@ export const commandSpec: NationTurnCommandSpec = {
|
||||
args: { isGold: true, amount: 1, destGeneralId: 0 },
|
||||
createDefinition: (env: TurnCommandEnv) => {
|
||||
const maxAmount =
|
||||
env.maxResourceActionAmount > 0
|
||||
? env.maxResourceActionAmount
|
||||
: Math.max(env.baseGold, env.baseRice, 1000);
|
||||
env.maxResourceActionAmount > 0 ? env.maxResourceActionAmount : Math.max(env.baseGold, env.baseRice, 1000);
|
||||
return new ActionDefinition({
|
||||
baseGold: env.baseGold,
|
||||
baseRice: env.baseRice,
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import type {
|
||||
General,
|
||||
GeneralTriggerState,
|
||||
} from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { General, GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import {
|
||||
allowDiplomacyStatus,
|
||||
@@ -9,10 +6,7 @@ import {
|
||||
beChief,
|
||||
occupiedCity,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import {
|
||||
GeneralActionPipeline,
|
||||
type GeneralActionModule,
|
||||
} from '@sammo-ts/logic/triggers/general-action.js';
|
||||
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type {
|
||||
GeneralActionEffect,
|
||||
@@ -30,7 +24,7 @@ import type { NationTurnCommandSpec } from './index.js';
|
||||
export interface DesperateFightArgs {}
|
||||
|
||||
export interface DesperateFightResolveContext<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> extends GeneralActionResolveContext<TriggerState> {
|
||||
nationGenerals: Array<General<TriggerState>>;
|
||||
}
|
||||
@@ -43,9 +37,7 @@ const TRAIN_CAP = 100;
|
||||
const ATMOS_CAP = 100;
|
||||
|
||||
// 필사즉생 쿨타임 계산을 담당한다.
|
||||
export class CommandResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> {
|
||||
export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
||||
|
||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>) {
|
||||
@@ -53,20 +45,13 @@ export class CommandResolver<
|
||||
}
|
||||
|
||||
getGlobalDelay(context: DesperateFightResolveContext<TriggerState>): number {
|
||||
return Math.round(
|
||||
this.pipeline.onCalcStrategic(
|
||||
context,
|
||||
ACTION_NAME,
|
||||
'globalDelay',
|
||||
DEFAULT_GLOBAL_DELAY
|
||||
)
|
||||
);
|
||||
return Math.round(this.pipeline.onCalcStrategic(context, ACTION_NAME, 'globalDelay', DEFAULT_GLOBAL_DELAY));
|
||||
}
|
||||
}
|
||||
|
||||
// 필사즉생 실행 결과를 계산한다.
|
||||
export class ActionResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionResolver<TriggerState, DesperateFightArgs> {
|
||||
readonly key = 'che_필사즉생';
|
||||
private readonly command: CommandResolver<TriggerState>;
|
||||
@@ -96,9 +81,7 @@ export class ActionResolver<
|
||||
|
||||
const effects: Array<GeneralActionEffect<TriggerState>> = [];
|
||||
|
||||
const updateTrainAtmos = (
|
||||
target: General<TriggerState>
|
||||
): { train: number; atmos: number } | null => {
|
||||
const updateTrainAtmos = (target: General<TriggerState>): { train: number; atmos: number } | null => {
|
||||
const nextTrain = Math.max(target.train, TRAIN_CAP);
|
||||
const nextAtmos = Math.max(target.atmos, ATMOS_CAP);
|
||||
if (nextTrain === target.train && nextAtmos === target.atmos) {
|
||||
@@ -119,9 +102,7 @@ export class ActionResolver<
|
||||
}
|
||||
const patch = updateTrainAtmos(target);
|
||||
if (patch) {
|
||||
effects.push(
|
||||
createGeneralPatchEffect(patch, target.id)
|
||||
);
|
||||
effects.push(createGeneralPatchEffect(patch, target.id));
|
||||
}
|
||||
effects.push(
|
||||
createLogEffect(broadcastMessage, {
|
||||
@@ -155,12 +136,8 @@ export class ActionResolver<
|
||||
|
||||
// 필사즉생 실행을 위한 정의/제약을 구성한다.
|
||||
export class ActionDefinition<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> implements GeneralActionDefinition<
|
||||
TriggerState,
|
||||
DesperateFightArgs,
|
||||
DesperateFightResolveContext<TriggerState>
|
||||
> {
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionDefinition<TriggerState, DesperateFightArgs, DesperateFightResolveContext<TriggerState>> {
|
||||
public readonly key = 'che_필사즉생';
|
||||
public readonly name = ACTION_NAME;
|
||||
private readonly resolver: ActionResolver<TriggerState>;
|
||||
@@ -174,10 +151,7 @@ export class ActionDefinition<
|
||||
return {};
|
||||
}
|
||||
|
||||
buildConstraints(
|
||||
_ctx: ConstraintContext,
|
||||
_args: DesperateFightArgs
|
||||
): Constraint[] {
|
||||
buildConstraints(_ctx: ConstraintContext, _args: DesperateFightArgs): Constraint[] {
|
||||
void _ctx;
|
||||
void _args;
|
||||
return [
|
||||
@@ -202,9 +176,7 @@ export const actionContextBuilder: ActionContextBuilder = (base, options) => {
|
||||
if (!worldRef) {
|
||||
return null;
|
||||
}
|
||||
const nationGenerals = worldRef
|
||||
.listGenerals()
|
||||
.filter((entry) => entry.nationId === base.general.nationId);
|
||||
const nationGenerals = worldRef.listGenerals().filter((entry) => entry.nationId === base.general.nationId);
|
||||
return {
|
||||
...base,
|
||||
nationGenerals,
|
||||
@@ -216,6 +188,5 @@ export const commandSpec: NationTurnCommandSpec = {
|
||||
category: '전략',
|
||||
reqArg: false,
|
||||
args: {},
|
||||
createDefinition: (env: TurnCommandEnv) =>
|
||||
new ActionDefinition(env.generalActionModules ?? []),
|
||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.generalActionModules ?? []),
|
||||
};
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import type {
|
||||
City,
|
||||
General,
|
||||
GeneralTriggerState,
|
||||
Nation,
|
||||
} from '@sammo-ts/logic/domain/entities.js';
|
||||
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 {
|
||||
allowDiplomacyBetweenStatus,
|
||||
@@ -13,10 +8,7 @@ import {
|
||||
notOccupiedDestCity,
|
||||
occupiedCity,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import {
|
||||
GeneralActionPipeline,
|
||||
type GeneralActionModule,
|
||||
} from '@sammo-ts/logic/triggers/general-action.js';
|
||||
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type {
|
||||
GeneralActionEffect,
|
||||
@@ -36,7 +28,7 @@ export interface DeceptionArgs {
|
||||
}
|
||||
|
||||
export interface DeceptionResolveContext<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> extends GeneralActionResolveContext<TriggerState> {
|
||||
destCity: City;
|
||||
destNation: Nation | null;
|
||||
@@ -58,11 +50,7 @@ const parseCityId = (raw: unknown): number | null => {
|
||||
return value > 0 ? value : null;
|
||||
};
|
||||
|
||||
const pickMoveCityId = (
|
||||
rng: GeneralActionResolveContext['rng'],
|
||||
destCityId: number,
|
||||
candidates: City[]
|
||||
): number => {
|
||||
const pickMoveCityId = (rng: GeneralActionResolveContext['rng'], destCityId: number, candidates: City[]): number => {
|
||||
if (candidates.length === 0) {
|
||||
return destCityId;
|
||||
}
|
||||
@@ -76,9 +64,7 @@ const pickMoveCityId = (
|
||||
};
|
||||
|
||||
// 허보 쿨타임 계산을 담당한다.
|
||||
export class CommandResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
> {
|
||||
export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
||||
|
||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>) {
|
||||
@@ -86,20 +72,13 @@ export class CommandResolver<
|
||||
}
|
||||
|
||||
getGlobalDelay(context: DeceptionResolveContext<TriggerState>): number {
|
||||
return Math.round(
|
||||
this.pipeline.onCalcStrategic(
|
||||
context,
|
||||
ACTION_NAME,
|
||||
'globalDelay',
|
||||
DEFAULT_GLOBAL_DELAY
|
||||
)
|
||||
);
|
||||
return Math.round(this.pipeline.onCalcStrategic(context, ACTION_NAME, 'globalDelay', DEFAULT_GLOBAL_DELAY));
|
||||
}
|
||||
}
|
||||
|
||||
// 허보 실행 결과를 계산한다.
|
||||
export class ActionResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionResolver<TriggerState, DeceptionArgs> {
|
||||
readonly key = 'che_허보';
|
||||
private readonly command: CommandResolver<TriggerState>;
|
||||
@@ -108,10 +87,7 @@ export class ActionResolver<
|
||||
this.command = new CommandResolver(modules);
|
||||
}
|
||||
|
||||
resolve(
|
||||
context: DeceptionResolveContext<TriggerState>,
|
||||
_args: DeceptionArgs
|
||||
): GeneralActionOutcome<TriggerState> {
|
||||
resolve(context: DeceptionResolveContext<TriggerState>, _args: DeceptionArgs): GeneralActionOutcome<TriggerState> {
|
||||
void _args;
|
||||
const { general, nation } = context;
|
||||
const generalName = general.name;
|
||||
@@ -124,13 +100,10 @@ export class ActionResolver<
|
||||
general.dedication += EXP_DED_GAIN;
|
||||
|
||||
context.addLog(`${ACTION_NAME} 발동!`, { format: LogFormat.MONTH });
|
||||
context.addLog(
|
||||
`<G><b>${cityName}</b></>에 <M>${ACTION_NAME}</>를 발동`,
|
||||
{
|
||||
category: LogCategory.HISTORY,
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
}
|
||||
);
|
||||
context.addLog(`<G><b>${cityName}</b></>에 <M>${ACTION_NAME}</>를 발동`, {
|
||||
category: LogCategory.HISTORY,
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
});
|
||||
|
||||
const effects: Array<GeneralActionEffect<TriggerState>> = [];
|
||||
|
||||
@@ -149,11 +122,7 @@ export class ActionResolver<
|
||||
}
|
||||
|
||||
for (const target of context.destCityGenerals) {
|
||||
const moveCityId = pickMoveCityId(
|
||||
context.rng,
|
||||
context.destCity.id,
|
||||
context.destNationSupplyCities
|
||||
);
|
||||
const moveCityId = pickMoveCityId(context.rng, context.destCity.id, context.destNationSupplyCities);
|
||||
effects.push(
|
||||
createLogEffect(destBroadcastMessage, {
|
||||
scope: LogScope.GENERAL,
|
||||
@@ -163,12 +132,7 @@ export class ActionResolver<
|
||||
})
|
||||
);
|
||||
if (moveCityId !== target.cityId) {
|
||||
effects.push(
|
||||
createGeneralPatchEffect(
|
||||
{ cityId: moveCityId },
|
||||
target.id
|
||||
)
|
||||
);
|
||||
effects.push(createGeneralPatchEffect({ cityId: moveCityId }, target.id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +172,7 @@ export class ActionResolver<
|
||||
|
||||
// 허보 실행을 위한 정의/제약을 구성한다.
|
||||
export class ActionDefinition<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionDefinition<TriggerState, DeceptionArgs, DeceptionResolveContext<TriggerState>> {
|
||||
public readonly key = 'che_허보';
|
||||
public readonly name = ACTION_NAME;
|
||||
@@ -227,10 +191,7 @@ export class ActionDefinition<
|
||||
return { destCityId };
|
||||
}
|
||||
|
||||
buildConstraints(
|
||||
_ctx: ConstraintContext,
|
||||
_args: DeceptionArgs
|
||||
): Constraint[] {
|
||||
buildConstraints(_ctx: ConstraintContext, _args: DeceptionArgs): Constraint[] {
|
||||
void _ctx;
|
||||
void _args;
|
||||
return [
|
||||
@@ -238,18 +199,12 @@ export class ActionDefinition<
|
||||
beChief(),
|
||||
notNeutralDestCity(),
|
||||
notOccupiedDestCity(),
|
||||
allowDiplomacyBetweenStatus(
|
||||
[0, 1],
|
||||
'선포, 전쟁중인 상대국에게만 가능합니다.'
|
||||
),
|
||||
allowDiplomacyBetweenStatus([0, 1], '선포, 전쟁중인 상대국에게만 가능합니다.'),
|
||||
availableStrategicCommand(),
|
||||
];
|
||||
}
|
||||
|
||||
resolve(
|
||||
context: DeceptionResolveContext<TriggerState>,
|
||||
args: DeceptionArgs
|
||||
): GeneralActionOutcome<TriggerState> {
|
||||
resolve(context: DeceptionResolveContext<TriggerState>, args: DeceptionArgs): GeneralActionOutcome<TriggerState> {
|
||||
return this.resolver.resolve(context, args);
|
||||
}
|
||||
}
|
||||
@@ -271,19 +226,12 @@ export const actionContextBuilder: ActionContextBuilder = (base, options) => {
|
||||
const destNation = worldRef.getNationById(destCity.nationId);
|
||||
const generals = worldRef.listGenerals();
|
||||
const destCityGenerals = generals.filter(
|
||||
(general) =>
|
||||
general.nationId === destCity.nationId &&
|
||||
general.cityId === destCity.id
|
||||
);
|
||||
const friendlyGenerals = generals.filter(
|
||||
(general) => general.nationId === base.general.nationId
|
||||
(general) => general.nationId === destCity.nationId && general.cityId === destCity.id
|
||||
);
|
||||
const friendlyGenerals = generals.filter((general) => general.nationId === base.general.nationId);
|
||||
const destNationSupplyCities = worldRef
|
||||
.listCities()
|
||||
.filter(
|
||||
(city) =>
|
||||
city.nationId === destCity.nationId && city.supplyState > 0
|
||||
);
|
||||
.filter((city) => city.nationId === destCity.nationId && city.supplyState > 0);
|
||||
return {
|
||||
...base,
|
||||
destCity,
|
||||
@@ -299,6 +247,5 @@ export const commandSpec: NationTurnCommandSpec = {
|
||||
category: '전략',
|
||||
reqArg: true,
|
||||
args: { destCityId: 0 },
|
||||
createDefinition: (env: TurnCommandEnv) =>
|
||||
new ActionDefinition(env.generalActionModules ?? []),
|
||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.generalActionModules ?? []),
|
||||
};
|
||||
|
||||
@@ -17,21 +17,15 @@ export const NATION_TURN_COMMAND_KEYS = [
|
||||
'che_급습',
|
||||
] as const;
|
||||
|
||||
export type NationTurnCommandKey =
|
||||
(typeof NATION_TURN_COMMAND_KEYS)[number];
|
||||
export type NationTurnCommandKey = (typeof NATION_TURN_COMMAND_KEYS)[number];
|
||||
|
||||
export type NationTurnCommandSpec =
|
||||
TurnCommandSpecBase<NationTurnCommandKey>;
|
||||
export type NationTurnCommandSpec = TurnCommandSpecBase<NationTurnCommandKey>;
|
||||
|
||||
export type NationTurnCommandModule =
|
||||
TurnCommandModule<NationTurnCommandSpec>;
|
||||
export type NationTurnCommandModule = TurnCommandModule<NationTurnCommandSpec>;
|
||||
|
||||
export type NationTurnCommandImporter = () => Promise<NationTurnCommandModule>;
|
||||
|
||||
const defaultImporters: Record<
|
||||
NationTurnCommandKey,
|
||||
NationTurnCommandImporter
|
||||
> = {
|
||||
const defaultImporters: Record<NationTurnCommandKey, NationTurnCommandImporter> = {
|
||||
휴식: async () => import('./휴식.js'),
|
||||
che_포상: async () => import('./che_포상.js'),
|
||||
che_부대탈퇴지시: async () => import('./che_부대탈퇴지시.js'),
|
||||
@@ -48,29 +42,17 @@ const defaultImporters: Record<
|
||||
che_급습: async () => import('./che_급습.js'),
|
||||
};
|
||||
|
||||
export const isNationTurnCommandKey = (
|
||||
value: string
|
||||
): value is NationTurnCommandKey =>
|
||||
export const isNationTurnCommandKey = (value: string): value is NationTurnCommandKey =>
|
||||
NATION_TURN_COMMAND_KEYS.includes(value as NationTurnCommandKey);
|
||||
|
||||
|
||||
|
||||
export class NationTurnCommandLoader {
|
||||
private readonly cache = new Map<
|
||||
NationTurnCommandKey,
|
||||
Promise<NationTurnCommandModule>
|
||||
>();
|
||||
private readonly cache = new Map<NationTurnCommandKey, Promise<NationTurnCommandModule>>();
|
||||
|
||||
constructor(
|
||||
private readonly importers: Record<
|
||||
NationTurnCommandKey,
|
||||
NationTurnCommandImporter
|
||||
> = defaultImporters
|
||||
) { }
|
||||
private readonly importers: Record<NationTurnCommandKey, NationTurnCommandImporter> = defaultImporters
|
||||
) {}
|
||||
|
||||
async load(
|
||||
key: NationTurnCommandKey
|
||||
): Promise<NationTurnCommandModule> {
|
||||
async load(key: NationTurnCommandKey): Promise<NationTurnCommandModule> {
|
||||
const cached = this.cache.get(key);
|
||||
if (cached) {
|
||||
return cached;
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import type {
|
||||
GeneralTriggerState,
|
||||
} from '@sammo-ts/logic/domain/entities.js';
|
||||
import type {
|
||||
Constraint,
|
||||
ConstraintContext,
|
||||
} from '@sammo-ts/logic/constraints/types.js';
|
||||
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type {
|
||||
GeneralActionOutcome,
|
||||
@@ -20,7 +15,7 @@ export interface NationRestArgs {}
|
||||
const ACTION_NAME = '휴식';
|
||||
|
||||
export class ActionResolver<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionResolver<TriggerState, NationRestArgs> {
|
||||
readonly key = '휴식';
|
||||
|
||||
@@ -35,7 +30,7 @@ export class ActionResolver<
|
||||
}
|
||||
|
||||
export class ActionDefinition<
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState
|
||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||
> implements GeneralActionDefinition<TriggerState, NationRestArgs> {
|
||||
public readonly key = '휴식';
|
||||
public readonly name = ACTION_NAME;
|
||||
@@ -46,10 +41,7 @@ export class ActionDefinition<
|
||||
return {};
|
||||
}
|
||||
|
||||
buildConstraints(
|
||||
_ctx: ConstraintContext,
|
||||
_args: NationRestArgs
|
||||
): Constraint[] {
|
||||
buildConstraints(_ctx: ConstraintContext, _args: NationRestArgs): Constraint[] {
|
||||
void _ctx;
|
||||
void _args;
|
||||
return [];
|
||||
|
||||
Reference in New Issue
Block a user