mirror of
https://github.com/migatu/vtt_work.git
synced 2026-07-14 13:34:42 +00:00
125 lines
5.2 KiB
JavaScript
125 lines
5.2 KiB
JavaScript
// gk-greyknight — auto-attach loadout (deduped) v0.4.5
|
||
Hooks.once("ready", () => {
|
||
const PACK_KEY = "gk-greyknight.gk-items"; // moduleId.packName
|
||
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});
|
||
}
|
||
|
||
// De-register old hook if present to avoid double dialogs
|
||
if (window._gkAutoLoadoutHookId) {
|
||
Hooks.off("createItem", window._gkAutoLoadoutHookId);
|
||
window._gkAutoLoadoutHookId = null;
|
||
}
|
||
|
||
window._gkAutoLoadoutHookId = Hooks.on("createItem", async (item, opts, userId) => {
|
||
try {
|
||
if (item?.type !== "archetype") return;
|
||
if (item?.name !== "Grey Knight (Archetype)") return;
|
||
// Only the client that performed the creation
|
||
if (game.userId !== userId) return;
|
||
|
||
const actor = item.parent;
|
||
if (!actor) return;
|
||
// Avoid duplicate prompts per actor
|
||
if (actor.getFlag(FLAG_SCOPE, FLAG_DONE)) return;
|
||
await actor.setFlag(FLAG_SCOPE, FLAG_DONE, true);
|
||
|
||
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">War‑Plate — 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");
|
||
|
||
// Clear both armours equipped
|
||
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);
|
||
}
|
||
|
||
// Synergy toggle
|
||
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 (id=", window._gkAutoLoadoutHookId, ")");
|
||
});
|