Enhance tactical sortie preparation

This commit is contained in:
2026-06-23 01:57:24 +09:00
parent 056fb34226
commit 91b8abc7e3
3 changed files with 190 additions and 29 deletions

View File

@@ -360,9 +360,10 @@ try {
if (!campStateWithSortiePrep?.sortieVisible) {
throw new Error(`Expected sortie preparation overlay from next story button: ${JSON.stringify(campStateWithSortiePrep)}`);
}
assertSortieTacticalRoster(campStateWithSortiePrep, ['liu-bei', 'guan-yu', 'zhang-fei']);
await page.screenshot({ path: 'dist/verification-camp-sortie.png', fullPage: true });
await page.mouse.click(792, 596);
await page.mouse.click(922, 646);
await page.waitForTimeout(140);
const campStateAfterSortieClose = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (campStateAfterSortieClose?.sortieVisible) {
@@ -371,7 +372,7 @@ try {
await page.mouse.click(1120, 38);
await page.waitForTimeout(120);
await page.mouse.click(938, 596);
await page.mouse.click(1068, 646);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('StoryScene');
@@ -443,7 +444,7 @@ try {
if (!secondCampSortieState?.sortieVisible) {
throw new Error(`Expected second camp sortie preparation overlay: ${JSON.stringify(secondCampSortieState)}`);
}
await page.mouse.click(938, 596);
await page.mouse.click(1068, 646);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('StoryScene');
@@ -515,7 +516,7 @@ try {
if (!thirdCampSortieState?.sortieVisible) {
throw new Error(`Expected third camp sortie preparation overlay: ${JSON.stringify(thirdCampSortieState)}`);
}
await page.mouse.click(938, 596);
await page.mouse.click(1068, 646);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('StoryScene');
@@ -587,7 +588,7 @@ try {
if (!fourthCampSortieState?.sortieVisible) {
throw new Error(`Expected fourth camp sortie preparation overlay: ${JSON.stringify(fourthCampSortieState)}`);
}
await page.mouse.click(938, 596);
await page.mouse.click(1068, 646);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('StoryScene');
@@ -669,7 +670,7 @@ try {
if (!fifthCampSortieState?.sortieVisible) {
throw new Error(`Expected fifth camp sortie preparation overlay: ${JSON.stringify(fifthCampSortieState)}`);
}
await page.mouse.click(938, 596);
await page.mouse.click(1068, 646);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('StoryScene');
@@ -754,6 +755,7 @@ try {
if (!sixthCampSortieState.selectedSortieUnitIds?.includes('liu-bei') || sixthCampSortieState.selectedSortieUnitIds.length < 3) {
throw new Error(`Expected sortie prep to default to the core brother roster: ${JSON.stringify(sixthCampSortieState)}`);
}
assertSortieTacticalRoster(sixthCampSortieState, ['liu-bei', 'guan-yu', 'zhang-fei']);
await page.mouse.click(254, 450);
await page.waitForTimeout(220);
@@ -766,7 +768,7 @@ try {
) {
throw new Error(`Expected sortie selection toggle to bench Guan Yu while keeping Liu Bei/Zhang Fei: ${JSON.stringify(sixthCampAfterSortieToggle)}`);
}
await page.mouse.click(938, 596);
await page.mouse.click(1068, 646);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('StoryScene');
@@ -862,7 +864,8 @@ try {
if (!seventhCampRecruitSortieState.selectedSortieUnitIds?.includes('jian-yong')) {
throw new Error(`Expected recruit to be selectable in seventh camp sortie prep: ${JSON.stringify(seventhCampRecruitSortieState)}`);
}
await page.mouse.click(938, 596);
assertSortieTacticalRoster(seventhCampRecruitSortieState, ['liu-bei', 'zhang-fei', 'jian-yong', 'mi-zhu']);
await page.mouse.click(1068, 646);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('StoryScene');
@@ -944,7 +947,8 @@ try {
if (!eighthCampMiZhuSortieState.selectedSortieUnitIds?.includes('mi-zhu')) {
throw new Error(`Expected Mi Zhu to be selectable for ninth battle sortie: ${JSON.stringify(eighthCampMiZhuSortieState)}`);
}
await page.mouse.click(938, 596);
assertSortieTacticalRoster(eighthCampMiZhuSortieState, ['liu-bei', 'zhang-fei', 'jian-yong', 'mi-zhu']);
await page.mouse.click(1068, 646);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('StoryScene');
@@ -1076,3 +1080,34 @@ async function canReach(url) {
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
function assertSortieTacticalRoster(state, requiredUnitIds) {
if (!state?.sortieVisible || !Array.isArray(state.sortieRoster)) {
throw new Error(`Expected sortie tactical roster to be exposed: ${JSON.stringify(state)}`);
}
const missingIds = requiredUnitIds.filter((unitId) => !state.sortieRoster.some((unit) => unit.id === unitId));
if (missingIds.length > 0) {
throw new Error(`Expected sortie roster to include ${missingIds.join(', ')}: ${JSON.stringify(state.sortieRoster)}`);
}
const invalidUnits = state.sortieRoster.filter((unit) => {
return (
!unit.classRole ||
!unit.statLine?.includes('무 ') ||
!unit.statLine?.includes('지 ') ||
!unit.equipmentLine?.includes('Lv') ||
!unit.bondLine?.includes('공명') ||
!unit.terrainLine?.includes('지형')
);
});
if (invalidUnits.length > 0) {
throw new Error(`Expected sortie roster to include class, stats, equipment, bond, and terrain advice: ${JSON.stringify(invalidUnits)}`);
}
const liuBei = state.sortieRoster.find((unit) => unit.id === 'liu-bei');
if (!liuBei?.equipmentLine?.includes('자웅일대검')) {
throw new Error(`Expected Liu Bei sortie row to expose named treasure weapon: ${JSON.stringify(liuBei)}`);
}
}