Add selectable reserve drill focus

This commit is contained in:
2026-06-23 17:34:45 +09:00
parent 0736f07d1d
commit 8591fd7fa3
4 changed files with 242 additions and 21 deletions

View File

@@ -18,7 +18,10 @@ try {
await page.waitForFunction(() => document.querySelector('canvas') !== null, undefined, { timeout: 90000 });
await page.waitForFunction(() => window.__HEROS_GAME__ !== undefined, undefined, { timeout: 90000 });
await page.waitForFunction(() => window.__HEROS_DEBUG__ !== undefined, undefined, { timeout: 90000 });
await page.waitForTimeout(500);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('TitleScene');
}, undefined, { timeout: 90000 });
const debugBeforeBattle = await page.evaluate(() => window.__HEROS_DEBUG__?.activeScenes() ?? []);
if (!debugBeforeBattle.includes('TitleScene')) {
@@ -5480,6 +5483,7 @@ try {
await clickSortieRosterUnit(page, unitId);
}
}
await clickReserveTrainingFocus(page, 'bond-practice');
const jingRearSortieReadyState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
@@ -5489,9 +5493,12 @@ try {
!jingRearSortieReadyState.sortieRoster?.some((unit) => unit.id === 'liu-bei' && unit.selected && unit.required) ||
!jingRearSortieReadyState.sortieRoster?.some((unit) => unit.id === 'guan-yu' && unit.selected && unit.required) ||
jingRearSortieReadyState.sortiePlan?.selectedCount !== 7 ||
jingRearSortieReadyState.sortiePlan?.recommendedSelectedCount < 7
jingRearSortieReadyState.sortiePlan?.recommendedSelectedCount < 7 ||
jingRearSortieReadyState.reserveTrainingFocus?.id !== 'bond-practice' ||
!jingRearSortieReadyState.sortiePlan?.reserveTrainingLine?.includes('공명 합숙') ||
jingRearSortieReadyState.sortiePlan?.reserveTrainingBondPreview !== 4
) {
throw new Error(`Expected Jing rear sortie to deploy Liu Bei, Guan Yu, Ma Liang, Mi Zhu, Zhao Yun, Huang Quan, and Wang Ping: ${JSON.stringify(jingRearSortieReadyState)}`);
throw new Error(`Expected Jing rear sortie to deploy Liu Bei, Guan Yu, Ma Liang, Mi Zhu, Zhao Yun, Huang Quan, Wang Ping, and bond-focused reserve drill: ${JSON.stringify(jingRearSortieReadyState)}`);
}
await page.screenshot({ path: 'dist/verification-jing-rear-sortie.png', fullPage: true });
@@ -5563,9 +5570,13 @@ try {
!fortySecondCampState.availableDialogueIds.every((id) => id.endsWith('jing-rear')) ||
fortySecondCampState.availableVisitIds?.length !== 2 ||
!fortySecondCampState.availableVisitIds.every((id) => id.includes('jing-rear')) ||
fortySecondCampState.rosterCollection?.total < 22
fortySecondCampState.rosterCollection?.total < 22 ||
fortySecondCampState.campaign?.reserveTrainingFocus !== 'bond-practice' ||
!fortySecondCampState.reserveTrainingAwards?.some(
(entry) => entry.focusId === 'bond-practice' && entry.focusLabel === '공명 합숙' && entry.bondExpGained > 0
)
) {
throw new Error(`Expected forty-second camp to expose Jing rear dialogue/visit sets and preserve the full officer roster: ${JSON.stringify(fortySecondCampState)}`);
throw new Error(`Expected forty-second camp to expose Jing rear dialogue/visit sets, preserve the full officer roster, and record bond-focused reserve training: ${JSON.stringify(fortySecondCampState)}`);
}
await page.screenshot({ path: 'dist/verification-jing-rear-camp.png', fullPage: true });
@@ -5706,15 +5717,28 @@ function assertSortieTacticalRoster(state, requiredUnitIds) {
!state.sortiePlan ||
!state.sortiePlan.deploymentLine?.includes('전열') ||
!state.sortiePlan.objectiveLine ||
!state.sortiePlan.reserveTrainingLine?.includes('대기 훈련') ||
!state.sortiePlan.recommendationLine?.includes('추천') ||
!Array.isArray(state.sortiePlan.formationSlots) ||
state.sortiePlan.formationSlots.length < 3 ||
typeof state.sortiePlan.activeBondCount !== 'number' ||
typeof state.sortiePlan.terrainScore !== 'number' ||
typeof state.sortiePlan.recommendedSelectedCount !== 'number' ||
typeof state.sortiePlan.recommendedTotal !== 'number'
typeof state.sortiePlan.recommendedTotal !== 'number' ||
typeof state.sortiePlan.reserveTrainingExpPreview !== 'number' ||
typeof state.sortiePlan.reserveTrainingEquipmentPreview !== 'number' ||
typeof state.sortiePlan.reserveTrainingBondPreview !== 'number'
) {
throw new Error(`Expected sortie preparation to expose deployment plan, bond count, and terrain score: ${JSON.stringify(state.sortiePlan)}`);
throw new Error(`Expected sortie preparation to expose deployment plan, reserve training, bond count, and terrain score: ${JSON.stringify(state.sortiePlan)}`);
}
if (
!state.reserveTrainingFocus ||
!Array.isArray(state.reserveTrainingFocusOptions) ||
state.reserveTrainingFocusOptions.length !== 3 ||
!state.reserveTrainingFocusOptions.some((focus) => focus.id === 'bond-practice' && focus.bondExpGained > 0)
) {
throw new Error(`Expected sortie preparation to expose selectable reserve drill focuses: ${JSON.stringify(state.reserveTrainingFocusOptions)}`);
}
const recommendedUnits = state.sortieRoster.filter((unit) => unit.recommended);
@@ -5739,3 +5763,20 @@ async function clickSortieRosterUnit(page, unitId) {
await page.mouse.click(254, 314 + (denseRoster ? 48 : 50) + index * rowGap);
await page.waitForTimeout(120);
}
async function clickReserveTrainingFocus(page, focusId) {
const state = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (!state?.sortieVisible || !Array.isArray(state.reserveTrainingFocusOptions)) {
throw new Error(`Cannot click reserve drill ${focusId}; sortie reserve drill selector is not visible: ${JSON.stringify(state)}`);
}
const index = state.reserveTrainingFocusOptions.findIndex((focus) => focus.id === focusId);
if (index < 0) {
throw new Error(`Cannot click reserve drill ${focusId}; focus is missing: ${JSON.stringify(state.reserveTrainingFocusOptions)}`);
}
const selectorX = 574;
const buttonWidth = Math.floor((314 - 40) / state.reserveTrainingFocusOptions.length);
await page.mouse.click(selectorX + 12 + index * (buttonWidth + 8) + buttonWidth / 2, 655);
await page.waitForTimeout(120);
}