From 5e77008c236851444766646a452370b8e545ffba Mon Sep 17 00:00:00 2001 From: cosmo Date: Sun, 26 Apr 2026 17:17:00 +0200 Subject: [PATCH] add auto-sync for Ikonis features and implement documentation via README.md --- README.md | 56 +++++++++++++++++++++++++++++++++ scripts/ikonis-data.js | 17 +++------- scripts/main.js | 70 ++++++++++++++++++++++++++++++------------ 3 files changed, 111 insertions(+), 32 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e47c7b4 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# Daggerheart - Ikonis + +A Foundry VTT module for the **Daggerheart** system that adds a customizable "Ikonis" personalized weapon system. + +The Ikonis system allows weapons to be upgraded with "Augments" (Tech) that provide various bonuses, effects, and modifications, managed through a dedicated hardware interface on the weapon sheet. + +## Features + +### 🛠️ The Ikonis Hardware Tab +Every weapon sheet now includes a dedicated **Ikonis** tab. +- **Install Tech**: Drag and drop features or select from the pre-defined list. +- **Bonded Features**: Link a specific "Bonded" feature to the weapon that follows the user. +- **Dynamic Slot Scaling**: The number of available augment slots automatically scales based on the weapon's **Tier** (1-4). + +### ⚙️ Global Hardware Manager +GMs can access the **Global Hardware Manager** in the module settings to: +- Define the global pool of available Augments. +- Set the cost, effect, and name of each augment. +- Link augments to specific **Features** (items) for automated description and icon fetching. +- Configure the default "Bonded" feature for all Ikonis weapons. + +### 📚 Integrated Compendium +Includes an **Ikonis Features** compendium containing 10 ready-to-use augments and bond effects with custom icons and descriptions. + +### ⚖️ Per-Tier Configuration +Fine-tune the balance of your game by setting exactly how many slots are provided at each tier (1, 2, 3, and 4) in the module settings. + +## Installation + +1. Open the Foundry VTT Setup screen. +2. Go to the **Add-on Modules** tab. +3. Click **Install Module**. +4. Paste the following manifest URL: + `https://git.geeks.gay/cosmo/dh-ikonis/raw/branch/main/module.json` +5. Click **Install**. + +## Usage + +1. **For GMs**: + - Go to **Configure Settings** > **Daggerheart - Ikonis**. + - Click **Open Augment Manager** to customize your global tech list. + - Adjust the **Slots per Tier** settings to match your desired power level. +2. **For Players**: + - Open a Weapon sheet. + - Click the **Ikonis** tab (microchip icon). + - Use the **Install Tech** button to add augments from the global list. + - Drag and drop features from the compendium into the Ikonis tab to link them. + +## Credits + +- Developed for the Daggerheart community. +- Built by Antigravity & Cosmo. +- Icons from the Foundry VTT core library. + +--- +*This is an unofficial module for the Daggerheart system.* diff --git a/scripts/ikonis-data.js b/scripts/ikonis-data.js index 5bbe54e..cbb8700 100644 --- a/scripts/ikonis-data.js +++ b/scripts/ikonis-data.js @@ -4,10 +4,10 @@ export const DEFAULT_AUGMENTS = [ { id: "shock", name: "Static Coil", effect: "Targets hit are Dazed", cost: "3 Copper", precompile: 2 }, { id: "shield", name: "Reactive Plating", effect: "+1 Armor while equipped", cost: "2 Steel", precompile: 1 }, { id: "range", name: "Long-Range Optics", effect: "Increases Range by 1 step", cost: "1 Lens", precompile: 2 }, - { id: "crit", "name": "Precision Chip", "effect": "+1 to Crit range", "cost": "1 Gold", "precompile": 3 }, - { id: "multi", "name": "Burst Module", "effect": "Can target 2 enemies (Half damage)", "cost": "2 Gears", "precompile": 4 }, - { id: "drain", "name": "Siphon Link", "effect": "Recover 1 Hope on kill", "cost": "1 Soul Gem", "precompile": 4 }, - { id: "weight", "name": "Gravity Plate", "effect": "Weapon is Heavy (more damage)", "cost": "4 Lead", "precompile": 2 } + { id: "crit", name: "Precision Chip", effect: "+1 to Crit range", cost: "1 Gold", precompile: 3 }, + { id: "multi", name: "Burst Module", effect: "Can target 2 enemies (Half damage)", cost: "2 Gears", precompile: 4 }, + { id: "drain", name: "Siphon Link", effect: "Recover 1 Hope on kill", cost: "1 Soul Gem", precompile: 4 }, + { id: "weight", name: "Gravity Plate", effect: "Weapon is Heavy (more damage)", cost: "4 Lead", precompile: 2 } ]; export function getAugments() { @@ -18,20 +18,13 @@ export function getSlotCount(item) { const flags = item.getFlag('dh-ikonis') || {}; if (typeof flags.slotOverride === "number") return flags.slotOverride; - // Daggerheart Tier detection (can be system.tier.value or system.tier) let tier = item.system?.tier?.value; if (tier === undefined) tier = item.system?.tier; - - // Ensure we have a number const tierNum = parseInt(tier) || 1; - console.log(`DH-Ikonis | Detecting slots for Tier ${tierNum} (Raw: ${tier})`); - const settingKey = `slotsTier${tierNum}`; try { - const slots = game.settings.get('dh-ikonis', settingKey); - console.log(`DH-Ikonis | Setting [${settingKey}] returned: ${slots}`); - return slots; + return game.settings.get('dh-ikonis', settingKey); } catch (e) { return tierNum >= 2 ? 3 : 2; } diff --git a/scripts/main.js b/scripts/main.js index 42e83c2..af1f4af 100644 --- a/scripts/main.js +++ b/scripts/main.js @@ -35,7 +35,7 @@ Hooks.once('init', () => { }); }); - // Configuration Menu (V2 compliant) + // Configuration Menu game.settings.registerMenu(MODULE_ID, "augmentsMenu", { name: "Manage Ikonis Augments", label: "Open Augment Manager", @@ -56,37 +56,67 @@ Hooks.on('setup', () => { patchIkonisSheet(); }); -// Watch for Tier changes and force a refresh Hooks.on('updateItem', (item, changes, options, userId) => { - // Check if system data or flags were updated - const isTierUpdate = foundry.utils.hasProperty(changes, "system.tier"); - const isFlagUpdate = foundry.utils.hasProperty(changes, "flags.dh-ikonis"); - - if (isTierUpdate || isFlagUpdate) { - console.log(`DH-Ikonis | Update detected for ${item.name}. Re-rendering sheets...`); - // Find all active sheets for this item and force a full render - Object.values(item.apps || {}).forEach(app => { - if (app.render) app.render(true); - }); + if (foundry.utils.hasProperty(changes, "system.tier") || foundry.utils.hasProperty(changes, "flags.dh-ikonis")) { + Object.values(item.apps || {}).forEach(app => { app.render?.(true); }); } }); -Hooks.once('ready', () => { +Hooks.once('ready', async () => { + // Perform Auto-Sync for Features + if (game.user.isGM) { + await syncIkonisFeatures(); + } + const actorsApi = game.system.api.models.actors || {}; const DhCharacter = actorsApi.DhCharacter || actorsApi.DHCharacter || actorsApi.character; if (DhCharacter) { Object.defineProperty(DhCharacter.prototype, 'primaryWeapon', { - get: function() { - return this.parent.items.find(x => x.type === 'weapon' && x.system.equipped && !x.system.secondary); - }, + get: function() { return this.parent.items.find(x => x.type === 'weapon' && x.system.equipped && !x.system.secondary); }, configurable: true }); - Object.defineProperty(DhCharacter.prototype, 'secondaryWeapon', { - get: function() { - return this.parent.items.find(x => x.type === 'weapon' && x.system.equipped && x.system.secondary); - }, + get: function() { return this.parent.items.find(x => x.type === 'weapon' && x.system.equipped && x.system.secondary); }, configurable: true }); } }); + +/** + * Automatically links augments in the settings to features in the compendium by name. + */ +async function syncIkonisFeatures() { + const pack = game.packs.get("dh-ikonis.ikonis-features"); + if (!pack) return; + + const index = await pack.getIndex(); + const currentAugs = game.settings.get(MODULE_ID, 'augmentsList') || []; + let updates = false; + + // 1. Sync Augments + const newAugs = currentAugs.map(aug => { + if (!aug.featureUuid) { + const match = index.find(i => i.name === aug.name); + if (match) { + aug.featureUuid = match.uuid; + updates = true; + console.log(`DH-Ikonis | Auto-linked augment [${aug.name}] to compendium feature.`); + } + } + return aug; + }); + + if (updates) { + await game.settings.set(MODULE_ID, 'augmentsList', newAugs); + } + + // 2. Sync Bonded Feature + let bondedUuid = game.settings.get(MODULE_ID, 'defaultBondedUuid'); + if (!bondedUuid) { + const bondMatch = index.find(i => i.name === "Ikonis Bond"); + if (bondMatch) { + await game.settings.set(MODULE_ID, 'defaultBondedUuid', bondMatch.uuid); + console.log(`DH-Ikonis | Auto-linked default Bonded feature.`); + } + } +}