// gk-greyknight helpers.js — consolidated 0.6.4.6 // Zawiera: Brotherhood prompt + starter, powiadomienie (także poza walką), sheet summary, // mini-widżet, oraz patcher traitów (Psycannon/Psilencer -> force). /* ---------------- Utilities ---------------- */ const GK_DEBUG = false; const FLAG_SCOPE = "gk-greyknight"; async function findItemInAllPacksByName(name, type=null) { for (const pack of game.packs) { if (pack.documentName !== "Item") continue; const idx = await pack.getIndex(); const hit = idx.find(e => e.name === name && (!type || e.type === type)); if (hit) return await pack.getDocument(hit._id); } return null; } async function ensureHasItemByName(actor, name, type=null) { const existing = actor.items?.find(i => i.name === name && (!type || i.type === type)); if (existing) return existing; const doc = await findItemInAllPacksByName(name, type); if (!doc) return null; const data = doc.toObject(); delete data._id; const [created] = await actor.createEmbeddedDocuments("Item", [data]); return created; } async function promptDiscipline(actor) { const existing = await actor.getFlag(FLAG_SCOPE, "discipline"); if (existing) return existing; return await new Promise(resolve => { new Dialog({ title: "Brotherhood of Psykers — Choose Discipline", content: `
Select a discipline for this character:
`, buttons: { ok: { label: "Confirm", icon: "", callback: html => resolve(html.find('input[name="disc"]:checked').val() || "sanctic") }, cancel: { label: "Cancel", callback: () => resolve(null) } }, default: "ok" }).render(true); }); } async function gkResolveActorFromMessage(doc) { const sp = doc.speaker || {}; let actor = sp.actor ? game.actors?.get(sp.actor) : null; if (!actor && canvas?.tokens) { const t = (sp.token && canvas.tokens.get(sp.token)) || canvas.tokens.controlled?.[0] || null; actor = t?.actor || actor; } return actor; } async function gkIsPsychicMessage(doc) { try { const raw = `${doc.flavor || ""} ${TextEditor?.stripHTML(doc.content || "") || ""}`.toLowerCase(); const keys = ["psychic","psychic mastery","psychic power","moc psioniczna","smite","hammerhand","sanctuary","shrouding","might of titan"]; if (keys.some(k=>raw.includes(k))) return true; const flagsStr = JSON.stringify(doc.flags || {}).toLowerCase(); if (flagsStr.includes("psychic")) return true; if (flagsStr.includes("psychicpower")) return true; if (flagsStr.includes("\"power\"")) return true; const tryUuids = [ doc.getFlag?.("core","sourceId"), doc.getFlag?.("wng-core","itemUuid"), doc.flags?.document?.uuid, doc.flags?.uuid ].filter(Boolean); for (const u of tryUuids) { try { const it = await fromUuid(u); if (it?.type === "psychicPower") return true; } catch(e){} } } catch(e) { if (GK_DEBUG) console.warn("gk IsPsychicMessage error:", e); } return false; } function gkBrotherhoodAlliesAndBonus(actor) { const tokens = canvas?.tokens?.placeables || []; const ids = new Set(); for (const t of tokens) { const a = t.actor; if (!a) continue; const ok = a.items?.some(i => i.type === "ability" && i.name === "Brotherhood of Psykers"); if (ok) ids.add(a.id); } const total = ids.size; const bonus = ids.has(actor?.id) ? Math.max(0, total - 1) : total; return { total, bonus }; } /* ---------------- 1) Brotherhood: prompt + starter ---------------- */ Hooks.once("ready", () => { // Avoid duplicate hook if hot-reloaded if (window._gkBroCreateHookId) { Hooks.off("createItem", window._gkBroCreateHookId); window._gkBroCreateHookId = null; } window._gkBroCreateHookId = Hooks.on("createItem", async (item, opts, userId) => { try { if (game.userId !== userId) return; if (item?.type !== "ability" || item?.name !== "Brotherhood of Psykers") return; const actor = item.parent; if (!actor) return; const chosen = await promptDiscipline(actor); if (!chosen) return; await actor.setFlag(FLAG_SCOPE, "discipline", chosen); const psyker = await ensureHasItemByName(actor, "PSYKER", "keyword"); if (!psyker) ui.notifications?.warn("PSYKER keyword not found in loaded packs. Add it manually from wng-core."); if (chosen === "sanctic") { const ok = await ensureHasItemByName(actor, "Hammerhand (Sanctic)", "psychicPower"); if (!ok) ui.notifications?.warn("Couldn't auto-add Hammerhand (Sanctic). Drag a Sanctic power from the GK pack."); } else { const ok = await ensureHasItemByName(actor, "Smite", "psychicPower"); if (!ok) { ui.notifications?.warn("Smite not found in available packs. Please add a Librarius power manually."); game.ui?.sidebar?.tabs?.compendium?.activate(); } } } catch (e) { console.error("gk-greyknight — Brotherhood prompt:", e); } }); });