Files
vtt_work/wg-greyknights/scripts/auto-loadout.js
T

136 lines
6.5 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 + incognito + ORDO) v0.6.1
Hooks.once("ready", () => {
const PACK_KEY = "gk-greyknight.gk-items";
const PACK_SRC_PREFIX = `Compendium.${PACK_KEY}.`;
const CORE = {
knife: "Compendium.wng-core.items.Item.4QVBQYWXXLyvFWkj",
pistol: "Compendium.wng-core.items.Item.7b2xcPWBB7up65PM",
ordo: "Compendium.wng-core.items.Item.mpcvHYlffwcBy9gP"
};
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)",
pilgrim: "Pilgrim Astartes Power Armor",
ordo: "ORDO MALLEUS"
};
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 fetchFromUuid(uuid) { try { const doc = await fromUuid(uuid); return doc?.toObject(); } catch(e){ return null; } }
async function ensureOnActor(actor, srcDoc, equip=false) {
const name = srcDoc?.name; if (!name) return null;
let have = actor.items.getName(name);
if (have) { if (typeof have.system?.equipped !== "undefined") await have.update({"system.equipped": !!equip}); return have; }
if (equip && srcDoc.system && typeof srcDoc.system.equipped !== "undefined") srcDoc.system.equipped = true;
const [created] = await actor.createEmbeddedDocuments("Item", [srcDoc]);
return created;
}
async function ensureByName(actor, name, equip=false) {
const 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;
return ensureOnActor(actor, src, equip);
}
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});
}
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;
const src = item?.flags?.core?.sourceId || "";
const isFromOurPack = src.startsWith(PACK_SRC_PREFIX);
const isOurGKByName = item?.name === "Grey Knight (Archetype)";
if (!isFromOurPack && !isOurGKByName) return;
if (game.userId !== userId) return;
const actor = item.parent; if (!actor) return;
if (actor.getFlag(FLAG_SCOPE, FLAG_DONE)) return;
await actor.setFlag(FLAG_SCOPE, FLAG_DONE, true);
await ensureByName(actor, ITEMS.ability, false);
let ordoDoc = await fetchFromUuid(CORE.ordo);
if (!ordoDoc) ordoDoc = await fetchFromCompendium(ITEMS.ordo);
if (ordoDoc) await ensureOnActor(actor, ordoDoc, false);
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 — Pilgrim Astartes Power Armor + Combat Knife + Bolt Pistol</label>
</div>
<div class="hint">Lowprofile loadout (bez Nemesis/SB)</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">Aegis PA + Nemesis + Integrated Storm Bolter</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">Terminator Aegis + Nemesis + Integrated Storm Bolter</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 setEquipped(actor, ITEMS.aegisPA, false);
await setEquipped(actor, ITEMS.aegisTerm, false);
await setEquipped(actor, ITEMS.nemesis, false);
await setEquipped(actor, ITEMS.storm, false);
await setEquipped(actor, ITEMS.pilgrim, false);
if (choice === "incog") {
await ensureByName(actor, ITEMS.pilgrim, true);
const knife = await fetchFromUuid(CORE.knife); if (knife) await ensureOnActor(actor, knife, true);
const pistol = await fetchFromUuid(CORE.pistol); if (pistol) await ensureOnActor(actor, pistol, true);
} else if (choice === "war") {
await ensureByName(actor, ITEMS.nemesis, true);
await ensureByName(actor, ITEMS.storm, true);
await ensureByName(actor, ITEMS.aegisPA, true);
} else if (choice === "term") {
await ensureByName(actor, ITEMS.nemesis, true);
await ensureByName(actor, ITEMS.storm, true);
await ensureByName(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 (v0.6.1)");
});