feat(scenario): CHE 0기 여명 시나리오를 추가한다
일반 공백지 규칙을 유지하면서 가동 전 M장 50명과 유니크 획득 계수 2배를 적용한다. 시나리오 합성, 실제 M장 생성, Gateway 카탈로그와 Chromium 선택지를 회귀 검증한다.
This commit is contained in:
@@ -151,6 +151,25 @@ const buildHarness = (
|
||||
};
|
||||
|
||||
describe('CreateManyNPC monthly action', () => {
|
||||
it('creates exactly 50 ordinary M generals without fill-count expansion', async () => {
|
||||
const { world, reservedTurns, handler, environment } = buildHarness();
|
||||
|
||||
await handler([50, 0], environment, {
|
||||
id: 1,
|
||||
targetCode: 'month',
|
||||
priority: 1,
|
||||
condition: true,
|
||||
action: [],
|
||||
meta: {},
|
||||
});
|
||||
|
||||
const created = world.peekDirtyState().createdGenerals;
|
||||
expect(created).toHaveLength(50);
|
||||
expect(created.every((general) => general.npcState === 3 && general.name.startsWith('ⓜ'))).toBe(true);
|
||||
expect(reservedTurns.peekDirtyState().generalInitializationIds).toHaveLength(50);
|
||||
expect(world.peekDirtyState().logs.map((log) => log.text)).toContain('장수 <C>50</>명이 <S>등장</>하였습니다.');
|
||||
});
|
||||
|
||||
it('uses and consumes an available U30 candidate without random-name or random-stat fallback', async () => {
|
||||
const info = {
|
||||
generalName: '풀장수',
|
||||
|
||||
@@ -52,10 +52,38 @@ describe('tracked scenario resources', () => {
|
||||
|
||||
expect(scenarioIds).toContain(914);
|
||||
expect(scenarioIds).toContain(915);
|
||||
expect(scenarioIds).toContain(916);
|
||||
const scenarios = await Promise.all(scenarioIds.map((scenarioId) => loadScenarioDefinitionById(scenarioId)));
|
||||
expect(scenarios.every((scenario) => scenario.title.length > 0)).toBe(true);
|
||||
});
|
||||
|
||||
it('keeps scenario 916 equal to ordinary blank land except for its launch modifiers', async () => {
|
||||
const [ordinaryBlank, dawn] = await Promise.all(
|
||||
[0, 916].map((scenarioId) => loadScenarioDefinitionById(scenarioId))
|
||||
);
|
||||
const { uniqueTrialCoef, ...dawnConst } = dawn.config.const;
|
||||
|
||||
expect(dawn.title).toBe('【공백지】 여명');
|
||||
expect(uniqueTrialCoef).toBe(2);
|
||||
expect({ ...dawn.config, const: dawnConst }).toEqual(ordinaryBlank.config);
|
||||
expect(dawn.history).toEqual(ordinaryBlank.history);
|
||||
expect(dawn.events[0]).toEqual([
|
||||
'month',
|
||||
1000,
|
||||
['or', ['Date', '==', null, 12], ['Date', '==', null, 6]],
|
||||
['CreateManyNPC', 50, 0],
|
||||
['DeleteEvent'],
|
||||
]);
|
||||
expect(dawn.events.slice(1)).toEqual(ordinaryBlank.events.slice(1));
|
||||
|
||||
expect({
|
||||
...dawn,
|
||||
title: ordinaryBlank.title,
|
||||
events: ordinaryBlank.events,
|
||||
config: ordinaryBlank.config,
|
||||
}).toEqual(ordinaryBlank);
|
||||
});
|
||||
|
||||
refSourceIt('preserves the Ref scenario 915 S100 pool and event order exactly', async () => {
|
||||
const referencePath = path.join(resolveRefSourceRoot(), 'hwe', 'scenario', 'scenario_915.json');
|
||||
const [scenario, referenceSource] = await Promise.all([
|
||||
|
||||
@@ -3,6 +3,16 @@ import { describe, expect, it } from 'vitest';
|
||||
import { listScenarioPreviews, resolveGitCommitSha } from '../src/scenario/scenarioCatalog.js';
|
||||
|
||||
describe('scenarioCatalog git ref support', () => {
|
||||
it('includes the CHE zero-season dawn scenario in the local catalog', async () => {
|
||||
const previews = await listScenarioPreviews();
|
||||
|
||||
expect(previews.find((scenario) => scenario.id === 916)).toMatchObject({
|
||||
id: 916,
|
||||
title: '【공백지】 여명',
|
||||
year: 180,
|
||||
});
|
||||
});
|
||||
|
||||
it('resolves HEAD to a commit hash', async () => {
|
||||
const commitSha = await resolveGitCommitSha('HEAD');
|
||||
expect(commitSha).toMatch(/^[0-9a-f]{40}$/i);
|
||||
@@ -18,6 +28,11 @@ describe('scenarioCatalog git ref support', () => {
|
||||
expect(previews.every((scenario) => scenario.fiction === null || Number.isInteger(scenario.fiction))).toBe(
|
||||
true
|
||||
);
|
||||
expect(previews.find((scenario) => scenario.id === 916)).toMatchObject({
|
||||
id: 916,
|
||||
title: '【공백지】 여명',
|
||||
year: 180,
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects without crashing when git cannot be spawned', async () => {
|
||||
|
||||
@@ -125,6 +125,16 @@ const scenarios = [
|
||||
nations: [],
|
||||
isCurrent: false,
|
||||
},
|
||||
{
|
||||
id: 916,
|
||||
title: '【공백지】 여명',
|
||||
year: 180,
|
||||
npcCount: 0,
|
||||
npcExCount: 0,
|
||||
npcNeutralCount: 0,
|
||||
nations: [],
|
||||
isCurrent: false,
|
||||
},
|
||||
];
|
||||
|
||||
const response = (data: unknown) => ({ result: { data } });
|
||||
@@ -538,6 +548,7 @@ test('separates branch and commit semantics and submits a reset from the dedicat
|
||||
await expect(page.getByTestId('scenario-select')).toHaveValue('2');
|
||||
await expect(page.getByTestId('request-reset')).toBeEnabled();
|
||||
await expect(page.getByTestId('scenario-select').locator('option:checked')).toContainText('현재 시나리오');
|
||||
await expect(page.getByTestId('scenario-select').locator('option[value="916"]')).toContainText('【공백지】 여명');
|
||||
const catalogGeometry = await page.getByTestId('scenario-select').evaluate((select) => {
|
||||
const scenarioSelect = select as HTMLSelectElement;
|
||||
const rect = select.getBoundingClientRect();
|
||||
@@ -550,7 +561,7 @@ test('separates branch and commit semantics and submits a reset from the dedicat
|
||||
value: scenarioSelect.value,
|
||||
};
|
||||
});
|
||||
expect(catalogGeometry.optionCount).toBe(3);
|
||||
expect(catalogGeometry.optionCount).toBe(4);
|
||||
expect(catalogGeometry.value).toBe('2');
|
||||
expect(catalogGeometry.width).toBeGreaterThan(300);
|
||||
await page.screenshot({ path: testInfo.outputPath('current-scenario-catalog.png'), fullPage: true });
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"title": "【공백지】 여명",
|
||||
"extends": ["scenario_0.json"],
|
||||
"const": {
|
||||
"uniqueTrialCoef": 2
|
||||
},
|
||||
"events": [
|
||||
["month", 1000, ["or", ["Date", "==", null, 12], ["Date", "==", null, 6]], ["CreateManyNPC", 50, 0], ["DeleteEvent"]],
|
||||
["month", 1000, ["Date", "==", 181, 1], ["RaiseNPCNation"], ["DeleteEvent"]],
|
||||
["month", 999, ["Date", "==", 181, 1], ["OpenNationBetting", 4, 5000], ["OpenNationBetting", 1, 2000], ["DeleteEvent"]],
|
||||
["month", 999, ["and", ["Date", ">=", 183, 1], ["RemainNation", "<=", 8]], ["OpenNationBetting", 1, 1000], ["DeleteEvent"]],
|
||||
["destroy_nation", 1000, ["and", ["Date", ">=", 183, 1], ["RemainNation", "==", 1]], ["BlockScoutAction"], ["DeleteEvent"]]
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user