사령턴 추가
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
import type { City, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
|
import type { City, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
|
||||||
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
|
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
|
||||||
import {
|
import { beChief, occupiedCity, suppliedCity } from '@sammo-ts/logic/constraints/presets.js';
|
||||||
beChief,
|
|
||||||
occupiedCity,
|
|
||||||
suppliedCity,
|
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type { GeneralActionEffect, GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
import type {
|
||||||
|
GeneralActionEffect,
|
||||||
|
GeneralActionOutcome,
|
||||||
|
GeneralActionResolveContext,
|
||||||
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { createLogEffect, createNationPatchEffect, createCityPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
import { createLogEffect, createNationPatchEffect, createCityPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
@@ -14,7 +14,7 @@ import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js'
|
|||||||
import type { NationTurnCommandSpec } from './index.js';
|
import type { NationTurnCommandSpec } from './index.js';
|
||||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
|
|
||||||
export interface ReduceCityArgs { }
|
export interface ReduceCityArgs {}
|
||||||
|
|
||||||
export interface ReduceCityResolveContext<
|
export interface ReduceCityResolveContext<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -37,7 +37,7 @@ export class ActionDefinition<
|
|||||||
public readonly key = 'che_감축';
|
public readonly key = 'che_감축';
|
||||||
public readonly name = ACTION_NAME;
|
public readonly name = ACTION_NAME;
|
||||||
|
|
||||||
constructor(private readonly env: TurnCommandEnv) { }
|
constructor(private readonly env: TurnCommandEnv) {}
|
||||||
|
|
||||||
parseArgs(_raw: unknown): ReduceCityArgs | null {
|
parseArgs(_raw: unknown): ReduceCityArgs | null {
|
||||||
return {};
|
return {};
|
||||||
@@ -56,7 +56,7 @@ export class ActionDefinition<
|
|||||||
name: 'reducibleCity',
|
name: 'reducibleCity',
|
||||||
requires: (ctx) => [
|
requires: (ctx) => [
|
||||||
{ kind: 'nation', id: ctx.nationId! },
|
{ kind: 'nation', id: ctx.nationId! },
|
||||||
{ kind: 'city', id: 0 }
|
{ kind: 'city', id: 0 },
|
||||||
],
|
],
|
||||||
test: (ctx: ConstraintContext, view: StateView) => {
|
test: (ctx: ConstraintContext, view: StateView) => {
|
||||||
const nation = view.get({ kind: 'nation', id: ctx.nationId! }) as Nation | undefined;
|
const nation = view.get({ kind: 'nation', id: ctx.nationId! }) as Nation | undefined;
|
||||||
@@ -69,8 +69,8 @@ export class ActionDefinition<
|
|||||||
if (capitalCity.level <= 4) return { kind: 'deny', reason: '더이상 감축할 수 없습니다.' };
|
if (capitalCity.level <= 4) return { kind: 'deny', reason: '더이상 감축할 수 없습니다.' };
|
||||||
|
|
||||||
return { kind: 'allow' };
|
return { kind: 'allow' };
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,44 +93,59 @@ export class ActionDefinition<
|
|||||||
const josaYiNation = JosaUtil.pick(nationName, '이');
|
const josaYiNation = JosaUtil.pick(nationName, '이');
|
||||||
|
|
||||||
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
||||||
createCityPatchEffect({
|
createCityPatchEffect(
|
||||||
level: capitalCity.level - 1,
|
{
|
||||||
population: Math.max(capitalCity.population - POP_INCREASE, MIN_POP),
|
level: capitalCity.level - 1,
|
||||||
agriculture: Math.max(capitalCity.agriculture - DEVEL_INCREASE, 0),
|
population: Math.max(capitalCity.population - POP_INCREASE, MIN_POP),
|
||||||
commerce: Math.max(capitalCity.commerce - DEVEL_INCREASE, 0),
|
agriculture: Math.max(capitalCity.agriculture - DEVEL_INCREASE, 0),
|
||||||
security: Math.max(capitalCity.security - DEVEL_INCREASE, 0),
|
commerce: Math.max(capitalCity.commerce - DEVEL_INCREASE, 0),
|
||||||
defence: Math.max(capitalCity.defence - WALL_INCREASE, 0),
|
security: Math.max(capitalCity.security - DEVEL_INCREASE, 0),
|
||||||
wall: Math.max(capitalCity.wall - WALL_INCREASE, 0),
|
defence: Math.max(capitalCity.defence - WALL_INCREASE, 0),
|
||||||
populationMax: capitalCity.populationMax - POP_INCREASE,
|
wall: Math.max(capitalCity.wall - WALL_INCREASE, 0),
|
||||||
agricultureMax: capitalCity.agricultureMax - DEVEL_INCREASE,
|
populationMax: capitalCity.populationMax - POP_INCREASE,
|
||||||
commerceMax: capitalCity.commerceMax - DEVEL_INCREASE,
|
agricultureMax: capitalCity.agricultureMax - DEVEL_INCREASE,
|
||||||
securityMax: capitalCity.securityMax - DEVEL_INCREASE,
|
commerceMax: capitalCity.commerceMax - DEVEL_INCREASE,
|
||||||
defenceMax: capitalCity.defenceMax - WALL_INCREASE,
|
securityMax: capitalCity.securityMax - DEVEL_INCREASE,
|
||||||
wallMax: capitalCity.wallMax - WALL_INCREASE,
|
defenceMax: capitalCity.defenceMax - WALL_INCREASE,
|
||||||
}, capitalCity.id),
|
wallMax: capitalCity.wallMax - WALL_INCREASE,
|
||||||
createNationPatchEffect({
|
},
|
||||||
gold: nation.gold + recoverAmount,
|
capitalCity.id
|
||||||
rice: nation.rice + recoverAmount,
|
),
|
||||||
}, nation.id),
|
createNationPatchEffect(
|
||||||
|
{
|
||||||
|
gold: nation.gold + recoverAmount,
|
||||||
|
rice: nation.rice + recoverAmount,
|
||||||
|
},
|
||||||
|
nation.id
|
||||||
|
),
|
||||||
// Global Action Log
|
// Global Action Log
|
||||||
createLogEffect(`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaUl} <M>${ACTION_NAME}</>하였습니다.`, {
|
createLogEffect(
|
||||||
scope: LogScope.SYSTEM,
|
`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaUl} <M>${ACTION_NAME}</>하였습니다.`,
|
||||||
category: LogCategory.ACTION,
|
{
|
||||||
format: LogFormat.PLAIN,
|
scope: LogScope.SYSTEM,
|
||||||
}),
|
category: LogCategory.ACTION,
|
||||||
|
format: LogFormat.PLAIN,
|
||||||
|
}
|
||||||
|
),
|
||||||
// Global History Log
|
// Global History Log
|
||||||
createLogEffect(`<M><b>【${ACTION_NAME}】</b></><D><b>${nationName}</b></>${josaYiNation} <G><b>${destCityName}</b></>${josaUl} <M>${ACTION_NAME}</>하였습니다.`, {
|
createLogEffect(
|
||||||
scope: LogScope.SYSTEM,
|
`<M><b>【${ACTION_NAME}】</b></><D><b>${nationName}</b></>${josaYiNation} <G><b>${destCityName}</b></>${josaUl} <M>${ACTION_NAME}</>하였습니다.`,
|
||||||
category: LogCategory.HISTORY,
|
{
|
||||||
format: LogFormat.YEAR_MONTH,
|
scope: LogScope.SYSTEM,
|
||||||
}),
|
category: LogCategory.HISTORY,
|
||||||
|
format: LogFormat.YEAR_MONTH,
|
||||||
|
}
|
||||||
|
),
|
||||||
// Actor Nation History Log
|
// Actor Nation History Log
|
||||||
createLogEffect(`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaUl} <M>${ACTION_NAME}</>`, {
|
createLogEffect(
|
||||||
scope: LogScope.NATION,
|
`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaUl} <M>${ACTION_NAME}</>`,
|
||||||
nationId: nation.id,
|
{
|
||||||
category: LogCategory.HISTORY,
|
scope: LogScope.NATION,
|
||||||
format: LogFormat.YEAR_MONTH,
|
nationId: nation.id,
|
||||||
}),
|
category: LogCategory.HISTORY,
|
||||||
|
format: LogFormat.YEAR_MONTH,
|
||||||
|
}
|
||||||
|
),
|
||||||
// General Action Log
|
// General Action Log
|
||||||
createLogEffect(`<G><b>${destCityName}</b></>${josaUl} ${ACTION_NAME}했습니다.`, {
|
createLogEffect(`<G><b>${destCityName}</b></>${josaUl} ${ACTION_NAME}했습니다.`, {
|
||||||
scope: LogScope.GENERAL,
|
scope: LogScope.GENERAL,
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import type { GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
|
import type { 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 type { StateView } from '@sammo-ts/logic/world/stateView.js';
|
import { beChief, occupiedCity, suppliedCity } from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import {
|
|
||||||
beChief,
|
|
||||||
occupiedCity,
|
|
||||||
suppliedCity,
|
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type { GeneralActionEffect, GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
import type {
|
||||||
|
GeneralActionEffect,
|
||||||
|
GeneralActionOutcome,
|
||||||
|
GeneralActionResolveContext,
|
||||||
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { createLogEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
import { createLogEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
@@ -21,10 +20,39 @@ export interface ChangeFlagArgs {
|
|||||||
const ACTION_NAME = '국기변경';
|
const ACTION_NAME = '국기변경';
|
||||||
|
|
||||||
const NATION_COLORS = [
|
const NATION_COLORS = [
|
||||||
'#FF0000', '#800000', '#A0522D', '#FF6347', '#FFA500', '#FFDAB9', '#FFD700', '#FFFF00', '#7CFC00', '#00FF00',
|
'#FF0000',
|
||||||
'#808000', '#008000', '#2E8B57', '#008080', '#20B2AA', '#6495ED', '#7FFFD4', '#AFEEEE', '#87CEEB', '#00FFFF',
|
'#800000',
|
||||||
'#00BFFF', '#0000FF', '#000080', '#483D8B', '#7B68EE', '#BA55D3', '#800080', '#FF00FF', '#FFC0CB', '#F5F5DC',
|
'#A0522D',
|
||||||
'#E0FFFF', '#FFFFFF', '#A9A9A9',
|
'#FF6347',
|
||||||
|
'#FFA500',
|
||||||
|
'#FFDAB9',
|
||||||
|
'#FFD700',
|
||||||
|
'#FFFF00',
|
||||||
|
'#7CFC00',
|
||||||
|
'#00FF00',
|
||||||
|
'#808000',
|
||||||
|
'#008000',
|
||||||
|
'#2E8B57',
|
||||||
|
'#008080',
|
||||||
|
'#20B2AA',
|
||||||
|
'#6495ED',
|
||||||
|
'#7FFFD4',
|
||||||
|
'#AFEEEE',
|
||||||
|
'#87CEEB',
|
||||||
|
'#00FFFF',
|
||||||
|
'#00BFFF',
|
||||||
|
'#0000FF',
|
||||||
|
'#000080',
|
||||||
|
'#483D8B',
|
||||||
|
'#7B68EE',
|
||||||
|
'#BA55D3',
|
||||||
|
'#800080',
|
||||||
|
'#FF00FF',
|
||||||
|
'#FFC0CB',
|
||||||
|
'#F5F5DC',
|
||||||
|
'#E0FFFF',
|
||||||
|
'#FFFFFF',
|
||||||
|
'#A9A9A9',
|
||||||
];
|
];
|
||||||
|
|
||||||
export class ActionDefinition<
|
export class ActionDefinition<
|
||||||
@@ -50,11 +78,12 @@ export class ActionDefinition<
|
|||||||
requires: (ctx) => [{ kind: 'nation', id: ctx.nationId! }],
|
requires: (ctx) => [{ kind: 'nation', id: ctx.nationId! }],
|
||||||
test: (ctx: ConstraintContext, view: StateView) => {
|
test: (ctx: ConstraintContext, view: StateView) => {
|
||||||
const nation = view.get({ kind: 'nation', id: ctx.nationId! }) as Nation | undefined;
|
const nation = view.get({ kind: 'nation', id: ctx.nationId! }) as Nation | undefined;
|
||||||
const canChange = ((nation?.meta as any)?.[`can_${ACTION_NAME}`] ?? 0) !== 0;
|
const canChangeRaw = nation?.meta[`can_${ACTION_NAME}`];
|
||||||
|
const canChange = (typeof canChangeRaw === 'number' ? canChangeRaw : 0) !== 0;
|
||||||
if (!canChange) return { kind: 'deny', reason: '더이상 변경이 불가능합니다.' };
|
if (!canChange) return { kind: 'deny', reason: '더이상 변경이 불가능합니다.' };
|
||||||
return { kind: 'allow' };
|
return { kind: 'allow' };
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,32 +104,44 @@ export class ActionDefinition<
|
|||||||
const josaYiNation = JosaUtil.pick(nationName, '이');
|
const josaYiNation = JosaUtil.pick(nationName, '이');
|
||||||
|
|
||||||
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
||||||
createNationPatchEffect({
|
createNationPatchEffect(
|
||||||
color: color!,
|
{
|
||||||
meta: {
|
color: color!,
|
||||||
...nation.meta,
|
meta: {
|
||||||
[`can_${ACTION_NAME}`]: 0,
|
...nation.meta,
|
||||||
|
[`can_${ACTION_NAME}`]: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}, nation.id),
|
nation.id
|
||||||
|
),
|
||||||
// Global Action Log
|
// Global Action Log
|
||||||
createLogEffect(`<Y>${generalName}</>${josaYi} <span style='color:${color};'><b>국기</b></span>를 변경하였습니다.`, {
|
createLogEffect(
|
||||||
scope: LogScope.SYSTEM,
|
`<Y>${generalName}</>${josaYi} <span style='color:${color};'><b>국기</b></span>를 변경하였습니다.`,
|
||||||
category: LogCategory.ACTION,
|
{
|
||||||
format: LogFormat.PLAIN,
|
scope: LogScope.SYSTEM,
|
||||||
}),
|
category: LogCategory.ACTION,
|
||||||
|
format: LogFormat.PLAIN,
|
||||||
|
}
|
||||||
|
),
|
||||||
// Global History Log
|
// Global History Log
|
||||||
createLogEffect(`<S><b>【${ACTION_NAME}】</b></><D><b>${nationName}</b></>${josaYiNation} <span style='color:${color};'><b>국기</b></span>를 변경하였습니다.`, {
|
createLogEffect(
|
||||||
scope: LogScope.SYSTEM,
|
`<S><b>【${ACTION_NAME}】</b></><D><b>${nationName}</b></>${josaYiNation} <span style='color:${color};'><b>국기</b></span>를 변경하였습니다.`,
|
||||||
category: LogCategory.HISTORY,
|
{
|
||||||
format: LogFormat.YEAR_MONTH,
|
scope: LogScope.SYSTEM,
|
||||||
}),
|
category: LogCategory.HISTORY,
|
||||||
|
format: LogFormat.YEAR_MONTH,
|
||||||
|
}
|
||||||
|
),
|
||||||
// Actor Nation History Log
|
// Actor Nation History Log
|
||||||
createLogEffect(`<Y>${generalName}</>${josaYi} <span style='color:${color};'><b>국기</b></span>를 변경하였습니다.`, {
|
createLogEffect(
|
||||||
scope: LogScope.NATION,
|
`<Y>${generalName}</>${josaYi} <span style='color:${color};'><b>국기</b></span>를 변경하였습니다.`,
|
||||||
nationId: nation.id,
|
{
|
||||||
category: LogCategory.HISTORY,
|
scope: LogScope.NATION,
|
||||||
format: LogFormat.YEAR_MONTH,
|
nationId: nation.id,
|
||||||
}),
|
category: LogCategory.HISTORY,
|
||||||
|
format: LogFormat.YEAR_MONTH,
|
||||||
|
}
|
||||||
|
),
|
||||||
// General Action Log
|
// General Action Log
|
||||||
createLogEffect(`<span style='color:${color};'><b>국기</b></span>를 변경하였습니다.`, {
|
createLogEffect(`<span style='color:${color};'><b>국기</b></span>를 변경하였습니다.`, {
|
||||||
scope: LogScope.GENERAL,
|
scope: LogScope.GENERAL,
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import type { GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
|
import type { 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 {
|
import { beChief, occupiedCity, suppliedCity, checkNationNameDuplicate } from '@sammo-ts/logic/constraints/presets.js';
|
||||||
beChief,
|
|
||||||
occupiedCity,
|
|
||||||
suppliedCity,
|
|
||||||
checkNationNameDuplicate,
|
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type { GeneralActionEffect, GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
import type {
|
||||||
|
GeneralActionEffect,
|
||||||
|
GeneralActionOutcome,
|
||||||
|
GeneralActionResolveContext,
|
||||||
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { createLogEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
import { createLogEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
@@ -46,12 +45,13 @@ export class ActionDefinition<
|
|||||||
name: 'canChangeNationName',
|
name: 'canChangeNationName',
|
||||||
requires: (ctx) => [{ kind: 'nation', id: ctx.nationId! }],
|
requires: (ctx) => [{ kind: 'nation', id: ctx.nationId! }],
|
||||||
test: (_ctx: ConstraintContext, view: StateView) => {
|
test: (_ctx: ConstraintContext, view: StateView) => {
|
||||||
const nation = view.get({ kind: 'nation', id: ctx.nationId! }) as Nation | undefined;
|
const nation = view.get({ kind: 'nation', id: _ctx.nationId! }) as Nation | undefined;
|
||||||
const canChange = ((nation?.meta as any)?.[`can_${ACTION_NAME}`] ?? 0) !== 0;
|
const canChangeRaw = nation?.meta[`can_${ACTION_NAME}`];
|
||||||
|
const canChange = (typeof canChangeRaw === 'number' ? canChangeRaw : 0) !== 0;
|
||||||
if (!canChange) return { kind: 'deny', reason: '더이상 변경이 불가능합니다.' };
|
if (!canChange) return { kind: 'deny', reason: '더이상 변경이 불가능합니다.' };
|
||||||
return { kind: 'allow' };
|
return { kind: 'allow' };
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,13 +72,16 @@ export class ActionDefinition<
|
|||||||
const josaYiNation = JosaUtil.pick(newNationName, '이');
|
const josaYiNation = JosaUtil.pick(newNationName, '이');
|
||||||
|
|
||||||
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
||||||
createNationPatchEffect({
|
createNationPatchEffect(
|
||||||
name: newNationName,
|
{
|
||||||
meta: {
|
name: newNationName,
|
||||||
...nation.meta,
|
meta: {
|
||||||
[`can_${ACTION_NAME}`]: 0,
|
...nation.meta,
|
||||||
|
[`can_${ACTION_NAME}`]: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}, nation.id),
|
nation.id
|
||||||
|
),
|
||||||
// Global Action Log
|
// Global Action Log
|
||||||
createLogEffect(`<Y>${generalName}</>${josaYi} 국호를 <D><b>${newNationName}</b></>로 변경하였습니다.`, {
|
createLogEffect(`<Y>${generalName}</>${josaYi} 국호를 <D><b>${newNationName}</b></>로 변경하였습니다.`, {
|
||||||
scope: LogScope.SYSTEM,
|
scope: LogScope.SYSTEM,
|
||||||
@@ -86,11 +89,14 @@ export class ActionDefinition<
|
|||||||
format: LogFormat.PLAIN,
|
format: LogFormat.PLAIN,
|
||||||
}),
|
}),
|
||||||
// Global History Log
|
// Global History Log
|
||||||
createLogEffect(`<S><b>【${ACTION_NAME}】</b></><D><b>${oldNationName}</b></>${josaYiNation} 국호를 <D><b>${newNationName}</b></>로 변경하였습니다.`, {
|
createLogEffect(
|
||||||
scope: LogScope.SYSTEM,
|
`<S><b>【${ACTION_NAME}】</b></><D><b>${oldNationName}</b></>${josaYiNation} 국호를 <D><b>${newNationName}</b></>로 변경하였습니다.`,
|
||||||
category: LogCategory.HISTORY,
|
{
|
||||||
format: LogFormat.YEAR_MONTH,
|
scope: LogScope.SYSTEM,
|
||||||
}),
|
category: LogCategory.HISTORY,
|
||||||
|
format: LogFormat.YEAR_MONTH,
|
||||||
|
}
|
||||||
|
),
|
||||||
// Actor Nation History Log
|
// Actor Nation History Log
|
||||||
createLogEffect(`<Y>${generalName}</>${josaYi} 국호를 <D><b>${newNationName}</b></>로 변경하였습니다.`, {
|
createLogEffect(`<Y>${generalName}</>${josaYi} 국호를 <D><b>${newNationName}</b></>로 변경하였습니다.`, {
|
||||||
scope: LogScope.NATION,
|
scope: LogScope.NATION,
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ import {
|
|||||||
suppliedCity,
|
suppliedCity,
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
} from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type { GeneralActionEffect, GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
import type {
|
||||||
|
GeneralActionEffect,
|
||||||
|
GeneralActionOutcome,
|
||||||
|
GeneralActionResolveContext,
|
||||||
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { createLogEffect, createNationPatchEffect, createGeneralPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
import { createLogEffect, createNationPatchEffect, createGeneralPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
@@ -37,7 +41,7 @@ export class ActionDefinition<
|
|||||||
public readonly key = 'che_몰수';
|
public readonly key = 'che_몰수';
|
||||||
public readonly name = ACTION_NAME;
|
public readonly name = ACTION_NAME;
|
||||||
|
|
||||||
constructor(private readonly env: TurnCommandEnv) { }
|
constructor(private readonly env: TurnCommandEnv) {}
|
||||||
|
|
||||||
parseArgs(raw: unknown): SeizureArgs | null {
|
parseArgs(raw: unknown): SeizureArgs | null {
|
||||||
const data = raw as { isGold?: boolean; amount?: number; destGeneralID?: number };
|
const data = raw as { isGold?: boolean; amount?: number; destGeneralID?: number };
|
||||||
@@ -70,15 +74,12 @@ export class ActionDefinition<
|
|||||||
return { kind: 'deny', reason: '본인입니다' };
|
return { kind: 'deny', reason: '본인입니다' };
|
||||||
}
|
}
|
||||||
return { kind: 'allow' };
|
return { kind: 'allow' };
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(
|
resolve(context: SeizureResolveContext<TriggerState>, args: SeizureArgs): GeneralActionOutcome<TriggerState> {
|
||||||
context: SeizureResolveContext<TriggerState>,
|
|
||||||
args: SeizureArgs
|
|
||||||
): GeneralActionOutcome<TriggerState> {
|
|
||||||
const { general, nation, destGeneral } = context;
|
const { general, nation, destGeneral } = context;
|
||||||
if (!nation) {
|
if (!nation) {
|
||||||
return { effects: [createLogEffect('국가 정보가 없습니다.', { scope: LogScope.GENERAL })] };
|
return { effects: [createLogEffect('국가 정보가 없습니다.', { scope: LogScope.GENERAL })] };
|
||||||
@@ -87,7 +88,7 @@ export class ActionDefinition<
|
|||||||
const resKey = args.isGold ? 'gold' : 'rice';
|
const resKey = args.isGold ? 'gold' : 'rice';
|
||||||
const resName = args.isGold ? '금' : '쌀';
|
const resName = args.isGold ? '금' : '쌀';
|
||||||
|
|
||||||
const actualAmount = clamp(args.amount, 0, (destGeneral as any)[resKey] ?? 0);
|
const actualAmount = clamp(args.amount, 0, destGeneral[resKey] ?? 0);
|
||||||
|
|
||||||
if (actualAmount <= 0) {
|
if (actualAmount <= 0) {
|
||||||
return {
|
return {
|
||||||
@@ -105,12 +106,18 @@ export class ActionDefinition<
|
|||||||
const josaUl = JosaUtil.pick(amountText, '을');
|
const josaUl = JosaUtil.pick(amountText, '을');
|
||||||
|
|
||||||
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
||||||
createGeneralPatchEffect({
|
createGeneralPatchEffect(
|
||||||
[resKey]: (destGeneral as any)[resKey] - actualAmount,
|
{
|
||||||
}, destGeneral.id),
|
[resKey]: destGeneral[resKey] - actualAmount,
|
||||||
createNationPatchEffect({
|
},
|
||||||
[resKey]: (nation as any)[resKey] + actualAmount,
|
destGeneral.id
|
||||||
}, nation.id),
|
),
|
||||||
|
createNationPatchEffect(
|
||||||
|
{
|
||||||
|
[resKey]: nation[resKey] + actualAmount,
|
||||||
|
},
|
||||||
|
nation.id
|
||||||
|
),
|
||||||
// Actor General Action Log
|
// Actor General Action Log
|
||||||
createLogEffect(`<Y>${destGeneral.name}</>에게서 ${resName} <C>${amountText}</>${josaUl} 몰수했습니다.`, {
|
createLogEffect(`<Y>${destGeneral.name}</>에게서 ${resName} <C>${amountText}</>${josaUl} 몰수했습니다.`, {
|
||||||
scope: LogScope.GENERAL,
|
scope: LogScope.GENERAL,
|
||||||
|
|||||||
@@ -1,20 +1,25 @@
|
|||||||
import type { GeneralTriggerState, Nation, City, General } from '@sammo-ts/logic/domain/entities.js';
|
import type { GeneralTriggerState, Nation, City, General } from '@sammo-ts/logic/domain/entities.js';
|
||||||
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
|
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
|
||||||
import {
|
import { beMonarch, occupiedCity, suppliedCity } from '@sammo-ts/logic/constraints/presets.js';
|
||||||
beMonarch,
|
|
||||||
occupiedCity,
|
|
||||||
suppliedCity,
|
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type { GeneralActionEffect, GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
import type {
|
||||||
import { createLogEffect, createNationPatchEffect, createCityPatchEffect, createGeneralPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
GeneralActionEffect,
|
||||||
|
GeneralActionOutcome,
|
||||||
|
GeneralActionResolveContext,
|
||||||
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
|
import {
|
||||||
|
createLogEffect,
|
||||||
|
createNationPatchEffect,
|
||||||
|
createCityPatchEffect,
|
||||||
|
createGeneralPatchEffect,
|
||||||
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import type { NationTurnCommandSpec } from './index.js';
|
import type { NationTurnCommandSpec } from './index.js';
|
||||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
|
|
||||||
export interface RandomMoveCapitalArgs { }
|
export interface RandomMoveCapitalArgs {}
|
||||||
|
|
||||||
export interface RandomMoveCapitalResolveContext<
|
export interface RandomMoveCapitalResolveContext<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -27,7 +32,11 @@ const ACTION_NAME = '무작위 수도 이전';
|
|||||||
|
|
||||||
export class ActionDefinition<
|
export class ActionDefinition<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
> implements GeneralActionDefinition<TriggerState, RandomMoveCapitalArgs, RandomMoveCapitalResolveContext<TriggerState>> {
|
> implements GeneralActionDefinition<
|
||||||
|
TriggerState,
|
||||||
|
RandomMoveCapitalArgs,
|
||||||
|
RandomMoveCapitalResolveContext<TriggerState>
|
||||||
|
> {
|
||||||
public readonly key = 'che_무작위수도이전';
|
public readonly key = 'che_무작위수도이전';
|
||||||
public readonly name = ACTION_NAME;
|
public readonly name = ACTION_NAME;
|
||||||
|
|
||||||
@@ -45,11 +54,12 @@ export class ActionDefinition<
|
|||||||
requires: (ctx) => [{ kind: 'nation', id: ctx.nationId! }],
|
requires: (ctx) => [{ kind: 'nation', id: ctx.nationId! }],
|
||||||
test: (ctx: ConstraintContext, view: StateView) => {
|
test: (ctx: ConstraintContext, view: StateView) => {
|
||||||
const nation = view.get({ kind: 'nation', id: ctx.nationId! }) as Nation | undefined;
|
const nation = view.get({ kind: 'nation', id: ctx.nationId! }) as Nation | undefined;
|
||||||
const canMove = ((nation?.meta as any)?.[`can_무작위수도이전`] ?? 0) > 0;
|
const canMoveRaw = nation?.meta[`can_무작위수도이전`];
|
||||||
|
const canMove = (typeof canMoveRaw === 'number' ? canMoveRaw : 0) > 0;
|
||||||
if (!canMove) return { kind: 'deny', reason: '더이상 변경이 불가능합니다.' };
|
if (!canMove) return { kind: 'deny', reason: '더이상 변경이 불가능합니다.' };
|
||||||
return { kind: 'allow' };
|
return { kind: 'allow' };
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,41 +95,59 @@ export class ActionDefinition<
|
|||||||
const josaYiNation = JosaUtil.pick(nationName, '이');
|
const josaYiNation = JosaUtil.pick(nationName, '이');
|
||||||
|
|
||||||
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
||||||
createNationPatchEffect({
|
createNationPatchEffect(
|
||||||
capitalCityId: destCity.id,
|
{
|
||||||
meta: {
|
capitalCityId: destCity.id,
|
||||||
...nation.meta,
|
meta: {
|
||||||
can_무작위수도이전: ((nation.meta as any).can_무작위수도이전 ?? 0) - 1,
|
...nation.meta,
|
||||||
|
can_무작위수도이전: Number(nation.meta.can_무작위수도이전 ?? 0) - 1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}, nation.id),
|
nation.id
|
||||||
|
),
|
||||||
// Set new capital
|
// Set new capital
|
||||||
createCityPatchEffect({
|
createCityPatchEffect(
|
||||||
nationId: nation.id,
|
{
|
||||||
}, destCity.id),
|
nationId: nation.id,
|
||||||
|
},
|
||||||
|
destCity.id
|
||||||
|
),
|
||||||
// Set old capital to neutral
|
// Set old capital to neutral
|
||||||
createCityPatchEffect({
|
createCityPatchEffect(
|
||||||
nationId: 0,
|
{
|
||||||
frontState: 0,
|
nationId: 0,
|
||||||
}, oldCityId!),
|
frontState: 0,
|
||||||
|
},
|
||||||
|
oldCityId!
|
||||||
|
),
|
||||||
// Global Action Log
|
// Global Action Log
|
||||||
createLogEffect(`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaRo} <M>수도 이전</}하였습니다.`, {
|
createLogEffect(
|
||||||
scope: LogScope.SYSTEM,
|
`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaRo} <M>수도 이전</}하였습니다.`,
|
||||||
category: LogCategory.ACTION,
|
{
|
||||||
format: LogFormat.PLAIN,
|
scope: LogScope.SYSTEM,
|
||||||
}),
|
category: LogCategory.ACTION,
|
||||||
|
format: LogFormat.PLAIN,
|
||||||
|
}
|
||||||
|
),
|
||||||
// Global History Log
|
// Global History Log
|
||||||
createLogEffect(`<S><b>【${ACTION_NAME}】</b></><D><b>${nationName}</b></>${josaYiNation} <G><b>${destCityName}</b></>${josaRo} <M>수도 이전</}하였습니다.`, {
|
createLogEffect(
|
||||||
scope: LogScope.SYSTEM,
|
`<S><b>【${ACTION_NAME}】</b></><D><b>${nationName}</b></>${josaYiNation} <G><b>${destCityName}</b></>${josaRo} <M>수도 이전</}하였습니다.`,
|
||||||
category: LogCategory.HISTORY,
|
{
|
||||||
format: LogFormat.YEAR_MONTH,
|
scope: LogScope.SYSTEM,
|
||||||
}),
|
category: LogCategory.HISTORY,
|
||||||
|
format: LogFormat.YEAR_MONTH,
|
||||||
|
}
|
||||||
|
),
|
||||||
// Actor Nation History Log
|
// Actor Nation History Log
|
||||||
createLogEffect(`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaRo} <M>${ACTION_NAME}</} `, {
|
createLogEffect(
|
||||||
scope: LogScope.NATION,
|
`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaRo} <M>${ACTION_NAME}</} `,
|
||||||
nationId: nation.id,
|
{
|
||||||
category: LogCategory.HISTORY,
|
scope: LogScope.NATION,
|
||||||
format: LogFormat.YEAR_MONTH,
|
nationId: nation.id,
|
||||||
}),
|
category: LogCategory.HISTORY,
|
||||||
|
format: LogFormat.YEAR_MONTH,
|
||||||
|
}
|
||||||
|
),
|
||||||
// General Action Log
|
// General Action Log
|
||||||
createLogEffect(`<G><b>${destCityName}</b></>${josaRo} 국가를 옮겼습니다.`, {
|
createLogEffect(`<G><b>${destCityName}</b></>${josaRo} 국가를 옮겼습니다.`, {
|
||||||
scope: LogScope.GENERAL,
|
scope: LogScope.GENERAL,
|
||||||
@@ -130,17 +158,24 @@ export class ActionDefinition<
|
|||||||
|
|
||||||
// Move all generals to new capital
|
// Move all generals to new capital
|
||||||
for (const targetGeneral of nationGenerals) {
|
for (const targetGeneral of nationGenerals) {
|
||||||
effects.push(createGeneralPatchEffect({
|
effects.push(
|
||||||
cityId: destCity.id,
|
createGeneralPatchEffect(
|
||||||
}, targetGeneral.id));
|
{
|
||||||
|
cityId: destCity.id,
|
||||||
|
},
|
||||||
|
targetGeneral.id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
if (targetGeneral.id !== general.id) {
|
if (targetGeneral.id !== general.id) {
|
||||||
effects.push(createLogEffect(`국가 수도를 <G><b>${destCityName}</b></>${josaRo} 옮겼습니다.`, {
|
effects.push(
|
||||||
scope: LogScope.GENERAL,
|
createLogEffect(`국가 수도를 <G><b>${destCityName}</b></>${josaRo} 옮겼습니다.`, {
|
||||||
category: LogCategory.ACTION,
|
scope: LogScope.GENERAL,
|
||||||
generalId: targetGeneral.id,
|
category: LogCategory.ACTION,
|
||||||
format: LogFormat.PLAIN,
|
generalId: targetGeneral.id,
|
||||||
}));
|
format: LogFormat.PLAIN,
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,8 +191,8 @@ export const actionContextBuilder: ActionContextBuilder = (base, options) => {
|
|||||||
if (!worldRef) return null;
|
if (!worldRef) return null;
|
||||||
|
|
||||||
const allCities = worldRef.listCities();
|
const allCities = worldRef.listCities();
|
||||||
const neutralCandidateCities = allCities.filter(c => c.nationId === 0 && c.level >= 5 && c.level <= 6);
|
const neutralCandidateCities = allCities.filter((c) => c.nationId === 0 && c.level >= 5 && c.level <= 6);
|
||||||
const nationGenerals = worldRef.listGenerals().filter(g => g.nationId === base.general.nationId);
|
const nationGenerals = worldRef.listGenerals().filter((g) => g.nationId === base.general.nationId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...base,
|
...base,
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ import {
|
|||||||
existsDestNation,
|
existsDestNation,
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
} from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type { GeneralActionEffect, GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
import type {
|
||||||
|
GeneralActionEffect,
|
||||||
|
GeneralActionOutcome,
|
||||||
|
GeneralActionResolveContext,
|
||||||
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { createLogEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
import { createLogEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
@@ -38,7 +42,7 @@ export class ActionDefinition<
|
|||||||
public readonly key = 'che_물자원조';
|
public readonly key = 'che_물자원조';
|
||||||
public readonly name = ACTION_NAME;
|
public readonly name = ACTION_NAME;
|
||||||
|
|
||||||
constructor(private readonly env: TurnCommandEnv) { }
|
constructor(private readonly env: TurnCommandEnv) {}
|
||||||
|
|
||||||
parseArgs(raw: unknown): MaterialAidArgs | null {
|
parseArgs(raw: unknown): MaterialAidArgs | null {
|
||||||
const data = raw as { destNationId?: number; amountList?: [number, number] };
|
const data = raw as { destNationId?: number; amountList?: [number, number] };
|
||||||
@@ -70,28 +74,30 @@ export class ActionDefinition<
|
|||||||
return { kind: 'deny', reason: '작위 제한량 이상은 보낼 수 없습니다.' };
|
return { kind: 'deny', reason: '작위 제한량 이상은 보낼 수 없습니다.' };
|
||||||
}
|
}
|
||||||
return { kind: 'allow' };
|
return { kind: 'allow' };
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'nationSurlimit',
|
name: 'nationSurlimit',
|
||||||
requires: (ctx) => [{ kind: 'nation', id: ctx.nationId! }],
|
requires: (ctx) => [{ kind: 'nation', id: ctx.nationId! }],
|
||||||
test: (_ctx: ConstraintContext, view: StateView) => {
|
test: (_ctx: ConstraintContext, view: StateView) => {
|
||||||
const nation = view.get({ kind: 'nation', id: _ctx.nationId! }) as Nation | undefined;
|
const nation = view.get({ kind: 'nation', id: _ctx.nationId! }) as Nation | undefined;
|
||||||
const surlimit = (nation?.meta as any)?.surlimit ?? 0;
|
const surlimitRaw = nation?.meta.surlimit;
|
||||||
|
const surlimit = typeof surlimitRaw === 'number' ? surlimitRaw : 0;
|
||||||
if (surlimit > 0) return { kind: 'deny', reason: '외교제한중입니다.' };
|
if (surlimit > 0) return { kind: 'deny', reason: '외교제한중입니다.' };
|
||||||
return { kind: 'allow' };
|
return { kind: 'allow' };
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'destNationSurlimit',
|
name: 'destNationSurlimit',
|
||||||
requires: () => [{ kind: 'nation', id: args.destNationId }],
|
requires: () => [{ kind: 'nation', id: args.destNationId }],
|
||||||
test: (ctx: ConstraintContext, view: StateView) => {
|
test: (_ctx: ConstraintContext, view: StateView) => {
|
||||||
const destNation = view.get({ kind: 'nation', id: args.destNationId }) as Nation | undefined;
|
const destNation = view.get({ kind: 'nation', id: args.destNationId }) as Nation | undefined;
|
||||||
const surlimit = (destNation?.meta as any)?.surlimit ?? 0;
|
const surlimitRaw = destNation?.meta.surlimit;
|
||||||
|
const surlimit = typeof surlimitRaw === 'number' ? surlimitRaw : 0;
|
||||||
if (surlimit > 0) return { kind: 'deny', reason: '상대국이 외교제한중입니다.' };
|
if (surlimit > 0) return { kind: 'deny', reason: '상대국이 외교제한중입니다.' };
|
||||||
return { kind: 'allow' };
|
return { kind: 'allow' };
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,38 +125,53 @@ export class ActionDefinition<
|
|||||||
const broadcastMessage = `<D><b>${destNation.name}</b></>${josaRo} 금<C>${goldText}</> 쌀<C>${riceText}</>을 지원했습니다.`;
|
const broadcastMessage = `<D><b>${destNation.name}</b></>${josaRo} 금<C>${goldText}</> 쌀<C>${riceText}</>을 지원했습니다.`;
|
||||||
|
|
||||||
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
||||||
createNationPatchEffect({
|
createNationPatchEffect(
|
||||||
gold: nation.gold - actualGold,
|
{
|
||||||
rice: nation.rice - actualRice,
|
gold: nation.gold - actualGold,
|
||||||
meta: {
|
rice: nation.rice - actualRice,
|
||||||
...nation.meta,
|
meta: {
|
||||||
surlimit: ((nation.meta as any)?.surlimit ?? 0) + POST_REQ_TURN,
|
...nation.meta,
|
||||||
|
surlimit: Number(nation.meta.surlimit ?? 0) + POST_REQ_TURN,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}, nation.id),
|
nation.id
|
||||||
createNationPatchEffect({
|
),
|
||||||
gold: destNation.gold + actualGold,
|
createNationPatchEffect(
|
||||||
rice: destNation.rice + actualRice,
|
{
|
||||||
}, destNation.id),
|
gold: destNation.gold + actualGold,
|
||||||
|
rice: destNation.rice + actualRice,
|
||||||
|
},
|
||||||
|
destNation.id
|
||||||
|
),
|
||||||
// Global History Log
|
// Global History Log
|
||||||
createLogEffect(`<Y><b>【${ACTION_NAME}】</b></><D><b>${nationName}</b></>에서 <D><b>${destNation.name}</b></>${josaRo} 물자를 지원합니다`, {
|
createLogEffect(
|
||||||
scope: LogScope.SYSTEM,
|
`<Y><b>【${ACTION_NAME}】</b></><D><b>${nationName}</b></>에서 <D><b>${destNation.name}</b></>${josaRo} 물자를 지원합니다`,
|
||||||
category: LogCategory.HISTORY,
|
{
|
||||||
format: LogFormat.YEAR_MONTH,
|
scope: LogScope.SYSTEM,
|
||||||
}),
|
category: LogCategory.HISTORY,
|
||||||
|
format: LogFormat.YEAR_MONTH,
|
||||||
|
}
|
||||||
|
),
|
||||||
// Actor Nation History Log
|
// Actor Nation History Log
|
||||||
createLogEffect(`<D><b>${destNation.name}</b></>${josaRo} 금<C>${goldText}</> 쌀<C>${riceText}</>${josaUlRice} 지원`, {
|
createLogEffect(
|
||||||
scope: LogScope.NATION,
|
`<D><b>${destNation.name}</b></>${josaRo} 금<C>${goldText}</> 쌀<C>${riceText}</>${josaUlRice} 지원`,
|
||||||
nationId: nation.id,
|
{
|
||||||
category: LogCategory.HISTORY,
|
scope: LogScope.NATION,
|
||||||
format: LogFormat.YEAR_MONTH,
|
nationId: nation.id,
|
||||||
}),
|
category: LogCategory.HISTORY,
|
||||||
|
format: LogFormat.YEAR_MONTH,
|
||||||
|
}
|
||||||
|
),
|
||||||
// Dest Nation History Log
|
// Dest Nation History Log
|
||||||
createLogEffect(`<D><b>${nationName}</b></>로부터 금<C>${goldText}</> 쌀<C>${riceText}</>${josaUlRice} 지원 받음`, {
|
createLogEffect(
|
||||||
scope: LogScope.NATION,
|
`<D><b>${nationName}</b></>로부터 금<C>${goldText}</> 쌀<C>${riceText}</>${josaUlRice} 지원 받음`,
|
||||||
nationId: destNation.id,
|
{
|
||||||
category: LogCategory.HISTORY,
|
scope: LogScope.NATION,
|
||||||
format: LogFormat.YEAR_MONTH,
|
nationId: destNation.id,
|
||||||
}),
|
category: LogCategory.HISTORY,
|
||||||
|
format: LogFormat.YEAR_MONTH,
|
||||||
|
}
|
||||||
|
),
|
||||||
// General Action Log
|
// General Action Log
|
||||||
createLogEffect(broadcastMessage, {
|
createLogEffect(broadcastMessage, {
|
||||||
scope: LogScope.GENERAL,
|
scope: LogScope.GENERAL,
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ import {
|
|||||||
reqNationRice,
|
reqNationRice,
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
} from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type { GeneralActionEffect, GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
import type {
|
||||||
|
GeneralActionEffect,
|
||||||
|
GeneralActionOutcome,
|
||||||
|
GeneralActionResolveContext,
|
||||||
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { createLogEffect, createNationPatchEffect, createCityPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
import { createLogEffect, createNationPatchEffect, createCityPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
@@ -16,7 +20,7 @@ import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js'
|
|||||||
import type { NationTurnCommandSpec } from './index.js';
|
import type { NationTurnCommandSpec } from './index.js';
|
||||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
|
|
||||||
export interface ExpandCityArgs { }
|
export interface ExpandCityArgs {}
|
||||||
|
|
||||||
export interface ExpandCityResolveContext<
|
export interface ExpandCityResolveContext<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -38,7 +42,7 @@ export class ActionDefinition<
|
|||||||
public readonly key = 'che_증축';
|
public readonly key = 'che_증축';
|
||||||
public readonly name = ACTION_NAME;
|
public readonly name = ACTION_NAME;
|
||||||
|
|
||||||
constructor(private readonly env: TurnCommandEnv) { }
|
constructor(private readonly env: TurnCommandEnv) {}
|
||||||
|
|
||||||
parseArgs(_raw: unknown): ExpandCityArgs | null {
|
parseArgs(_raw: unknown): ExpandCityArgs | null {
|
||||||
return {};
|
return {};
|
||||||
@@ -60,7 +64,7 @@ export class ActionDefinition<
|
|||||||
name: 'expandableCity',
|
name: 'expandableCity',
|
||||||
requires: (ctx) => [
|
requires: (ctx) => [
|
||||||
{ kind: 'nation', id: ctx.nationId! },
|
{ kind: 'nation', id: ctx.nationId! },
|
||||||
{ kind: 'city', id: 0 }
|
{ kind: 'city', id: 0 },
|
||||||
],
|
],
|
||||||
test: (ctx: ConstraintContext, view: StateView) => {
|
test: (ctx: ConstraintContext, view: StateView) => {
|
||||||
const nation = view.get({ kind: 'nation', id: ctx.nationId! }) as Nation | undefined;
|
const nation = view.get({ kind: 'nation', id: ctx.nationId! }) as Nation | undefined;
|
||||||
@@ -74,8 +78,8 @@ export class ActionDefinition<
|
|||||||
if (capitalCity.level >= 8) return { kind: 'deny', reason: '더이상 증축할 수 없습니다.' };
|
if (capitalCity.level >= 8) return { kind: 'deny', reason: '더이상 증축할 수 없습니다.' };
|
||||||
|
|
||||||
return { kind: 'allow' };
|
return { kind: 'allow' };
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,38 +102,53 @@ export class ActionDefinition<
|
|||||||
const josaYiNation = JosaUtil.pick(nationName, '이');
|
const josaYiNation = JosaUtil.pick(nationName, '이');
|
||||||
|
|
||||||
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
||||||
createCityPatchEffect({
|
createCityPatchEffect(
|
||||||
level: capitalCity.level + 1,
|
{
|
||||||
populationMax: capitalCity.populationMax + POP_INCREASE,
|
level: capitalCity.level + 1,
|
||||||
agricultureMax: capitalCity.agricultureMax + DEVEL_INCREASE,
|
populationMax: capitalCity.populationMax + POP_INCREASE,
|
||||||
commerceMax: capitalCity.commerceMax + DEVEL_INCREASE,
|
agricultureMax: capitalCity.agricultureMax + DEVEL_INCREASE,
|
||||||
securityMax: capitalCity.securityMax + DEVEL_INCREASE,
|
commerceMax: capitalCity.commerceMax + DEVEL_INCREASE,
|
||||||
defenceMax: capitalCity.defenceMax + WALL_INCREASE,
|
securityMax: capitalCity.securityMax + DEVEL_INCREASE,
|
||||||
wallMax: capitalCity.wallMax + WALL_INCREASE,
|
defenceMax: capitalCity.defenceMax + WALL_INCREASE,
|
||||||
}, capitalCity.id),
|
wallMax: capitalCity.wallMax + WALL_INCREASE,
|
||||||
createNationPatchEffect({
|
},
|
||||||
gold: nation.gold - cost,
|
capitalCity.id
|
||||||
rice: nation.rice - cost,
|
),
|
||||||
}, nation.id),
|
createNationPatchEffect(
|
||||||
|
{
|
||||||
|
gold: nation.gold - cost,
|
||||||
|
rice: nation.rice - cost,
|
||||||
|
},
|
||||||
|
nation.id
|
||||||
|
),
|
||||||
// Global Action Log
|
// Global Action Log
|
||||||
createLogEffect(`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaUl} <M>${ACTION_NAME}</>하였습니다.`, {
|
createLogEffect(
|
||||||
scope: LogScope.SYSTEM,
|
`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaUl} <M>${ACTION_NAME}</>하였습니다.`,
|
||||||
category: LogCategory.ACTION,
|
{
|
||||||
format: LogFormat.PLAIN,
|
scope: LogScope.SYSTEM,
|
||||||
}),
|
category: LogCategory.ACTION,
|
||||||
|
format: LogFormat.PLAIN,
|
||||||
|
}
|
||||||
|
),
|
||||||
// Global History Log
|
// Global History Log
|
||||||
createLogEffect(`<C><b>【${ACTION_NAME}】</b></><D><b>${nationName}</b></>${josaYiNation} <G><b>${destCityName}</b></>${josaUl} <M>${ACTION_NAME}</>하였습니다.`, {
|
createLogEffect(
|
||||||
scope: LogScope.SYSTEM,
|
`<C><b>【${ACTION_NAME}】</b></><D><b>${nationName}</b></>${josaYiNation} <G><b>${destCityName}</b></>${josaUl} <M>${ACTION_NAME}</>하였습니다.`,
|
||||||
category: LogCategory.HISTORY,
|
{
|
||||||
format: LogFormat.YEAR_MONTH,
|
scope: LogScope.SYSTEM,
|
||||||
}),
|
category: LogCategory.HISTORY,
|
||||||
|
format: LogFormat.YEAR_MONTH,
|
||||||
|
}
|
||||||
|
),
|
||||||
// Actor Nation History Log
|
// Actor Nation History Log
|
||||||
createLogEffect(`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaUl} <M>${ACTION_NAME}</>`, {
|
createLogEffect(
|
||||||
scope: LogScope.NATION,
|
`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaUl} <M>${ACTION_NAME}</>`,
|
||||||
nationId: nation.id,
|
{
|
||||||
category: LogCategory.HISTORY,
|
scope: LogScope.NATION,
|
||||||
format: LogFormat.YEAR_MONTH,
|
nationId: nation.id,
|
||||||
}),
|
category: LogCategory.HISTORY,
|
||||||
|
format: LogFormat.YEAR_MONTH,
|
||||||
|
}
|
||||||
|
),
|
||||||
// General Action Log
|
// General Action Log
|
||||||
createLogEffect(`<G><b>${destCityName}</b></>${josaUl} ${ACTION_NAME}했습니다.`, {
|
createLogEffect(`<G><b>${destCityName}</b></>${josaUl} ${ACTION_NAME}했습니다.`, {
|
||||||
scope: LogScope.GENERAL,
|
scope: LogScope.GENERAL,
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ import {
|
|||||||
suppliedDestCity,
|
suppliedDestCity,
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
} from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type { GeneralActionEffect, GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
import type {
|
||||||
|
GeneralActionEffect,
|
||||||
|
GeneralActionOutcome,
|
||||||
|
GeneralActionResolveContext,
|
||||||
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { createLogEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
import { createLogEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.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 { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
@@ -30,11 +34,7 @@ export interface MoveCapitalResolveContext<
|
|||||||
|
|
||||||
const ACTION_NAME = '천도';
|
const ACTION_NAME = '천도';
|
||||||
|
|
||||||
const calcDistance = (
|
const calcDistance = (fromCityId: number, toCityId: number, map: MapDefinition): number => {
|
||||||
fromCityId: number,
|
|
||||||
toCityId: number,
|
|
||||||
map: MapDefinition
|
|
||||||
): number => {
|
|
||||||
if (fromCityId === toCityId) return 0;
|
if (fromCityId === toCityId) return 0;
|
||||||
|
|
||||||
const connections = new Map<number, number[]>();
|
const connections = new Map<number, number[]>();
|
||||||
@@ -68,7 +68,7 @@ export class ActionDefinition<
|
|||||||
public readonly key = 'che_천도';
|
public readonly key = 'che_천도';
|
||||||
public readonly name = ACTION_NAME;
|
public readonly name = ACTION_NAME;
|
||||||
|
|
||||||
constructor(private readonly env: TurnCommandEnv) { }
|
constructor(private readonly env: TurnCommandEnv) {}
|
||||||
|
|
||||||
parseArgs(raw: unknown): MoveCapitalArgs | null {
|
parseArgs(raw: unknown): MoveCapitalArgs | null {
|
||||||
const data = raw as { destCityID?: number };
|
const data = raw as { destCityID?: number };
|
||||||
@@ -94,28 +94,31 @@ export class ActionDefinition<
|
|||||||
return { kind: 'deny', reason: '이미 수도입니다.' };
|
return { kind: 'deny', reason: '이미 수도입니다.' };
|
||||||
}
|
}
|
||||||
return { kind: 'allow' };
|
return { kind: 'allow' };
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'reqMoveCapitalCost',
|
name: 'reqMoveCapitalCost',
|
||||||
requires: (ctx) => [
|
requires: (ctx) => [
|
||||||
{ kind: 'nation', id: ctx.nationId! },
|
{ kind: 'nation', id: ctx.nationId! },
|
||||||
{ kind: 'env', key: 'map' }
|
{ kind: 'env', key: 'map' },
|
||||||
],
|
],
|
||||||
test: (ctx: ConstraintContext, view: StateView) => {
|
test: (ctx: ConstraintContext, view: StateView) => {
|
||||||
const nation = view.get({ kind: 'nation', id: ctx.nationId! }) as Nation | undefined;
|
const nation = view.get({ kind: 'nation', id: ctx.nationId! }) as Nation | undefined;
|
||||||
const map = view.get({ kind: 'env', key: 'map' }) as MapDefinition | undefined;
|
const map = view.get({ kind: 'env', key: 'map' }) as MapDefinition | undefined;
|
||||||
if (!map || !nation || nation.capitalCityId === undefined || nation.capitalCityId === null) return { kind: 'allow' };
|
if (!map || !nation || nation.capitalCityId === undefined || nation.capitalCityId === null)
|
||||||
|
return { kind: 'allow' };
|
||||||
|
|
||||||
const dist = calcDistance(nation.capitalCityId, args.destCityID, map);
|
const dist = calcDistance(nation.capitalCityId, args.destCityID, map);
|
||||||
const cost = develcost * 5 * Math.pow(2, dist);
|
const cost = develcost * 5 * Math.pow(2, dist);
|
||||||
|
|
||||||
if (nation.gold < cost + 1000) return { kind: 'deny', reason: `금이 부족합니다. (필요: ${cost + 1000})` };
|
if (nation.gold < cost + 1000)
|
||||||
if (nation.rice < cost + 1000) return { kind: 'deny', reason: `쌀이 부족합니다. (필요: ${cost + 1000})` };
|
return { kind: 'deny', reason: `금이 부족합니다. (필요: ${cost + 1000})` };
|
||||||
|
if (nation.rice < cost + 1000)
|
||||||
|
return { kind: 'deny', reason: `쌀이 부족합니다. (필요: ${cost + 1000})` };
|
||||||
|
|
||||||
return { kind: 'allow' };
|
return { kind: 'allow' };
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,30 +143,42 @@ export class ActionDefinition<
|
|||||||
const josaYiNation = JosaUtil.pick(nationName, '이');
|
const josaYiNation = JosaUtil.pick(nationName, '이');
|
||||||
|
|
||||||
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
||||||
createNationPatchEffect({
|
createNationPatchEffect(
|
||||||
capitalCityId: args.destCityID,
|
{
|
||||||
gold: nation.gold - cost,
|
capitalCityId: args.destCityID,
|
||||||
rice: nation.rice - cost,
|
gold: nation.gold - cost,
|
||||||
}, nation.id),
|
rice: nation.rice - cost,
|
||||||
|
},
|
||||||
|
nation.id
|
||||||
|
),
|
||||||
// Global Action Log
|
// Global Action Log
|
||||||
createLogEffect(`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaRo} <M>${ACTION_NAME}</>를 명령하였습니다.`, {
|
createLogEffect(
|
||||||
scope: LogScope.SYSTEM,
|
`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaRo} <M>${ACTION_NAME}</>를 명령하였습니다.`,
|
||||||
category: LogCategory.ACTION,
|
{
|
||||||
format: LogFormat.PLAIN,
|
scope: LogScope.SYSTEM,
|
||||||
}),
|
category: LogCategory.ACTION,
|
||||||
|
format: LogFormat.PLAIN,
|
||||||
|
}
|
||||||
|
),
|
||||||
// Global History Log
|
// Global History Log
|
||||||
createLogEffect(`<S><b>【${ACTION_NAME}】</b></><D><b>${nationName}</b></>${josaYiNation} <G><b>${destCityName}</b></>${josaRo} <M>${ACTION_NAME}</>하였습니다.`, {
|
createLogEffect(
|
||||||
scope: LogScope.SYSTEM,
|
`<S><b>【${ACTION_NAME}】</b></><D><b>${nationName}</b></>${josaYiNation} <G><b>${destCityName}</b></>${josaRo} <M>${ACTION_NAME}</>하였습니다.`,
|
||||||
category: LogCategory.HISTORY,
|
{
|
||||||
format: LogFormat.YEAR_MONTH,
|
scope: LogScope.SYSTEM,
|
||||||
}),
|
category: LogCategory.HISTORY,
|
||||||
|
format: LogFormat.YEAR_MONTH,
|
||||||
|
}
|
||||||
|
),
|
||||||
// Actor Nation History Log
|
// Actor Nation History Log
|
||||||
createLogEffect(`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaRo} <M>${ACTION_NAME}</> 명령`, {
|
createLogEffect(
|
||||||
scope: LogScope.NATION,
|
`<Y>${generalName}</>${josaYi} <G><b>${destCityName}</b></>${josaRo} <M>${ACTION_NAME}</> 명령`,
|
||||||
nationId: nation.id,
|
{
|
||||||
category: LogCategory.HISTORY,
|
scope: LogScope.NATION,
|
||||||
format: LogFormat.YEAR_MONTH,
|
nationId: nation.id,
|
||||||
}),
|
category: LogCategory.HISTORY,
|
||||||
|
format: LogFormat.YEAR_MONTH,
|
||||||
|
}
|
||||||
|
),
|
||||||
// General Action Log
|
// General Action Log
|
||||||
createLogEffect(`<G><b>${destCityName}</b></>${josaRo} ${ACTION_NAME}했습니다.`, {
|
createLogEffect(`<G><b>${destCityName}</b></>${josaRo} ${ACTION_NAME}했습니다.`, {
|
||||||
scope: LogScope.GENERAL,
|
scope: LogScope.GENERAL,
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export class NationTurnCommandLoader {
|
|||||||
|
|
||||||
constructor(
|
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);
|
const cached = this.cache.get(key);
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ import { describe, expect, it } from 'vitest';
|
|||||||
import type { City, General, Nation } from '../../../src/domain/entities.js';
|
import type { City, General, Nation } from '../../../src/domain/entities.js';
|
||||||
import { resolveGeneralAction } from '../../../src/actions/engine.js';
|
import { resolveGeneralAction } from '../../../src/actions/engine.js';
|
||||||
import { ActionDefinition as DeclareWarAction } from '../../../src/actions/turn/nation/che_선전포고.js';
|
import { ActionDefinition as DeclareWarAction } from '../../../src/actions/turn/nation/che_선전포고.js';
|
||||||
|
import { ActionDefinition as MoveCapitalAction } from '../../../src/actions/turn/nation/che_천도.js';
|
||||||
|
import { ActionDefinition as ChangeNationNameAction } from '../../../src/actions/turn/nation/che_국호변경.js';
|
||||||
|
import { ActionDefinition as ExpandCityAction } from '../../../src/actions/turn/nation/che_증축.js';
|
||||||
import { ActionDefinition as LastStandAction } from '../../../src/actions/turn/nation/che_필사즉생.js';
|
import { ActionDefinition as LastStandAction } from '../../../src/actions/turn/nation/che_필사즉생.js';
|
||||||
import { LogCategory, LogScope } from '../../../src/logging/types.js';
|
import { LogCategory, LogScope } from '../../../src/logging/types.js';
|
||||||
import type { MapDefinition } from '../../../src/world/types.js';
|
import type { MapDefinition } from '../../../src/world/types.js';
|
||||||
@@ -241,4 +244,91 @@ describe('Nation Actions', () => {
|
|||||||
expect(nation.meta.strategic_cmd_limit).toBeGreaterThan(0);
|
expect(nation.meta.strategic_cmd_limit).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('che_천도 (Move Capital)', () => {
|
||||||
|
it('changes nation capital city', () => {
|
||||||
|
const nation = buildNation(1);
|
||||||
|
const city1 = buildCity(1, 1);
|
||||||
|
const city2 = buildCity(2, 1);
|
||||||
|
const general = buildGeneral(1, 1, 1);
|
||||||
|
const env = { develCost: 100, baseGold: 100, baseRice: 100 };
|
||||||
|
const definition = new MoveCapitalAction(env as any);
|
||||||
|
|
||||||
|
const context = {
|
||||||
|
general,
|
||||||
|
nation,
|
||||||
|
city: city1,
|
||||||
|
destCity: city2,
|
||||||
|
rng: {} as any,
|
||||||
|
map: {
|
||||||
|
cities: [
|
||||||
|
{ id: 1, connections: [2] },
|
||||||
|
{ id: 2, connections: [1] },
|
||||||
|
],
|
||||||
|
} as any,
|
||||||
|
addLog: () => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const resolution = definition.resolve(context as any, { destCityID: 2 });
|
||||||
|
|
||||||
|
expect(resolution.effects).toContainEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
type: 'nation:patch',
|
||||||
|
patch: expect.objectContaining({ capitalCityId: 2 }),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('che_국호변경 (Change Nation Name)', () => {
|
||||||
|
it('changes nation name', () => {
|
||||||
|
const nation = buildNation(1, 'OldName');
|
||||||
|
const general = buildGeneral(1, 1, 1);
|
||||||
|
const definition = new ChangeNationNameAction();
|
||||||
|
|
||||||
|
const context = {
|
||||||
|
general,
|
||||||
|
nation,
|
||||||
|
rng: {} as any,
|
||||||
|
addLog: () => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const resolution = definition.resolve(context as any, { nationName: 'NewName' });
|
||||||
|
|
||||||
|
expect(resolution.effects).toContainEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
type: 'nation:patch',
|
||||||
|
patch: expect.objectContaining({ name: 'NewName' }),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('che_증축 (City Expansion)', () => {
|
||||||
|
it('increases city level and stats', () => {
|
||||||
|
const nation = buildNation(1);
|
||||||
|
const city = buildCity(1, 1);
|
||||||
|
city.level = 2;
|
||||||
|
const general = buildGeneral(1, 1, 1);
|
||||||
|
const env = { develCost: 100, baseGold: 100, baseRice: 100 };
|
||||||
|
const definition = new ExpandCityAction(env as any);
|
||||||
|
|
||||||
|
const context = {
|
||||||
|
general,
|
||||||
|
nation,
|
||||||
|
capitalCity: city,
|
||||||
|
rng: {} as any,
|
||||||
|
addLog: () => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const resolution = definition.resolve(context as any, {});
|
||||||
|
|
||||||
|
expect(resolution.effects).toContainEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
type: 'city:patch',
|
||||||
|
patch: expect.objectContaining({ level: 3 }),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user