Release Healer Man 0.1.4

This commit is contained in:
phenom
2026-08-18 12:06:04 -04:00
parent 5bb170039a
commit f4c9cf356c
63 changed files with 2694 additions and 81 deletions
@@ -0,0 +1,72 @@
import assert from "node:assert/strict";
import test from "node:test";
import { decodeWotlkM2Effects, parseDbc, parseRunewakerImageRecords } from "./generate-manifest.mjs";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
function tinyDbc() {
const strings = Buffer.from("\0hello\0", "utf8");
const buffer = Buffer.alloc(20 + 8 + strings.length);
buffer.write("WDBC", 0, "ascii");
buffer.writeUInt32LE(1, 4);
buffer.writeUInt32LE(2, 8);
buffer.writeUInt32LE(8, 12);
buffer.writeUInt32LE(strings.length, 16);
buffer.writeUInt32LE(42, 20);
buffer.writeUInt32LE(1, 24);
strings.copy(buffer, 28);
return buffer;
}
test("parses numeric and string DBC fields", () => {
const table = parseDbc(tinyDbc(), "fixture");
assert.equal(table.row(0).uint(0), 42);
assert.equal(table.row(0).string(1), "hello");
});
test("classifies paths from fixed RuneWaker ImageObject records", () => {
const buffer = Buffer.alloc(140 + 3712);
buffer.writeInt32LE(1, 132);
buffer.writeInt32LE(573727, 140);
Buffer.from("model\\fx\\skill\\fire\\act_fireball01_f_i.ros\0", "ascii").copy(buffer, 140 + 300);
const records = parseRunewakerImageRecords(buffer, [573727]);
assert.deepEqual(records.get(573727), ["model/fx/skill/fire/act_fireball01_f_i.ros"]);
});
test("decodes supported WotLK M2 particle and ribbon records", () => {
const particleOffset = 304;
const buffer = Buffer.alloc(particleOffset + 476);
buffer.write("MD20", 0, "ascii");
buffer.writeUInt32LE(1, 296);
buffer.writeUInt32LE(particleOffset, 300);
buffer.writeUInt32LE(17, particleOffset);
buffer.writeUInt16LE(4, particleOffset + 20);
buffer.writeUInt16LE(9, particleOffset + 22);
buffer.writeUInt8(2, particleOffset + 40);
buffer.writeUInt8(1, particleOffset + 41);
buffer.writeUInt16LE(4, particleOffset + 48);
buffer.writeUInt16LE(8, particleOffset + 50);
buffer.writeUInt16LE(1, particleOffset + 56);
buffer.writeUInt32LE(3, particleOffset + 56 + 12);
const decoded = decodeWotlkM2Effects(buffer, "fixture");
assert.equal(decoded.particles[0].id, 17);
assert.equal(decoded.particles[0].textureIndex, 9);
assert.equal(decoded.particles[0].blendMode, 2);
assert.equal(decoded.particles[0].textureColumns, 8);
assert.equal(decoded.particles[0].tracks.emissionSpeed.interpolation, 1);
assert.equal(decoded.particles[0].tracks.emissionSpeed.keyCount, 3);
});
test("generated coverage packages every referenced source sound", () => {
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
const manifest = JSON.parse(fs.readFileSync(path.join(root, "public", "assets", "game", "combat-effects", "manifest.json"), "utf8"));
assert.equal(manifest.coverage.requested, manifest.coverage.authentic + manifest.coverage.fallback);
assert.deepEqual(manifest.coverage.audio.missing, []);
const sounds = manifest.entries.flatMap((entry) => entry.sounds ?? []);
assert.ok(sounds.length > 0);
for (const sound of sounds) {
assert.ok(sound.url?.startsWith("/assets/game/combat-effects/audio/"));
assert.ok(fs.existsSync(path.join(root, "public", sound.url)));
}
});