buildMinConstraints 구현
This commit is contained in:
@@ -184,6 +184,8 @@ const buildCommandEnv = (worldState: WorldStateRow): CommandEnv => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const buildConstraintEnv = (worldState: WorldStateRow): Record<string, unknown> => {
|
const buildConstraintEnv = (worldState: WorldStateRow): Record<string, unknown> => {
|
||||||
|
const config = asRecord(worldState.config);
|
||||||
|
const constValues = asRecord(config.const);
|
||||||
const meta = asRecord(worldState.meta);
|
const meta = asRecord(worldState.meta);
|
||||||
const scenarioMeta = asRecord(meta.scenarioMeta);
|
const scenarioMeta = asRecord(meta.scenarioMeta);
|
||||||
const startYear = typeof scenarioMeta.startYear === 'number' ? scenarioMeta.startYear : undefined;
|
const startYear = typeof scenarioMeta.startYear === 'number' ? scenarioMeta.startYear : undefined;
|
||||||
@@ -196,6 +198,7 @@ const buildConstraintEnv = (worldState: WorldStateRow): Record<string, unknown>
|
|||||||
month: worldState.currentMonth,
|
month: worldState.currentMonth,
|
||||||
startYear,
|
startYear,
|
||||||
relYear,
|
relYear,
|
||||||
|
openingPartYear: resolveNumber(constValues, ['openingPartYear'], 0),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -352,7 +355,10 @@ const evaluateDefinition = (
|
|||||||
reqArg: boolean,
|
reqArg: boolean,
|
||||||
args: unknown
|
args: unknown
|
||||||
): AvailabilityCore => {
|
): AvailabilityCore => {
|
||||||
const constraints = definition.buildConstraints(ctx, args);
|
const constraints =
|
||||||
|
ctx.mode === 'precheck' && definition.buildMinConstraints
|
||||||
|
? definition.buildMinConstraints(ctx, args)
|
||||||
|
: definition.buildConstraints(ctx, args);
|
||||||
return evaluateAvailability(constraints, ctx, view, reqArg);
|
return evaluateAvailability(constraints, ctx, view, reqArg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
import type { CityRow, GeneralRow, NationRow, WorldStateRow } from '../src/context.js';
|
||||||
|
import { buildTurnCommandTable } from '../src/turns/commandTable.js';
|
||||||
|
|
||||||
|
const buildWorldState = (): WorldStateRow =>
|
||||||
|
({
|
||||||
|
id: 1,
|
||||||
|
scenarioCode: 'default',
|
||||||
|
currentYear: 3,
|
||||||
|
currentMonth: 1,
|
||||||
|
tickSeconds: 600,
|
||||||
|
config: {
|
||||||
|
const: {
|
||||||
|
baseGold: 1000,
|
||||||
|
baseRice: 1000,
|
||||||
|
develCost: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
meta: {
|
||||||
|
scenarioMeta: {
|
||||||
|
startYear: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
updatedAt: new Date('2026-01-01T00:00:00Z'),
|
||||||
|
}) as unknown as WorldStateRow;
|
||||||
|
|
||||||
|
const buildGeneral = (): GeneralRow =>
|
||||||
|
({
|
||||||
|
id: 1,
|
||||||
|
name: 'TestGeneral',
|
||||||
|
nationId: 1,
|
||||||
|
cityId: 1,
|
||||||
|
troopId: 0,
|
||||||
|
leadership: 70,
|
||||||
|
strength: 60,
|
||||||
|
intel: 60,
|
||||||
|
experience: 0,
|
||||||
|
dedication: 0,
|
||||||
|
officerLevel: 6,
|
||||||
|
personalCode: null,
|
||||||
|
specialCode: null,
|
||||||
|
special2Code: null,
|
||||||
|
horseCode: null,
|
||||||
|
weaponCode: null,
|
||||||
|
bookCode: null,
|
||||||
|
itemCode: null,
|
||||||
|
injury: 0,
|
||||||
|
gold: 0,
|
||||||
|
rice: 0,
|
||||||
|
crew: 100,
|
||||||
|
crewTypeId: 1100,
|
||||||
|
train: 0,
|
||||||
|
atmos: 0,
|
||||||
|
age: 25,
|
||||||
|
npcState: 0,
|
||||||
|
meta: {},
|
||||||
|
}) as unknown as GeneralRow;
|
||||||
|
|
||||||
|
const buildCity = (): CityRow =>
|
||||||
|
({
|
||||||
|
id: 1,
|
||||||
|
name: 'TestCity',
|
||||||
|
nationId: 1,
|
||||||
|
level: 5,
|
||||||
|
population: 100000,
|
||||||
|
populationMax: 200000,
|
||||||
|
agriculture: 1000,
|
||||||
|
agricultureMax: 2000,
|
||||||
|
commerce: 1000,
|
||||||
|
commerceMax: 2000,
|
||||||
|
security: 1000,
|
||||||
|
securityMax: 2000,
|
||||||
|
supplyState: 1,
|
||||||
|
frontState: 0,
|
||||||
|
defence: 0,
|
||||||
|
defenceMax: 0,
|
||||||
|
wall: 0,
|
||||||
|
wallMax: 0,
|
||||||
|
meta: {},
|
||||||
|
trust: 50,
|
||||||
|
trade: 0,
|
||||||
|
region: 0,
|
||||||
|
}) as unknown as CityRow;
|
||||||
|
|
||||||
|
const buildNation = (): NationRow =>
|
||||||
|
({
|
||||||
|
id: 1,
|
||||||
|
name: 'TestNation',
|
||||||
|
color: '#000000',
|
||||||
|
capitalCityId: 1,
|
||||||
|
gold: 0,
|
||||||
|
rice: 0,
|
||||||
|
level: 1,
|
||||||
|
typeCode: 'default',
|
||||||
|
tech: 0,
|
||||||
|
meta: {},
|
||||||
|
}) as unknown as NationRow;
|
||||||
|
|
||||||
|
describe('buildTurnCommandTable', () => {
|
||||||
|
it('uses min-condition constraints for availability', async () => {
|
||||||
|
const table = await buildTurnCommandTable({
|
||||||
|
worldState: buildWorldState(),
|
||||||
|
general: buildGeneral(),
|
||||||
|
city: buildCity(),
|
||||||
|
nation: buildNation(),
|
||||||
|
nationGenerals: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
const nationCommand = table.nation
|
||||||
|
.flatMap((group) => group.values)
|
||||||
|
.find((command) => command.key === 'che_포상');
|
||||||
|
|
||||||
|
expect(nationCommand).toBeDefined();
|
||||||
|
expect(nationCommand?.possible).toBe(true);
|
||||||
|
expect(nationCommand?.status).not.toBe('blocked');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -7,9 +7,12 @@ export interface GeneralActionDefinition<
|
|||||||
Args = unknown,
|
Args = unknown,
|
||||||
Context extends GeneralActionResolveContext<TriggerState> = GeneralActionResolveContext<TriggerState>,
|
Context extends GeneralActionResolveContext<TriggerState> = GeneralActionResolveContext<TriggerState>,
|
||||||
> {
|
> {
|
||||||
|
// TODO: legacy permissionConstraints(예약 권한) 모델링 필요.
|
||||||
key: string;
|
key: string;
|
||||||
name: string;
|
name: string;
|
||||||
parseArgs(raw: unknown): Args | null;
|
parseArgs(raw: unknown): Args | null;
|
||||||
|
// 커맨드 입력 단계에서 최소 조건만 평가할 때 사용한다.
|
||||||
|
buildMinConstraints?(ctx: ConstraintContext, args: Args): Constraint[];
|
||||||
buildConstraints(ctx: ConstraintContext, args: Args): Constraint[];
|
buildConstraints(ctx: ConstraintContext, args: Args): Constraint[];
|
||||||
resolve(context: Context, args: Args): GeneralActionOutcome<TriggerState>;
|
resolve(context: Context, args: Args): GeneralActionOutcome<TriggerState>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,6 +164,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: ForcedMoveArgs): Constraint[] {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(ctx: ConstraintContext, _args: ForcedMoveArgs): Constraint[] {
|
buildConstraints(ctx: ConstraintContext, _args: ForcedMoveArgs): Constraint[] {
|
||||||
return [
|
return [
|
||||||
existsDestCity(),
|
existsDestCity(),
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: FoundingArgs): Constraint[] {
|
||||||
|
return [beOpeningPart(), beWanderingNation()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: FoundingArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: FoundingArgs): Constraint[] {
|
||||||
return [
|
return [
|
||||||
beOpeningPart(),
|
beOpeningPart(),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||||
import { occupiedCity, reqGeneralGold, reqGeneralRice } from '@sammo-ts/logic/constraints/presets.js';
|
import { occupiedCity, reqGeneralGold, reqGeneralRice, 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 { 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';
|
||||||
@@ -37,8 +37,12 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: TradeArgs): Constraint[] {
|
||||||
|
return [occupiedCity(), suppliedCity()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: TradeArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: TradeArgs): Constraint[] {
|
||||||
const constraints: Constraint[] = [occupiedCity()];
|
const constraints: Constraint[] = [occupiedCity(), suppliedCity()];
|
||||||
if (args.buyRice) {
|
if (args.buyRice) {
|
||||||
constraints.push(reqGeneralGold(() => 1));
|
constraints.push(reqGeneralGold(() => 1));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -150,6 +150,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: EmployArgs): Constraint[] {
|
||||||
|
return [notBeNeutral(), occupiedCity(), suppliedCity()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: EmployArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: EmployArgs): Constraint[] {
|
||||||
const develCost = this.env.develCost ?? 100;
|
const develCost = this.env.develCost ?? 100;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
import type { GeneralTriggerState } 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 { notBeNeutral, reqGeneralGold } from '@sammo-ts/logic/constraints/presets.js';
|
import {
|
||||||
|
notBeNeutral,
|
||||||
|
notWanderingNation,
|
||||||
|
occupiedCity,
|
||||||
|
reqGeneralCrew,
|
||||||
|
reqGeneralGold,
|
||||||
|
} 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 { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
@@ -36,9 +42,13 @@ export class ActionDefinition<
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: BoostMoraleArgs): Constraint[] {
|
||||||
|
return [notBeNeutral(), notWanderingNation(), occupiedCity()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: BoostMoraleArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: BoostMoraleArgs): Constraint[] {
|
||||||
const getRequiredGold = (_context: ConstraintContext, _view: StateView): number => this.env.costGold ?? 0;
|
const getRequiredGold = (_context: ConstraintContext, _view: StateView): number => this.env.costGold ?? 0;
|
||||||
return [notBeNeutral(), reqGeneralGold(getRequiredGold)];
|
return [notBeNeutral(), notWanderingNation(), occupiedCity(), reqGeneralCrew(), reqGeneralGold(getRequiredGold)];
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(
|
resolve(
|
||||||
|
|||||||
@@ -160,6 +160,15 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(ctx: ConstraintContext, _args: MoveArgs): Constraint[] {
|
||||||
|
return [
|
||||||
|
reqGeneralGold(() => {
|
||||||
|
const develCost = ctx.env.develCost as number;
|
||||||
|
return develCost ?? 0;
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(ctx: ConstraintContext, _args: MoveArgs): Constraint[] {
|
buildConstraints(ctx: ConstraintContext, _args: MoveArgs): Constraint[] {
|
||||||
const constraints = [
|
const constraints = [
|
||||||
existsDestCity(),
|
existsDestCity(),
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ export class ActionDefinition<
|
|||||||
return { destNationId };
|
return { destNationId };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: AppointmentArgs): Constraint[] {
|
||||||
|
return [beNeutral()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: AppointmentArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: AppointmentArgs): Constraint[] {
|
||||||
return [beNeutral(), existsDestNation()];
|
return [beNeutral(), existsDestNation()];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -419,6 +419,16 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: RecruitArgs): Constraint[] {
|
||||||
|
const minPopBase = this.env.minAvailableRecruitPop ?? DEFAULT_MIN_POP;
|
||||||
|
return [
|
||||||
|
notBeNeutral(),
|
||||||
|
occupiedCity(),
|
||||||
|
reqCityCapacity('population', '주민', minPopBase + MIN_CREW),
|
||||||
|
reqCityTrust(20),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(ctx: ConstraintContext, _args: RecruitArgs): Constraint[] {
|
buildConstraints(ctx: ConstraintContext, _args: RecruitArgs): Constraint[] {
|
||||||
const requirements: RequirementKey[] = [
|
const requirements: RequirementKey[] = [
|
||||||
{ kind: 'arg', key: 'crewType' },
|
{ kind: 'arg', key: 'crewType' },
|
||||||
|
|||||||
@@ -131,6 +131,12 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(ctx: ConstraintContext, _args: SpyArgs): Constraint[] {
|
||||||
|
const env = ctx.env;
|
||||||
|
const cost = ((env.develCost as number) ?? 100) * 3;
|
||||||
|
return [notBeNeutral(), reqGeneralGold(() => cost), reqGeneralRice(() => cost)];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(ctx: ConstraintContext, _args: SpyArgs): Constraint[] {
|
buildConstraints(ctx: ConstraintContext, _args: SpyArgs): Constraint[] {
|
||||||
const env = ctx.env;
|
const env = ctx.env;
|
||||||
const cost = ((env.develCost as number) ?? 100) * 3;
|
const cost = ((env.develCost as number) ?? 100) * 3;
|
||||||
|
|||||||
@@ -260,6 +260,19 @@ export class ActionDefinition<
|
|||||||
return { destCityId };
|
return { destCityId };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(ctx: ConstraintContext, _args: DispatchArgs): Constraint[] {
|
||||||
|
const relYear = typeof ctx.env.relYear === 'number' ? ctx.env.relYear : 0;
|
||||||
|
const openingPartYear = typeof ctx.env.openingPartYear === 'number' ? ctx.env.openingPartYear : 0;
|
||||||
|
return [
|
||||||
|
notOpeningPart(relYear + 2, openingPartYear),
|
||||||
|
notBeNeutral(),
|
||||||
|
occupiedCity(),
|
||||||
|
suppliedCity(),
|
||||||
|
reqGeneralCrew(),
|
||||||
|
reqGeneralRice(getRequiredRice),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: DispatchArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: DispatchArgs): Constraint[] {
|
||||||
const relYear = typeof _ctx.env.relYear === 'number' ? _ctx.env.relYear : 0;
|
const relYear = typeof _ctx.env.relYear === 'number' ? _ctx.env.relYear : 0;
|
||||||
const openingPartYear = typeof _ctx.env.openingPartYear === 'number' ? _ctx.env.openingPartYear : 0;
|
const openingPartYear = typeof _ctx.env.openingPartYear === 'number' ? _ctx.env.openingPartYear : 0;
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/
|
|||||||
import {
|
import {
|
||||||
notBeNeutral,
|
notBeNeutral,
|
||||||
notWanderingNation,
|
notWanderingNation,
|
||||||
|
occupiedCity,
|
||||||
reqGeneralGold,
|
reqGeneralGold,
|
||||||
reqGeneralRice,
|
reqGeneralRice,
|
||||||
|
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 {
|
import type {
|
||||||
@@ -96,11 +98,15 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: DonateArgs): Constraint[] {
|
||||||
|
return [notBeNeutral(), occupiedCity(), suppliedCity()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: DonateArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: DonateArgs): Constraint[] {
|
||||||
if (args.isGold) {
|
if (args.isGold) {
|
||||||
return [notBeNeutral(), notWanderingNation(), reqGeneralGold(() => args.amount)];
|
return [notBeNeutral(), notWanderingNation(), occupiedCity(), suppliedCity(), reqGeneralGold(() => args.amount)];
|
||||||
}
|
}
|
||||||
return [notBeNeutral(), notWanderingNation(), reqGeneralRice(() => args.amount)];
|
return [notBeNeutral(), notWanderingNation(), occupiedCity(), suppliedCity(), reqGeneralRice(() => args.amount)];
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(context: GeneralActionResolveContext<TriggerState>, args: DonateArgs): GeneralActionOutcome<TriggerState> {
|
resolve(context: GeneralActionResolveContext<TriggerState>, args: DonateArgs): GeneralActionOutcome<TriggerState> {
|
||||||
|
|||||||
@@ -362,6 +362,17 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: FireAttackArgs): Constraint[] {
|
||||||
|
const { gold, rice } = this.command.getCost();
|
||||||
|
return [
|
||||||
|
notBeNeutral(),
|
||||||
|
occupiedCity(),
|
||||||
|
suppliedCity(),
|
||||||
|
reqGeneralGold(() => gold),
|
||||||
|
reqGeneralRice(() => rice),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: FireAttackArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: FireAttackArgs): Constraint[] {
|
||||||
void _ctx;
|
void _ctx;
|
||||||
void _args;
|
void _args;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
import type { GeneralTriggerState } 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 { notBeNeutral, reqGeneralGold } from '@sammo-ts/logic/constraints/presets.js';
|
import { notBeNeutral, notWanderingNation, occupiedCity, reqGeneralCrew, reqGeneralGold } 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 { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
@@ -36,9 +36,13 @@ export class ActionDefinition<
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: TrainingArgs): Constraint[] {
|
||||||
|
return [notBeNeutral(), notWanderingNation(), occupiedCity()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: TrainingArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: TrainingArgs): Constraint[] {
|
||||||
const getRequiredGold = (_context: ConstraintContext, _view: StateView): number => this.env.costGold ?? 0;
|
const getRequiredGold = (_context: ConstraintContext, _view: StateView): number => this.env.costGold ?? 0;
|
||||||
return [notBeNeutral(), reqGeneralGold(getRequiredGold)];
|
return [notBeNeutral(), notWanderingNation(), occupiedCity(), reqGeneralCrew(), reqGeneralGold(getRequiredGold)];
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(
|
resolve(
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ export class ActionDefinition<
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: ReduceCityArgs): Constraint[] {
|
||||||
|
return [occupiedCity(), beChief(), suppliedCity()];
|
||||||
|
}
|
||||||
|
|
||||||
private getRecoverAmount(): number {
|
private getRecoverAmount(): number {
|
||||||
return this.env.develCost * COST_COEF + DEFAULT_COST / 2;
|
return this.env.develCost * COST_COEF + DEFAULT_COST / 2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,25 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: ChangeNationNameArgs): Constraint[] {
|
||||||
|
return [
|
||||||
|
occupiedCity(),
|
||||||
|
beChief(),
|
||||||
|
suppliedCity(),
|
||||||
|
{
|
||||||
|
name: 'canChangeNationName',
|
||||||
|
requires: (ctx) => [{ kind: 'nation', id: ctx.nationId! }],
|
||||||
|
test: (_ctx: ConstraintContext, view: StateView) => {
|
||||||
|
const nation = view.get({ kind: 'nation', id: _ctx.nationId! }) as Nation | undefined;
|
||||||
|
const canChangeRaw = nation?.meta[`can_${ACTION_NAME}`];
|
||||||
|
const canChange = (typeof canChangeRaw === 'number' ? canChangeRaw : 0) !== 0;
|
||||||
|
if (!canChange) return { kind: 'deny', reason: '더이상 변경이 불가능합니다.' };
|
||||||
|
return { kind: 'allow' };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: ChangeNationNameArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: ChangeNationNameArgs): Constraint[] {
|
||||||
return [
|
return [
|
||||||
occupiedCity(),
|
occupiedCity(),
|
||||||
|
|||||||
@@ -174,6 +174,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: RaidArgs): Constraint[] {
|
||||||
|
return [occupiedCity(), beChief(), availableStrategicCommand()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: RaidArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: RaidArgs): Constraint[] {
|
||||||
void _ctx;
|
void _ctx;
|
||||||
void _args;
|
void _args;
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import {
|
|||||||
beChief,
|
beChief,
|
||||||
existsDestGeneral,
|
existsDestGeneral,
|
||||||
friendlyDestGeneral,
|
friendlyDestGeneral,
|
||||||
|
notBeNeutral,
|
||||||
|
notOpeningPart,
|
||||||
occupiedCity,
|
occupiedCity,
|
||||||
suppliedCity,
|
suppliedCity,
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
} from '@sammo-ts/logic/constraints/presets.js';
|
||||||
@@ -60,10 +62,20 @@ export class ActionDefinition<
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(ctx: ConstraintContext, _args: SeizureArgs): Constraint[] {
|
||||||
|
const relYear = typeof ctx.env.relYear === 'number' ? ctx.env.relYear : 0;
|
||||||
|
const openingPartYear = typeof ctx.env.openingPartYear === 'number' ? ctx.env.openingPartYear : 0;
|
||||||
|
return [notBeNeutral(), occupiedCity(), beChief(), notOpeningPart(relYear, openingPartYear), suppliedCity()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: SeizureArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: SeizureArgs): Constraint[] {
|
||||||
|
const relYear = typeof _ctx.env.relYear === 'number' ? _ctx.env.relYear : 0;
|
||||||
|
const openingPartYear = typeof _ctx.env.openingPartYear === 'number' ? _ctx.env.openingPartYear : 0;
|
||||||
return [
|
return [
|
||||||
|
notBeNeutral(),
|
||||||
occupiedCity(),
|
occupiedCity(),
|
||||||
beChief(),
|
beChief(),
|
||||||
|
notOpeningPart(relYear, openingPartYear),
|
||||||
suppliedCity(),
|
suppliedCity(),
|
||||||
existsDestGeneral(),
|
existsDestGeneral(),
|
||||||
friendlyDestGeneral(),
|
friendlyDestGeneral(),
|
||||||
|
|||||||
@@ -51,6 +51,25 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: MaterialAidArgs): Constraint[] {
|
||||||
|
return [
|
||||||
|
occupiedCity(),
|
||||||
|
beChief(),
|
||||||
|
suppliedCity(),
|
||||||
|
{
|
||||||
|
name: 'nationSurlimit',
|
||||||
|
requires: (ctx) => [{ kind: 'nation', id: ctx.nationId! }],
|
||||||
|
test: (_ctx: ConstraintContext, view: StateView) => {
|
||||||
|
const nation = view.get({ kind: 'nation', id: _ctx.nationId! }) as Nation | undefined;
|
||||||
|
const surlimitRaw = nation?.meta.surlimit;
|
||||||
|
const surlimit = typeof surlimitRaw === 'number' ? surlimitRaw : 0;
|
||||||
|
if (surlimit > 0) return { kind: 'deny', reason: '외교제한중입니다.' };
|
||||||
|
return { kind: 'allow' };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: MaterialAidArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: MaterialAidArgs): Constraint[] {
|
||||||
const [goldAmount, riceAmount] = args.amountList;
|
const [goldAmount, riceAmount] = args.amountList;
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -152,6 +152,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: AssignmentArgs): Constraint[] {
|
||||||
|
return [beChief(), notBeNeutral(), occupiedCity(), suppliedCity()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(ctx: ConstraintContext, _args: AssignmentArgs): Constraint[] {
|
buildConstraints(ctx: ConstraintContext, _args: AssignmentArgs): Constraint[] {
|
||||||
void _args;
|
void _args;
|
||||||
if (ctx.destGeneralId === ctx.actorId) {
|
if (ctx.destGeneralId === ctx.actorId) {
|
||||||
|
|||||||
@@ -152,6 +152,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: MobilizePeopleArgs): Constraint[] {
|
||||||
|
return [occupiedCity(), beChief(), availableStrategicCommand()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: MobilizePeopleArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: MobilizePeopleArgs): Constraint[] {
|
||||||
void _ctx;
|
void _ctx;
|
||||||
void _args;
|
void _args;
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: TroopKickArgs): Constraint[] {
|
||||||
|
return [notBeNeutral(), beChief()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(ctx: ConstraintContext, _args: TroopKickArgs): Constraint[] {
|
buildConstraints(ctx: ConstraintContext, _args: TroopKickArgs): Constraint[] {
|
||||||
if (ctx.destGeneralId !== undefined && ctx.destGeneralId === ctx.actorId) {
|
if (ctx.destGeneralId !== undefined && ctx.destGeneralId === ctx.actorId) {
|
||||||
return [alwaysFail('본인입니다')];
|
return [alwaysFail('본인입니다')];
|
||||||
|
|||||||
@@ -97,6 +97,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: NonAggressionProposalArgs): Constraint[] {
|
||||||
|
return [beChief(), notBeNeutral()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: NonAggressionProposalArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: NonAggressionProposalArgs): Constraint[] {
|
||||||
return [
|
return [
|
||||||
beChief(),
|
beChief(),
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: NonAggressionCancelProposalArgs): Constraint[] {
|
||||||
|
return [beChief(), notBeNeutral(), occupiedCity(), suppliedCity()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: NonAggressionCancelProposalArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: NonAggressionCancelProposalArgs): Constraint[] {
|
||||||
return [
|
return [
|
||||||
beChief(),
|
beChief(),
|
||||||
|
|||||||
@@ -53,6 +53,24 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: DeclareWarArgs): Constraint[] {
|
||||||
|
const relYear = typeof _ctx.env.relYear === 'number' ? _ctx.env.relYear : 0;
|
||||||
|
return [
|
||||||
|
notBeNeutral(),
|
||||||
|
occupiedCity(),
|
||||||
|
suppliedCity(),
|
||||||
|
beChief(),
|
||||||
|
{
|
||||||
|
name: 'declareWarYearLimit',
|
||||||
|
requires: () => [],
|
||||||
|
test: () => {
|
||||||
|
if (relYear >= 1) return { kind: 'allow' };
|
||||||
|
return { kind: 'deny', reason: '초반제한 해제 2년전부터 가능합니다.' };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: DeclareWarArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: DeclareWarArgs): Constraint[] {
|
||||||
const relYear = typeof _ctx.env.relYear === 'number' ? _ctx.env.relYear : 0;
|
const relYear = typeof _ctx.env.relYear === 'number' ? _ctx.env.relYear : 0;
|
||||||
|
|
||||||
|
|||||||
@@ -177,6 +177,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: FloodArgs): Constraint[] {
|
||||||
|
return [occupiedCity(), beChief(), availableStrategicCommand()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: FloodArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: FloodArgs): Constraint[] {
|
||||||
void _ctx;
|
void _ctx;
|
||||||
void _args;
|
void _args;
|
||||||
|
|||||||
@@ -181,6 +181,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: DegradeRelationsArgs): Constraint[] {
|
||||||
|
return [occupiedCity(), beChief(), availableStrategicCommand()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: DegradeRelationsArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: DegradeRelationsArgs): Constraint[] {
|
||||||
void _ctx;
|
void _ctx;
|
||||||
void _args;
|
void _args;
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: StopWarProposalArgs): Constraint[] {
|
||||||
|
return [beChief(), notBeNeutral(), occupiedCity(), suppliedCity()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: StopWarProposalArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: StopWarProposalArgs): Constraint[] {
|
||||||
return [
|
return [
|
||||||
beChief(),
|
beChief(),
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ export class ActionDefinition<
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: ExpandCityArgs): Constraint[] {
|
||||||
|
return [occupiedCity(), beChief(), suppliedCity()];
|
||||||
|
}
|
||||||
|
|
||||||
private getCost(): number {
|
private getCost(): number {
|
||||||
return this.env.develCost * COST_COEF + DEFAULT_COST;
|
return this.env.develCost * COST_COEF + DEFAULT_COST;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: MoveCapitalArgs): Constraint[] {
|
||||||
|
return [occupiedCity(), beChief(), suppliedCity()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: MoveCapitalArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: MoveCapitalArgs): Constraint[] {
|
||||||
const develcost = this.env.develCost;
|
const develcost = this.env.develCost;
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: ScorchedEarthArgs): Constraint[] {
|
||||||
|
return [occupiedCity(), beChief(), suppliedCity(), requireNoDiplomacyLimit()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: ScorchedEarthArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: ScorchedEarthArgs): Constraint[] {
|
||||||
void _ctx;
|
void _ctx;
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -180,6 +180,10 @@ export class ActionDefinition<
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: AwardArgs): Constraint[] {
|
||||||
|
return [notBeNeutral(), occupiedCity(), beChief(), suppliedCity()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(ctx: ConstraintContext, args: AwardArgs): Constraint[] {
|
buildConstraints(ctx: ConstraintContext, args: AwardArgs): Constraint[] {
|
||||||
const requirements: RequirementKey[] = [];
|
const requirements: RequirementKey[] = [];
|
||||||
if (ctx.cityId !== undefined) {
|
if (ctx.cityId !== undefined) {
|
||||||
|
|||||||
@@ -211,6 +211,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: CounterStrategyArgs): Constraint[] {
|
||||||
|
return [occupiedCity(), beChief()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: CounterStrategyArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: CounterStrategyArgs): Constraint[] {
|
||||||
void _ctx;
|
void _ctx;
|
||||||
void _args;
|
void _args;
|
||||||
|
|||||||
@@ -184,6 +184,10 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: DeceptionArgs): Constraint[] {
|
||||||
|
return [occupiedCity(), beChief(), availableStrategicCommand()];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: DeceptionArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: DeceptionArgs): Constraint[] {
|
||||||
void _ctx;
|
void _ctx;
|
||||||
void _args;
|
void _args;
|
||||||
|
|||||||
@@ -65,6 +65,15 @@ export class ActionDefinition<
|
|||||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildMinConstraints(_ctx: ConstraintContext, _args: PopulationMoveArgs): Constraint[] {
|
||||||
|
return [
|
||||||
|
occupiedCity(),
|
||||||
|
beChief(),
|
||||||
|
suppliedCity(),
|
||||||
|
reqCityCapacity('population', '주민', MIN_AVAILABLE_RECRUIT_POP + 100),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: PopulationMoveArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: PopulationMoveArgs): Constraint[] {
|
||||||
const cost = calcCost(this.env.develCost, args.amount);
|
const cost = calcCost(this.env.develCost, args.amount);
|
||||||
return [
|
return [
|
||||||
|
|||||||
Reference in New Issue
Block a user