feat: 새로운 제약 조건 추가 및 기존 제약 조건 개선
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import type { City, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
|
import type { City, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
|
||||||
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
|
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
|
||||||
import { beChief, occupiedCity, suppliedCity } from '@sammo-ts/logic/constraints/presets.js';
|
import { beChief, notBeNeutral, occupiedCity, suppliedCity } from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type {
|
import type {
|
||||||
GeneralActionEffect,
|
GeneralActionEffect,
|
||||||
@@ -13,6 +13,7 @@ import { JosaUtil } from '@sammo-ts/common';
|
|||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import type { NationTurnCommandSpec } from './index.js';
|
import type { NationTurnCommandSpec } from './index.js';
|
||||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
|
import type { MapDefinition } from '@sammo-ts/logic/world/types.js';
|
||||||
|
|
||||||
export interface ReduceCityArgs {}
|
export interface ReduceCityArgs {}
|
||||||
|
|
||||||
@@ -31,6 +32,64 @@ const DEFAULT_COST = 60000;
|
|||||||
const COST_COEF = 500;
|
const COST_COEF = 500;
|
||||||
const MIN_POP = 30000;
|
const MIN_POP = 30000;
|
||||||
|
|
||||||
|
const requireCapitalCity = (reason: string): Constraint => ({
|
||||||
|
name: 'requireCapitalCity',
|
||||||
|
requires: (ctx) => (ctx.nationId !== undefined ? [{ kind: 'nation', id: ctx.nationId }] : []),
|
||||||
|
test: (ctx: ConstraintContext, view: StateView) => {
|
||||||
|
if (ctx.nationId === undefined) {
|
||||||
|
return { kind: 'deny', reason };
|
||||||
|
}
|
||||||
|
const nation = view.get({ kind: 'nation', id: ctx.nationId }) as Nation | undefined;
|
||||||
|
if (!nation || !nation.capitalCityId) {
|
||||||
|
return { kind: 'deny', reason };
|
||||||
|
}
|
||||||
|
return { kind: 'allow' };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const reqDestCityValue = (
|
||||||
|
comp: '>' | '<' | '>=' | '<=',
|
||||||
|
required: number | 'origin',
|
||||||
|
reason: string
|
||||||
|
): Constraint => ({
|
||||||
|
name: 'reqDestCityValue',
|
||||||
|
requires: (ctx) =>
|
||||||
|
ctx.nationId !== undefined ? [{ kind: 'nation', id: ctx.nationId }, { kind: 'env', key: 'map' }] : [],
|
||||||
|
test: (ctx: ConstraintContext, view: StateView) => {
|
||||||
|
if (ctx.nationId === undefined) {
|
||||||
|
return { kind: 'deny', reason };
|
||||||
|
}
|
||||||
|
const nation = view.get({ kind: 'nation', id: ctx.nationId }) as Nation | undefined;
|
||||||
|
if (!nation || !nation.capitalCityId) {
|
||||||
|
return { kind: 'deny', reason: '방랑상태에서는 불가능합니다.' };
|
||||||
|
}
|
||||||
|
const city = view.get({ kind: 'city', id: nation.capitalCityId }) as City | undefined;
|
||||||
|
if (!city) {
|
||||||
|
return { kind: 'deny', reason: '수도 정보를 찾을 수 없습니다.' };
|
||||||
|
}
|
||||||
|
const compareTarget =
|
||||||
|
required === 'origin'
|
||||||
|
? ((view.get({ kind: 'env', key: 'map' }) as MapDefinition | undefined)?.cities.find(
|
||||||
|
(mapCity) => mapCity.id === nation.capitalCityId
|
||||||
|
)?.level ??
|
||||||
|
0)
|
||||||
|
: required;
|
||||||
|
const level = city.level;
|
||||||
|
const allow =
|
||||||
|
comp === '>'
|
||||||
|
? level > compareTarget
|
||||||
|
: comp === '<'
|
||||||
|
? level < compareTarget
|
||||||
|
: comp === '>='
|
||||||
|
? level >= compareTarget
|
||||||
|
: level <= compareTarget;
|
||||||
|
if (allow) {
|
||||||
|
return { kind: 'allow' };
|
||||||
|
}
|
||||||
|
return { kind: 'deny', reason };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export class ActionDefinition<
|
export class ActionDefinition<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
> implements GeneralActionDefinition<TriggerState, ReduceCityArgs, ReduceCityResolveContext<TriggerState>> {
|
> implements GeneralActionDefinition<TriggerState, ReduceCityArgs, ReduceCityResolveContext<TriggerState>> {
|
||||||
@@ -44,7 +103,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildMinConstraints(_ctx: ConstraintContext, _args: ReduceCityArgs): Constraint[] {
|
buildMinConstraints(_ctx: ConstraintContext, _args: ReduceCityArgs): Constraint[] {
|
||||||
return [occupiedCity(), beChief(), suppliedCity()];
|
return [notBeNeutral()];
|
||||||
}
|
}
|
||||||
|
|
||||||
private getRecoverAmount(): number {
|
private getRecoverAmount(): number {
|
||||||
@@ -53,28 +112,13 @@ export class ActionDefinition<
|
|||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, _args: ReduceCityArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: ReduceCityArgs): Constraint[] {
|
||||||
return [
|
return [
|
||||||
|
notBeNeutral(),
|
||||||
occupiedCity(),
|
occupiedCity(),
|
||||||
beChief(),
|
beChief(),
|
||||||
suppliedCity(),
|
suppliedCity(),
|
||||||
{
|
requireCapitalCity('방랑상태에서는 불가능합니다.'),
|
||||||
name: 'reducibleCity',
|
reqDestCityValue('>', 4, '더이상 감축할 수 없습니다.'),
|
||||||
requires: (ctx) => [
|
reqDestCityValue('>', 'origin', '더이상 감축할 수 없습니다.'),
|
||||||
{ kind: 'nation', id: ctx.nationId! },
|
|
||||||
{ kind: 'city', id: 0 },
|
|
||||||
],
|
|
||||||
test: (ctx: ConstraintContext, view: StateView) => {
|
|
||||||
const nation = view.get({ kind: 'nation', id: ctx.nationId! }) as Nation | undefined;
|
|
||||||
const capitalCityId = nation?.capitalCityId;
|
|
||||||
|
|
||||||
if (!capitalCityId) return { kind: 'deny', reason: '방랑상태에서는 불가능합니다.' };
|
|
||||||
|
|
||||||
const capitalCity = view.get({ kind: 'city', id: capitalCityId }) as City | undefined;
|
|
||||||
if (!capitalCity) return { kind: 'deny', reason: '수도 정보를 찾을 수 없습니다.' };
|
|
||||||
if (capitalCity.level <= 4) return { kind: 'deny', reason: '더이상 감축할 수 없습니다.' };
|
|
||||||
|
|
||||||
return { kind: 'allow' };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ import {
|
|||||||
suppliedCity,
|
suppliedCity,
|
||||||
differentDestNation,
|
differentDestNation,
|
||||||
existsDestNation,
|
existsDestNation,
|
||||||
|
reqDestNationValue,
|
||||||
|
reqNationGold,
|
||||||
|
reqNationRice,
|
||||||
|
reqNationValue,
|
||||||
} 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 {
|
||||||
@@ -39,6 +43,25 @@ const ACTION_NAME = '원조';
|
|||||||
const COEF_AID_AMOUNT = 10000;
|
const COEF_AID_AMOUNT = 10000;
|
||||||
const POST_REQ_TURN = 12;
|
const POST_REQ_TURN = 12;
|
||||||
|
|
||||||
|
const reqAidWithinLimit = (goldAmount: number, riceAmount: number): Constraint => ({
|
||||||
|
name: 'reqAidWithinLimit',
|
||||||
|
requires: (ctx) => (ctx.nationId !== undefined ? [{ kind: 'nation', id: ctx.nationId }] : []),
|
||||||
|
test: (ctx: ConstraintContext, view: StateView) => {
|
||||||
|
if (ctx.nationId === undefined) {
|
||||||
|
return { kind: 'deny', reason: '국가 정보가 없습니다.' };
|
||||||
|
}
|
||||||
|
const nation = view.get({ kind: 'nation', id: ctx.nationId }) as Nation | undefined;
|
||||||
|
if (!nation) {
|
||||||
|
return { kind: 'deny', reason: '국가 정보가 없습니다.' };
|
||||||
|
}
|
||||||
|
const limit = nation.level * COEF_AID_AMOUNT;
|
||||||
|
if (goldAmount > limit || riceAmount > limit) {
|
||||||
|
return { kind: 'deny', reason: '작위 제한량 이상은 보낼 수 없습니다.' };
|
||||||
|
}
|
||||||
|
return { kind: 'allow' };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export class ActionDefinition<
|
export class ActionDefinition<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
> implements GeneralActionDefinition<TriggerState, MaterialAidArgs, MaterialAidResolveContext<TriggerState>> {
|
> implements GeneralActionDefinition<TriggerState, MaterialAidArgs, MaterialAidResolveContext<TriggerState>> {
|
||||||
@@ -52,22 +75,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildMinConstraints(_ctx: ConstraintContext, _args: MaterialAidArgs): Constraint[] {
|
buildMinConstraints(_ctx: ConstraintContext, _args: MaterialAidArgs): Constraint[] {
|
||||||
return [
|
return [occupiedCity(), beChief(), suppliedCity(), reqNationValue('surlimit', '외교제한', '==', 0, '외교제한중입니다.')];
|
||||||
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[] {
|
||||||
@@ -78,40 +86,11 @@ export class ActionDefinition<
|
|||||||
suppliedCity(),
|
suppliedCity(),
|
||||||
existsDestNation(),
|
existsDestNation(),
|
||||||
differentDestNation(),
|
differentDestNation(),
|
||||||
{
|
reqAidWithinLimit(goldAmount, riceAmount),
|
||||||
name: 'aidLimit',
|
reqNationGold(() => this.env.baseGold + (goldAmount > 0 ? 1 : 0)),
|
||||||
requires: (ctx) => [{ kind: 'nation', id: ctx.nationId! }],
|
reqNationRice(() => this.env.baseRice + (riceAmount > 0 ? 1 : 0)),
|
||||||
test: (ctx: ConstraintContext, view: StateView) => {
|
reqNationValue('surlimit', '외교제한', '==', 0, '외교제한중입니다.'),
|
||||||
const nation = view.get({ kind: 'nation', id: ctx.nationId! }) as Nation | undefined;
|
reqDestNationValue('surlimit', '외교제한', '==', 0, '상대국이 외교제한중입니다.'),
|
||||||
const limit = (nation?.level ?? 1) * COEF_AID_AMOUNT;
|
|
||||||
if (goldAmount > limit || riceAmount > limit) {
|
|
||||||
return { kind: 'deny', reason: '작위 제한량 이상은 보낼 수 없습니다.' };
|
|
||||||
}
|
|
||||||
return { kind: 'allow' };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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' };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'destNationSurlimit',
|
|
||||||
requires: () => [{ kind: 'nation', id: args.destNationId }],
|
|
||||||
test: (_ctx: ConstraintContext, view: StateView) => {
|
|
||||||
const destNation = view.get({ kind: 'nation', id: args.destNationId }) as Nation | undefined;
|
|
||||||
const surlimitRaw = destNation?.meta.surlimit;
|
|
||||||
const surlimit = typeof surlimitRaw === 'number' ? surlimitRaw : 0;
|
|
||||||
if (surlimit > 0) return { kind: 'deny', reason: '상대국이 외교제한중입니다.' };
|
|
||||||
return { kind: 'allow' };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import type { City, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/e
|
|||||||
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
|
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
|
||||||
import {
|
import {
|
||||||
beChief,
|
beChief,
|
||||||
|
notBeNeutral,
|
||||||
occupiedCity,
|
occupiedCity,
|
||||||
suppliedCity,
|
suppliedCity,
|
||||||
reqNationGold,
|
reqNationGold,
|
||||||
@@ -36,6 +37,52 @@ const WALL_INCREASE = 2000;
|
|||||||
const DEFAULT_COST = 60000;
|
const DEFAULT_COST = 60000;
|
||||||
const COST_COEF = 500;
|
const COST_COEF = 500;
|
||||||
|
|
||||||
|
const requireCapitalCity = (reason: string): Constraint => ({
|
||||||
|
name: 'requireCapitalCity',
|
||||||
|
requires: (ctx) => (ctx.nationId !== undefined ? [{ kind: 'nation', id: ctx.nationId }] : []),
|
||||||
|
test: (ctx: ConstraintContext, view: StateView) => {
|
||||||
|
if (ctx.nationId === undefined) {
|
||||||
|
return { kind: 'deny', reason };
|
||||||
|
}
|
||||||
|
const nation = view.get({ kind: 'nation', id: ctx.nationId }) as Nation | undefined;
|
||||||
|
if (!nation || !nation.capitalCityId) {
|
||||||
|
return { kind: 'deny', reason };
|
||||||
|
}
|
||||||
|
return { kind: 'allow' };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const reqDestCityValue = (comp: '>' | '<' | '>=' | '<=', required: number, reason: string): Constraint => ({
|
||||||
|
name: 'reqDestCityValue',
|
||||||
|
requires: (ctx) => (ctx.nationId !== undefined ? [{ kind: 'nation', id: ctx.nationId }] : []),
|
||||||
|
test: (ctx: ConstraintContext, view: StateView) => {
|
||||||
|
if (ctx.nationId === undefined) {
|
||||||
|
return { kind: 'deny', reason };
|
||||||
|
}
|
||||||
|
const nation = view.get({ kind: 'nation', id: ctx.nationId }) as Nation | undefined;
|
||||||
|
if (!nation || !nation.capitalCityId) {
|
||||||
|
return { kind: 'deny', reason: '방랑상태에서는 불가능합니다.' };
|
||||||
|
}
|
||||||
|
const city = view.get({ kind: 'city', id: nation.capitalCityId }) as City | undefined;
|
||||||
|
if (!city) {
|
||||||
|
return { kind: 'deny', reason: '수도 정보를 찾을 수 없습니다.' };
|
||||||
|
}
|
||||||
|
const level = city.level;
|
||||||
|
const allow =
|
||||||
|
comp === '>'
|
||||||
|
? level > required
|
||||||
|
: comp === '<'
|
||||||
|
? level < required
|
||||||
|
: comp === '>='
|
||||||
|
? level >= required
|
||||||
|
: level <= required;
|
||||||
|
if (allow) {
|
||||||
|
return { kind: 'allow' };
|
||||||
|
}
|
||||||
|
return { kind: 'deny', reason };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export class ActionDefinition<
|
export class ActionDefinition<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
> implements GeneralActionDefinition<TriggerState, ExpandCityArgs, ExpandCityResolveContext<TriggerState>> {
|
> implements GeneralActionDefinition<TriggerState, ExpandCityArgs, ExpandCityResolveContext<TriggerState>> {
|
||||||
@@ -49,7 +96,7 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildMinConstraints(_ctx: ConstraintContext, _args: ExpandCityArgs): Constraint[] {
|
buildMinConstraints(_ctx: ConstraintContext, _args: ExpandCityArgs): Constraint[] {
|
||||||
return [occupiedCity(), beChief(), suppliedCity()];
|
return [notBeNeutral()];
|
||||||
}
|
}
|
||||||
|
|
||||||
private getCost(): number {
|
private getCost(): number {
|
||||||
@@ -59,31 +106,15 @@ export class ActionDefinition<
|
|||||||
buildConstraints(_ctx: ConstraintContext, _args: ExpandCityArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, _args: ExpandCityArgs): Constraint[] {
|
||||||
const cost = this.getCost();
|
const cost = this.getCost();
|
||||||
return [
|
return [
|
||||||
|
notBeNeutral(),
|
||||||
occupiedCity(),
|
occupiedCity(),
|
||||||
beChief(),
|
beChief(),
|
||||||
suppliedCity(),
|
suppliedCity(),
|
||||||
|
requireCapitalCity('방랑상태에서는 불가능합니다.'),
|
||||||
|
reqDestCityValue('>', 3, '수진, 진, 관문에서는 불가능합니다.'),
|
||||||
|
reqDestCityValue('<', 8, '더이상 증축할 수 없습니다.'),
|
||||||
reqNationGold(() => this.env.baseGold + cost),
|
reqNationGold(() => this.env.baseGold + cost),
|
||||||
reqNationRice(() => this.env.baseRice + cost),
|
reqNationRice(() => this.env.baseRice + cost),
|
||||||
{
|
|
||||||
name: 'expandableCity',
|
|
||||||
requires: (ctx) => [
|
|
||||||
{ kind: 'nation', id: ctx.nationId! },
|
|
||||||
{ kind: 'city', id: 0 },
|
|
||||||
],
|
|
||||||
test: (ctx: ConstraintContext, view: StateView) => {
|
|
||||||
const nation = view.get({ kind: 'nation', id: ctx.nationId! }) as Nation | undefined;
|
|
||||||
const capitalCityId = nation?.capitalCityId;
|
|
||||||
|
|
||||||
if (!capitalCityId) return { kind: 'deny', reason: '방랑상태에서는 불가능합니다.' };
|
|
||||||
|
|
||||||
const capitalCity = view.get({ kind: 'city', id: capitalCityId }) as City | undefined;
|
|
||||||
if (!capitalCity) return { kind: 'deny', reason: '수도 정보를 찾을 수 없습니다.' };
|
|
||||||
if (capitalCity.level <= 3) return { kind: 'deny', reason: '수진, 진, 관문에서는 불가능합니다.' };
|
|
||||||
if (capitalCity.level >= 8) return { kind: 'deny', reason: '더이상 증축할 수 없습니다.' };
|
|
||||||
|
|
||||||
return { kind: 'allow' };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import type { City, GeneralTriggerState, Nation, TriggerValue } from '@sammo-ts/logic/domain/entities.js';
|
import type { City, GeneralTriggerState, Nation, TriggerValue } from '@sammo-ts/logic/domain/entities.js';
|
||||||
import type { Constraint, ConstraintContext, StateView } from '@sammo-ts/logic/constraints/types.js';
|
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||||
import {
|
import {
|
||||||
beChief,
|
beChief,
|
||||||
disallowDiplomacyBetweenStatus,
|
disallowDiplomacyStatus,
|
||||||
occupiedCity,
|
occupiedCity,
|
||||||
occupiedDestCity,
|
occupiedDestCity,
|
||||||
|
reqNationValue,
|
||||||
suppliedCity,
|
suppliedCity,
|
||||||
suppliedDestCity,
|
suppliedDestCity,
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
} from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import { allow, unknownOrDeny } from '@sammo-ts/logic/constraints/helpers.js';
|
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type {
|
import type {
|
||||||
GeneralActionEffect,
|
GeneralActionEffect,
|
||||||
@@ -43,45 +43,6 @@ const ACTION_NAME = '초토화';
|
|||||||
const PRE_REQ_TURN = 2;
|
const PRE_REQ_TURN = 2;
|
||||||
const POST_REQ_TURN = 24;
|
const POST_REQ_TURN = 24;
|
||||||
|
|
||||||
const requireNoDiplomacyLimit = (): Constraint => ({
|
|
||||||
name: 'requireNoDiplomacyLimit',
|
|
||||||
requires: (ctx) => (ctx.nationId !== undefined ? [{ kind: 'nation', id: ctx.nationId }] : []),
|
|
||||||
test: (ctx: ConstraintContext, view: StateView) => {
|
|
||||||
const nationId = ctx.nationId;
|
|
||||||
if (nationId === undefined) {
|
|
||||||
return unknownOrDeny(ctx, [], '국가 정보가 없습니다.');
|
|
||||||
}
|
|
||||||
const nation = view.get({ kind: 'nation', id: nationId }) as Nation | null;
|
|
||||||
if (!nation) {
|
|
||||||
return unknownOrDeny(ctx, [{ kind: 'nation', id: nationId }], '국가 정보가 없습니다.');
|
|
||||||
}
|
|
||||||
const surlimit = typeof nation.meta?.surlimit === 'number' ? Number(nation.meta.surlimit) : 0;
|
|
||||||
if (surlimit > 0) {
|
|
||||||
return { kind: 'deny', reason: '외교제한 턴이 남아있습니다.' };
|
|
||||||
}
|
|
||||||
return allow();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const notCapitalCity = (destCityId: number): Constraint => ({
|
|
||||||
name: 'notCapitalCity',
|
|
||||||
requires: (ctx) => (ctx.nationId !== undefined ? [{ kind: 'nation', id: ctx.nationId }] : []),
|
|
||||||
test: (ctx: ConstraintContext, view: StateView) => {
|
|
||||||
const nationId = ctx.nationId;
|
|
||||||
if (nationId === undefined) {
|
|
||||||
return unknownOrDeny(ctx, [], '국가 정보가 없습니다.');
|
|
||||||
}
|
|
||||||
const nation = view.get({ kind: 'nation', id: nationId }) as Nation | null;
|
|
||||||
if (!nation) {
|
|
||||||
return unknownOrDeny(ctx, [{ kind: 'nation', id: nationId }], '국가 정보가 없습니다.');
|
|
||||||
}
|
|
||||||
if (nation.capitalCityId === destCityId) {
|
|
||||||
return { kind: 'deny', reason: '수도입니다.' };
|
|
||||||
}
|
|
||||||
return allow();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const calcReturnAmount = (destCity: City): number => {
|
const calcReturnAmount = (destCity: City): number => {
|
||||||
let amount = destCity.population / 5;
|
let amount = destCity.population / 5;
|
||||||
const resourcePairs: Array<[number, number]> = [
|
const resourcePairs: Array<[number, number]> = [
|
||||||
@@ -117,7 +78,12 @@ export class ActionDefinition<
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildMinConstraints(_ctx: ConstraintContext, _args: ScorchedEarthArgs): Constraint[] {
|
buildMinConstraints(_ctx: ConstraintContext, _args: ScorchedEarthArgs): Constraint[] {
|
||||||
return [occupiedCity(), beChief(), suppliedCity(), requireNoDiplomacyLimit()];
|
return [
|
||||||
|
occupiedCity(),
|
||||||
|
beChief(),
|
||||||
|
suppliedCity(),
|
||||||
|
reqNationValue('surlimit', '제한 턴', '==', 0, '외교제한 턴이 남아있습니다.'),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConstraints(_ctx: ConstraintContext, args: ScorchedEarthArgs): Constraint[] {
|
buildConstraints(_ctx: ConstraintContext, args: ScorchedEarthArgs): Constraint[] {
|
||||||
@@ -128,9 +94,9 @@ export class ActionDefinition<
|
|||||||
beChief(),
|
beChief(),
|
||||||
suppliedCity(),
|
suppliedCity(),
|
||||||
suppliedDestCity(),
|
suppliedDestCity(),
|
||||||
notCapitalCity(args.destCityId),
|
reqNationValue('capitalCityId', '수도', '!=', args.destCityId, '수도입니다.'),
|
||||||
requireNoDiplomacyLimit(),
|
reqNationValue('surlimit', '제한 턴', '==', 0, '외교제한 턴이 남아있습니다.'),
|
||||||
disallowDiplomacyBetweenStatus({
|
disallowDiplomacyStatus({
|
||||||
0: '평시에만 가능합니다.',
|
0: '평시에만 가능합니다.',
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -92,6 +92,11 @@ export const disallowDiplomacyBetweenStatus = (disallowList: Record<number, stri
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const disallowDiplomacyStatus = (disallowList: Record<number, string>): Constraint => ({
|
||||||
|
...disallowDiplomacyBetweenStatus(disallowList),
|
||||||
|
name: 'disallowDiplomacyStatus',
|
||||||
|
});
|
||||||
|
|
||||||
export const allowDiplomacyBetweenStatus = (allowList: number[], reason: string): Constraint => ({
|
export const allowDiplomacyBetweenStatus = (allowList: number[], reason: string): Constraint => ({
|
||||||
name: 'allowDiplomacyBetweenStatus',
|
name: 'allowDiplomacyBetweenStatus',
|
||||||
requires: (ctx) => {
|
requires: (ctx) => {
|
||||||
|
|||||||
@@ -310,6 +310,8 @@ const ALWAYS_FAIL_TS_ALIASES = new Set([
|
|||||||
'reqfuturetreatyterm',
|
'reqfuturetreatyterm',
|
||||||
'reqvalidstrategiccommandtype',
|
'reqvalidstrategiccommandtype',
|
||||||
'hasroutetodestcity',
|
'hasroutetodestcity',
|
||||||
|
'requirecapitalcity',
|
||||||
|
'reqaidwithinlimit',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const canonicalizeConstraintName = (side, normalizedName) => {
|
const canonicalizeConstraintName = (side, normalizedName) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user