Files
vtt_work/wg-greyknights/gk-greyknight-0.4.7-patch/scripts/auto-loadout.js
T

123 lines
5.4 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.
// gk-greyknight — auto-attach loadout (scoped, no clashes) v0.4.7
Hooks.once("ready", () => {
const PACK_KEY = "gk-greyknight.gk-items"; // our compendium
const PACK_SRC_PREFIX = `Compendium.${PACK_KEY}.`; // prefix in core.sourceId
const ITEMS = {
ability: "Aegis of Titan (Ability)",
nemesis: "Nemesis Force Halberd",
storm: "Grey Knight Armour Integrated Storm Bolter",
aegisPA: "Aegis Power Armour",
aegisTerm: "Terminator Aegis (Grey Knights)"
};
const FLAG_SCOPE = "gk-greyknight"; const FLAG_DONE = "autoLoadoutDone";
async function fetchFromCompendium(name) {
const pack = game.packs.get(PACK_KEY);
if (!pack) return null;
const index = await pack.getIndex();
const hit = index.find(e => e.name === name);
if (!hit) return null;
const doc = await pack.getDocument(hit._id);
return doc?.toObject();
}
async function ensureOnActor(actor, name, equip=false) {
let have = actor.items.getName(name);
if (have) {
if (typeof have.system?.equipped !== "undefined") await have.update({"system.equipped": !!equip});
return have;
}
let src = await fetchFromCompendium(name);
if (!src) { const world = game.items.getName(name); if (world) src = world.toObject(); }
if (!src) return null;
if (equip && src.system && typeof src.system.equipped !== "undefined") src.system.equipped = true;
const [created] = await actor.createEmbeddedDocuments("Item", [src]);
return created;
}
async function setEquipped(actor, name, on) {
const it = actor.items.getName(name);
if (it && typeof it.system?.equipped !== "undefined") await it.update({"system.equipped": !!on});
}
// Dedupe our hook
if (window._gkAutoLoadoutHookId) {
Hooks.off("createItem", window._gkAutoLoadoutHookId);
window._gkAutoLoadoutHookId = null;
}
window._gkAutoLoadoutHookId = Hooks.on("createItem", async (item, opts, userId) => {
try {
// 1) only archetypes
if (item?.type !== "archetype") return;
// 2) only our GK archetype coming from our pack (prevents clashes with Cubicle7 archetypes)
const src = item?.flags?.core?.sourceId || "";
const isFromOurPack = src.startsWith(PACK_SRC_PREFIX);
const isOurGKByName = item?.name === "Grey Knight (Archetype)";
if (!isFromOurPack && !isOurGKByName) return; // ignore all others (e.g. Inquisitor, Guardsman, etc.)
// 3) only the client that created the item
if (game.userId !== userId) return;
// 4) once per actor
const actor = item.parent; if (!actor) return;
if (actor.getFlag(FLAG_SCOPE, FLAG_DONE)) return;
await actor.setFlag(FLAG_SCOPE, FLAG_DONE, true);
// Dialog
const content = `
<style>
.gk-choices .opt{display:flex;gap:.6rem;align-items:flex-start;padding:.35rem .5rem;border:1px solid #6663;border-radius:6px;margin:.35rem 0}
.gk-choices .opt label{font-weight:600}
.gk-choices .hint{font-size:.9em;opacity:.85;margin-left:1.7rem}
</style>
<div class="gk-choices">
<div class="opt">
<input type="radio" name="mode" value="incog" id="gk-incog">
<label for="gk-incog">Incognito (bez Aegis)</label>
</div>
<div class="hint">Brak Aegis na starcie; dodam Ability i broń, ale nie będą <i>equipped</i>.</div>
<div class="opt">
<input type="radio" name="mode" value="war" id="gk-war" checked>
<label for="gk-war">WarPlate — Aegis Power Armour</label>
</div>
<div class="hint">Wyposaża: Aegis Power Armour + Nemesis + Integrated Storm Bolter. Włącza synergię Aegis.</div>
<div class="opt">
<input type="radio" name="mode" value="term" id="gk-term">
<label for="gk-term">Terminator — Terminator Aegis</label>
</div>
<div class="hint">Wyposaża: Terminator Aegis + Nemesis + Integrated Storm Bolter. Włącza synergię Aegis.</div>
</div>`;
const choice = await new Promise(resolve => {
new Dialog({
title: "Grey Knight — Wybierz Loadout",
content,
buttons: {
ok: {label: "Zastosuj", icon:"<i class='fas fa-check'></i>", callback: html => resolve(html.find('input[name=\"mode\"]:checked').val() || "war")},
cancel: {label:"Anuluj", callback: ()=>resolve(null)}
},
default: "ok"
}).render(true);
});
if (!choice) return;
await ensureOnActor(actor, ITEMS.ability, false);
await ensureOnActor(actor, ITEMS.nemesis, choice!=="incog");
await ensureOnActor(actor, ITEMS.storm, choice!=="incog");
await setEquipped(actor, ITEMS.aegisPA, false);
await setEquipped(actor, ITEMS.aegisTerm, false);
if (choice === "war") await ensureOnActor(actor, ITEMS.aegisPA, true);
else if (choice === "term") await ensureOnActor(actor, ITEMS.aegisTerm, true);
const abil = actor.items.getName(ITEMS.ability);
const anyAegisOn = !!actor.items.find(i => ["armour","armor"].includes(i.type) && /Aegis/.test(i.name) && i.system?.equipped);
if (abil?.effects?.length) for (const ef of abil.effects) if (ef.name?.toLowerCase().includes("synergy")) await ef.update({disabled: !anyAegisOn});
ui.notifications.info(`GK loadout: ${choice.toUpperCase()} ustawiony.`);
} catch (e) { console.error("gk-greyknight auto-loadout error:", e); }
});
console.log("gk-greyknight: auto-loadout hook active (scoped)");
});