add auto-sync for Ikonis features and implement documentation via README.md
This commit is contained in:
parent
7bffeacaac
commit
5e77008c23
3 changed files with 111 additions and 32 deletions
56
README.md
Normal file
56
README.md
Normal file
|
|
@ -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.*
|
||||||
|
|
@ -4,10 +4,10 @@ export const DEFAULT_AUGMENTS = [
|
||||||
{ id: "shock", name: "Static Coil", effect: "Targets hit are Dazed", cost: "3 Copper", precompile: 2 },
|
{ 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: "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: "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: "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: "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: "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: "weight", name: "Gravity Plate", effect: "Weapon is Heavy (more damage)", cost: "4 Lead", precompile: 2 }
|
||||||
];
|
];
|
||||||
|
|
||||||
export function getAugments() {
|
export function getAugments() {
|
||||||
|
|
@ -18,20 +18,13 @@ export function getSlotCount(item) {
|
||||||
const flags = item.getFlag('dh-ikonis') || {};
|
const flags = item.getFlag('dh-ikonis') || {};
|
||||||
if (typeof flags.slotOverride === "number") return flags.slotOverride;
|
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;
|
let tier = item.system?.tier?.value;
|
||||||
if (tier === undefined) tier = item.system?.tier;
|
if (tier === undefined) tier = item.system?.tier;
|
||||||
|
|
||||||
// Ensure we have a number
|
|
||||||
const tierNum = parseInt(tier) || 1;
|
const tierNum = parseInt(tier) || 1;
|
||||||
|
|
||||||
console.log(`DH-Ikonis | Detecting slots for Tier ${tierNum} (Raw: ${tier})`);
|
|
||||||
|
|
||||||
const settingKey = `slotsTier${tierNum}`;
|
const settingKey = `slotsTier${tierNum}`;
|
||||||
try {
|
try {
|
||||||
const slots = game.settings.get('dh-ikonis', settingKey);
|
return game.settings.get('dh-ikonis', settingKey);
|
||||||
console.log(`DH-Ikonis | Setting [${settingKey}] returned: ${slots}`);
|
|
||||||
return slots;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return tierNum >= 2 ? 3 : 2;
|
return tierNum >= 2 ? 3 : 2;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ Hooks.once('init', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Configuration Menu (V2 compliant)
|
// Configuration Menu
|
||||||
game.settings.registerMenu(MODULE_ID, "augmentsMenu", {
|
game.settings.registerMenu(MODULE_ID, "augmentsMenu", {
|
||||||
name: "Manage Ikonis Augments",
|
name: "Manage Ikonis Augments",
|
||||||
label: "Open Augment Manager",
|
label: "Open Augment Manager",
|
||||||
|
|
@ -56,37 +56,67 @@ Hooks.on('setup', () => {
|
||||||
patchIkonisSheet();
|
patchIkonisSheet();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Watch for Tier changes and force a refresh
|
|
||||||
Hooks.on('updateItem', (item, changes, options, userId) => {
|
Hooks.on('updateItem', (item, changes, options, userId) => {
|
||||||
// Check if system data or flags were updated
|
if (foundry.utils.hasProperty(changes, "system.tier") || foundry.utils.hasProperty(changes, "flags.dh-ikonis")) {
|
||||||
const isTierUpdate = foundry.utils.hasProperty(changes, "system.tier");
|
Object.values(item.apps || {}).forEach(app => { app.render?.(true); });
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
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 actorsApi = game.system.api.models.actors || {};
|
||||||
const DhCharacter = actorsApi.DhCharacter || actorsApi.DHCharacter || actorsApi.character;
|
const DhCharacter = actorsApi.DhCharacter || actorsApi.DHCharacter || actorsApi.character;
|
||||||
if (DhCharacter) {
|
if (DhCharacter) {
|
||||||
Object.defineProperty(DhCharacter.prototype, 'primaryWeapon', {
|
Object.defineProperty(DhCharacter.prototype, 'primaryWeapon', {
|
||||||
get: function() {
|
get: function() { return this.parent.items.find(x => x.type === 'weapon' && x.system.equipped && !x.system.secondary); },
|
||||||
return this.parent.items.find(x => x.type === 'weapon' && x.system.equipped && !x.system.secondary);
|
|
||||||
},
|
|
||||||
configurable: true
|
configurable: true
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(DhCharacter.prototype, 'secondaryWeapon', {
|
Object.defineProperty(DhCharacter.prototype, 'secondaryWeapon', {
|
||||||
get: function() {
|
get: function() { return this.parent.items.find(x => x.type === 'weapon' && x.system.equipped && x.system.secondary); },
|
||||||
return this.parent.items.find(x => x.type === 'weapon' && x.system.equipped && x.system.secondary);
|
|
||||||
},
|
|
||||||
configurable: true
|
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.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue