feat: 여러 커맨드의 제약 조건 개선 및 새로운 제약 조건 추가
This commit is contained in:
@@ -5,7 +5,6 @@ import {
|
||||
nearCity,
|
||||
reqGeneralGold,
|
||||
reqGeneralRice,
|
||||
existsDestCity,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type {
|
||||
@@ -173,7 +172,6 @@ export class ActionDefinition<
|
||||
|
||||
buildConstraints(ctx: ConstraintContext, _args: ForcedMoveArgs): Constraint[] {
|
||||
return [
|
||||
existsDestCity(),
|
||||
notSameDestCity(),
|
||||
nearCity(3),
|
||||
reqGeneralGold((_c, _v) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import { beNeutral } from '@sammo-ts/logic/constraints/presets.js';
|
||||
import { allowJoinAction, beNeutral, beOpeningPart, noPenalty } from '@sammo-ts/logic/constraints/presets.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
import {
|
||||
@@ -33,7 +33,7 @@ export class ActionDefinition<
|
||||
}
|
||||
|
||||
buildConstraints(_ctx: ConstraintContext, _args: UprisingArgs): Constraint[] {
|
||||
return [beNeutral()];
|
||||
return [beNeutral(), beOpeningPart(), allowJoinAction(), noPenalty('noFoundNation')];
|
||||
}
|
||||
|
||||
resolve(
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import { occupiedCity, reqGeneralGold, reqGeneralRice, suppliedCity } from '@sammo-ts/logic/constraints/presets.js';
|
||||
import {
|
||||
occupiedCity,
|
||||
reqCityTrader,
|
||||
reqGeneralGold,
|
||||
reqGeneralRice,
|
||||
suppliedCity,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
import { LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||
@@ -39,11 +45,11 @@ export class ActionDefinition<
|
||||
}
|
||||
|
||||
buildMinConstraints(_ctx: ConstraintContext, _args: TradeArgs): Constraint[] {
|
||||
return [occupiedCity(), suppliedCity()];
|
||||
return [reqCityTrader(), occupiedCity({ allowNeutral: true }), suppliedCity()];
|
||||
}
|
||||
|
||||
buildConstraints(_ctx: ConstraintContext, args: TradeArgs): Constraint[] {
|
||||
const constraints: Constraint[] = [occupiedCity(), suppliedCity()];
|
||||
const constraints: Constraint[] = [reqCityTrader(), occupiedCity({ allowNeutral: true }), suppliedCity()];
|
||||
if (args.buyRice) {
|
||||
constraints.push(reqGeneralGold(() => 1));
|
||||
} else {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
notWanderingNation,
|
||||
occupiedCity,
|
||||
reqGeneralGold,
|
||||
reqGeneralRice,
|
||||
suppliedCity,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
@@ -52,7 +53,14 @@ export class ActionDefinition<
|
||||
|
||||
buildConstraints(_ctx: ConstraintContext, _args: TechResearchArgs): Constraint[] {
|
||||
const getRequiredGold = (_context: ConstraintContext, _view: StateView): number => this.env.costGold ?? 0;
|
||||
return [notBeNeutral(), notWanderingNation(), occupiedCity(), suppliedCity(), reqGeneralGold(getRequiredGold)];
|
||||
return [
|
||||
notBeNeutral(),
|
||||
notWanderingNation(),
|
||||
occupiedCity(),
|
||||
suppliedCity(),
|
||||
reqGeneralGold(getRequiredGold),
|
||||
reqGeneralRice(() => 0),
|
||||
];
|
||||
}
|
||||
|
||||
resolve(
|
||||
|
||||
@@ -15,8 +15,8 @@ const ACTION_NAME = '내정 특기 초기화';
|
||||
const hasSpecial = (value: string | null | undefined): boolean =>
|
||||
value !== null && value !== undefined && value !== 'None';
|
||||
|
||||
const reqDomesticSpecial = (): Constraint => ({
|
||||
name: 'ReqGeneralDomesticSpecial',
|
||||
const reqGeneralValue = (): Constraint => ({
|
||||
name: 'reqGeneralValue',
|
||||
requires: (ctx) => [{ kind: 'general', id: ctx.actorId }],
|
||||
test: (ctx, view) => {
|
||||
const general = readGeneral(ctx, view);
|
||||
@@ -42,8 +42,12 @@ export class ActionDefinition<
|
||||
return {};
|
||||
}
|
||||
|
||||
buildMinConstraints(_ctx: ConstraintContext, _args: ResetSpecialDomesticArgs): Constraint[] {
|
||||
return [reqGeneralValue()];
|
||||
}
|
||||
|
||||
buildConstraints(_ctx: ConstraintContext, _args: ResetSpecialDomesticArgs): Constraint[] {
|
||||
return [reqDomesticSpecial()];
|
||||
return [reqGeneralValue()];
|
||||
}
|
||||
|
||||
resolve(
|
||||
|
||||
@@ -62,8 +62,8 @@ const pickByWeight = <T extends string>(rng: DrillContext['rng'], weights: Recor
|
||||
return last ? last[0] : first[0];
|
||||
};
|
||||
|
||||
const reqGeneralStat = (key: 'train' | 'atmos', label: string, minValue: number): Constraint => ({
|
||||
name: `ReqGeneral${label}`,
|
||||
const reqGeneralValue = (key: 'train' | 'atmos', label: string, minValue: number): Constraint => ({
|
||||
name: 'reqGeneralValue',
|
||||
requires: (ctx) => [{ kind: 'general', id: ctx.actorId }],
|
||||
test: (ctx, view) => {
|
||||
const general = readGeneral(ctx, view);
|
||||
@@ -103,8 +103,8 @@ export class ActionDefinition<
|
||||
return [
|
||||
notBeNeutral(),
|
||||
reqGeneralCrew(),
|
||||
reqGeneralStat('train', '훈련', trainLow),
|
||||
reqGeneralStat('atmos', '사기', atmosLow),
|
||||
reqGeneralValue('train', '훈련', trainLow),
|
||||
reqGeneralValue('atmos', '사기', atmosLow),
|
||||
reqGeneralGold(getRequiredGold),
|
||||
reqGeneralRice(getRequiredRice),
|
||||
];
|
||||
|
||||
@@ -4,8 +4,10 @@ import {
|
||||
notBeNeutral,
|
||||
notWanderingNation,
|
||||
occupiedCity,
|
||||
reqGeneralAtmosMargin,
|
||||
reqGeneralCrew,
|
||||
reqGeneralGold,
|
||||
reqGeneralRice,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
@@ -49,7 +51,19 @@ export class ActionDefinition<
|
||||
|
||||
buildConstraints(_ctx: ConstraintContext, _args: BoostMoraleArgs): Constraint[] {
|
||||
const getRequiredGold = (_context: ConstraintContext, _view: StateView): number => this.env.costGold ?? 0;
|
||||
return [notBeNeutral(), notWanderingNation(), occupiedCity(), reqGeneralCrew(), reqGeneralGold(getRequiredGold)];
|
||||
const maxAtmos =
|
||||
this.env.maxAtmosByCommand && this.env.maxAtmosByCommand > 0
|
||||
? this.env.maxAtmosByCommand
|
||||
: DEFAULT_MAX_ATMOS;
|
||||
return [
|
||||
notBeNeutral(),
|
||||
notWanderingNation(),
|
||||
occupiedCity(),
|
||||
reqGeneralCrew(),
|
||||
reqGeneralGold(getRequiredGold),
|
||||
reqGeneralRice(() => 0),
|
||||
reqGeneralAtmosMargin(maxAtmos),
|
||||
];
|
||||
}
|
||||
|
||||
resolve(
|
||||
|
||||
@@ -52,6 +52,12 @@ export class ActionDefinition<
|
||||
return parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||
}
|
||||
|
||||
buildMinConstraints(_ctx: ConstraintContext, _args: DexTransferArgs): Constraint[] {
|
||||
const getRequiredGold = (_context: ConstraintContext, _view: StateView): number => this.env.develCost ?? 0;
|
||||
const getRequiredRice = (_context: ConstraintContext, _view: StateView): number => this.env.develCost ?? 0;
|
||||
return [notBeNeutral(), occupiedCity(), reqGeneralGold(getRequiredGold), reqGeneralRice(getRequiredRice)];
|
||||
}
|
||||
|
||||
buildConstraints(_ctx: ConstraintContext, _args: DexTransferArgs): Constraint[] {
|
||||
const getRequiredGold = (_context: ConstraintContext, _view: StateView): number => this.env.develCost ?? 0;
|
||||
const getRequiredRice = (_context: ConstraintContext, _view: StateView): number => this.env.develCost ?? 0;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
|
||||
import { notBeNeutral, reqGeneralGold } from '@sammo-ts/logic/constraints/presets.js';
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
@@ -34,8 +33,7 @@ export class ActionDefinition<
|
||||
}
|
||||
|
||||
buildConstraints(_ctx: ConstraintContext, _args: RecoveryArgs): Constraint[] {
|
||||
const getRequiredGold = (_context: ConstraintContext, _view: StateView): number => this.env.costGold ?? 0;
|
||||
return [notBeNeutral(), reqGeneralGold(getRequiredGold)];
|
||||
return [];
|
||||
}
|
||||
|
||||
resolve(
|
||||
|
||||
@@ -22,8 +22,8 @@ const ACTION_KEY = 'che_은퇴';
|
||||
|
||||
const REQ_AGE = 60;
|
||||
|
||||
const reqAge = (): Constraint => ({
|
||||
name: 'ReqAge',
|
||||
const reqGeneralValue = (): Constraint => ({
|
||||
name: 'reqGeneralValue',
|
||||
requires: (ctx) => [{ kind: 'general', id: ctx.actorId }],
|
||||
test: (ctx, view) => {
|
||||
const generalKey: RequirementKey = { kind: 'general', id: ctx.actorId };
|
||||
@@ -118,7 +118,7 @@ export class ActionDefinition<
|
||||
}
|
||||
|
||||
buildConstraints(_ctx: ConstraintContext, _args: RetireArgs): Constraint[] {
|
||||
return [reqAge()];
|
||||
return [reqGeneralValue()];
|
||||
}
|
||||
|
||||
resolve(context: GeneralActionResolveContext<TriggerState>, args: RetireArgs): GeneralActionOutcome<TriggerState> {
|
||||
|
||||
@@ -16,8 +16,8 @@ const ACTION_NAME = '전투 특기 초기화';
|
||||
const hasSpecial = (value: string | null | undefined): boolean =>
|
||||
value !== null && value !== undefined && value !== 'None';
|
||||
|
||||
const reqWarSpecial = (): Constraint => ({
|
||||
name: 'ReqGeneralWarSpecial',
|
||||
const reqGeneralValue = (): Constraint => ({
|
||||
name: 'reqGeneralValue',
|
||||
requires: (ctx) => [{ kind: 'general', id: ctx.actorId }],
|
||||
test: (ctx, view) => {
|
||||
const general = readGeneral(ctx, view);
|
||||
@@ -43,8 +43,12 @@ export class ActionDefinition<
|
||||
return {};
|
||||
}
|
||||
|
||||
buildMinConstraints(_ctx: ConstraintContext, _args: ResetSpecialWarArgs): Constraint[] {
|
||||
return [reqGeneralValue()];
|
||||
}
|
||||
|
||||
buildConstraints(_ctx: ConstraintContext, _args: ResetSpecialWarArgs): Constraint[] {
|
||||
return [reqWarSpecial()];
|
||||
return [reqGeneralValue()];
|
||||
}
|
||||
|
||||
resolve(
|
||||
|
||||
@@ -4,7 +4,8 @@ import {
|
||||
notBeNeutral,
|
||||
notWanderingNation,
|
||||
occupiedCity,
|
||||
remainCityCapacityByMax,
|
||||
remainCityCapacity,
|
||||
reqGeneralGold,
|
||||
reqGeneralRice,
|
||||
suppliedCity,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
@@ -76,7 +77,8 @@ export class ActionDefinition<
|
||||
notWanderingNation(),
|
||||
occupiedCity(),
|
||||
suppliedCity(),
|
||||
remainCityCapacityByMax('population', 'populationMax', '인구'),
|
||||
reqGeneralGold(() => 0),
|
||||
remainCityCapacity('population', '인구'),
|
||||
reqGeneralRice(getRequiredRice),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
notBeNeutral,
|
||||
notWanderingNation,
|
||||
occupiedCity,
|
||||
reqGeneralGold,
|
||||
reqGeneralRice,
|
||||
suppliedCity,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
@@ -134,6 +135,7 @@ export class ActionDefinition<
|
||||
notWanderingNation(),
|
||||
occupiedCity(),
|
||||
suppliedCity(),
|
||||
reqGeneralGold(() => 0, requirements),
|
||||
reqGeneralRice(getRiceCost, requirements),
|
||||
remainCityTrust(),
|
||||
];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import { notBeNeutral } from '@sammo-ts/logic/constraints/presets.js';
|
||||
import { notBeNeutral, notLord } from '@sammo-ts/logic/constraints/presets.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type {
|
||||
GeneralActionOutcome,
|
||||
@@ -106,7 +106,7 @@ export class ActionDefinition<
|
||||
}
|
||||
|
||||
buildConstraints(_ctx: ConstraintContext, _args: ResignArgs): Constraint[] {
|
||||
return [notBeNeutral()];
|
||||
return [notBeNeutral(), notLord()];
|
||||
}
|
||||
|
||||
resolve(context: GeneralActionResolveContext<TriggerState>, args: ResignArgs): GeneralActionOutcome<TriggerState> {
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import {
|
||||
notBeNeutral,
|
||||
notWanderingNation,
|
||||
occupiedCity,
|
||||
reqGeneralGold,
|
||||
reqGeneralRice,
|
||||
@@ -107,9 +106,9 @@ export class ActionDefinition<
|
||||
|
||||
buildConstraints(_ctx: ConstraintContext, args: DonateArgs): Constraint[] {
|
||||
if (args.isGold) {
|
||||
return [notBeNeutral(), notWanderingNation(), occupiedCity(), suppliedCity(), reqGeneralGold(() => args.amount)];
|
||||
return [notBeNeutral(), occupiedCity(), suppliedCity(), reqGeneralGold(() => args.amount)];
|
||||
}
|
||||
return [notBeNeutral(), notWanderingNation(), occupiedCity(), suppliedCity(), reqGeneralRice(() => args.amount)];
|
||||
return [notBeNeutral(), occupiedCity(), suppliedCity(), reqGeneralRice(() => args.amount)];
|
||||
}
|
||||
|
||||
resolve(context: GeneralActionResolveContext<TriggerState>, args: DonateArgs): GeneralActionOutcome<TriggerState> {
|
||||
|
||||
@@ -10,7 +10,6 @@ import type {
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import {
|
||||
disallowDiplomacyBetweenStatus,
|
||||
existsDestCity,
|
||||
notBeNeutral,
|
||||
notNeutralDestCity,
|
||||
notOccupiedDestCity,
|
||||
@@ -393,7 +392,6 @@ export class ActionDefinition<
|
||||
notBeNeutral(),
|
||||
occupiedCity(),
|
||||
suppliedCity(),
|
||||
existsDestCity(),
|
||||
notOccupiedDestCity(),
|
||||
notNeutralDestCity(),
|
||||
reqGeneralGold(() => gold),
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
|
||||
import { notBeNeutral, notWanderingNation, occupiedCity, reqGeneralCrew, reqGeneralGold } from '@sammo-ts/logic/constraints/presets.js';
|
||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||
import {
|
||||
notBeNeutral,
|
||||
notWanderingNation,
|
||||
occupiedCity,
|
||||
reqGeneralCrew,
|
||||
reqGeneralTrainMargin,
|
||||
} from '@sammo-ts/logic/constraints/presets.js';
|
||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
@@ -42,8 +48,11 @@ export class ActionDefinition<
|
||||
}
|
||||
|
||||
buildConstraints(_ctx: ConstraintContext, _args: TrainingArgs): Constraint[] {
|
||||
const getRequiredGold = (_context: ConstraintContext, _view: StateView): number => this.env.costGold ?? 0;
|
||||
return [notBeNeutral(), notWanderingNation(), occupiedCity(), reqGeneralCrew(), reqGeneralGold(getRequiredGold)];
|
||||
const maxTrain =
|
||||
this.env.maxTrainByCommand && this.env.maxTrainByCommand > 0
|
||||
? this.env.maxTrainByCommand
|
||||
: DEFAULT_MAX_TRAIN;
|
||||
return [notBeNeutral(), notWanderingNation(), occupiedCity(), reqGeneralCrew(), reqGeneralTrainMargin(maxTrain)];
|
||||
}
|
||||
|
||||
resolve(
|
||||
|
||||
@@ -24,8 +24,8 @@ export interface EventResearchConfig {
|
||||
category?: string;
|
||||
}
|
||||
|
||||
const requireNationAux = (auxKey: string, actionName: string): Constraint => ({
|
||||
name: 'requireNationAux',
|
||||
const reqNationAuxValue = (auxKey: string, actionName: string): Constraint => ({
|
||||
name: 'reqNationAuxValue',
|
||||
requires: (ctx) => (ctx.nationId !== undefined ? [{ kind: 'nation', id: ctx.nationId }] : []),
|
||||
test: (ctx: ConstraintContext, view: StateView) => {
|
||||
if (ctx.nationId === undefined) {
|
||||
@@ -69,13 +69,25 @@ export const createEventResearchCommand = (config: EventResearchConfig): {
|
||||
return {};
|
||||
}
|
||||
|
||||
buildMinConstraints(_ctx: ConstraintContext, _args: Record<string, never>): Constraint[] {
|
||||
void _ctx;
|
||||
void _args;
|
||||
return [
|
||||
occupiedCity(),
|
||||
beChief(),
|
||||
reqNationAuxValue(config.auxKey, ACTION_NAME),
|
||||
reqNationGold(() => this.env.baseGold + COST),
|
||||
reqNationRice(() => this.env.baseRice + COST),
|
||||
];
|
||||
}
|
||||
|
||||
buildConstraints(_ctx: ConstraintContext, _args: Record<string, never>): Constraint[] {
|
||||
void _ctx;
|
||||
void _args;
|
||||
return [
|
||||
occupiedCity(),
|
||||
beChief(),
|
||||
requireNationAux(config.auxKey, ACTION_NAME),
|
||||
reqNationAuxValue(config.auxKey, ACTION_NAME),
|
||||
reqNationGold(() => this.env.baseGold + COST),
|
||||
reqNationRice(() => this.env.baseRice + COST),
|
||||
];
|
||||
|
||||
@@ -109,6 +109,42 @@ export const suppliedCity = (): Constraint => ({
|
||||
},
|
||||
});
|
||||
|
||||
export const reqCityTrader = (): Constraint => ({
|
||||
name: 'reqCityTrader',
|
||||
requires: (ctx) => {
|
||||
const reqs: RequirementKey[] = [{ kind: 'general', id: ctx.actorId }];
|
||||
if (ctx.cityId !== undefined) {
|
||||
reqs.push({ kind: 'city', id: ctx.cityId });
|
||||
}
|
||||
return reqs;
|
||||
},
|
||||
test: (ctx, view) => {
|
||||
const generalReq: RequirementKey = { kind: 'general', id: ctx.actorId };
|
||||
if (!view.has(generalReq)) {
|
||||
return unknownOrDeny(ctx, [generalReq], '장수 정보가 없습니다.');
|
||||
}
|
||||
const general = view.get(generalReq) as General | null;
|
||||
if (!general) {
|
||||
return unknownOrDeny(ctx, [generalReq], '장수 정보가 없습니다.');
|
||||
}
|
||||
|
||||
const city = readCity(view, ctx.cityId);
|
||||
if (!city) {
|
||||
if (ctx.cityId === undefined) {
|
||||
return unknownOrDeny(ctx, [], '도시 정보가 없습니다.');
|
||||
}
|
||||
const req: RequirementKey = { kind: 'city', id: ctx.cityId };
|
||||
return unknownOrDeny(ctx, [req], '도시 정보가 없습니다.');
|
||||
}
|
||||
|
||||
const trade = readMetaNumberFromUnknown(city.meta, 'trade');
|
||||
if (trade !== null || general.npcState >= 2) {
|
||||
return allow();
|
||||
}
|
||||
return { kind: 'deny', reason: '도시에 상인이 없습니다.' };
|
||||
},
|
||||
});
|
||||
|
||||
export const suppliedDestCity = (): Constraint => ({
|
||||
name: 'suppliedDestCity',
|
||||
requires: (ctx) =>
|
||||
|
||||
@@ -145,6 +145,98 @@ export const reqGeneralCrew = (): Constraint => ({
|
||||
},
|
||||
});
|
||||
|
||||
export const reqGeneralTrainMargin = (maxTrain: number): Constraint => ({
|
||||
name: 'reqGeneralTrainMargin',
|
||||
requires: (ctx) => [{ kind: 'general', id: ctx.actorId }],
|
||||
test: (ctx, view) => {
|
||||
const generalReq: RequirementKey = { kind: 'general', id: ctx.actorId };
|
||||
if (!view.has(generalReq)) {
|
||||
return unknownOrDeny(ctx, [generalReq], '장수 정보가 없습니다.');
|
||||
}
|
||||
const general = view.get(generalReq) as General | null;
|
||||
if (!general) {
|
||||
return unknownOrDeny(ctx, [generalReq], '장수 정보가 없습니다.');
|
||||
}
|
||||
if (general.train < maxTrain) {
|
||||
return allow();
|
||||
}
|
||||
return { kind: 'deny', reason: '병사들은 이미 정예병사들입니다.' };
|
||||
},
|
||||
});
|
||||
|
||||
export const reqGeneralAtmosMargin = (maxAtmos: number): Constraint => ({
|
||||
name: 'reqGeneralAtmosMargin',
|
||||
requires: (ctx) => [{ kind: 'general', id: ctx.actorId }],
|
||||
test: (ctx, view) => {
|
||||
const generalReq: RequirementKey = { kind: 'general', id: ctx.actorId };
|
||||
if (!view.has(generalReq)) {
|
||||
return unknownOrDeny(ctx, [generalReq], '장수 정보가 없습니다.');
|
||||
}
|
||||
const general = view.get(generalReq) as General | null;
|
||||
if (!general) {
|
||||
return unknownOrDeny(ctx, [generalReq], '장수 정보가 없습니다.');
|
||||
}
|
||||
if (general.atmos < maxAtmos) {
|
||||
return allow();
|
||||
}
|
||||
return { kind: 'deny', reason: '이미 사기는 하늘을 찌를듯 합니다.' };
|
||||
},
|
||||
});
|
||||
|
||||
export const allowJoinAction = (): Constraint => ({
|
||||
name: 'allowJoinAction',
|
||||
requires: (ctx) => [{ kind: 'general', id: ctx.actorId }],
|
||||
test: (ctx, view) => {
|
||||
const generalReq: RequirementKey = { kind: 'general', id: ctx.actorId };
|
||||
if (!view.has(generalReq)) {
|
||||
return unknownOrDeny(ctx, [generalReq], '장수 정보가 없습니다.');
|
||||
}
|
||||
const general = view.get(generalReq) as General | null;
|
||||
if (!general) {
|
||||
return unknownOrDeny(ctx, [generalReq], '장수 정보가 없습니다.');
|
||||
}
|
||||
|
||||
const makelimit = typeof general.meta.makelimit === 'number' ? general.meta.makelimit : 0;
|
||||
if (makelimit === 0) {
|
||||
return allow();
|
||||
}
|
||||
|
||||
const joinActionLimit = typeof ctx.env.joinActionLimit === 'number' ? ctx.env.joinActionLimit : 12;
|
||||
return { kind: 'deny', reason: `재야가 된지 ${joinActionLimit}턴이 지나야 합니다.` };
|
||||
},
|
||||
});
|
||||
|
||||
export const noPenalty = (penaltyKey: string): Constraint => ({
|
||||
name: 'noPenalty',
|
||||
requires: (ctx) => [{ kind: 'general', id: ctx.actorId }],
|
||||
test: (ctx, view) => {
|
||||
const generalReq: RequirementKey = { kind: 'general', id: ctx.actorId };
|
||||
if (!view.has(generalReq)) {
|
||||
return unknownOrDeny(ctx, [generalReq], '장수 정보가 없습니다.');
|
||||
}
|
||||
const general = view.get(generalReq) as General | null;
|
||||
if (!general) {
|
||||
return unknownOrDeny(ctx, [generalReq], '장수 정보가 없습니다.');
|
||||
}
|
||||
|
||||
const penalty = general.meta.penalty;
|
||||
if (!penalty || typeof penalty !== 'object' || Array.isArray(penalty)) {
|
||||
return allow();
|
||||
}
|
||||
|
||||
const penaltyMap = penalty as Record<string, unknown>;
|
||||
if (!Object.prototype.hasOwnProperty.call(penaltyMap, penaltyKey)) {
|
||||
return allow();
|
||||
}
|
||||
|
||||
const reason = penaltyMap[penaltyKey];
|
||||
return {
|
||||
kind: 'deny',
|
||||
reason: `징계 사유: ${typeof reason === 'string' ? reason : String(reason)}`,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const reqGeneralCrewMargin = (
|
||||
getCrewTypeId: (ctx: ConstraintContext, view: StateView) => number | null,
|
||||
requirements: RequirementKey[] = []
|
||||
|
||||
Reference in New Issue
Block a user