diff --git a/.gitignore b/.gitignore index 61c6b176..264581a4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ node_modules /packs Build +build foundry -styles/daggerheart.css \ No newline at end of file +styles/daggerheart.css diff --git a/README.md b/README.md index 5e2bbcec..fda78b4b 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,26 @@ -# Daggerheart +# Foundryborne Daggerheart ## Table of Contents - [Overview](#overview) - [User Install Guide](#user-install) +- [Documentation](#documentation) - [Developer Setup](#development-setup) - [Contribution Info](#contributing) ## Overview -This is a community repo for a Foundry VTT implementation of Daggerheart. It is not associated with Critical Role or Darrington Press. +This is the community repo for the Foundry VTT system _Foundryborne_ Daggerheart. It is not associated with Critical Role or Darrington Press. ## User Install -1. **(Not Yet Supported - No Releases Yet)** Pasting `https://raw.githubusercontent.com/Foundryborne/daggerheart/refs/heads/main/system.json` into the Install System dialog on the Setup menu of the application. -2. **(Not Yet Supported - No Releases Yet)** Browsing the repository's Releases page, where you can copy any system.json link for use in the Install System dialog. -3. **(Not Yet Supported - No Releases Yet)** Downloading one of the .zip archives from the Releases page and extracting it into your foundry Data folder, under Data/systems/daggerheart. +1. **Recommended** Searching for _Daggerheart_ or _Foundryborne_ in the System Installation dialogue of the FoundryVTT admin settings. +2. Pasting `https://raw.githubusercontent.com/Foundryborne/daggerheart/refs/heads/main/system.json` into the Install System dialog on the Setup menu of the application. +3. Downloading one of the .zip archives from the Releases page and extracting it into your foundry Data folder, under Data/systems/daggerheart. + +## Documentation + +You can find the documentation here: https://github.com/Foundryborne/daggerheart/wiki ## Development Setup diff --git a/assets/icons/documents/items/ArcaneWheelchair.webp b/assets/icons/documents/items/ArcaneWheelchair.webp new file mode 100644 index 00000000..ae8e0e37 Binary files /dev/null and b/assets/icons/documents/items/ArcaneWheelchair.webp differ diff --git a/assets/icons/documents/items/HeavyWheelchair.webp b/assets/icons/documents/items/HeavyWheelchair.webp new file mode 100644 index 00000000..e82071ee Binary files /dev/null and b/assets/icons/documents/items/HeavyWheelchair.webp differ diff --git a/assets/icons/documents/items/LightWheelchair.webp b/assets/icons/documents/items/LightWheelchair.webp new file mode 100644 index 00000000..f7efca16 Binary files /dev/null and b/assets/icons/documents/items/LightWheelchair.webp differ diff --git a/assets/logos/FoundrybornBackgroundLogo.png b/assets/logos/FoundrybornBackgroundLogo.png new file mode 100644 index 00000000..9639b92f Binary files /dev/null and b/assets/logos/FoundrybornBackgroundLogo.png differ diff --git a/lang/en.json b/lang/en.json index d03ce369..d182a77c 100755 --- a/lang/en.json +++ b/lang/en.json @@ -272,7 +272,8 @@ "combatStarted": "Active", "giveSpotlight": "Give The Spotlight", "requestingSpotlight": "Requesting The Spotlight", - "requestSpotlight": "Request The Spotlight" + "requestSpotlight": "Request The Spotlight", + "openCountdowns": "Countdowns" }, "ContextMenu": { "disableEffect": "Disable Effect", @@ -498,6 +499,11 @@ "ReactionRoll": { "title": "Reaction Roll: {trait}" }, + "RerollDialog": { + "title": "Reroll", + "deselectDiceNotification": "Deselect one of the selected dice first", + "acceptCurrentRolls": "Accept Current Rolls" + }, "ResourceDice": { "title": "{name} Resource", "rerollDice": "Reroll Dice" @@ -505,7 +511,8 @@ }, "CLASS": { "Feature": { - "rallyDice": "Bardic Rally Dice" + "rallyDice": "Bardic Rally Dice", + "short": "Rally" } }, "CONFIG": { @@ -817,8 +824,8 @@ "name": "Restrained", "description": "When an effect makes a creature Restrained, it means they cannot move until this condition is cleared.\nThey can still take actions from their current position." }, - "unconcious": { - "name": "Unconcious", + "unconscious": { + "name": "Unconscious", "description": "Your character can’t move or act while unconscious, they can’t be targeted by an attack." }, "vulnerable": { @@ -1757,6 +1764,7 @@ "weapon": "Range Increase: Weapon" }, "RefreshType": { + "scene": "Scene", "session": "Session", "shortrest": "Short Rest", "longrest": "Long Rest" @@ -1892,6 +1900,7 @@ "difficulty": "Difficulty", "downtime": "Downtime", "dropActorsHere": "Drop Actors here", + "dropFeaturesHere": "Drop Features here", "duality": "Duality", "dualityRoll": "Duality Roll", "enabled": "Enabled", @@ -2259,11 +2268,6 @@ "abilityCheckTitle": "{ability} Check" }, "featureTitle": "Class Feature", - "foundationCard": { - "ancestryTitle": "Ancestry Card", - "communityTitle": "Community Card", - "subclassFeatureTitle": "Subclass Feature" - }, "healingRoll": { "title": "Heal - {damage}", "heal": "Heal", diff --git a/module/applications/characterCreation/characterCreation.mjs b/module/applications/characterCreation/characterCreation.mjs index d45fe54e..c160b2fd 100644 --- a/module/applications/characterCreation/characterCreation.mjs +++ b/module/applications/characterCreation/characterCreation.mjs @@ -359,6 +359,11 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl context.community = { ...this.setup.community, compendium: 'communities' }; context.class = { ...this.setup.class, compendium: 'classes' }; context.subclass = { ...this.setup.subclass, compendium: 'subclasses' }; + + const allDomainData = CONFIG.DH.DOMAIN.allDomains(); + context.classDomains = context.class.uuid + ? context.class.system.domains.map(key => game.i18n.localize(allDomainData[key].label)) + : []; context.domainCards = Object.keys(this.setup.domainCards).reduce((acc, x) => { acc[x] = { ...this.setup.domainCards[x], compendium: 'domains' }; return acc; diff --git a/module/applications/dialogs/_module.mjs b/module/applications/dialogs/_module.mjs index 520c90b6..8908ae2b 100644 --- a/module/applications/dialogs/_module.mjs +++ b/module/applications/dialogs/_module.mjs @@ -6,5 +6,6 @@ export { default as DeathMove } from './deathMove.mjs'; export { default as Downtime } from './downtime.mjs'; export { default as MulticlassChoiceDialog } from './multiclassChoiceDialog.mjs'; export { default as OwnershipSelection } from './ownershipSelection.mjs'; +export { default as RerollDamageDialog } from './rerollDamageDialog.mjs'; export { default as ResourceDiceDialog } from './resourceDiceDialog.mjs'; export { default as ActionSelectionDialog } from './actionSelectionDialog.mjs'; diff --git a/module/applications/dialogs/d20RollDialog.mjs b/module/applications/dialogs/d20RollDialog.mjs index 4b8749a3..0f1cd946 100644 --- a/module/applications/dialogs/d20RollDialog.mjs +++ b/module/applications/dialogs/d20RollDialog.mjs @@ -45,6 +45,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio return this.config.title; } + get actor() { + return this.config?.data?.parent; + } + /** @override */ static PARTS = { header: { @@ -69,9 +73,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio icon })); + this.config.costs ??= []; if (this.config.costs?.length) { const updatedCosts = game.system.api.fields.ActionFields.CostField.calcCosts.call( - this.action, + this.action ?? { actor: this.actor }, this.config.costs ); context.costs = updatedCosts.map(x => ({ @@ -80,7 +85,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio ? this.action.parent.parent.name : game.i18n.localize(CONFIG.DH.GENERAL.abilityCosts[x.key].label) })); - context.canRoll = game.system.api.fields.ActionFields.CostField.hasCost.call(this.action, updatedCosts); + context.canRoll = game.system.api.fields.ActionFields.CostField.hasCost.call( + this.action ?? { actor: this.actor }, + updatedCosts + ); this.config.data.scale = this.config.costs[0].total; } if (this.config.uses?.max) { @@ -143,6 +151,20 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio this.config.experiences.indexOf(button.dataset.key) > -1 ? this.config.experiences.filter(x => x !== button.dataset.key) : [...this.config.experiences, button.dataset.key]; + if (this.config?.data?.parent?.type === 'character' || this.config?.data?.parent?.type === 'companion') { + this.config.costs = + this.config.costs.indexOf(this.config.costs.find(c => c.extKey === button.dataset.key)) > -1 + ? this.config.costs.filter(x => x.extKey !== button.dataset.key) + : [ + ...this.config.costs, + { + extKey: button.dataset.key, + key: 'hope', + value: 1, + name: this.config.data?.experiences?.[button.dataset.key]?.name + } + ]; + } this.render(); } @@ -152,8 +174,8 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio this.config.roll.type = this.reactionOverride ? CONFIG.DH.ITEM.actionTypes.reaction.id : this.config.roll.type === CONFIG.DH.ITEM.actionTypes.reaction.id - ? null - : this.config.roll.type; + ? null + : this.config.roll.type; this.render(); } } diff --git a/module/applications/dialogs/damageDialog.mjs b/module/applications/dialogs/damageDialog.mjs index 2d372725..fbc584e4 100644 --- a/module/applications/dialogs/damageDialog.mjs +++ b/module/applications/dialogs/damageDialog.mjs @@ -56,12 +56,14 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application label, icon })); + context.modifiers = this.config.modifiers; return context; } static updateRollConfiguration(_event, _, formData) { const { ...rest } = foundry.utils.expandObject(formData.object); foundry.utils.mergeObject(this.config.roll, rest.roll); + foundry.utils.mergeObject(this.config.modifiers, rest.modifiers); this.config.selectedRollMode = rest.selectedRollMode; this.render(); diff --git a/module/applications/dialogs/rerollDamageDialog.mjs b/module/applications/dialogs/rerollDamageDialog.mjs new file mode 100644 index 00000000..0c2ea0e1 --- /dev/null +++ b/module/applications/dialogs/rerollDamageDialog.mjs @@ -0,0 +1,279 @@ +const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; + +export default class RerollDamageDialog extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(message, options = {}) { + super(options); + + this.message = message; + this.damage = Object.keys(message.system.damage).reduce((acc, typeKey) => { + const type = message.system.damage[typeKey]; + acc[typeKey] = Object.keys(type.parts).reduce((acc, partKey) => { + const part = type.parts[partKey]; + acc[partKey] = Object.keys(part.dice).reduce((acc, diceKey) => { + const dice = part.dice[diceKey]; + const activeResults = dice.results.filter(x => x.active); + acc[diceKey] = { + dice: dice.dice, + selectedResults: activeResults.length, + maxSelected: activeResults.length, + results: activeResults.map(x => ({ ...x, selected: true })) + }; + + return acc; + }, {}); + + return acc; + }, {}); + + return acc; + }, {}); + } + + static DEFAULT_OPTIONS = { + id: 'reroll-dialog', + classes: ['daggerheart', 'dialog', 'dh-style', 'views', 'reroll-dialog'], + window: { + icon: 'fa-solid fa-dice' + }, + actions: { + toggleResult: RerollDamageDialog.#toggleResult, + selectRoll: RerollDamageDialog.#selectRoll, + doReroll: RerollDamageDialog.#doReroll, + save: RerollDamageDialog.#save + } + }; + + /** @override */ + static PARTS = { + main: { + id: 'main', + template: 'systems/daggerheart/templates/dialogs/rerollDialog/damage/main.hbs' + }, + footer: { + id: 'footer', + template: 'systems/daggerheart/templates/dialogs/rerollDialog/footer.hbs' + } + }; + + get title() { + return game.i18n.localize('DAGGERHEART.APPLICATIONS.RerollDialog.damageTitle'); + } + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + + htmlElement.querySelectorAll('.to-reroll-input').forEach(element => { + element.addEventListener('change', this.toggleDice.bind(this)); + }); + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.damage = this.damage; + context.disabledReroll = !this.getRerollDice().length; + context.saveDisabled = !this.isSelectionDone(); + + return context; + } + + static async #save() { + const update = { + 'system.damage': Object.keys(this.damage).reduce((acc, typeKey) => { + const type = this.damage[typeKey]; + let typeTotal = 0; + const messageType = this.message.system.damage[typeKey]; + const parts = Object.keys(type).map(partKey => { + const part = type[partKey]; + const messagePart = messageType.parts[partKey]; + let partTotal = messagePart.modifierTotal; + const dice = Object.keys(part).map(diceKey => { + const dice = part[diceKey]; + const total = dice.results.reduce((acc, result) => { + if (result.active) acc += result.result; + return acc; + }, 0); + partTotal += total; + const messageDice = messagePart.dice[diceKey]; + return { + ...messageDice, + total: total, + results: dice.results.map(x => ({ + ...x, + hasRerolls: dice.results.length > 1 + })) + }; + }); + + typeTotal += partTotal; + return { + ...messagePart, + total: partTotal, + dice: dice + }; + }); + + acc[typeKey] = { + ...messageType, + total: typeTotal, + parts: parts + }; + + return acc; + }, {}) + }; + await this.message.update(update); + await this.close(); + } + + getRerollDice() { + const rerollDice = []; + Object.keys(this.damage).forEach(typeKey => { + const type = this.damage[typeKey]; + Object.keys(type).forEach(partKey => { + const part = type[partKey]; + Object.keys(part).forEach(diceKey => { + const dice = part[diceKey]; + Object.keys(dice.results).forEach(resultKey => { + const result = dice.results[resultKey]; + if (result.toReroll) { + rerollDice.push({ + ...result, + dice: dice.dice, + type: typeKey, + part: partKey, + dice: diceKey, + result: resultKey + }); + } + }); + }); + }); + }); + + return rerollDice; + } + + isSelectionDone() { + const diceFinishedData = []; + Object.keys(this.damage).forEach(typeKey => { + const type = this.damage[typeKey]; + Object.keys(type).forEach(partKey => { + const part = type[partKey]; + Object.keys(part).forEach(diceKey => { + const dice = part[diceKey]; + const selected = dice.results.reduce((acc, result) => acc + (result.active ? 1 : 0), 0); + diceFinishedData.push(selected === dice.maxSelected); + }); + }); + }); + + return diceFinishedData.every(x => x); + } + + toggleDice(event) { + const target = event.target; + const { type, part, dice } = target.dataset; + const toggleDice = this.damage[type][part][dice]; + + const existingDiceRerolls = this.getRerollDice().filter( + x => x.type === type && x.part === part && x.dice === dice + ); + + const allRerolled = existingDiceRerolls.length === toggleDice.results.filter(x => x.active).length; + + toggleDice.toReroll = !allRerolled; + toggleDice.results.forEach(result => { + if (result.active) { + result.toReroll = !allRerolled; + } + }); + + this.render(); + } + + static #toggleResult(event) { + event.stopPropagation(); + + const target = event.target.closest('.to-reroll-result'); + const { type, part, dice, result } = target.dataset; + const toggleDice = this.damage[type][part][dice]; + const toggleResult = toggleDice.results[result]; + toggleResult.toReroll = !toggleResult.toReroll; + + const existingDiceRerolls = this.getRerollDice().filter( + x => x.type === type && x.part === part && x.dice === dice + ); + + const allToReroll = existingDiceRerolls.length === toggleDice.results.filter(x => x.active).length; + toggleDice.toReroll = allToReroll; + + this.render(); + } + + static async #selectRoll(_, button) { + const { type, part, dice, result } = button.dataset; + + const diceVal = this.damage[type][part][dice]; + const diceResult = diceVal.results[result]; + if (!diceResult.active && diceVal.results.filter(x => x.active).length === diceVal.maxSelected) { + return ui.notifications.warn( + game.i18n.localize('DAGGERHEART.APPLICATIONS.RerollDialog.deselectDiceNotification') + ); + } + + if (diceResult.active) { + diceVal.toReroll = false; + diceResult.toReroll = false; + } + + diceVal.selectedResults += diceResult.active ? -1 : 1; + diceResult.active = !diceResult.active; + + this.render(); + } + + static async #doReroll() { + const toReroll = this.getRerollDice().map(x => { + const { type, part, dice, result } = x; + const diceData = this.damage[type][part][dice].results[result]; + return { + ...diceData, + dice: this.damage[type][part][dice].dice, + typeKey: type, + partKey: part, + diceKey: dice, + resultsIndex: result + }; + }); + + const roll = await new Roll(toReroll.map(x => `1${x.dice}`).join(' + ')).evaluate(); + + if (game.modules.get('dice-so-nice')?.active) { + const diceSoNiceRoll = { + _evaluated: true, + dice: roll.dice, + options: { appearance: {} } + }; + + await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true); + } + + toReroll.forEach((data, index) => { + const { typeKey, partKey, diceKey, resultsIndex } = data; + const rerolledDice = roll.dice[index]; + + const dice = this.damage[typeKey][partKey][diceKey]; + dice.toReroll = false; + dice.results[resultsIndex].active = false; + dice.results[resultsIndex].discarded = true; + dice.results[resultsIndex].toReroll = false; + dice.results.splice(dice.results.length, 0, { + ...rerolledDice.results[0], + toReroll: false, + selected: true + }); + }); + + this.render(); + } +} diff --git a/module/applications/dialogs/rerollDialog.mjs b/module/applications/dialogs/rerollDialog.mjs new file mode 100644 index 00000000..cae4e53a --- /dev/null +++ b/module/applications/dialogs/rerollDialog.mjs @@ -0,0 +1,279 @@ +const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; + +export default class RerollDialog extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(message, options = {}) { + super(options); + + this.message = message; + this.damage = Object.keys(message.system.damage).reduce((acc, typeKey) => { + const type = message.system.damage[typeKey]; + acc[typeKey] = Object.keys(type.parts).reduce((acc, partKey) => { + const part = type.parts[partKey]; + acc[partKey] = Object.keys(part.dice).reduce((acc, diceKey) => { + const dice = part.dice[diceKey]; + const activeResults = dice.results.filter(x => x.active); + acc[diceKey] = { + dice: dice.dice, + selectedResults: activeResults.length, + maxSelected: activeResults.length, + results: activeResults.map(x => ({ ...x, selected: true })) + }; + + return acc; + }, {}); + + return acc; + }, {}); + + return acc; + }, {}); + } + + static DEFAULT_OPTIONS = { + id: 'reroll-dialog', + classes: ['daggerheart', 'dialog', 'dh-style', 'views', 'reroll-dialog'], + window: { + icon: 'fa-solid fa-dice' + }, + actions: { + toggleResult: RerollDialog.#toggleResult, + selectRoll: RerollDialog.#selectRoll, + doReroll: RerollDialog.#doReroll, + save: RerollDialog.#save + } + }; + + /** @override */ + static PARTS = { + main: { + id: 'main', + template: 'systems/daggerheart/templates/dialogs/rerollDialog/main.hbs' + }, + footer: { + id: 'footer', + template: 'systems/daggerheart/templates/dialogs/rerollDialog/footer.hbs' + } + }; + + get title() { + return game.i18n.localize('DAGGERHEART.APPLICATIONS.RerollDialog.title'); + } + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + + htmlElement.querySelectorAll('.to-reroll-input').forEach(element => { + element.addEventListener('change', this.toggleDice.bind(this)); + }); + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.damage = this.damage; + context.disabledReroll = !this.getRerollDice().length; + context.saveDisabled = !this.isSelectionDone(); + + return context; + } + + static async #save() { + const update = { + 'system.damage': Object.keys(this.damage).reduce((acc, typeKey) => { + const type = this.damage[typeKey]; + let typeTotal = 0; + const messageType = this.message.system.damage[typeKey]; + const parts = Object.keys(type).map(partKey => { + const part = type[partKey]; + const messagePart = messageType.parts[partKey]; + let partTotal = messagePart.modifierTotal; + const dice = Object.keys(part).map(diceKey => { + const dice = part[diceKey]; + const total = dice.results.reduce((acc, result) => { + if (result.active) acc += result.result; + return acc; + }, 0); + partTotal += total; + const messageDice = messagePart.dice[diceKey]; + return { + ...messageDice, + total: total, + results: dice.results.map(x => ({ + ...x, + hasRerolls: dice.results.length > 1 + })) + }; + }); + + typeTotal += partTotal; + return { + ...messagePart, + total: partTotal, + dice: dice + }; + }); + + acc[typeKey] = { + ...messageType, + total: typeTotal, + parts: parts + }; + + return acc; + }, {}) + }; + await this.message.update(update); + await this.close(); + } + + getRerollDice() { + const rerollDice = []; + Object.keys(this.damage).forEach(typeKey => { + const type = this.damage[typeKey]; + Object.keys(type).forEach(partKey => { + const part = type[partKey]; + Object.keys(part).forEach(diceKey => { + const dice = part[diceKey]; + Object.keys(dice.results).forEach(resultKey => { + const result = dice.results[resultKey]; + if (result.toReroll) { + rerollDice.push({ + ...result, + dice: dice.dice, + type: typeKey, + part: partKey, + dice: diceKey, + result: resultKey + }); + } + }); + }); + }); + }); + + return rerollDice; + } + + isSelectionDone() { + const diceFinishedData = []; + Object.keys(this.damage).forEach(typeKey => { + const type = this.damage[typeKey]; + Object.keys(type).forEach(partKey => { + const part = type[partKey]; + Object.keys(part).forEach(diceKey => { + const dice = part[diceKey]; + const selected = dice.results.reduce((acc, result) => acc + (result.active ? 1 : 0), 0); + diceFinishedData.push(selected === dice.maxSelected); + }); + }); + }); + + return diceFinishedData.every(x => x); + } + + toggleDice(event) { + const target = event.target; + const { type, part, dice } = target.dataset; + const toggleDice = this.damage[type][part][dice]; + + const existingDiceRerolls = this.getRerollDice().filter( + x => x.type === type && x.part === part && x.dice === dice + ); + + const allRerolled = existingDiceRerolls.length === toggleDice.results.filter(x => x.active).length; + + toggleDice.toReroll = !allRerolled; + toggleDice.results.forEach(result => { + if (result.active) { + result.toReroll = !allRerolled; + } + }); + + this.render(); + } + + static #toggleResult(event) { + event.stopPropagation(); + + const target = event.target.closest('.to-reroll-result'); + const { type, part, dice, result } = target.dataset; + const toggleDice = this.damage[type][part][dice]; + const toggleResult = toggleDice.results[result]; + toggleResult.toReroll = !toggleResult.toReroll; + + const existingDiceRerolls = this.getRerollDice().filter( + x => x.type === type && x.part === part && x.dice === dice + ); + + const allToReroll = existingDiceRerolls.length === toggleDice.results.length; + toggleDice.toReroll = allToReroll; + + this.render(); + } + + static async #selectRoll(_, button) { + const { type, part, dice, result } = button.dataset; + + const diceVal = this.damage[type][part][dice]; + const diceResult = diceVal.results[result]; + if (!diceResult.active && diceVal.results.filter(x => x.active).length === diceVal.maxSelected) { + return ui.notifications.warn( + game.i18n.localize('DAGGERHEART.APPLICATIONS.RerollDialog.deselectDiceNotification') + ); + } + + if (diceResult.active) { + diceVal.toReroll = false; + diceResult.toReroll = false; + } + + diceVal.selectedResults += diceResult.active ? -1 : 1; + diceResult.active = !diceResult.active; + + this.render(); + } + + static async #doReroll() { + const toReroll = this.getRerollDice().map(x => { + const { type, part, dice, result } = x; + const diceData = this.damage[type][part][dice].results[result]; + return { + ...diceData, + dice: this.damage[type][part][dice].dice, + typeKey: type, + partKey: part, + diceKey: dice, + resultsIndex: result + }; + }); + + const roll = await new Roll(toReroll.map(x => `1${x.dice}`).join(' + ')).evaluate(); + + if (game.modules.get('dice-so-nice')?.active) { + const diceSoNiceRoll = { + _evaluated: true, + dice: roll.dice, + options: { appearance: {} } + }; + + await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true); + } + + toReroll.forEach((data, index) => { + const { typeKey, partKey, diceKey, resultsIndex } = data; + const rerolledDice = roll.dice[index]; + + const dice = this.damage[typeKey][partKey][diceKey]; + dice.toReroll = false; + dice.results[resultsIndex].active = false; + dice.results[resultsIndex].discarded = true; + dice.results[resultsIndex].toReroll = false; + dice.results.splice(dice.results.length, 0, { + ...rerolledDice.results[0], + toReroll: false, + selected: true + }); + }); + + this.render(); + } +} diff --git a/module/applications/levelup/characterLevelup.mjs b/module/applications/levelup/characterLevelup.mjs index de28f241..0ae136c4 100644 --- a/module/applications/levelup/characterLevelup.mjs +++ b/module/applications/levelup/characterLevelup.mjs @@ -51,7 +51,7 @@ export default class DhCharacterLevelUp extends LevelUpBase { .filter(exp => exp.data.length > 0) .flatMap(exp => exp.data.map(data => { - const experience = Object.keys(this.actor.system.experiences).find(x => x === data); + const experience = Object.keys(this.actor.system.experiences)[data]; return this.actor.system.experiences[experience].name; }) ); diff --git a/module/applications/levelup/companionLevelup.mjs b/module/applications/levelup/companionLevelup.mjs index 2fcc42a0..c94d7d2b 100644 --- a/module/applications/levelup/companionLevelup.mjs +++ b/module/applications/levelup/companionLevelup.mjs @@ -39,7 +39,7 @@ export default class DhCompanionLevelUp extends BaseLevelUp { .filter(exp => exp.data.length > 0) .flatMap(exp => exp.data.map(data => { - const experience = Object.keys(this.actor.system.experiences).find(x => x === data); + const experience = Object.keys(this.actor.system.experiences)[data]; return this.actor.system.experiences[experience].name; }) ); diff --git a/module/applications/settings/appearanceSettings.mjs b/module/applications/settings/appearanceSettings.mjs index 491c9799..f0310477 100644 --- a/module/applications/settings/appearanceSettings.mjs +++ b/module/applications/settings/appearanceSettings.mjs @@ -1,4 +1,5 @@ import DhAppearance from '../../data/settings/Appearance.mjs'; +import { getDiceSoNicePreset } from '../../config/generalConfig.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -25,7 +26,8 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App }, actions: { reset: this.reset, - save: this.save + save: this.save, + preview: this.preview }, form: { handler: this.updateData, submitOnChange: true } }; @@ -89,6 +91,22 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App this.render(); } + static async preview() { + const source = this.settings._source.diceSoNice[this.tabGroups.diceSoNice]; + let faces = 'd12'; + switch (this.tabGroups.diceSoNice) { + case 'advantage': + case 'disadvantage': + faces = 'd6'; + } + const preset = await getDiceSoNicePreset(source, faces); + const diceSoNiceRoll = await new Roll(`1${faces}`).evaluate(); + diceSoNiceRoll.dice[0].options.appearance = preset.appearance; + diceSoNiceRoll.dice[0].options.modelFile = preset.modelFile; + + await game.dice3d.showForRoll(diceSoNiceRoll, game.user, false); + } + static async reset() { this.settings = new DhAppearance(); this.render(); diff --git a/module/applications/sheets-configs/adversary-settings.mjs b/module/applications/sheets-configs/adversary-settings.mjs index 57deea25..bcc8b1c9 100644 --- a/module/applications/sheets-configs/adversary-settings.mjs +++ b/module/applications/sheets-configs/adversary-settings.mjs @@ -98,11 +98,17 @@ export default class DHAdversarySettings extends DHBaseActorSettings { async _onDrop(event) { const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); - if (data.fromInternal) return; - + const item = await fromUuid(data.uuid); - if (item.type === 'feature') { - await this.actor.createEmbeddedDocuments('Item', [item]); + if (item?.type === 'feature') { + if (data.fromInternal && item.parent?.uuid === this.actor.uuid) { + return; + } + + const itemData = item.toObject(); + delete itemData._id; + + await this.actor.createEmbeddedDocuments('Item', [itemData]); } } } diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index 55662f90..ae597270 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -631,13 +631,33 @@ export default class CharacterSheet extends DHBaseActorSheet { }, hasRoll: true }; - this.document.diceRoll({ + const result = await this.document.diceRoll({ ...config, headerTitle: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${this.actor.name}`, title: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { ability: abilityLabel }) }); + + setTimeout(() => { + this.consumeResource(result?.costs); + }, 50); + } + + async consumeResource(costs) { + if (!costs?.length) return; + const usefulResources = foundry.utils.deepClone(this.actor.system.resources); + const resources = game.system.api.fields.ActionFields.CostField.getRealCosts(costs).map(c => { + const resource = usefulResources[c.key]; + return { + key: c.key, + value: (c.total ?? c.value) * (resource.isReversed ? 1 : -1), + target: resource.target, + keyIsID: resource.keyIsID + }; + }); + + await this.actor.modifyResource(resources); } //TODO: redo toggleEquipItem method diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs index 2a02ba01..18a5ac91 100644 --- a/module/applications/sheets/api/application-mixin.mjs +++ b/module/applications/sheets/api/application-mixin.mjs @@ -51,9 +51,8 @@ import { ItemBrowser } from '../../ui/itemBrowser.mjs'; */ /** - * @template {Constructor} BaseDocumentSheet - * @param {BaseDocumentSheet} Base - The base class to extend. - * @returns {BaseDocumentSheet} + * @template {new (...args: any[]) => {}} T + * @arg Base {T} */ export default function DHApplicationMixin(Base) { class DHSheetV2 extends HandlebarsApplicationMixin(Base) { @@ -123,12 +122,14 @@ export default function DHApplicationMixin(Base) { super._attachPartListeners(partId, htmlElement, options); this._dragDrop.forEach(d => d.bind(htmlElement)); } + /**@inheritdoc */ async _onFirstRender(context, options) { await super._onFirstRender(context, options); const docs = []; - for (var docData of this.relatedDocs) { + for (const docData of this.relatedDocs) { + if (!docData) continue; const doc = await foundry.utils.fromUuid(docData.uuid); docs.push(doc); } @@ -247,6 +248,9 @@ export default function DHApplicationMixin(Base) { /* Context Menu */ /* -------------------------------------------- */ + /** + * Create all configured context menus for this application ins tance. + */ _createContextMenus() { for (const config of this.options.contextMenus) { const { handler, selector, options } = config; @@ -257,9 +261,9 @@ export default function DHApplicationMixin(Base) { /* -------------------------------------------- */ /** - * Get the set of ContextMenu options for DomainCards. + * Get the set of ContextMenu options for ActiveEffects. * @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance - * @this {CharacterSheet} + * @this {DHSheetV2} * @protected */ static #getEffectContextOptions() { @@ -305,8 +309,13 @@ export default function DHApplicationMixin(Base) { } /** - * Get the set of ContextMenu options. - * @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance + * Get the common ContextMenu options for an element. + * @param {Object} options + * @param {boolean} [options.usable=false] - Whether to include an option to use the item or apply damage. + * @param {boolean} [options.toChat=false] - Whether to include an option to send the item to chat. + * @param {boolean} [options.deletable=true] - Whether to include an option to delete the item. + * + * @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} */ _getContextMenuCommonOptions({ usable = false, toChat = false, deletable = true }) { const options = [ @@ -325,7 +334,7 @@ export default function DHApplicationMixin(Base) { } ]; - if (usable) + if (usable) { options.unshift({ name: 'DAGGERHEART.GENERAL.damage', icon: 'fa-solid fa-explosion', @@ -340,15 +349,16 @@ export default function DHApplicationMixin(Base) { } }); - 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) - }); + 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({ @@ -410,7 +420,7 @@ export default function DHApplicationMixin(Base) { : this.document.system.actions?.get(actionId); if (!doc) return; - const description = doc.system?.description ?? doc.description; + const description = game.i18n.localize(doc.system?.description ?? doc.description); const isAction = !!actionId; descriptionElement.innerHTML = await foundry.applications.ux.TextEditor.implementation.enrichHTML( description, diff --git a/module/applications/sheets/api/base-actor.mjs b/module/applications/sheets/api/base-actor.mjs index b664929c..67cec44f 100644 --- a/module/applications/sheets/api/base-actor.mjs +++ b/module/applications/sheets/api/base-actor.mjs @@ -7,8 +7,6 @@ const { ActorSheetV2 } = foundry.applications.sheets; /** * A base actor sheet extending {@link ActorSheetV2} via {@link DHApplicationMixin} - * @extends ActorSheetV2 - * @mixes DHSheetV2 */ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) { /** @inheritDoc */ @@ -106,7 +104,7 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) { /** * Get the set of ContextMenu options for Features. * @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance - * @this {DHSheetV2} + * @this {DHBaseActorSheet} * @protected */ static #getFeatureContextOptions() { diff --git a/module/applications/sheets/api/base-item.mjs b/module/applications/sheets/api/base-item.mjs index b5573a0c..a9d3237d 100644 --- a/module/applications/sheets/api/base-item.mjs +++ b/module/applications/sheets/api/base-item.mjs @@ -7,8 +7,6 @@ const { ItemSheetV2 } = foundry.applications.sheets; /** * A base item sheet extending {@link ItemSheetV2} via {@link DHApplicationMixin} - * @extends ItemSheetV2 - * @mixes DHSheetV2 */ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) { /** @inheritDoc */ @@ -108,7 +106,7 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) { /** * Get the set of ContextMenu options for Features. * @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance - * @this {DHSheetV2} + * @this {DHBaseItemSheet} * @protected */ static #getFeatureContextOptions() { @@ -183,12 +181,18 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) { static async #deleteFeature(_, element) { const target = element.closest('[data-item-uuid]'); const feature = await getDocFromElement(target); - if (!feature) return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureIsMissing')); - await this.document.update({ - 'system.features': this.document.system.features - .filter(x => target.dataset.type !== x.type || x.item.uuid !== feature.uuid) - .map(x => ({ ...x, item: x.item.uuid })) - }); + if (!feature) { + await this.document.update({ + 'system.features': this.document.system.features + .filter(x => x.item) + .map(x => ({ ...x, item: x.item.uuid })) + }); + } else + await this.document.update({ + 'system.features': this.document.system.features + .filter(x => target.dataset.type !== x.type || x.item.uuid !== feature.uuid) + .map(x => ({ ...x, item: x.item.uuid })) + }); } /** @@ -261,21 +265,45 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) { if (data.fromInternal) return; const target = event.target.closest('fieldset.drop-section'); - const item = await fromUuid(data.uuid); + let item = await fromUuid(data.uuid); if (item?.type === 'feature') { + const cls = foundry.documents.Item.implementation; + + if (this.document.parent?.type === 'character') { + const itemData = item.toObject(); + item = await cls.create( + { + ...itemData, + system: { + ...itemData.system, + originItemType: this.document.type, + originId: this.document.id, + identifier: this.document.system.isMulticlass ? 'multiclass' : null + } + }, + { parent: this.document.parent } + ); + } + if (target.dataset.type) { - await this.document.update({ - 'system.features': [...this.document.system.features, { type: target.dataset.type, item }].map( - x => ({ - ...x, - item: x.item?.uuid - }) - ) - }); + await this.document.update( + { + 'system.features': [...this.document.system.features, { type: target.dataset.type, item }].map( + x => ({ + ...x, + item: x.item?.uuid + }) + ) + }, + { parent: this.document.parent?.type === 'character' ? this.document.parent : undefined } + ); } else { - await this.document.update({ - 'system.features': [...this.document.system.features, item].map(x => x.uuid) - }); + await this.document.update( + { + 'system.features': [...this.document.system.features, item].map(x => x.uuid) + }, + { parent: this.document.parent?.type === 'character' ? this.document.parent : undefined } + ); } } } diff --git a/module/applications/ui/chatLog.mjs b/module/applications/ui/chatLog.mjs index fd9ab096..8b4b12d3 100644 --- a/module/applications/ui/chatLog.mjs +++ b/module/applications/ui/chatLog.mjs @@ -20,6 +20,40 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo classes: ['daggerheart'] }; + _getEntryContextOptions() { + return [ + ...super._getEntryContextOptions(), + // { + // name: 'Reroll', + // icon: '', + // condition: li => { + // const message = game.messages.get(li.dataset.messageId); + + // return (game.user.isGM || message.isAuthor) && message.rolls.length > 0; + // }, + // callback: li => { + // const message = game.messages.get(li.dataset.messageId); + // new game.system.api.applications.dialogs.RerollDialog(message).render({ force: true }); + // } + // }, + { + name: 'Reroll Damage', + icon: '', + condition: li => { + const message = game.messages.get(li.dataset.messageId); + const hasRolledDamage = message.system.hasDamage + ? Object.keys(message.system.damage).length > 0 + : false; + return (game.user.isGM || message.isAuthor) && hasRolledDamage; + }, + callback: li => { + const message = game.messages.get(li.dataset.messageId); + new game.system.api.applications.dialogs.RerollDamageDialog(message).render({ force: true }); + } + } + ]; + } + addChatListeners = async (app, html, data) => { html.querySelectorAll('.duality-action-damage').forEach(element => element.addEventListener('click', event => this.onRollDamage(event, data.message)) @@ -33,14 +67,6 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo html.querySelectorAll('.simple-roll-button').forEach(element => element.addEventListener('click', event => this.onRollSimple(event, data.message)) ); - html.querySelectorAll('.target-container').forEach(element => { - element.addEventListener('mouseenter', this.hoverTarget); - element.addEventListener('mouseleave', this.unhoverTarget); - element.addEventListener('click', this.clickTarget); - }); - html.querySelectorAll('.button-target-selection').forEach(element => { - element.addEventListener('click', event => this.onTargetSelection(event, data.message)); - }); html.querySelectorAll('.healing-button').forEach(element => element.addEventListener('click', event => this.onHealing(event, data.message)) ); @@ -138,33 +164,6 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo }); } - onTargetSelection(event, message) { - event.stopPropagation(); - const msg = ui.chat.collection.get(message._id); - msg.system.targetMode = Boolean(event.target.dataset.targetHit); - } - - hoverTarget(event) { - event.stopPropagation(); - const token = canvas.tokens.get(event.currentTarget.dataset.token); - if (!token?.controlled) token._onHoverIn(event, { hoverOutOthers: true }); - } - - unhoverTarget(event) { - const token = canvas.tokens.get(event.currentTarget.dataset.token); - if (!token?.controlled) token._onHoverOut(event); - } - - clickTarget(event) { - event.stopPropagation(); - const token = canvas.tokens.get(event.currentTarget.dataset.token); - if (!token) { - ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.attackTargetDoesNotExist')); - return; - } - game.canvas.pan(token); - } - async onRollSimple(event, message) { const buttonType = event.target.dataset.type ?? 'damage', total = message.rolls.reduce((a, c) => a + Roll.fromJSON(c).total, 0), @@ -228,19 +227,28 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo } const target = event.target.closest('[data-die-index]'); - let originalRoll_parsed = message.rolls.map(roll => JSON.parse(roll))[0]; - const rollClass = - game.system.api.dice[ - message.type === 'dualityRoll' ? 'DualityRoll' : target.dataset.type === 'damage' ? 'DHRoll' : 'D20Roll' - ]; - if (!game.modules.get('dice-so-nice')?.active) foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice }); + if (target.dataset.type === 'damage') { + game.system.api.dice.DamageRoll.reroll(target, message); + } else { + let originalRoll_parsed = message.rolls.map(roll => JSON.parse(roll))[0]; + const rollClass = + game.system.api.dice[ + message.type === 'dualityRoll' + ? 'DualityRoll' + : target.dataset.type === 'damage' + ? 'DHRoll' + : 'D20Roll' + ]; - const { newRoll, parsedRoll } = await rollClass.reroll(originalRoll_parsed, target, message); + if (!game.modules.get('dice-so-nice')?.active) foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice }); - await game.messages.get(message._id).update({ - 'system.roll': newRoll, - 'rolls': [parsedRoll] - }); + const { newRoll, parsedRoll } = await rollClass.reroll(originalRoll_parsed, target, message); + + await game.messages.get(message._id).update({ + 'system.roll': newRoll, + 'rolls': [parsedRoll] + }); + } } } diff --git a/module/applications/ui/itemBrowser.mjs b/module/applications/ui/itemBrowser.mjs index 69de5249..3763bd36 100644 --- a/module/applications/ui/itemBrowser.mjs +++ b/module/applications/ui/itemBrowser.mjs @@ -17,7 +17,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { this.config = CONFIG.DH.ITEMBROWSER.compendiumConfig; this.presets = options.presets; - if(this.presets?.compendium && this.presets?.folder) + if (this.presets?.compendium && this.presets?.folder) ItemBrowser.selectFolder.call(this, null, null, this.presets.compendium, this.presets.folder); } @@ -26,7 +26,6 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { id: 'itemBrowser', classes: ['daggerheart', 'dh-style', 'dialog', 'compendium-browser'], tag: 'div', - // title: 'Item Browser', window: { frame: true, title: 'Compendium Browser', @@ -41,9 +40,8 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { sortList: this.sortList }, position: { - top: 330, - left: 120, - width: 800, + left: 100, + width: 850, height: 600 } }; @@ -88,16 +86,14 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { /** @inheritDoc */ async _preFirstRender(context, options) { - if(context.presets?.render?.noFolder || context.presets?.render?.lite) - options.position.width = 600; - + 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) + if (context.presets?.render?.noFolder || context.presets?.render?.lite) options.parts.splice(options.parts.indexOf('sidebar'), 1); await super._preRender(context, options); @@ -110,18 +106,17 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { 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); + 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(); } } @@ -198,6 +193,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { formatLabel(item, field) { const property = foundry.utils.getProperty(item, field.key); + if (Array.isArray(property)) property.join(', '); if (typeof field.format !== 'function') return property ?? '-'; return field.format(property); } @@ -315,19 +311,18 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { async _onInputFilterBrowser(event) { this.#filteredItems.browser.input.clear(); - if(event) this.fieldFilter.find(f => f.name === event.target.name).value = event.target.value; + 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; + + if (!item) continue; const matchesMenu = this.fieldFilter.length === 0 || - this.fieldFilter.every(f => ( - !f.value && f.value !== false) || - ItemBrowser.evaluateFilter(item, this.createFilterData(f)) + this.fieldFilter.every( + f => (!f.value && f.value !== false) || ItemBrowser.evaluateFilter(item, this.createFilterData(f)) ); if (matchesMenu) this.#filteredItems.browser.input.add(item.id); @@ -335,21 +330,21 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { 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 + * @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": + case 'contains2': filterValue = Array.isArray(filterValue) ? filterValue : [filterValue]; docValue = Array.isArray(docValue) ? docValue : [docValue]; return docValue.some(dv => filterValue.includes(dv)); - case "contains3": + case 'contains3': return docValue.some(f => f.value === filterValue); default: return foundry.applications.ux.SearchFilter.evaluateFilter(obj, filter); @@ -373,30 +368,33 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { this.render({ force: true }); } - static getFolderConfig(folder, property = "columns") { - if(!folder) return []; + 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"); + 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 + .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") { + 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); } diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index 7785b6a6..ee0b6671 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -183,11 +183,11 @@ export const conditions = { icon: 'icons/magic/control/debuff-chains-shackle-movement-red.webp', description: 'DAGGERHEART.CONFIG.Condition.restrained.description' }, - unconcious: { - id: 'unconcious', - name: 'DAGGERHEART.CONFIG.Condition.unconcious.name', + unconscious: { + id: 'unconscious', + name: 'DAGGERHEART.CONFIG.Condition.unconscious.name', icon: 'icons/magic/control/sleep-bubble-purple.webp', - description: 'DAGGERHEART.CONFIG.Condition.unconcious.description' + description: 'DAGGERHEART.CONFIG.Condition.unconscious.description' }, dead: { id: 'dead', @@ -494,44 +494,49 @@ export const diceSetNumbers = { flat: 'Flat' }; -export const getDiceSoNicePresets = async (hopeFaces, fearFaces, advantageFaces = 'd6', disadvantageFaces = 'd6') => { - const { diceSoNice } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance); - const getPreset = async (type, faces) => { - const system = game.dice3d.DiceFactory.systems.get(type.system).dice.get(faces); - if (!system) { - ui.notifications.error( - game.i18n.format('DAGGERHEART.UI.Notifications.noDiceSystem', { - system: game.dice3d.DiceFactory.systems.get(type.system).name, - faces: faces - }) - ); - return; - } +export const getDiceSoNicePreset = async (type, faces) => { + const system = game.dice3d.DiceFactory.systems.get(type.system).dice.get(faces); + if (!system) { + ui.notifications.error( + game.i18n.format('DAGGERHEART.UI.Notifications.noDiceSystem', { + system: game.dice3d.DiceFactory.systems.get(type.system).name, + faces: faces + }) + ); + return; + } - if (system.modelFile && !system.modelLoaded) { - await system.loadModel(game.dice3d.DiceFactory.loaderGLTF); - } else { - await system.loadTextures(); - } - - return { - modelFile: system.modelFile, - appearance: { - ...system.appearance, - ...type - } - }; - }; + if (system.modelFile && !system.modelLoaded) { + await system.loadModel(game.dice3d.DiceFactory.loaderGLTF); + } else { + await system.loadTextures(); + } return { - hope: await getPreset(diceSoNice.hope, hopeFaces), - fear: await getPreset(diceSoNice.fear, fearFaces), - advantage: await getPreset(diceSoNice.advantage, advantageFaces), - disadvantage: await getPreset(diceSoNice.disadvantage, disadvantageFaces) + modelFile: system.modelFile, + appearance: { + ...system.appearance, + ...type + } + }; +}; + +export const getDiceSoNicePresets = async (hopeFaces, fearFaces, advantageFaces = 'd6', disadvantageFaces = 'd6') => { + const { diceSoNice } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance); + + return { + hope: await getDiceSoNicePreset(diceSoNice.hope, hopeFaces), + fear: await getDiceSoNicePreset(diceSoNice.fear, fearFaces), + advantage: await getDiceSoNicePreset(diceSoNice.advantage, advantageFaces), + disadvantage: await getDiceSoNicePreset(diceSoNice.disadvantage, disadvantageFaces) }; }; export const refreshTypes = { + scene: { + id: 'session', + label: 'DAGGERHEART.GENERAL.RefreshType.scene' + }, session: { id: 'session', label: 'DAGGERHEART.GENERAL.RefreshType.session' diff --git a/module/config/itemConfig.mjs b/module/config/itemConfig.mjs index e9d8de4c..cb244469 100644 --- a/module/config/itemConfig.mjs +++ b/module/config/itemConfig.mjs @@ -780,7 +780,15 @@ export const weaponFeatures = { mode: 2, value: '1' } - ] + ], + system: { + rangeDependence: { + enabled: true, + range: 'melee', + target: 'hostile', + type: 'withinRange' + } + } } ] }, @@ -1040,16 +1048,6 @@ export const weaponFeatures = { key: 'system.evasion', mode: 2, value: '-1' - }, - { - key: 'system.bonuses.damage.primaryWeapon.extraDice', - mode: 2, - value: '1' - }, - { - key: 'system.rules.weapon.dropLowestDamageDice', - mode: 5, - value: '1' } ] } @@ -1089,7 +1087,15 @@ export const weaponFeatures = { mode: 2, value: 'ITEM.@system.tier + 1' } - ] + ], + system: { + rangeDependence: { + enabled: true, + range: 'melee', + target: 'hostile', + type: 'withinRange' + } + } } ] }, @@ -1166,18 +1172,7 @@ export const weaponFeatures = { name: 'DAGGERHEART.CONFIG.WeaponFeature.powerful.effects.powerful.name', description: 'DAGGERHEART.CONFIG.WeaponFeature.powerful.effects.powerful.description', img: 'icons/magic/control/buff-flight-wings-runes-red-yellow.webp', - changes: [ - { - key: 'system.bonuses.damage.primaryWeapon.extraDice', - mode: 2, - value: '1' - }, - { - key: 'system.rules.weapon.dropLowestDamageDice', - mode: 5, - value: '1' - } - ] + changes: [] } ] }, @@ -1229,7 +1224,7 @@ export const weaponFeatures = { img: 'icons/skills/melee/strike-sword-slashing-red.webp', changes: [ { - key: 'system.bonuses.roll.primaryWeapon.attack', + key: 'system.bonuses.roll.primaryWeapon.bonus', mode: 2, value: 1 } @@ -1301,13 +1296,7 @@ export const weaponFeatures = { name: 'DAGGERHEART.CONFIG.WeaponFeature.selfCorrecting.effects.selfCorrecting.name', description: 'DAGGERHEART.CONFIG.WeaponFeature.selfCorrecting.effects.selfCorrecting.description', img: 'icons/weapons/ammunition/arrow-broadhead-glowing-orange.webp', - changes: [ - { - key: 'system.rules.damage.flipMinDiceValue', - mode: 5, - value: 1 - } - ] + changes: [] } ] }, @@ -1319,13 +1308,7 @@ export const weaponFeatures = { name: 'DAGGERHEART.CONFIG.WeaponFeature.serrated.effects.serrated.name', description: 'DAGGERHEART.CONFIG.WeaponFeature.serrated.effects.serrated.description', img: 'icons/weapons/ammunition/arrow-broadhead-glowing-orange.webp', - changes: [ - { - key: 'system.rules.damage.flipMinDiceValue', - mode: 5, - value: 1 - } - ] + changes: [] } ] }, diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index 070864da..a886bf49 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -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++) { @@ -145,9 +144,8 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel if (this.rollDamage && this.damage.parts.length) await this.rollDamage(event, config); else if (this.trigger) await this.trigger(event, config); else if (this.hasSave || this.hasEffect) { - const roll = new Roll(''); + const roll = new CONFIG.Dice.daggerheart.DHRoll(''); roll._evaluated = true; - if (this.hasTarget) config.targetSelection = config.targets.length > 0; await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config); } } @@ -180,7 +178,6 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel hasHealing: this.damage?.parts?.length && this.type === 'healing', hasEffect: !!this.effects?.length, hasSave: this.hasSave, - hasTarget: true, selectedRollMode: game.settings.get('core', 'rollMode'), isFastForward: event.shiftKey, data: this.getRollData(), @@ -211,7 +208,14 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel } async consume(config, successCost = false) { - const usefulResources = foundry.utils.deepClone(this.actor.system.resources); + const usefulResources = { + ...foundry.utils.deepClone(this.actor.system.resources), + fear: { + value: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear), + max: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxFear, + reversed: false + } + }; for (var cost of config.costs) { if (cost.keyIsID) { @@ -223,24 +227,26 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel } } - const resources = config.costs + const resources = game.system.api.fields.ActionFields.CostField.getRealCosts(config.costs) .filter( c => - c.enabled !== false && - ((!successCost && (!c.consumeOnSuccess || config.roll?.success)) || - (successCost && c.consumeOnSuccess)) + (!successCost && (!c.consumeOnSuccess || config.roll?.success)) || + (successCost && c.consumeOnSuccess) ) - .map(c => { + .reduce((a, c) => { const resource = usefulResources[c.key]; - return { - key: c.key, - value: (c.total ?? c.value) * (resource.isReversed ? 1 : -1), - target: resource.target, - keyIsID: resource.keyIsID - }; - }); + if (resource) { + a.push({ + key: c.key, + value: (c.total ?? c.value) * (resource.isReversed ? 1 : -1), + target: resource.target, + keyIsID: resource.keyIsID + }); + return a; + } + }, []); - await this.actor.modifyResource(resources); + await (this.actor.system.partner ?? this.actor).modifyResource(resources); if ( config.uses?.enabled && ((!successCost && (!config.uses?.consumeOnSuccess || config.roll?.success)) || @@ -248,8 +254,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel ) this.update({ 'uses.value': this.uses.value + 1 }); - if (config.roll?.success || successCost) - (config.message ?? config.parent).update({ 'system.successConsumed': true }); + if (config.roll?.success || successCost) { + setTimeout(() => { + (config.message ?? config.parent).update({ 'system.successConsumed': true }); + }, 50); + } } /* */ @@ -368,15 +377,15 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel async updateChatMessage(message, targetId, changes, chain = true) { setTimeout(async () => { - const chatMessage = ui.chat.collection.get(message._id), - msgTarget = - chatMessage.system.targets.find(mt => mt.id === targetId) ?? - chatMessage.system.oldTargets.find(mt => mt.id === targetId); - msgTarget.saved = changes; + const chatMessage = ui.chat.collection.get(message._id); + await chatMessage.update({ - system: { - targets: chatMessage.system.targets, - oldTargets: chatMessage.system.oldTargets + flags: { + [game.system.id]: { + reactionRolls: { + [targetId]: changes + } + } } }); }, 100); diff --git a/module/data/action/damageAction.mjs b/module/data/action/damageAction.mjs index 88eec481..1627f8e8 100644 --- a/module/data/action/damageAction.mjs +++ b/module/data/action/damageAction.mjs @@ -49,8 +49,7 @@ export default class DHDamageAction extends DHBaseAction { ...systemData, roll: formulas, dialog: {}, - data: this.getRollData(), - targetSelection: systemData.targets.length > 0 + data: this.getRollData() }; if (this.hasSave) config.onSave = this.save.damageMod; if (data.system) { diff --git a/module/data/activeEffect/beastformEffect.mjs b/module/data/activeEffect/beastformEffect.mjs index e040d8d8..b5cbdb28 100644 --- a/module/data/activeEffect/beastformEffect.mjs +++ b/module/data/activeEffect/beastformEffect.mjs @@ -32,7 +32,7 @@ export default class BeastformEffect extends BaseEffect { if (this.parent.parent?.type === 'character') { this.parent.parent.system.primaryWeapon?.update?.({ 'system.equipped': false }); - this.parent.parent.system.secondayWeapon?.update?.({ 'system.equipped': false }); + this.parent.parent.system.secondaryWeapon?.update?.({ 'system.equipped': false }); } } diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 6256aa8a..c2a8f400 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -287,18 +287,6 @@ export default class DhCharacter extends BaseDataActor { }) }) }), - weapon: new fields.SchemaField({ - /* Unimplemented - -> Should remove the lowest damage dice from weapon damage - -> Reflect this in the chat message somehow so players get feedback that their choice is helping them. - */ - dropLowestDamageDice: new fields.BooleanField({ initial: false }), - /* Unimplemented - -> Should flip any lowest possible dice rolls for weapon damage to highest - -> Reflect this in the chat message somehow so players get feedback that their choice is helping them. - */ - flipMinDiceValue: new fields.BooleanField({ intial: false }) - }), runeWard: new fields.BooleanField({ initial: false }), burden: new fields.SchemaField({ ignore: new fields.BooleanField() @@ -363,6 +351,17 @@ export default class DhCharacter extends BaseDataActor { return [...classDomains, ...multiclassDomains]; } + get domainData() { + const allDomainData = CONFIG.DH.DOMAIN.allDomains(); + return this.domains.map(key => { + const domain = allDomainData[key]; + return { + ...domain, + label: game.i18n.localize(domain.label) + }; + }); + } + get domainCards() { const domainCards = this.parent.items.filter(x => x.type === 'domainCard'); const loadout = domainCards.filter(x => !x.system.inVault); diff --git a/module/data/chat-message/abilityUse.mjs b/module/data/chat-message/abilityUse.mjs index c431f14a..07209fe2 100644 --- a/module/data/chat-message/abilityUse.mjs +++ b/module/data/chat-message/abilityUse.mjs @@ -3,7 +3,6 @@ export default class DHAbilityUse extends foundry.abstract.TypeDataModel { const fields = foundry.data.fields; return { - title: new fields.StringField({}), origin: new fields.StringField({}), img: new fields.StringField({}), name: new fields.StringField({}), diff --git a/module/data/chat-message/adversaryRoll.mjs b/module/data/chat-message/adversaryRoll.mjs index fa6e48a6..337acf5b 100644 --- a/module/data/chat-message/adversaryRoll.mjs +++ b/module/data/chat-message/adversaryRoll.mjs @@ -18,15 +18,11 @@ const targetsField = () => ); export default class DHActorRoll extends foundry.abstract.TypeDataModel { - targetHook = null; - static defineSchema() { return { title: new fields.StringField(), roll: new fields.ObjectField(), targets: targetsField(), - oldTargets: targetsField(), - targetSelection: new fields.BooleanField({ initial: false }), hasRoll: new fields.BooleanField({ initial: false }), hasDamage: new fields.BooleanField({ initial: false }), hasHealing: new fields.BooleanField({ initial: false }), @@ -63,66 +59,59 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel { return actionItem.system.actionsList?.find(a => a.id === this.source.action); } - get messageTemplate() { - return 'systems/daggerheart/templates/ui/chat/roll.hbs'; - } - get targetMode() { - return this.targetSelection; + return this.parent.targetSelection; } set targetMode(mode) { - this.targetSelection = mode; - this.updateTargets(); + if (!this.parent.isAuthor) return; + this.parent.targetSelection = mode; this.registerTargetHook(); - this.parent.update({ - system: { - targetSelection: this.targetSelection, - oldTargets: this.oldTargets + this.updateTargets(); + } + + get hitTargets() { + return this.currentTargets.filter(t => t.hit || !this.hasRoll || !this.targetMode); + } + + async updateTargets() { + if (!ui.chat.collection.get(this.parent.id)) return; + let targets; + if (this.targetMode) targets = this.targets; + else + targets = Array.from(game.user.targets).map(t => + game.system.api.fields.ActionFields.TargetField.formatTarget(t) + ); + + await this.parent.update({ + flags: { + [game.system.id]: { + targets: targets, + targetMode: this.targetMode + } } }); } - get hitTargets() { - return this.currentTargets.filter(t => t.hit || !this.hasRoll || !this.targetSelection); - } - - async updateTargets() { - this.currentTargets = this.getTargetList(); - if (!this.targetSelection) { - this.currentTargets.forEach(ct => { - if (this.targets.find(t => t.actorId === ct.actorId)) return; - const indexTarget = this.oldTargets.findIndex(ot => ot.actorId === ct.actorId); - if (indexTarget === -1) this.oldTargets.push(ct); - }); - if (this.hasSave) this.setPendingSaves(); - if (this.currentTargets.length) { - if (!this.parent._id) return; - const updates = await this.parent.update({ - system: { - oldTargets: this.oldTargets - } - }); - if (!updates && ui.chat.collection.get(this.parent.id)) ui.chat.updateMessage(this.parent); - } - } - } - registerTargetHook() { - 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)); + if (!this.parent.isAuthor) return; + if (this.targetMode && this.parent.targetHook !== null) { + Hooks.off('targetToken', this.parent.targetHook); + return (this.parent.targetHook = null); + } else if (!this.targetMode && this.parent.targetHook === null) { + return (this.parent.targetHook = Hooks.on( + 'targetToken', + foundry.utils.debounce(this.updateTargets.bind(this), 50) + )); } } prepareDerivedData() { if (this.hasTarget) { this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0; - this.updateTargets(); - this.registerTargetHook(); - if (this.targetSelection === true) { + this.currentTargets = this.getTargetList(); + + if (this.targetMode === true && this.hasRoll) { this.targetShort = this.targets.reduce( (a, c) => { if (c.hit) a.hit += 1; @@ -136,23 +125,28 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel { } this.canViewSecret = this.parent.speakerActor?.testUserPermission(game.user, 'OBSERVER'); + this.canButtonApply = game.user.isGM; } getTargetList() { - return this.targetSelection !== true - ? Array.from(game.user.targets).map(t => { - const target = game.system.api.fields.ActionFields.TargetField.formatTarget(t), - oldTarget = - this.targets.find(ot => ot.actorId === target.actorId) ?? - this.oldTargets.find(ot => ot.actorId === target.actorId); - if (oldTarget) return oldTarget; - return target; - }) - : this.targets; + const targets = + this.targetMode && this.parent.isAuthor + ? this.targets + : (this.parent.getFlag(game.system.id, 'targets') ?? this.targets), + reactionRolls = this.parent.getFlag(game.system.id, 'reactionRolls'); + + if (reactionRolls) { + Object.entries(reactionRolls).forEach(([k, r]) => { + const target = targets.find(t => t.id === k); + if (target) target.saved = r; + }); + } + + return targets; } setPendingSaves() { - this.pendingSaves = this.targetSelection + this.pendingSaves = this.targetMode ? this.targets.filter(target => target.hit && target.saved.success === null).length > 0 : this.currentTargets.filter(target => target.saved.success === null).length > 0; } diff --git a/module/data/fields/action/costField.mjs b/module/data/fields/action/costField.mjs index b9495e8b..f4d942b1 100644 --- a/module/data/fields/action/costField.mjs +++ b/module/data/fields/action/costField.mjs @@ -12,7 +12,10 @@ export default class CostField extends fields.ArrayField { value: new fields.NumberField({ nullable: true, initial: 1, min: 0 }), scalable: new fields.BooleanField({ initial: false }), step: new fields.NumberField({ nullable: true, initial: null }), - 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(element, options, context); } @@ -47,6 +50,7 @@ export default class CostField extends fields.ArrayField { static hasCost(costs) { const realCosts = CostField.getRealCosts.call(this, costs), hasFearCost = realCosts.findIndex(c => c.key === 'fear'); + if (hasFearCost > -1) { const fearCost = realCosts.splice(hasFearCost, 1)[0]; if ( @@ -70,7 +74,9 @@ export default class CostField extends fields.ArrayField { } static getResources(costs) { - const actorResources = this.actor.system.resources; + const actorResources = foundry.utils.deepClone(this.actor.system.resources); + if (this.actor.system.partner) + actorResources.hope = foundry.utils.deepClone(this.actor.system.partner.system.resources.hope); const itemResources = {}; for (let itemResource of costs) { if (itemResource.keyIsID) { @@ -89,7 +95,13 @@ export default class CostField extends fields.ArrayField { static getRealCosts(costs) { const realCosts = costs?.length ? costs.filter(c => c.enabled) : []; - return realCosts; + let mergedCosts = []; + realCosts.forEach(c => { + const getCost = Object.values(mergedCosts).find(gc => gc.key === c.key); + if (getCost) getCost.total += c.total; + else mergedCosts.push(c); + }); + return mergedCosts; } static formatMax(max) { diff --git a/module/data/fields/action/targetField.mjs b/module/data/fields/action/targetField.mjs index 681f8353..bfb01db9 100644 --- a/module/data/fields/action/targetField.mjs +++ b/module/data/fields/action/targetField.mjs @@ -15,6 +15,7 @@ export default class TargetField extends fields.SchemaField { static prepareConfig(config) { if (!this.target?.type) return []; + config.hasTarget = true; let targets; if (this.target?.type === CONFIG.DH.GENERAL.targetTypes.self.id) targets = [this.actor.token ?? this.actor.prototypeToken]; diff --git a/module/data/fields/actionField.mjs b/module/data/fields/actionField.mjs index c3bdcaaa..8d865562 100644 --- a/module/data/fields/actionField.mjs +++ b/module/data/fields/actionField.mjs @@ -229,7 +229,7 @@ export function ActionMixin(Base) { } return this.inCollection - ? foundry.utils.getProperty(result, basePath).get(this.id) + ? foundry.utils.getProperty(result, basePath)?.get(this.id) : foundry.utils.getProperty(result, basePath); } @@ -285,6 +285,7 @@ export function ActionMixin(Base) { } }; + ChatMessage.applyRollMode(msg, game.settings.get('core', 'rollMode')); cls.create(msg); } } diff --git a/module/data/item/armor.mjs b/module/data/item/armor.mjs index 01e1d186..a8c3dcec 100644 --- a/module/data/item/armor.mjs +++ b/module/data/item/armor.mjs @@ -60,7 +60,7 @@ export default class DHArmor extends AttachableItem { const allowed = await super._preUpdate(changes, options, user); if (allowed === false) return false; - if (changes.system.armorFeatures) { + if (changes.system?.armorFeatures) { const removed = this.armorFeatures.filter(x => !changes.system.armorFeatures.includes(x)); const added = changes.system.armorFeatures.filter(x => !this.armorFeatures.includes(x)); diff --git a/module/data/item/domainCard.mjs b/module/data/item/domainCard.mjs index 34754a41..7705adb1 100644 --- a/module/data/item/domainCard.mjs +++ b/module/data/item/domainCard.mjs @@ -33,6 +33,11 @@ export default class DHDomainCard extends BaseDataItem { }; } + get domainLabel() { + const allDomainData = CONFIG.DH.DOMAIN.allDomains(); + return game.i18n.localize(allDomainData[this.domain].label); + } + /* -------------------------------------------- */ /**@override */ @@ -71,7 +76,7 @@ export default class DHDomainCard extends BaseDataItem { _getTags() { const tags = [ game.i18n.localize(`DAGGERHEART.CONFIG.DomainCardTypes.${this.type}`), - game.i18n.localize(`DAGGERHEART.GENERAL.Domain.${this.domain}.label`), + this.domainLabel, `${game.i18n.localize('DAGGERHEART.ITEMS.DomainCard.recallCost')}: ${this.recallCost}` ]; @@ -85,7 +90,7 @@ export default class DHDomainCard extends BaseDataItem { _getLabels() { const labels = [ game.i18n.localize(`DAGGERHEART.CONFIG.DomainCardTypes.${this.type}`), - game.i18n.localize(`DAGGERHEART.GENERAL.Domain.${this.domain}.label`), + this.domainLabel, { value: `${this.recallCost}`, //converts the number to a string icons: ['fa-bolt'] diff --git a/module/data/item/subclass.mjs b/module/data/item/subclass.mjs index ce52fdc6..221785b3 100644 --- a/module/data/item/subclass.mjs +++ b/module/data/item/subclass.mjs @@ -21,7 +21,7 @@ export default class DHSubclass extends BaseDataItem { integer: false, nullable: true, initial: null, - label: "DAGGERHEART.ITEMS.Subclass.spellcastingTrait" + label: 'DAGGERHEART.ITEMS.Subclass.spellcastingTrait' }), features: new ItemLinkFields(), featureState: new fields.NumberField({ required: true, initial: 1, min: 1 }), @@ -50,7 +50,8 @@ export default class DHSubclass extends BaseDataItem { async _preCreate(data, options, user) { if (this.actor?.type === 'character') { - const dataUuid = data.uuid ?? data._stats?.compendiumSource ?? `Item.${data._id}`; + const dataUuid = + (data.uuid ?? data.folder) ? `Compendium.daggerheart.subclasses.Item.${data._id}` : `Item.${data._id}`; if (this.actor.system.class.subclass) { if (this.actor.system.multiclass.subclass) { ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassesAlreadyPresent')); diff --git a/module/dice/d20Roll.mjs b/module/dice/d20Roll.mjs index 45471532..63d84744 100644 --- a/module/dice/d20Roll.mjs +++ b/module/dice/d20Roll.mjs @@ -139,17 +139,15 @@ export default class D20Roll extends DHRoll { static postEvaluate(roll, config = {}) { const data = super.postEvaluate(roll, config); data.type = config.roll?.type; + data.difficulty = config.roll.difficulty; if (config.targets?.length) { - config.targetSelection = true; config.targets.forEach(target => { const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion; target.hit = roll.isCritical || roll.total >= difficulty; }); data.success = config.targets.some(target => target.hit); - } else if (config.roll.difficulty) { - data.difficulty = config.roll.difficulty; - data.success = roll.isCritical || roll.total >= config.roll.difficulty; - } + } else if (config.roll.difficulty) data.success = roll.isCritical || roll.total >= config.roll.difficulty; + data.advantage = { type: config.roll.advantage, dice: roll.dAdvantage?.denomination, diff --git a/module/dice/damageRoll.mjs b/module/dice/damageRoll.mjs index 999a4bb8..8a72d86e 100644 --- a/module/dice/damageRoll.mjs +++ b/module/dice/damageRoll.mjs @@ -15,7 +15,6 @@ export default class DamageRoll extends DHRoll { const parts = config.roll.map(r => this.postEvaluate(r)); config.damage = this.unifyDamageRoll(parts); - // config.targetSelection = config.targets?.length } static postEvaluate(roll, config = {}) { @@ -30,16 +29,18 @@ export default class DamageRoll extends DHRoll { } static async buildPost(roll, config, message) { + const chatMessage = config.source?.message + ? ui.chat.collection.get(config.source.message) + : getDocumentClass('ChatMessage').applyRollMode({}, config.rollMode); if (game.modules.get('dice-so-nice')?.active) { const pool = foundry.dice.terms.PoolTerm.fromRolls( Object.values(config.damage).flatMap(r => r.parts.map(p => p.roll)) ), diceRoll = Roll.fromTerms([pool]); - await game.dice3d.showForRoll(diceRoll, game.user, true); + await game.dice3d.showForRoll(diceRoll, game.user, true, chatMessage.whisper, chatMessage.blind); } await super.buildPost(roll, config, message); if (config.source?.message) { - const chatMessage = ui.chat.collection.get(config.source.message); chatMessage.update({ 'system.damage': config.damage }); } } @@ -102,14 +103,14 @@ export default class DamageRoll extends DHRoll { } constructFormula(config) { - this.options.roll.forEach(part => { + this.options.roll.forEach((part, index) => { part.roll = new Roll(Roll.replaceFormulaData(part.formula, config.data)); - this.constructFormulaPart(config, part); + this.constructFormulaPart(config, part, index); }); return this.options.roll; } - constructFormulaPart(config, part) { + constructFormulaPart(config, part, index) { part.roll.terms = Roll.parse(part.roll.formula, config.data); if (part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { @@ -120,6 +121,14 @@ export default class DamageRoll extends DHRoll { }); } + /* To Remove When Reaction System */ + if (index === 0 && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { + for (const mod in config.modifiers) { + const modifier = config.modifiers[mod]; + if (modifier.beforeCrit === true && (modifier.enabled || modifier.value)) modifier.callback(part); + } + } + if (part.extraFormula) { part.roll.terms.push( new foundry.dice.terms.OperatorTerm({ operator: '+' }), @@ -132,6 +141,192 @@ export default class DamageRoll extends DHRoll { criticalBonus = tmpRoll.total - this.constructor.calculateTotalModifiers(tmpRoll); part.roll.terms.push(...this.formatModifier(criticalBonus)); } + + /* To Remove When Reaction System */ + if (index === 0 && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { + for (const mod in config.modifiers) { + const modifier = config.modifiers[mod]; + if (!modifier.beforeCrit && (modifier.enabled || modifier.value)) modifier.callback(part); + } + } + return (part.roll._formula = this.constructor.getFormula(part.roll.terms)); } + + /* To Remove When Reaction System */ + static temporaryModifierBuilder(config) { + const mods = {}; + if (config.data?.parent) { + if (config.data.parent.appliedEffects) { + // Bardic Rally + const rallyChoices = config.data?.parent?.appliedEffects.reduce((a, c) => { + const change = c.changes.find(ch => ch.key === 'system.bonuses.rally'); + if (change) a.push({ value: c.id, label: change.value }); + return a; + }, []) + if(rallyChoices.length) { + mods.rally = { + label: 'DAGGERHEART.CLASS.Feature.rallyDice', + values: rallyChoices, + value: null, + beforeCrit: true, + callback: part => { + const rallyFaces = config.modifiers.rally.values.find( + r => r.value === config.modifiers.rally.value + )?.label; + part.roll.terms.push( + new foundry.dice.terms.OperatorTerm({ operator: '+' }), + ...this.parse(`1${rallyFaces}`) + ); + } + }; + } + } + + const item = config.data.parent.items?.get(config.source.item); + if (item) { + // Massive (Weapon Feature) + if (item.system.itemFeatures.find(f => f.value === 'massive')) + mods.massive = { + label: CONFIG.DH.ITEM.weaponFeatures.massive.label, + enabled: true, + callback: part => { + part.roll.terms[0].modifiers.push(`kh${part.roll.terms[0].number}`); + part.roll.terms[0].number += 1; + } + }; + + // Powerful (Weapon Feature) + if (item.system.itemFeatures.find(f => f.value === 'powerful')) + mods.powerful = { + label: CONFIG.DH.ITEM.weaponFeatures.powerful.label, + enabled: true, + callback: part => { + part.roll.terms[0].modifiers.push(`kh${part.roll.terms[0].number}`); + part.roll.terms[0].number += 1; + } + }; + + // Brutal (Weapon Feature) + if (item.system.itemFeatures.find(f => f.value === 'brutal')) + mods.brutal = { + label: CONFIG.DH.ITEM.weaponFeatures.brutal.label, + enabled: true, + beforeCrit: true, + callback: part => { + part.roll.terms[0].modifiers.push(`x${part.roll.terms[0].faces}`); + } + }; + + // Serrated (Weapon Feature) + if (item.system.itemFeatures.find(f => f.value === 'serrated')) + mods.serrated = { + label: CONFIG.DH.ITEM.weaponFeatures.serrated.label, + enabled: true, + callback: part => { + part.roll.terms[0].modifiers.push(`sc8`); + } + }; + + // Self-Correcting (Weapon Feature) + if (item.system.itemFeatures.find(f => f.value === 'selfCorrecting')) + mods.selfCorrecting = { + label: CONFIG.DH.ITEM.weaponFeatures.selfCorrecting.label, + enabled: true, + callback: part => { + part.roll.terms[0].modifiers.push(`sc6`); + } + }; + } + } + + config.modifiers = mods; + return mods; + } + + static async reroll(target, message) { + const { damageType, part, dice, result } = target.dataset; + const rollPart = message.system.damage[damageType].parts[part]; + + let diceIndex = 0; + let parsedRoll = game.system.api.dice.DamageRoll.fromData({ + ...rollPart.roll, + terms: rollPart.roll.terms.map(term => { + const isDie = term.class === 'Die'; + const fixedTerm = { + ...term, + ...(isDie ? { results: rollPart.dice[diceIndex].results } : {}) + }; + + if (isDie) diceIndex++; + return fixedTerm; + }), + class: 'DamageRoll', + evaluated: false + }); + + const parsedDiceTerms = Object.keys(parsedRoll.terms).reduce((acc, key) => { + const term = parsedRoll.terms[key]; + if (term instanceof CONFIG.Dice.termTypes.DiceTerm) acc[Object.keys(acc).length] = term; + return acc; + }, {}); + const term = parsedDiceTerms[dice]; + const termResult = parsedDiceTerms[dice].results[result]; + + const newIndex = parsedDiceTerms[dice].results.length; + await term.reroll(`/r1=${termResult.result}`); + + if (game.modules.get('dice-so-nice')?.active) { + const newResult = parsedDiceTerms[dice].results[newIndex]; + const diceSoNiceRoll = { + _evaluated: true, + dice: [ + new foundry.dice.terms.Die({ + ...term, + total: newResult.result, + faces: term._faces, + results: [newResult] + }) + ], + options: { appearance: {} } + }; + + await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true); + } + + await parsedRoll.evaluate(); + + const results = parsedRoll.dice[dice].results.map(result => ({ + ...result, + discarded: !result.active + })); + const newResult = results.splice(results.length - 1, 1); + results.splice(Number(result) + 1, 0, newResult[0]); + + const rerolledDice = parsedRoll.dice.map((x, index) => { + const isRerollDice = index === Number(dice); + if (!isRerollDice) return { ...x, dice: x.denomination }; + return { + dice: parsedRoll.dice[dice].denomination, + total: parsedRoll.dice[dice].total, + results: results.map(result => ({ + ...result, + hasRerolls: result.hasRerolls || isRerollDice + })) + }; + }); + + const updateMessage = game.messages.get(message._id); + await updateMessage.update({ + [`system.damage.${damageType}`]: { + ...updateMessage, + total: parsedRoll.total, + [`parts.${part}`]: { + ...rollPart, + total: parsedRoll.total, + dice: rerolledDice + } + } + }); + } } diff --git a/module/dice/dhRoll.mjs b/module/dice/dhRoll.mjs index 1b490921..126a7944 100644 --- a/module/dice/dhRoll.mjs +++ b/module/dice/dhRoll.mjs @@ -2,19 +2,19 @@ import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs'; export default class DHRoll extends Roll { baseTerms = []; - constructor(formula, data, options) { + constructor(formula, data = {}, options = {}) { super(formula, data, options); if (!this.data || !Object.keys(this.data).length) this.data = options.data; } get title() { - return game.i18n.localize( - "DAGGERHEART.GENERAL.Roll.basic" - ); + return game.i18n.localize('DAGGERHEART.GENERAL.Roll.basic'); } static messageType = 'adversaryRoll'; + static CHAT_TEMPLATE = 'systems/daggerheart/templates/ui/chat/roll.hbs'; + static DefaultDialog = D20RollDialog; static async build(config = {}, message = {}) { @@ -34,6 +34,8 @@ export default class DHRoll extends Roll { this.applyKeybindings(config); + this.temporaryModifierBuilder(config); + let roll = new this(config.roll.formula, config.data, config); if (config.dialog.configure !== false) { // Open Roll Dialog @@ -64,8 +66,7 @@ export default class DHRoll extends Roll { } // Create Chat Message - if (!config.source?.message) - config.message = await this.toMessage(roll, config); + if (!config.source?.message) config.message = await this.toMessage(roll, config); } static postEvaluate(roll, config = {}) { @@ -92,10 +93,37 @@ export default class DHRoll extends Roll { system: config, rolls: [roll] }; - if(roll._evaluated) return await cls.create(msg, { rollMode: config.selectedRollMode }); + config.selectedRollMode ??= game.settings.get('core', 'rollMode'); + if (roll._evaluated) return await cls.create(msg, { rollMode: config.selectedRollMode }); return msg; } + /** @inheritDoc */ + async render({ flavor, template = this.constructor.CHAT_TEMPLATE, isPrivate = false, ...options } = {}) { + if (!this._evaluated) return; + const chatData = await this._prepareChatRenderContext({ flavor, isPrivate, ...options }); + return foundry.applications.handlebars.renderTemplate(template, chatData); + } + + /** @inheritDoc */ + async _prepareChatRenderContext({ flavor, isPrivate = false, ...options } = {}) { + if (isPrivate) { + return { + user: game.user.id, + flavor: null, + title: '???', + roll: { + total: '??' + }, + hasRoll: true, + isPrivate + }; + } else { + options.message.system.user = game.user.id; + return options.message.system; + } + } + static applyKeybindings(config) { if (config.event) config.dialog.configure ??= !(config.event.shiftKey || config.event.altKey || config.event.ctrlKey); @@ -178,11 +206,15 @@ export default class DHRoll extends Roll { } return modifierTotal; } + + static temporaryModifierBuilder(config) { + return {}; + } } export const registerRollDiceHooks = () => { Hooks.on(`${CONFIG.DH.id}.postRollDuality`, async (config, message) => { - const hopeFearAutomation = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).hopeFear; + const hopeFearAutomation = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).hopeFear; if ( !config.source?.actor || (game.user.isGM ? !hopeFearAutomation.gm : !hopeFearAutomation.players) || @@ -206,8 +238,10 @@ export const registerRollDiceHooks = () => { if (updates.length) { const target = actor.system.partner ?? actor; - if (!['dead', 'unconcious'].some(x => actor.statuses.has(x))) { - target.modifyResource(updates); + if (!['dead', 'unconscious'].some(x => actor.statuses.has(x))) { + setTimeout(() => { + target.modifyResource(updates); + }, 50); } } diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index 3aced0bf..bf535b78 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -124,15 +124,20 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { return tags; } + /** + * Create a new ChatMessage to display this document’s data. + * @param {String} origin - uuid of a document. TODO: This needs to be reviewed. + */ async toChat(origin) { + /**@type {foundry.documents.ChatMessage} */ const cls = getDocumentClass('ChatMessage'); - const actor = game.actors.get(cls.getSpeaker().actor); + const speaker = cls.getSpeaker(); + const actor = cls.getSpeakerActor(speaker); const systemData = { action: { img: this.img, name: this.name }, - actor: { name: actor.name, img: actor.img }, - author: this.author, - speaker: cls.getSpeaker(), - origin: origin, + actor: { name: actor?.name, img: actor?.img }, + speaker, + origin, description: this.description, actions: [] }; diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 910ec4f1..c75db559 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -84,6 +84,8 @@ export default class DhpActor extends Actor { await this.update({ 'system.levelData.level.changed': Math.min(newLevel, maxLevel) }); } else { + const levelupAuto = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto; + const usedLevel = Math.max(newLevel, 1); if (newLevel < 1) { ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.tooLowLevel')); @@ -95,79 +97,90 @@ export default class DhpActor extends Actor { return acc; }, {}); - const features = []; - const domainCards = []; - const experiences = []; - const subclassFeatureState = { class: null, multiclass: null }; - let multiclass = null; - Object.keys(this.system.levelData.levelups) - .filter(x => x > usedLevel) - .forEach(levelKey => { - const level = this.system.levelData.levelups[levelKey]; - const achievementCards = level.achievements.domainCards.map(x => x.itemUuid); - const advancementCards = level.selections.filter(x => x.type === 'domainCard').map(x => x.itemUuid); - domainCards.push(...achievementCards, ...advancementCards); - experiences.push(...Object.keys(level.achievements.experiences)); - features.push(...level.selections.flatMap(x => x.features)); + if (levelupAuto) { + const features = []; + const domainCards = []; + const experiences = []; + const subclassFeatureState = { class: null, multiclass: null }; + let multiclass = null; + Object.keys(this.system.levelData.levelups) + .filter(x => x > usedLevel) + .forEach(levelKey => { + const level = this.system.levelData.levelups[levelKey]; + const achievementCards = level.achievements.domainCards.map(x => x.itemUuid); + const advancementCards = level.selections + .filter(x => x.type === 'domainCard') + .map(x => x.itemUuid); + domainCards.push(...achievementCards, ...advancementCards); + experiences.push(...Object.keys(level.achievements.experiences)); + features.push(...level.selections.flatMap(x => x.features)); - const subclass = level.selections.find(x => x.type === 'subclass'); - if (subclass) { - const path = subclass.secondaryData.isMulticlass === 'true' ? 'multiclass' : 'class'; - const subclassState = Number(subclass.secondaryData.featureState) - 1; - subclassFeatureState[path] = subclassFeatureState[path] - ? Math.min(subclassState, subclassFeatureState[path]) - : subclassState; - } + const subclass = level.selections.find(x => x.type === 'subclass'); + if (subclass) { + const path = subclass.secondaryData.isMulticlass === 'true' ? 'multiclass' : 'class'; + const subclassState = Number(subclass.secondaryData.featureState) - 1; + subclassFeatureState[path] = subclassFeatureState[path] + ? Math.min(subclassState, subclassFeatureState[path]) + : subclassState; + } - multiclass = level.selections.find(x => x.type === 'multiclass'); - }); + multiclass = level.selections.find(x => x.type === 'multiclass'); + }); - for (let feature of features) { - if (feature.onPartner && !this.system.partner) continue; + for (let feature of features) { + if (feature.onPartner && !this.system.partner) continue; - const document = feature.onPartner ? this.system.partner : this; - document.items.get(feature.id)?.delete(); - } - - if (experiences.length > 0) { - const getUpdate = () => ({ - 'system.experiences': experiences.reduce((acc, key) => { - acc[`-=${key}`] = null; - return acc; - }, {}) - }); - this.update(getUpdate()); - if (this.system.companion) { - this.system.companion.update(getUpdate()); + const document = feature.onPartner ? this.system.partner : this; + document.items.get(feature.id)?.delete(); } - } - if (subclassFeatureState.class) { - this.system.class.subclass.update({ 'system.featureState': subclassFeatureState.class }); - } - - if (subclassFeatureState.multiclass) { - this.system.multiclass.subclass.update({ 'system.featureState': subclassFeatureState.multiclass }); - } - - if (multiclass) { - const multiclassSubclass = this.items.find(x => x.type === 'subclass' && x.system.isMulticlass); - const multiclassItem = this.items.find(x => x.uuid === multiclass.itemUuid); - - multiclassSubclass.delete(); - multiclassItem.delete(); - - this.update({ - 'system.multiclass': { - value: null, - subclass: null + if (experiences.length > 0) { + const getUpdate = () => ({ + 'system.experiences': experiences.reduce((acc, key) => { + acc[`-=${key}`] = null; + return acc; + }, {}) + }); + this.update(getUpdate()); + if (this.system.companion) { + this.system.companion.update(getUpdate()); } - }); - } + } - for (let domainCard of domainCards) { - const itemCard = this.items.find(x => x.uuid === domainCard); - itemCard.delete(); + if (subclassFeatureState.class) { + this.system.class.subclass.update({ 'system.featureState': subclassFeatureState.class }); + } + + if (subclassFeatureState.multiclass) { + this.system.multiclass.subclass.update({ 'system.featureState': subclassFeatureState.multiclass }); + } + + if (multiclass) { + const multiclassItem = this.items.find(x => x.uuid === multiclass.itemUuid); + const multiclassFeatures = this.items.filter( + x => x.system.originItemType === 'class' && x.system.identifier === 'multiclass' + ); + const subclassFeatures = this.items.filter( + x => x.system.originItemType === 'subclass' && x.system.identifier === 'multiclass' + ); + + this.deleteEmbeddedDocuments( + 'Item', + [multiclassItem, ...multiclassFeatures, ...subclassFeatures].map(x => x.id) + ); + + this.update({ + 'system.multiclass': { + value: null, + subclass: null + } + }); + } + + for (let domainCard of domainCards) { + const itemCard = this.items.find(x => x.uuid === domainCard); + itemCard.delete(); + } } await this.update({ @@ -315,6 +328,7 @@ export default class DhpActor extends Actor { ...multiclassData, system: { ...multiclassData.system, + features: multiclassData.system.features.filter(x => x.type !== 'hope'), domains: [multiclass.secondaryData.domain], isMulticlass: true } @@ -644,16 +658,23 @@ export default class DhpActor extends Actor { ); break; case 'armor': - updates.armor.resources['system.marks.value'] = Math.max( - Math.min(this.system.armor.system.marks.value + r.value, this.system.armorScore), - 0 - ); + if (this.system.armor?.system?.marks) { + updates.armor.resources['system.marks.value'] = Math.max( + Math.min(this.system.armor.system.marks.value + r.value, this.system.armorScore), + 0 + ); + } break; default: - updates.actor.resources[`system.resources.${r.key}.value`] = Math.max( - Math.min(this.system.resources[r.key].value + r.value, this.system.resources[r.key].max), - 0 - ); + if (this.system.resources?.[r.key]) { + updates.actor.resources[`system.resources.${r.key}.value`] = Math.max( + Math.min( + this.system.resources[r.key].value + r.value, + this.system.resources[r.key].max + ), + 0 + ); + } break; } } diff --git a/module/documents/chatMessage.mjs b/module/documents/chatMessage.mjs index 302ba1d8..2b10e251 100644 --- a/module/documents/chatMessage.mjs +++ b/module/documents/chatMessage.mjs @@ -1,21 +1,61 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { - async renderHTML() { - if (this.system.messageTemplate) - this.content = await foundry.applications.handlebars.renderTemplate(this.system.messageTemplate, { - ...this.system, - _source: this.system._source - }); + targetHook = null; + targetSelection = null; + async renderHTML() { const actor = game.actors.get(this.speaker.actor); - const actorData = actor ?? { - img: this.author.avatar ? this.author.avatar : 'icons/svg/mystery-man.svg', - name: '' - }; + const actorData = + actor && this.isContentVisible + ? actor + : { + img: this.author.avatar ? this.author.avatar : 'icons/svg/mystery-man.svg', + name: '' + }; /* We can change to fully implementing the renderHTML function if needed, instead of augmenting it. */ const html = await super.renderHTML({ actor: actorData, author: this.author }); - this.applyPermission(html); - if (this.type === 'dualityRoll') { + this.enrichChatMessage(html); + this.addChatListeners(html); + + return html; + } + + /* -------------------------------------------- */ + + /** @inheritDoc */ + prepareData() { + if (this.isAuthor && this.targetSelection === null) this.targetSelection = this.system.targets?.length > 0; + super.prepareData(); + } + + /* -------------------------------------------- */ + + /** @inheritDoc */ + _onCreate(data, options, userId) { + super._onCreate(data, options, userId); + if (this.system.registerTargetHook) this.system.registerTargetHook(); + } + + /* -------------------------------------------- */ + + /** @inheritDoc */ + async _preDelete(options, user) { + if (this.targetHook !== null) Hooks.off('targetToken', this.targetHook); + return super._preDelete(options, user); + } + + enrichChatMessage(html) { + const elements = html.querySelectorAll('[data-perm-id]'); + elements.forEach(e => { + const uuid = e.dataset.permId, + document = fromUuidSync(uuid); + if (!document) return; + + e.setAttribute('data-view-perm', document.testUserPermission(game.user, 'OBSERVER')); + e.setAttribute('data-use-perm', document.testUserPermission(game.user, 'OWNER')); + }); + + if (this.isContentVisible && this.type === 'dualityRoll') { html.classList.add('duality'); switch (this.system.roll?.result?.duality) { case 1: @@ -29,36 +69,14 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { break; } } - - this.enrichChatMessage(html); - - return html; - } - - applyPermission(html) { - const elements = html.querySelectorAll('[data-perm-id]'); - elements.forEach(e => { - const uuid = e.dataset.permId, - document = fromUuidSync(uuid); - if (!document) return; - - e.setAttribute('data-view-perm', document.testUserPermission(game.user, 'OBSERVER')); - e.setAttribute('data-use-perm', document.testUserPermission(game.user, 'OWNER')); - }); - } - - async _preCreate(data, options, user) { - options.speaker = ChatMessage.getSpeaker(); - const rollActorOwner = data.rolls?.[0]?.data?.parent?.owner; - if (rollActorOwner) { - data.author = rollActorOwner ? rollActorOwner.id : data.author; - await this.updateSource({ author: rollActorOwner ?? user }); + + if(!game.user.isGM && !this.isAuthor && !this.speakerActor?.isOwner) { + const buttons = html.querySelectorAll(".ability-card-footer > .ability-use-button"); + buttons.forEach(b => b.remove()); } - - return super._preCreate(data, options, rollActorOwner ?? user); } - enrichChatMessage(html) { + addChatListeners(html) { html.querySelectorAll('.damage-button').forEach(element => element.addEventListener('click', this.onDamage.bind(this)) ); @@ -66,10 +84,20 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { html.querySelectorAll('.duality-action-effect').forEach(element => element.addEventListener('click', this.onApplyEffect.bind(this)) ); + + html.querySelectorAll('.roll-target').forEach(element => { + element.addEventListener('mouseenter', this.hoverTarget); + element.addEventListener('mouseleave', this.unhoverTarget); + element.addEventListener('click', this.clickTarget); + }); + + html.querySelectorAll('.button-target-selection').forEach(element => { + element.addEventListener('click', this.onTargetSelection.bind(this)); + }); } getTargetList() { - const targets = this.system.hitTargets; + const targets = this.system.hitTargets ?? []; return targets.map(target => game.canvas.tokens.documentCollection.find(t => t.actor?.uuid === target.actorId)); } @@ -141,9 +169,36 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { } consumeOnSuccess() { - if (!this.system.successConsumed && !this.system.targetSelection) { + if (!this.system.successConsumed && !this.targetSelection) { const action = this.system.action; if (action) action.consume(this.system, true); } } + + hoverTarget(event) { + event.stopPropagation(); + const token = canvas.tokens.get(event.currentTarget.dataset.token); + if (token && !token?.controlled) token._onHoverIn(event, { hoverOutOthers: true }); + } + + unhoverTarget(event) { + const token = canvas.tokens.get(event.currentTarget.dataset.token); + if (token && !token?.controlled) token._onHoverOut(event); + } + + clickTarget(event) { + event.stopPropagation(); + const token = canvas.tokens.get(event.currentTarget.dataset.token); + if (!token) { + ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.attackTargetDoesNotExist')); + return; + } + game.canvas.pan(token); + } + + onTargetSelection(event) { + event.stopPropagation(); + if (!event.target.classList.contains('target-selected')) + this.system.targetMode = Boolean(event.target.dataset.targetHit); + } } diff --git a/module/documents/item.mjs b/module/documents/item.mjs index a261677a..fb558e8c 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -142,19 +142,16 @@ export default class DHItem extends foundry.documents.Item { } } + /** + * Create a new ChatMessage to display this document’s data + * @param {String} origin - uuid of a document. TODO: This needs to be reviewed. + */ async toChat(origin) { + /**@type {foundry.documents.ChatMessage} */ const cls = getDocumentClass('ChatMessage'); const item = await foundry.utils.fromUuid(origin); const systemData = { - title: - 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'), origin: origin, img: this.img, item: { @@ -170,7 +167,6 @@ export default class DHItem extends foundry.documents.Item { type: 'abilityUse', user: game.user.id, actor: item.parent, - author: this.author, speaker: cls.getSpeaker(), system: systemData, title: game.i18n.localize('DAGGERHEART.ACTIONS.Config.displayInChat'), diff --git a/module/helpers/handlebarsHelper.mjs b/module/helpers/handlebarsHelper.mjs index deb62659..171255e2 100644 --- a/module/helpers/handlebarsHelper.mjs +++ b/module/helpers/handlebarsHelper.mjs @@ -60,7 +60,7 @@ export default class RegisterHandlebarsHelpers { static rollParsed(value, actor, item, numerical) { const isNumerical = typeof numerical === 'boolean' ? numerical : false; - const result = itemAbleRollParse(value, actor.getRollData(), item); + const result = itemAbleRollParse(value, actor?.getRollData() ?? {}, item); return isNumerical ? (!result ? 0 : Number(result)) : result; } @@ -69,7 +69,7 @@ export default class RegisterHandlebarsHelpers { } static empty(object) { - if(!(typeof object === 'object')) return true; + if (!(typeof object === 'object')) return true; return Object.keys(object).length === 0; } } diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 7b588fc7..63507782 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -85,7 +85,12 @@ export const chunkify = (array, chunkSize, mappingFunc) => { export const tagifyElement = (element, baseOptions, onChange, tagifyOptions = {}) => { const { maxTags } = tagifyOptions; - const options = typeof baseOptions === 'object' ? Object.values(baseOptions) : baseOptions; + const options = Array.isArray(baseOptions) + ? baseOptions + : Object.keys(baseOptions).map(optionKey => ({ + ...baseOptions[optionKey], + id: optionKey + })); const tagifyElement = new Tagify(element, { tagTextProp: 'name', @@ -172,6 +177,26 @@ Roll.replaceFormulaData = function (formula, data = {}, { missing, warn = false return nativeReplaceFormulaData(formula, data, { missing, warn }); }; +foundry.dice.terms.Die.MODIFIERS.sc = 'selfCorrecting'; + +/** + * Return the configured value as result if 1 is rolled + * Example: 6d6sc6 Roll 6d6, each result of 1 will be changed into 6 + * @param {string} modifier The matched modifier query + */ +foundry.dice.terms.Die.prototype.selfCorrecting = function (modifier) { + const rgx = /(?:sc)([0-9]+)/i; + const match = modifier.match(rgx); + if (!match) return false; + let [target] = match.slice(1); + target = parseInt(target); + for (const r of this.results) { + if (r.result === 1) { + r.result = target; + } + } +}; + export const getDamageKey = damage => { return ['none', 'minor', 'major', 'severe'][damage]; }; diff --git a/src/packs/classes/feature_Prayer_Dice_Xd7RYhfTxIj9aWI2.json b/src/packs/classes/feature_Prayer_Dice_Xd7RYhfTxIj9aWI2.json index 7705d9d6..8203a246 100644 --- a/src/packs/classes/feature_Prayer_Dice_Xd7RYhfTxIj9aWI2.json +++ b/src/packs/classes/feature_Prayer_Dice_Xd7RYhfTxIj9aWI2.json @@ -9,7 +9,7 @@ "resource": { "type": "diceValue", "value": 0, - "max": "2", + "max": "@system.traits.strength.value", "icon": "", "recovery": "session" }, @@ -28,12 +28,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1754352649696, - "modifiedTime": 1754352712334, - "lastModifiedBy": "Q9NoTaEarn3VMS6Z" + "modifiedTime": 1754845640002, + "lastModifiedBy": "H02dtt2xvVJvYESk" }, "_key": "!items!Xd7RYhfTxIj9aWI2" } diff --git a/src/packs/classes/feature_Rally_PydiMnNCKpd44SGS.json b/src/packs/classes/feature_Rally_PydiMnNCKpd44SGS.json index 4b509228..c5933ca8 100644 --- a/src/packs/classes/feature_Rally_PydiMnNCKpd44SGS.json +++ b/src/packs/classes/feature_Rally_PydiMnNCKpd44SGS.json @@ -14,16 +14,7 @@ "description": "", "chatDisplay": false, "actionType": "action", - "cost": [ - { - "scalable": false, - "key": "hitPoints", - "value": 1, - "keyIsID": false, - "step": null, - "consumeOnSuccess": false - } - ], + "cost": [], "uses": { "value": null, "max": "1", @@ -67,7 +58,7 @@ { "key": "system.bonuses.rally", "mode": 2, - "value": "1d6", + "value": "d6", "priority": null } ], diff --git a/src/packs/classes/feature_Rally__Level_5__TVeEyqmPPiRa2r3i.json b/src/packs/classes/feature_Rally__Level_5__TVeEyqmPPiRa2r3i.json index bba20558..da124244 100644 --- a/src/packs/classes/feature_Rally__Level_5__TVeEyqmPPiRa2r3i.json +++ b/src/packs/classes/feature_Rally__Level_5__TVeEyqmPPiRa2r3i.json @@ -14,16 +14,7 @@ "description": "", "chatDisplay": true, "actionType": "action", - "cost": [ - { - "scalable": false, - "key": "hitPoints", - "value": 1, - "keyIsID": false, - "step": null, - "consumeOnSuccess": false - } - ], + "cost": [], "uses": { "value": null, "max": "1", @@ -67,7 +58,7 @@ { "key": "system.bonuses.rally", "mode": 2, - "value": "1d8", + "value": "d8", "priority": null } ], diff --git a/src/packs/classes/feature_Sneak_Attack_5QqpEwmwkPfZHpMW.json b/src/packs/classes/feature_Sneak_Attack_5QqpEwmwkPfZHpMW.json index a0e98763..ec203e9a 100644 --- a/src/packs/classes/feature_Sneak_Attack_5QqpEwmwkPfZHpMW.json +++ b/src/packs/classes/feature_Sneak_Attack_5QqpEwmwkPfZHpMW.json @@ -59,13 +59,13 @@ { "key": "system.bonuses.damage.physical.dice", "mode": 2, - "value": "@system.tierd6", + "value": "@tierd6", "priority": null }, { "key": "system.bonuses.damage.magical.dice", "mode": 2, - "value": "@system.tierd6", + "value": "@tierd6", "priority": null } ], diff --git a/src/packs/domains/domainCard_Gifted_Tracker_VZ2b4zfRzV73XTuT.json b/src/packs/domains/domainCard_Gifted_Tracker_VZ2b4zfRzV73XTuT.json index c274b9ac..a9e66110 100644 --- a/src/packs/domains/domainCard_Gifted_Tracker_VZ2b4zfRzV73XTuT.json +++ b/src/packs/domains/domainCard_Gifted_Tracker_VZ2b4zfRzV73XTuT.json @@ -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" } diff --git a/src/packs/domains/domainCard_Healing_Hands_WTlhnQMajc1r8i50.json b/src/packs/domains/domainCard_Healing_Hands_WTlhnQMajc1r8i50.json index 622e2266..a7aeb6b2 100644 --- a/src/packs/domains/domainCard_Healing_Hands_WTlhnQMajc1r8i50.json +++ b/src/packs/domains/domainCard_Healing_Hands_WTlhnQMajc1r8i50.json @@ -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" } diff --git a/src/packs/domains/domainCard_Life_Ward_OszbCj0jTqq2ADx9.json b/src/packs/domains/domainCard_Life_Ward_OszbCj0jTqq2ADx9.json index efdec150..78b2ec5e 100644 --- a/src/packs/domains/domainCard_Life_Ward_OszbCj0jTqq2ADx9.json +++ b/src/packs/domains/domainCard_Life_Ward_OszbCj0jTqq2ADx9.json @@ -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" } diff --git a/src/packs/domains/domainCard_On_the_Brink_zbxPl81kbWEegKQN.json b/src/packs/domains/domainCard_On_the_Brink_zbxPl81kbWEegKQN.json index a7276bba..b6f6548f 100644 --- a/src/packs/domains/domainCard_On_the_Brink_zbxPl81kbWEegKQN.json +++ b/src/packs/domains/domainCard_On_the_Brink_zbxPl81kbWEegKQN.json @@ -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" } diff --git a/src/packs/items/weapons/weapon_Aantari_Bow_ijodu5yNBoMxpkHV.json b/src/packs/items/weapons/weapon_Aantari_Bow_ijodu5yNBoMxpkHV.json index 16c4b359..0dc1f068 100644 --- a/src/packs/items/weapons/weapon_Aantari_Bow_ijodu5yNBoMxpkHV.json +++ b/src/packs/items/weapons/weapon_Aantari_Bow_ijodu5yNBoMxpkHV.json @@ -16,7 +16,7 @@ { "value": "reliable", "effectIds": [ - "HrbJ0bI7lMAYUCux" + "nRNnU57i7RMJoklC" ], "actionIds": [] } @@ -109,14 +109,21 @@ "img": "icons/skills/melee/strike-sword-slashing-red.webp", "changes": [ { - "key": "system.bonuses.roll.primaryWeapon.attack", + "key": "system.bonuses.roll.primaryWeapon.bonus", "mode": 2, "value": "1" } ], - "_id": "HrbJ0bI7lMAYUCux", + "_id": "nRNnU57i7RMJoklC", "type": "base", - "system": {}, + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753835307838, - "modifiedTime": 1753835307838, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754815224718, + "modifiedTime": 1754815224718, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!ijodu5yNBoMxpkHV.HrbJ0bI7lMAYUCux" + "_key": "!items.effects!ijodu5yNBoMxpkHV.nRNnU57i7RMJoklC" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753835285790, - "modifiedTime": 1753835317605, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754815224721, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!ijodu5yNBoMxpkHV" } diff --git a/src/packs/items/weapons/weapon_Advanced_Arcane_Frame_Wheelchair_la3sAWgnvadc4NvP.json b/src/packs/items/weapons/weapon_Advanced_Arcane_Frame_Wheelchair_la3sAWgnvadc4NvP.json index f0796325..0abfe057 100644 --- a/src/packs/items/weapons/weapon_Advanced_Arcane_Frame_Wheelchair_la3sAWgnvadc4NvP.json +++ b/src/packs/items/weapons/weapon_Advanced_Arcane_Frame_Wheelchair_la3sAWgnvadc4NvP.json @@ -2,7 +2,7 @@ "folder": "TyqMEXhSkjOUq5SA", "name": "Advanced Arcane-Frame Wheelchair", "type": "weapon", - "img": "icons/svg/item-bag.svg", + "img": "systems/daggerheart/assets/icons/documents/items/ArcaneWheelchair.webp", "system": { "description": "", "actions": {}, @@ -15,7 +15,7 @@ { "value": "reliable", "effectIds": [ - "G561ymlNGmaFAYFB" + "VnV5X9MBMabhz47b" ], "actionIds": [] } @@ -108,14 +108,21 @@ "img": "icons/skills/melee/strike-sword-slashing-red.webp", "changes": [ { - "key": "system.bonuses.roll.primaryWeapon.attack", + "key": "system.bonuses.roll.primaryWeapon.bonus", "mode": 2, "value": "1" } ], - "_id": "G561ymlNGmaFAYFB", + "_id": "VnV5X9MBMabhz47b", "type": "base", - "system": {}, + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, "disabled": false, "duration": { "startTime": null, @@ -131,12 +138,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "lastModifiedBy": null + "systemVersion": "1.0.0", + "createdTime": 1754815300372, + "modifiedTime": 1754815300372, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!la3sAWgnvadc4NvP.G561ymlNGmaFAYFB" + "_key": "!items.effects!la3sAWgnvadc4NvP.VnV5X9MBMabhz47b" } ], "ownership": { @@ -148,12 +157,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753836715885, - "modifiedTime": 1753836789197, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754845968271, + "lastModifiedBy": "H02dtt2xvVJvYESk" }, "_id": "la3sAWgnvadc4NvP", "sort": 0, diff --git a/src/packs/items/weapons/weapon_Advanced_Broadsword_WtQAGz0TUgz8Xg70.json b/src/packs/items/weapons/weapon_Advanced_Broadsword_WtQAGz0TUgz8Xg70.json index ad5ad7ae..19a6d9bf 100644 --- a/src/packs/items/weapons/weapon_Advanced_Broadsword_WtQAGz0TUgz8Xg70.json +++ b/src/packs/items/weapons/weapon_Advanced_Broadsword_WtQAGz0TUgz8Xg70.json @@ -16,7 +16,7 @@ { "value": "reliable", "effectIds": [ - "fRPKHzbKRz4yTHAF" + "wu2AmDvgeWI3hmRQ" ], "actionIds": [] } @@ -109,14 +109,21 @@ "img": "icons/skills/melee/strike-sword-slashing-red.webp", "changes": [ { - "key": "system.bonuses.roll.primaryWeapon.attack", + "key": "system.bonuses.roll.primaryWeapon.bonus", "mode": 2, "value": "1" } ], - "_id": "fRPKHzbKRz4yTHAF", + "_id": "wu2AmDvgeWI3hmRQ", "type": "base", - "system": {}, + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753831629563, - "modifiedTime": 1753831629563, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754814950116, + "modifiedTime": 1754814950116, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!WtQAGz0TUgz8Xg70.fRPKHzbKRz4yTHAF" + "_key": "!items.effects!WtQAGz0TUgz8Xg70.wu2AmDvgeWI3hmRQ" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753831599435, - "modifiedTime": 1753831629573, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814950120, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!WtQAGz0TUgz8Xg70" } diff --git a/src/packs/items/weapons/weapon_Advanced_Heavy_Frame_Wheelchair_eT2Qwb0RdrLX2hH1.json b/src/packs/items/weapons/weapon_Advanced_Heavy_Frame_Wheelchair_eT2Qwb0RdrLX2hH1.json index 34383448..f8257028 100644 --- a/src/packs/items/weapons/weapon_Advanced_Heavy_Frame_Wheelchair_eT2Qwb0RdrLX2hH1.json +++ b/src/packs/items/weapons/weapon_Advanced_Heavy_Frame_Wheelchair_eT2Qwb0RdrLX2hH1.json @@ -2,7 +2,7 @@ "folder": "TyqMEXhSkjOUq5SA", "name": "Advanced Heavy-Frame Wheelchair", "type": "weapon", - "img": "icons/svg/item-bag.svg", + "img": "systems/daggerheart/assets/icons/documents/items/HeavyWheelchair.webp", "system": { "description": "", "actions": {}, @@ -148,12 +148,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", "systemVersion": "0.0.1", "createdTime": 1753836675558, - "modifiedTime": 1753836795905, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754845996869, + "lastModifiedBy": "H02dtt2xvVJvYESk" }, "_id": "eT2Qwb0RdrLX2hH1", "sort": 0, diff --git a/src/packs/items/weapons/weapon_Advanced_Light_Frame_Wheelchair_BuMfupnCzHbziQ8o.json b/src/packs/items/weapons/weapon_Advanced_Light_Frame_Wheelchair_BuMfupnCzHbziQ8o.json index add61418..324af2b1 100644 --- a/src/packs/items/weapons/weapon_Advanced_Light_Frame_Wheelchair_BuMfupnCzHbziQ8o.json +++ b/src/packs/items/weapons/weapon_Advanced_Light_Frame_Wheelchair_BuMfupnCzHbziQ8o.json @@ -2,7 +2,7 @@ "folder": "TyqMEXhSkjOUq5SA", "name": "Advanced Light-Frame Wheelchair", "type": "weapon", - "img": "icons/svg/item-bag.svg", + "img": "systems/daggerheart/assets/icons/documents/items/LightWheelchair.webp", "system": { "description": "", "actions": { @@ -141,12 +141,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", "systemVersion": "0.0.1", "createdTime": 1753836614032, - "modifiedTime": 1753836802197, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754846020904, + "lastModifiedBy": "H02dtt2xvVJvYESk" }, "_id": "BuMfupnCzHbziQ8o", "sort": 0, diff --git a/src/packs/items/weapons/weapon_Advanced_Longsword_9xkB3MWXahrsVP4N.json b/src/packs/items/weapons/weapon_Advanced_Longsword_9xkB3MWXahrsVP4N.json index 79ce8416..8b44c759 100644 --- a/src/packs/items/weapons/weapon_Advanced_Longsword_9xkB3MWXahrsVP4N.json +++ b/src/packs/items/weapons/weapon_Advanced_Longsword_9xkB3MWXahrsVP4N.json @@ -43,7 +43,7 @@ "parts": [ { "value": { - "dice": "d8", + "dice": "d10", "bonus": 9, "multiplier": "prof", "flatMultiplier": 1, diff --git a/src/packs/items/weapons/weapon_Advanced_Small_Dagger_0thN0BpN05KT8Avx.json b/src/packs/items/weapons/weapon_Advanced_Small_Dagger_0thN0BpN05KT8Avx.json index cf3ae063..bfcef598 100644 --- a/src/packs/items/weapons/weapon_Advanced_Small_Dagger_0thN0BpN05KT8Avx.json +++ b/src/packs/items/weapons/weapon_Advanced_Small_Dagger_0thN0BpN05KT8Avx.json @@ -16,7 +16,7 @@ { "value": "paired", "effectIds": [ - "gJ7Ey9CfPZqYgxEO" + "MYgB3v3oQ5lIr3VE" ], "actionIds": [] } @@ -114,9 +114,16 @@ "value": "ITEM.@system.tier + 1" } ], - "_id": "gJ7Ey9CfPZqYgxEO", + "system": { + "rangeDependence": { + "enabled": true, + "range": "melee", + "target": "hostile", + "type": "withinRange" + } + }, + "_id": "MYgB3v3oQ5lIr3VE", "type": "base", - "system": {}, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753794991410, - "modifiedTime": 1753794991410, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754814673988, + "modifiedTime": 1754814673988, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!0thN0BpN05KT8Avx.gJ7Ey9CfPZqYgxEO" + "_key": "!items.effects!0thN0BpN05KT8Avx.MYgB3v3oQ5lIr3VE" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753794938643, - "modifiedTime": 1753794991413, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814673991, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!0thN0BpN05KT8Avx" } diff --git a/src/packs/items/weapons/weapon_Advanced_Spear_pK6dsNABKKp1CIGN.json b/src/packs/items/weapons/weapon_Advanced_Spear_pK6dsNABKKp1CIGN.json index 433533e3..0bfb4a8f 100644 --- a/src/packs/items/weapons/weapon_Advanced_Spear_pK6dsNABKKp1CIGN.json +++ b/src/packs/items/weapons/weapon_Advanced_Spear_pK6dsNABKKp1CIGN.json @@ -12,15 +12,7 @@ "equipped": false, "secondary": false, "burden": "twoHanded", - "weaponFeatures": [ - { - "value": "cumbersome", - "effectIds": [ - "hl0S2LrBY5Mg69q6" - ], - "actionIds": [] - } - ], + "weaponFeatures": [], "attack": { "name": "Attack", "img": "icons/skills/melee/blood-slash-foam-red.webp", @@ -51,8 +43,8 @@ "parts": [ { "value": { - "dice": "d10", - "bonus": 8, + "dice": "d8", + "bonus": 9, "multiplier": "prof", "flatMultiplier": 1, "custom": { diff --git a/src/packs/items/weapons/weapon_Arcane_Frame_Wheelchair_XRChepscgr75Uug7.json b/src/packs/items/weapons/weapon_Arcane_Frame_Wheelchair_XRChepscgr75Uug7.json index 6d18e14c..3dd7d463 100644 --- a/src/packs/items/weapons/weapon_Arcane_Frame_Wheelchair_XRChepscgr75Uug7.json +++ b/src/packs/items/weapons/weapon_Arcane_Frame_Wheelchair_XRChepscgr75Uug7.json @@ -3,7 +3,7 @@ "name": "Arcane-Frame Wheelchair", "type": "weapon", "_id": "XRChepscgr75Uug7", - "img": "icons/svg/item-bag.svg", + "img": "systems/daggerheart/assets/icons/documents/items/ArcaneWheelchair.webp", "system": { "description": "", "actions": {}, @@ -16,7 +16,7 @@ { "value": "reliable", "effectIds": [ - "G561ymlNGmaFAYFB" + "dXHsy9qr5FWZqsVq" ], "actionIds": [] } @@ -109,14 +109,21 @@ "img": "icons/skills/melee/strike-sword-slashing-red.webp", "changes": [ { - "key": "system.bonuses.roll.primaryWeapon.attack", + "key": "system.bonuses.roll.primaryWeapon.bonus", "mode": 2, "value": "1" } ], - "_id": "G561ymlNGmaFAYFB", + "_id": "dXHsy9qr5FWZqsVq", "type": "base", - "system": {}, + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753836707582, - "modifiedTime": 1753836707582, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754815278217, + "modifiedTime": 1754815278217, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!XRChepscgr75Uug7.G561ymlNGmaFAYFB" + "_key": "!items.effects!XRChepscgr75Uug7.dXHsy9qr5FWZqsVq" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753836689082, - "modifiedTime": 1753836707594, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754845945327, + "lastModifiedBy": "H02dtt2xvVJvYESk" }, "_key": "!items!XRChepscgr75Uug7" } diff --git a/src/packs/items/weapons/weapon_Broadsword_1cwWNt4sqlgA8gCT.json b/src/packs/items/weapons/weapon_Broadsword_1cwWNt4sqlgA8gCT.json index 1934036f..959a8547 100644 --- a/src/packs/items/weapons/weapon_Broadsword_1cwWNt4sqlgA8gCT.json +++ b/src/packs/items/weapons/weapon_Broadsword_1cwWNt4sqlgA8gCT.json @@ -16,7 +16,7 @@ { "value": "reliable", "effectIds": [ - "GNwIa1EAaa0T0RZi" + "mqcpj2cFAprf2AmY" ], "actionIds": [] } @@ -109,14 +109,21 @@ "img": "icons/skills/melee/strike-sword-slashing-red.webp", "changes": [ { - "key": "system.bonuses.roll.primaryWeapon.attack", + "key": "system.bonuses.roll.primaryWeapon.bonus", "mode": 2, "value": "1" } ], - "_id": "GNwIa1EAaa0T0RZi", + "_id": "mqcpj2cFAprf2AmY", "type": "base", - "system": {}, + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753827762112, - "modifiedTime": 1753827762112, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754814769818, + "modifiedTime": 1754814769818, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!1cwWNt4sqlgA8gCT.GNwIa1EAaa0T0RZi" + "_key": "!items.effects!1cwWNt4sqlgA8gCT.mqcpj2cFAprf2AmY" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753827734892, - "modifiedTime": 1753827762118, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814769821, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!1cwWNt4sqlgA8gCT" } diff --git a/src/packs/items/weapons/weapon_Heavy_Frame_Wheelchair_XjPQjhRCH08VUIbr.json b/src/packs/items/weapons/weapon_Heavy_Frame_Wheelchair_XjPQjhRCH08VUIbr.json index 92131406..b4c48925 100644 --- a/src/packs/items/weapons/weapon_Heavy_Frame_Wheelchair_XjPQjhRCH08VUIbr.json +++ b/src/packs/items/weapons/weapon_Heavy_Frame_Wheelchair_XjPQjhRCH08VUIbr.json @@ -3,7 +3,7 @@ "name": "Heavy-Frame Wheelchair", "type": "weapon", "_id": "XjPQjhRCH08VUIbr", - "img": "icons/svg/item-bag.svg", + "img": "systems/daggerheart/assets/icons/documents/items/HeavyWheelchair.webp", "system": { "description": "", "actions": {}, @@ -152,12 +152,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", "systemVersion": "0.0.1", "createdTime": 1753836652314, - "modifiedTime": 1753836667128, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754845988869, + "lastModifiedBy": "H02dtt2xvVJvYESk" }, "_key": "!items!XjPQjhRCH08VUIbr" } diff --git a/src/packs/items/weapons/weapon_Improved_Arcane_Frame_Wheelchair_N9P695V5KKlJbAY5.json b/src/packs/items/weapons/weapon_Improved_Arcane_Frame_Wheelchair_N9P695V5KKlJbAY5.json index 36070ae1..69744aab 100644 --- a/src/packs/items/weapons/weapon_Improved_Arcane_Frame_Wheelchair_N9P695V5KKlJbAY5.json +++ b/src/packs/items/weapons/weapon_Improved_Arcane_Frame_Wheelchair_N9P695V5KKlJbAY5.json @@ -2,7 +2,7 @@ "folder": "fFuMdvpD1F3UshmM", "name": "Improved Arcane-Frame Wheelchair", "type": "weapon", - "img": "icons/svg/item-bag.svg", + "img": "systems/daggerheart/assets/icons/documents/items/ArcaneWheelchair.webp", "system": { "description": "", "actions": {}, @@ -15,7 +15,7 @@ { "value": "reliable", "effectIds": [ - "G561ymlNGmaFAYFB" + "1f6fFhOLwZrmA6e5" ], "actionIds": [] } @@ -108,14 +108,21 @@ "img": "icons/skills/melee/strike-sword-slashing-red.webp", "changes": [ { - "key": "system.bonuses.roll.primaryWeapon.attack", + "key": "system.bonuses.roll.primaryWeapon.bonus", "mode": 2, "value": "1" } ], - "_id": "G561ymlNGmaFAYFB", + "_id": "1f6fFhOLwZrmA6e5", "type": "base", - "system": {}, + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, "disabled": false, "duration": { "startTime": null, @@ -131,12 +138,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "lastModifiedBy": null + "systemVersion": "1.0.0", + "createdTime": 1754815290648, + "modifiedTime": 1754815290648, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!N9P695V5KKlJbAY5.G561ymlNGmaFAYFB" + "_key": "!items.effects!N9P695V5KKlJbAY5.1f6fFhOLwZrmA6e5" } ], "ownership": { @@ -148,12 +157,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753836714712, - "modifiedTime": 1753836748404, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754845960700, + "lastModifiedBy": "H02dtt2xvVJvYESk" }, "_id": "N9P695V5KKlJbAY5", "sort": 0, diff --git a/src/packs/items/weapons/weapon_Improved_Broadsword_OcKeLJxvmdT81VBc.json b/src/packs/items/weapons/weapon_Improved_Broadsword_OcKeLJxvmdT81VBc.json index dad2f4db..69e46858 100644 --- a/src/packs/items/weapons/weapon_Improved_Broadsword_OcKeLJxvmdT81VBc.json +++ b/src/packs/items/weapons/weapon_Improved_Broadsword_OcKeLJxvmdT81VBc.json @@ -16,7 +16,7 @@ { "value": "reliable", "effectIds": [ - "xU0DD5ydbwmXMKtF" + "228lcQpohdJ3Bbga" ], "actionIds": [] } @@ -109,14 +109,21 @@ "img": "icons/skills/melee/strike-sword-slashing-red.webp", "changes": [ { - "key": "system.bonuses.roll.primaryWeapon.attack", + "key": "system.bonuses.roll.primaryWeapon.bonus", "mode": 2, "value": "1" } ], - "_id": "xU0DD5ydbwmXMKtF", + "_id": "228lcQpohdJ3Bbga", "type": "base", - "system": {}, + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753829126416, - "modifiedTime": 1753829126416, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754814935810, + "modifiedTime": 1754814935810, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!OcKeLJxvmdT81VBc.xU0DD5ydbwmXMKtF" + "_key": "!items.effects!OcKeLJxvmdT81VBc.228lcQpohdJ3Bbga" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753829098118, - "modifiedTime": 1753829367508, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814935815, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!OcKeLJxvmdT81VBc" } diff --git a/src/packs/items/weapons/weapon_Improved_Heavy_Frame_Wheelchair_L5KeCtrs768PmYWW.json b/src/packs/items/weapons/weapon_Improved_Heavy_Frame_Wheelchair_L5KeCtrs768PmYWW.json index 41abaff0..70531b7c 100644 --- a/src/packs/items/weapons/weapon_Improved_Heavy_Frame_Wheelchair_L5KeCtrs768PmYWW.json +++ b/src/packs/items/weapons/weapon_Improved_Heavy_Frame_Wheelchair_L5KeCtrs768PmYWW.json @@ -2,7 +2,7 @@ "folder": "fFuMdvpD1F3UshmM", "name": "Improved Heavy-Frame Wheelchair", "type": "weapon", - "img": "icons/svg/item-bag.svg", + "img": "systems/daggerheart/assets/icons/documents/items/HeavyWheelchair.webp", "system": { "description": "", "actions": {}, @@ -148,12 +148,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", "systemVersion": "0.0.1", "createdTime": 1753836674233, - "modifiedTime": 1753836769685, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754845992757, + "lastModifiedBy": "H02dtt2xvVJvYESk" }, "_id": "L5KeCtrs768PmYWW", "sort": 0, diff --git a/src/packs/items/weapons/weapon_Improved_Light_Frame_Wheelchair_ZJsetdHKV77ygtCE.json b/src/packs/items/weapons/weapon_Improved_Light_Frame_Wheelchair_ZJsetdHKV77ygtCE.json index c750bac9..737e2c55 100644 --- a/src/packs/items/weapons/weapon_Improved_Light_Frame_Wheelchair_ZJsetdHKV77ygtCE.json +++ b/src/packs/items/weapons/weapon_Improved_Light_Frame_Wheelchair_ZJsetdHKV77ygtCE.json @@ -2,7 +2,7 @@ "folder": "fFuMdvpD1F3UshmM", "name": "Improved Light-Frame Wheelchair", "type": "weapon", - "img": "icons/svg/item-bag.svg", + "img": "systems/daggerheart/assets/icons/documents/items/LightWheelchair.webp", "system": { "description": "", "actions": { @@ -141,12 +141,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", "systemVersion": "0.0.1", "createdTime": 1753836612291, - "modifiedTime": 1753836778961, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754846018260, + "lastModifiedBy": "H02dtt2xvVJvYESk" }, "_id": "ZJsetdHKV77ygtCE", "sort": 0, diff --git a/src/packs/items/weapons/weapon_Improved_Longsword_QyBZ5NxM8F9nCL9s.json b/src/packs/items/weapons/weapon_Improved_Longsword_QyBZ5NxM8F9nCL9s.json index 867a563f..b064b1c2 100644 --- a/src/packs/items/weapons/weapon_Improved_Longsword_QyBZ5NxM8F9nCL9s.json +++ b/src/packs/items/weapons/weapon_Improved_Longsword_QyBZ5NxM8F9nCL9s.json @@ -43,7 +43,7 @@ "parts": [ { "value": { - "dice": "d8", + "dice": "d10", "bonus": 6, "multiplier": "prof", "flatMultiplier": 1, diff --git a/src/packs/items/weapons/weapon_Improved_Shortsword_rSyBNRwemBVuTo3H.json b/src/packs/items/weapons/weapon_Improved_Shortsword_rSyBNRwemBVuTo3H.json index 65f03b0b..fb585281 100644 --- a/src/packs/items/weapons/weapon_Improved_Shortsword_rSyBNRwemBVuTo3H.json +++ b/src/packs/items/weapons/weapon_Improved_Shortsword_rSyBNRwemBVuTo3H.json @@ -16,7 +16,7 @@ { "value": "paired", "effectIds": [ - "cSmiIOXeuw0xpjel" + "9iHHwd9BxkBsV9lY" ], "actionIds": [] } @@ -114,9 +114,16 @@ "value": "ITEM.@system.tier + 1" } ], - "_id": "cSmiIOXeuw0xpjel", + "system": { + "rangeDependence": { + "enabled": true, + "range": "melee", + "target": "hostile", + "type": "withinRange" + } + }, + "_id": "9iHHwd9BxkBsV9lY", "type": "base", - "system": {}, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753794021004, - "modifiedTime": 1753794021004, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754814695260, + "modifiedTime": 1754814695260, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!rSyBNRwemBVuTo3H.cSmiIOXeuw0xpjel" + "_key": "!items.effects!rSyBNRwemBVuTo3H.9iHHwd9BxkBsV9lY" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753744566951, - "modifiedTime": 1753794021010, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814695265, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!rSyBNRwemBVuTo3H" } diff --git a/src/packs/items/weapons/weapon_Improved_Small_Dagger_nMuF8ZDZ2aXZVTg6.json b/src/packs/items/weapons/weapon_Improved_Small_Dagger_nMuF8ZDZ2aXZVTg6.json index 04379b71..e141fbc2 100644 --- a/src/packs/items/weapons/weapon_Improved_Small_Dagger_nMuF8ZDZ2aXZVTg6.json +++ b/src/packs/items/weapons/weapon_Improved_Small_Dagger_nMuF8ZDZ2aXZVTg6.json @@ -16,7 +16,7 @@ { "value": "paired", "effectIds": [ - "rOjtLkrnI9EZHJm8" + "JHIUGyZH5q83ODvd" ], "actionIds": [] } @@ -114,9 +114,16 @@ "value": "ITEM.@system.tier + 1" } ], - "_id": "rOjtLkrnI9EZHJm8", + "system": { + "rangeDependence": { + "enabled": true, + "range": "melee", + "target": "hostile", + "type": "withinRange" + } + }, + "_id": "JHIUGyZH5q83ODvd", "type": "base", - "system": {}, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753794340876, - "modifiedTime": 1753794340876, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754814703717, + "modifiedTime": 1754814703717, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!nMuF8ZDZ2aXZVTg6.rOjtLkrnI9EZHJm8" + "_key": "!items.effects!nMuF8ZDZ2aXZVTg6.JHIUGyZH5q83ODvd" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753794291887, - "modifiedTime": 1753794340879, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814703719, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!nMuF8ZDZ2aXZVTg6" } diff --git a/src/packs/items/weapons/weapon_Improved_Spear_j5Pt1thLfcvopBij.json b/src/packs/items/weapons/weapon_Improved_Spear_j5Pt1thLfcvopBij.json index beb295d6..367f80ad 100644 --- a/src/packs/items/weapons/weapon_Improved_Spear_j5Pt1thLfcvopBij.json +++ b/src/packs/items/weapons/weapon_Improved_Spear_j5Pt1thLfcvopBij.json @@ -12,15 +12,7 @@ "equipped": false, "secondary": false, "burden": "twoHanded", - "weaponFeatures": [ - { - "value": "cumbersome", - "effectIds": [ - "8twXPJELZpvFWA5K" - ], - "actionIds": [] - } - ], + "weaponFeatures": [], "attack": { "name": "Attack", "img": "icons/skills/melee/blood-slash-foam-red.webp", @@ -51,8 +43,8 @@ "parts": [ { "value": { - "dice": "d10", - "bonus": 5, + "dice": "d8", + "bonus": 6, "multiplier": "prof", "flatMultiplier": 1, "custom": { diff --git a/src/packs/items/weapons/weapon_Keeper_s_Staff_q382JqMkqLaaFLIr.json b/src/packs/items/weapons/weapon_Keeper_s_Staff_q382JqMkqLaaFLIr.json index c7b5c32f..d934731d 100644 --- a/src/packs/items/weapons/weapon_Keeper_s_Staff_q382JqMkqLaaFLIr.json +++ b/src/packs/items/weapons/weapon_Keeper_s_Staff_q382JqMkqLaaFLIr.json @@ -16,7 +16,7 @@ { "value": "reliable", "effectIds": [ - "FlmOrbhYbieIAVJL" + "LvxPAfrKuRfgubGV" ], "actionIds": [] } @@ -109,14 +109,21 @@ "img": "icons/skills/melee/strike-sword-slashing-red.webp", "changes": [ { - "key": "system.bonuses.roll.primaryWeapon.attack", + "key": "system.bonuses.roll.primaryWeapon.bonus", "mode": 2, "value": "1" } ], - "_id": "FlmOrbhYbieIAVJL", + "_id": "LvxPAfrKuRfgubGV", "type": "base", - "system": {}, + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753831441325, - "modifiedTime": 1753831441325, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754815023490, + "modifiedTime": 1754815023490, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!q382JqMkqLaaFLIr.FlmOrbhYbieIAVJL" + "_key": "!items.effects!q382JqMkqLaaFLIr.LvxPAfrKuRfgubGV" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753831418620, - "modifiedTime": 1753831441332, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754815023493, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!q382JqMkqLaaFLIr" } diff --git a/src/packs/items/weapons/weapon_Knuckle_Claws_SFqganS8Du4aEKjQ.json b/src/packs/items/weapons/weapon_Knuckle_Claws_SFqganS8Du4aEKjQ.json index c65353db..f2f53dc7 100644 --- a/src/packs/items/weapons/weapon_Knuckle_Claws_SFqganS8Du4aEKjQ.json +++ b/src/packs/items/weapons/weapon_Knuckle_Claws_SFqganS8Du4aEKjQ.json @@ -7,63 +7,22 @@ "system": { "description": "", "actions": { - "fRKcEeShWSLkoExh": { + "B0uT1D1WRidiHxyh": { "type": "effect", "actionType": "action", "chatDisplay": true, "name": "Double Up", "description": "When you make an attack with your primary weapon, you can deal damage to another target within Melee range.", "img": "icons/skills/melee/strike-slashes-orange.webp", - "_id": "fRKcEeShWSLkoExh", + "_id": "B0uT1D1WRidiHxyh", "effects": [], "systemPath": "actions", "cost": [], "uses": { "value": null, "max": null, - "recovery": null - }, - "target": { - "type": "any", - "amount": null - } - }, - "lVsEmJwjYgpYL9l4": { - "type": "effect", - "actionType": "action", - "chatDisplay": true, - "name": "Double Up", - "description": "When you make an attack with your primary weapon, you can deal damage to another target within Melee range.", - "img": "icons/skills/melee/strike-slashes-orange.webp", - "_id": "lVsEmJwjYgpYL9l4", - "effects": [], - "systemPath": "actions", - "cost": [], - "uses": { - "value": null, - "max": null, - "recovery": null - }, - "target": { - "type": "any", - "amount": null - } - }, - "2ndqofzTHsEUMxsm": { - "type": "effect", - "actionType": "action", - "chatDisplay": true, - "name": "Double Up", - "description": "When you make an attack with your primary weapon, you can deal damage to another target within Melee range.", - "img": "icons/skills/melee/strike-slashes-orange.webp", - "_id": "2ndqofzTHsEUMxsm", - "effects": [], - "systemPath": "actions", - "cost": [], - "uses": { - "value": null, - "max": null, - "recovery": null + "recovery": null, + "consumeOnSuccess": false }, "target": { "type": "any", @@ -81,7 +40,7 @@ "value": "doubledUp", "effectIds": [], "actionIds": [ - "2ndqofzTHsEUMxsm" + "B0uT1D1WRidiHxyh" ] } ], @@ -177,12 +136,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753797258168, - "modifiedTime": 1753798882899, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814600761, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!SFqganS8Du4aEKjQ" } diff --git a/src/packs/items/weapons/weapon_Legendary_Arcane_Frame_Wheelchair_gA2tiET9VHGhwMoO.json b/src/packs/items/weapons/weapon_Legendary_Arcane_Frame_Wheelchair_gA2tiET9VHGhwMoO.json index 16211d24..b402692f 100644 --- a/src/packs/items/weapons/weapon_Legendary_Arcane_Frame_Wheelchair_gA2tiET9VHGhwMoO.json +++ b/src/packs/items/weapons/weapon_Legendary_Arcane_Frame_Wheelchair_gA2tiET9VHGhwMoO.json @@ -2,7 +2,7 @@ "folder": "beilKE5ZPAihKg3O", "name": "Legendary Arcane-Frame Wheelchair", "type": "weapon", - "img": "icons/svg/item-bag.svg", + "img": "systems/daggerheart/assets/icons/documents/items/ArcaneWheelchair.webp", "system": { "description": "", "actions": {}, @@ -15,7 +15,7 @@ { "value": "reliable", "effectIds": [ - "G561ymlNGmaFAYFB" + "TvsoAiqHCwgtYat1" ], "actionIds": [] } @@ -108,14 +108,21 @@ "img": "icons/skills/melee/strike-sword-slashing-red.webp", "changes": [ { - "key": "system.bonuses.roll.primaryWeapon.attack", + "key": "system.bonuses.roll.primaryWeapon.bonus", "mode": 2, "value": "1" } ], - "_id": "G561ymlNGmaFAYFB", + "_id": "TvsoAiqHCwgtYat1", "type": "base", - "system": {}, + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, "disabled": false, "duration": { "startTime": null, @@ -131,12 +138,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "lastModifiedBy": null + "systemVersion": "1.0.0", + "createdTime": 1754815308723, + "modifiedTime": 1754815308723, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!gA2tiET9VHGhwMoO.G561ymlNGmaFAYFB" + "_key": "!items.effects!gA2tiET9VHGhwMoO.TvsoAiqHCwgtYat1" } ], "ownership": { @@ -148,12 +157,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753836717240, - "modifiedTime": 1753836812453, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754845972571, + "lastModifiedBy": "H02dtt2xvVJvYESk" }, "_id": "gA2tiET9VHGhwMoO", "sort": 0, diff --git a/src/packs/items/weapons/weapon_Legendary_Broadsword_y3hfTPfZhMognyaJ.json b/src/packs/items/weapons/weapon_Legendary_Broadsword_y3hfTPfZhMognyaJ.json index ca0622de..32d19734 100644 --- a/src/packs/items/weapons/weapon_Legendary_Broadsword_y3hfTPfZhMognyaJ.json +++ b/src/packs/items/weapons/weapon_Legendary_Broadsword_y3hfTPfZhMognyaJ.json @@ -16,7 +16,7 @@ { "value": "reliable", "effectIds": [ - "lmUzKw6J6RW3krRT" + "ujb6VAqjyXmfnnjy" ], "actionIds": [] } @@ -109,14 +109,21 @@ "img": "icons/skills/melee/strike-sword-slashing-red.webp", "changes": [ { - "key": "system.bonuses.roll.primaryWeapon.attack", + "key": "system.bonuses.roll.primaryWeapon.bonus", "mode": 2, "value": "1" } ], - "_id": "lmUzKw6J6RW3krRT", + "_id": "ujb6VAqjyXmfnnjy", "type": "base", - "system": {}, + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753834461846, - "modifiedTime": 1753834461846, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754814961439, + "modifiedTime": 1754814961439, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!y3hfTPfZhMognyaJ.lmUzKw6J6RW3krRT" + "_key": "!items.effects!y3hfTPfZhMognyaJ.ujb6VAqjyXmfnnjy" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753834430378, - "modifiedTime": 1753834465538, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814961454, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!y3hfTPfZhMognyaJ" } diff --git a/src/packs/items/weapons/weapon_Legendary_Heavy_Frame_Wheelchair_S6nB0CNlzdU05o5U.json b/src/packs/items/weapons/weapon_Legendary_Heavy_Frame_Wheelchair_S6nB0CNlzdU05o5U.json index ade62012..d337d32f 100644 --- a/src/packs/items/weapons/weapon_Legendary_Heavy_Frame_Wheelchair_S6nB0CNlzdU05o5U.json +++ b/src/packs/items/weapons/weapon_Legendary_Heavy_Frame_Wheelchair_S6nB0CNlzdU05o5U.json @@ -2,7 +2,7 @@ "folder": "beilKE5ZPAihKg3O", "name": "Legendary Heavy-Frame Wheelchair", "type": "weapon", - "img": "icons/svg/item-bag.svg", + "img": "systems/daggerheart/assets/icons/documents/items/HeavyWheelchair.webp", "system": { "description": "", "actions": {}, @@ -148,12 +148,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", "systemVersion": "0.0.1", "createdTime": 1753836676831, - "modifiedTime": 1753836820180, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754846000470, + "lastModifiedBy": "H02dtt2xvVJvYESk" }, "_id": "S6nB0CNlzdU05o5U", "sort": 0, diff --git a/src/packs/items/weapons/weapon_Legendary_Light_Frame_Wheelchair_Xt8tVSn5Fu6ly6LF.json b/src/packs/items/weapons/weapon_Legendary_Light_Frame_Wheelchair_Xt8tVSn5Fu6ly6LF.json index 5b704d6c..622fcf12 100644 --- a/src/packs/items/weapons/weapon_Legendary_Light_Frame_Wheelchair_Xt8tVSn5Fu6ly6LF.json +++ b/src/packs/items/weapons/weapon_Legendary_Light_Frame_Wheelchair_Xt8tVSn5Fu6ly6LF.json @@ -2,7 +2,7 @@ "folder": "beilKE5ZPAihKg3O", "name": "Legendary Light-Frame Wheelchair", "type": "weapon", - "img": "icons/svg/item-bag.svg", + "img": "systems/daggerheart/assets/icons/documents/items/LightWheelchair.webp", "system": { "description": "", "actions": { @@ -141,12 +141,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", "systemVersion": "0.0.1", "createdTime": 1753836615437, - "modifiedTime": 1753836826572, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754846023338, + "lastModifiedBy": "H02dtt2xvVJvYESk" }, "_id": "Xt8tVSn5Fu6ly6LF", "sort": 0, diff --git a/src/packs/items/weapons/weapon_Legendary_Longsword_14abPqQcROJfDChR.json b/src/packs/items/weapons/weapon_Legendary_Longsword_14abPqQcROJfDChR.json index 186cd1c1..636dd7a5 100644 --- a/src/packs/items/weapons/weapon_Legendary_Longsword_14abPqQcROJfDChR.json +++ b/src/packs/items/weapons/weapon_Legendary_Longsword_14abPqQcROJfDChR.json @@ -43,7 +43,7 @@ "parts": [ { "value": { - "dice": "d8", + "dice": "d10", "bonus": 12, "multiplier": "prof", "flatMultiplier": 1, diff --git a/src/packs/items/weapons/weapon_Legendary_Shortsword_dEumq3BIZBk5xYTk.json b/src/packs/items/weapons/weapon_Legendary_Shortsword_dEumq3BIZBk5xYTk.json index 2f832ee7..5f6f6cb2 100644 --- a/src/packs/items/weapons/weapon_Legendary_Shortsword_dEumq3BIZBk5xYTk.json +++ b/src/packs/items/weapons/weapon_Legendary_Shortsword_dEumq3BIZBk5xYTk.json @@ -16,7 +16,7 @@ { "value": "paired", "effectIds": [ - "DgZQSBJx9JmoOngB" + "VFt61c2Apfbli2dG" ], "actionIds": [] } @@ -114,9 +114,16 @@ "value": "ITEM.@system.tier + 1" } ], - "_id": "DgZQSBJx9JmoOngB", + "system": { + "rangeDependence": { + "enabled": true, + "range": "melee", + "target": "hostile", + "type": "withinRange" + } + }, + "_id": "VFt61c2Apfbli2dG", "type": "base", - "system": {}, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753796957432, - "modifiedTime": 1753796957432, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754814544486, + "modifiedTime": 1754814544486, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!dEumq3BIZBk5xYTk.DgZQSBJx9JmoOngB" + "_key": "!items.effects!dEumq3BIZBk5xYTk.VFt61c2Apfbli2dG" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753796913551, - "modifiedTime": 1753796957439, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814544510, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!dEumq3BIZBk5xYTk" } diff --git a/src/packs/items/weapons/weapon_Legendary_Small_Dagger_Px3Rh3kIvAqyISxJ.json b/src/packs/items/weapons/weapon_Legendary_Small_Dagger_Px3Rh3kIvAqyISxJ.json index be3a5886..855ddd80 100644 --- a/src/packs/items/weapons/weapon_Legendary_Small_Dagger_Px3Rh3kIvAqyISxJ.json +++ b/src/packs/items/weapons/weapon_Legendary_Small_Dagger_Px3Rh3kIvAqyISxJ.json @@ -16,7 +16,7 @@ { "value": "paired", "effectIds": [ - "Wjl3MEwNdQPeY63u" + "rnVm0jSEtdWhKGCh" ], "actionIds": [] } @@ -114,9 +114,16 @@ "value": "ITEM.@system.tier + 1" } ], - "_id": "Wjl3MEwNdQPeY63u", + "system": { + "rangeDependence": { + "enabled": true, + "range": "melee", + "target": "hostile", + "type": "withinRange" + } + }, + "_id": "rnVm0jSEtdWhKGCh", "type": "base", - "system": {}, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753797088930, - "modifiedTime": 1753797088930, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754814562988, + "modifiedTime": 1754814562988, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!Px3Rh3kIvAqyISxJ.Wjl3MEwNdQPeY63u" + "_key": "!items.effects!Px3Rh3kIvAqyISxJ.rnVm0jSEtdWhKGCh" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753797057472, - "modifiedTime": 1753797088933, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814562995, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!Px3Rh3kIvAqyISxJ" } diff --git a/src/packs/items/weapons/weapon_Legendary_Spear_4e5pWxi2qohuGsWh.json b/src/packs/items/weapons/weapon_Legendary_Spear_4e5pWxi2qohuGsWh.json index c1322de0..bfdcd4eb 100644 --- a/src/packs/items/weapons/weapon_Legendary_Spear_4e5pWxi2qohuGsWh.json +++ b/src/packs/items/weapons/weapon_Legendary_Spear_4e5pWxi2qohuGsWh.json @@ -12,15 +12,7 @@ "equipped": false, "secondary": false, "burden": "twoHanded", - "weaponFeatures": [ - { - "value": "cumbersome", - "effectIds": [ - "f44KWDgCQeKYfccr" - ], - "actionIds": [] - } - ], + "weaponFeatures": [], "attack": { "name": "Attack", "img": "icons/skills/melee/blood-slash-foam-red.webp", @@ -51,8 +43,8 @@ "parts": [ { "value": { - "dice": "d10", - "bonus": 11, + "dice": "d8", + "bonus": 12, "multiplier": "prof", "flatMultiplier": 1, "custom": { diff --git a/src/packs/items/weapons/weapon_Light_Frame_Wheelchair_iaGnlUkShBgdeMo0.json b/src/packs/items/weapons/weapon_Light_Frame_Wheelchair_iaGnlUkShBgdeMo0.json index 543a0f23..9bb97d2b 100644 --- a/src/packs/items/weapons/weapon_Light_Frame_Wheelchair_iaGnlUkShBgdeMo0.json +++ b/src/packs/items/weapons/weapon_Light_Frame_Wheelchair_iaGnlUkShBgdeMo0.json @@ -3,7 +3,7 @@ "name": "Light-Frame Wheelchair", "type": "weapon", "_id": "iaGnlUkShBgdeMo0", - "img": "icons/svg/item-bag.svg", + "img": "systems/daggerheart/assets/icons/documents/items/LightWheelchair.webp", "system": { "description": "", "actions": { @@ -143,12 +143,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", "systemVersion": "0.0.1", "createdTime": 1753836579296, - "modifiedTime": 1753836587147, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754846015528, + "lastModifiedBy": "H02dtt2xvVJvYESk" }, "_key": "!items!iaGnlUkShBgdeMo0" } diff --git a/src/packs/items/weapons/weapon_Longsword_Iv8BZM1R24QMT72M.json b/src/packs/items/weapons/weapon_Longsword_Iv8BZM1R24QMT72M.json index 54d18b78..c5d9070b 100644 --- a/src/packs/items/weapons/weapon_Longsword_Iv8BZM1R24QMT72M.json +++ b/src/packs/items/weapons/weapon_Longsword_Iv8BZM1R24QMT72M.json @@ -43,7 +43,7 @@ "parts": [ { "value": { - "dice": "d8", + "dice": "d10", "bonus": 3, "multiplier": "prof", "flatMultiplier": 1, diff --git a/src/packs/items/weapons/weapon_Primer_Shard_SxcblanBvqaest3A.json b/src/packs/items/weapons/weapon_Primer_Shard_SxcblanBvqaest3A.json index 2b39a221..e3dd3035 100644 --- a/src/packs/items/weapons/weapon_Primer_Shard_SxcblanBvqaest3A.json +++ b/src/packs/items/weapons/weapon_Primer_Shard_SxcblanBvqaest3A.json @@ -7,21 +7,22 @@ "system": { "description": "", "actions": { - "KGJJgz0SMdY0f0em": { + "dNN2KOfUxGzQ2yjY": { "type": "effect", "actionType": "action", "chatDisplay": true, "name": "Lock On", "description": "On a successful attack, your next attack against the same target with your primary weapon automatically succeeds.", "img": "icons/skills/targeting/crosshair-arrowhead-blue.webp", - "_id": "KGJJgz0SMdY0f0em", + "_id": "dNN2KOfUxGzQ2yjY", "effects": [], "systemPath": "actions", "cost": [], "uses": { "value": null, "max": null, - "recovery": null + "recovery": null, + "consumeOnSuccess": false }, "target": { "type": "any", @@ -36,10 +37,10 @@ "burden": "oneHanded", "weaponFeatures": [ { - "value": "lockedon", + "value": "lockedOn", "effectIds": [], "actionIds": [ - "KGJJgz0SMdY0f0em" + "dNN2KOfUxGzQ2yjY" ] } ], @@ -135,12 +136,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753797317938, - "modifiedTime": 1753797376548, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814518028, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!SxcblanBvqaest3A" } diff --git a/src/packs/items/weapons/weapon_Shortsword_cjGZpXCoshEqi1FI.json b/src/packs/items/weapons/weapon_Shortsword_cjGZpXCoshEqi1FI.json index 92cb44b7..31cb74cd 100644 --- a/src/packs/items/weapons/weapon_Shortsword_cjGZpXCoshEqi1FI.json +++ b/src/packs/items/weapons/weapon_Shortsword_cjGZpXCoshEqi1FI.json @@ -16,7 +16,7 @@ { "value": "paired", "effectIds": [ - "VII5oRJrQTsSir0E" + "5RpOUFs0kDhzwltM" ], "actionIds": [] } @@ -114,9 +114,16 @@ "value": "ITEM.@system.tier + 1" } ], - "_id": "VII5oRJrQTsSir0E", + "system": { + "rangeDependence": { + "enabled": true, + "range": "melee", + "target": "hostile", + "type": "withinRange" + } + }, + "_id": "5RpOUFs0kDhzwltM", "type": "base", - "system": {}, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753793980974, - "modifiedTime": 1753793980974, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754814729443, + "modifiedTime": 1754814729443, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!cjGZpXCoshEqi1FI.VII5oRJrQTsSir0E" + "_key": "!items.effects!cjGZpXCoshEqi1FI.5RpOUFs0kDhzwltM" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753741549716, - "modifiedTime": 1753793980983, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814729447, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!cjGZpXCoshEqi1FI" } diff --git a/src/packs/items/weapons/weapon_Small_Dagger_wKklDxs5nkzILNp4.json b/src/packs/items/weapons/weapon_Small_Dagger_wKklDxs5nkzILNp4.json index 4e9613f6..229162f8 100644 --- a/src/packs/items/weapons/weapon_Small_Dagger_wKklDxs5nkzILNp4.json +++ b/src/packs/items/weapons/weapon_Small_Dagger_wKklDxs5nkzILNp4.json @@ -16,7 +16,7 @@ { "value": "paired", "effectIds": [ - "2OLsxbZJqMgk680J" + "wK6ccFAirp9HYK5Q" ], "actionIds": [] } @@ -114,9 +114,16 @@ "value": "ITEM.@system.tier + 1" } ], - "_id": "2OLsxbZJqMgk680J", + "system": { + "rangeDependence": { + "enabled": true, + "range": "melee", + "target": "hostile", + "type": "withinRange" + } + }, + "_id": "wK6ccFAirp9HYK5Q", "type": "base", - "system": {}, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753794165509, - "modifiedTime": 1753794165509, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754814738851, + "modifiedTime": 1754814738851, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!wKklDxs5nkzILNp4.2OLsxbZJqMgk680J" + "_key": "!items.effects!wKklDxs5nkzILNp4.wK6ccFAirp9HYK5Q" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753744141625, - "modifiedTime": 1753794165511, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814738854, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!wKklDxs5nkzILNp4" } diff --git a/src/packs/items/weapons/weapon_Spear_TF85tKJetUjLwh54.json b/src/packs/items/weapons/weapon_Spear_TF85tKJetUjLwh54.json index 6aa8fe8c..77ba9a93 100644 --- a/src/packs/items/weapons/weapon_Spear_TF85tKJetUjLwh54.json +++ b/src/packs/items/weapons/weapon_Spear_TF85tKJetUjLwh54.json @@ -12,15 +12,7 @@ "equipped": false, "secondary": false, "burden": "twoHanded", - "weaponFeatures": [ - { - "value": "cumbersome", - "effectIds": [ - "Z5MnVI8EOOgzRdXC" - ], - "actionIds": [] - } - ], + "weaponFeatures": [], "attack": { "name": "Attack", "img": "icons/skills/melee/blood-slash-foam-red.webp", @@ -51,8 +43,8 @@ "parts": [ { "value": { - "dice": "d10", - "bonus": 2, + "dice": "d8", + "bonus": 3, "multiplier": "prof", "flatMultiplier": 1, "custom": { diff --git a/src/packs/items/weapons/weapon_Spiked_Shield_vzyzFwLUniWZV1rt.json b/src/packs/items/weapons/weapon_Spiked_Shield_vzyzFwLUniWZV1rt.json index 8a40a800..9b9d691a 100644 --- a/src/packs/items/weapons/weapon_Spiked_Shield_vzyzFwLUniWZV1rt.json +++ b/src/packs/items/weapons/weapon_Spiked_Shield_vzyzFwLUniWZV1rt.json @@ -16,7 +16,7 @@ { "value": "doubleDuty", "effectIds": [ - "qo4VPSV0VZha1ya2" + "d3TJtlpoHBCztbom" ], "actionIds": [] } @@ -119,9 +119,16 @@ "value": "1" } ], - "_id": "qo4VPSV0VZha1ya2", + "system": { + "rangeDependence": { + "enabled": true, + "range": "melee", + "target": "hostile", + "type": "withinRange" + } + }, + "_id": "d3TJtlpoHBCztbom", "type": "base", - "system": {}, "disabled": false, "duration": { "startTime": null, @@ -137,14 +144,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753794551639, - "modifiedTime": 1753794551639, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754814481208, + "modifiedTime": 1754814481208, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!vzyzFwLUniWZV1rt.qo4VPSV0VZha1ya2" + "_key": "!items.effects!vzyzFwLUniWZV1rt.d3TJtlpoHBCztbom" } ], "sort": 0, @@ -157,12 +164,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753794535926, - "modifiedTime": 1753794665373, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814481212, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!vzyzFwLUniWZV1rt" } diff --git a/src/packs/items/weapons/weapon_Thistlebow_I1nDGpulg29GpWOW.json b/src/packs/items/weapons/weapon_Thistlebow_I1nDGpulg29GpWOW.json index ca641ad2..cec5b0d1 100644 --- a/src/packs/items/weapons/weapon_Thistlebow_I1nDGpulg29GpWOW.json +++ b/src/packs/items/weapons/weapon_Thistlebow_I1nDGpulg29GpWOW.json @@ -16,7 +16,7 @@ { "value": "reliable", "effectIds": [ - "YA5tbB6XBISWsf0p" + "G9mMGxBSexwjWTYV" ], "actionIds": [] } @@ -109,14 +109,21 @@ "img": "icons/skills/melee/strike-sword-slashing-red.webp", "changes": [ { - "key": "system.bonuses.roll.primaryWeapon.attack", + "key": "system.bonuses.roll.primaryWeapon.bonus", "mode": 2, "value": "1" } ], - "_id": "YA5tbB6XBISWsf0p", + "_id": "G9mMGxBSexwjWTYV", "type": "base", - "system": {}, + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753836322206, - "modifiedTime": 1753836322206, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754815251133, + "modifiedTime": 1754815251133, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!I1nDGpulg29GpWOW.YA5tbB6XBISWsf0p" + "_key": "!items.effects!I1nDGpulg29GpWOW.G9mMGxBSexwjWTYV" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753836302436, - "modifiedTime": 1753836334493, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754815251135, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!I1nDGpulg29GpWOW" } diff --git a/src/packs/items/weapons/weapon_War_Scythe_z6yEdFYQJ5IzgTX3.json b/src/packs/items/weapons/weapon_War_Scythe_z6yEdFYQJ5IzgTX3.json index 458d8136..5d65a310 100644 --- a/src/packs/items/weapons/weapon_War_Scythe_z6yEdFYQJ5IzgTX3.json +++ b/src/packs/items/weapons/weapon_War_Scythe_z6yEdFYQJ5IzgTX3.json @@ -16,7 +16,7 @@ { "value": "reliable", "effectIds": [ - "Gt0tHtJDQwdSActw" + "cOYeI9TxHXpDwszu" ], "actionIds": [] } @@ -109,14 +109,21 @@ "img": "icons/skills/melee/strike-sword-slashing-red.webp", "changes": [ { - "key": "system.bonuses.roll.primaryWeapon.attack", + "key": "system.bonuses.roll.primaryWeapon.bonus", "mode": 2, "value": "1" } ], - "_id": "Gt0tHtJDQwdSActw", + "_id": "cOYeI9TxHXpDwszu", "type": "base", - "system": {}, + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, "disabled": false, "duration": { "startTime": null, @@ -132,14 +139,14 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", - "createdTime": 1753829771677, - "modifiedTime": 1753829771677, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "systemVersion": "1.0.0", + "createdTime": 1754814992368, + "modifiedTime": 1754814992368, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, - "_key": "!items.effects!z6yEdFYQJ5IzgTX3.Gt0tHtJDQwdSActw" + "_key": "!items.effects!z6yEdFYQJ5IzgTX3.cOYeI9TxHXpDwszu" } ], "sort": 0, @@ -152,12 +159,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.0.0", "createdTime": 1753829740082, - "modifiedTime": 1753829771680, - "lastModifiedBy": "FecEtPuoQh6MpjQ0" + "modifiedTime": 1754814992370, + "lastModifiedBy": "MQSznptE5yLT7kj8" }, "_key": "!items!z6yEdFYQJ5IzgTX3" } diff --git a/src/packs/journals/journal_Welcome___Information_g7NhKvwltwafmMyR.json b/src/packs/journals/journal_Welcome___Information_g7NhKvwltwafmMyR.json index b08e4a1d..af31907f 100644 --- a/src/packs/journals/journal_Welcome___Information_g7NhKvwltwafmMyR.json +++ b/src/packs/journals/journal_Welcome___Information_g7NhKvwltwafmMyR.json @@ -132,7 +132,7 @@ "image": {}, "text": { "format": 1, - "content": "

This product includes materials from the Daggerheart System Reference Document 1.0, © Critical Role, LLC. under the terms of the Darrington Press Community Gaming (DPCGL) License. More information can be found at https://www.daggerheart.com. There are no previous modifications by others.

The Foundryborne Team

The Foundryborne Team consists of:

With Art from:

We would also like to thank the FoundryVTT team for their support in publishing this system.

And, of course, special thanks to the teams at Critical Role and Darrington Press for making such a wonderful game and updating the license to allow a FoundryVTT version of the system.

The Foundryborne Community

Without our amazing community this project would not have been possible.

You kept us going with both direct contributions and just endless support!

We thank you with all our hearts.

Come join us!

" + "content": "

This product includes materials from the Daggerheart System Reference Document 1.0, © Critical Role, LLC. under the terms of the Darrington Press Community Gaming (DPCGL) License. More information can be found at https://www.daggerheart.com. There are no previous modifications by others.

The Foundryborne Team

The Foundryborne Team consists of:

With Art from:

And special thanks to our hard working community testers:

We would also like to thank the FoundryVTT team for their support in publishing this system, as well as providing countless Icons to be used in many places.

And, of course, special thanks to the teams at Critical Role and Darrington Press for making such a wonderful game and updating the license to allow a FoundryVTT version of the system.

The Foundryborne Community

Without our amazing community this project would not have been possible.

You kept us going with both direct contributions and just endless support!

We thank you with all our hearts.

Come join us!

" }, "video": { "controls": true, @@ -153,8 +153,8 @@ "systemId": "daggerheart", "systemVersion": "0.0.1", "createdTime": 1754225939902, - "modifiedTime": 1754226994508, - "lastModifiedBy": "l5jB3XmcVXOTQpRZ" + "modifiedTime": 1754847043391, + "lastModifiedBy": "9GFCfEY8m5Co2mHo" }, "_key": "!journal.pages!g7NhKvwltwafmMyR.dP6xSKEld4TSqHhK" } diff --git a/src/packs/subclasses/feature_Epic_Poetry_eCoEWkWuZPMZ9C6a.json b/src/packs/subclasses/feature_Epic_Poetry_eCoEWkWuZPMZ9C6a.json index 3429f585..f80c05e3 100644 --- a/src/packs/subclasses/feature_Epic_Poetry_eCoEWkWuZPMZ9C6a.json +++ b/src/packs/subclasses/feature_Epic_Poetry_eCoEWkWuZPMZ9C6a.json @@ -23,7 +23,7 @@ } }, "_id": "RSmscgGyuHJucF6C", - "img": "icons/magic/life/heart-cross-blue.webp", + "img": "icons/sundries/documents/document-letter-blue.webp", "changes": [ { "key": "system.bonuses.rally", @@ -53,10 +53,11 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", "systemVersion": "0.0.1", - "lastModifiedBy": null + "lastModifiedBy": "49DaecTcBSc5d0DA", + "modifiedTime": 1754669077252 }, "_key": "!items.effects!eCoEWkWuZPMZ9C6a.RSmscgGyuHJucF6C" } diff --git a/styles/less/dialog/index.less b/styles/less/dialog/index.less index 942016e0..05593d44 100644 --- a/styles/less/dialog/index.less +++ b/styles/less/dialog/index.less @@ -27,3 +27,5 @@ @import './damage-reduction/sheets.less'; @import './multiclass-choice/sheet.less'; + +@import './reroll-dialog/sheet.less'; diff --git a/styles/less/dialog/reroll-dialog/sheet.less b/styles/less/dialog/reroll-dialog/sheet.less new file mode 100644 index 00000000..f8687009 --- /dev/null +++ b/styles/less/dialog/reroll-dialog/sheet.less @@ -0,0 +1,125 @@ +.daggerheart.dialog.dh-style.views.reroll-dialog { + .window-content { + max-width: 648px; + } + + .reroll-outer-container { + h2 { + margin: 0; + } + + .dices-container { + display: flex; + flex-wrap: wrap; + gap: 8px; + } + + .dice-outer-container { + width: 300px; + + legend { + display: flex; + align-items: center; + gap: 4px; + + i { + margin-right: 4px; + } + } + + .dice-container { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; + + .result-container { + position: relative; + aspect-ratio: 1; + display: flex; + align-items: center; + justify-content: center; + font-size: 22px; + opacity: 0.8; + + &.selected { + opacity: 1; + border: 1px solid; + border-radius: 6px; + border-color: light-dark(@dark-blue, @golden); + filter: drop-shadow(0 0 3px @golden); + } + + &:before { + content: ' '; + position: absolute; + width: 100%; + height: 100%; + z-index: -1; + mask: var(--svg-die) no-repeat center; + mask-size: contain; + background: linear-gradient(139.01deg, #efe6d8 3.51%, #372e1f 96.49%); + } + + &.d4:before { + --svg-die: url(../assets/icons/dice/default/d4.svg); + } + &.d6:before { + --svg-die: url(../assets/icons/dice/default/d6.svg); + } + &.d8:before { + --svg-die: url(../assets/icons/dice/default/d8.svg); + } + &.d10:before { + --svg-die: url(../assets/icons/dice/default/d10.svg); + } + &.d12:before { + --svg-die: url('../assets/icons/dice/default/d12.svg'); + } + &.d20:before { + --svg-die: url(../assets/icons/dice/default/d20.svg); + } + + .to-reroll-result { + position: absolute; + bottom: -7px; + gap: 2px; + border: 1px solid; + border-radius: 6px; + background-image: url(../assets/parchments/dh-parchment-dark.png); + display: flex; + align-items: center; + padding: 2px 6px; + + input { + margin: 0; + height: 12px; + line-height: 0px; + position: relative; + top: 1px; + + &:before, + &:after { + line-height: 12px; + font-size: 12px; + } + } + + i { + font-size: 10px; + } + } + } + } + } + } + + footer { + margin-top: 8px; + display: flex; + justify-content: space-between; + + .controls { + display: flex; + gap: 8px; + } + } +} diff --git a/styles/less/global/chat.less b/styles/less/global/chat.less index 1e37309d..37ec993d 100644 --- a/styles/less/global/chat.less +++ b/styles/less/global/chat.less @@ -32,6 +32,7 @@ .message-header-metadata { flex: none; display: flex; + flex-direction: column; .message-metadata { font-family: @font-body; @@ -73,6 +74,13 @@ .message-content { padding-bottom: 8px; + .flavor-text { + font-size: var(--font-size-12); + line-height: 20px; + color: var(--color-dark-4); + text-align: center; + display: block; + } } } } diff --git a/styles/less/global/dialog.less b/styles/less/global/dialog.less index aaa5c812..701d5025 100644 --- a/styles/less/global/dialog.less +++ b/styles/less/global/dialog.less @@ -53,7 +53,7 @@ font-weight: 500; font-size: 14px; line-height: 17px; - + white-space: nowrap; color: light-dark(@dark, @beige); } diff --git a/styles/less/global/elements.less b/styles/less/global/elements.less index 7f8cdd94..4c0243f6 100755 --- a/styles/less/global/elements.less +++ b/styles/less/global/elements.less @@ -571,6 +571,16 @@ white-space: nowrap; } } + + .button-container { + display: grid; + grid-template-columns: 1fr; + gap: 10px; + text-align: center; + display: flex; + justify-content: center; + width: 100%; + } } footer { diff --git a/styles/less/sheets-settings/adversary-settings/features.less b/styles/less/sheets-settings/adversary-settings/features.less index 037a08ea..29c9874e 100644 --- a/styles/less/sheets-settings/adversary-settings/features.less +++ b/styles/less/sheets-settings/adversary-settings/features.less @@ -14,8 +14,14 @@ margin-bottom: 12px; } - .feature-list { + .feature-list, + .features-dragger { display: flex; + width: 100%; + font-family: @font-body; + } + + .feature-list { flex-direction: column; gap: 10px; @@ -45,5 +51,16 @@ } } } + + .features-dragger { + align-items: center; + justify-content: center; + box-sizing: border-box; + height: 40px; + margin-top: 10px; + border: 1px dashed light-dark(@dark-blue-50, @beige-50); + border-radius: 3px; + color: light-dark(@dark-blue-50, @beige-50); + } } } diff --git a/styles/less/sheets/actors/character/header.less b/styles/less/sheets/actors/character/header.less index 5de7a827..7bfcc7c9 100644 --- a/styles/less/sheets/actors/character/header.less +++ b/styles/less/sheets/actors/character/header.less @@ -10,7 +10,7 @@ } .character-row .domains-section img { - filter: invert(88%) sepia(98%) saturate(1784%) hue-rotate(311deg) brightness(104%) contrast(91%); + filter: @golden-filter; } } }, { @@ -20,7 +20,7 @@ } .character-row .domains-section img { - filter: invert(87%) sepia(15%) saturate(343%) hue-rotate(333deg) brightness(110%) contrast(87%); + filter: brightness(0) saturate(100%); } } }); diff --git a/styles/less/ui/chat/chat.less b/styles/less/ui/chat/chat.less index 9afa32d3..81af3d23 100644 --- a/styles/less/ui/chat/chat.less +++ b/styles/less/ui/chat/chat.less @@ -11,333 +11,6 @@ } } - /* &.roll { - .dice-flavor { - text-align: center; - font-weight: bold; - } - .dice-tooltip { - .dice-rolls { - &.duality { - display: flex; - gap: 0.25rem; - - > .roll { - background-image: none; - - .reroll-button { - border: none; - background: initial; - width: 42px; - - &:hover { - background: var(--button-background-color); - border: 1px solid var(--button-border-color); - } - } - } - } - - &.rerollable { - position: relative; - flex: none; - - .dice-rerolled { - z-index: 2; - position: absolute; - right: 0; - font-size: 12px; - cursor: help; - } - - .reroll-button { - border: none; - background: initial; - - &:hover { - background: var(--button-background-color); - border: 1px solid var(--button-border-color); - } - } - } - - // margin: 0; - > .roll { - display: flex; - align-items: center; - justify-content: center; - gap: 4px; - margin-bottom: 4px; - - .dice-container { - display: flex; - flex-direction: column; - gap: 2px; - position: relative; - - .dice-title { - color: var(--color-light-1); - text-shadow: 0 0 1px black; - } - - .dice-rerolled { - z-index: 2; - position: absolute; - right: -2px; - font-size: 12px; - cursor: help; - } - - .dice-inner-container { - display: flex; - align-items: center; - justify-content: center; - position: relative; - &.hope, - &.fear { - .dice-wrapper { - clip-path: polygon( - 50% 0%, - 80% 10%, - 100% 35%, - 100% 70%, - 80% 90%, - 50% 100%, - 20% 90%, - 0% 70%, - 0% 35%, - 20% 10% - ); - } - } - .dice-wrapper { - height: 24px; - width: 24px; - position: relative; - display: flex; - align-items: center; - justify-content: center; - - .dice { - height: 26px; - width: 26px; - max-width: unset; - position: absolute; - } - } - - .dice-value { - position: absolute; - font-weight: bold; - font-size: 16px; - } - - &.hope { - .dice-wrapper { - background: black; - - .dice { - filter: brightness(0) saturate(100%) invert(79%) sepia(79%) saturate(333%) - hue-rotate(352deg) brightness(102%) contrast(103%); - } - } - - .dice-value { - color: var(--color-dark-1); - text-shadow: 0 0 4px white; - } - } - - &.fear { - .dice-wrapper { - background: white; - - .dice { - filter: brightness(0) saturate(100%) invert(12%) sepia(88%) saturate(4321%) - hue-rotate(221deg) brightness(92%) contrast(110%); - } - } - - .dice-value { - color: var(--color-light-1); - text-shadow: 0 0 4px black; - } - } - - &.advantage { - .dice-wrapper { - .dice { - filter: brightness(0) saturate(100%) invert(18%) sepia(92%) saturate(4133%) - hue-rotate(96deg) brightness(104%) contrast(107%); - } - } - } - - &.disadvantage { - .dice-wrapper { - .dice { - filter: brightness(0) saturate(100%) invert(9%) sepia(78%) saturate(6903%) - hue-rotate(11deg) brightness(93%) contrast(117%); - } - } - } - } - } - } - } - - .damage-resource { - font-weight: 600; - margin-top: 5px; - } - } - - .dice-total { - &.duality { - &.hope { - border-color: @hope; - border-width: 3px; - background: rgba(@hope, 0.5); - } - &.fear { - border-color: @fear; - border-width: 3px; - background: rgba(@fear, 0.5); - } - &.critical { - border-color: @critical; - border-width: 3px; - background: rgba(@critical, 0.5); - } - } - - .dice-total-value { - .hope { - color: @hope; - } - .fear { - color: @fear; - } - .critical { - color: @critical; - } - } - } - - .dice-total-label { - font-size: 12px; - font-weight: bold; - font-variant: all-small-caps; - margin: -@fullMargin 0; - } - - .target-selection { - display: flex; - justify-content: space-around; - input[type='radio'] { - display: none; - &:checked + label { - text-shadow: 0px 0px 4px #ce5937; - } - &:not(:checked) + label { - opacity: 0.75; - } - } - label { - cursor: pointer; - opacity: 0.75; - &.target-selected { - text-shadow: 0px 0px 4px #ce5937; - opacity: 1; - } - } - } - - .target-section { - margin-top: 5px; - - .target-container { - display: flex; - transition: all 0.2s ease-in-out; - - &:hover { - filter: drop-shadow(0 0 3px @secondaryShadow); - border-color: gold; - } - - &.hidden { - display: none; - border: 0; - } - - &.hit { - background: @hit; - } - - &.miss { - background: @miss; - } - - img, - .target-save-container { - width: 22px; - height: 22px; - align-self: center; - border-color: transparent; - } - - img { - flex: 0; - margin-left: 8px; - } - - .target-save-container { - margin-right: 8px; - justify-content: center; - display: flex; - align-items: center; - min-height: unset; - border: 1px solid black; - } - - .target-inner-container { - flex: 1; - display: flex; - justify-content: center; - font-size: var(--font-size-16); - } - - &:not(:has(.target-save-container)) .target-inner-container { - margin-right: @hugeMargin; - } - } - } - - .dice-actions { - display: flex; - gap: 4px; - - button { - flex: 1; - height: 40px; - font-family: @font-body; - font-weight: 600; - } - } - - .dice-result { - .roll-damage-button, - .damage-button, - .duality-action { - margin-top: 5px; - } - } - - &:not(.expanded) .dice-tooltip { - grid-template-rows: 0fr; - } - } */ - button { &.inner-button { --button-size: 1.25rem; @@ -349,19 +22,6 @@ } } } - - [data-use-perm='false'] { - pointer-events: none; - border-color: transparent; - } - [data-view-perm='false'] { - > * { - display: none; - } - &::after { - content: '??'; - } - } } .daggerheart, @@ -370,6 +30,20 @@ --text-color: light-dark(@dark-blue, @golden); --bg-color: light-dark(@dark-blue-40, @golden-40); + [data-use-perm='false'] { + pointer-events: none; + border-color: transparent; + } + [data-view-perm='false'] { + &[data-perm-hidden='true'], + > * { + display: none; + } + &::after { + content: '??'; + } + } + &.duality { &.hope { --text-color: @golden; @@ -412,7 +86,7 @@ grid-template-columns: 1fr auto 1fr; align-items: center; color: light-dark(@dark, @beige); - margin: 5px 0; + margin: 10px 0; span { display: flex; @@ -450,7 +124,6 @@ flex-direction: column; align-items: center; gap: 5px; - padding: 5px 0; .dice-tooltip { width: 100%; @@ -489,6 +162,7 @@ color: var(--text-color); font-weight: 700; font-family: 'Cinzel', sans-serif; + line-height: 0.75; .roll-result-value { font-size: var(--font-size-24); @@ -503,10 +177,6 @@ } } } - - .roll-difficulty { - margin-top: -5px; - } } } @@ -522,10 +192,14 @@ .roll-die { display: grid; grid-template-areas: - ". a a" - "c b b"; + '. a a' + 'c b b'; gap: 3px; + .reroll-button:hover { + filter: drop-shadow(0 0 3px @golden); + } + label { text-align: center; height: var(--font-size-12); @@ -580,7 +254,7 @@ .button-target-selection { flex: 1; text-align: center; - padding: 5px 0; + margin: -5px 0; } .button-target-selection:hover, @@ -600,6 +274,11 @@ width: 100%; gap: 10px; align-items: center; + border-radius: 3px; + + &:hover { + background-color: rgba(255, 255, 255, 0.1); + } .target-img { border-radius: 50%; @@ -640,6 +319,7 @@ padding: 3px 5px; width: fit-content; margin: auto; + white-space: nowrap; } .roll-difficulty, @@ -706,6 +386,19 @@ margin-top: 0; } + .damage-section[data-action='expandRoll'] { + .on-reduced { + .wrapper { + flex-wrap: wrap; + gap: 10px 5px; + } + + .roll-formula { + font-size: var(--font-size-16); + } + } + } + .target-section { .roll-part-content { gap: 10px; diff --git a/styles/less/ui/combat-sidebar/encounter-controls.less b/styles/less/ui/combat-sidebar/encounter-controls.less index 58deaae8..fd0c1aee 100644 --- a/styles/less/ui/combat-sidebar/encounter-controls.less +++ b/styles/less/ui/combat-sidebar/encounter-controls.less @@ -2,43 +2,14 @@ .encounter-controls.combat { justify-content: space-between; - .encounter-fear-controls { + .encounter-title { + text-align: left; + } + + .inner-controls { display: flex; align-items: center; - gap: 8px; - - .encounter-fear-dice-container { - display: flex; - gap: 2px; - - .encounter-control-fear-container { - display: flex; - position: relative; - align-items: center; - justify-content: center; - color: black; - - .dice { - height: 22px; - width: 22px; - } - - .encounter-control-fear { - position: absolute; - font-size: 16px; - } - - .encounter-control-counter { - position: absolute; - right: -10px; - color: var(--color-text-secondary); - } - } - } - - .encounter-countdowns { - color: var(--content-link-icon-color); - } + gap: 4px; } .control-buttons { diff --git a/styles/less/ui/item-browser/item-browser.less b/styles/less/ui/item-browser/item-browser.less index 3b13056b..e7ff3b12 100644 --- a/styles/less/ui/item-browser/item-browser.less +++ b/styles/less/ui/item-browser/item-browser.less @@ -227,14 +227,16 @@ display: flex; > * { - flex: 1; + flex: 2.5; + text-align: center; } .item-list-img { width: 40px; flex: unset; } .item-list-name { - flex-grow: 3 !important; + flex-grow: 3; + text-align: start; } } diff --git a/styles/less/ui/resources/resources.less b/styles/less/ui/resources/resources.less index 1f609c5e..3982d990 100644 --- a/styles/less/ui/resources/resources.less +++ b/styles/less/ui/resources/resources.less @@ -108,7 +108,7 @@ box-shadow: unset; border-color: transparent; header, - .controls, + #resource-fear .controls, .window-resize-handle { opacity: 0; } diff --git a/system.json b/system.json index 7501cfa7..a0c91923 100644 --- a/system.json +++ b/system.json @@ -44,6 +44,10 @@ "url": "https://github.com/joaquinpereyra98", "email": "joaquinpereyra98@gmail.com", "discord": "joaquinp98" + }, + { + "name": "chrisryan10", + "discord": "lazjen" } ], "esmodules": ["build/daggerheart.js"], @@ -262,6 +266,7 @@ "abilityUse": {} } }, + "background": "systems/daggerheart/assets/logos/FoundrybornBackgroundLogo.png", "primaryTokenAttribute": "resources.hitPoints", "secondaryTokenAttribute": "resources.stress", "url": "https://your/hosted/system/repo/", diff --git a/templates/characterCreation/setupTabs/domainCards.hbs b/templates/characterCreation/setupTabs/domainCards.hbs index 298d8859..66526689 100644 --- a/templates/characterCreation/setupTabs/domainCards.hbs +++ b/templates/characterCreation/setupTabs/domainCards.hbs @@ -10,9 +10,7 @@ {{#each domainCards as |domainCard id|}}
{{#> "systems/daggerheart/templates/components/card-preview.hbs" domainCard }} - {{#each @root.class.system.domains }} -
{{localize (concat "DAGGERHEART.GENERAL.Domain." this ".label")}}
- {{/each}} + {{#each @root.classDomains }}
{{this}}
{{/each}} {{/"systems/daggerheart/templates/components/card-preview.hbs"}}
{{/each}} diff --git a/templates/dialogs/dice-roll/costSelection.hbs b/templates/dialogs/dice-roll/costSelection.hbs index 765fbaf9..775e681c 100644 --- a/templates/dialogs/dice-roll/costSelection.hbs +++ b/templates/dialogs/dice-roll/costSelection.hbs @@ -5,25 +5,29 @@
  • - - + +
    - +
  • {{/if}} {{#each costs as | cost index |}}
  • - - + +
    {{#if (and scalable maxStep)}} {{/if}} - +
  • {{/each}} diff --git a/templates/dialogs/dice-roll/damageSelection.hbs b/templates/dialogs/dice-roll/damageSelection.hbs index 2967b675..ba542666 100644 --- a/templates/dialogs/dice-roll/damageSelection.hbs +++ b/templates/dialogs/dice-roll/damageSelection.hbs @@ -24,6 +24,22 @@ {{/each}} + {{#unless (empty @root.modifiers)}} +
    + {{localize "DAGGERHEART.GENERAL.Modifier.plural"}} + {{#each @root.modifiers}} + {{ localize label }} + {{#if (hasProperty this "values")}} + + {{/if}} + {{#if (hasProperty this "enabled")}} + + {{/if}} + {{/each}} +
    + {{/unless}}
    {{#if directDamage}} + + {{this.selectedResults}}/{{this.maxSelected}} Selected + + +
    + {{#each this.results}} +
    + {{this.result}} + {{#if this.active}} + + + + + {{/if}} +
    + {{/each}} +
    + + {{/each}} +
    + {{/each}} + {{/each}} + \ No newline at end of file diff --git a/templates/dialogs/rerollDialog/footer.hbs b/templates/dialogs/rerollDialog/footer.hbs new file mode 100644 index 00000000..4aff2823 --- /dev/null +++ b/templates/dialogs/rerollDialog/footer.hbs @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/templates/dialogs/rerollDialog/main.hbs b/templates/dialogs/rerollDialog/main.hbs new file mode 100644 index 00000000..6f10ce33 --- /dev/null +++ b/templates/dialogs/rerollDialog/main.hbs @@ -0,0 +1,35 @@ +
    + {{#each damage}} +

    {{localize (concat 'DAGGERHEART.CONFIG.HealingType.' @key '.name')}}

    + {{#each this}} +
    + {{#each this}} +
    + + + + {{this.selectedResults}}/{{this.results.length}} Selected + + +
    + {{#each this.results}} +
    + {{this.result}} + {{#if this.active}} + + + + + {{/if}} +
    + {{/each}} +
    +
    + {{/each}} +
    + {{/each}} + {{/each}} +
    \ No newline at end of file diff --git a/templates/settings/appearance-settings.hbs b/templates/settings/appearance-settings.hbs index e7c1d757..ab30eefd 100644 --- a/templates/settings/appearance-settings.hbs +++ b/templates/settings/appearance-settings.hbs @@ -69,7 +69,13 @@ {{selectOptions diceSoNiceMaterials selected=diceTab.source.material valueAttr="key" labelAttr="name" localize=true}} - +
    + +
    + {{/if}} diff --git a/templates/settings/variant-rules.hbs b/templates/settings/variant-rules.hbs index 03027f69..5cc5c90c 100644 --- a/templates/settings/variant-rules.hbs +++ b/templates/settings/variant-rules.hbs @@ -11,7 +11,6 @@ {{formGroup settingFields.schema.fields.rangeMeasurement.fields.veryClose value=settingFields._source.rangeMeasurement.veryClose localize=true}} {{formGroup settingFields.schema.fields.rangeMeasurement.fields.close value=settingFields._source.rangeMeasurement.close localize=true}} {{formGroup settingFields.schema.fields.rangeMeasurement.fields.far value=settingFields._source.rangeMeasurement.far localize=true}} - {{formGroup settingFields.schema.fields.rangeMeasurement.fields.veryFar value=settingFields._source.rangeMeasurement.veryFar localize=true}}
    diff --git a/templates/sheets-settings/adversary-settings/attack.hbs b/templates/sheets-settings/adversary-settings/attack.hbs index a51128a1..f7d38f1e 100644 --- a/templates/sheets-settings/adversary-settings/attack.hbs +++ b/templates/sheets-settings/adversary-settings/attack.hbs @@ -5,19 +5,19 @@ >
    {{localize "DAGGERHEART.GENERAL.basics"}} - {{formGroup systemFields.attack.fields.img value=document.system.attack.img label="DAGGERHEART.GENERAL.imagePath" name="system.attack.img" localize=true}} - {{formGroup systemFields.attack.fields.name value=document.system.attack.name label="DAGGERHEART.ACTIONS.Settings.attackName" name="system.attack.name" localize=true}} + {{formGroup systemFields.attack.fields.img value=document._source.system.attack.img label="DAGGERHEART.GENERAL.imagePath" name="system.attack.img" localize=true}} + {{formGroup systemFields.attack.fields.name value=document._source.system.attack.name label="DAGGERHEART.ACTIONS.Settings.attackName" name="system.attack.name" localize=true}}
    {{localize "DAGGERHEART.GENERAL.attack"}} - {{formField systemFields.attack.fields.roll.fields.bonus value=document.system.attack.roll.bonus label="DAGGERHEART.ACTIONS.Settings.attackBonus" name="system.attack.roll.bonus" localize=true}} - {{formField systemFields.attack.fields.range value=document.system.attack.range label="DAGGERHEART.GENERAL.range" name="system.attack.range" localize=true}} + {{formField systemFields.attack.fields.roll.fields.bonus value=document._source.system.attack.roll.bonus label="DAGGERHEART.ACTIONS.Settings.attackBonus" name="system.attack.roll.bonus" localize=true}} + {{formField systemFields.attack.fields.range value=document._source.system.attack.range label="DAGGERHEART.GENERAL.range" name="system.attack.range" localize=true}} {{#if systemFields.attack.fields.target.fields}} - {{ formField systemFields.attack.fields.target.fields.type value=document.system.attack.target.type label="DAGGERHEART.GENERAL.Target.single" name="system.attack.target.type" localize=true }} - {{#if (and document.system.attack.target.type (not (eq document.system.attack.target.type 'self')))}} - {{ formField systemFields.attack.fields.target.fields.amount value=document.system.attack.target.amount label="DAGGERHEART.GENERAL.amount" name="system.attack.target.amount" localize=true}} + {{ formField systemFields.attack.fields.target.fields.type value=document._source.system.attack.target.type label="DAGGERHEART.GENERAL.Target.single" name="system.attack.target.type" localize=true }} + {{#if (and document._source.system.attack.target.type (not (eq document._source.system.attack.target.type 'self')))}} + {{ formField systemFields.attack.fields.target.fields.amount value=document._source.system.attack.target.amount label="DAGGERHEART.GENERAL.amount" name="system.attack.target.amount" localize=true}} {{/if}} {{/if}}
    - {{> 'systems/daggerheart/templates/actionTypes/damage.hbs' fields=systemFields.attack.fields.damage.fields.parts.element.fields source=document.system.attack.damage path="system.attack." horde=(eq document.system.type 'horde')}} + {{> 'systems/daggerheart/templates/actionTypes/damage.hbs' fields=systemFields.attack.fields.damage.fields.parts.element.fields source=document.system.attack.damage path="system.attack." horde=(eq document._source.system.type 'horde')}} \ No newline at end of file diff --git a/templates/sheets-settings/adversary-settings/details.hbs b/templates/sheets-settings/adversary-settings/details.hbs index e3ecf859..194c7f0c 100644 --- a/templates/sheets-settings/adversary-settings/details.hbs +++ b/templates/sheets-settings/adversary-settings/details.hbs @@ -6,33 +6,33 @@
    {{localize 'DAGGERHEART.GENERAL.basics'}}
    - {{formGroup systemFields.tier value=document.system.tier localize=true}} - {{formGroup systemFields.type value=document.system.type localize=true}} - {{#if (eq document.system.type 'horde')}} - {{formGroup systemFields.hordeHp value=document.system.hordeHp label=(localize "DAGGERHEART.ACTORS.Adversary.horderHp")}} + {{formGroup systemFields.tier value=document._source.system.tier localize=true}} + {{formGroup systemFields.type value=document._source.system.type localize=true}} + {{#if (eq document._source.system.type 'horde')}} + {{formGroup systemFields.hordeHp value=document._source.system.hordeHp label=(localize "DAGGERHEART.ACTORS.Adversary.horderHp")}} {{/if}} - {{formGroup systemFields.difficulty value=document.system.difficulty localize=true}} + {{formGroup systemFields.difficulty value=document._source.system.difficulty localize=true}}
    - {{formField systemFields.description value=document.system.description label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.description.label")}} - {{formField systemFields.motivesAndTactics value=document.system.motivesAndTactics label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.motivesAndTactics.label")}} + {{formField systemFields.description value=document._source.system.description label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.description.label")}} + {{formField systemFields.motivesAndTactics value=document._source.system.motivesAndTactics label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.motivesAndTactics.label")}}
    {{localize "DAGGERHEART.GENERAL.HitPoints.plural"}} - {{formGroup systemFields.resources.fields.hitPoints.fields.value value=document.system.resources.hitPoints.value label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.resources.hitPoints.value.label")}} - {{formGroup systemFields.resources.fields.hitPoints.fields.max value=document.system.resources.hitPoints.max}} + {{formGroup systemFields.resources.fields.hitPoints.fields.value value=document._source.system.resources.hitPoints.value label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.resources.hitPoints.value.label")}} + {{formGroup systemFields.resources.fields.hitPoints.fields.max value=document._source.system.resources.hitPoints.max}}
    {{localize "DAGGERHEART.GENERAL.stress"}} - {{formGroup systemFields.resources.fields.stress.fields.value value=document.system.resources.stress.value label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.resources.stress.value.label")}} - {{formGroup systemFields.resources.fields.stress.fields.max value=document.system.resources.stress.max}} + {{formGroup systemFields.resources.fields.stress.fields.value value=document._source.system.resources.stress.value label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.resources.stress.value.label")}} + {{formGroup systemFields.resources.fields.stress.fields.max value=document._source.system.resources.stress.max}}
    {{localize "DAGGERHEART.GENERAL.DamageThresholds.title"}} - {{formGroup systemFields.damageThresholds.fields.major value=document.system.damageThresholds.major label=(localize "DAGGERHEART.GENERAL.DamageThresholds.majorThreshold")}} - {{formGroup systemFields.damageThresholds.fields.severe value=document.system.damageThresholds.severe label=(localize "DAGGERHEART.GENERAL.DamageThresholds.severeThreshold")}} + {{formGroup systemFields.damageThresholds.fields.major value=document._source.system.damageThresholds.major label=(localize "DAGGERHEART.GENERAL.DamageThresholds.majorThreshold")}} + {{formGroup systemFields.damageThresholds.fields.severe value=document._source.system.damageThresholds.severe label=(localize "DAGGERHEART.GENERAL.DamageThresholds.severeThreshold")}}
    \ No newline at end of file diff --git a/templates/sheets-settings/adversary-settings/experiences.hbs b/templates/sheets-settings/adversary-settings/experiences.hbs index 942fb238..a2c2b6de 100644 --- a/templates/sheets-settings/adversary-settings/experiences.hbs +++ b/templates/sheets-settings/adversary-settings/experiences.hbs @@ -10,7 +10,7 @@
    {{localize tabs.experiences.label}}
      - {{#each document.system.experiences as |experience key|}} + {{#each document._source.system.experiences as |experience key|}}
    • diff --git a/templates/sheets-settings/adversary-settings/features.hbs b/templates/sheets-settings/adversary-settings/features.hbs index a287c2a8..b26fa10c 100644 --- a/templates/sheets-settings/adversary-settings/features.hbs +++ b/templates/sheets-settings/adversary-settings/features.hbs @@ -10,7 +10,7 @@ {{localize tabs.features.label}}
        {{#each document.system.features as |feature|}} -
      • +
      • {{feature.name}} @@ -22,5 +22,8 @@
      • {{/each}}
      +
      + {{localize "DAGGERHEART.GENERAL.dropFeaturesHere"}} +
    \ No newline at end of file diff --git a/templates/sheets-settings/companion-settings/attack.hbs b/templates/sheets-settings/companion-settings/attack.hbs index bebe40b3..0ec43d35 100644 --- a/templates/sheets-settings/companion-settings/attack.hbs +++ b/templates/sheets-settings/companion-settings/attack.hbs @@ -5,16 +5,16 @@ >
    {{localize "DAGGERHEART.GENERAL.basics"}} - {{formGroup systemFields.attack.fields.img value=document.system.attack.img label="DAGGERHEART.GENERAL.imagePath" name="system.attack.img" localize=true}} - {{formGroup systemFields.attack.fields.name value=document.system.attack.name label="DAGGERHEART.ACTIONS.Settings.attackName" name="system.attack.name" localize=true}} + {{formGroup systemFields.attack.fields.img value=document._source.system.attack.img label="DAGGERHEART.GENERAL.imagePath" name="system.attack.img" localize=true}} + {{formGroup systemFields.attack.fields.name value=document._source.system.attack.name label="DAGGERHEART.ACTIONS.Settings.attackName" name="system.attack.name" localize=true}}
    {{localize "DAGGERHEART.GENERAL.attack"}} - {{formField systemFields.attack.fields.range value=document.system.attack.range label="DAGGERHEART.GENERAL.range" name="system.attack.range" localize=true}} + {{formField systemFields.attack.fields.range value=document._source.system.attack.range label="DAGGERHEART.GENERAL.range" name="system.attack.range" localize=true}} {{#if systemFields.attack.fields.target.fields}} - {{ formField systemFields.attack.fields.target.fields.type value=document.system.attack.target.type label="DAGGERHEART.GENERAL.Target.single" name="system.attack.target.type" localize=true}} - {{#if (and document.system.attack.target.type (not (eq document.system.attack.target.type 'self')))}} - {{ formField systemFields.attack.fields.target.fields.amount value=document.system.attack.target.amount label="DAGGERHEART.GENERAL.amount" name="system.attack.target.amount" localize=true}} + {{ formField systemFields.attack.fields.target.fields.type value=document._source.system.attack.target.type label="DAGGERHEART.GENERAL.Target.single" name="system.attack.target.type" localize=true}} + {{#if (and document._source.system.attack.target.type (not (eq document._source.system.attack.target.type 'self')))}} + {{ formField systemFields.attack.fields.target.fields.amount value=document._source.system.attack.target.amount label="DAGGERHEART.GENERAL.amount" name="system.attack.target.amount" localize=true}} {{/if}} {{/if}}
    diff --git a/templates/sheets-settings/companion-settings/details.hbs b/templates/sheets-settings/companion-settings/details.hbs index 4f1825d8..e4293443 100644 --- a/templates/sheets-settings/companion-settings/details.hbs +++ b/templates/sheets-settings/companion-settings/details.hbs @@ -6,18 +6,18 @@
    {{localize 'DAGGERHEART.GENERAL.basics'}}
    - {{formGroup systemFields.evasion value=document.system.evasion localize=true}} - {{formGroup systemFields.resources.fields.stress.fields.value value=document.system.resources.stress.value label='DAGGERHEART.ACTORS.Companion.FIELDS.resources.stress.currentStress.label' localize=true}} - {{formGroup systemFields.resources.fields.stress.fields.max value=document.system.resources.stress.max label='DAGGERHEART.ACTORS.Companion.FIELDS.resources.stress.maxStress.label' localize=true}} + {{formGroup systemFields.evasion value=document._source.system.evasion localize=true}} + {{formGroup systemFields.resources.fields.stress.fields.value value=document._source.system.resources.stress.value label='DAGGERHEART.ACTORS.Companion.FIELDS.resources.stress.currentStress.label' localize=true}} + {{formGroup systemFields.resources.fields.stress.fields.max value=document._source.system.resources.stress.max label='DAGGERHEART.ACTORS.Companion.FIELDS.resources.stress.maxStress.label' localize=true}}
    - + \ No newline at end of file diff --git a/templates/sheets-settings/environment-settings/details.hbs b/templates/sheets-settings/environment-settings/details.hbs index 1f8c45f2..ecb47ca8 100644 --- a/templates/sheets-settings/environment-settings/details.hbs +++ b/templates/sheets-settings/environment-settings/details.hbs @@ -6,11 +6,11 @@
    {{localize 'DAGGERHEART.GENERAL.basics'}}
    - {{formGroup systemFields.tier value=document.system.tier localize=true}} - {{formGroup systemFields.type value=document.system.type localize=true}} - {{formGroup systemFields.difficulty value=document.system.difficulty localize=true}} + {{formGroup systemFields.tier value=document._source.system.tier localize=true}} + {{formGroup systemFields.type value=document._source.system.type localize=true}} + {{formGroup systemFields.difficulty value=document._source.system.difficulty localize=true}}
    - {{formField systemFields.description value=document.system.description label=(localize "DAGGERHEART.ACTORS.Environment.FIELDS.description.label")}} - {{formField systemFields.impulses value=document.system.impulses label=(localize "DAGGERHEART.ACTORS.Environment.FIELDS.impulses.label")}} + {{formField systemFields.description value=document._source.system.description label=(localize "DAGGERHEART.ACTORS.Environment.FIELDS.description.label")}} + {{formField systemFields.impulses value=document._source.system.impulses label=(localize "DAGGERHEART.ACTORS.Environment.FIELDS.impulses.label")}}
    \ No newline at end of file diff --git a/templates/sheets/actors/character/header.hbs b/templates/sheets/actors/character/header.hbs index b6f51bcf..9f2d56a1 100644 --- a/templates/sheets/actors/character/header.hbs +++ b/templates/sheets/actors/character/header.hbs @@ -87,9 +87,9 @@
    {{#if document.system.class.value}}
    - {{#each document.system.class.value.system.domains as |domain|}} + {{#each document.system.domainData as |data|}}
    - +
    {{/each}}
    diff --git a/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs b/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs index 8fbd5800..1ef065d5 100644 --- a/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs +++ b/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs @@ -26,7 +26,7 @@ Parameters: {{localize title}} {{#if canCreate}} -
    - {{#if (eq message.type 'base')}} -
    -

    {{actor.name}}

    -
    {{author.name}}
    -
    - {{else}} -
    -

    {{ifThen message.title message.title alias}}

    -
    {{actor.name}} {{#if author.isGM}}(GM){{/if}}
    -
    - {{/if}} +
    + {{#unless actor.name}} +

    {{author.name}}

    + {{else}} + {{#if (eq message.type 'base')}} +

    {{actor.name}}

    +
    {{author.name}}
    + {{else}} +

    {{ifThen message.title message.title alias}}

    +
    {{actor.name}} {{#if author.isGM}}(GM){{/if}}
    + {{/if}} + {{/unless}} +
    {{{message.content}}} + {{#if message.flavor}} + {{{message.flavor}}} + {{/if}}
    \ No newline at end of file diff --git a/templates/ui/chat/parts/button-part.hbs b/templates/ui/chat/parts/button-part.hbs index f28f1a7b..f83972f7 100644 --- a/templates/ui/chat/parts/button-part.hbs +++ b/templates/ui/chat/parts/button-part.hbs @@ -1,17 +1,17 @@
    {{#if hasDamage}} {{#unless (empty damage)}} - + {{#if canButtonApply}}{{/if}} {{else}} {{/unless}} {{/if}} {{#if hasHealing}} {{#unless (empty damage)}} - + {{#if canButtonApply}}{{/if}} {{else}} {{/unless}} {{/if}} - {{#if hasEffect}}{{/if}} + {{#if (and hasEffect canButtonApply)}}{{/if}}
    \ No newline at end of file diff --git a/templates/ui/chat/parts/damage-part.hbs b/templates/ui/chat/parts/damage-part.hbs index 7ec8bfd8..232b1303 100644 --- a/templates/ui/chat/parts/damage-part.hbs +++ b/templates/ui/chat/parts/damage-part.hbs @@ -29,7 +29,13 @@ {{#each results}} {{#unless discarded}}
    -
    {{result}}
    +
    + {{#if hasRerolls}}{{/if}} + {{result}} +
    {{/unless}} {{/each}} diff --git a/templates/ui/chat/parts/roll-part.hbs b/templates/ui/chat/parts/roll-part.hbs index d4e46b1f..cd9bb3d6 100644 --- a/templates/ui/chat/parts/roll-part.hbs +++ b/templates/ui/chat/parts/roll-part.hbs @@ -14,14 +14,15 @@ {{#if roll.difficulty}} - {{#if canViewSecret}} + {{!-- {{#if canViewSecret}} --}} difficulty {{roll.difficulty}} - {{else}} + {{!-- {{else}} {{localize (ifThen roll.success "DAGGERHEART.GENERAL.success" "DAGGERHEART.GENERAL.failure")}} - {{/if}} + {{/if}} --}} {{/if}} + {{#unless isPrivate}}
    {{localize "DAGGERHEART.GENERAL.formula"}}
    @@ -56,7 +57,7 @@ {{/if}} {{#if roll.rally.dice}}
    - +
    {{roll.rally.value}}
    {{/if}} @@ -87,4 +88,5 @@
    + {{/unless}} \ No newline at end of file diff --git a/templates/ui/chat/parts/target-part.hbs b/templates/ui/chat/parts/target-part.hbs index 94810a03..82c71456 100644 --- a/templates/ui/chat/parts/target-part.hbs +++ b/templates/ui/chat/parts/target-part.hbs @@ -14,12 +14,12 @@
    - {{#if targets.length}} + {{#if (and parent.isAuthor targets.length)}}
    -
    {{localize "DAGGERHEART.UI.Chat.damageRoll.hitTarget"}}
    -
    {{localize "DAGGERHEART.UI.Chat.damageRoll.currentTarget"}}
    +
    {{localize "DAGGERHEART.UI.Chat.damageRoll.hitTarget"}}
    +
    {{localize "DAGGERHEART.UI.Chat.damageRoll.currentTarget"}}
    @@ -29,8 +29,8 @@
    -
    {{name}}
    - {{#if (and ../targetSelection ../hasRoll)}} +
    {{name}}
    + {{#if (and ../targetMode ../hasRoll)}}
    {{#if hit}} {{localize "DAGGERHEART.GENERAL.hit.single"}} @@ -40,7 +40,7 @@
    {{/if}}
    - {{#if (and ../hasSave (or hit (not @root.targetSelection)))}} + {{#if (and ../hasSave (or hit (not @root.hasRoll)))}}
    diff --git a/templates/ui/chat/roll.hbs b/templates/ui/chat/roll.hbs index 37e1aef2..2e6f5d24 100644 --- a/templates/ui/chat/roll.hbs +++ b/templates/ui/chat/roll.hbs @@ -5,4 +5,4 @@ {{#if hasTarget}}{{> 'systems/daggerheart/templates/ui/chat/parts/target-part.hbs'}}{{/if}}
    -{{> 'systems/daggerheart/templates/ui/chat/parts/button-part.hbs'}} \ No newline at end of file +{{#if (or parent.isAuthor canButtonApply)}}{{> 'systems/daggerheart/templates/ui/chat/parts/button-part.hbs'}}{{/if}} \ No newline at end of file diff --git a/templates/ui/combatTracker/combatTrackerHeader.hbs b/templates/ui/combatTracker/combatTrackerHeader.hbs index de666168..9ecff9e6 100644 --- a/templates/ui/combatTracker/combatTrackerHeader.hbs +++ b/templates/ui/combatTracker/combatTrackerHeader.hbs @@ -51,19 +51,6 @@ {{/if}}
    - {{#if hasCombat}} - - {{/if}} - {{!-- Combat Status --}} {{#if combats.length}} @@ -78,14 +65,16 @@ {{!-- Combat Controls --}} - {{#if hasCombat}} -
    -
    - -
    - {{/if}} - +
    + {{#if hasCombat}} + +
    +
    + +
    + {{/if}} +