diff --git a/wg-greyknights/gk-greyknight-0.4.4-patch/module.json.patch.json b/wg-greyknights/gk-greyknight-0.4.7-patch/module.json.patch.json similarity index 100% rename from wg-greyknights/gk-greyknight-0.4.4-patch/module.json.patch.json rename to wg-greyknights/gk-greyknight-0.4.7-patch/module.json.patch.json diff --git a/wg-greyknights/gk-greyknight-0.4.6-patch/scripts/auto-loadout.js b/wg-greyknights/gk-greyknight-0.4.7-patch/scripts/auto-loadout.js similarity index 78% rename from wg-greyknights/gk-greyknight-0.4.6-patch/scripts/auto-loadout.js rename to wg-greyknights/gk-greyknight-0.4.7-patch/scripts/auto-loadout.js index 69cb0fd..4840d1d 100644 --- a/wg-greyknights/gk-greyknight-0.4.6-patch/scripts/auto-loadout.js +++ b/wg-greyknights/gk-greyknight-0.4.7-patch/scripts/auto-loadout.js @@ -1,6 +1,7 @@ -// gk-greyknight — auto-attach loadout (dedupe + legacy scrub) v0.4.6 +// gk-greyknight — auto-attach loadout (scoped, no clashes) v0.4.7 Hooks.once("ready", () => { - const PACK_KEY = "gk-greyknight.gk-items"; // moduleId.packName + 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", @@ -10,20 +11,6 @@ Hooks.once("ready", () => { }; const FLAG_SCOPE = "gk-greyknight"; const FLAG_DONE = "autoLoadoutDone"; - // --- REMOVE legacy createItem handlers that emit 'Choice 1/2' or 'ORDO MALLEUS' dialogs --- - const removeLegacy = () => { - const list = (Hooks.events && Hooks.events.createItem) || Hooks._hooks?.createItem || []; - // copy to avoid mutating while iterating - const arr = Array.from(list); - for (const cb of arr) { - const src = (cb && cb.toString && cb.toString()) || ""; - if (/ORDO\s+MALLEUS/i.test(src) || /Choice\s*1/i.test(src) || /macro-gk-auto-loadout-on-archetype/i.test(src)) { - try { Hooks.off("createItem", cb); console.warn("gk-greyknight: removed legacy createItem hook"); } catch(e){} - } - } - }; - removeLegacy(); - async function fetchFromCompendium(name) { const pack = game.packs.get(PACK_KEY); if (!pack) return null; @@ -51,19 +38,29 @@ Hooks.once("ready", () => { if (it && typeof it.system?.equipped !== "undefined") await it.update({"system.equipped": !!on}); } - if (window._gkAutoLoadoutHookId) { Hooks.off("createItem", window._gkAutoLoadoutHookId); window._gkAutoLoadoutHookId = null; } + // 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; - if (item?.name !== "Grey Knight (Archetype)") return; - if (game.userId !== userId) return; // only the originating client + // 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 a legacy dialog already fired very early, bail out to avoid double prompts if (actor.getFlag(FLAG_SCOPE, FLAG_DONE)) return; await actor.setFlag(FLAG_SCOPE, FLAG_DONE, true); + // Dialog const content = `