Files
vtt_work/wg-voidships-builder/scripts/voidship-actor.js
T
2025-09-18 09:12:46 +02:00

166 lines
6.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// W&G Voidships Builder — Voidship Actor Sheet (vehicle+flag emulation)
// v1.0.0 (safe MVP) — works on Foundry v11v13
/* eslint-env es2021 */
const VB_MOD = "wg-voidships-builder";
class VoidshipSheet extends ActorSheet {
static get defaultOptions() {
const opts = super.defaultOptions;
return foundry.utils.mergeObject(opts, {
classes: ["wg-voidships", "sheet", "actor", "voidship"],
template: `modules/${VB_MOD}/templates/voidship-sheet.hbs`,
width: 720,
height: 620,
tabs: [{ navSelector: ".tabs", contentSelector: ".sheet-body", initial: "stats" }]
});
}
/** Prefer to use this sheet only for vehicles marked flagiem voidship */
_canUserView(user) {
return !!user;
}
get isVoidship() {
return this.actor?.getFlag(VB_MOD, "isVoidship") === true;
}
/** Aggregate base + mods from items into derived summary (safe, optional) */
_computeDerived() {
const a = this.actor;
const base = {
armour: Number(a.getFlag(VB_MOD, "base.armour")) || 0,
integrity: Number(a.getFlag(VB_MOD, "base.integrity")) || 0,
manoeuvre: Number(a.getFlag(VB_MOD, "base.manoeuvre")) || 0,
detection: Number(a.getFlag(VB_MOD, "base.detection")) || 0,
speed: Number(a.getFlag(VB_MOD, "base.speed")) || 0,
space: Number(a.getFlag(VB_MOD, "base.space")) || 0,
power: Number(a.getFlag(VB_MOD, "base.power")) || 0
};
const mods = { armour:0, integrity:0, manoeuvre:0, detection:0, speed:0, space:0, power:0 };
const slots = { prow:0, dorsal:0, port:0, starboard:0, keel:0, other:0 };
const items = a?.items ?? [];
for (const it of items) {
const eq = (it.system?.equipped ?? true); // treat as mounted unless explicitly off
const v = it.system?.voidship ?? {};
const m = v.mods ?? {};
if (eq) {
for (const k of Object.keys(mods)) {
const val = Number(m[k]);
if (Number.isFinite(val)) mods[k] += val;
}
}
const slot = String((v.slot || it.getFlag(VB_MOD, "slot") || "")).toLowerCase();
if (slot && slots.hasOwnProperty(slot)) slots[slot]++; else slots.other++;
}
const total = {
armour: base.armour + mods.armour,
integrity: base.integrity + mods.integrity,
manoeuvre: base.manoeuvre + mods.manoeuvre,
detection: base.detection + mods.detection,
speed: base.speed + mods.speed,
space: base.space + mods.space,
power: base.power + mods.power
};
// Headroom (positive = free)
total.spaceFree = total.space;
total.powerFree = total.power;
// If components encode their usage (voidship.use.{space|power})
for (const it of items) {
const use = it.system?.voidship?.use ?? {};
if (Number.isFinite(Number(use.space))) total.spaceFree -= Number(use.space);
if (Number.isFinite(Number(use.power))) total.powerFree -= Number(use.power);
}
return { base, mods, total, slots };
}
async getData(options={}) {
const data = await super.getData(options);
data.isVoidship = this.isVoidship;
data.voidship = this._computeDerived();
// expose a minimal config (labels)
data.cfg = {
labels: {
armour: "Armour",
integrity: "Integrity",
manoeuvre: "Manoeuvre",
detection: "Detection",
speed: "Speed",
space: "Space",
power: "Power",
spaceFree: "Space (free)",
powerFree: "Power (free)"
}
};
return data;
}
activateListeners(html) {
super.activateListeners(html);
// Guard: allow sheet UI even for non-voidship, but prompt to mark
html.find("[data-action='mark-voidship']").on("click", async () => {
await this.actor.setFlag(VB_MOD, "isVoidship", true);
ui.notifications.info("Marked as Voidship.");
this.render(true);
});
html.find("[data-action='unmark-voidship']").on("click", async () => {
await this.actor.unsetFlag(VB_MOD, "isVoidship");
ui.notifications.info("Unmarked Voidship.");
this.render(true);
});
html.find("[data-action='configure-base']").on("click", async () => {
const cur = this._computeDerived().base;
const content = `
<div class="form-group"><label>Armour</label><input type="number" name="armour" value="${cur.armour}"/></div>
<div class="form-group"><label>Integrity</label><input type="number" name="integrity" value="${cur.integrity}"/></div>
<div class="form-group"><label>Manoeuvre</label><input type="number" name="manoeuvre" value="${cur.manoeuvre}"/></div>
<div class="form-group"><label>Detection</label><input type="number" name="detection" value="${cur.detection}"/></div>
<div class="form-group"><label>Speed</label><input type="number" name="speed" value="${cur.speed}"/></div>
<div class="form-group"><label>Space</label><input type="number" name="space" value="${cur.space}"/></div>
<div class="form-group"><label>Power</label><input type="number" name="power" value="${cur.power}"/></div>
`;
new Dialog({
title: "Voidship — Base Stats",
content, buttons: {
ok: {
label: "Save",
callback: async (html) => {
const form = html[0].querySelector("form") || html[0];
const get = (k) => Number(form.querySelector(`[name="${k}"]`)?.value || 0);
const patch = {
"base.armour": get("armour"),
"base.integrity": get("integrity"),
"base.manoeuvre": get("manoeuvre"),
"base.detection": get("detection"),
"base.speed": get("speed"),
"base.space": get("space"),
"base.power": get("power")
};
for (const [k,v] of Object.entries(patch)) await this.actor.setFlag(VB_MOD, k, v);
this.render(true);
}
},
cancel: { label: "Cancel" }
},
default: "ok"
}, { jQuery: true }).render(true);
});
}
}
Hooks.once("init", () => {
// Register the sheet for the 'vehicle' type (W&G Vehicles via Church of Steel)
Actors.registerSheet(VB_MOD, VoidshipSheet, {
types: ["vehicle"],
makeDefault: false,
label: "Voidship (W&G)"
});
// Optional: a convenient factory on game namespace
game.wgVoidships = game.wgVoidships || {};
game.wgVoidships.createVoidship = async function(name="New Voidship") {
const actor = await Actor.create({ name, type: "vehicle", folder: null });
await actor.setFlag(VB_MOD, "isVoidship", true);
ui.notifications.info(`Voidship created: ${name}`);
return actor;
};
console.log(`${VB_MOD}: VoidshipSheet registered`);
});