mirror of
https://github.com/migatu/vtt_work.git
synced 2026-07-14 13:34:42 +00:00
aaa
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
// W&G Voidships Builder — Voidship Actor Sheet (vehicle+flag emulation)
|
||||
// v1.0.0 (safe MVP) — works on Foundry v11–v13
|
||||
/* 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`);
|
||||
});
|
||||
Reference in New Issue
Block a user