Release Healer Man 0.1.5
This commit is contained in:
1 parent
f4c9cf356c
commit
55cfd43d66
62 files changed
+3030
-153
No files matched your search
@@ -0,0 +1,93 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { runtimeStages } from "./manastorm";
|
||||
import {
|
||||
DEFAULT_MANASTORM_ADMIN_CONFIG,
|
||||
UNIFIED_MANASTORM_BOSS_CATALOG,
|
||||
authoredStageConfigForBoss,
|
||||
bossAdminRecordForStatus,
|
||||
derivePartySpawnSlots,
|
||||
effectiveManastormCatalog,
|
||||
isGameMasterSession,
|
||||
resolveBossAdminEntry,
|
||||
resolvedBossAdminCatalog,
|
||||
type ManastormAdminConfig,
|
||||
} from "./manastormAdminConfig";
|
||||
|
||||
function configWithBoss(key: string, record: ManastormAdminConfig["bosses"][string]): ManastormAdminConfig {
|
||||
return {
|
||||
...DEFAULT_MANASTORM_ADMIN_CONFIG,
|
||||
bosses: { [key]: record },
|
||||
};
|
||||
}
|
||||
|
||||
describe("Manastorm GM catalog", () => {
|
||||
it("deduplicates map/name records and defaults every boss to Needs tested", () => {
|
||||
const identities = UNIFIED_MANASTORM_BOSS_CATALOG.map((entry) => `${entry.mapId}:${entry.name.toLowerCase()}`);
|
||||
expect(new Set(identities).size).toBe(identities.length);
|
||||
expect(UNIFIED_MANASTORM_BOSS_CATALOG.length).toBeGreaterThan(0);
|
||||
expect(resolvedBossAdminCatalog(DEFAULT_MANASTORM_ADMIN_CONFIG).every((entry) => (
|
||||
entry.status === "needs-tested" && !entry.inPublicPool
|
||||
))).toBe(true);
|
||||
const crossMode = UNIFIED_MANASTORM_BOSS_CATALOG.find((entry) => entry.name === "Burning Felguard");
|
||||
expect(crossMode?.baseStage?.modeIds).toEqual(expect.arrayContaining([0, 2]));
|
||||
});
|
||||
|
||||
it("publishes only runnable Ready bosses and never restores the legacy pool", () => {
|
||||
const candidate = UNIFIED_MANASTORM_BOSS_CATALOG.find((entry) => (
|
||||
resolveBossAdminEntry(entry, configWithBoss(entry.key, { status: "ready" })).runnable
|
||||
));
|
||||
expect(candidate).toBeTruthy();
|
||||
const config = configWithBoss(candidate!.key, { status: "ready" });
|
||||
const effective = effectiveManastormCatalog(config);
|
||||
expect(effective.fallbackPolicy).toBe("none");
|
||||
expect(runtimeStages(effective)).toHaveLength(1);
|
||||
expect(runtimeStages(effective)[0].bossName).toBe(candidate!.name);
|
||||
|
||||
const empty = effectiveManastormCatalog(DEFAULT_MANASTORM_ADMIN_CONFIG);
|
||||
expect(empty.fallbackPolicy).toBe("none");
|
||||
expect(runtimeStages(empty)).toEqual([]);
|
||||
});
|
||||
|
||||
it("materializes an inherited imported stage when a runnable boss becomes Ready", () => {
|
||||
const candidate = UNIFIED_MANASTORM_BOSS_CATALOG.find((entry) => entry.baseStage);
|
||||
expect(candidate).toBeTruthy();
|
||||
const record = bossAdminRecordForStatus(candidate!, DEFAULT_MANASTORM_ADMIN_CONFIG, "ready");
|
||||
expect(record.status).toBe("ready");
|
||||
expect(record.stage).toMatchObject({
|
||||
dungeonId: candidate!.baseStage!.dungeonId,
|
||||
bossRuntimeId: candidate!.baseStage!.bossRuntimeId,
|
||||
bossPosition: candidate!.baseStage!.bossPosition,
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects stale exact-mob IDs and bounds required kills", () => {
|
||||
const candidate = UNIFIED_MANASTORM_BOSS_CATALOG.find((entry) => authoredStageConfigForBoss(entry, DEFAULT_MANASTORM_ADMIN_CONFIG));
|
||||
expect(candidate).toBeTruthy();
|
||||
const stage = authoredStageConfigForBoss(candidate!, DEFAULT_MANASTORM_ADMIN_CONFIG)!;
|
||||
const stale = configWithBoss(candidate!.key, {
|
||||
status: "ready",
|
||||
stage: {
|
||||
...stage,
|
||||
linkedMobRuntimeIds: ["missing:runtime-id"],
|
||||
requiredKillCount: 1,
|
||||
},
|
||||
});
|
||||
const resolved = resolveBossAdminEntry(candidate!, stale);
|
||||
expect(resolved.runnable).toBe(false);
|
||||
expect(resolved.validationIssues.join(" ")).toContain("missing:runtime-id");
|
||||
});
|
||||
|
||||
it("derives a stable five-person formation from one anchor and yaw", () => {
|
||||
const slots = derivePartySpawnSlots({ footPosition: [10, 2, 20], yaw: Math.PI / 2 }, 5);
|
||||
expect(slots).toHaveLength(5);
|
||||
expect(slots[0]).toEqual({ footPosition: [10, 2, 20], yaw: Math.PI / 2 });
|
||||
expect(new Set(slots.map((slot) => slot.footPosition.join(","))).size).toBe(5);
|
||||
expect(slots.every((slot) => slot.yaw === Math.PI / 2)).toBe(true);
|
||||
});
|
||||
|
||||
it("never grants GM UI authority to offline or local-only sessions", () => {
|
||||
expect(isGameMasterSession({ kind: "offline", roles: ["gm"] })).toBe(false);
|
||||
expect(isGameMasterSession({ kind: "account", roles: ["gm"] })).toBe(false);
|
||||
expect(isGameMasterSession({ kind: "account", accessToken: "server-token", roles: ["gm"] })).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user