forked from phenom/healer-man
Release Healer Man 0.1.32
This commit is contained in:
1 parent
d3d6aaebdb
commit
6dcb1034e5
102 files changed
+10772
-788
No files matched your search
@@ -431,6 +431,35 @@ function yawFromDirection(direction) {
|
||||
return Number(((((direction % turn) + turn) % turn) * Math.PI * 2 / turn).toFixed(9));
|
||||
}
|
||||
|
||||
function scriptedPlacements() {
|
||||
const placements = [...(recipe.scriptedSpawns ?? [])];
|
||||
for (const formation of recipe.scriptedFormations ?? []) {
|
||||
const radians = formation.direction * Math.PI / 180;
|
||||
for (const [index, member] of formation.members.entries()) {
|
||||
const rowDistance = (member.row - 1) * formation.spacingSourceUnits;
|
||||
const columnDistance = member.column * formation.spacingSourceUnits;
|
||||
placements.push({
|
||||
id: formation.id + "-" + (index + 1),
|
||||
templateId: member.templateId,
|
||||
sourceAnchorSpawnId: formation.sourceAnchorSpawnId,
|
||||
controllerSpawnId: formation.controllerSpawnId ?? formation.sourceAnchorSpawnId,
|
||||
sourceOffset: [
|
||||
-rowDistance * Math.cos(radians) - columnDistance * Math.sin(radians),
|
||||
0,
|
||||
rowDistance * Math.sin(radians) - columnDistance * Math.cos(radians),
|
||||
],
|
||||
direction: formation.direction,
|
||||
sourceScriptRoot: formation.sourceScriptRoot,
|
||||
evidence: formation.evidence,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (new Set(placements.map((placement) => placement.id)).size !== placements.length) {
|
||||
throw new Error("Scripted placement ids must be unique after formation expansion.");
|
||||
}
|
||||
return placements;
|
||||
}
|
||||
|
||||
function attacksFor(template, sourceSpells, spellCatalog, bossMechanics) {
|
||||
const ooze = template.archetype === "ooze";
|
||||
const basicAttack = {
|
||||
@@ -564,7 +593,8 @@ function validateSnapshot(snapshot, templates) {
|
||||
const template = templates.get(row.templateId);
|
||||
if (!template) throw new Error("Unmapped RuneWaker template " + row.templateId + ".");
|
||||
if (template.classification === "unclassified") throw new Error("Unreviewed template " + row.templateId + ".");
|
||||
if (row.classification !== template.classification) {
|
||||
if (row.classification !== template.classification
|
||||
&& template.source?.classificationRule !== "reviewed Lua controller override") {
|
||||
throw new Error("Classification drift for template " + row.templateId + ".");
|
||||
}
|
||||
const actor = recipe.actors.find((entry) => entry.id === template.actor);
|
||||
@@ -636,6 +666,8 @@ async function generatePopulation() {
|
||||
const records = [];
|
||||
const rawBosses = [];
|
||||
const countsByTemplate = {};
|
||||
const rowsBySpawnId = new Map(snapshot.rows.map((row) => [row.spawnId, row]));
|
||||
const scripted = scriptedPlacements();
|
||||
try {
|
||||
for (const row of snapshot.rows) {
|
||||
const template = templates.get(row.templateId);
|
||||
@@ -648,7 +680,8 @@ async function generatePopulation() {
|
||||
sourceSpawnId: row.spawnId,
|
||||
sourceTemplateId: row.templateId,
|
||||
name: row.name,
|
||||
classification: row.classification,
|
||||
classification: template.classification,
|
||||
sourceClassification: row.classification,
|
||||
sourcePosition: row.sourcePosition,
|
||||
sourceDirection: row.direction,
|
||||
localPosition: local.map((value) => Number(value.toFixed(6))),
|
||||
@@ -687,6 +720,72 @@ async function generatePopulation() {
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const placementDefinition of scripted) {
|
||||
const anchor = rowsBySpawnId.get(placementDefinition.sourceAnchorSpawnId);
|
||||
if (!anchor) {
|
||||
throw new Error(
|
||||
"Scripted placement " + placementDefinition.id + " has no source anchor row "
|
||||
+ placementDefinition.sourceAnchorSpawnId + ".",
|
||||
);
|
||||
}
|
||||
if (placementDefinition.controllerSpawnId !== undefined
|
||||
&& !rowsBySpawnId.has(placementDefinition.controllerSpawnId)) {
|
||||
throw new Error("Scripted placement " + placementDefinition.id + " has no controller row " + placementDefinition.controllerSpawnId + ".");
|
||||
}
|
||||
const template = templates.get(placementDefinition.templateId);
|
||||
const offset = placementDefinition.sourceOffset ?? [0, 0, 0];
|
||||
const sourcePosition = anchor.sourcePosition.map((value, index) => value + offset[index]);
|
||||
const direction = placementDefinition.direction ?? anchor.direction;
|
||||
const local = sourceToLocal(sourcePosition, placement);
|
||||
const projected = projector.project(local);
|
||||
if (projected.distance > recipe.coordinateSystem.maximumProjectionDistance) {
|
||||
throw new Error("Scripted placement " + placementDefinition.id + " is " + projected.distance + "m from navigation.");
|
||||
}
|
||||
const entityId = runtimePrefix + "-" + template.id;
|
||||
if (!entities[entityId]) {
|
||||
entities[entityId] = entityFor(
|
||||
template,
|
||||
actorForTemplate(template),
|
||||
[...(sourceSpellsByTemplate.get(template.id)?.values() ?? [])],
|
||||
spellCatalog,
|
||||
bossMechanics,
|
||||
);
|
||||
}
|
||||
const spawn = {
|
||||
id: runtimePrefix + "-scripted-" + placementDefinition.id,
|
||||
entityId,
|
||||
position: projected.position,
|
||||
yaw: yawFromDirection(direction),
|
||||
spawnMask: template.spawnMask ?? 1,
|
||||
};
|
||||
staticSpawns.push(spawn);
|
||||
records.push({
|
||||
sourceSpawnId: anchor.spawnId,
|
||||
sourceTemplateId: template.id,
|
||||
scriptedPlacementId: placementDefinition.id,
|
||||
sourceControllerSpawnId: placementDefinition.controllerSpawnId ?? null,
|
||||
sourceScriptRoot: placementDefinition.sourceScriptRoot ?? null,
|
||||
evidence: placementDefinition.evidence,
|
||||
name: template.name,
|
||||
classification: template.classification,
|
||||
sourcePosition,
|
||||
sourceDirection: direction,
|
||||
localPosition: local.map((value) => Number(value.toFixed(6))),
|
||||
projectedPosition: projected.position,
|
||||
projectionDistance: projected.distance,
|
||||
modelPath: template.source?.modelPath ?? null,
|
||||
});
|
||||
countsByTemplate[template.id] = (countsByTemplate[template.id] ?? 0) + 1;
|
||||
if (template.classification === "boss" && placementDefinition.objective !== false) {
|
||||
rawBosses.push({
|
||||
id: spawn.id,
|
||||
sourceSpawnId: anchor.spawnId,
|
||||
templateId: template.id,
|
||||
name: template.name,
|
||||
position: spawn.position,
|
||||
});
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
projector.dispose();
|
||||
}
|
||||
@@ -720,6 +819,7 @@ async function generatePopulation() {
|
||||
zoneId: recipe.zoneId,
|
||||
sourceRowCount: snapshot.rows.length,
|
||||
importedSpawnCount: staticSpawns.length,
|
||||
scriptedSpawnCount: scripted.length,
|
||||
excludedRowCount: excluded.length,
|
||||
bossSpawnCount: bosses.length,
|
||||
objectiveOrder: objectiveOrder.provenance,
|
||||
|
||||
Reference in new issue
Block a user