test: cover multi-turn nation strategy commands
This commit is contained in:
@@ -48,14 +48,23 @@ const DEFAULT_GLOBAL_DELAY = 9;
|
||||
const PRE_REQ_TURN = 1;
|
||||
const EXP_DED_GAIN = 5 * (PRE_REQ_TURN + 1);
|
||||
|
||||
type InclusiveRandomGenerator = GeneralActionResolveContext['rng'] & {
|
||||
nextIntInclusive?: (maxInclusive: number) => number;
|
||||
};
|
||||
|
||||
const legacyChoiceIndex = (rng: GeneralActionResolveContext['rng'], length: number): number => {
|
||||
const inclusive = rng as InclusiveRandomGenerator;
|
||||
return inclusive.nextIntInclusive ? inclusive.nextIntInclusive(length - 1) : rng.nextInt(0, length);
|
||||
};
|
||||
|
||||
const pickMoveCityId = (rng: GeneralActionResolveContext['rng'], destCityId: number, candidates: City[]): number => {
|
||||
if (candidates.length === 0) {
|
||||
return destCityId;
|
||||
}
|
||||
let idx = rng.nextInt(0, candidates.length);
|
||||
let idx = legacyChoiceIndex(rng, candidates.length);
|
||||
let cityId = candidates[idx]?.id ?? destCityId;
|
||||
if (cityId === destCityId && candidates.length > 1) {
|
||||
idx = rng.nextInt(0, candidates.length);
|
||||
if (cityId === destCityId) {
|
||||
idx = legacyChoiceIndex(rng, candidates.length);
|
||||
cityId = candidates[idx]?.id ?? destCityId;
|
||||
}
|
||||
return cityId;
|
||||
|
||||
@@ -93,8 +93,51 @@ export const disallowDiplomacyBetweenStatus = (disallowList: Record<number, stri
|
||||
});
|
||||
|
||||
export const disallowDiplomacyStatus = (disallowList: Record<number, string>): Constraint => ({
|
||||
...disallowDiplomacyBetweenStatus(disallowList),
|
||||
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 => ({
|
||||
|
||||
@@ -422,6 +422,37 @@ describe('Nation Missing Actions', () => {
|
||||
expect(result.kind).toBe('deny');
|
||||
});
|
||||
|
||||
it('che_초토화: blocks when the nation is at war with any nation', () => {
|
||||
const general = buildGeneral(1, 1, 1);
|
||||
const nation = buildNation(1);
|
||||
const destNation = buildNation(2);
|
||||
const city = buildCity(1, 1);
|
||||
const destCity = buildCity(2, 2);
|
||||
const view = new TestStateView();
|
||||
view.set({ kind: 'general', id: general.id }, general);
|
||||
view.set({ kind: 'city', id: city.id }, city);
|
||||
view.set({ kind: 'nation', id: nation.id }, nation);
|
||||
view.set({ kind: 'destCity', id: destCity.id }, destCity);
|
||||
view.set({ kind: 'destNation', id: destNation.id }, destNation);
|
||||
setupDiplomacy(view, nation.id, destNation.id, 3);
|
||||
view.set({ kind: 'diplomacyList' }, [{ fromNationId: nation.id, toNationId: 3, state: 0, term: 12 }]);
|
||||
|
||||
const definition = new ScorchedEarthAction();
|
||||
const args = { destCityId: destCity.id };
|
||||
const ctx: ConstraintContext = {
|
||||
actorId: general.id,
|
||||
nationId: nation.id,
|
||||
cityId: city.id,
|
||||
destCityId: destCity.id,
|
||||
destNationId: destNation.id,
|
||||
args,
|
||||
env: {},
|
||||
mode: 'full',
|
||||
};
|
||||
|
||||
expect(evaluateConstraints(definition.buildConstraints(ctx, args), ctx, view).kind).toBe('deny');
|
||||
});
|
||||
|
||||
it('che_초토화: neutralizes city and increases nation resources', () => {
|
||||
const general = buildGeneral(1, 1, 1);
|
||||
const nation = buildNation(1);
|
||||
|
||||
Reference in New Issue
Block a user