Release Healer Man 0.1.21

This commit is contained in:
phenom committed 2026-09-08 10:40:26 -04:00
1 parent 699fc858c9
commit f6f2375145
210 files changed
+976039 -6247

No files matched your search

@@ -7,6 +7,7 @@ import { BufferAttribute, BufferGeometry, Matrix4, Vector3 } from "three";
import {
buildPartyNavigationGraph,
} from "../../src/game/partyNavigation.ts";
import { generateEncounterImplementationReport } from "./lib/encounter-implementation-report.mjs";
import { auditOrderedObjectiveRoutes } from "./lib/objective-route-audit.mjs";
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
@@ -156,6 +157,19 @@ function validateAttack(dungeonId, entityId, attack, issues) {
}
}
function formulaMatchesCatalog(attackFormula, catalogFormula) {
if (!catalogFormula) return attackFormula === undefined;
if (!attackFormula || typeof attackFormula !== "object") return false;
const expected = {
...catalogFormula,
// NPC assignments carry their source spell level. Script-derived boss
// references use the documented zero sentinel because no assignment level
// exists in the packaged row.
spellLevel: attackFormula.spellLevel,
};
return JSON.stringify(attackFormula) === JSON.stringify(expected);
}
function renderMarkdown(report) {
const rows = report.dungeons.map((dungeon) => [
"|", dungeon.id, "|", dungeon.sourceRows, "|", dungeon.runtimeSpawns, "|",
@@ -171,7 +185,7 @@ function renderMarkdown(report) {
return [
"# RuneWaker gameplay content audit",
"",
"Structural validation: **" + report.validationStatus + "** ",
"Structural validation: **" + report.validationStatus + "**",
"Original-mechanics fidelity: **" + report.fidelityStatus + "**",
"",
"This offline audit reads packaged recipes, snapshots, generated TypeScript, reports,",
@@ -200,6 +214,10 @@ function renderMarkdown(report) {
"- Boss signaling includes " + summary.telegraphedBossMechanics
+ " spatial telegraphs and " + summary.healthTriggeredBossMechanics
+ " visible health-triggered mechanics.",
"- The exhaustive encounter implementation ledger tracks "
+ report.encounterImplementationLedger.deferredSourceRows + " deferred source rows and "
+ report.encounterImplementationLedger.uniqueMechanicsEvidence
+ " unique mechanics evidence records without inflating overlapping regex labels.",
"",
"## Authentic source data currently used",
"",
@@ -215,10 +233,12 @@ function renderMarkdown(report) {
"- " + summary.builderAuthoredAttacks + " attacks are builder exceptions outside the modular boss catalog.",
"- " + summary.sourceBackedDamageFamilyAttacks
+ " executable attacks carry a conservative source-backed direct-damage family mapping.",
"- Source-backed mapping preserves spell identity, damage family, school, range, and cooldown;",
" HealerMan's 0.85 damage coefficient is intentionally generic, not claimed as source-exact.",
"- Scaling, movement/leash, clustering, aggro, death state, loot, and objective ordering are generic.",
"- Unmapped complex doors, multi-actor phases, patrols, resets, interactions, and source loot remain review-required.",
"- Source-backed mapping preserves spell identity, damage family, school, range, cooldown,",
" source power fields, and the exact native formula shape/provenance.",
"- Damage execution uses a labeled HealerMan baseline adapter because native ATK/MATK,",
" DEF/MDEF, weapon power, resist, critical, level-delta, and global rate inputs are unavailable.",
"- Scaling, movement/leash, clustering, aggro, death state, loot item stats/slots, and objective ordering are generic.",
"- Unmapped complex doors, multi-actor phases, patrols, resets, and interactions remain review-required.",
"- Procedural animation states are HealerMan-authored; native GLBs must provide idle, move,",
" attack, cast, wound, and death families.",
"",
@@ -530,11 +550,16 @@ for (const recipeName of recipeNames) {
+ executableSpellId + ".");
} else {
counts.sourceBackedDamageFamilyAttacks += 1;
if (attack.spellId && [
const runtimeMappingDrift = !catalogAuthored && [
"name", "school", "animation", "cooldownMs", "damageMultiplier",
].some((field) => attack[field] !== (
field === "name" ? catalogSpell.name : catalogSpell.runtime[field]
))) {
));
const formulaDrift = !formulaMatchesCatalog(
attack.runewakerFormula,
catalogSpell.runtime.formula,
);
if (attack.spellId && (runtimeMappingDrift || formulaDrift)) {
issue(issues, dungeonId, entityId + " spell " + executableSpellId
+ " drifted from the portable source-backed runtime mapping.");
}
@@ -749,8 +774,8 @@ summary.portableDamageFamilyRecords = spellCatalogSnapshot?.damageFamilyCount ??
summary.portableEvidenceOnlyRecords = spellCatalogSnapshot?.evidenceOnlyCount ?? 0;
reviewNotes.push(summary.sourceGapBossMechanics
+ " boss mechanics are conservative, telegraphed fallbacks for preserved bosses whose scripts expose no executable combat spell.");
reviewNotes.push("Source-backed spell coefficients are HealerMan-generic; the original RuneWaker "
+ "formula/stat scaling has not been reconstructed.");
reviewNotes.push("Source formula structure is preserved, but live damage uses a labeled HealerMan "
+ "baseline adapter because the required native combat-stat inputs are not packaged.");
const navigationBlockerEntries = dungeons.flatMap((dungeon) => (
dungeon.objectiveRouteEvidence
.filter((route) => route.orderAuthoritative && !route.reachable)
@@ -784,6 +809,12 @@ if (summary.derivedObjectiveRoutes) {
+ summary.unreachableDerivedObjectiveRoutes + " unreachable heuristic legs remain navigation/order review evidence.");
}
const encounterImplementation = await generateEncounterImplementationReport();
if (encounterImplementation.report.issues.length) {
issues.push("Encounter implementation ledger is blocked: "
+ encounterImplementation.report.issues.join("; "));
}
const report = {
schemaVersion: 1,
validationStatus: issues.length ? "blocked" : "green",
@@ -797,11 +828,11 @@ const report = {
],
genericRuntimeSystems: [
"source-gap attacks", "health/damage scaling", "movement/leash", "clustering/aggro",
"combat/death state", "loot policy", "objective ordering", "procedural animation",
"combat/death state", "loot item stats/slots", "objective ordering", "procedural animation",
],
deferredMechanics: [
"complex doors/gates", "unmapped multi-actor waves", "unmapped phases", "patrols", "interactions",
"encounter resets", "source loot",
"encounter resets", "blocked source-loot predicates", "source item stat/slot mapping",
],
blockerGroups: {
navigation: {
@@ -829,6 +860,14 @@ const report = {
mappingPolicy: "Only positively classified direct-HP damage families execute; "
+ "named source auras, controls, summons, and health gates use conservative modular effects; unknown semantics remain evidence-only.",
},
encounterImplementationLedger: {
json: encounterImplementation.reportJson,
markdown: encounterImplementation.reportMarkdown,
validationStatus: encounterImplementation.report.validationStatus,
completionStatus: encounterImplementation.report.completionStatus,
deferredSourceRows: encounterImplementation.report.summary.deferredSourceRows,
uniqueMechanicsEvidence: encounterImplementation.report.summary.uniqueMechanicsEvidence,
},
resolvedRuntimeObservations,
documentedExceptions,
issues,