Update Healer Man server

This commit is contained in:
phenom committed 2026-10-06 22:25:34 -04:00
1 parent 6114a2295f
commit 69809f7228
593 files changed
+903643 -40774

No files matched your search

+25 -15
View File
@@ -6,8 +6,12 @@ const path = require('node:path');
const {
DEFAULT_TEST_DUNGEON_ID,
DEFAULT_TEST_DUNGEON_TITLE,
DEFAULT_TEST_DUNGEON_BOSS,
DEFAULT_TEST_DUNGEON_CATEGORY,
FULL_STOCKADE_DUNGEON_ID,
FULL_STOCKADE_DUNGEON_TITLE,
FULL_STOCKADE_BOSS,
selectDefaultTestDungeon,
selectFullStockadeDungeon,
openSelectedDungeonRoles,
} = require('./playtest-defaults.cjs');
@@ -50,7 +54,8 @@ const moduleUrls = moduleFiles.map((file) => `/assets/${file}`);
const routes = [
{ id: 'barren-caves', title: 'Barren Caves', category: 'RoM' },
{ id: 'wailing-caverns', title: 'Wailing Caverns', category: 'WoW' },
{ id: DEFAULT_TEST_DUNGEON_ID, title: DEFAULT_TEST_DUNGEON_TITLE, category: 'WoW' },
{ id: DEFAULT_TEST_DUNGEON_ID, title: DEFAULT_TEST_DUNGEON_TITLE, category: DEFAULT_TEST_DUNGEON_CATEGORY },
{ id: FULL_STOCKADE_DUNGEON_ID, title: FULL_STOCKADE_DUNGEON_TITLE, category: 'WoW' },
];
const routesToRun = routeSelection
? routes.filter((route) => route.id === routeSelection)
@@ -62,7 +67,10 @@ if (routeSelection === 'wailing-caverns' && !historicalWailing) {
if (historicalWailing && routeSelection !== 'wailing-caverns') {
throw new Error('--historical-wailing requires --route=wailing-caverns.');
}
if (stockadeVowDiagnostic && (!campaignBossRoute || routeSelection !== DEFAULT_TEST_DUNGEON_ID)) {
if (campaignBossRoute && !routeSelection) {
throw new Error('--campaign-boss-route requires an explicit --route=<dungeon-id> selection.');
}
if (stockadeVowDiagnostic && (!campaignBossRoute || routeSelection !== FULL_STOCKADE_DUNGEON_ID)) {
throw new Error('--stockade-vow-diagnostic requires --campaign-boss-route --route=stormwind-stockade.');
}
const dataDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'healer-man-native-routes-'));
@@ -335,7 +343,7 @@ function sameObservedMobCast(left, right) {
}
function isHamhockChainLightning(mob) {
return Boolean(mob && !mob.dead && mob.health > 0 && mob.name === DEFAULT_TEST_DUNGEON_BOSS
return Boolean(mob && !mob.dead && mob.health > 0 && mob.name === FULL_STOCKADE_BOSS
&& mob.activeCast?.interruptible
&& (mob.activeCast.spellId === 421 || mob.activeCast.attackId === 'spell-421'
|| /chain lightning/i.test(mob.activeCast.name ?? '')));
@@ -607,7 +615,7 @@ async function attemptStockadeVowInterrupt(page, routeResult, record, initialSna
}
let current = initialSnapshot;
let hamhock = current.mobs.find((mob) => mob.id === diagnostic.targetBossId)
?? current.mobs.find((mob) => mob.name === DEFAULT_TEST_DUNGEON_BOSS && mob.boss);
?? current.mobs.find((mob) => mob.name === FULL_STOCKADE_BOSS && mob.boss);
if (!isHamhockChainLightning(hamhock)) return { snapshot: current, attempted: false };
diagnostic.hamhockObserved = true;
const watchedCast = { attackId: hamhock.activeCast.attackId,
@@ -1737,7 +1745,7 @@ async function runCampaignBossCheckpoint(page, route, result, objective, profile
}
}
if (stockadeVowDiagnostic && boss.name === DEFAULT_TEST_DUNGEON_BOSS
if (stockadeVowDiagnostic && boss.name === FULL_STOCKADE_BOSS
&& isHamhockChainLightning(boss)) {
const vowWatch = await attemptStockadeVowInterrupt(page, result, record, current,
plan.vowOfSilence, collect);
@@ -1752,11 +1760,11 @@ async function runCampaignBossCheckpoint(page, route, result, objective, profile
}
continue;
}
const casterCast = !stockadeVowDiagnostic && boss.name === DEFAULT_TEST_DUNGEON_BOSS
const casterCast = !stockadeVowDiagnostic && boss.name === FULL_STOCKADE_BOSS
&& (boss.activeCast?.spellId === 421 || boss.activeCast?.attackId === 'spell-421'
|| /chain lightning/i.test(boss.activeCast?.name ?? ''))
? boss.activeCast : null;
if (route.id === DEFAULT_TEST_DUNGEON_ID && vowSetup?.menuAssignmentObserved && casterCast
if (route.id === FULL_STOCKADE_DUNGEON_ID && vowSetup?.menuAssignmentObserved && casterCast
&& casterCast.completesAt > current.now && current.player.selectedTargetId === boss.id
&& current.now - (record.lastVowAttemptAt ?? 0) > 1_000) {
const attempt = { observedAt: current.now, input: vowSetup.input, abilityId: vowSetup.id,
@@ -2115,10 +2123,10 @@ async function replayRecoveredRouteToCursor(page, route, result, profile, plan,
async function runCampaignBossRoute(page, route, entryState, profile) {
const guidance = readNavigationGuidance(route.id);
const vowSetup = route.id === DEFAULT_TEST_DUNGEON_ID ? await assignVowThroughAbilityControls(page) : null;
if (route.id === DEFAULT_TEST_DUNGEON_ID && vowSetup?.menuAssignmentObserved) entryState = await readLiveState(page, true);
const vowSetup = route.id === FULL_STOCKADE_DUNGEON_ID ? await assignVowThroughAbilityControls(page) : null;
if (route.id === FULL_STOCKADE_DUNGEON_ID && vowSetup?.menuAssignmentObserved) entryState = await readLiveState(page, true);
const plan = actionPlanFromSnapshot(entryState);
const hamhockObjective = guidance.objectives.find((objective) => objective.name === DEFAULT_TEST_DUNGEON_BOSS);
const hamhockObjective = guidance.objectives.find((objective) => objective.name === FULL_STOCKADE_BOSS);
const result = {
dungeonId: route.id, title: route.title,
coverage: stockadeVowDiagnostic
@@ -2145,7 +2153,7 @@ async function runCampaignBossRoute(page, route, entryState, profile) {
status: vowSetup?.menuAssignmentObserved && plan.vowOfSilence
? 'watching' : 'vow-not-learned-or-not-bound-through-normal-ability-controls',
targetBossId: hamhockObjective?.id ?? null,
targetBossName: hamhockObjective?.name ?? DEFAULT_TEST_DUNGEON_BOSS,
targetBossName: hamhockObjective?.name ?? FULL_STOCKADE_BOSS,
abilityId: vowSetup?.id ?? null,
abilityName: vowSetup?.name ?? 'Vow of Silence',
input: vowSetup?.input ?? plan.vowOfSilence?.key ?? null,
@@ -2179,7 +2187,7 @@ async function runCampaignBossRoute(page, route, entryState, profile) {
throw new Error(`Targeted Vow diagnostic cannot start: ${result.vowDiagnostic.status}.`);
}
if (!plan.damage) throw new Error(`${route.id}: no normal bound damage ability for campaign route.`);
if (route.id === DEFAULT_TEST_DUNGEON_ID && !result.vowSetup?.menuAssignmentObserved) {
if (route.id === FULL_STOCKADE_DUNGEON_ID && !result.vowSetup?.menuAssignmentObserved) {
result.vowSetup?.learned || console.warn('Vow of Silence was not observed in the selected identity action catalog.');
}
if (cameraDiagnostic) {
@@ -2211,7 +2219,7 @@ async function runCampaignBossRoute(page, route, entryState, profile) {
result.vowDiagnostic.targetDefeatedAt = snapshot.now;
result.vowDiagnostic.stopReason = 'Hamhock was defeated before a Vow cancellation was confirmed';
} else if (snapshot.mobs.some((mob) => mob.id === result.vowDiagnostic.targetBossId
|| (mob.name === DEFAULT_TEST_DUNGEON_BOSS && mob.boss))) {
|| (mob.name === FULL_STOCKADE_BOSS && mob.boss))) {
result.vowDiagnostic.hamhockObserved = true;
}
}
@@ -3389,6 +3397,8 @@ async function enterCampaignDungeon(page, route, isFirst, minimumLevel = 30) {
await page.locator('.dungeon-select-screen').waitFor();
if (route.id === DEFAULT_TEST_DUNGEON_ID) {
await selectDefaultTestDungeon(page);
} else if (route.id === FULL_STOCKADE_DUNGEON_ID) {
await selectFullStockadeDungeon(page);
} else {
await page.locator('.dungeon-category-tab').filter({ hasText: route.category }).click();
}
@@ -3402,7 +3412,7 @@ async function enterCampaignDungeon(page, route, isFirst, minimumLevel = 30) {
const selectedRowTitle = (await row.locator('strong').innerText()).trim();
assert.equal(selectedRowTitle, route.title, `${route.title} campaign selection is exact`);
await page.screenshot({ path: path.join(outputDirectory, `${route.id}-campaign-picker.png`) });
if (route.id !== DEFAULT_TEST_DUNGEON_ID) await row.click();
if (route.id !== DEFAULT_TEST_DUNGEON_ID && route.id !== FULL_STOCKADE_DUNGEON_ID) await row.click();
await openSelectedDungeonRoles(page);
await page.locator('.dungeon-role-option--healer').waitFor({ state: 'visible', timeout: 180_000 });
await page.locator('.dungeon-role-option--healer').click();