Release Healer Man 0.1.7

This commit is contained in:
phenom
2026-08-22 15:53:43 -04:00
parent b12fb84859
commit eca6b5db9b
99 changed files with 1931 additions and 150 deletions
+106
View File
@@ -0,0 +1,106 @@
import {
mkdirSync,
readFileSync,
readdirSync,
unlinkSync,
writeFileSync,
} from "node:fs";
import { basename, resolve } from "node:path";
import {
CLASSES,
COA_CLASS_IDS,
type ClassId,
type CoaClassId,
} from "../src/app/characterCatalog";
import { TALENT_NODES, TALENT_TREES } from "../src/game/talentCatalog";
const projectRoot = resolve(import.meta.dirname, "..");
const talentOutputDirectory = resolve(projectRoot, "src/game/generated/talentUi");
const coaAbilityOutputDirectory = resolve(projectRoot, "src/game/generated/coaAbilities");
function writeJson(file: string, value: unknown): void {
writeFileSync(file, `${JSON.stringify(value)}\n`, "utf8");
console.log(`Wrote ${file}`);
}
function removeStaleJson(directory: string, expectedNames: ReadonlySet<string>): void {
for (const name of readdirSync(directory)) {
if (!name.endsWith(".json") || expectedNames.has(name)) continue;
unlinkSync(resolve(directory, name));
}
}
mkdirSync(talentOutputDirectory, { recursive: true });
const talentClassIds = new Set<ClassId>(TALENT_TREES.map((tree) => tree.classId));
const talentFileNames = new Set([...talentClassIds].map((classId) => `${classId}.json`));
removeStaleJson(talentOutputDirectory, talentFileNames);
for (const classId of talentClassIds) {
const trees = TALENT_TREES.filter((tree) => tree.classId === classId).map((tree) => ({
id: tree.id,
classId: tree.classId,
name: tree.name,
icon: tree.icon,
background: tree.background,
description: tree.description,
system: tree.system,
}));
const treeIds = new Set(trees.map((tree) => tree.id));
const nodes = TALENT_NODES.filter((node) => treeIds.has(node.treeId)).map((node) => ({
id: node.id,
treeId: node.treeId,
index: node.index,
prerequisiteId: node.prerequisiteId,
prerequisiteRank: node.prerequisiteRank,
prerequisites: node.prerequisites,
column: node.column,
row: node.row,
icon: node.icon,
maxRank: node.maxRank,
name: node.name,
description: node.description,
rankDescriptions: node.rankDescriptions,
system: node.system,
entryType: node.entryType,
abilityEssenceCost: node.abilityEssenceCost,
talentEssenceCost: node.talentEssenceCost,
requiredClassPoints: node.requiredClassPoints,
requiredSpecPoints: node.requiredSpecPoints,
requiredLevel: node.requiredLevel,
isPassive: node.isPassive,
}));
writeJson(resolve(talentOutputDirectory, `${classId}.json`), {
schemaVersion: 1,
classId,
trees,
nodes,
});
}
interface CoaAbilitySnapshot {
readonly schemaVersion: 1;
readonly abilitiesByClass: Readonly<Record<CoaClassId, readonly unknown[]>>;
readonly resourcesByClass: Readonly<Record<CoaClassId, unknown>>;
readonly triggeredAbilitiesBySpellId: Readonly<Record<string, { readonly classId?: ClassId }>>;
}
const coaAbilityInput = resolve(projectRoot, "src/game/generated/coaAbilityRuntimeCatalog.json");
const coaSnapshot = JSON.parse(readFileSync(coaAbilityInput, "utf8")) as CoaAbilitySnapshot;
mkdirSync(coaAbilityOutputDirectory, { recursive: true });
const coaAbilityFileNames = new Set(COA_CLASS_IDS.map((classId) => `${classId}.json`));
removeStaleJson(coaAbilityOutputDirectory, coaAbilityFileNames);
for (const classId of COA_CLASS_IDS) {
const triggeredAbilitiesBySpellId = Object.fromEntries(Object.entries(
coaSnapshot.triggeredAbilitiesBySpellId,
).filter(([, ability]) => ability.classId === classId));
writeJson(resolve(coaAbilityOutputDirectory, `${classId}.json`), {
schemaVersion: 1,
classId,
abilities: coaSnapshot.abilitiesByClass[classId] ?? [],
resource: coaSnapshot.resourcesByClass[classId],
triggeredAbilitiesBySpellId,
});
}
console.log(`Generated ${talentFileNames.size} talent UI shards and ${coaAbilityFileNames.size} Conquest ability shards from ${basename(coaAbilityInput)}.`);