코드 이식
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import type { City, General, Nation } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { MapDefinition } from '@sammo-ts/logic/world/types.js';
|
||||
import { getCityDistance } from '../world/distance.js';
|
||||
import {
|
||||
allow,
|
||||
parsePercent,
|
||||
@@ -113,11 +114,11 @@ export const suppliedDestCity = (): Constraint => ({
|
||||
requires: (ctx) =>
|
||||
resolveDestCityId(ctx) !== undefined
|
||||
? [
|
||||
{
|
||||
kind: 'destCity',
|
||||
id: resolveDestCityId(ctx) ?? 0,
|
||||
},
|
||||
]
|
||||
{
|
||||
kind: 'destCity',
|
||||
id: resolveDestCityId(ctx) ?? 0,
|
||||
},
|
||||
]
|
||||
: [],
|
||||
test: (ctx, view) => {
|
||||
const destCity = readDestCity(ctx, view);
|
||||
@@ -249,11 +250,11 @@ export const existsDestCity = (): Constraint => ({
|
||||
requires: (ctx) =>
|
||||
resolveDestCityId(ctx) !== undefined
|
||||
? [
|
||||
{
|
||||
kind: 'destCity',
|
||||
id: resolveDestCityId(ctx) ?? 0,
|
||||
},
|
||||
]
|
||||
{
|
||||
kind: 'destCity',
|
||||
id: resolveDestCityId(ctx) ?? 0,
|
||||
},
|
||||
]
|
||||
: [],
|
||||
test: (ctx, view) => {
|
||||
const destCityId = resolveDestCityId(ctx);
|
||||
@@ -315,11 +316,11 @@ export const notNeutralDestCity = (): Constraint => ({
|
||||
requires: (ctx) =>
|
||||
resolveDestCityId(ctx) !== undefined
|
||||
? [
|
||||
{
|
||||
kind: 'destCity',
|
||||
id: resolveDestCityId(ctx) ?? 0,
|
||||
},
|
||||
]
|
||||
{
|
||||
kind: 'destCity',
|
||||
id: resolveDestCityId(ctx) ?? 0,
|
||||
},
|
||||
]
|
||||
: [],
|
||||
test: (ctx, view) => {
|
||||
const destCity = readDestCity(ctx, view);
|
||||
@@ -480,3 +481,94 @@ export const reqCityLevel = (levels: number[]): Constraint => ({
|
||||
return { kind: 'deny', reason: '규모가 맞지 않습니다.' };
|
||||
},
|
||||
});
|
||||
|
||||
export const nearCity = (maxDistance: number): Constraint => ({
|
||||
name: 'nearCity',
|
||||
requires: (ctx) => {
|
||||
const reqs: RequirementKey[] = [{ kind: 'env', key: 'map' }];
|
||||
const destCityId = resolveDestCityId(ctx);
|
||||
if (destCityId !== undefined) {
|
||||
reqs.push({ kind: 'destCity', id: destCityId });
|
||||
}
|
||||
if (ctx.cityId !== undefined) {
|
||||
reqs.push({ kind: 'city', id: ctx.cityId });
|
||||
}
|
||||
return reqs;
|
||||
},
|
||||
test: (ctx, view) => {
|
||||
const map = view.get({ kind: 'env', key: 'map' }) as MapDefinition | null;
|
||||
if (!map) {
|
||||
return unknownOrDeny(ctx, [], '지도 정보가 없습니다.');
|
||||
}
|
||||
|
||||
const destCityId = resolveDestCityId(ctx);
|
||||
if (destCityId === undefined) {
|
||||
return unknownOrDeny(ctx, [], '도시 정보가 없습니다.');
|
||||
}
|
||||
|
||||
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 distance = getCityDistance(map, city.id, destCityId);
|
||||
if (distance <= maxDistance) {
|
||||
return allow();
|
||||
}
|
||||
|
||||
return { kind: 'deny', reason: '너무 멉니다.' };
|
||||
},
|
||||
});
|
||||
|
||||
export const notCapital = (checkCurrentCity = false): Constraint => ({
|
||||
name: 'notCapital',
|
||||
requires: (ctx) => {
|
||||
const reqs: RequirementKey[] = [{ kind: 'general', id: ctx.actorId }];
|
||||
if (checkCurrentCity) {
|
||||
if (ctx.cityId !== undefined) {
|
||||
reqs.push({ kind: 'city', id: ctx.cityId });
|
||||
}
|
||||
} else {
|
||||
// If checking dest, we need destCityId
|
||||
const destCityId = resolveDestCityId(ctx);
|
||||
if (destCityId !== undefined) {
|
||||
reqs.push({ kind: 'destCity', id: destCityId });
|
||||
}
|
||||
}
|
||||
// Need nation to know capital
|
||||
reqs.push({ kind: 'nation', id: ctx.nationId });
|
||||
return reqs;
|
||||
},
|
||||
test: (ctx, view) => {
|
||||
const nationReq: RequirementKey = { kind: 'nation', id: ctx.nationId };
|
||||
if (!view.has(nationReq)) return unknownOrDeny(ctx, [nationReq], '국가 정보가 없습니다.');
|
||||
const nation = view.get(nationReq) as Nation | null;
|
||||
if (!nation) return unknownOrDeny(ctx, [nationReq], '국가 정보가 없습니다.');
|
||||
|
||||
let targetCityId: number | undefined;
|
||||
|
||||
if (checkCurrentCity) {
|
||||
targetCityId = ctx.cityId;
|
||||
if (targetCityId === undefined) {
|
||||
const general = readGeneral(ctx, view);
|
||||
targetCityId = general?.cityId;
|
||||
}
|
||||
} else {
|
||||
targetCityId = resolveDestCityId(ctx);
|
||||
}
|
||||
|
||||
if (targetCityId === undefined) {
|
||||
return unknownOrDeny(ctx, [], '도시 정보가 없습니다.');
|
||||
}
|
||||
|
||||
if (targetCityId === nation.capitalCityId) {
|
||||
return { kind: 'deny', reason: '수도입니다.' };
|
||||
}
|
||||
return allow();
|
||||
},
|
||||
});
|
||||
|
||||
@@ -181,11 +181,11 @@ export const existsDestGeneral = (): Constraint => ({
|
||||
requires: (ctx) =>
|
||||
resolveDestGeneralId(ctx) !== undefined
|
||||
? [
|
||||
{
|
||||
kind: 'destGeneral',
|
||||
id: resolveDestGeneralId(ctx) ?? 0,
|
||||
},
|
||||
]
|
||||
{
|
||||
kind: 'destGeneral',
|
||||
id: resolveDestGeneralId(ctx) ?? 0,
|
||||
},
|
||||
]
|
||||
: [],
|
||||
test: (ctx, view) => {
|
||||
const destGeneralId = resolveDestGeneralId(ctx);
|
||||
@@ -282,3 +282,75 @@ export const friendlyDestGeneral = (): Constraint => ({
|
||||
return { kind: 'deny', reason: '아군이 아닙니다.' };
|
||||
},
|
||||
});
|
||||
|
||||
export const mustBeNPC = (): Constraint => ({
|
||||
name: 'mustBeNPC',
|
||||
requires: (ctx) => [{ kind: 'general', id: ctx.actorId }],
|
||||
test: (ctx, view) => {
|
||||
const req: RequirementKey = { kind: 'general', id: ctx.actorId };
|
||||
const general = view.get(req) as General | null;
|
||||
if (!general) {
|
||||
return unknownOrDeny(ctx, [req], '장수 정보가 없습니다.');
|
||||
}
|
||||
// Assuming npcState >= 2 means NPC. Need to verify exact logic if possible,
|
||||
// but typically 0=human, 1=?, 2=NPC.
|
||||
// Legacy: $general->getNPC() where 0:User, 1:Virtual User(unused?), 2:NPC ...
|
||||
if (general.npcState >= 2) {
|
||||
return allow();
|
||||
}
|
||||
return { kind: 'deny', reason: 'NPC가 아닙니다.' };
|
||||
},
|
||||
});
|
||||
|
||||
export const notSameDestNation = (): Constraint => ({
|
||||
name: 'notSameDestNation',
|
||||
requires: (ctx) => {
|
||||
const reqs: RequirementKey[] = [];
|
||||
const destNationId = resolveDestNationId(ctx);
|
||||
if (destNationId !== undefined) {
|
||||
reqs.push({ kind: 'destNation', id: destNationId });
|
||||
}
|
||||
return reqs;
|
||||
},
|
||||
test: (ctx, _view) => {
|
||||
const destNationId = resolveDestNationId(ctx);
|
||||
if (destNationId === undefined) {
|
||||
return unknownOrDeny(ctx, [], '목표 국가가 없습니다.');
|
||||
}
|
||||
|
||||
if (ctx.nationId === destNationId) {
|
||||
return { kind: 'deny', reason: '이미 소속된 국가입니다.' };
|
||||
}
|
||||
return allow();
|
||||
},
|
||||
});
|
||||
|
||||
export const notLord = (): Constraint => ({
|
||||
name: 'notLord',
|
||||
requires: (ctx) => [{ kind: 'general', id: ctx.actorId }],
|
||||
test: (ctx, view) => {
|
||||
const req: RequirementKey = { kind: 'general', id: ctx.actorId };
|
||||
const general = view.get(req) as General | null;
|
||||
if (!general) return unknownOrDeny(ctx, [req], '장수 정보가 없습니다.');
|
||||
|
||||
if (general.officerLevel !== 12) {
|
||||
return allow();
|
||||
}
|
||||
return { kind: 'deny', reason: '군주는 불가능합니다.' };
|
||||
},
|
||||
});
|
||||
|
||||
export const notChief = (): Constraint => ({
|
||||
name: 'notChief',
|
||||
requires: (ctx) => [{ kind: 'general', id: ctx.actorId }],
|
||||
test: (ctx, view) => {
|
||||
const req: RequirementKey = { kind: 'general', id: ctx.actorId };
|
||||
const general = view.get(req) as General | null;
|
||||
if (!general) return unknownOrDeny(ctx, [req], '장수 정보가 없습니다.');
|
||||
|
||||
if (general.officerLevel <= 4) {
|
||||
return allow();
|
||||
}
|
||||
return { kind: 'deny', reason: '수뇌입니다.' };
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user