286 lines
10 KiB
TypeScript
286 lines
10 KiB
TypeScript
import {
|
|
allow,
|
|
readDestCity,
|
|
readDiplomacyState,
|
|
readGeneral,
|
|
resolveDestCityId,
|
|
resolveDestNationId,
|
|
unknownOrDeny,
|
|
} from './helpers.js';
|
|
import type { Constraint, RequirementKey } from './types.js';
|
|
|
|
const readDiplomacyEntry = (
|
|
view: { has(req: RequirementKey): boolean; get(req: RequirementKey): unknown },
|
|
srcNationId: number,
|
|
destNationId: number
|
|
): { state: number | null; term: number | null } | null => {
|
|
const req: RequirementKey = {
|
|
kind: 'diplomacy',
|
|
srcNationId,
|
|
destNationId,
|
|
};
|
|
if (!view.has(req)) {
|
|
return null;
|
|
}
|
|
const value = view.get(req);
|
|
if (typeof value === 'number') {
|
|
return { state: value, term: null };
|
|
}
|
|
if (value && typeof value === 'object') {
|
|
const record = value as { state?: number; stateCode?: number; term?: number };
|
|
const state =
|
|
typeof record.state === 'number'
|
|
? record.state
|
|
: typeof record.stateCode === 'number'
|
|
? record.stateCode
|
|
: null;
|
|
const term = typeof record.term === 'number' ? record.term : null;
|
|
return { state, term };
|
|
}
|
|
return null;
|
|
};
|
|
|
|
export const disallowDiplomacyBetweenStatus = (disallowList: Record<number, string>): Constraint => ({
|
|
name: 'disallowDiplomacyBetweenStatus',
|
|
requires: (ctx) => {
|
|
const reqs: RequirementKey[] = [];
|
|
if (ctx.nationId !== undefined) {
|
|
reqs.push({ kind: 'nation', id: ctx.nationId });
|
|
}
|
|
const destNationId = resolveDestNationId(ctx);
|
|
if (destNationId !== undefined) {
|
|
reqs.push({ kind: 'destNation', id: destNationId });
|
|
if (ctx.nationId !== undefined) {
|
|
reqs.push({
|
|
kind: 'diplomacy',
|
|
srcNationId: ctx.nationId,
|
|
destNationId,
|
|
});
|
|
}
|
|
}
|
|
const destCityId = resolveDestCityId(ctx);
|
|
if (destCityId !== undefined) {
|
|
reqs.push({ kind: 'destCity', id: destCityId });
|
|
}
|
|
return reqs;
|
|
},
|
|
test: (ctx, view) => {
|
|
const general = readGeneral(ctx, view);
|
|
const baseNationId = ctx.nationId ?? general?.nationId;
|
|
if (baseNationId === undefined) {
|
|
return unknownOrDeny(ctx, [], '국가 정보가 없습니다.');
|
|
}
|
|
const destCity = readDestCity(ctx, view);
|
|
const destNationId = resolveDestNationId(ctx) ?? destCity?.nationId;
|
|
if (destNationId === undefined) {
|
|
return unknownOrDeny(ctx, [], '상대 국가 정보가 없습니다.');
|
|
}
|
|
const state = readDiplomacyState(view, baseNationId, destNationId);
|
|
if (state === null) {
|
|
const req: RequirementKey = {
|
|
kind: 'diplomacy',
|
|
srcNationId: baseNationId,
|
|
destNationId,
|
|
};
|
|
return unknownOrDeny(ctx, [req], '외교 정보가 없습니다.');
|
|
}
|
|
const reason = disallowList[state];
|
|
if (reason !== undefined) {
|
|
return { kind: 'deny', reason };
|
|
}
|
|
return allow();
|
|
},
|
|
});
|
|
|
|
export const disallowDiplomacyStatus = (disallowList: Record<number, string>): Constraint => ({
|
|
name: 'disallowDiplomacyStatus',
|
|
requires: (ctx) => [
|
|
...(ctx.nationId !== undefined ? ([{ kind: 'nation', id: ctx.nationId }] as RequirementKey[]) : []),
|
|
{ kind: 'diplomacyList' },
|
|
],
|
|
test: (ctx, view) => {
|
|
const general = readGeneral(ctx, view);
|
|
const baseNationId = ctx.nationId ?? general?.nationId;
|
|
if (baseNationId === undefined) {
|
|
return unknownOrDeny(ctx, [], '국가 정보가 없습니다.');
|
|
}
|
|
const req: RequirementKey = { kind: 'diplomacyList' };
|
|
if (!view.has(req)) {
|
|
return unknownOrDeny(ctx, [req], '외교 정보가 없습니다.');
|
|
}
|
|
const entries = view.get(req);
|
|
if (!Array.isArray(entries)) {
|
|
return unknownOrDeny(ctx, [req], '외교 정보가 없습니다.');
|
|
}
|
|
for (const value of entries) {
|
|
if (!value || typeof value !== 'object') {
|
|
continue;
|
|
}
|
|
const entry = value as {
|
|
fromNationId?: number;
|
|
srcNationId?: number;
|
|
me?: number;
|
|
state?: number;
|
|
stateCode?: number;
|
|
};
|
|
const fromNationId = entry.fromNationId ?? entry.srcNationId ?? entry.me;
|
|
if (fromNationId !== baseNationId) {
|
|
continue;
|
|
}
|
|
const state = entry.state ?? entry.stateCode;
|
|
if (state === undefined) {
|
|
continue;
|
|
}
|
|
const reason = disallowList[state];
|
|
if (reason !== undefined) {
|
|
return { kind: 'deny', reason };
|
|
}
|
|
}
|
|
return allow();
|
|
},
|
|
});
|
|
|
|
export const allowDiplomacyBetweenStatus = (allowList: number[], reason: string): Constraint => ({
|
|
name: 'allowDiplomacyBetweenStatus',
|
|
requires: (ctx) => {
|
|
const reqs: RequirementKey[] = [];
|
|
if (ctx.nationId !== undefined) {
|
|
reqs.push({ kind: 'nation', id: ctx.nationId });
|
|
}
|
|
const destNationId = resolveDestNationId(ctx);
|
|
if (destNationId !== undefined) {
|
|
reqs.push({ kind: 'destNation', id: destNationId });
|
|
if (ctx.nationId !== undefined) {
|
|
reqs.push({
|
|
kind: 'diplomacy',
|
|
srcNationId: ctx.nationId,
|
|
destNationId,
|
|
});
|
|
}
|
|
}
|
|
const destCityId = resolveDestCityId(ctx);
|
|
if (destCityId !== undefined) {
|
|
reqs.push({ kind: 'destCity', id: destCityId });
|
|
}
|
|
return reqs;
|
|
},
|
|
test: (ctx, view) => {
|
|
const general = readGeneral(ctx, view);
|
|
const baseNationId = ctx.nationId ?? general?.nationId;
|
|
if (baseNationId === undefined) {
|
|
return unknownOrDeny(ctx, [], '국가 정보가 없습니다.');
|
|
}
|
|
const destCity = readDestCity(ctx, view);
|
|
const destNationId = resolveDestNationId(ctx) ?? destCity?.nationId;
|
|
if (destNationId === undefined) {
|
|
return unknownOrDeny(ctx, [], '상대 국가 정보가 없습니다.');
|
|
}
|
|
const state = readDiplomacyState(view, baseNationId, destNationId);
|
|
if (state === null) {
|
|
const req: RequirementKey = {
|
|
kind: 'diplomacy',
|
|
srcNationId: baseNationId,
|
|
destNationId,
|
|
};
|
|
return unknownOrDeny(ctx, [req], '외교 정보가 없습니다.');
|
|
}
|
|
if (!allowList.includes(state)) {
|
|
return { kind: 'deny', reason };
|
|
}
|
|
return allow();
|
|
},
|
|
});
|
|
|
|
export const allowDiplomacyWithTerm = (requiredState: number, minTerm: number, reason: string): Constraint => ({
|
|
name: 'allowDiplomacyWithTerm',
|
|
requires: (ctx) => {
|
|
const reqs: RequirementKey[] = [];
|
|
if (ctx.nationId !== undefined) {
|
|
reqs.push({ kind: 'nation', id: ctx.nationId });
|
|
}
|
|
const destNationId = resolveDestNationId(ctx);
|
|
if (destNationId !== undefined) {
|
|
reqs.push({ kind: 'destNation', id: destNationId });
|
|
if (ctx.nationId !== undefined) {
|
|
reqs.push({
|
|
kind: 'diplomacy',
|
|
srcNationId: ctx.nationId,
|
|
destNationId,
|
|
});
|
|
}
|
|
}
|
|
const destCityId = resolveDestCityId(ctx);
|
|
if (destCityId !== undefined) {
|
|
reqs.push({ kind: 'destCity', id: destCityId });
|
|
}
|
|
return reqs;
|
|
},
|
|
test: (ctx, view) => {
|
|
const general = readGeneral(ctx, view);
|
|
const baseNationId = ctx.nationId ?? general?.nationId;
|
|
if (baseNationId === undefined) {
|
|
return unknownOrDeny(ctx, [], '국가 정보가 없습니다.');
|
|
}
|
|
const destCity = readDestCity(ctx, view);
|
|
const destNationId = resolveDestNationId(ctx) ?? destCity?.nationId;
|
|
if (destNationId === undefined) {
|
|
return unknownOrDeny(ctx, [], '상대 국가 정보가 없습니다.');
|
|
}
|
|
const entry = readDiplomacyEntry(view, baseNationId, destNationId);
|
|
if (!entry || entry.state === null || entry.term === null) {
|
|
const req: RequirementKey = {
|
|
kind: 'diplomacy',
|
|
srcNationId: baseNationId,
|
|
destNationId,
|
|
};
|
|
return unknownOrDeny(ctx, [req], '외교 정보가 없습니다.');
|
|
}
|
|
if (entry.state !== requiredState || entry.term < minTerm) {
|
|
return { kind: 'deny', reason };
|
|
}
|
|
return allow();
|
|
},
|
|
});
|
|
|
|
export const allowDiplomacyStatus = (allowList: number[], reason: string): Constraint => ({
|
|
name: 'allowDiplomacyStatus',
|
|
requires: (ctx) => {
|
|
const reqs: RequirementKey[] = [{ kind: 'general', id: ctx.actorId }];
|
|
if (ctx.nationId !== undefined) {
|
|
reqs.push({ kind: 'nation', id: ctx.nationId });
|
|
}
|
|
reqs.push({ kind: 'diplomacyList' });
|
|
return reqs;
|
|
},
|
|
test: (ctx, view) => {
|
|
const general = readGeneral(ctx, view);
|
|
const baseNationId = ctx.nationId ?? general?.nationId;
|
|
if (baseNationId === undefined) {
|
|
return unknownOrDeny(ctx, [], '국가 정보가 없습니다.');
|
|
}
|
|
const req: RequirementKey = { kind: 'diplomacyList' };
|
|
if (!view.has(req)) {
|
|
return unknownOrDeny(ctx, [req], '외교 정보가 없습니다.');
|
|
}
|
|
const list = view.get(req);
|
|
if (!Array.isArray(list)) {
|
|
return unknownOrDeny(ctx, [req], '외교 정보가 없습니다.');
|
|
}
|
|
const matched = list.some((entry) => {
|
|
if (!entry || typeof entry !== 'object') {
|
|
return false;
|
|
}
|
|
const record = entry as { fromNationId?: number; state?: number };
|
|
return (
|
|
record.fromNationId === baseNationId &&
|
|
typeof record.state === 'number' &&
|
|
allowList.includes(record.state)
|
|
);
|
|
});
|
|
if (!matched) {
|
|
return { kind: 'deny', reason };
|
|
}
|
|
return allow();
|
|
},
|
|
});
|