feat: add Zod schema validation for command arguments in various action modules
- Introduced `argsSchema` property in `TurnCommandSpecBase` to enforce argument validation using Zod. - Refactored argument parsing in multiple action modules (e.g., `che_NPC능동`, `che_강행`, `che_건국`, etc.) to utilize Zod schemas for improved type safety and validation. - Removed redundant manual checks for argument types and replaced them with Zod's validation mechanisms. - Enhanced code maintainability and readability by centralizing argument validation logic.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
|
import type { ZodType } from 'zod';
|
||||||
import type { ActionContextBuilder } from './actionContext.js';
|
import type { ActionContextBuilder } from './actionContext.js';
|
||||||
import type { TurnCommandEnv } from './commandEnv.js';
|
import type { TurnCommandEnv } from './commandEnv.js';
|
||||||
|
|
||||||
@@ -7,6 +8,7 @@ export interface TurnCommandSpecBase<TKey extends string = string> {
|
|||||||
category: string;
|
category: string;
|
||||||
reqArg: boolean;
|
reqArg: boolean;
|
||||||
args: Record<string, unknown>;
|
args: Record<string, unknown>;
|
||||||
|
argsSchema?: ZodType<unknown>;
|
||||||
createDefinition(env: TurnCommandEnv): GeneralActionDefinition;
|
createDefinition(env: TurnCommandEnv): GeneralActionDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,6 @@ import type { GeneralTurnCommandSpec } from './index.js';
|
|||||||
import type { MapDefinition } from '@sammo-ts/logic/world/types.js';
|
import type { MapDefinition } from '@sammo-ts/logic/world/types.js';
|
||||||
import { parseArgsWithSchema } from '../parseArgs.js';
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
|
|
||||||
export interface NPCSelfArgs {
|
|
||||||
optionText: string;
|
|
||||||
destCityId?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type NPCSelfResolveContext<TriggerState extends GeneralTriggerState = GeneralTriggerState> =
|
export type NPCSelfResolveContext<TriggerState extends GeneralTriggerState = GeneralTriggerState> =
|
||||||
GeneralActionResolveContext<TriggerState> & {
|
GeneralActionResolveContext<TriggerState> & {
|
||||||
map?: MapDefinition;
|
map?: MapDefinition;
|
||||||
@@ -29,12 +24,13 @@ export type NPCSelfResolveContext<TriggerState extends GeneralTriggerState = Gen
|
|||||||
|
|
||||||
const ACTION_NAME = 'NPC능동';
|
const ACTION_NAME = 'NPC능동';
|
||||||
const ACTION_KEY = 'che_NPC능동';
|
const ACTION_KEY = 'che_NPC능동';
|
||||||
const NPC_SELF_ARGS_SCHEMA = z.discriminatedUnion('optionText', [
|
const ARGS_SCHEMA = z.discriminatedUnion('optionText', [
|
||||||
z.object({
|
z.object({
|
||||||
optionText: z.literal('순간이동'),
|
optionText: z.literal('순간이동'),
|
||||||
destCityId: z.number(),
|
destCityId: z.number(),
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
export type NPCSelfArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
export class ActionResolver<
|
export class ActionResolver<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -98,7 +94,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): NPCSelfArgs | null {
|
parseArgs(raw: unknown): NPCSelfArgs | null {
|
||||||
return parseArgsWithSchema(NPC_SELF_ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: NPCSelfArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: NPCSelfArgs): Constraint[] {
|
||||||
@@ -121,5 +117,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '특수', // Valid category? Legacy didn't specify category in static prop usually, handled by mapping. Defaulting to '특수'.
|
category: '특수', // Valid category? Legacy didn't specify category in static prop usually, handled by mapping. Defaulting to '특수'.
|
||||||
reqArg: true,
|
reqArg: true,
|
||||||
args: { optionText: '', destCityId: 0 },
|
args: { optionText: '', destCityId: 0 },
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,10 +24,6 @@ import type { MapDefinition } from '@sammo-ts/logic/world/types.js';
|
|||||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import { parseArgsWithSchema } from '../parseArgs.js';
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
|
|
||||||
export interface ForcedMoveArgs {
|
|
||||||
destCityId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ForcedMoveResolveContext<
|
export interface ForcedMoveResolveContext<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
> extends GeneralActionResolveContext<TriggerState> {
|
> extends GeneralActionResolveContext<TriggerState> {
|
||||||
@@ -38,9 +34,10 @@ export interface ForcedMoveResolveContext<
|
|||||||
|
|
||||||
const ACTION_NAME = '강행';
|
const ACTION_NAME = '강행';
|
||||||
const ACTION_KEY = 'che_강행';
|
const ACTION_KEY = 'che_강행';
|
||||||
const FORCED_MOVE_ARGS_SCHEMA = z.object({
|
const ARGS_SCHEMA = z.object({
|
||||||
destCityId: z.number(),
|
destCityId: z.number(),
|
||||||
});
|
});
|
||||||
|
export type ForcedMoveArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
export class ActionResolver<
|
export class ActionResolver<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -164,7 +161,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): ForcedMoveArgs | null {
|
parseArgs(raw: unknown): ForcedMoveArgs | null {
|
||||||
return parseArgsWithSchema(FORCED_MOVE_ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(ctx: ConstraintContext, _args: ForcedMoveArgs): Constraint[] {
|
buildConstraints(ctx: ConstraintContext, _args: ForcedMoveArgs): Constraint[] {
|
||||||
@@ -199,5 +196,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '군사',
|
category: '군사',
|
||||||
reqArg: true,
|
reqArg: true,
|
||||||
args: { destCityId: 0 },
|
args: { destCityId: 0 },
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,17 +17,19 @@ import {
|
|||||||
createNationPatchEffect,
|
createNationPatchEffect,
|
||||||
} from '@sammo-ts/logic/actions/engine.js';
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||||
|
import { z } from 'zod';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
export interface FoundingArgs {
|
|
||||||
nationName: string;
|
|
||||||
nationType: string;
|
|
||||||
colorType: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ACTION_NAME = '건국';
|
const ACTION_NAME = '건국';
|
||||||
|
const ARGS_SCHEMA = z.object({
|
||||||
|
nationName: z.string().min(1),
|
||||||
|
nationType: z.string().min(1),
|
||||||
|
colorType: z.number(),
|
||||||
|
});
|
||||||
|
export type FoundingArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
const NATION_COLORS = [
|
const NATION_COLORS = [
|
||||||
'#FF0000',
|
'#FF0000',
|
||||||
@@ -72,13 +74,7 @@ export class ActionDefinition<
|
|||||||
public readonly name = ACTION_NAME;
|
public readonly name = ACTION_NAME;
|
||||||
|
|
||||||
parseArgs(raw: unknown): FoundingArgs | null {
|
parseArgs(raw: unknown): FoundingArgs | null {
|
||||||
if (typeof raw !== 'object' || raw === null) return null;
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
const { nationName, nationType, colorType } = raw as Record<string, unknown>;
|
|
||||||
if (typeof nationName !== 'string' || !nationName) return null;
|
|
||||||
if (typeof nationType !== 'string' || !nationType) return null;
|
|
||||||
if (typeof colorType !== 'number') return null;
|
|
||||||
|
|
||||||
return { nationName, nationType, colorType };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: FoundingArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: FoundingArgs): Constraint[] {
|
||||||
@@ -174,5 +170,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
nationType: 'string',
|
nationType: 'string',
|
||||||
colorType: 'number',
|
colorType: 'number',
|
||||||
},
|
},
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,14 +4,11 @@ import { occupiedCity, reqGeneralGold, reqGeneralRice } from '@sammo-ts/logic/co
|
|||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.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 { LogFormat } from '@sammo-ts/logic/logging/types.js';
|
import { LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||||
|
import { z } from 'zod';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
export interface TradeArgs {
|
|
||||||
buyRice: boolean;
|
|
||||||
amount: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TradeEnvironment {
|
export interface TradeEnvironment {
|
||||||
exchangeFee?: number;
|
exchangeFee?: number;
|
||||||
@@ -19,6 +16,11 @@ export interface TradeEnvironment {
|
|||||||
|
|
||||||
const ACTION_NAME = '군량매매';
|
const ACTION_NAME = '군량매매';
|
||||||
const DEFAULT_EXCHANGE_FEE = 0.01;
|
const DEFAULT_EXCHANGE_FEE = 0.01;
|
||||||
|
const ARGS_SCHEMA = z.object({
|
||||||
|
buyRice: z.boolean(),
|
||||||
|
amount: z.number(),
|
||||||
|
});
|
||||||
|
export type TradeArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
export class ActionDefinition<
|
export class ActionDefinition<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -32,16 +34,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): TradeArgs | null {
|
parseArgs(raw: unknown): TradeArgs | null {
|
||||||
if (typeof raw !== 'object' || raw === null) {
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const record = raw as Record<string, unknown>;
|
|
||||||
const buyRice = record.buyRice;
|
|
||||||
const amount = record.amount;
|
|
||||||
if (typeof buyRice !== 'boolean' || typeof amount !== 'number') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return { buyRice, amount };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: TradeArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: TradeArgs): Constraint[] {
|
||||||
@@ -129,5 +122,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
buyRice: 'boolean',
|
buyRice: 'boolean',
|
||||||
amount: 'number',
|
amount: 'number',
|
||||||
},
|
},
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,13 +16,11 @@ import type {
|
|||||||
} from '@sammo-ts/logic/actions/engine.js';
|
} 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 { LogCategory, LogScope } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||||
|
import { z } from 'zod';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
export interface EmployArgs {
|
|
||||||
destGeneralId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EmployResolveContext<
|
export interface EmployResolveContext<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -33,6 +31,10 @@ export interface EmployResolveContext<
|
|||||||
|
|
||||||
const ACTION_NAME = '등용';
|
const ACTION_NAME = '등용';
|
||||||
const ACTION_KEY = 'che_등용';
|
const ACTION_KEY = 'che_등용';
|
||||||
|
const ARGS_SCHEMA = z.object({
|
||||||
|
destGeneralId: z.number(),
|
||||||
|
});
|
||||||
|
export type EmployArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
const differentNationDestGeneral = (): Constraint => ({
|
const differentNationDestGeneral = (): Constraint => ({
|
||||||
name: 'DifferentNationDestGeneral',
|
name: 'DifferentNationDestGeneral',
|
||||||
@@ -145,9 +147,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): EmployArgs | null {
|
parseArgs(raw: unknown): EmployArgs | null {
|
||||||
const data = raw as Partial<EmployArgs>;
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
if (typeof data.destGeneralId !== 'number') return null;
|
|
||||||
return { destGeneralId: data.destGeneralId };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: EmployArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: EmployArgs): Constraint[] {
|
||||||
@@ -205,5 +205,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '인사',
|
category: '인사',
|
||||||
reqArg: true,
|
reqArg: true,
|
||||||
args: { destGeneralId: 0 },
|
args: { destGeneralId: 0 },
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env),
|
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,17 +18,19 @@ import type {
|
|||||||
import { createGeneralPatchEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
import { createGeneralPatchEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
|
import { z } from 'zod';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
export interface AcceptScoutArgs {
|
|
||||||
destNationId: number;
|
|
||||||
destGeneralId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ACTION_NAME = '등용수락';
|
const ACTION_NAME = '등용수락';
|
||||||
const ACTION_KEY = 'che_등용수락';
|
const ACTION_KEY = 'che_등용수락';
|
||||||
|
const ARGS_SCHEMA = z.object({
|
||||||
|
destNationId: z.number(),
|
||||||
|
destGeneralId: z.number(),
|
||||||
|
});
|
||||||
|
export type AcceptScoutArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
export interface AcceptScoutResolveContext<
|
export interface AcceptScoutResolveContext<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -180,9 +182,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): AcceptScoutArgs | null {
|
parseArgs(raw: unknown): AcceptScoutArgs | null {
|
||||||
const args = raw as Partial<AcceptScoutArgs>;
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
if (typeof args.destNationId !== 'number' || typeof args.destGeneralId !== 'number') return null;
|
|
||||||
return { destNationId: args.destNationId, destGeneralId: args.destGeneralId };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: AcceptScoutArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: AcceptScoutArgs): Constraint[] {
|
||||||
@@ -224,5 +224,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
destNationId: 'number',
|
destNationId: 'number',
|
||||||
destGeneralId: 'number',
|
destGeneralId: 'number',
|
||||||
},
|
},
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env),
|
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,14 +16,12 @@ import type {
|
|||||||
} from '@sammo-ts/logic/actions/engine.js';
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { createGeneralPatchEffect, createCityPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
import { createGeneralPatchEffect, createCityPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||||
|
import { z } from 'zod';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
export interface AgitateArgs {
|
|
||||||
destCityId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AgitateResolveContext<
|
export interface AgitateResolveContext<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -34,6 +32,10 @@ export interface AgitateResolveContext<
|
|||||||
|
|
||||||
const ACTION_NAME = '선동';
|
const ACTION_NAME = '선동';
|
||||||
const ACTION_KEY = 'che_선동';
|
const ACTION_KEY = 'che_선동';
|
||||||
|
const ARGS_SCHEMA = z.object({
|
||||||
|
destCityId: z.number(),
|
||||||
|
});
|
||||||
|
export type AgitateArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
export class ActionResolver<
|
export class ActionResolver<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -130,9 +132,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): AgitateArgs | null {
|
parseArgs(raw: unknown): AgitateArgs | null {
|
||||||
const data = raw as Partial<AgitateArgs>;
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
if (typeof data.destCityId !== 'number') return null;
|
|
||||||
return { destCityId: data.destCityId };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(ctx: ConstraintContext, _args: AgitateArgs): Constraint[] {
|
buildConstraints(ctx: ConstraintContext, _args: AgitateArgs): Constraint[] {
|
||||||
@@ -170,5 +170,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '군사',
|
category: '군사',
|
||||||
reqArg: true,
|
reqArg: true,
|
||||||
args: { destCityId: 0 },
|
args: { destCityId: 0 },
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env),
|
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,11 +9,8 @@ import type { GeneralTurnCommandSpec } from './index.js';
|
|||||||
import type { UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
|
import type { UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
import { getMetaNumber, setMetaNumber, increaseMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
import { getMetaNumber, setMetaNumber, increaseMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
||||||
|
import { z } from 'zod';
|
||||||
export interface DexTransferArgs {
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
srcArmType: number;
|
|
||||||
destArmType: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DexTransferContext<
|
export interface DexTransferContext<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -28,16 +25,13 @@ export interface DexTransferEnvironment {
|
|||||||
const ACTION_NAME = '숙련전환';
|
const ACTION_NAME = '숙련전환';
|
||||||
const DECREASE_COEFF = 0.4;
|
const DECREASE_COEFF = 0.4;
|
||||||
const CONVERT_COEFF = 0.9;
|
const CONVERT_COEFF = 0.9;
|
||||||
|
const ARGS_SCHEMA = z
|
||||||
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
.object({
|
||||||
value !== null && typeof value === 'object' && !Array.isArray(value);
|
srcArmType: z.number().int().positive(),
|
||||||
|
destArmType: z.number().int().positive(),
|
||||||
const resolveArmType = (value: unknown): number | null => {
|
})
|
||||||
if (typeof value !== 'number' || !Number.isInteger(value)) {
|
.refine((data) => data.srcArmType !== data.destArmType);
|
||||||
return null;
|
export type DexTransferArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
}
|
|
||||||
return value > 0 ? value : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const resolveArmTypeName = (unitSet: UnitSetDefinition | null | undefined, armType: number): string =>
|
const resolveArmTypeName = (unitSet: UnitSetDefinition | null | undefined, armType: number): string =>
|
||||||
unitSet?.armTypes?.[String(armType)] ?? `병종${armType}`;
|
unitSet?.armTypes?.[String(armType)] ?? `병종${armType}`;
|
||||||
@@ -54,16 +48,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): DexTransferArgs | null {
|
parseArgs(raw: unknown): DexTransferArgs | null {
|
||||||
const data = isRecord(raw) ? raw : {};
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
const srcArmType = resolveArmType(data.srcArmType);
|
|
||||||
const destArmType = resolveArmType(data.destArmType);
|
|
||||||
if (srcArmType === null || destArmType === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (srcArmType === destArmType) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return { srcArmType, destArmType };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: DexTransferArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: DexTransferArgs): Constraint[] {
|
||||||
@@ -110,5 +95,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '군사',
|
category: '군사',
|
||||||
reqArg: true,
|
reqArg: true,
|
||||||
args: { srcArmType: 0, destArmType: 0 },
|
args: { srcArmType: 0, destArmType: 0 },
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition({ develCost: env.develCost }),
|
createDefinition: (env: TurnCommandEnv) => new ActionDefinition({ develCost: env.develCost }),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,10 +24,6 @@ import type { GeneralTurnCommandSpec } from './index.js';
|
|||||||
import type { MapDefinition } from '@sammo-ts/logic/world/types.js';
|
import type { MapDefinition } from '@sammo-ts/logic/world/types.js';
|
||||||
import { parseArgsWithSchema } from '../parseArgs.js';
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
|
|
||||||
export interface MoveArgs {
|
|
||||||
destCityId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MoveResolveContext<
|
export interface MoveResolveContext<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
> extends GeneralActionResolveContext<TriggerState> {
|
> extends GeneralActionResolveContext<TriggerState> {
|
||||||
@@ -38,9 +34,10 @@ export interface MoveResolveContext<
|
|||||||
|
|
||||||
const ACTION_NAME = '이동';
|
const ACTION_NAME = '이동';
|
||||||
const ACTION_KEY = 'che_이동';
|
const ACTION_KEY = 'che_이동';
|
||||||
const MOVE_ARGS_SCHEMA = z.object({
|
const ARGS_SCHEMA = z.object({
|
||||||
destCityId: z.number(),
|
destCityId: z.number(),
|
||||||
});
|
});
|
||||||
|
export type MoveArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
// Helper for map connectivity
|
// Helper for map connectivity
|
||||||
const connectedCity = (): Constraint => ({
|
const connectedCity = (): Constraint => ({
|
||||||
@@ -160,7 +157,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): MoveArgs | null {
|
parseArgs(raw: unknown): MoveArgs | null {
|
||||||
return parseArgsWithSchema(MOVE_ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(ctx: ConstraintContext, _args: MoveArgs): Constraint[] {
|
buildConstraints(ctx: ConstraintContext, _args: MoveArgs): Constraint[] {
|
||||||
@@ -195,5 +192,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '군사',
|
category: '군사',
|
||||||
reqArg: true,
|
reqArg: true,
|
||||||
args: { destCityId: 0 },
|
args: { destCityId: 0 },
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,15 +5,17 @@ import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition
|
|||||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { createGeneralPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
import { createGeneralPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||||
|
import { z } from 'zod';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
export interface AppointmentArgs {
|
|
||||||
destNationId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ACTION_NAME = '임관';
|
const ACTION_NAME = '임관';
|
||||||
|
const ARGS_SCHEMA = z.object({
|
||||||
|
destNationId: z.number(),
|
||||||
|
});
|
||||||
|
export type AppointmentArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
const parseNationId = (raw: unknown): number | null => {
|
const parseNationId = (raw: unknown): number | null => {
|
||||||
if (typeof raw !== 'number' || !Number.isFinite(raw)) {
|
if (typeof raw !== 'number' || !Number.isFinite(raw)) {
|
||||||
@@ -29,8 +31,11 @@ export class ActionDefinition<
|
|||||||
public readonly name = ACTION_NAME;
|
public readonly name = ACTION_NAME;
|
||||||
|
|
||||||
parseArgs(raw: unknown): AppointmentArgs | null {
|
parseArgs(raw: unknown): AppointmentArgs | null {
|
||||||
const data = raw as { destNationId?: unknown };
|
const data = parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
const destNationId = parseNationId(data?.destNationId);
|
if (!data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const destNationId = parseNationId(data.destNationId);
|
||||||
if (destNationId === null) {
|
if (destNationId === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -69,5 +74,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '전략',
|
category: '전략',
|
||||||
reqArg: true,
|
reqArg: true,
|
||||||
args: { destNationId: 0 },
|
args: { destNationId: 0 },
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import type {
|
|||||||
import type { MapDefinition, UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
|
import type { MapDefinition, UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
|
||||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import { resolveStartYear } from '@sammo-ts/logic/actions/turn/actionContextHelpers.js';
|
import { resolveStartYear } from '@sammo-ts/logic/actions/turn/actionContextHelpers.js';
|
||||||
|
import { z } from 'zod';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import {
|
import {
|
||||||
@@ -27,11 +28,7 @@ import {
|
|||||||
getTechCost,
|
getTechCost,
|
||||||
isCrewTypeAvailable,
|
isCrewTypeAvailable,
|
||||||
} from '@sammo-ts/logic/world/unitSet.js';
|
} from '@sammo-ts/logic/world/unitSet.js';
|
||||||
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
export interface RecruitArgs {
|
|
||||||
crewType: number;
|
|
||||||
amount: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RecruitEnvironment {
|
export interface RecruitEnvironment {
|
||||||
costOffset?: number;
|
costOffset?: number;
|
||||||
@@ -58,9 +55,27 @@ const DEFAULT_ATMOS = 40;
|
|||||||
const DEFAULT_MIN_POP = 30000;
|
const DEFAULT_MIN_POP = 30000;
|
||||||
const DEFAULT_TRUST = 50;
|
const DEFAULT_TRUST = 50;
|
||||||
const MIN_CREW = 100;
|
const MIN_CREW = 100;
|
||||||
|
const ARGS_SCHEMA = z.preprocess(
|
||||||
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
(raw) => {
|
||||||
value !== null && typeof value === 'object' && !Array.isArray(value);
|
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
const record = raw as Record<string, unknown>;
|
||||||
|
const crewType = record.crewType ?? record.crewTypeId;
|
||||||
|
return { ...record, crewType };
|
||||||
|
},
|
||||||
|
z.object({
|
||||||
|
crewType: z.preprocess(
|
||||||
|
(value) => (typeof value === 'number' ? Math.floor(value) : value),
|
||||||
|
z.number().int().positive()
|
||||||
|
),
|
||||||
|
amount: z.preprocess(
|
||||||
|
(value) => (typeof value === 'number' ? Math.floor(value) : value),
|
||||||
|
z.number().int().min(0)
|
||||||
|
),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
export type RecruitArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
const clamp = (value: number, min: number | null, max: number | null): number => {
|
const clamp = (value: number, min: number | null, max: number | null): number => {
|
||||||
if (max !== null && min !== null && max < min) {
|
if (max !== null && min !== null && max < min) {
|
||||||
@@ -401,13 +416,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): RecruitArgs | null {
|
parseArgs(raw: unknown): RecruitArgs | null {
|
||||||
const data = isRecord(raw) ? raw : {};
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
const crewTypeId = resolveCrewTypeId(data);
|
|
||||||
const amount = resolveCrewAmount(data);
|
|
||||||
if (crewTypeId === null || amount === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return { crewType: crewTypeId, amount };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(ctx: ConstraintContext, _args: RecruitArgs): Constraint[] {
|
buildConstraints(ctx: ConstraintContext, _args: RecruitArgs): Constraint[] {
|
||||||
@@ -528,5 +537,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '내정',
|
category: '내정',
|
||||||
reqArg: true,
|
reqArg: true,
|
||||||
args: {},
|
args: {},
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.generalActionModules ?? [], {}),
|
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.generalActionModules ?? [], {}),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,14 +16,12 @@ import type {
|
|||||||
} from '@sammo-ts/logic/actions/engine.js';
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { createGeneralPatchEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
import { createGeneralPatchEffect, 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 { z } from 'zod';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import type { MapDefinition } from '@sammo-ts/logic/world/types.js';
|
import type { MapDefinition } from '@sammo-ts/logic/world/types.js';
|
||||||
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
export interface SpyArgs {
|
|
||||||
destCityId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SpyResolveContext<
|
export interface SpyResolveContext<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -35,6 +33,10 @@ export interface SpyResolveContext<
|
|||||||
|
|
||||||
const ACTION_NAME = '첩보';
|
const ACTION_NAME = '첩보';
|
||||||
const ACTION_KEY = 'che_첩보';
|
const ACTION_KEY = 'che_첩보';
|
||||||
|
const ARGS_SCHEMA = z.object({
|
||||||
|
destCityId: z.number(),
|
||||||
|
});
|
||||||
|
export type SpyArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
export class ActionResolver<
|
export class ActionResolver<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -126,9 +128,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): SpyArgs | null {
|
parseArgs(raw: unknown): SpyArgs | null {
|
||||||
const data = raw as Partial<SpyArgs>;
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
if (typeof data.destCityId !== 'number') return null;
|
|
||||||
return { destCityId: data.destCityId };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(ctx: ConstraintContext, _args: SpyArgs): Constraint[] {
|
buildConstraints(ctx: ConstraintContext, _args: SpyArgs): Constraint[] {
|
||||||
@@ -167,5 +167,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '군사',
|
category: '군사',
|
||||||
reqArg: true,
|
reqArg: true,
|
||||||
args: { destCityId: 0 },
|
args: { destCityId: 0 },
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
createNationPatchEffect,
|
createNationPatchEffect,
|
||||||
} from '@sammo-ts/logic/actions/engine.js';
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { JosaUtil, LiteHashDRBG } from '@sammo-ts/common';
|
import { JosaUtil, LiteHashDRBG } from '@sammo-ts/common';
|
||||||
|
import { z } from 'zod';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import type { WarAftermathConfig, WarEngineConfig, WarTimeContext } from '@sammo-ts/logic/war/types.js';
|
import type { WarAftermathConfig, WarEngineConfig, WarTimeContext } from '@sammo-ts/logic/war/types.js';
|
||||||
@@ -40,10 +41,7 @@ import {
|
|||||||
buildWarConfig,
|
buildWarConfig,
|
||||||
buildWarTime,
|
buildWarTime,
|
||||||
} from '@sammo-ts/logic/actions/turn/actionContextHelpers.js';
|
} from '@sammo-ts/logic/actions/turn/actionContextHelpers.js';
|
||||||
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
export interface DispatchArgs {
|
|
||||||
destCityId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DispatchResolveContext<
|
export interface DispatchResolveContext<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -63,6 +61,10 @@ export interface DispatchResolveContext<
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ACTION_NAME = '출병';
|
const ACTION_NAME = '출병';
|
||||||
|
const ARGS_SCHEMA = z.object({
|
||||||
|
destCityId: z.number(),
|
||||||
|
});
|
||||||
|
export type DispatchArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
const parseCityId = (raw: unknown): number | null => {
|
const parseCityId = (raw: unknown): number | null => {
|
||||||
if (typeof raw !== 'number' || !Number.isFinite(raw)) {
|
if (typeof raw !== 'number' || !Number.isFinite(raw)) {
|
||||||
@@ -247,8 +249,11 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): DispatchArgs | null {
|
parseArgs(raw: unknown): DispatchArgs | null {
|
||||||
const data = raw as { destCityId?: unknown };
|
const data = parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
const destCityId = parseCityId(data?.destCityId);
|
if (!data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const destCityId = parseCityId(data.destCityId);
|
||||||
if (destCityId === null) {
|
if (destCityId === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -534,5 +539,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '군사',
|
category: '군사',
|
||||||
reqArg: true,
|
reqArg: true,
|
||||||
args: { destCityId: 0 },
|
args: { destCityId: 0 },
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.warActionModules ?? []),
|
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.warActionModules ?? []),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,14 +20,12 @@ import {
|
|||||||
createNationPatchEffect,
|
createNationPatchEffect,
|
||||||
} from '@sammo-ts/logic/actions/engine.js';
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||||
|
import { z } from 'zod';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
export interface SeizeArgs {
|
|
||||||
destCityId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SeizeResolveContext<
|
export interface SeizeResolveContext<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -40,6 +38,10 @@ export interface SeizeResolveContext<
|
|||||||
|
|
||||||
const ACTION_NAME = '탈취';
|
const ACTION_NAME = '탈취';
|
||||||
const ACTION_KEY = 'che_탈취';
|
const ACTION_KEY = 'che_탈취';
|
||||||
|
const ARGS_SCHEMA = z.object({
|
||||||
|
destCityId: z.number(),
|
||||||
|
});
|
||||||
|
export type SeizeArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
export class ActionResolver<
|
export class ActionResolver<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -194,9 +196,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): SeizeArgs | null {
|
parseArgs(raw: unknown): SeizeArgs | null {
|
||||||
const data = raw as Partial<SeizeArgs>;
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
if (typeof data.destCityId !== 'number') return null;
|
|
||||||
return { destCityId: data.destCityId };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(ctx: ConstraintContext, _args: SeizeArgs): Constraint[] {
|
buildConstraints(ctx: ConstraintContext, _args: SeizeArgs): Constraint[] {
|
||||||
@@ -240,5 +240,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '군사',
|
category: '군사',
|
||||||
reqArg: true,
|
reqArg: true,
|
||||||
args: { destCityId: 0 },
|
args: { destCityId: 0 },
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env),
|
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,14 +16,12 @@ import type {
|
|||||||
} from '@sammo-ts/logic/actions/engine.js';
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { createGeneralPatchEffect, createCityPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
import { createGeneralPatchEffect, createCityPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||||
|
import { z } from 'zod';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
export interface DestroyArgs {
|
|
||||||
destCityId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DestroyResolveContext<
|
export interface DestroyResolveContext<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -34,6 +32,10 @@ export interface DestroyResolveContext<
|
|||||||
|
|
||||||
const ACTION_NAME = '파괴';
|
const ACTION_NAME = '파괴';
|
||||||
const ACTION_KEY = 'che_파괴';
|
const ACTION_KEY = 'che_파괴';
|
||||||
|
const ARGS_SCHEMA = z.object({
|
||||||
|
destCityId: z.number(),
|
||||||
|
});
|
||||||
|
export type DestroyArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
export class ActionResolver<
|
export class ActionResolver<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -127,9 +129,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): DestroyArgs | null {
|
parseArgs(raw: unknown): DestroyArgs | null {
|
||||||
const data = raw as Partial<DestroyArgs>;
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
if (typeof data.destCityId !== 'number') return null;
|
|
||||||
return { destCityId: data.destCityId };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(ctx: ConstraintContext, _args: DestroyArgs): Constraint[] {
|
buildConstraints(ctx: ConstraintContext, _args: DestroyArgs): Constraint[] {
|
||||||
@@ -167,5 +167,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '군사',
|
category: '군사',
|
||||||
reqArg: true,
|
reqArg: true,
|
||||||
args: { destCityId: 0 },
|
args: { destCityId: 0 },
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env),
|
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,17 +14,19 @@ import type {
|
|||||||
} from '@sammo-ts/logic/actions/engine.js';
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { createGeneralPatchEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
import { createGeneralPatchEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||||
|
import { z } from 'zod';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
export interface DonateArgs {
|
|
||||||
isGold: boolean;
|
|
||||||
amount: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ACTION_NAME = '헌납';
|
const ACTION_NAME = '헌납';
|
||||||
const ACTION_KEY = 'che_헌납';
|
const ACTION_KEY = 'che_헌납';
|
||||||
|
const ARGS_SCHEMA = z.object({
|
||||||
|
isGold: z.boolean(),
|
||||||
|
amount: z.number(),
|
||||||
|
});
|
||||||
|
export type DonateArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
|
|
||||||
export class ActionResolver<
|
export class ActionResolver<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -91,9 +93,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): DonateArgs | null {
|
parseArgs(raw: unknown): DonateArgs | null {
|
||||||
const data = raw as Partial<DonateArgs>;
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
if (typeof data.isGold !== 'boolean' || typeof data.amount !== 'number') return null;
|
|
||||||
return { isGold: data.isGold, amount: data.amount };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: DonateArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: DonateArgs): Constraint[] {
|
||||||
@@ -115,5 +115,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '내정',
|
category: '내정',
|
||||||
reqArg: true,
|
reqArg: true,
|
||||||
args: { isGold: true, amount: 0 },
|
args: { isGold: true, amount: 0 },
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
createDefinition: (_env: TurnCommandEnv) => new ActionDefinition(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,14 +23,12 @@ import type {
|
|||||||
} from '@sammo-ts/logic/actions/engine.js';
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { createCityPatchEffect, createGeneralPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
import { 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 { z } from 'zod';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import { clamp } from 'es-toolkit';
|
import { clamp } from 'es-toolkit';
|
||||||
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
export interface FireAttackArgs {
|
|
||||||
destCityId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FireAttackEnvironment {
|
export interface FireAttackEnvironment {
|
||||||
develCost: number;
|
develCost: number;
|
||||||
@@ -84,6 +82,10 @@ export interface FireAttackResult<TriggerState extends GeneralTriggerState = Gen
|
|||||||
|
|
||||||
const ACTION_NAME = '화계';
|
const ACTION_NAME = '화계';
|
||||||
const ACTION_KEY = '계략';
|
const ACTION_KEY = '계략';
|
||||||
|
const ARGS_SCHEMA = z.object({
|
||||||
|
destCityId: z.number(),
|
||||||
|
});
|
||||||
|
export type FireAttackArgs = z.infer<typeof ARGS_SCHEMA>;
|
||||||
const STAT_EXP_KEY = 'intel_exp';
|
const STAT_EXP_KEY = 'intel_exp';
|
||||||
const DEFAULT_MAX_PROB = 0.5;
|
const DEFAULT_MAX_PROB = 0.5;
|
||||||
const INJURY_MAX = 80;
|
const INJURY_MAX = 80;
|
||||||
@@ -357,14 +359,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): FireAttackArgs | null {
|
parseArgs(raw: unknown): FireAttackArgs | null {
|
||||||
if (!raw || typeof raw !== 'object') {
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const destCityId = (raw as { destCityId?: unknown }).destCityId;
|
|
||||||
if (typeof destCityId !== 'number' || Number.isNaN(destCityId)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return { destCityId };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: FireAttackArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: FireAttackArgs): Constraint[] {
|
||||||
@@ -399,5 +394,6 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '계략',
|
category: '계략',
|
||||||
reqArg: true,
|
reqArg: true,
|
||||||
args: { destCityId: 0 },
|
args: { destCityId: 0 },
|
||||||
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.generalActionModules ?? [], env),
|
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.generalActionModules ?? [], env),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user