Import gk-greyknight-0.6.1.zip do wg-greyknights (2025-08-22T11:40:25Z)

This commit is contained in:
2025-08-22 11:40:25 +00:00
parent 4408ca8971
commit bf3fe1e7c8
4 changed files with 160 additions and 25 deletions
+11 -7
View File
@@ -1,8 +1,12 @@
Grey Knights — Compendium (Wrath & Glory) v0.6.0 Grey Knights — Compendium (Wrath & Glory) v0.6.1
This version ships an additive compendium 'Grey Knights — Items (0.6.0, Updated Icons)' with the seven updated items only. - Consolidated main pack 'gk-items' (merged updated items; icons improved where missing/generic).
Import/replace these into your existing GK pack to avoid LevelDB caching issues. Icons now point into modules/wng-core/assets/... - Auto-loadout scoped to our GK archetype.
- If you previously had a LevelDB folder packs/gk-items/, delete it once to force re-migration, then Rebuild Index.
Changelog highlights:
* Replaced Aegis/Terminator Aegis/Integrated Storm Bolter with your updated JSONs (equip-only effects left intact).
* Added Pilgrim Astartes Power Armor and ORDO MALLEUS keyword fallback to the main pack.
* Added Nemesis Falchions (Pair), Psycannon, Psilencer, Psybolt Ammunition.
* Set rarity 'unique' for new weapons/ammo.
* Improved icons for items lacking an icon, using modules/wng-core/assets list.
Install:
1) Unzip as Data/modules/gk-greyknight (or merge into the existing module of the same id).
2) Enable module; open Compendium sidebar and use the new pack 'Grey Knights — Items (0.6.0, Updated Icons)'.
3) Drag/drop items into actors or replace entries in your main GK pack.
+4 -4
View File
@@ -1,7 +1,7 @@
{ {
"id": "gk-greyknight", "id": "gk-greyknight",
"title": "Grey Knights — Compendium (Wrath & Glory)", "title": "Grey Knights — Compendium (Wrath & Glory)",
"version": "0.6.0", "version": "0.6.1",
"compatibility": { "compatibility": {
"minimum": "11", "minimum": "11",
"verified": "13" "verified": "13"
@@ -16,9 +16,9 @@
], ],
"packs": [ "packs": [
{ {
"name": "gk-items-060", "name": "gk-items",
"label": "Grey Knights — Items (0.6.0, Updated Icons)", "label": "Grey Knights — Items",
"path": "packs/gk-items-060", "path": "packs/gk-items",
"type": "Item", "type": "Item",
"system": "wrath-and-glory", "system": "wrath-and-glory",
"private": false "private": false
File diff suppressed because one or more lines are too long
+133 -2
View File
@@ -1,4 +1,135 @@
// gk-greyknight — (optional) auto-loadout helper v0.6.0 (unchanged hook) // gk-greyknight — auto-attach loadout (scoped + incognito + ORDO) v0.6.1
Hooks.once("ready", () => { Hooks.once("ready", () => {
console.log("gk-greyknight v0.6.0 loaded — add-on compendium 'gk-items-060' available."); 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)");
}); });