mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-17 23:49:02 +01:00
Fix conflicts
This commit is contained in:
commit
3ff6ec4f5e
164 changed files with 2542 additions and 749 deletions
2
.github/workflows/deploy.yml
vendored
2
.github/workflows/deploy.yml
vendored
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
|
||||
- name: Build Packs
|
||||
run: |
|
||||
npm run pullYMLtoLDB
|
||||
npm run pullYMLtoLDBBuild
|
||||
mv --force src/packs/LICENSE packs/LICENSE
|
||||
|
||||
- name: Build daggerheart.js
|
||||
|
|
|
|||
|
|
@ -259,7 +259,10 @@ Hooks.on('moveToken', async (movedToken, data) => {
|
|||
const rangeDependantEffects = movedToken.actor.effects.filter(effect => effect.system.rangeDependence?.enabled);
|
||||
|
||||
const updateEffects = async (disposition, token, effects, effectUpdates) => {
|
||||
const rangeMeasurement = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.RangeMeasurement);
|
||||
const rangeMeasurement = game.settings.get(
|
||||
CONFIG.DH.id,
|
||||
CONFIG.DH.SETTINGS.gameSettings.variantRules
|
||||
).rangeMeasurement;
|
||||
|
||||
for (let effect of effects.filter(x => x.system.rangeDependence?.enabled)) {
|
||||
const { target, range, type } = effect.system.rangeDependence;
|
||||
|
|
|
|||
19
lang/en.json
19
lang/en.json
|
|
@ -188,7 +188,8 @@
|
|||
"manualMulticlassSubclass": {
|
||||
"title": "Multiclass Subclass",
|
||||
"text": "Do you want to add this subclass as your multiclass subclass?"
|
||||
}
|
||||
},
|
||||
"cannotRemoveCoreExperience": "You are using Levelup Auto. You cannot remove an experience given to you by the rule progression."
|
||||
},
|
||||
"Companion": {
|
||||
"FIELDS": {
|
||||
|
|
@ -880,7 +881,7 @@
|
|||
"Gold": {
|
||||
"title": "Gold",
|
||||
"coins": "Coins",
|
||||
"handfulls": "Handfulls",
|
||||
"handfuls": "Handfuls",
|
||||
"bags": "Bags",
|
||||
"chests": "Chests"
|
||||
},
|
||||
|
|
@ -2115,6 +2116,10 @@
|
|||
"resourceScrollTexts": {
|
||||
"label": "Show Resource Change Scrolltexts",
|
||||
"hint": "When a character is damaged, uses armor etc, a scrolling text will briefly appear by the token to signify this."
|
||||
},
|
||||
"playerCanEditSheet": {
|
||||
"label": "Players Can Manually Edit Character Settings",
|
||||
"hint": "Players are allowed to access the manual Character Settings and change their statistics beyond the rules."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -2138,7 +2143,7 @@
|
|||
"title": "Currency Overrides",
|
||||
"currencyName": "Currency Name",
|
||||
"coinName": "Coin Name",
|
||||
"handfullName": "Handfull Name",
|
||||
"handfulName": "Handful Name",
|
||||
"bagName": "Bag Name",
|
||||
"chestName": "Chest Name"
|
||||
},
|
||||
|
|
@ -2210,10 +2215,6 @@
|
|||
"actionTokens": {
|
||||
"enabled": { "label": "Enabled" },
|
||||
"tokens": { "label": "Tokens" }
|
||||
},
|
||||
"useCoins": {
|
||||
"label": "Use Coins",
|
||||
"hint": "test"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -2360,8 +2361,10 @@
|
|||
"diceIsRerolled": "The dice has been rerolled (x{times})",
|
||||
"pendingSaves": "Pending Reaction Rolls",
|
||||
"openSheetSettings": "Open Settings",
|
||||
"compendiumBrowser": "Compendium Browser",
|
||||
"rulesOn": "Rules On",
|
||||
"rulesOff": "Rules Off"
|
||||
"rulesOff": "Rules Off",
|
||||
"remainingUses": "Uses refresh on {type}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { abilities } from '../../config/actorConfig.mjs';
|
||||
import { burden } from '../../config/generalConfig.mjs';
|
||||
import { createEmbeddedItemWithEffects } from '../../helpers/utils.mjs';
|
||||
import { ItemBrowser } from '../ui/itemBrowser.mjs';
|
||||
import { createEmbeddedItemsWithEffects, createEmbeddedItemWithEffects } from '../../helpers/utils.mjs';
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
|
||||
|
|
@ -20,8 +21,8 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
class: this.character.system.class?.value ?? {},
|
||||
subclass: this.character.system.class?.subclass ?? {},
|
||||
experiences: {
|
||||
[foundry.utils.randomID()]: { name: '', value: 2 },
|
||||
[foundry.utils.randomID()]: { name: '', value: 2 }
|
||||
[foundry.utils.randomID()]: { name: '', value: 2, core: true },
|
||||
[foundry.utils.randomID()]: { name: '', value: 2, core: true }
|
||||
},
|
||||
domainCards: {
|
||||
[foundry.utils.randomID()]: {},
|
||||
|
|
@ -42,6 +43,8 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
};
|
||||
|
||||
this._dragDrop = this._createDragDropHandlers();
|
||||
|
||||
this.itemBrowser = null;
|
||||
}
|
||||
|
||||
get title() {
|
||||
|
|
@ -370,13 +373,18 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
);
|
||||
context.armor = {
|
||||
...this.equipment.armor,
|
||||
suggestion: { ...suggestions.armor, taken: suggestions.armor?.uuid === this.equipment.armor?.uuid },
|
||||
suggestion: {
|
||||
...suggestions.armor,
|
||||
uuid: suggestions.armor?.uuid,
|
||||
taken: suggestions.armor?.uuid === this.equipment.armor?.uuid
|
||||
},
|
||||
compendium: 'armors'
|
||||
};
|
||||
context.primaryWeapon = {
|
||||
...this.equipment.primaryWeapon,
|
||||
suggestion: {
|
||||
...suggestions.primaryWeapon,
|
||||
uuid: suggestions.primaryWeapon?.uuid,
|
||||
taken: suggestions.primaryWeapon?.uuid === this.equipment.primaryWeapon?.uuid
|
||||
},
|
||||
compendium: 'weapons'
|
||||
|
|
@ -385,6 +393,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
...this.equipment.secondaryWeapon,
|
||||
suggestion: {
|
||||
...suggestions.secondaryWeapon,
|
||||
uuid: suggestions.secondaryWeapon?.uuid,
|
||||
taken: suggestions.secondaryWeapon?.uuid === this.equipment.secondaryWeapon?.uuid
|
||||
},
|
||||
disabled: this.equipment.primaryWeapon?.system?.burden === burden.twoHanded.value,
|
||||
|
|
@ -485,8 +494,24 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
});
|
||||
}
|
||||
|
||||
static async viewCompendium(_, target) {
|
||||
(await game.packs.get(`daggerheart.${target.dataset.compendium}`))?.render(true);
|
||||
static async viewCompendium(event, target) {
|
||||
const type = target.dataset.compendium ?? target.dataset.type;
|
||||
|
||||
const presets = {
|
||||
compendium: 'daggerheart',
|
||||
folder: type,
|
||||
render: {
|
||||
noFolder: true
|
||||
}
|
||||
};
|
||||
|
||||
if (type == 'domains')
|
||||
presets.filter = {
|
||||
'level.max': { key: 'level.max', value: 1 },
|
||||
'system.domain': { key: 'system.domain', value: this.setup.class?.system.domains ?? null }
|
||||
};
|
||||
|
||||
return (this.itemBrowser = await new ItemBrowser({ presets }).render({ force: true }));
|
||||
}
|
||||
|
||||
static async viewItem(_, target) {
|
||||
|
|
@ -555,13 +580,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
await createEmbeddedItemWithEffects(this.character, this.setup.community);
|
||||
await createEmbeddedItemWithEffects(this.character, this.setup.class);
|
||||
await createEmbeddedItemWithEffects(this.character, this.setup.subclass);
|
||||
await this.character.createEmbeddedDocuments(
|
||||
'Item',
|
||||
Object.values(this.setup.domainCards).map(x => ({
|
||||
...x,
|
||||
effects: x.effects?.map(effect => effect.toObject())
|
||||
}))
|
||||
);
|
||||
await createEmbeddedItemsWithEffects(this.character, Object.values(this.setup.domainCards));
|
||||
|
||||
if (this.equipment.armor.uuid)
|
||||
await createEmbeddedItemWithEffects(this.character, this.equipment.armor, {
|
||||
|
|
@ -583,23 +602,28 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
if (this.equipment.inventory.choiceB.uuid)
|
||||
await createEmbeddedItemWithEffects(this.character, this.equipment.inventory.choiceB);
|
||||
|
||||
await this.character.createEmbeddedDocuments(
|
||||
'Item',
|
||||
this.setup.class.system.inventory.take
|
||||
.filter(x => x)
|
||||
.map(x => ({
|
||||
...x,
|
||||
effects: x.effects?.map(effect => effect.toObject())
|
||||
}))
|
||||
await createEmbeddedItemsWithEffects(
|
||||
this.character,
|
||||
this.setup.class.system.inventory.take.filter(x => x)
|
||||
);
|
||||
|
||||
await this.character.update({
|
||||
system: {
|
||||
traits: this.setup.traits,
|
||||
experiences: this.setup.experiences
|
||||
}
|
||||
});
|
||||
await this.character.update(
|
||||
{
|
||||
system: {
|
||||
traits: this.setup.traits,
|
||||
experiences: {
|
||||
...this.setup.experiences,
|
||||
...Object.keys(this.character.system.experiences).reduce((acc, key) => {
|
||||
acc[`-=${key}`] = null;
|
||||
return acc;
|
||||
}, {})
|
||||
}
|
||||
}
|
||||
},
|
||||
{ overwrite: true }
|
||||
);
|
||||
|
||||
if (this.itemBrowser) this.itemBrowser.close();
|
||||
this.close();
|
||||
}
|
||||
|
||||
|
|
@ -690,6 +714,10 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
return;
|
||||
}
|
||||
|
||||
if (item.system.burden === CONFIG.DH.GENERAL.burden.twoHanded.value) {
|
||||
this.equipment.secondaryWeapon = {};
|
||||
}
|
||||
|
||||
this.equipment.primaryWeapon = { ...item, uuid: item.uuid };
|
||||
} else if (item.type === 'weapon' && event.target.closest('.secondary-weapon-card')) {
|
||||
if (this.equipment.primaryWeapon?.system?.burden === burden.twoHanded.value) {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application
|
|||
};
|
||||
|
||||
get title() {
|
||||
return game.i18n.localize(`DAGGERHEART.EFFECTS.ApplyLocations.${this.config.hasHealing ? 'healing' : 'damage'}Roll.name`);
|
||||
return game.i18n.localize(
|
||||
`DAGGERHEART.EFFECTS.ApplyLocations.${this.config.hasHealing ? 'healing' : 'damage'}Roll.name`
|
||||
);
|
||||
}
|
||||
|
||||
async _prepareContext(_options) {
|
||||
|
|
|
|||
|
|
@ -94,7 +94,10 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
const actionItems = this.actor.items.reduce((acc, x) => {
|
||||
if (x.system.actions) {
|
||||
const recoverable = x.system.actions.reduce((acc, action) => {
|
||||
if (action.uses.recovery && (action.uses.recovery === 'shortRest') === this.shortrest) {
|
||||
if (
|
||||
(action.uses.recovery && (action.uses.recovery === 'longRest') === !this.shortrest) ||
|
||||
action.uses.recovery === 'shortRest'
|
||||
) {
|
||||
acc.push({
|
||||
title: x.name,
|
||||
name: action.name,
|
||||
|
|
@ -116,7 +119,8 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
if (
|
||||
x.system.resource &&
|
||||
x.system.resource.type &&
|
||||
(x.system.resource.recovery === 'shortRest') === this.shortrest
|
||||
((x.system.resource.recovery === 'longRest') === !this.shortrest ||
|
||||
x.system.resource.recovery === 'shortRest')
|
||||
) {
|
||||
acc.push({
|
||||
title: game.i18n.localize(`TYPES.Item.${x.type}`),
|
||||
|
|
@ -226,14 +230,18 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
) {
|
||||
for (var data of this.refreshables.actionItems) {
|
||||
const action = await foundry.utils.fromUuid(data.uuid);
|
||||
await action.parent.parent.update({ [`system.actions.${action.id}.uses.value`]: action.uses.max ?? 1 });
|
||||
await action.parent.parent.update({ [`system.actions.${action.id}.uses.value`]: 0 });
|
||||
}
|
||||
|
||||
for (var data of this.refreshables.resourceItems) {
|
||||
const feature = await foundry.utils.fromUuid(data.uuid);
|
||||
const increasing =
|
||||
feature.system.resource.progression === CONFIG.DH.ITEM.itemResourceProgression.increasing.id;
|
||||
const resetValue = increasing ? 0 : (feature.system.resource.max ?? 0);
|
||||
const resetValue = increasing
|
||||
? 0
|
||||
: feature.system.resource.max
|
||||
? Roll.replaceFormulaData(feature.system.resource.max, this.actor)
|
||||
: 0;
|
||||
await feature.update({ 'system.resource.value': resetValue });
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ export default class DhCharacterLevelUp extends LevelUpBase {
|
|||
const experience = Object.keys(this.actor.system.experiences).find(
|
||||
x => x === data
|
||||
);
|
||||
return this.actor.system.experiences[experience]?.description ?? '';
|
||||
return this.actor.system.experiences[experience]?.name ?? '';
|
||||
});
|
||||
advancement[choiceKey].push({ data: data, value: checkbox.value });
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { abilities, subclassFeatureLabels } from '../../config/actorConfig.mjs';
|
||||
import { getDeleteKeys, tagifyElement } from '../../helpers/utils.mjs';
|
||||
import { ItemBrowser } from '../ui/itemBrowser.mjs';
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
|
||||
|
|
@ -11,6 +12,8 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
|
|||
|
||||
this._dragDrop = this._createDragDropHandlers();
|
||||
this.tabGroups.primary = 'advancements';
|
||||
|
||||
this.itemBrowser = null;
|
||||
}
|
||||
|
||||
get title() {
|
||||
|
|
@ -44,10 +47,12 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
|
|||
|
||||
static PARTS = {
|
||||
tabs: { template: 'systems/daggerheart/templates/levelup/tabs/tab-navigation.hbs' },
|
||||
advancements: { template: 'systems/daggerheart/templates/levelup/tabs/advancements.hbs' },
|
||||
advancements: {
|
||||
template: 'systems/daggerheart/templates/levelup/tabs/advancements.hbs'
|
||||
},
|
||||
selections: {
|
||||
template: 'systems/daggerheart/templates/levelup/tabs/selections.hbs',
|
||||
scrollable: ['.selections']
|
||||
scrollable: ['.levelup-selections-container']
|
||||
},
|
||||
summary: { template: 'systems/daggerheart/templates/levelup/tabs/summary.hbs' },
|
||||
footer: { template: 'systems/daggerheart/templates/levelup/tabs/footer.hbs' }
|
||||
|
|
@ -531,8 +536,30 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
|
|||
this.render();
|
||||
}
|
||||
|
||||
static async viewCompendium(_, button) {
|
||||
(await game.packs.get(`daggerheart.${button.dataset.compendium}`))?.render(true);
|
||||
static async viewCompendium(event, target) {
|
||||
const type = target.dataset.compendium ?? target.dataset.type;
|
||||
|
||||
const presets = {
|
||||
compendium: 'daggerheart',
|
||||
folder: type,
|
||||
render: {
|
||||
noFolder: true
|
||||
}
|
||||
};
|
||||
|
||||
if (type == 'domains') {
|
||||
const domains = this.actor.system.domains,
|
||||
multiclassDomain = this.levelup.classUpgradeChoices?.multiclass?.domain;
|
||||
if (multiclassDomain) {
|
||||
if (!domains.includes(x => x === multiclassDomain)) domains.push(multiclassDomain);
|
||||
}
|
||||
presets.filter = {
|
||||
'level.max': { key: 'level.max', value: this.levelup.currentLevel },
|
||||
'system.domain': { key: 'system.domain', value: domains }
|
||||
};
|
||||
}
|
||||
|
||||
return (this.itemBrowser = await new ItemBrowser({ presets }).render({ force: true }));
|
||||
}
|
||||
|
||||
static async selectPreview(_, button) {
|
||||
|
|
@ -633,6 +660,7 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
|
|||
}, {});
|
||||
|
||||
await this.actor.levelUp(levelupData);
|
||||
if (this.itemBrowser) this.itemBrowser.close();
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
export { default as DhAppearanceSettings } from './appearanceSettings.mjs';
|
||||
export { default as DhAutomationSettings } from './automationSettings.mjs';
|
||||
export { default as DhHomebrewSettings } from './homebrewSettings.mjs';
|
||||
export { default as DhRangeMeasurementSettings } from './rangeMeasurementSettings.mjs';
|
||||
export { default as DhVariantRuleSettings } from './variantRuleSettings.mjs';
|
||||
|
|
|
|||
|
|
@ -1,66 +0,0 @@
|
|||
import { DhRangeMeasurement } from '../../data/settings/_module.mjs';
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
|
||||
export default class DhRangeMeasurementSettings extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
constructor() {
|
||||
super({});
|
||||
|
||||
this.settings = new DhRangeMeasurement(
|
||||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.RangeMeasurement).toObject()
|
||||
);
|
||||
}
|
||||
|
||||
get title() {
|
||||
return game.i18n.localize('DAGGERHEART.SETTINGS.Menu.title');
|
||||
}
|
||||
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
id: 'daggerheart-automation-settings',
|
||||
classes: ['daggerheart', 'dialog', 'dh-style', 'setting'],
|
||||
position: { width: '600', height: 'auto' },
|
||||
window: {
|
||||
icon: 'fa-solid fa-gears'
|
||||
},
|
||||
actions: {
|
||||
reset: this.reset,
|
||||
save: this.save
|
||||
},
|
||||
form: { handler: this.updateData, submitOnChange: true }
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: 'systems/daggerheart/templates/settings/range-measurement-settings.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.settingFields = this.settings;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static async updateData(event, element, formData) {
|
||||
const updatedSettings = foundry.utils.expandObject(formData.object);
|
||||
|
||||
await this.settings.updateSource(updatedSettings);
|
||||
this.render();
|
||||
}
|
||||
|
||||
static async reset() {
|
||||
this.settings = new DhRangeMeasurement();
|
||||
this.render();
|
||||
}
|
||||
|
||||
static async save() {
|
||||
await game.settings.set(
|
||||
CONFIG.DH.id,
|
||||
CONFIG.DH.SETTINGS.gameSettings.RangeMeasurement,
|
||||
this.settings.toObject()
|
||||
);
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import DhCharacterlevelUp from '../../levelup/characterLevelup.mjs';
|
|||
import DhCharacterCreation from '../../characterCreation/characterCreation.mjs';
|
||||
import FilterMenu from '../../ux/filter-menu.mjs';
|
||||
import { getDocFromElement, getDocFromElementSync } from '../../../helpers/utils.mjs';
|
||||
import { ItemBrowser } from '../../ui/itemBrowser.mjs';
|
||||
|
||||
/**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */
|
||||
|
||||
|
|
@ -25,7 +26,8 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
toggleEquipItem: CharacterSheet.#toggleEquipItem,
|
||||
toggleResourceDice: CharacterSheet.#toggleResourceDice,
|
||||
handleResourceDice: CharacterSheet.#handleResourceDice,
|
||||
useDowntime: this.useDowntime
|
||||
useDowntime: this.useDowntime,
|
||||
tempBrowser: CharacterSheet.#tempBrowser
|
||||
},
|
||||
window: {
|
||||
resizable: true
|
||||
|
|
@ -156,7 +158,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
currency: {
|
||||
title: game.i18n.localize('DAGGERHEART.CONFIG.Gold.title'),
|
||||
coins: game.i18n.localize('DAGGERHEART.CONFIG.Gold.coins'),
|
||||
handfulls: game.i18n.localize('DAGGERHEART.CONFIG.Gold.handfulls'),
|
||||
handfuls: game.i18n.localize('DAGGERHEART.CONFIG.Gold.handfuls'),
|
||||
bags: game.i18n.localize('DAGGERHEART.CONFIG.Gold.bags'),
|
||||
chests: game.i18n.localize('DAGGERHEART.CONFIG.Gold.chests')
|
||||
}
|
||||
|
|
@ -178,6 +180,13 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
async _preparePartContext(partId, context, options) {
|
||||
context = await super._preparePartContext(partId, context, options);
|
||||
switch (partId) {
|
||||
case 'header':
|
||||
const { playerCanEditSheet, levelupAuto } = game.settings.get(
|
||||
CONFIG.DH.id,
|
||||
CONFIG.DH.SETTINGS.gameSettings.Automation
|
||||
);
|
||||
context.showSettings = game.user.isGM || !levelupAuto || (levelupAuto && playerCanEditSheet);
|
||||
break;
|
||||
case 'loadout':
|
||||
await this._prepareLoadoutContext(context, options);
|
||||
break;
|
||||
|
|
@ -188,6 +197,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
await this._prepareBiographyContext(context, options);
|
||||
break;
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -592,7 +602,16 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
*/
|
||||
static async #openPack(_event, button) {
|
||||
const { key } = button.dataset;
|
||||
game.packs.get(key)?.render(true);
|
||||
|
||||
const presets = {
|
||||
compendium: 'daggerheart',
|
||||
folder: key,
|
||||
render: {
|
||||
noFolder: true
|
||||
}
|
||||
};
|
||||
|
||||
return new ItemBrowser({ presets }).render({ force: true });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -707,6 +726,13 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Temp
|
||||
*/
|
||||
static async #tempBrowser(_, target) {
|
||||
new ItemBrowser().render({ force: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the roll values of resource dice.
|
||||
* @type {ApplicationClickAction}
|
||||
|
|
|
|||
|
|
@ -101,8 +101,7 @@ export default class DhpEnvironment extends DHBaseActorSheet {
|
|||
const item = event.currentTarget.closest('.inventory-item');
|
||||
|
||||
if (item) {
|
||||
const adversary = game.actors.find(x => x.type === 'adversary' && x.id === item.dataset.itemId);
|
||||
const adversaryData = { type: 'Actor', uuid: adversary.uuid };
|
||||
const adversaryData = { type: 'Actor', uuid: item.dataset.itemUuid };
|
||||
event.dataTransfer.setData('text/plain', JSON.stringify(adversaryData));
|
||||
event.dataTransfer.setDragImage(item, 60, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
const { HandlebarsApplicationMixin } = foundry.applications.api;
|
||||
import { getDocFromElement, getDocFromElementSync, tagifyElement } from '../../../helpers/utils.mjs';
|
||||
import { ItemBrowser } from '../../ui/itemBrowser.mjs';
|
||||
|
||||
/**
|
||||
* @typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction
|
||||
|
|
@ -82,7 +83,9 @@ export default function DHApplicationMixin(Base) {
|
|||
toChat: DHSheetV2.#toChat,
|
||||
useItem: DHSheetV2.#useItem,
|
||||
toggleEffect: DHSheetV2.#toggleEffect,
|
||||
toggleExtended: DHSheetV2.#toggleExtended
|
||||
toggleExtended: DHSheetV2.#toggleExtended,
|
||||
addNewItem: DHSheetV2.#addNewItem,
|
||||
browseItem: DHSheetV2.#browseItem
|
||||
},
|
||||
contextMenus: [
|
||||
{
|
||||
|
|
@ -342,11 +345,25 @@ export default function DHApplicationMixin(Base) {
|
|||
icon: 'fa-solid fa-burst',
|
||||
condition: target => {
|
||||
const doc = getDocFromElementSync(target);
|
||||
return doc && !(doc.type === 'domainCard' && doc.system.inVault);
|
||||
return doc?.system?.attack?.damage.parts.length || doc?.damage?.parts.length;
|
||||
},
|
||||
callback: async (target, event) => (await getDocFromElement(target)).use(event)
|
||||
callback: async (target, event) => {
|
||||
const doc = await getDocFromElement(target),
|
||||
action = doc?.system?.attack ?? doc;
|
||||
return action && action.use(event, { byPassRoll: true });
|
||||
}
|
||||
});
|
||||
|
||||
options.unshift({
|
||||
name: 'DAGGERHEART.APPLICATIONS.ContextMenu.useItem',
|
||||
icon: 'fa-solid fa-burst',
|
||||
condition: target => {
|
||||
const doc = getDocFromElementSync(target);
|
||||
return doc && !(doc.type === 'domainCard' && doc.system.inVault);
|
||||
},
|
||||
callback: async (target, event) => (await getDocFromElement(target)).use(event)
|
||||
});
|
||||
|
||||
if (toChat)
|
||||
options.push({
|
||||
name: 'DAGGERHEART.APPLICATIONS.ContextMenu.sendToChat',
|
||||
|
|
@ -423,6 +440,68 @@ export default function DHApplicationMixin(Base) {
|
|||
/* Application Clicks Actions */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
static async #addNewItem(event, target) {
|
||||
const { type } = target.dataset;
|
||||
|
||||
const createChoice = await foundry.applications.api.DialogV2.wait({
|
||||
classes: ['dh-style', 'two-big-buttons'],
|
||||
buttons: [
|
||||
{
|
||||
action: 'create',
|
||||
label: 'Create Item',
|
||||
icon: 'fa-solid fa-plus'
|
||||
},
|
||||
{
|
||||
action: 'browse',
|
||||
label: 'Browse Compendium',
|
||||
icon: 'fa-solid fa-book'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
if (!createChoice) return;
|
||||
|
||||
if (createChoice === 'browse') return DHSheetV2.#browseItem.call(this, event, target);
|
||||
else return DHSheetV2.#createDoc.call(this, event, target);
|
||||
}
|
||||
|
||||
static async #browseItem(event, target) {
|
||||
const type = target.dataset.compendium ?? target.dataset.type;
|
||||
|
||||
const presets = {};
|
||||
|
||||
switch (type) {
|
||||
case 'loot':
|
||||
case 'consumable':
|
||||
case 'armor':
|
||||
case 'weapon':
|
||||
presets.compendium = 'daggerheart';
|
||||
presets.folder = 'equipments';
|
||||
presets.render = {
|
||||
noFolder: true
|
||||
};
|
||||
presets.filter = {
|
||||
type: { key: 'type', value: type, forced: true }
|
||||
};
|
||||
break;
|
||||
case 'domainCard':
|
||||
presets.compendium = 'daggerheart';
|
||||
presets.folder = 'domains';
|
||||
presets.render = {
|
||||
noFolder: true
|
||||
};
|
||||
presets.filter = {
|
||||
'level.max': { key: 'level.max', value: this.document.system.levelData.level.current },
|
||||
'system.domain': { key: 'system.domain', value: this.document.system.domains }
|
||||
};
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
return new ItemBrowser({ presets }).render({ force: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an embedded document.
|
||||
* @type {ApplicationClickAction}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
|||
},
|
||||
actions: {
|
||||
openSettings: DHBaseActorSheet.#openSettings,
|
||||
sendExpToChat: DHBaseActorSheet.#sendExpToChat
|
||||
sendExpToChat: DHBaseActorSheet.#sendExpToChat,
|
||||
increaseActionUses: event => DHBaseActorSheet.#modifyActionUses(event, true)
|
||||
},
|
||||
contextMenus: [
|
||||
{
|
||||
|
|
@ -70,6 +71,15 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
|||
return context;
|
||||
}
|
||||
|
||||
/**@inheritdoc */
|
||||
_attachPartListeners(partId, htmlElement, options) {
|
||||
super._attachPartListeners(partId, htmlElement, options);
|
||||
|
||||
htmlElement.querySelectorAll('.item-button .action-uses-button').forEach(element => {
|
||||
element.addEventListener('contextmenu', DHBaseActorSheet.#modifyActionUses);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare render context for the Effect part.
|
||||
* @param {ApplicationRenderContext} context
|
||||
|
|
@ -154,6 +164,19 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
|||
cls.create(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static async #modifyActionUses(event, increase) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
const actionId = event.target.dataset.itemUuid;
|
||||
const action = await foundry.utils.fromUuid(actionId);
|
||||
|
||||
const newValue = (action.uses.value ?? 0) + (increase ? 1 : -1);
|
||||
await action.update({ 'uses.value': Math.min(Math.max(newValue, 0), action.uses.max ?? 0) });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Application Drag/Drop */
|
||||
/* -------------------------------------------- */
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import DHBaseItemSheet from '../api/base-item.mjs';
|
|||
export default class FeatureSheet extends DHBaseItemSheet {
|
||||
/** @inheritDoc */
|
||||
static DEFAULT_OPTIONS = {
|
||||
id: 'daggerheart-feature',
|
||||
classes: ['feature'],
|
||||
actions: {}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export default class SubclassSheet extends DHBaseItemSheet {
|
|||
static DEFAULT_OPTIONS = {
|
||||
classes: ['subclass'],
|
||||
position: { width: 600 },
|
||||
window: { resizable: false }
|
||||
window: { resizable: true }
|
||||
};
|
||||
|
||||
/**@override */
|
||||
|
|
|
|||
|
|
@ -159,11 +159,12 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
event.stopPropagation();
|
||||
|
||||
const item = await foundry.utils.fromUuid(message.system.origin);
|
||||
const action = item.system.attack?.id === event.currentTarget.id ? item.system.attack : item.system.actions.get(event.currentTarget.id);
|
||||
if(event.currentTarget.dataset.directDamage)
|
||||
action.use(event, { byPassRoll: true })
|
||||
else
|
||||
action.use(event);
|
||||
const action =
|
||||
item.system.attack?.id === event.currentTarget.id
|
||||
? item.system.attack
|
||||
: item.system.actions.get(event.currentTarget.id);
|
||||
if (event.currentTarget.dataset.directDamage) action.use(event, { byPassRoll: true });
|
||||
else action.use(event);
|
||||
}
|
||||
|
||||
async actionUseButton(event, message) {
|
||||
|
|
|
|||
|
|
@ -88,7 +88,10 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C
|
|||
}
|
||||
}
|
||||
|
||||
await this.viewed.update({ turn: this.viewed.turn === toggleTurn ? null : toggleTurn });
|
||||
await this.viewed.update({
|
||||
turn: this.viewed.turn === toggleTurn ? null : toggleTurn,
|
||||
round: this.viewed.round + 1
|
||||
});
|
||||
await combatant.update(update);
|
||||
}
|
||||
|
||||
|
|
|
|||
425
module/applications/ui/itemBrowser.mjs
Normal file
425
module/applications/ui/itemBrowser.mjs
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
|
||||
/**
|
||||
* A UI element which displays the Users defined for this world.
|
||||
* Currently active users are always displayed, while inactive users can be displayed on toggle.
|
||||
*
|
||||
* @extends ApplicationV2
|
||||
* @mixes HandlebarsApplication
|
||||
*/
|
||||
|
||||
export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
constructor(options = {}) {
|
||||
super(options);
|
||||
this.items = [];
|
||||
this.fieldFilter = [];
|
||||
this.selectedMenu = { path: [], data: null };
|
||||
this.config = CONFIG.DH.ITEMBROWSER.compendiumConfig;
|
||||
this.presets = options.presets;
|
||||
|
||||
if(this.presets?.compendium && this.presets?.folder)
|
||||
ItemBrowser.selectFolder.call(this, null, null, this.presets.compendium, this.presets.folder);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
static DEFAULT_OPTIONS = {
|
||||
id: 'itemBrowser',
|
||||
classes: ['daggerheart', 'dh-style', 'dialog', 'compendium-browser'],
|
||||
tag: 'div',
|
||||
// title: 'Item Browser',
|
||||
window: {
|
||||
frame: true,
|
||||
title: 'Compendium Browser',
|
||||
icon: 'fa-solid fa-book-atlas',
|
||||
positioned: true,
|
||||
resizable: true
|
||||
},
|
||||
actions: {
|
||||
selectFolder: this.selectFolder,
|
||||
expandContent: this.expandContent,
|
||||
resetFilters: this.resetFilters,
|
||||
sortList: this.sortList
|
||||
},
|
||||
position: {
|
||||
top: 330,
|
||||
left: 120,
|
||||
width: 800,
|
||||
height: 600
|
||||
}
|
||||
};
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sidebar: {
|
||||
template: 'systems/daggerheart/templates/ui/itemBrowser/sidebar.hbs'
|
||||
},
|
||||
list: {
|
||||
template: 'systems/daggerheart/templates/ui/itemBrowser/itemBrowser.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Filter Tracking */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The currently active search filter.
|
||||
* @type {foundry.applications.ux.SearchFilter}
|
||||
*/
|
||||
#search = {};
|
||||
|
||||
#input = {};
|
||||
|
||||
/**
|
||||
* Tracks which item IDs are currently displayed, organized by filter type and section.
|
||||
* @type {{
|
||||
* inventory: {
|
||||
* search: Set<string>,
|
||||
* input: Set<string>
|
||||
* }
|
||||
* }}
|
||||
*/
|
||||
#filteredItems = {
|
||||
browser: {
|
||||
search: new Set(),
|
||||
input: new Set()
|
||||
}
|
||||
};
|
||||
|
||||
/** @inheritDoc */
|
||||
async _preFirstRender(context, options) {
|
||||
if(context.presets?.render?.noFolder || context.presets?.render?.lite)
|
||||
options.position.width = 600;
|
||||
|
||||
await super._preFirstRender(context, options);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
async _preRender(context, options) {
|
||||
|
||||
if(context.presets?.render?.noFolder || context.presets?.render?.lite)
|
||||
options.parts.splice(options.parts.indexOf('sidebar'), 1);
|
||||
|
||||
await super._preRender(context, options);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
async _onRender(context, options) {
|
||||
await super._onRender(context, options);
|
||||
|
||||
this._createSearchFilter();
|
||||
this._createFilterInputs();
|
||||
this._createDragProcess();
|
||||
|
||||
if(context.presets?.render?.lite)
|
||||
this.element.classList.add('lite');
|
||||
|
||||
if(context.presets?.render?.noFolder)
|
||||
this.element.classList.add('no-folder');
|
||||
|
||||
if(context.presets?.render?.noFilter)
|
||||
this.element.classList.add('no-filter');
|
||||
|
||||
if(this.presets?.filter) {
|
||||
Object.entries(this.presets.filter).forEach(([k,v]) => this.fieldFilter.find(c => c.name === k).value = v.value);
|
||||
await this._onInputFilterBrowser();
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Rendering */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
async _prepareContext(options) {
|
||||
const context = await super._prepareContext(options);
|
||||
context.compendiums = this.getCompendiumFolders(foundry.utils.deepClone(this.config));
|
||||
// context.pathTitle = this.pathTile;
|
||||
context.menu = this.selectedMenu;
|
||||
context.formatLabel = this.formatLabel;
|
||||
context.formatChoices = this.formatChoices;
|
||||
context.fieldFilter = this.fieldFilter = this._createFieldFilter();
|
||||
context.items = this.items;
|
||||
context.presets = this.presets;
|
||||
return context;
|
||||
}
|
||||
|
||||
getCompendiumFolders(config, parent = null, depth = 0) {
|
||||
let folders = [];
|
||||
Object.values(config).forEach(c => {
|
||||
const folder = {
|
||||
id: c.id,
|
||||
label: c.label,
|
||||
selected: (!parent || parent.selected) && this.selectedMenu.path[depth] === c.id
|
||||
};
|
||||
folder.folders = c.folders
|
||||
? ItemBrowser.sortBy(this.getCompendiumFolders(c.folders, folder, depth + 2), 'label')
|
||||
: [];
|
||||
folders.push(folder);
|
||||
});
|
||||
|
||||
return folders;
|
||||
}
|
||||
|
||||
static async selectFolder(_, target, compend, folder) {
|
||||
const config = foundry.utils.deepClone(this.config),
|
||||
compendium = compend ?? target.closest('[data-compendium-id]').dataset.compendiumId,
|
||||
folderId = folder ?? target.dataset.folderId,
|
||||
folderPath = `${compendium}.folders.${folderId}`,
|
||||
folderData = foundry.utils.getProperty(config, folderPath);
|
||||
|
||||
this.selectedMenu = {
|
||||
path: folderPath.split('.'),
|
||||
data: {
|
||||
...folderData,
|
||||
columns: ItemBrowser.getFolderConfig(folderData)
|
||||
}
|
||||
};
|
||||
|
||||
let items = [];
|
||||
for (const key of folderData.keys) {
|
||||
const comp = game.packs.get(`${compendium}.${key}`);
|
||||
if (!comp) return;
|
||||
items = items.concat(await comp.getDocuments({ type__in: folderData.type }));
|
||||
}
|
||||
|
||||
this.items = ItemBrowser.sortBy(items, 'name');
|
||||
this.render({ force: true });
|
||||
}
|
||||
|
||||
static expandContent(_, target) {
|
||||
const parent = target.parentElement;
|
||||
parent.classList.toggle('expanded');
|
||||
}
|
||||
|
||||
static sortBy(data, property) {
|
||||
return data.sort((a, b) => (a[property] > b[property] ? 1 : -1));
|
||||
}
|
||||
|
||||
formatLabel(item, field) {
|
||||
const property = foundry.utils.getProperty(item, field.key);
|
||||
if (typeof field.format !== 'function') return property ?? '-';
|
||||
return field.format(property);
|
||||
}
|
||||
|
||||
formatChoices(data) {
|
||||
if (!data.field.choices) return null;
|
||||
const config = {
|
||||
choices: data.field.choices
|
||||
};
|
||||
foundry.data.fields.StringField._prepareChoiceConfig(config);
|
||||
return config.options.filter(
|
||||
c => data.filtered.includes(c.value) || data.filtered.includes(c.label.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
_createFieldFilter() {
|
||||
const filters = ItemBrowser.getFolderConfig(this.selectedMenu.data, 'filters');
|
||||
filters.forEach(f => {
|
||||
if (typeof f.field === 'string') f.field = foundry.utils.getProperty(game, f.field);
|
||||
else if (typeof f.choices === 'function') {
|
||||
f.choices = f.choices();
|
||||
}
|
||||
f.name ??= f.key;
|
||||
f.value = this.presets?.filter?.[f.name]?.value ?? null;
|
||||
});
|
||||
return filters;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Search Inputs */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Create and initialize search filter instances for the inventory and loadout sections.
|
||||
*
|
||||
* Sets up two {@link foundry.applications.ux.SearchFilter} instances:
|
||||
* - One for the inventory, which filters items in the inventory grid.
|
||||
* - One for the loadout, which filters items in the loadout/card grid.
|
||||
* @private
|
||||
*/
|
||||
_createSearchFilter() {
|
||||
//Filters could be a application option if needed
|
||||
const filters = [
|
||||
{
|
||||
key: 'browser',
|
||||
input: 'input[type="search"].search-input',
|
||||
content: '[data-application-part="list"] .item-list',
|
||||
callback: this._onSearchFilterBrowser.bind(this)
|
||||
}
|
||||
];
|
||||
|
||||
for (const { key, input, content, callback } of filters) {
|
||||
const filter = new foundry.applications.ux.SearchFilter({
|
||||
inputSelector: input,
|
||||
contentSelector: content,
|
||||
callback
|
||||
});
|
||||
filter.bind(this.element);
|
||||
this.#search[key] = filter;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Filter Inputs */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
_createFilterInputs() {
|
||||
const inputs = [
|
||||
{
|
||||
key: 'browser',
|
||||
container: '[data-application-part="list"] .filter-content .wrapper',
|
||||
content: '[data-application-part="list"] .item-list',
|
||||
callback: this._onInputFilterBrowser.bind(this)
|
||||
}
|
||||
];
|
||||
|
||||
inputs.forEach(m => {
|
||||
const container = this.element.querySelector(m.container);
|
||||
if (!container) return (this.#input[m.key] = {});
|
||||
const inputs = container.querySelectorAll('input, select');
|
||||
inputs.forEach(input => {
|
||||
input.addEventListener('change', this._onInputFilterBrowser.bind(this));
|
||||
});
|
||||
this.#filteredItems[m.key].input = new Set(this.items.map(i => i.id));
|
||||
this.#input[m.key] = inputs;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle invetory items search and filtering.
|
||||
* @param {KeyboardEvent} event The keyboard input event.
|
||||
* @param {string} query The input search string.
|
||||
* @param {RegExp} rgx The regular expression query that should be matched against.
|
||||
* @param {HTMLElement} html The container to filter items from.
|
||||
* @protected
|
||||
*/
|
||||
async _onSearchFilterBrowser(event, query, rgx, html) {
|
||||
this.#filteredItems.browser.search.clear();
|
||||
|
||||
for (const li of html.querySelectorAll('.item-container')) {
|
||||
const itemUUID = li.dataset.itemUuid,
|
||||
item = this.items.find(i => i.uuid === itemUUID);
|
||||
const matchesSearch = !query || foundry.applications.ux.SearchFilter.testQuery(rgx, item.name);
|
||||
if (matchesSearch) this.#filteredItems.browser.search.add(item.id);
|
||||
const { input } = this.#filteredItems.browser;
|
||||
li.hidden = !(input.has(item.id) && matchesSearch);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback when filters change
|
||||
* @param {PointerEvent} event
|
||||
* @param {HTMLElement} html
|
||||
*/
|
||||
async _onInputFilterBrowser(event) {
|
||||
this.#filteredItems.browser.input.clear();
|
||||
|
||||
if(event) this.fieldFilter.find(f => f.name === event.target.name).value = event.target.value;
|
||||
|
||||
for (const li of this.element.querySelectorAll('.item-container')) {
|
||||
const itemUUID = li.dataset.itemUuid,
|
||||
item = this.items.find(i => i.uuid === itemUUID);
|
||||
|
||||
if(!item) continue;
|
||||
|
||||
const matchesMenu =
|
||||
this.fieldFilter.length === 0 ||
|
||||
this.fieldFilter.every(f => (
|
||||
!f.value && f.value !== false) ||
|
||||
ItemBrowser.evaluateFilter(item, this.createFilterData(f))
|
||||
);
|
||||
if (matchesMenu) this.#filteredItems.browser.input.add(item.id);
|
||||
|
||||
const { search } = this.#filteredItems.browser;
|
||||
li.hidden = !(search.has(item.id) && matchesMenu);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Foundry evaluateFilter doesn't allow you to match if filter values are included into item data
|
||||
* @param {*} obj
|
||||
* @param {*} filter
|
||||
*/
|
||||
static evaluateFilter(obj, filter) {
|
||||
let docValue = foundry.utils.getProperty(obj, filter.field);
|
||||
let filterValue = filter.value;
|
||||
switch (filter.operator) {
|
||||
case "contains2":
|
||||
filterValue = Array.isArray(filterValue) ? filterValue : [filterValue];
|
||||
docValue = Array.isArray(docValue) ? docValue : [docValue];
|
||||
return docValue.some(dv => filterValue.includes(dv));
|
||||
case "contains3":
|
||||
return docValue.some(f => f.value === filterValue);
|
||||
default:
|
||||
return foundry.applications.ux.SearchFilter.evaluateFilter(obj, filter);
|
||||
}
|
||||
}
|
||||
|
||||
createFilterData(filter) {
|
||||
return {
|
||||
field: filter.key,
|
||||
value: isNaN(filter.value)
|
||||
? ['true', 'false'].includes(filter.value)
|
||||
? filter.value === 'true'
|
||||
: filter.value
|
||||
: Number(filter.value),
|
||||
operator: filter.operator,
|
||||
negate: filter.negate
|
||||
};
|
||||
}
|
||||
|
||||
static resetFilters() {
|
||||
this.render({ force: true });
|
||||
}
|
||||
|
||||
static getFolderConfig(folder, property = "columns") {
|
||||
if(!folder) return [];
|
||||
return folder[property] ?? CONFIG.DH.ITEMBROWSER.typeConfig[folder.listType]?.[property] ?? [];
|
||||
}
|
||||
|
||||
static sortList(_, target) {
|
||||
const key = target.dataset.sortKey,
|
||||
type = !target.dataset.sortType || target.dataset.sortType === "DESC" ? "ASC" : "DESC",
|
||||
itemListContainer = target.closest(".compendium-results").querySelector(".item-list"),
|
||||
itemList = itemListContainer.querySelectorAll(".item-container");
|
||||
|
||||
target.closest(".item-list-header").querySelectorAll('[data-sort-key]').forEach(b => b.dataset.sortType = "");
|
||||
target.dataset.sortType = type;
|
||||
|
||||
const newOrder = [...itemList].reverse().sort((a, b) => {
|
||||
const aProp = a.querySelector(`[data-item-key="${key}"]`),
|
||||
bProp = b.querySelector(`[data-item-key="${key}"]`)
|
||||
if(type === "DESC") {
|
||||
return aProp.innerText < bProp.innerText ? 1 : -1;
|
||||
} else {
|
||||
return aProp.innerText > bProp.innerText ? 1 : -1;
|
||||
}
|
||||
});
|
||||
|
||||
itemListContainer.replaceChildren(...newOrder);
|
||||
}
|
||||
|
||||
_createDragProcess() {
|
||||
new foundry.applications.ux.DragDrop.implementation({
|
||||
dragSelector: '.item-container',
|
||||
permissions: {
|
||||
dragstart: this._canDragStart.bind(this)
|
||||
},
|
||||
callbacks: {
|
||||
dragstart: this._onDragStart.bind(this)
|
||||
}
|
||||
}).bind(this.element);
|
||||
}
|
||||
|
||||
async _onDragStart(event) {
|
||||
const { itemUuid } = event.target.closest('[data-item-uuid]').dataset,
|
||||
item = await foundry.utils.fromUuid(itemUuid),
|
||||
dragData = item.toDragData();
|
||||
event.dataTransfer.setData('text/plain', JSON.stringify(dragData));
|
||||
}
|
||||
|
||||
_canDragStart() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,8 +4,8 @@ export default class DhMeasuredTemplate extends foundry.canvas.placeables.Measur
|
|||
|
||||
const rangeMeasurementSettings = game.settings.get(
|
||||
CONFIG.DH.id,
|
||||
CONFIG.DH.SETTINGS.gameSettings.RangeMeasurement
|
||||
);
|
||||
CONFIG.DH.SETTINGS.gameSettings.variantRules
|
||||
).rangeMeasurement;
|
||||
if (rangeMeasurementSettings.enabled) {
|
||||
const splitRulerText = this.ruler.text.split(' ');
|
||||
if (splitRulerText.length > 0) {
|
||||
|
|
@ -29,7 +29,7 @@ export default class DhMeasuredTemplate extends foundry.canvas.placeables.Measur
|
|||
if (distance <= settings.far) {
|
||||
return game.i18n.localize('DAGGERHEART.CONFIG.Range.far.name');
|
||||
}
|
||||
if (distance <= settings.veryFar) {
|
||||
if (distance > settings.far) {
|
||||
return game.i18n.localize('DAGGERHEART.CONFIG.Range.veryFar.name');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export default class DhpRuler extends foundry.canvas.interaction.Ruler {
|
|||
const context = super._getWaypointLabelContext(waypoint, state);
|
||||
if (!context) return;
|
||||
|
||||
const range = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.RangeMeasurement);
|
||||
const range = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).rangeMeasurement;
|
||||
|
||||
if (range.enabled) {
|
||||
const distance = DhMeasuredTemplate.getDistanceLabel(waypoint.measurement.distance.toNearest(0.01), range);
|
||||
|
|
|
|||
|
|
@ -53,4 +53,40 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token {
|
|||
this.effects.renderable = true;
|
||||
this.renderFlags.set({ refreshEffects: true });
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
_drawBar(number, bar, data) {
|
||||
const val = Number(data.value);
|
||||
const pct = Math.clamp(val, 0, data.max) / data.max;
|
||||
|
||||
// Determine sizing
|
||||
const { width, height } = this.document.getSize();
|
||||
const s = canvas.dimensions.uiScale;
|
||||
const bw = width;
|
||||
const bh = 8 * (this.document.height >= 2 ? 1.5 : 1) * s;
|
||||
|
||||
// Determine the color to use
|
||||
const fillColor =
|
||||
number === 0 ? foundry.utils.Color.fromRGB([1, 0, 0]) : foundry.utils.Color.fromString('#0032b1');
|
||||
|
||||
// Draw the bar
|
||||
const widthUnit = bw / data.max;
|
||||
bar.clear().lineStyle(s, 0x000000, 1.0);
|
||||
const sections = [...Array(data.max).keys()];
|
||||
for (let mark of sections) {
|
||||
const x = mark * widthUnit;
|
||||
const marked = mark + 1 <= data.value;
|
||||
const color = marked ? fillColor : foundry.utils.Color.fromRGB([0, 0, 0]);
|
||||
if (mark === 0 || mark === sections.length - 1) {
|
||||
bar.beginFill(color, marked ? 1.0 : 0.5).drawRect(x, 0, widthUnit, bh, 2 * s); // Would like drawRoundedRect, but it's very troublsome with the corners. Leaving for now.
|
||||
} else {
|
||||
bar.beginFill(color, marked ? 1.0 : 0.5).drawRect(x, 0, widthUnit, bh, 2 * s);
|
||||
}
|
||||
}
|
||||
|
||||
// Set position
|
||||
const posY = number === 0 ? height - bh : 0;
|
||||
bar.position.set(0, posY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export default class DhpTokenRuler extends foundry.canvas.placeables.tokens.Toke
|
|||
const context = super._getWaypointLabelContext(waypoint, state);
|
||||
if (!context) return;
|
||||
|
||||
const range = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.RangeMeasurement);
|
||||
const range = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).rangeMeasurement;
|
||||
|
||||
if (range.enabled) {
|
||||
const distance = DhMeasuredTemplate.getDistanceLabel(waypoint.measurement.distance.toNearest(0.01), range);
|
||||
|
|
|
|||
|
|
@ -7,3 +7,4 @@ export * as generalConfig from './generalConfig.mjs';
|
|||
export * as itemConfig from './itemConfig.mjs';
|
||||
export * as settingsConfig from './settingsConfig.mjs';
|
||||
export * as systemConfig from './system.mjs';
|
||||
export * as itemBrowserConfig from './itemBrowserConfig.mjs';
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export const ruleChoice = {
|
|||
}
|
||||
};
|
||||
|
||||
export const range = {
|
||||
export const templateRanges = {
|
||||
self: {
|
||||
id: 'self',
|
||||
short: 's',
|
||||
|
|
@ -56,7 +56,11 @@ export const range = {
|
|||
label: 'DAGGERHEART.CONFIG.Range.far.name',
|
||||
description: 'DAGGERHEART.CONFIG.Range.far.description',
|
||||
distance: 20
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
export const range = {
|
||||
...templateRanges,
|
||||
veryFar: {
|
||||
id: 'veryFar',
|
||||
short: 'vf',
|
||||
|
|
@ -479,7 +483,8 @@ export const multiplierTypes = {
|
|||
cast: 'Spellcast',
|
||||
scale: 'Cost Scaling',
|
||||
result: 'Roll Result',
|
||||
flat: 'Flat'
|
||||
flat: 'Flat',
|
||||
tier: 'Tier'
|
||||
};
|
||||
|
||||
export const diceSetNumbers = {
|
||||
|
|
|
|||
405
module/config/itemBrowserConfig.mjs
Normal file
405
module/config/itemBrowserConfig.mjs
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
export const typeConfig = {
|
||||
adversaries: {
|
||||
columns: [
|
||||
{
|
||||
key: "system.tier",
|
||||
label: "Tier"
|
||||
},
|
||||
{
|
||||
key: "system.type",
|
||||
label: "Type"
|
||||
}
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
key: "system.tier",
|
||||
label: "Tier",
|
||||
field: 'system.api.models.actors.DhAdversary.schema.fields.tier'
|
||||
},
|
||||
{
|
||||
key: "system.type",
|
||||
label: "Type",
|
||||
field: 'system.api.models.actors.DhAdversary.schema.fields.type'
|
||||
},
|
||||
{
|
||||
key: "system.difficulty",
|
||||
name: "difficulty.min",
|
||||
label: "Difficulty (Min)",
|
||||
field: 'system.api.models.actors.DhAdversary.schema.fields.difficulty',
|
||||
operator: "gte"
|
||||
},
|
||||
{
|
||||
key: "system.difficulty",
|
||||
name: "difficulty.max",
|
||||
label: "Difficulty (Max)",
|
||||
field: 'system.api.models.actors.DhAdversary.schema.fields.difficulty',
|
||||
operator: "lte"
|
||||
},
|
||||
{
|
||||
key: "system.resources.hitPoints.max",
|
||||
name: "hp.min",
|
||||
label: "Hit Points (Min)",
|
||||
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.hitPoints.fields.max',
|
||||
operator: "gte"
|
||||
},
|
||||
{
|
||||
key: "system.resources.hitPoints.max",
|
||||
name: "hp.max",
|
||||
label: "Hit Points (Max)",
|
||||
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.hitPoints.fields.max',
|
||||
operator: "lte"
|
||||
},
|
||||
{
|
||||
key: "system.resources.stress.max",
|
||||
name: "stress.min",
|
||||
label: "Stress (Min)",
|
||||
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.stress.fields.max',
|
||||
operator: "gte"
|
||||
},
|
||||
{
|
||||
key: "system.resources.stress.max",
|
||||
name: "stress.max",
|
||||
label: "Stress (Max)",
|
||||
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.stress.fields.max',
|
||||
operator: "lte"
|
||||
},
|
||||
]
|
||||
},
|
||||
items: {
|
||||
columns: [
|
||||
{
|
||||
key: "type",
|
||||
label: "Type"
|
||||
},
|
||||
{
|
||||
key: "system.secondary",
|
||||
label: "Subtype",
|
||||
format: (isSecondary) => isSecondary ? "secondary" : (isSecondary === false ? "primary" : '-')
|
||||
},
|
||||
{
|
||||
key: "system.tier",
|
||||
label: "Tier"
|
||||
}
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
key: "type",
|
||||
label: "Type",
|
||||
choices: () => CONFIG.Item.documentClass.TYPES.filter(t => ["armor", "weapon", "consumable", "loot"].includes(t)).map(t => ({ value: t, label: t }))
|
||||
},
|
||||
{
|
||||
key: "system.secondary",
|
||||
label: "Subtype",
|
||||
choices: [
|
||||
{ value: false, label: "Primary Weapon"},
|
||||
{ value: true, label: "Secondary Weapon"}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: "system.tier",
|
||||
label: "Tier",
|
||||
choices: [{ value: "1", label: "1"}, { value: "2", label: "2"}, { value: "3", label: "3"}, { value: "4", label: "4"}]
|
||||
},
|
||||
{
|
||||
key: "system.burden",
|
||||
label: "Burden",
|
||||
field: 'system.api.models.items.DHWeapon.schema.fields.burden'
|
||||
},
|
||||
{
|
||||
key: "system.attack.roll.trait",
|
||||
label: "Trait",
|
||||
field: 'system.api.models.actions.actionsTypes.attack.schema.fields.roll.fields.trait'
|
||||
},
|
||||
{
|
||||
key: "system.attack.range",
|
||||
label: "Range",
|
||||
field: 'system.api.models.actions.actionsTypes.attack.schema.fields.range'
|
||||
},
|
||||
{
|
||||
key: "system.baseScore",
|
||||
name: "armor.min",
|
||||
label: "Armor Score (Min)",
|
||||
field: 'system.api.models.items.DHArmor.schema.fields.baseScore',
|
||||
operator: "gte"
|
||||
},
|
||||
{
|
||||
key: "system.baseScore",
|
||||
name: "armor.max",
|
||||
label: "Armor Score (Max)",
|
||||
field: 'system.api.models.items.DHArmor.schema.fields.baseScore',
|
||||
operator: "lte"
|
||||
},
|
||||
{
|
||||
key: "system.itemFeatures",
|
||||
label: "Features",
|
||||
choices: () => [...Object.entries(CONFIG.DH.ITEM.weaponFeatures), ...Object.entries(CONFIG.DH.ITEM.armorFeatures)].map(([k,v]) => ({ value: k, label: v.label})),
|
||||
operator: "contains3"
|
||||
}
|
||||
]
|
||||
},
|
||||
features: {
|
||||
columns: [
|
||||
|
||||
],
|
||||
filters: [
|
||||
|
||||
]
|
||||
},
|
||||
cards: {
|
||||
columns: [
|
||||
{
|
||||
key: "system.type",
|
||||
label: "Type"
|
||||
},
|
||||
{
|
||||
key: "system.domain",
|
||||
label: "Domain"
|
||||
},
|
||||
{
|
||||
key: "system.level",
|
||||
label: "Level"
|
||||
}
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
key: "system.type",
|
||||
label: "Type",
|
||||
field: 'system.api.models.items.DHDomainCard.schema.fields.type'
|
||||
},
|
||||
{
|
||||
key: "system.domain",
|
||||
label: "Domain",
|
||||
field: 'system.api.models.items.DHDomainCard.schema.fields.domain',
|
||||
operator: "contains2"
|
||||
},
|
||||
{
|
||||
key: "system.level",
|
||||
name: "level.min",
|
||||
label: "Level (Min)",
|
||||
field: 'system.api.models.items.DHDomainCard.schema.fields.level',
|
||||
operator: "gte"
|
||||
},
|
||||
{
|
||||
key: "system.level",
|
||||
name: "level.max",
|
||||
label: "Level (Max)",
|
||||
field: 'system.api.models.items.DHDomainCard.schema.fields.level',
|
||||
operator: "lte"
|
||||
},
|
||||
{
|
||||
key: "system.recallCost",
|
||||
name: "recall.min",
|
||||
label: "Recall Cost (Min)",
|
||||
field: 'system.api.models.items.DHDomainCard.schema.fields.recallCost',
|
||||
operator: "gte"
|
||||
},
|
||||
{
|
||||
key: "system.recallCost",
|
||||
name: "recall.max",
|
||||
label: "Recall Cost (Max)",
|
||||
field: 'system.api.models.items.DHDomainCard.schema.fields.recallCost',
|
||||
operator: "lte"
|
||||
}
|
||||
]
|
||||
},
|
||||
classes: {
|
||||
columns: [
|
||||
{
|
||||
key: "system.evasion",
|
||||
label: "Evasion"
|
||||
},
|
||||
{
|
||||
key: "system.hitPoints",
|
||||
label: "Hit Points"
|
||||
},
|
||||
{
|
||||
key: "system.domains",
|
||||
label: "Domains"
|
||||
}
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
key: "system.evasion",
|
||||
name: "evasion.min",
|
||||
label: "Evasion (Min)",
|
||||
field: 'system.api.models.items.DHClass.schema.fields.evasion',
|
||||
operator: "gte"
|
||||
},
|
||||
{
|
||||
key: "system.evasion",
|
||||
name: "evasion.max",
|
||||
label: "Evasion (Max)",
|
||||
field: 'system.api.models.items.DHClass.schema.fields.evasion',
|
||||
operator: "lte"
|
||||
},
|
||||
{
|
||||
key: "system.hitPoints",
|
||||
name: "hp.min",
|
||||
label: "Hit Points (Min)",
|
||||
field: 'system.api.models.items.DHClass.schema.fields.hitPoints',
|
||||
operator: "gte"
|
||||
},
|
||||
{
|
||||
key: "system.hitPoints",
|
||||
name: "hp.max",
|
||||
label: "Hit Points (Max)",
|
||||
field: 'system.api.models.items.DHClass.schema.fields.hitPoints',
|
||||
operator: "lte"
|
||||
},
|
||||
{
|
||||
key: "system.domains",
|
||||
label: "Domains",
|
||||
choices: () => Object.values(CONFIG.DH.DOMAIN.domains).map(d => ({ value: d.id, label: d.label})),
|
||||
operator: "contains2"
|
||||
}
|
||||
]
|
||||
},
|
||||
subclasses: {
|
||||
columns: [
|
||||
{
|
||||
key: "id",
|
||||
label: "Class",
|
||||
format: (id) => {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "system.spellcastingTrait",
|
||||
label: "Spellcasting Trait"
|
||||
}
|
||||
],
|
||||
filters: []
|
||||
},
|
||||
beastforms: {
|
||||
columns: [
|
||||
{
|
||||
key: "system.tier",
|
||||
label: "Tier"
|
||||
},
|
||||
{
|
||||
key: "system.mainTrait",
|
||||
label: "Main Trait"
|
||||
}
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
key: "system.tier",
|
||||
label: "Tier",
|
||||
field: 'system.api.models.items.DHBeastform.schema.fields.tier'
|
||||
},
|
||||
{
|
||||
key: "system.mainTrait",
|
||||
label: "Main Trait",
|
||||
field: 'system.api.models.items.DHBeastform.schema.fields.mainTrait'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
export const compendiumConfig = {
|
||||
"daggerheart": {
|
||||
id: "daggerheart",
|
||||
label: "DAGGERHEART",
|
||||
folders: {
|
||||
"adversaries": {
|
||||
id: "adversaries",
|
||||
keys: ["adversaries"],
|
||||
label: "Adversaries",
|
||||
type: ["adversary"],
|
||||
listType: "adversaries"
|
||||
},
|
||||
"ancestries": {
|
||||
id: "ancestries",
|
||||
keys: ["ancestries"],
|
||||
label: "Ancestries",
|
||||
type: ["ancestry"],
|
||||
folders: {
|
||||
"features": {
|
||||
id: "features",
|
||||
keys: ["ancestries"],
|
||||
label: "Features",
|
||||
type: ["feature"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"equipments": {
|
||||
id: "equipments",
|
||||
keys: ["armors", "weapons", "consumables", "loot"],
|
||||
label: "Equipments",
|
||||
type: ["armor", "weapon", "consumable", "loot"],
|
||||
listType: "items"
|
||||
},
|
||||
"classes": {
|
||||
id: "classes",
|
||||
keys: ["classes"],
|
||||
label: "Classes",
|
||||
type: ["class"],
|
||||
folders: {
|
||||
"features": {
|
||||
id: "features",
|
||||
keys: ["classes"],
|
||||
label: "Features",
|
||||
type: ["feature"]
|
||||
},
|
||||
"items": {
|
||||
id: "items",
|
||||
keys: ["classes"],
|
||||
label: "Items",
|
||||
type: ["armor", "weapon", "consumable", "loot"],
|
||||
listType: "items"
|
||||
}
|
||||
},
|
||||
listType: "classes"
|
||||
},
|
||||
"subclasses": {
|
||||
id: "subclasses",
|
||||
keys: ["subclasses"],
|
||||
label: "Subclasses",
|
||||
type: ["subclass"],
|
||||
listType: "subclasses"
|
||||
},
|
||||
"domains": {
|
||||
id: "domains",
|
||||
keys: ["domains"],
|
||||
label: "Domain Cards",
|
||||
type: ["domainCard"],
|
||||
listType: "cards"
|
||||
},
|
||||
"communities": {
|
||||
id: "communities",
|
||||
keys: ["communities"],
|
||||
label: "Communities",
|
||||
type: ["community"],
|
||||
folders: {
|
||||
"features": {
|
||||
id: "features",
|
||||
keys: ["communities"],
|
||||
label: "Features",
|
||||
type: ["feature"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"environments": {
|
||||
id: "environments",
|
||||
keys: ["environments"],
|
||||
label: "Environments",
|
||||
type: ["environment"]
|
||||
},
|
||||
"beastforms": {
|
||||
id: "beastforms",
|
||||
keys: ["beastforms"],
|
||||
label: "Beastforms",
|
||||
type: ["beastform"],
|
||||
listType: "beastforms",
|
||||
folders: {
|
||||
"features": {
|
||||
id: "features",
|
||||
keys: ["beastforms"],
|
||||
label: "Features",
|
||||
type: ["feature"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -380,7 +380,7 @@ export const armorFeatures = {
|
|||
img: 'icons/magic/time/hourglass-brown-orange.webp',
|
||||
cost: [
|
||||
{
|
||||
key: 'armorStack',
|
||||
key: 'armorSlot',
|
||||
value: 1
|
||||
}
|
||||
],
|
||||
|
|
@ -857,7 +857,7 @@ export const weaponFeatures = {
|
|||
name: 'DAGGERHEART.CONFIG.WeaponFeature.greedy.name',
|
||||
description: 'DAGGERHEART.CONFIG.WeaponFeature.greedy.description',
|
||||
img: 'icons/commodities/currency/coins-crown-stack-gold.webp',
|
||||
// Should cost handfull of gold,
|
||||
// Should cost handful of gold,
|
||||
effects: [
|
||||
{
|
||||
name: 'DAGGERHEART.CONFIG.WeaponFeature.greedy.actions.greed.name',
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ export const menu = {
|
|||
export const gameSettings = {
|
||||
Automation: 'Automation',
|
||||
Homebrew: 'Homebrew',
|
||||
RangeMeasurement: 'RangeMeasurement',
|
||||
appearance: 'Appearance',
|
||||
variantRules: 'VariantRules',
|
||||
Resources: {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import * as SETTINGS from './settingsConfig.mjs';
|
|||
import * as EFFECTS from './effectConfig.mjs';
|
||||
import * as ACTIONS from './actionConfig.mjs';
|
||||
import * as FLAGS from './flagsConfig.mjs';
|
||||
import * as ITEMBROWSER from './itemBrowserConfig.mjs'
|
||||
|
||||
export const SYSTEM_ID = 'daggerheart';
|
||||
|
||||
|
|
@ -18,5 +19,6 @@ export const SYSTEM = {
|
|||
SETTINGS,
|
||||
EFFECTS,
|
||||
ACTIONS,
|
||||
FLAGS
|
||||
FLAGS,
|
||||
ITEMBROWSER
|
||||
};
|
||||
|
|
|
|||
|
|
@ -115,7 +115,6 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
if (!this.actor) throw new Error("An Action can't be used outside of an Actor context.");
|
||||
|
||||
if (this.chatDisplay) await this.toChat();
|
||||
|
||||
let { byPassRoll } = options,
|
||||
config = this.prepareConfig(event, byPassRoll);
|
||||
for (let i = 0; i < this.constructor.extraSchemas.length; i++) {
|
||||
|
|
@ -223,14 +222,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
}
|
||||
|
||||
const resources = config.costs
|
||||
.filter(c =>
|
||||
c.enabled !== false
|
||||
&&
|
||||
(
|
||||
(!successCost && (!c.consumeOnSuccess || config.roll?.success))
|
||||
||
|
||||
(successCost && c.consumeOnSuccess)
|
||||
)
|
||||
.filter(
|
||||
c =>
|
||||
c.enabled !== false &&
|
||||
((!successCost && (!c.consumeOnSuccess || config.roll?.success)) ||
|
||||
(successCost && c.consumeOnSuccess))
|
||||
)
|
||||
.map(c => {
|
||||
const resource = usefulResources[c.key];
|
||||
|
|
@ -243,14 +239,12 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
});
|
||||
|
||||
await this.actor.modifyResource(resources);
|
||||
if (config.uses?.enabled
|
||||
&&
|
||||
(
|
||||
(!successCost && (!config.uses?.consumeOnSuccess || config.roll?.success))
|
||||
||
|
||||
(successCost && config.uses?.consumeOnSuccess)
|
||||
)
|
||||
) this.update({ 'uses.value': this.uses.value + 1 });
|
||||
if (
|
||||
config.uses?.enabled &&
|
||||
((!successCost && (!config.uses?.consumeOnSuccess || config.roll?.success)) ||
|
||||
(successCost && config.uses?.consumeOnSuccess))
|
||||
)
|
||||
this.update({ 'uses.value': this.uses.value + 1 });
|
||||
|
||||
if(config.roll?.success || successCost) {
|
||||
setTimeout(() => {
|
||||
|
|
@ -309,11 +303,9 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
}
|
||||
|
||||
async applyEffect(effect, actor) {
|
||||
const origin = effect.parent?.parent ? effect.parent.parent.uuid : effect.parent.uuid;
|
||||
// Enable an existing effect on the target if it originated from this effect
|
||||
const existingEffect = actor.effects.find(e => e.origin === origin);
|
||||
const existingEffect = actor.effects.find(e => e.origin === effect.uuid);
|
||||
if (existingEffect) {
|
||||
return existingEffect.update(
|
||||
return effect.update(
|
||||
foundry.utils.mergeObject({
|
||||
...effect.constructor.getInitialDuration(),
|
||||
disabled: false
|
||||
|
|
@ -326,7 +318,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
...effect.toObject(),
|
||||
disabled: false,
|
||||
transfer: false,
|
||||
origin: origin
|
||||
origin: effect.uuid
|
||||
});
|
||||
await ActiveEffect.implementation.create(effectData, { parent: actor });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export default class DHDamageAction extends DHBaseAction {
|
|||
dialog: {},
|
||||
data: this.getRollData(),
|
||||
targetSelection: systemData.targets.length > 0
|
||||
}
|
||||
};
|
||||
if (this.hasSave) config.onSave = this.save.damageMod;
|
||||
if (data.system) {
|
||||
config.source.message = data._id;
|
||||
|
|
|
|||
|
|
@ -68,12 +68,13 @@ export default class DhCharacter extends BaseDataActor {
|
|||
new fields.SchemaField({
|
||||
name: new fields.StringField(),
|
||||
value: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
description: new fields.StringField()
|
||||
description: new fields.StringField(),
|
||||
core: new fields.BooleanField({ initial: false })
|
||||
})
|
||||
),
|
||||
gold: new fields.SchemaField({
|
||||
coins: new fields.NumberField({ initial: 0, integer: true }),
|
||||
handfulls: new fields.NumberField({ initial: 0, integer: true }),
|
||||
handfuls: new fields.NumberField({ initial: 1, integer: true }),
|
||||
bags: new fields.NumberField({ initial: 0, integer: true }),
|
||||
chests: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
|
|
@ -573,7 +574,10 @@ export default class DhCharacter extends BaseDataActor {
|
|||
case 'experience':
|
||||
selection.data.forEach(id => {
|
||||
const experience = this.experiences[id];
|
||||
if (experience) experience.value += selection.value;
|
||||
if (experience) {
|
||||
experience.value += selection.value;
|
||||
experience.leveledUp = true;
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
|
@ -620,6 +624,23 @@ export default class DhCharacter extends BaseDataActor {
|
|||
};
|
||||
}
|
||||
|
||||
async _preUpdate(changes, options, userId) {
|
||||
const allowed = await super._preUpdate(changes, options, userId);
|
||||
if (allowed === false) return;
|
||||
|
||||
/* The first two experiences are always marked as core */
|
||||
if (changes.system?.experiences && Object.keys(this.experiences).length < 2) {
|
||||
const experiences = new Set(Object.keys(this.experiences));
|
||||
const changeExperiences = new Set(Object.keys(changes.system.experiences));
|
||||
const newExperiences = Array.from(changeExperiences.difference(experiences));
|
||||
|
||||
for (var i = 0; i < Math.min(newExperiences.length, 2 - experiences.size); i++) {
|
||||
const experience = newExperiences[i];
|
||||
changes.system.experiences[experience].core = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async _preDelete() {
|
||||
if (this.companion) {
|
||||
this.companion.updateLevel(1);
|
||||
|
|
|
|||
|
|
@ -1,20 +1,21 @@
|
|||
const fields = foundry.data.fields;
|
||||
|
||||
const targetsField = () => new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
id: new fields.StringField({}),
|
||||
actorId: new fields.StringField({}),
|
||||
name: new fields.StringField({}),
|
||||
img: new fields.StringField({}),
|
||||
difficulty: new fields.NumberField({ integer: true, nullable: true }),
|
||||
evasion: new fields.NumberField({ integer: true }),
|
||||
hit: new fields.BooleanField({ initial: false }),
|
||||
saved: new fields.SchemaField({
|
||||
result: new fields.NumberField(),
|
||||
success: new fields.BooleanField({ nullable: true, initial: null })
|
||||
const targetsField = () =>
|
||||
new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
id: new fields.StringField({}),
|
||||
actorId: new fields.StringField({}),
|
||||
name: new fields.StringField({}),
|
||||
img: new fields.StringField({}),
|
||||
difficulty: new fields.NumberField({ integer: true, nullable: true }),
|
||||
evasion: new fields.NumberField({ integer: true }),
|
||||
hit: new fields.BooleanField({ initial: false }),
|
||||
saved: new fields.SchemaField({
|
||||
result: new fields.NumberField(),
|
||||
success: new fields.BooleanField({ nullable: true, initial: null })
|
||||
})
|
||||
})
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
||||
targetHook = null;
|
||||
|
|
@ -39,27 +40,25 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
|||
action: new fields.StringField()
|
||||
}),
|
||||
damage: new fields.ObjectField(),
|
||||
costs: new fields.ArrayField(
|
||||
new fields.ObjectField()
|
||||
),
|
||||
costs: new fields.ArrayField(new fields.ObjectField()),
|
||||
successConsumed: new fields.BooleanField({ initial: false })
|
||||
};
|
||||
}
|
||||
|
||||
get actionActor() {
|
||||
if(!this.source.actor) return null;
|
||||
if (!this.source.actor) return null;
|
||||
return fromUuidSync(this.source.actor);
|
||||
}
|
||||
|
||||
get actionItem() {
|
||||
const actionActor = this.actionActor;
|
||||
if(!actionActor || !this.source.item) return null;
|
||||
if (!actionActor || !this.source.item) return null;
|
||||
return actionActor.items.get(this.source.item);
|
||||
}
|
||||
|
||||
get action() {
|
||||
const actionItem = this.actionItem;
|
||||
if(!actionItem || !this.source.action) return null;
|
||||
if (!actionItem || !this.source.action) return null;
|
||||
return actionItem.system.actionsList?.find(a => a.id === this.source.action);
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +73,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
|||
}
|
||||
|
||||
get hitTargets() {
|
||||
return this.currentTargets.filter(t => (t.hit || !this.hasRoll || !this.targetSelection));
|
||||
return this.currentTargets.filter(t => t.hit || !this.hasRoll || !this.targetSelection);
|
||||
}
|
||||
|
||||
async updateTargets() {
|
||||
|
|
@ -98,13 +97,13 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
|||
if(this.targetSelection && this.targetHook !== null) {
|
||||
Hooks.off("targetToken", this.targetHook);
|
||||
this.targetHook = null;
|
||||
} else if(!this.targetSelection && this.targetHook === null) {
|
||||
this.targetHook = Hooks.on("targetToken", foundry.utils.debounce(this.updateTargets.bind(this), 50));
|
||||
} else if (!this.targetSelection && this.targetHook === null) {
|
||||
this.targetHook = Hooks.on('targetToken', foundry.utils.debounce(this.updateTargets.bind(this), 50));
|
||||
}
|
||||
}
|
||||
|
||||
prepareDerivedData() {
|
||||
if(this.hasTarget) {
|
||||
if (this.hasTarget) {
|
||||
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
||||
this.currentTargets = this.getTargetList();
|
||||
this. registerTargetHook();
|
||||
|
|
@ -116,7 +115,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
|||
return a;
|
||||
}, {hit: 0, miss: 0})
|
||||
}
|
||||
if(this.hasSave) this.setPendingSaves();
|
||||
if (this.hasSave) this.setPendingSaves();
|
||||
}
|
||||
|
||||
this.canViewSecret = this.parent.speakerActor?.testUserPermission(game.user, 'OBSERVER');
|
||||
|
|
@ -139,11 +138,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
|||
|
||||
setPendingSaves() {
|
||||
this.pendingSaves = this.targetSelection
|
||||
? this.targets.filter(
|
||||
target => target.hit && target.saved.success === null
|
||||
).length > 0
|
||||
: this.currentTargets.filter(
|
||||
target => target.saved.success === null
|
||||
).length > 0;
|
||||
? this.targets.filter(target => target.hit && target.saved.success === null).length > 0
|
||||
: this.currentTargets.filter(target => target.saved.success === null).length > 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,25 @@ export default class BeastformField extends fields.SchemaField {
|
|||
constructor(options = {}, context = {}) {
|
||||
const beastformFields = {
|
||||
tierAccess: new fields.SchemaField({
|
||||
exact: new fields.NumberField({ integer: true, nullable: true, initial: null })
|
||||
exact: new fields.NumberField({
|
||||
integer: true,
|
||||
nullable: true,
|
||||
initial: null,
|
||||
choices: () => {
|
||||
const settingsTiers = game.settings.get(
|
||||
CONFIG.DH.id,
|
||||
CONFIG.DH.SETTINGS.gameSettings.LevelTiers
|
||||
).tiers;
|
||||
return Object.values(settingsTiers).reduce(
|
||||
(acc, tier) => {
|
||||
acc[tier.tier] = game.i18n.localize(tier.name);
|
||||
return acc;
|
||||
},
|
||||
{ 1: game.i18n.localize('DAGGERHEART.GENERAL.Tiers.1') }
|
||||
);
|
||||
},
|
||||
hint: 'DAGGERHEART.ACTIONS.Config.beastform.exactHint'
|
||||
})
|
||||
})
|
||||
};
|
||||
super(beastformFields, options, context);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ export default class RangeField extends fields.StringField {
|
|||
const options = {
|
||||
choices: CONFIG.DH.GENERAL.range,
|
||||
required: false,
|
||||
blank: true
|
||||
blank: true,
|
||||
label: "DAGGERHEART.GENERAL.range"
|
||||
};
|
||||
super(options, context);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export class DHActionRollData extends foundry.abstract.DataModel {
|
|||
static defineSchema() {
|
||||
return {
|
||||
type: new fields.StringField({ nullable: true, initial: null, choices: CONFIG.DH.GENERAL.rollTypes }),
|
||||
trait: new fields.StringField({ nullable: true, initial: null, choices: CONFIG.DH.ACTOR.abilities }),
|
||||
trait: new fields.StringField({ nullable: true, initial: null, choices: CONFIG.DH.ACTOR.abilities, label: "DAGGERHEART.GENERAL.Trait.single" }),
|
||||
difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }),
|
||||
bonus: new fields.NumberField({ nullable: true, initial: null, integer: true }),
|
||||
advState: new fields.StringField({
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@ export default class UsesField extends fields.SchemaField {
|
|||
initial: null,
|
||||
nullable: true
|
||||
}),
|
||||
consumeOnSuccess: new fields.BooleanField({ initial: false, label: "DAGGERHEART.ACTIONS.Settings.consumeOnSuccess.label" })
|
||||
consumeOnSuccess: new fields.BooleanField({
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.ACTIONS.Settings.consumeOnSuccess.label'
|
||||
})
|
||||
};
|
||||
super(usesFields, options, context);
|
||||
}
|
||||
|
|
@ -30,6 +33,7 @@ export default class UsesField extends fields.SchemaField {
|
|||
if (!uses) return null;
|
||||
return {
|
||||
...uses,
|
||||
remaining: this.remainingUses,
|
||||
enabled: uses.hasOwnProperty('enabled') ? uses.enabled : true
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import DHActionConfig from '../../applications/sheets-configs/action-config.mjs';
|
||||
import { itemAbleRollParse } from '../../helpers/utils.mjs';
|
||||
import MappingField from './mappingField.mjs';
|
||||
|
||||
/**
|
||||
|
|
@ -164,6 +165,15 @@ export function ActionMixin(Base) {
|
|||
return foundry.utils.getProperty(this.parent, this.systemPath) instanceof Collection;
|
||||
}
|
||||
|
||||
get remainingUses() {
|
||||
if (!this.uses) return null;
|
||||
|
||||
return Math.max(
|
||||
(this.uses.max ? itemAbleRollParse(this.uses.max, this.actor) : 0) - (this.uses.value ?? 0),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
static async create(data, operation = {}) {
|
||||
const { parent, renderSheet } = operation;
|
||||
let { type } = data;
|
||||
|
|
|
|||
|
|
@ -147,4 +147,8 @@ export default class DHArmor extends AttachableItem {
|
|||
const labels = [`${game.i18n.localize('DAGGERHEART.ITEMS.Armor.baseScore')}: ${this.baseScore}`];
|
||||
return labels;
|
||||
}
|
||||
|
||||
get itemFeatures() {
|
||||
return this.armorFeatures;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,6 +106,10 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
return this.actions;
|
||||
}
|
||||
|
||||
get itemFeatures() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a data object used to evaluate any dice rolls associated with this Item Type
|
||||
* @param {object} [options] - Options which modify the getRollData method.
|
||||
|
|
|
|||
|
|
@ -88,6 +88,26 @@ export default class DHBeastform extends BaseDataItem {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
get beastformAttackData() {
|
||||
const effect = this.parent.effects.find(x => x.type === 'beastform');
|
||||
if (!effect) return null;
|
||||
|
||||
const traitBonus = effect.changes.find(x => x.key === `system.traits.${this.mainTrait}.value`)?.value ?? 0;
|
||||
const evasionBonus = effect.changes.find(x => x.key === 'system.evasion')?.value ?? 0;
|
||||
|
||||
const damageDiceIndex = effect.changes.find(x => x.key === 'system.rules.attack.damage.diceIndex');
|
||||
const damageDice = damageDiceIndex ? Object.keys(CONFIG.DH.GENERAL.diceTypes)[damageDiceIndex.value] : null;
|
||||
const damageBonus = effect.changes.find(x => x.key === 'system.rules.attack.damage.bonus')?.value ?? 0;
|
||||
|
||||
return {
|
||||
trait: game.i18n.localize(CONFIG.DH.ACTOR.abilities[this.mainTrait].label),
|
||||
traitBonus: traitBonus ? Number(traitBonus).signedString() : '',
|
||||
evasionBonus: evasionBonus ? Number(evasionBonus).signedString() : '',
|
||||
damageDice: damageDice,
|
||||
damageBonus: damageBonus ? `${Number(damageBonus).signedString()}` : ''
|
||||
};
|
||||
}
|
||||
|
||||
async _preCreate() {
|
||||
if (!this.actor) return;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ export default class DHSubclass extends BaseDataItem {
|
|||
choices: CONFIG.DH.ACTOR.abilities,
|
||||
integer: false,
|
||||
nullable: true,
|
||||
initial: null
|
||||
initial: null,
|
||||
label: "DAGGERHEART.ITEMS.Subclass.spellcastingTrait"
|
||||
}),
|
||||
features: new ItemLinkFields(),
|
||||
featureState: new fields.NumberField({ required: true, initial: 1, min: 1 }),
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ export default class DHWeapon extends AttachableItem {
|
|||
const fields = foundry.data.fields;
|
||||
return {
|
||||
...super.defineSchema(),
|
||||
tier: new fields.NumberField({ required: true, integer: true, initial: 1, min: 1 }),
|
||||
tier: new fields.NumberField({ required: true, integer: true, initial: 1, min: 1, label: "DAGGERHEART.GENERAL.Tiers.singular" }),
|
||||
equipped: new fields.BooleanField({ initial: false }),
|
||||
|
||||
//SETTINGS
|
||||
secondary: new fields.BooleanField({ initial: false }),
|
||||
burden: new fields.StringField({ required: true, choices: CONFIG.DH.GENERAL.burden, initial: 'oneHanded' }),
|
||||
secondary: new fields.BooleanField({ initial: false, label: "DAGGERHEART.ITEMS.Weapon.secondaryWeapon" }),
|
||||
burden: new fields.StringField({ required: true, choices: CONFIG.DH.GENERAL.burden, initial: 'oneHanded', label: "DAGGERHEART.GENERAL.burden" }),
|
||||
weaponFeatures: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
value: new fields.StringField({
|
||||
|
|
@ -234,4 +234,8 @@ export default class DHWeapon extends AttachableItem {
|
|||
|
||||
return labels;
|
||||
}
|
||||
|
||||
get itemFeatures() {
|
||||
return this.weaponFeatures;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,11 @@ export default class DhAutomation extends foundry.abstract.DataModel {
|
|||
required: true,
|
||||
initial: true,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.resourceScrollTexts.label'
|
||||
}),
|
||||
playerCanEditSheet: new fields.BooleanField({
|
||||
required: true,
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.playerCanEditSheet.label'
|
||||
})
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,10 +45,10 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
|
|||
initial: 'Coins',
|
||||
label: 'DAGGERHEART.SETTINGS.Homebrew.currency.coinName'
|
||||
}),
|
||||
handfulls: new fields.StringField({
|
||||
handfuls: new fields.StringField({
|
||||
required: true,
|
||||
initial: 'Handfulls',
|
||||
label: 'DAGGERHEART.SETTINGS.Homebrew.currency.handfullName'
|
||||
initial: 'Handfuls',
|
||||
label: 'DAGGERHEART.SETTINGS.Homebrew.currency.handfulName'
|
||||
}),
|
||||
bags: new fields.StringField({
|
||||
required: true,
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
export default class DhRangeMeasurement extends foundry.abstract.DataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
enabled: new fields.BooleanField({ required: true, initial: true, label: 'DAGGERHEART.GENERAL.enabled' }),
|
||||
melee: new fields.NumberField({ required: true, initial: 5, label: 'DAGGERHEART.CONFIG.Range.melee.name' }),
|
||||
veryClose: new fields.NumberField({
|
||||
required: true,
|
||||
initial: 15,
|
||||
label: 'DAGGERHEART.CONFIG.Range.veryClose.name'
|
||||
}),
|
||||
close: new fields.NumberField({
|
||||
required: true,
|
||||
initial: 30,
|
||||
label: 'DAGGERHEART.CONFIG.Range.close.name'
|
||||
}),
|
||||
far: new fields.NumberField({ required: true, initial: 60, label: 'DAGGERHEART.CONFIG.Range.far.name' }),
|
||||
veryFar: new fields.NumberField({
|
||||
required: true,
|
||||
initial: 120,
|
||||
label: 'DAGGERHEART.CONFIG.Range.veryFar.name'
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -17,9 +17,28 @@ export default class DhVariantRules extends foundry.abstract.DataModel {
|
|||
label: 'DAGGERHEART.SETTINGS.VariantRules.FIELDS.actionTokens.tokens.label'
|
||||
})
|
||||
}),
|
||||
useCoins: new fields.BooleanField({
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.VariantRules.FIELDS.useCoins.label'
|
||||
rangeMeasurement: new fields.SchemaField({
|
||||
enabled: new fields.BooleanField({
|
||||
required: true,
|
||||
initial: true,
|
||||
label: 'DAGGERHEART.GENERAL.enabled'
|
||||
}),
|
||||
melee: new fields.NumberField({
|
||||
required: true,
|
||||
initial: 5,
|
||||
label: 'DAGGERHEART.CONFIG.Range.melee.name'
|
||||
}),
|
||||
veryClose: new fields.NumberField({
|
||||
required: true,
|
||||
initial: 15,
|
||||
label: 'DAGGERHEART.CONFIG.Range.veryClose.name'
|
||||
}),
|
||||
close: new fields.NumberField({
|
||||
required: true,
|
||||
initial: 30,
|
||||
label: 'DAGGERHEART.CONFIG.Range.close.name'
|
||||
}),
|
||||
far: new fields.NumberField({ required: true, initial: 60, label: 'DAGGERHEART.CONFIG.Range.far.name' })
|
||||
})
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
export { default as DhAppearance } from './Appearance.mjs';
|
||||
export { default as DhAutomation } from './Automation.mjs';
|
||||
export { default as DhHomebrew } from './Homebrew.mjs';
|
||||
export { default as DhRangeMeasurement } from './RangeMeasurement.mjs';
|
||||
export { default as DhVariantRules } from './VariantRules.mjs';
|
||||
|
|
|
|||
|
|
@ -18,9 +18,7 @@ export default class D20Roll extends DHRoll {
|
|||
static DefaultDialog = D20RollDialog;
|
||||
|
||||
get title() {
|
||||
return game.i18n.localize(
|
||||
"DAGGERHEART.GENERAL.d20Roll"
|
||||
);
|
||||
return game.i18n.localize('DAGGERHEART.GENERAL.d20Roll');
|
||||
}
|
||||
|
||||
get d20() {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ export default class DamageRoll extends DHRoll {
|
|||
static DefaultDialog = DamageDialog;
|
||||
|
||||
static async buildEvaluate(roll, config = {}, message = {}) {
|
||||
if (config.evaluate !== false)
|
||||
for (const roll of config.roll) await roll.roll.evaluate();
|
||||
if (config.evaluate !== false) for (const roll of config.roll) await roll.roll.evaluate();
|
||||
|
||||
roll._evaluated = true;
|
||||
const parts = config.roll.map(r => this.postEvaluate(r));
|
||||
|
|
|
|||
|
|
@ -75,7 +75,8 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
|
|||
if (isOriginTarget && change.effect.origin) {
|
||||
change.value = change.value.replaceAll(/origin\.@/gi, '@');
|
||||
try {
|
||||
const doc = foundry.utils.fromUuidSync(change.effect.origin);
|
||||
const effect = foundry.utils.fromUuidSync(change.effect.origin);
|
||||
const doc = effect.parent?.parent;
|
||||
if (doc) parseModel = doc;
|
||||
} catch (_) {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,7 +202,8 @@ export default class DhpActor extends Actor {
|
|||
await this.update({
|
||||
[`system.experiences.${experienceKey}`]: {
|
||||
name: experience.name,
|
||||
value: experience.modifier
|
||||
value: experience.modifier,
|
||||
core: true
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -210,7 +211,8 @@ export default class DhpActor extends Actor {
|
|||
await this.system.companion.update({
|
||||
[`system.experiences.${experienceKey}`]: {
|
||||
name: '',
|
||||
value: experience.modifier
|
||||
value: experience.modifier,
|
||||
core: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -559,8 +561,8 @@ export default class DhpActor extends Actor {
|
|||
|
||||
updates.forEach(
|
||||
u =>
|
||||
(u.value =
|
||||
u.key === 'fear' || this.system?.resources?.[u.key]?.isReversed === false ? u.value * -1 : u.value)
|
||||
(u.value =
|
||||
u.key === 'fear' || this.system?.resources?.[u.key]?.isReversed === false ? u.value * -1 : u.value)
|
||||
);
|
||||
|
||||
await this.modifyResource(updates);
|
||||
|
|
@ -606,9 +608,9 @@ export default class DhpActor extends Actor {
|
|||
|
||||
updates.forEach(
|
||||
u =>
|
||||
(u.value = !(u.key === 'fear' || this.system?.resources?.[u.key]?.isReversed === false)
|
||||
? u.value * -1
|
||||
: u.value)
|
||||
(u.value = !(u.key === 'fear' || this.system?.resources?.[u.key]?.isReversed === false)
|
||||
? u.value * -1
|
||||
: u.value)
|
||||
);
|
||||
|
||||
await this.modifyResource(updates);
|
||||
|
|
|
|||
|
|
@ -74,8 +74,8 @@ export default class DHItem extends foundry.documents.Item {
|
|||
isInventoryItem === true
|
||||
? 'Inventory Items' //TODO localize
|
||||
: isInventoryItem === false
|
||||
? 'Character Items' //TODO localize
|
||||
: 'Other'; //TODO localize
|
||||
? 'Character Items' //TODO localize
|
||||
: 'Other'; //TODO localize
|
||||
|
||||
return { value: type, label, group };
|
||||
}
|
||||
|
|
@ -130,7 +130,6 @@ export default class DHItem extends foundry.documents.Item {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
|
||||
async use(event) {
|
||||
const actions = new Set(this.system.actionsList);
|
||||
if (actions?.size) {
|
||||
|
|
@ -152,10 +151,10 @@ export default class DHItem extends foundry.documents.Item {
|
|||
this.type === 'ancestry'
|
||||
? game.i18n.localize('DAGGERHEART.UI.Chat.foundationCard.ancestryTitle')
|
||||
: this.type === 'community'
|
||||
? game.i18n.localize('DAGGERHEART.UI.Chat.foundationCard.communityTitle')
|
||||
: this.type === 'feature'
|
||||
? game.i18n.localize('TYPES.Item.feature')
|
||||
: game.i18n.localize('DAGGERHEART.UI.Chat.foundationCard.subclassFeatureTitle'),
|
||||
? game.i18n.localize('DAGGERHEART.UI.Chat.foundationCard.communityTitle')
|
||||
: this.type === 'feature'
|
||||
? game.i18n.localize('TYPES.Item.feature')
|
||||
: game.i18n.localize('DAGGERHEART.UI.Chat.foundationCard.subclassFeatureTitle'),
|
||||
origin: origin,
|
||||
img: this.img,
|
||||
item: {
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
|||
for (const [index, itemValue] of pathValue.entries()) {
|
||||
const itemIsAction = itemValue instanceof game.system.api.models.actions.actionsTypes.base;
|
||||
const value = itemIsAction || !itemValue?.item ? itemValue : itemValue.item;
|
||||
const enrichedValue = await TextEditor.enrichHTML(value.description);
|
||||
const enrichedValue = await TextEditor.enrichHTML(value.system?.description ?? value.description);
|
||||
if (itemIsAction) value.enrichedDescription = enrichedValue;
|
||||
else foundry.utils.setProperty(item, `${basePath}.${index}.enrichedDescription`, enrichedValue);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import { range as configRange } from '../config/generalConfig.mjs';
|
||||
|
||||
export default function DhTemplateEnricher(match, _options) {
|
||||
const parts = match[1].split('|').map(x => x.trim());
|
||||
|
||||
|
|
@ -17,7 +15,7 @@ export default function DhTemplateEnricher(match, _options) {
|
|||
type = matchedType;
|
||||
break;
|
||||
case 'range':
|
||||
const matchedRange = Object.values(configRange).find(
|
||||
const matchedRange = Object.values(CONFIG.DH.GENERAL.templateRanges).find(
|
||||
x => x.id.toLowerCase() === split[1] || x.short === split[1]
|
||||
);
|
||||
range = matchedRange?.id;
|
||||
|
|
@ -55,7 +53,9 @@ export const renderMeasuredTemplate = async event => {
|
|||
? '180'
|
||||
: undefined;
|
||||
|
||||
const baseDistance = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.RangeMeasurement)[range];
|
||||
const baseDistance = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).rangeMeasurement[
|
||||
range
|
||||
];
|
||||
const distance = type === CONFIG.DH.GENERAL.templateTypes.EMANATION ? baseDistance + 2.5 : baseDistance;
|
||||
|
||||
const { width, height } = game.canvas.scene.dimensions;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export default class RegisterHandlebarsHelpers {
|
|||
damageSymbols: this.damageSymbols,
|
||||
rollParsed: this.rollParsed,
|
||||
hasProperty: foundry.utils.hasProperty,
|
||||
getProperty: foundry.utils.getProperty,
|
||||
setVar: this.setVar,
|
||||
empty: this.empty
|
||||
});
|
||||
|
|
|
|||
|
|
@ -313,8 +313,10 @@ export const itemAbleRollParse = (value, actor, item) => {
|
|||
|
||||
const isItemTarget = value.toLowerCase().includes('item.@');
|
||||
const slicedValue = isItemTarget ? value.replaceAll(/item\.@/gi, '@') : value;
|
||||
const model = isItemTarget ? item : actor;
|
||||
|
||||
try {
|
||||
return Roll.replaceFormulaData(slicedValue, isItemTarget ? item : actor);
|
||||
return Roll.replaceFormulaData(slicedValue, model?.getRollData?.() ?? model);
|
||||
} catch (_) {
|
||||
return '';
|
||||
}
|
||||
|
|
@ -362,6 +364,7 @@ export async function createEmbeddedItemWithEffects(actor, baseData, update) {
|
|||
const [doc] = await actor.createEmbeddedDocuments('Item', [
|
||||
{
|
||||
...(update ?? data),
|
||||
...baseData,
|
||||
id: data.id,
|
||||
uuid: data.uuid,
|
||||
effects: data.effects?.map(effect => effect.toObject())
|
||||
|
|
@ -371,6 +374,21 @@ export async function createEmbeddedItemWithEffects(actor, baseData, update) {
|
|||
return doc;
|
||||
}
|
||||
|
||||
export async function createEmbeddedItemsWithEffects(actor, baseData) {
|
||||
const effectData = [];
|
||||
for (let d of baseData) {
|
||||
const data = d.uuid.startsWith('Compendium') ? await foundry.utils.fromUuid(d.uuid) : d;
|
||||
effectData.push({
|
||||
...data,
|
||||
id: data.id,
|
||||
uuid: data.uuid,
|
||||
effects: data.effects?.map(effect => effect.toObject())
|
||||
});
|
||||
}
|
||||
|
||||
await actor.createEmbeddedDocuments('Item', effectData);
|
||||
}
|
||||
|
||||
export const slugify = name => {
|
||||
return name.toLowerCase().replaceAll(' ', '-').replaceAll('.', '');
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,17 +1,10 @@
|
|||
import { defaultLevelTiers, DhLevelTiers } from '../data/levelTier.mjs';
|
||||
import DhCountdowns from '../data/countdowns.mjs';
|
||||
import {
|
||||
DhAppearance,
|
||||
DhAutomation,
|
||||
DhHomebrew,
|
||||
DhRangeMeasurement,
|
||||
DhVariantRules
|
||||
} from '../data/settings/_module.mjs';
|
||||
import { DhAppearance, DhAutomation, DhHomebrew, DhVariantRules } from '../data/settings/_module.mjs';
|
||||
import {
|
||||
DhAppearanceSettings,
|
||||
DhAutomationSettings,
|
||||
DhHomebrewSettings,
|
||||
DhRangeMeasurementSettings,
|
||||
DhVariantRuleSettings
|
||||
} from '../applications/settings/_module.mjs';
|
||||
|
||||
|
|
@ -58,12 +51,6 @@ const registerMenuSettings = () => {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.RangeMeasurement, {
|
||||
scope: 'world',
|
||||
config: false,
|
||||
type: DhRangeMeasurement
|
||||
});
|
||||
};
|
||||
|
||||
const registerMenus = () => {
|
||||
|
|
@ -83,14 +70,6 @@ const registerMenus = () => {
|
|||
type: DhHomebrewSettings,
|
||||
restricted: true
|
||||
});
|
||||
game.settings.registerMenu(CONFIG.DH.id, CONFIG.DH.SETTINGS.menu.Range.Name, {
|
||||
name: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.range.name'),
|
||||
label: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.range.label'),
|
||||
hint: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.range.hint'),
|
||||
icon: CONFIG.DH.SETTINGS.menu.Range.Icon,
|
||||
type: DhRangeMeasurementSettings,
|
||||
restricted: true
|
||||
});
|
||||
|
||||
game.settings.registerMenu(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance, {
|
||||
name: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.appearance.title'),
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
"readline": "^1.3.0",
|
||||
"pushLDBtoYML": "node ./tools/pushLDBtoYML.mjs",
|
||||
"pullYMLtoLDB": "node ./tools/pullYMLtoLDB.mjs",
|
||||
"pullYMLtoLDBBuild": "node ./tools/pullYMLtoLDBBuild.mjs",
|
||||
"createSymlink": "node ./tools/create-symlink.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@
|
|||
],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"recovery": null
|
||||
"max": "1",
|
||||
"recovery": "shortRest"
|
||||
},
|
||||
"effects": [],
|
||||
"target": {
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753997061290,
|
||||
"modifiedTime": 1753997114091,
|
||||
"modifiedTime": 1754498245294,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_key": "!items!AXqcoxnRoWBbbKpK"
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@
|
|||
],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"recovery": null
|
||||
"max": "1",
|
||||
"recovery": "session"
|
||||
},
|
||||
"effects": [],
|
||||
"target": {
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753994658436,
|
||||
"modifiedTime": 1753994711690,
|
||||
"modifiedTime": 1754498186961,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_key": "!items!U6iFjZgLYawlOlQZ"
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
},
|
||||
"effects": [
|
||||
{
|
||||
"name": "Base",
|
||||
"name": "Tusks",
|
||||
"type": "base",
|
||||
"_id": "klEyAxQa5YHXVnrl",
|
||||
"img": "icons/creatures/abilities/fang-tooth-blood-red.webp",
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@
|
|||
"suggestedTraits": {
|
||||
"agility": 1,
|
||||
"strength": -1,
|
||||
"finesse": 0,
|
||||
"instinct": 2,
|
||||
"finesse": 2,
|
||||
"instinct": 0,
|
||||
"presence": 1,
|
||||
"knowledge": 0
|
||||
},
|
||||
|
|
@ -76,8 +76,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1754325275832,
|
||||
"modifiedTime": 1754325686143,
|
||||
"lastModifiedBy": "LgnbNMLaxandgMQq"
|
||||
"modifiedTime": 1754500637635,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
},
|
||||
"_key": "!items!CvHlkHZfpMiCz5uT"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,15 +6,7 @@
|
|||
"img": "icons/magic/unholy/strike-body-explode-disintegrate.webp",
|
||||
"system": {
|
||||
"description": "<p>Once per long rest, you can place a domain card from your loadout into your vault and choose to either:</p><ul><li><p>Gain Hope equal to the level of the card.</p></li><li><p>Enhance a spell that deals damage, gaining a bonus to your damage roll equal to twice the level of the card.</p></li></ul>",
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 1,
|
||||
"max": "1",
|
||||
"icon": "",
|
||||
"recovery": "longRest",
|
||||
"diceStates": {},
|
||||
"dieFaces": "d4"
|
||||
},
|
||||
"resource": null,
|
||||
"actions": {
|
||||
"YFmqnbMx540su2Ni": {
|
||||
"type": "effect",
|
||||
|
|
@ -26,17 +18,17 @@
|
|||
"cost": [
|
||||
{
|
||||
"scalable": false,
|
||||
"key": "P02cbN50LIoD662z",
|
||||
"key": "hitPoints",
|
||||
"value": 1,
|
||||
"keyIsID": true,
|
||||
"keyIsID": false,
|
||||
"step": null,
|
||||
"consumeOnSuccess": false
|
||||
}
|
||||
],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"recovery": null,
|
||||
"max": "1",
|
||||
"recovery": "longRest",
|
||||
"consumeOnSuccess": false
|
||||
},
|
||||
"effects": [],
|
||||
|
|
@ -67,8 +59,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1754349703843,
|
||||
"modifiedTime": 1754349703843,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754498040342,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_key": "!items!P02cbN50LIoD662z"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,7 @@
|
|||
"img": "icons/tools/instruments/drum-hand-tan.webp",
|
||||
"system": {
|
||||
"description": "<p>Once per session, describe how you rally the party and give yourself and each of your allies a Rally Die. At level 1, your Rally Die is a d6. A PC can spend their Rally Die to roll it, adding the result to their action roll, reaction roll, damage roll, or to clear a number of Stress equal to the result. At the end of each session, clear all unspent Rally Dice. At level 5, your Rally Die increases to a d8.</p>",
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 1,
|
||||
"max": "1",
|
||||
"icon": "",
|
||||
"recovery": "session",
|
||||
"diceStates": {},
|
||||
"dieFaces": "d4"
|
||||
},
|
||||
"resource": null,
|
||||
"actions": {
|
||||
"vI4Fph3y9ygsya9e": {
|
||||
"type": "effect",
|
||||
|
|
@ -25,7 +17,7 @@
|
|||
"cost": [],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"max": "1",
|
||||
"recovery": "session"
|
||||
},
|
||||
"effects": [
|
||||
|
|
@ -106,8 +98,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1754174497668,
|
||||
"modifiedTime": 1754246215191,
|
||||
"lastModifiedBy": "LgnbNMLaxandgMQq"
|
||||
"modifiedTime": 1754494820213,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"ownership": {
|
||||
"default": 0,
|
||||
|
|
|
|||
|
|
@ -5,15 +5,7 @@
|
|||
"img": "icons/tools/instruments/drum-hand-tan.webp",
|
||||
"system": {
|
||||
"description": "<p>Once per session, describe how you rally the party and give yourself and each of your allies a Rally Die. At level 1, your Rally Die is a d6. A PC can spend their Rally Die to roll it, adding the result to their action roll, reaction roll, damage roll, or to clear a number of Stress equal to the result. At the end of each session, clear all unspent Rally Dice. At level 5, your Rally Die increases to a d8.</p>",
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 1,
|
||||
"max": "1",
|
||||
"icon": "",
|
||||
"recovery": "session",
|
||||
"diceStates": {},
|
||||
"dieFaces": "d4"
|
||||
},
|
||||
"resource": null,
|
||||
"actions": {
|
||||
"Z1KWFrpXOqZWuZD1": {
|
||||
"type": "effect",
|
||||
|
|
@ -25,7 +17,7 @@
|
|||
"cost": [],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"max": "1",
|
||||
"recovery": "session"
|
||||
},
|
||||
"effects": [
|
||||
|
|
@ -106,8 +98,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1754174499893,
|
||||
"modifiedTime": 1754246215922,
|
||||
"lastModifiedBy": "LgnbNMLaxandgMQq"
|
||||
"modifiedTime": 1754494835723,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"ownership": {
|
||||
"default": 0,
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@
|
|||
"system": {
|
||||
"description": "<p>Choose a number between 1 and 12. When you roll that number on a Duality Die, gain a Hope or clear a Stress.</p><p></p><p>You can change this number when you take a long rest.</p>",
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"type": "diceValue",
|
||||
"value": 1,
|
||||
"max": "",
|
||||
"icon": "fa-solid fa-hashtag"
|
||||
"max": "1",
|
||||
"icon": "fa-solid fa-hashtag",
|
||||
"dieFaces": "d12"
|
||||
},
|
||||
"actions": {
|
||||
"RkqPzF1bdWzPPMml": {
|
||||
|
|
@ -100,7 +101,7 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1754254942995,
|
||||
"modifiedTime": 1754255067467,
|
||||
"modifiedTime": 1754498121727,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_key": "!items!6YsfFjmCGuFYVhT4"
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1754010247432,
|
||||
"modifiedTime": 1754010247432,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754498464092,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"sort": 0,
|
||||
"ownership": {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@
|
|||
}
|
||||
],
|
||||
"roll": {
|
||||
"type": null,
|
||||
"type": "spellcast",
|
||||
"trait": null,
|
||||
"difficulty": null,
|
||||
"bonus": null,
|
||||
|
|
@ -154,8 +154,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784434,
|
||||
"modifiedTime": 1754253433766,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754475145346,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "5EP2Lgf7ojfrc0Is",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@
|
|||
"cost": [],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"recovery": null,
|
||||
"consumeOnSuccess": false
|
||||
"max": "1",
|
||||
"recovery": "longRest",
|
||||
"consumeOnSuccess": true
|
||||
},
|
||||
"damage": {
|
||||
"parts": [],
|
||||
|
|
@ -128,8 +128,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784437,
|
||||
"modifiedTime": 1754254161910,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754501480068,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "R8NDiJXJWmC48WSr",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -9,12 +9,31 @@
|
|||
"recallCost": 3,
|
||||
"level": 9,
|
||||
"type": "spell",
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 1,
|
||||
"recovery": "longRest",
|
||||
"max": "1",
|
||||
"icon": ""
|
||||
"resource": null,
|
||||
"actions": {
|
||||
"RKEceNKiQirYwN45": {
|
||||
"type": "effect",
|
||||
"_id": "RKEceNKiQirYwN45",
|
||||
"systemPath": "actions",
|
||||
"description": "<p class=\"Body-Foundation\">Once per long rest, this card can mimic the features of another domain card of level 8 or lower in another player’s loadout. <strong>Spend Hope equal to half the card’s level</strong> to gain access to the feature. It lasts until your next rest or they place the card in their vault.</p>",
|
||||
"chatDisplay": true,
|
||||
"actionType": "action",
|
||||
"cost": [],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "1",
|
||||
"recovery": "longRest",
|
||||
"consumeOnSuccess": false
|
||||
},
|
||||
"effects": [],
|
||||
"target": {
|
||||
"type": "any",
|
||||
"amount": null
|
||||
},
|
||||
"name": "Mimic",
|
||||
"img": "icons/magic/perception/hand-eye-black.webp",
|
||||
"range": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -26,8 +45,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784439,
|
||||
"modifiedTime": 1754329311656,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754499898585,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "3A7LZ1xmDEMGa165",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@
|
|||
],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"recovery": null,
|
||||
"consumeOnSuccess": false
|
||||
"max": "1",
|
||||
"recovery": "shortRest",
|
||||
"consumeOnSuccess": true
|
||||
},
|
||||
"damage": {
|
||||
"parts": [
|
||||
|
|
@ -99,13 +99,7 @@
|
|||
"range": "veryFar"
|
||||
}
|
||||
},
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 1,
|
||||
"recovery": "shortRest",
|
||||
"max": "1",
|
||||
"icon": ""
|
||||
}
|
||||
"resource": null
|
||||
},
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
|
|
@ -116,8 +110,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784449,
|
||||
"modifiedTime": 1754254262215,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754501560924,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "C0qLOwSSvZ6PG3Ws",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -31,7 +31,12 @@
|
|||
"type": "any",
|
||||
"amount": null
|
||||
},
|
||||
"effects": [],
|
||||
"effects": [
|
||||
{
|
||||
"_id": "EYG5dLImk6GkmfRd",
|
||||
"onSave": false
|
||||
}
|
||||
],
|
||||
"roll": {
|
||||
"type": "spellcast",
|
||||
"trait": null,
|
||||
|
|
@ -127,7 +132,7 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784451,
|
||||
"modifiedTime": 1754340901029,
|
||||
"modifiedTime": 1754500747453,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
},
|
||||
"_id": "a8lFiKX1o8T924ze",
|
||||
|
|
@ -135,6 +140,10 @@
|
|||
"effects": [
|
||||
{
|
||||
"name": "Enraptured",
|
||||
"img": "icons/magic/control/hypnosis-mesmerism-eye.webp",
|
||||
"origin": "Compendium.daggerheart.domains.Item.a8lFiKX1o8T924ze",
|
||||
"transfer": false,
|
||||
"_id": "EYG5dLImk6GkmfRd",
|
||||
"type": "base",
|
||||
"system": {
|
||||
"rangeDependence": {
|
||||
|
|
@ -144,8 +153,6 @@
|
|||
"range": "melee"
|
||||
}
|
||||
},
|
||||
"_id": "FOQ2yqrpl2TPVxvt",
|
||||
"img": "icons/magic/control/hypnosis-mesmerism-eye.webp",
|
||||
"changes": [],
|
||||
"disabled": false,
|
||||
"duration": {
|
||||
|
|
@ -157,10 +164,8 @@
|
|||
"startRound": null,
|
||||
"startTurn": null
|
||||
},
|
||||
"description": "<p><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">While </span><span style=\"box-sizing:border-box;scrollbar-width:thin;scrollbar-color:rgb(93, 20, 43) rgba(0, 0, 0, 0);color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial\">Enraptured</span><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">, a target’s attention is fixed on you, narrowing their field of view and drowning out any sound but your voice.</span></p>",
|
||||
"origin": null,
|
||||
"description": "<p>While <em>Enraptured</em>, a target’s attention is fixed on you, narrowing their field of view and drowning out any sound but your voice.</p>",
|
||||
"tint": "#ffffff",
|
||||
"transfer": true,
|
||||
"statuses": [],
|
||||
"sort": 0,
|
||||
"flags": {},
|
||||
|
|
@ -171,11 +176,11 @@
|
|||
"coreVersion": "13.346",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1754106690796,
|
||||
"modifiedTime": 1754340886910,
|
||||
"createdTime": 1754500747406,
|
||||
"modifiedTime": 1754500810477,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
},
|
||||
"_key": "!items.effects!a8lFiKX1o8T924ze.FOQ2yqrpl2TPVxvt"
|
||||
"_key": "!items.effects!a8lFiKX1o8T924ze.EYG5dLImk6GkmfRd"
|
||||
}
|
||||
],
|
||||
"ownership": {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"type": "domainCard",
|
||||
"folder": "7Cs44YADBTmmtCw6",
|
||||
"system": {
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll</strong> against all adversaries within Far range. <strong>Mark any number of Stress</strong> to make shards of arcana rain down from above. Targets you succeed against take <strong>1d20+2</strong> magic damage for each Stress marked.</p>",
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll</strong> against all adversaries within Far range. <strong>Mark any number of Stress</strong> to make shards of arcana rain down from above. Targets you succeed against take <strong>1d20+2</strong> magic damage for each Stress marked.</p><p>@Template[type:emanation|range:f]</p>",
|
||||
"domain": "arcana",
|
||||
"recallCost": 1,
|
||||
"level": 10,
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
"type": "attack",
|
||||
"_id": "xJfXJDVsBayGaqkr",
|
||||
"systemPath": "actions",
|
||||
"description": "<p>Make a <strong>Spellcast Roll</strong> against all adversaries within Far range. <strong>Mark any number of Stress</strong> to make shards of arcana rain down from above. Targets you succeed against take <strong>1d20+2</strong> magic damage for each Stress marked.</p>",
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll</strong> against all adversaries within Far range. <strong>Mark any number of Stress</strong> to make shards of arcana rain down from above. Targets you succeed against take <strong>1d20+2</strong> magic damage for each Stress marked.</p><p>@Template[type:emanation|range:f]</p>",
|
||||
"chatDisplay": true,
|
||||
"actionType": "action",
|
||||
"cost": [
|
||||
|
|
@ -103,8 +103,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784452,
|
||||
"modifiedTime": 1754254370187,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754501517016,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "hZJp9mdkMnqKDROe",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@
|
|||
],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"recovery": null
|
||||
"max": "1",
|
||||
"recovery": "longRest"
|
||||
},
|
||||
"effects": [
|
||||
{
|
||||
|
|
@ -56,7 +56,7 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784460,
|
||||
"modifiedTime": 1754242182536,
|
||||
"modifiedTime": 1754498928489,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "SgvjJfMyubZowPxS",
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@
|
|||
"effects": [
|
||||
{
|
||||
"name": "Gifted Tracker",
|
||||
"img": "icons/svg/item-bag.svg",
|
||||
"img": "systems/daggerheart/assets/icons/domains/domain-card/sage.png",
|
||||
"origin": "Compendium.daggerheart.domains.Item.VZ2b4zfRzV73XTuT",
|
||||
"transfer": false,
|
||||
"_id": "47Oh2weCdmuvKHM9",
|
||||
|
|
@ -104,12 +104,12 @@
|
|||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.346",
|
||||
"coreVersion": "13.347",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1754114056078,
|
||||
"modifiedTime": 1754114073478,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754670410126,
|
||||
"lastModifiedBy": "49DaecTcBSc5d0DA"
|
||||
},
|
||||
"_key": "!items.effects!VZ2b4zfRzV73XTuT.47Oh2weCdmuvKHM9"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,7 +173,8 @@
|
|||
"value": 1,
|
||||
"recovery": "longRest",
|
||||
"max": "1",
|
||||
"icon": ""
|
||||
"icon": "",
|
||||
"progression": "decreasing"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -185,8 +186,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784466,
|
||||
"modifiedTime": 1754338717920,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754499077474,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "GlRm1Dxlc0Z1b04o",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@
|
|||
"effects": [
|
||||
{
|
||||
"name": "Healed by Healing Hands",
|
||||
"img": "icons/svg/item-bag.svg",
|
||||
"img": "systems/daggerheart/assets/icons/domains/domain-card/splendor.png",
|
||||
"origin": "Compendium.daggerheart.domains.Item.WTlhnQMajc1r8i50",
|
||||
"transfer": false,
|
||||
"_id": "sd5liP4ZcVeTMAoW",
|
||||
|
|
@ -422,12 +422,12 @@
|
|||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.346",
|
||||
"coreVersion": "13.347",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1754263407455,
|
||||
"modifiedTime": 1754263727114,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754670504951,
|
||||
"lastModifiedBy": "49DaecTcBSc5d0DA"
|
||||
},
|
||||
"_key": "!items.effects!WTlhnQMajc1r8i50.sd5liP4ZcVeTMAoW"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@
|
|||
"value": 0,
|
||||
"recovery": "longRest",
|
||||
"max": "@system.traits.presence.value",
|
||||
"icon": ""
|
||||
"icon": "",
|
||||
"progression": "decreasing"
|
||||
},
|
||||
"actions": {
|
||||
"5sGMd6m6Ltahit4h": {
|
||||
|
|
@ -253,8 +254,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784473,
|
||||
"modifiedTime": 1754340989544,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754499693699,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "cWu1o82ZF7GvnbXc",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@
|
|||
"effects": [
|
||||
{
|
||||
"name": "Life Ward",
|
||||
"img": "icons/svg/item-bag.svg",
|
||||
"img": "systems/daggerheart/assets/icons/domains/domain-card/splendor.png",
|
||||
"origin": "Compendium.daggerheart.domains.Item.OszbCj0jTqq2ADx9",
|
||||
"transfer": false,
|
||||
"_id": "E7Ou4OMEy3TeK1Gf",
|
||||
|
|
@ -99,12 +99,12 @@
|
|||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.346",
|
||||
"coreVersion": "13.347",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1754264687962,
|
||||
"modifiedTime": 1754264717646,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754670535710,
|
||||
"lastModifiedBy": "49DaecTcBSc5d0DA"
|
||||
},
|
||||
"_key": "!items.effects!OszbCj0jTqq2ADx9.E7Ou4OMEy3TeK1Gf"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"type": "domainCard",
|
||||
"folder": "7O1tTswJMNdPgLsx",
|
||||
"system": {
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll</strong> against all targets within Far range. Targets you succeed against become temporarily <em>Enraptured</em>. While <em>Enraptured</em>, a target’s attention is fixed on you, narrowing their field of view and drowning out any sound but your voice. <strong>Mark a Stress</strong> to force all <em>Enraptured</em> targets to mark a Stress, ending this spell.</p>",
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll</strong> against all targets within Far range. Targets you succeed against become temporarily <em>Enraptured</em>. While <em>Enraptured</em>, a target’s attention is fixed on you, narrowing their field of view and drowning out any sound but your voice. <strong>Mark a Stress</strong> to force all <em>Enraptured</em> targets to mark a Stress, ending this spell.</p><p>@Template[type:emanation|range:f]</p>",
|
||||
"domain": "grace",
|
||||
"recallCost": 3,
|
||||
"level": 8,
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
"type": "attack",
|
||||
"_id": "r5eA3tAH7EplOQCP",
|
||||
"systemPath": "actions",
|
||||
"description": "<p>Make a <strong>Spellcast Roll</strong> against all targets within Far range. Targets you succeed against become temporarily <em>Enraptured</em>. While <em>Enraptured</em>, a target’s attention is fixed on you, narrowing their field of view and drowning out any sound but your voice.</p>",
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll</strong> against all targets within Far range. Targets you succeed against become temporarily <em>Enraptured</em>. While <em>Enraptured</em>, a target’s attention is fixed on you, narrowing their field of view and drowning out any sound but your voice. <strong>Mark a Stress</strong> to force all <em>Enraptured</em> targets to mark a Stress, ending this spell.</p><p>@Template[type:emanation|range:f]</p>",
|
||||
"chatDisplay": true,
|
||||
"actionType": "action",
|
||||
"cost": [],
|
||||
|
|
@ -132,8 +132,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784481,
|
||||
"modifiedTime": 1754342040215,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754499825008,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "ubpixIgZrJXKyM3b",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -338,9 +338,10 @@
|
|||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 1,
|
||||
"recovery": "longRest",
|
||||
"progression": "decreasing",
|
||||
"max": "1",
|
||||
"icon": ""
|
||||
"icon": "fa-solid fa-hands-praying",
|
||||
"recovery": "longRest"
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
|
|
@ -352,8 +353,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784482,
|
||||
"modifiedTime": 1754269394280,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754498631054,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "TGjR4vJVNbQRV8zr",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"type": "domainCard",
|
||||
"folder": "2rqOUxEglhhPKk2j",
|
||||
"system": {
|
||||
"description": "<p class=\"Body-Foundation\">Once per long rest, choose any targets within Very Close range to perceive you as a nightmarish horror. The targets must succeed on a Reaction Roll (16) or become temporarily <em>Horrified</em>. While <em>Horrified</em>, they’re <em>Vulnerable</em>. Steal a number of Fear from the GM equal to the number of targets that are <em>Horrified</em> (up to the number of Fear in the GM’s pool). Roll a number of <strong>d6s</strong> equal to the number of stolen Fear and deal the total damage to each <em>Horrified</em> target. Discard the stolen Fear.</p>",
|
||||
"description": "<p class=\"Body-Foundation\">Once per long rest, choose any targets within Very Close range to perceive you as a nightmarish horror. The targets must succeed on a Reaction Roll (16) or become temporarily <em>Horrified</em>. While <em>Horrified</em>, they’re <em>Vulnerable</em>. Steal a number of Fear from the GM equal to the number of targets that are <em>Horrified</em> (up to the number of Fear in the GM’s pool). Roll a number of <strong>d6s</strong> equal to the number of stolen Fear and deal the total damage to each <em>Horrified</em> target. Discard the stolen Fear.</p><p>@Template[type:emanation|range:vc]</p>",
|
||||
"domain": "midnight",
|
||||
"recallCost": 2,
|
||||
"level": 9,
|
||||
|
|
@ -14,14 +14,14 @@
|
|||
"type": "attack",
|
||||
"_id": "e4A6GQERsn08IBby",
|
||||
"systemPath": "actions",
|
||||
"description": "<p>Once per long rest, choose any targets within Very Close range to perceive you as a nightmarish horror. The targets must succeed on a Reaction Roll (16) or become temporarily <em>Horrified</em>. While <em>Horrified</em>, they’re <em>Vulnerable</em>. Steal a number of Fear from the GM equal to the number of targets that are <em>Horrified</em> (up to the number of Fear in the GM’s pool). Roll a number of <strong>d6s</strong> equal to the number of stolen Fear and deal the total damage to each <em>Horrified</em> target. Discard the stolen Fear.</p><p></p>",
|
||||
"description": "<p class=\"Body-Foundation\">Once per long rest, choose any targets within Very Close range to perceive you as a nightmarish horror. The targets must succeed on a Reaction Roll (16) or become temporarily <em>Horrified</em>. While <em>Horrified</em>, they’re <em>Vulnerable</em>. Steal a number of Fear from the GM equal to the number of targets that are <em>Horrified</em> (up to the number of Fear in the GM’s pool). Roll a number of <strong>d6s</strong> equal to the number of stolen Fear and deal the total damage to each <em>Horrified</em> target. Discard the stolen Fear.</p><p>@Template[type:emanation|range:vc]</p>",
|
||||
"chatDisplay": true,
|
||||
"actionType": "action",
|
||||
"cost": [],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"recovery": null
|
||||
"max": "1",
|
||||
"recovery": "longRest"
|
||||
},
|
||||
"damage": {
|
||||
"parts": [],
|
||||
|
|
@ -121,12 +121,7 @@
|
|||
"range": ""
|
||||
}
|
||||
},
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 0,
|
||||
"max": "",
|
||||
"icon": ""
|
||||
}
|
||||
"resource": null
|
||||
},
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
|
|
@ -137,8 +132,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784487,
|
||||
"modifiedTime": 1754331219352,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754499654051,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "zcldCuqOg3dphUVI",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
}
|
||||
},
|
||||
"_id": "UJTsJlnhi5Zi0XQ2",
|
||||
"img": "icons/magic/life/heart-cross-blue.webp",
|
||||
"img": "systems/daggerheart/assets/icons/domains/domain-card/bone.png",
|
||||
"changes": [
|
||||
{
|
||||
"key": "system.rules.damageReduction.thresholdImmunities.minor",
|
||||
|
|
@ -67,12 +67,12 @@
|
|||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.346",
|
||||
"coreVersion": "13.347",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1754303484332,
|
||||
"modifiedTime": 1754303570504,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
"modifiedTime": 1754670012467,
|
||||
"lastModifiedBy": "49DaecTcBSc5d0DA"
|
||||
},
|
||||
"_key": "!items.effects!zbxPl81kbWEegKQN.UJTsJlnhi5Zi0XQ2"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@
|
|||
"uses": {
|
||||
"value": null,
|
||||
"max": "1",
|
||||
"recovery": "longRest"
|
||||
"recovery": "longRest",
|
||||
"consumeOnSuccess": true
|
||||
},
|
||||
"damage": {
|
||||
"parts": [],
|
||||
|
|
@ -67,8 +68,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784493,
|
||||
"modifiedTime": 1754340285152,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754499238543,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "9a6xP5pxhVvdugk9",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
"actionType": "action",
|
||||
"cost": [],
|
||||
"uses": {
|
||||
"value": 1,
|
||||
"value": 0,
|
||||
"max": "1",
|
||||
"recovery": "shortRest",
|
||||
"consumeOnSuccess": false
|
||||
|
|
@ -44,8 +44,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784499,
|
||||
"modifiedTime": 1754269219077,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754498645559,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "iYNVTB7uAD1FTCZu",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"type": "domainCard",
|
||||
"folder": "qY4Zqc1Ch6p317uK",
|
||||
"system": {
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll (15)</strong>. Once per rest on a success, create a temporary barrier of protective energy around you at Very Close range. You and all allies within the barrier when this spell is cast clear <strong>1d4</strong> Hit Points. While the barrier is up, you and all allies within have resistance to physical damage from outside the barrier.</p><p class=\"Body-Foundation\">When you move, the barrier follows you.</p>",
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll (15)</strong>. Once per rest on a success, create a temporary barrier of protective energy around you at Very Close range. You and all allies within the barrier when this spell is cast clear <strong>1d4</strong> Hit Points. While the barrier is up, you and all allies within have resistance to physical damage from outside the barrier.</p><p class=\"Body-Foundation\">When you move, the barrier follows you.</p><p>@Template[type:emanation|range:vc]</p>",
|
||||
"domain": "sage",
|
||||
"recallCost": 1,
|
||||
"level": 8,
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
"type": "healing",
|
||||
"_id": "XdAwXl2uWNinInFe",
|
||||
"systemPath": "actions",
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll (15)</strong>. Once per rest on a success, create a temporary barrier of protective energy around you at Very Close range. You and all allies within the barrier when this spell is cast clear <strong>1d4</strong> Hit Points. While the barrier is up, you and all allies within have resistance to physical damage from outside the barrier.</p><p class=\"Body-Foundation\">When you move, the barrier follows you.</p>",
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll (15)</strong>. Once per rest on a success, create a temporary barrier of protective energy around you at Very Close range. You and all allies within the barrier when this spell is cast clear <strong>1d4</strong> Hit Points. While the barrier is up, you and all allies within have resistance to physical damage from outside the barrier.</p><p class=\"Body-Foundation\">When you move, the barrier follows you.</p><p>@Template[type:emanation|range:vc]</p>",
|
||||
"chatDisplay": true,
|
||||
"actionType": "action",
|
||||
"cost": [],
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
"value": null,
|
||||
"max": "1",
|
||||
"recovery": "shortRest",
|
||||
"consumeOnSuccess": false
|
||||
"consumeOnSuccess": true
|
||||
},
|
||||
"damage": {
|
||||
"parts": [
|
||||
|
|
@ -93,8 +93,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784502,
|
||||
"modifiedTime": 1754339870857,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754499308449,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "HtWx5IIemCoorMj2",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@
|
|||
"value": 0,
|
||||
"recovery": "longRest",
|
||||
"max": "@cast",
|
||||
"icon": ""
|
||||
"icon": "",
|
||||
"progression": "decreasing"
|
||||
},
|
||||
"actions": {
|
||||
"udmHKUtCDClxeB4h": {
|
||||
|
|
@ -214,8 +215,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784502,
|
||||
"modifiedTime": 1754269768509,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754498742091,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "wUQFsRtww18naYaq",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"type": "domainCard",
|
||||
"folder": "Abn46nCQst6kpGeA",
|
||||
"system": {
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll</strong> against all adversaries within Very Close range. Targets you succeed against are temporarily <em>Restrained</em> as their shadow binds them in place.</p>",
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll</strong> against all adversaries within Very Close range. Targets you succeed against are temporarily <em>Restrained</em> as their shadow binds them in place.</p><p>@Template[type:emanation|range:vc]</p>",
|
||||
"domain": "midnight",
|
||||
"recallCost": 0,
|
||||
"level": 2,
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
"type": "attack",
|
||||
"_id": "Llr9uIDUCrfsiZNn",
|
||||
"systemPath": "actions",
|
||||
"description": "<p><span style=\"color: rgb(239, 230, 216); font-family: Montserrat, sans-serif; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgba(24, 22, 46, 0.376); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none\">Make a </span><span class=\"tooltip-convert\" style=\"box-sizing: border-box; scrollbar-width: thin; scrollbar-color: rgb(93, 20, 43) rgba(0, 0, 0, 0); color: rgb(239, 230, 216); font-family: Montserrat, sans-serif; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgba(24, 22, 46, 0.376); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial\"><strong style=\"box-sizing: border-box; scrollbar-width: thin; scrollbar-color: rgb(93, 20, 43) rgba(0, 0, 0, 0);\">Spellcast Roll</strong></span><span style=\"color: rgb(239, 230, 216); font-family: Montserrat, sans-serif; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgba(24, 22, 46, 0.376); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none\"> against all adversaries within </span><span class=\"tooltip-convert\" style=\"box-sizing: border-box; scrollbar-width: thin; scrollbar-color: rgb(93, 20, 43) rgba(0, 0, 0, 0); color: rgb(239, 230, 216); font-family: Montserrat, sans-serif; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgba(24, 22, 46, 0.376); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial\">Very Close</span><span style=\"color: rgb(239, 230, 216); font-family: Montserrat, sans-serif; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgba(24, 22, 46, 0.376); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none\"> range. Targets you succeed against are temporarily </span><span class=\"tooltip-convert\" style=\"box-sizing: border-box; scrollbar-width: thin; scrollbar-color: rgb(93, 20, 43) rgba(0, 0, 0, 0); color: rgb(239, 230, 216); font-family: Montserrat, sans-serif; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgba(24, 22, 46, 0.376); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial\"><em style=\"box-sizing: border-box; scrollbar-width: thin; scrollbar-color: rgb(93, 20, 43) rgba(0, 0, 0, 0);\">Restrained</em> </span><span style=\"color: rgb(239, 230, 216); font-family: Montserrat, sans-serif; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgba(24, 22, 46, 0.376); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none\">as their shadow binds them in place.</span></p>",
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll</strong> against all adversaries within Very Close range. Targets you succeed against are temporarily <em>Restrained</em> as their shadow binds them in place.</p><p>@Template[type:emanation|range:vc]</p>",
|
||||
"chatDisplay": true,
|
||||
"actionType": "action",
|
||||
"cost": [],
|
||||
|
|
@ -72,8 +72,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784512,
|
||||
"modifiedTime": 1754330643864,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754499502570,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "kguhWlidhxe2GbT0",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,31 @@
|
|||
"recallCost": 0,
|
||||
"level": 6,
|
||||
"type": "spell",
|
||||
"actions": {}
|
||||
"actions": {
|
||||
"MjSx44ovuKBGVKGs": {
|
||||
"type": "effect",
|
||||
"_id": "MjSx44ovuKBGVKGs",
|
||||
"systemPath": "actions",
|
||||
"description": "<p class=\"Body-Foundation\">Once per rest, take on the Stress from a willing creature within Melee range. The target describes what intimate knowledge or emotions telepathically leak from their mind in this moment between you. Transfer any number of their marked Stress to you, then gain a Hope for each Stress transferred.</p>",
|
||||
"chatDisplay": true,
|
||||
"actionType": "action",
|
||||
"cost": [],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "1",
|
||||
"recovery": "shortRest",
|
||||
"consumeOnSuccess": false
|
||||
},
|
||||
"effects": [],
|
||||
"target": {
|
||||
"type": "any",
|
||||
"amount": null
|
||||
},
|
||||
"name": "Take Stress",
|
||||
"img": "systems/daggerheart/assets/icons/domains/domain-card/grace.png",
|
||||
"range": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
|
|
@ -20,8 +44,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784515,
|
||||
"modifiedTime": 1754327488946,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754499760780,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "8nRle10pw1HO8QVu",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@
|
|||
],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"recovery": null,
|
||||
"max": "1",
|
||||
"recovery": "shortRest",
|
||||
"consumeOnSuccess": false
|
||||
},
|
||||
"effects": [
|
||||
|
|
@ -58,8 +58,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784519,
|
||||
"modifiedTime": 1754269704377,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754498725946,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "U1uWJE94HZVudujz",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
"level": 9,
|
||||
"type": "ability",
|
||||
"actions": {
|
||||
"B4vyaTibK0GiRBCW": {
|
||||
"type": "effect",
|
||||
"_id": "B4vyaTibK0GiRBCW",
|
||||
"yjEcSlzsWGX79gpB": {
|
||||
"type": "attack",
|
||||
"_id": "yjEcSlzsWGX79gpB",
|
||||
"systemPath": "actions",
|
||||
"description": "<p class=\"Body-Foundation\"><strong>Spend a Hope</strong> and make an attack against all adversaries within your weapon’s range. Once per long rest, on a success against any targets, add up the damage dealt, then redistribute that damage however you wish between the targets you succeeded against. When you deal damage to a target, roll an additional damage die and add its result to the damage you deal to that target.</p>",
|
||||
"chatDisplay": true,
|
||||
|
|
@ -29,15 +29,39 @@
|
|||
],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"recovery": null,
|
||||
"consumeOnSuccess": false
|
||||
"max": "1",
|
||||
"recovery": "longRest",
|
||||
"consumeOnSuccess": true
|
||||
},
|
||||
"damage": {
|
||||
"parts": [],
|
||||
"includeBase": false
|
||||
},
|
||||
"effects": [],
|
||||
"target": {
|
||||
"type": "any",
|
||||
"amount": null
|
||||
},
|
||||
"effects": [],
|
||||
"roll": {
|
||||
"type": "attack",
|
||||
"trait": null,
|
||||
"difficulty": null,
|
||||
"bonus": null,
|
||||
"advState": "neutral",
|
||||
"diceRolling": {
|
||||
"multiplier": "prof",
|
||||
"flatMultiplier": 1,
|
||||
"dice": "d6",
|
||||
"compare": null,
|
||||
"treshold": null
|
||||
},
|
||||
"useDefault": false
|
||||
},
|
||||
"save": {
|
||||
"trait": null,
|
||||
"difficulty": null,
|
||||
"damageMod": "none"
|
||||
},
|
||||
"name": "Spend Hope",
|
||||
"img": "icons/skills/melee/strike-sword-steel-yellow.webp",
|
||||
"range": ""
|
||||
|
|
@ -53,7 +77,7 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784522,
|
||||
"modifiedTime": 1754252510860,
|
||||
"modifiedTime": 1754501075258,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "TYKfM3H9vBXyWiH4",
|
||||
|
|
|
|||
|
|
@ -11,10 +11,11 @@
|
|||
"type": "ability",
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 1,
|
||||
"max": "",
|
||||
"value": 0,
|
||||
"max": "max(@system.traits.knowledge.value, 1)",
|
||||
"icon": "fa-solid fa-bullseye",
|
||||
"recovery": "longRest"
|
||||
"recovery": "longRest",
|
||||
"progression": "decreasing"
|
||||
},
|
||||
"actions": {
|
||||
"jTC0GbsBpGmaQLi7": {
|
||||
|
|
@ -60,7 +61,7 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784523,
|
||||
"modifiedTime": 1754249661976,
|
||||
"modifiedTime": 1754501630846,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "5b1awkgTmMp3FVrm",
|
||||
|
|
|
|||
|
|
@ -108,16 +108,17 @@
|
|||
"cost": [
|
||||
{
|
||||
"scalable": false,
|
||||
"key": "n0P3VS1WfxvmXbB6",
|
||||
"key": "hitPoints",
|
||||
"value": 1,
|
||||
"keyIsID": true,
|
||||
"step": null
|
||||
"keyIsID": false,
|
||||
"step": null,
|
||||
"consumeOnSuccess": false
|
||||
}
|
||||
],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"recovery": null
|
||||
"max": "1",
|
||||
"recovery": "shortRest"
|
||||
},
|
||||
"effects": [],
|
||||
"target": {
|
||||
|
|
@ -129,13 +130,7 @@
|
|||
"range": ""
|
||||
}
|
||||
},
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 1,
|
||||
"recovery": "shortRest",
|
||||
"max": "1",
|
||||
"icon": ""
|
||||
}
|
||||
"resource": null
|
||||
},
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
|
|
@ -146,8 +141,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784534,
|
||||
"modifiedTime": 1754338673637,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754499113867,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "n0P3VS1WfxvmXbB6",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@
|
|||
"value": 0,
|
||||
"max": "@cast",
|
||||
"icon": "",
|
||||
"recovery": "session"
|
||||
"recovery": "session",
|
||||
"progression": "decreasing"
|
||||
},
|
||||
"actions": {
|
||||
"MWvrKuwejWcQm7N1": {
|
||||
|
|
@ -143,8 +144,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784537,
|
||||
"modifiedTime": 1754253370819,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754501257508,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "o62i0QdbUDIiAhSq",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
"type": "effect",
|
||||
"_id": "nYu6LRNVDKfWUJhx",
|
||||
"systemPath": "actions",
|
||||
"description": "",
|
||||
"description": "<p class=\"Body-Foundation\">Once per long rest, <strong>mark a Stress</strong> to channel the natural world around you and enhance yourself. Describe how your appearance changes, then place a <strong>d6</strong> on this card with the 1 value facing up.</p><p class=\"Body-Foundation\">While the Wild Surge Die is active, you add its value to every action roll you make. After you add its value to a roll, increase the Wild Surge Die’s value by one. When the die’s value would exceed 6 or you take a rest, this form drops and you must <strong>mark an additional Stress</strong>.</p>",
|
||||
"chatDisplay": true,
|
||||
"actionType": "action",
|
||||
"cost": [
|
||||
|
|
@ -34,8 +34,8 @@
|
|||
],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"recovery": null
|
||||
"max": "1",
|
||||
"recovery": "longRest"
|
||||
},
|
||||
"effects": [],
|
||||
"target": {
|
||||
|
|
@ -57,8 +57,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784547,
|
||||
"modifiedTime": 1754340095871,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754499199811,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "DjnKlZQYaWdQGKcK",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"type": "domainCard",
|
||||
"folder": "OwsbTSWzKq2WJmQN",
|
||||
"system": {
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll (16)</strong>. Once per long rest on a success, choose a point within Far range and create a visible zone of protection there for all allies within Very Close range of that point. When you do, place a <strong>d6</strong> on this card with the 1 value facing up. When an ally in this zone takes damage, they reduce it by the die’s value. You then increase the die’s value by one. When the die’s value would exceed 6, this effect ends.</p><p></p><p><span style=\"color:oklab(0.952331 0.000418991 -0.00125992);font-family:'gg mono', 'Source Code Pro', Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace;font-size:13.6px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:left;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:pre-wrap;background-color:oklab(0.57738 0.0140701 -0.208587 / 0.0784314);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">@Template[type:emanation|range:vc]</span></p>",
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll (16)</strong>. Once per long rest on a success, choose a point within Far range and create a visible zone of protection there for all allies within Very Close range of that point. When you do, place a <strong>d6</strong> on this card with the 1 value facing up. When an ally in this zone takes damage, they reduce it by the die’s value. You then increase the die’s value by one. When the die’s value would exceed 6, this effect ends.</p><p><span style=\"color:oklab(0.952331 0.000418991 -0.00125992);font-family:'gg mono', 'Source Code Pro', Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace;font-size:13.6px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:left;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:pre-wrap;background-color:oklab(0.57738 0.0140701 -0.208587 / 0.0784314);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">@Template[type:emanation|range:vc]</span></p>",
|
||||
"domain": "splendor",
|
||||
"recallCost": 2,
|
||||
"level": 6,
|
||||
|
|
@ -58,13 +58,7 @@
|
|||
"range": "far"
|
||||
}
|
||||
},
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 0,
|
||||
"max": "6",
|
||||
"icon": "",
|
||||
"recovery": "longRest"
|
||||
}
|
||||
"resource": null
|
||||
},
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
|
|
@ -75,8 +69,8 @@
|
|||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"createdTime": 1753922784549,
|
||||
"modifiedTime": 1754269795161,
|
||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
||||
"modifiedTime": 1754498786877,
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
||||
},
|
||||
"_id": "lOZaRb4fCVgQsWB5",
|
||||
"sort": 3400000,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"sorting": "a",
|
||||
"_id": "pPzU9WOQNv3ckO1w",
|
||||
"description": "",
|
||||
"sort": 1000000,
|
||||
"sort": 2000000,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
|
|
@ -15,8 +15,8 @@
|
|||
"coreVersion": "13.346",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"lastModifiedBy": "YNJ4HgHtFrTI89mx",
|
||||
"modifiedTime": 1752681545540
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8",
|
||||
"modifiedTime": 1754499337594
|
||||
},
|
||||
"_key": "!folders!pPzU9WOQNv3ckO1w"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"sorting": "a",
|
||||
"_id": "EJoXzO85rG5EiZsh",
|
||||
"description": "",
|
||||
"sort": 100000,
|
||||
"sort": 1100000,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
|
|
@ -15,8 +15,8 @@
|
|||
"coreVersion": "13.346",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"lastModifiedBy": "YNJ4HgHtFrTI89mx",
|
||||
"modifiedTime": 1752681545540
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8",
|
||||
"modifiedTime": 1754499330683
|
||||
},
|
||||
"_key": "!folders!EJoXzO85rG5EiZsh"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"sorting": "a",
|
||||
"_id": "xZrCYAd05ayNu1yW",
|
||||
"description": "",
|
||||
"sort": 200000,
|
||||
"sort": 1200000,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
|
|
@ -15,8 +15,8 @@
|
|||
"coreVersion": "13.346",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "0.0.1",
|
||||
"lastModifiedBy": "YNJ4HgHtFrTI89mx",
|
||||
"modifiedTime": 1752681545540
|
||||
"lastModifiedBy": "MQSznptE5yLT7kj8",
|
||||
"modifiedTime": 1754499331503
|
||||
},
|
||||
"_key": "!folders!xZrCYAd05ayNu1yW"
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue