// 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 = `
Low‑profile loadout (bez Nemesis/SB)
Aegis PA + Nemesis + Integrated Storm Bolter
Terminator Aegis + Nemesis + Integrated Storm Bolter
`; const choice = await new Promise(resolve => { new Dialog({ title: "Grey Knight — Wybierz Loadout", content, buttons: { ok: {label: "Zastosuj", icon:"", 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)"); });