diff --git a/daggerheart.mjs b/daggerheart.mjs index 3abcd210..4e88c148 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -78,7 +78,6 @@ CONFIG.ux.ContextMenu = applications.ux.DHContextMenu; CONFIG.ux.TooltipManager = documents.DhTooltipManager; CONFIG.ux.TemplateManager = new TemplateManager(); CONFIG.ux.TokenManager = new TokenManager(); -CONFIG.debug.triggers = false; Hooks.once('init', () => { game.system.api = { @@ -90,7 +89,7 @@ Hooks.once('init', () => { fields }; - game.system.registeredTriggers = new game.system.api.data.RegisteredTriggers(); + game.system.registeredTriggers = new RegisteredTriggers(); const { DocumentSheetConfig } = foundry.applications.apps; DocumentSheetConfig.unregisterSheet(TokenDocument, 'core', foundry.applications.sheets.TokenConfig); @@ -390,12 +389,49 @@ Hooks.on('refreshToken', (_, options) => { Hooks.on('renderCompendiumDirectory', (app, html) => applications.ui.ItemBrowser.injectSidebarButton(html)); Hooks.on('renderDocumentDirectory', (app, html) => applications.ui.ItemBrowser.injectSidebarButton(html)); -/* Non actor-linked Actors should unregister the triggers of their tokens if a scene's token layer is torn down */ -Hooks.on('canvasTearDown', canvas => { - game.system.registeredTriggers.unregisterSceneTriggers(canvas.scene); -}); +class RegisteredTriggers extends Map { + constructor() { + super(); + } -/* Non actor-linked Actors should register the triggers of their tokens on a readied scene */ -Hooks.on('canvasReady', canas => { - game.system.registeredTriggers.registerSceneTriggers(canvas.scene); -}); + async registerTriggers(trigger, actor, triggeringActorType, uuid, commands) { + const existingTrigger = this.get(trigger); + if (!existingTrigger) this.set(trigger, new Map()); + + this.get(trigger).set(uuid, { actor, triggeringActorType, commands }); + } + + async runTrigger(trigger, currentActor, ...args) { + const updates = []; + const triggerSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).triggers; + if (!triggerSettings.enabled) return updates; + + const dualityTrigger = this.get(trigger); + if (dualityTrigger) { + for (let { actor, triggeringActorType, commands } of dualityTrigger.values()) { + const triggerData = CONFIG.DH.TRIGGER.triggers[trigger]; + if (triggerData.usesActor && triggeringActorType !== 'any') { + if (triggeringActorType === 'self' && currentActor?.uuid !== actor) continue; + else if (triggeringActorType === 'other' && currentActor?.uuid === actor) continue; + } + + for (let command of commands) { + try { + const result = await command(...args); + if (result?.updates?.length) updates.push(...result.updates); + } catch (_) { + const triggerName = game.i18n.localize(triggerData.label); + ui.notifications.error( + game.i18n.format('DAGGERHEART.CONFIG.Triggers.triggerError', { + trigger: triggerName, + actor: currentActor?.name + }) + ); + } + } + } + } + + return updates; + } +} diff --git a/lang/en.json b/lang/en.json index 870e1b2b..14915a81 100755 --- a/lang/en.json +++ b/lang/en.json @@ -237,13 +237,10 @@ "confirmText": "Would you like to level up your companion {name} by {levelChange} levels at this time? (You can do it manually later)" }, "viewLevelups": "View Levelups", - "resetCharacter": "Reset Character", "viewParty": "View Party", "InvalidOldCharacterImportTitle": "Old Character Import", "InvalidOldCharacterImportText": "Character data exported prior to system version 1.1 will not generate a complete character. Do you wish to continue?", - "cancelBeastform": "Cancel Beastform", - "resetCharacterConfirmationTitle": "Reset Character", - "resetCharacterConfirmationContent": "You are reseting all character data except name and portrait. Are you sure?" + "cancelBeastform": "Cancel Beastform" }, "Companion": { "FIELDS": { @@ -317,8 +314,6 @@ "selectPrimaryWeapon": "Select Primary Weapon", "selectSecondaryWeapon": "Select Secondary Weapon", "selectSubclass": "Select Subclass", - "setupSkipTitle": "Skipping Character Setup", - "setupSkipContent": "You are skipping the Character Setup by adding this manually. The character setup is the blinking arrows in the top-right. Are you sure you want to continue?", "startingItems": "Starting Items", "story": "Story", "storyExplanation": "Select which background and connection prompts you want to copy into your character's background.", @@ -2090,7 +2085,6 @@ "tier4": "tier 4", "domains": "Domains", "downtime": "Downtime", - "itemFeatures": "Item Features", "roll": "Roll", "rules": "Rules", "partyMembers": "Party Members", @@ -2455,6 +2449,10 @@ "label": "Show Resource Change Scrolltexts", "hint": "When a character is damaged, uses armor etc, a scrolling text will briefly appear by the token to signify this." }, + "playerCanEditSheet": { + "label": "Players Can Manually Edit Character Settings", + "hint": "Players are allowed to access the manual Character Settings and change their statistics beyond the rules." + }, "roll": { "roll": { "label": "Roll", @@ -2711,9 +2709,6 @@ "rerollDamage": "Reroll Damage", "assignTagRoll": "Assign as Tag Roll" }, - "ConsoleLogs": { - "triggerRun": "DH TRIGGER | Item '{item}' on actor '{actor}' ran a '{trigger}' trigger." - }, "Countdowns": { "title": "Countdowns", "toggleIconMode": "Toggle Icon Only", diff --git a/module/applications/dialogs/d20RollDialog.mjs b/module/applications/dialogs/d20RollDialog.mjs index 441842dc..d8306923 100644 --- a/module/applications/dialogs/d20RollDialog.mjs +++ b/module/applications/dialogs/d20RollDialog.mjs @@ -123,7 +123,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio context.formula = this.roll.constructFormula(this.config); if (this.actor?.system?.traits) context.abilities = this.getTraitModifiers(); - context.showReaction = !this.config.roll?.type || context.rollType === 'DualityRoll'; + context.showReaction = !this.config.roll?.type && context.rollType === 'DualityRoll'; context.reactionOverride = this.reactionOverride; } diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index d691c129..dd5f35fc 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -27,7 +27,6 @@ export default class CharacterSheet extends DHBaseActorSheet { makeDeathMove: CharacterSheet.#makeDeathMove, levelManagement: CharacterSheet.#levelManagement, viewLevelups: CharacterSheet.#viewLevelups, - resetCharacter: CharacterSheet.#resetCharacter, toggleEquipItem: CharacterSheet.#toggleEquipItem, toggleResourceDice: CharacterSheet.#toggleResourceDice, handleResourceDice: CharacterSheet.#handleResourceDice, @@ -43,11 +42,6 @@ export default class CharacterSheet extends DHBaseActorSheet { icon: 'fa-solid fa-angles-up', label: 'DAGGERHEART.ACTORS.Character.viewLevelups', action: 'viewLevelups' - }, - { - icon: 'fa-solid fa-arrow-rotate-left', - label: 'DAGGERHEART.ACTORS.Character.resetCharacter', - action: 'resetCharacter' } ] }, @@ -226,6 +220,13 @@ export default class CharacterSheet extends DHBaseActorSheet { async _preparePartContext(partId, context, options) { context = await super._preparePartContext(partId, context, options); switch (partId) { + case 'header': + const { playerCanEditSheet, levelupAuto } = game.settings.get( + CONFIG.DH.id, + CONFIG.DH.SETTINGS.gameSettings.Automation + ); + context.showSettings = game.user.isGM || !levelupAuto || (levelupAuto && playerCanEditSheet); + break; case 'loadout': await this._prepareLoadoutContext(context, options); break; @@ -665,32 +666,6 @@ export default class CharacterSheet extends DHBaseActorSheet { new LevelupViewMode(this.document).render({ force: true }); } - /** - * Resets the character data and removes all embedded documents. - */ - static async #resetCharacter() { - const confirmed = await foundry.applications.api.DialogV2.confirm({ - window: { - title: game.i18n.localize('DAGGERHEART.ACTORS.Character.resetCharacterConfirmationTitle') - }, - content: game.i18n.localize('DAGGERHEART.ACTORS.Character.resetCharacterConfirmationContent') - }); - - if (!confirmed) return; - - await this.document.update({ - '==system': {} - }); - await this.document.deleteEmbeddedDocuments( - 'Item', - this.document.items.map(x => x.id) - ); - await this.document.deleteEmbeddedDocuments( - 'ActiveEffect', - this.document.effects.map(x => x.id) - ); - } - /** * Opens the Death Move interface for the character. * @type {ApplicationClickAction} @@ -737,7 +712,7 @@ export default class CharacterSheet extends DHBaseActorSheet { headerTitle: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { ability: abilityLabel }), - effects: await game.system.api.data.actions.actionsTypes.base.getEffects(this.document), + effects: Array.from(await this.document.allApplicableEffects()), roll: { trait: button.dataset.attribute, type: 'trait' @@ -981,18 +956,6 @@ export default class CharacterSheet extends DHBaseActorSheet { } async _onDropItem(event, item) { - const setupCriticalItemTypes = ['class', 'subclass', 'ancestry', 'community']; - if (this.document.system.needsCharacterSetup && setupCriticalItemTypes.includes(item.type)) { - const confirmed = await foundry.applications.api.DialogV2.confirm({ - window: { - title: game.i18n.localize('DAGGERHEART.APPLICATIONS.CharacterCreation.setupSkipTitle') - }, - content: game.i18n.localize('DAGGERHEART.APPLICATIONS.CharacterCreation.setupSkipContent') - }); - - if (!confirmed) return; - } - if (this.document.uuid === item.parent?.uuid) { return super._onDropItem(event, item); } diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs index b590de86..7276316f 100644 --- a/module/applications/sheets/api/application-mixin.mjs +++ b/module/applications/sheets/api/application-mixin.mjs @@ -505,10 +505,7 @@ export default function DHApplicationMixin(Base) { const doc = await getDocFromElement(target), action = doc?.system?.attack ?? doc; const config = action.prepareConfig(event); - config.effects = await game.system.api.data.actions.actionsTypes.base.getEffects( - this.document, - doc - ); + config.effects = Array.from(await this.document.allApplicableEffects()); config.hasRoll = false; return action && action.workflow.get('damage').execute(config, null, true); } diff --git a/module/applications/sidebar/tabs/daggerheartMenu.mjs b/module/applications/sidebar/tabs/daggerheartMenu.mjs index b29437bf..6c7a9df1 100644 --- a/module/applications/sidebar/tabs/daggerheartMenu.mjs +++ b/module/applications/sidebar/tabs/daggerheartMenu.mjs @@ -25,7 +25,7 @@ export default class DaggerheartMenu extends HandlebarsApplicationMixin(Abstract /** @override */ static DEFAULT_OPTIONS = { - classes: ['dh-style', 'directory'], + classes: ['dh-style'], window: { title: 'SIDEBAR.TabSettings' }, diff --git a/module/applications/ui/chatLog.mjs b/module/applications/ui/chatLog.mjs index c4a313fa..20dfea8d 100644 --- a/module/applications/ui/chatLog.mjs +++ b/module/applications/ui/chatLog.mjs @@ -92,19 +92,6 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo super.close(options); } - /** Ensure the chat theme inherits the interface theme */ - _replaceHTML(result, content, options) { - const themedElement = result.log?.querySelector(".chat-log"); - themedElement?.classList.remove("themed", "theme-light", "theme-dark"); - super._replaceHTML(result, content, options); - } - - /** Remove chat log theme from notifications area */ - async _onFirstRender(result, content) { - await super._onFirstRender(result, content); - document.querySelector("#chat-notifications .chat-log")?.classList.remove("themed", "theme-light", "theme-dark") - } - async onRollSimple(event, message) { const buttonType = event.target.dataset.type ?? 'damage', total = message.rolls.reduce((a, c) => a + Roll.fromJSON(c).total, 0), diff --git a/module/data/_module.mjs b/module/data/_module.mjs index 7ad20808..0a476ee9 100644 --- a/module/data/_module.mjs +++ b/module/data/_module.mjs @@ -1,7 +1,6 @@ export { default as DhCombat } from './combat.mjs'; export { default as DhCombatant } from './combatant.mjs'; export { default as DhTagTeamRoll } from './tagTeamRoll.mjs'; -export { default as RegisteredTriggers } from './registeredTriggers.mjs'; export * as countdowns from './countdowns.mjs'; export * as actions from './action/_module.mjs'; diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index b5f95aff..dac4cf68 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -198,7 +198,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel let config = this.prepareConfig(event); if (!config) return; - config.effects = await game.system.api.data.actions.actionsTypes.base.getEffects(this.actor, this.item); + await this.addEffects(config); if (Hooks.call(`${CONFIG.DH.id}.preUseAction`, this, config) === false) return; @@ -266,26 +266,14 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel return config; } - /** - * Get the all potentially applicable effects on the actor - * @param {DHActor} actor The actor performing the action - * @param {DHItem|DhActor} effectParent The parent of the effect - * @returns {DhActiveEffect[]} - */ - static async getEffects(actor, effectParent) { - if (!actor) return []; + /** */ + async addEffects(config) { + let effects = []; + if (this.actor) { + effects = Array.from(await this.actor.allApplicableEffects()); + } - return Array.from(await actor.allApplicableEffects()).filter(effect => { - /* Effects on weapons only ever apply for the weapon itself */ - if (effect.parent.type === 'weapon') { - /* Unless they're secondary - then they apply only to other primary weapons */ - if (effect.parent.system.secondary) { - if (effectParent?.type !== 'weapon' || effectParent?.system.secondary) return false; - } else if (effectParent?.id !== effect.parent.id) return false; - } - - return !effect.isSuppressed; - }); + config.effects = effects; } /** diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index 0c9fdabe..415fc8d4 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -164,7 +164,26 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { prepareBaseData() { super.prepareBaseData(); - game.system.registeredTriggers.registerItemTriggers(this.parent); + + for (const action of this.actions ?? []) { + if (!action.actor) continue; + + const actionsToRegister = []; + for (let i = 0; i < action.triggers.length; i++) { + const trigger = action.triggers[i]; + const { args } = CONFIG.DH.TRIGGER.triggers[trigger.trigger]; + const fn = new foundry.utils.AsyncFunction(...args, `{${trigger.command}\n}`); + actionsToRegister.push(fn.bind(action)); + if (i === action.triggers.length - 1) + game.system.registeredTriggers.registerTriggers( + trigger.trigger, + action.actor?.uuid, + trigger.triggeringActorType, + this.parent.uuid, + actionsToRegister + ); + } + } } async _preCreate(data, options, user) { @@ -227,28 +246,6 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { const armorData = getScrollTextData(this.parent.parent.system.resources, changed.system.marks, 'armor'); options.scrollingTextData = [armorData]; } - - if (changed.system?.actions) { - const triggersToRemove = Object.keys(changed.system.actions).reduce((acc, key) => { - if (!changed.system.actions[key]) { - const strippedKey = key.replace('-=', ''); - acc.push(...this.actions.get(strippedKey).triggers.map(x => x.trigger)); - } - - return acc; - }, []); - - game.system.registeredTriggers.unregisterTriggers(triggersToRemove, this.parent.uuid); - - if (!(this.parent.parent.token instanceof game.system.api.documents.DhToken)) { - for (const token of this.parent.parent.getActiveTokens()) { - game.system.registeredTriggers.unregisterTriggers( - triggersToRemove, - `${token.document.uuid}.${this.parent.uuid}` - ); - } - } - } } _onUpdate(changed, options, userId) { diff --git a/module/data/registeredTriggers.mjs b/module/data/registeredTriggers.mjs deleted file mode 100644 index fe962c5e..00000000 --- a/module/data/registeredTriggers.mjs +++ /dev/null @@ -1,154 +0,0 @@ -export default class RegisteredTriggers extends Map { - constructor() { - super(); - } - - registerTriggers(triggers, actor, uuid) { - for (const triggerKey of Object.keys(CONFIG.DH.TRIGGER.triggers)) { - const match = triggers[triggerKey]; - const existingTrigger = this.get(triggerKey); - - if (!match) { - if (existingTrigger?.get(uuid)) this.get(triggerKey).delete(uuid); - } else { - const { trigger, triggeringActorType, commands } = match; - - if (!existingTrigger) this.set(trigger, new Map()); - this.get(trigger).set(uuid, { actor, triggeringActorType, commands }); - } - } - } - - registerItemTriggers(item, registerOverride) { - for (const action of item.system.actions ?? []) { - if (!action.actor) continue; - - /* Non actor-linked should only prep synthetic actors so they're not registering triggers unless they're on the canvas */ - if ( - !registerOverride && - !action.actor.prototypeToken.actorLink && - (!(action.actor.parent instanceof game.system.api.documents.DhToken) || !action.actor.parent?.uuid) - ) - continue; - - const triggers = {}; - for (const trigger of action.triggers) { - const { args } = CONFIG.DH.TRIGGER.triggers[trigger.trigger]; - const fn = new foundry.utils.AsyncFunction(...args, `{${trigger.command}\n}`); - - if (!triggers[trigger.trigger]) - triggers[trigger.trigger] = { - trigger: trigger.trigger, - triggeringActorType: trigger.triggeringActorType, - commands: [] - }; - triggers[trigger.trigger].commands.push(fn.bind(action)); - } - - this.registerTriggers(triggers, action.actor?.uuid, item.uuid); - } - } - - unregisterTriggers(triggerKeys, uuid) { - for (const triggerKey of triggerKeys) { - const existingTrigger = this.get(triggerKey); - if (!existingTrigger) return; - - existingTrigger.delete(uuid); - } - } - - unregisterItemTriggers(items) { - for (const item of items) { - if (!item.system.actions.size) continue; - - const triggers = (item.system.actions ?? []).reduce((acc, action) => { - acc.push(...action.triggers.map(x => x.trigger)); - return acc; - }, []); - - this.unregisterTriggers(triggers, item.uuid); - } - } - - unregisterSceneTriggers(scene) { - for (const triggerKey of Object.keys(CONFIG.DH.TRIGGER.triggers)) { - const existingTrigger = this.get(triggerKey); - if (!existingTrigger) continue; - const filtered = new Map(); - for (const [uuid, data] of existingTrigger.entries()) { - if (!uuid.startsWith(scene.uuid)) filtered.set(uuid, data); - } - this.set(triggerKey, filtered); - } - } - - registerSceneTriggers(scene) { - /* TODO: Finish sceneEnvironment registration and unreg */ - // const systemData = new game.system.api.data.scenes.DHScene(scene.flags.daggerheart); - // for (const environment of systemData.sceneEnvironments) { - // for (const feature of environment.system.features) { - // if(feature) this.registerItemTriggers(feature, true); - // } - // } - - for (const actor of scene.tokens.filter(x => x.actor).map(x => x.actor)) { - if (actor.prototypeToken.actorLink) continue; - - for (const item of actor.items) { - this.registerItemTriggers(item); - } - } - } - - async runTrigger(trigger, currentActor, ...args) { - const updates = []; - const triggerSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).triggers; - if (!triggerSettings.enabled) return updates; - - const dualityTrigger = this.get(trigger); - if (dualityTrigger) { - const tokenBoundActors = ['adversary', 'environment']; - const triggerActors = ['character', ...tokenBoundActors]; - for (let [itemUuid, { actor: actorUuid, triggeringActorType, commands }] of dualityTrigger.entries()) { - const actor = await foundry.utils.fromUuid(actorUuid); - if (!actor || !triggerActors.includes(actor.type)) continue; - if (tokenBoundActors.includes(actor.type) && !actor.getActiveTokens().length) continue; - - const triggerData = CONFIG.DH.TRIGGER.triggers[trigger]; - if (triggerData.usesActor && triggeringActorType !== 'any') { - if (triggeringActorType === 'self' && currentActor?.uuid !== actorUuid) continue; - else if (triggeringActorType === 'other' && currentActor?.uuid === actorUuid) continue; - } - - for (const command of commands) { - try { - if (CONFIG.debug.triggers) { - const item = await foundry.utils.fromUuid(itemUuid); - console.log( - game.i18n.format('DAGGERHEART.UI.ConsoleLogs.triggerRun', { - actor: actor.name ?? '', - item: item?.name ?? '', - trigger: game.i18n.localize(triggerData.label) - }) - ); - } - - const result = await command(...args); - if (result?.updates?.length) updates.push(...result.updates); - } catch (_) { - const triggerName = game.i18n.localize(triggerData.label); - ui.notifications.error( - game.i18n.format('DAGGERHEART.CONFIG.Triggers.triggerError', { - trigger: triggerName, - actor: currentActor?.name - }) - ); - } - } - } - } - - return updates; - } -} diff --git a/module/data/settings/Automation.mjs b/module/data/settings/Automation.mjs index bff0bae9..3376b153 100644 --- a/module/data/settings/Automation.mjs +++ b/module/data/settings/Automation.mjs @@ -55,6 +55,11 @@ export default class DhAutomation extends foundry.abstract.DataModel { initial: true, label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.resourceScrollTexts.label' }), + playerCanEditSheet: new fields.BooleanField({ + required: true, + initial: false, + label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.playerCanEditSheet.label' + }), defeated: new fields.SchemaField({ enabled: new fields.BooleanField({ required: true, diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 27c310ae..1a4153ad 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -104,16 +104,6 @@ export default class DhpActor extends Actor { } } - async _preDelete() { - if (this.prototypeToken.actorLink) { - game.system.registeredTriggers.unregisterItemTriggers(this.items); - } else { - for (const token of this.getActiveTokens()) { - game.system.registeredTriggers.unregisterItemTriggers(token.actor.items); - } - } - } - _onDelete(options, userId) { super._onDelete(options, userId); for (const party of this.parties) { diff --git a/module/documents/chatMessage.mjs b/module/documents/chatMessage.mjs index 2f23cc1a..d85bcb45 100644 --- a/module/documents/chatMessage.mjs +++ b/module/documents/chatMessage.mjs @@ -158,9 +158,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { const config = foundry.utils.deepClone(this.system); config.event = event; if (this.system.action) { - const actor = await foundry.utils.fromUuid(config.source.actor); - const item = actor?.items.get(config.source.item) ?? null; - config.effects = await game.system.api.data.actions.actionsTypes.base.getEffects(actor, item); + await this.system.action.addEffects(config); await this.system.action.workflow.get('damage')?.execute(config, this._id, true); } @@ -194,16 +192,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { return ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelectedOrPerm')); this.consumeOnSuccess(); - if (this.system.action) this.system.action.workflow.get('applyDamage')?.execute(config, targets, true); - else { - for (const target of targets) { - const actor = await foundry.utils.fromUuid(target.actorId); - if (!actor) continue; - - if (this.system.hasHealing) actor.takeHealing(this.system.damage); - else actor.takeDamage(this.system.damage); - } - } + this.system.action?.workflow.get('applyDamage')?.execute(config, targets, true); } async onRollSave(event) { diff --git a/module/documents/item.mjs b/module/documents/item.mjs index 0a163dab..7607658c 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -208,23 +208,4 @@ export default class DHItem extends foundry.documents.Item { cls.create(msg); } - - deleteTriggers() { - const actions = Array.from(this.system.actions ?? []); - if (!actions.length) return; - - const triggerKeys = actions.flatMap(action => action.triggers.map(x => x.trigger)); - - game.system.registeredTriggers.unregisterTriggers(triggerKeys, this.uuid); - - if (!(this.actor.parent instanceof game.system.api.documents.DhToken)) { - for (const token of this.actor.getActiveTokens()) { - game.system.registeredTriggers.unregisterTriggers(triggerKeys, `${token.document.uuid}.${this.uuid}`); - } - } - } - - async _preDelete() { - this.deleteTriggers(); - } } diff --git a/module/documents/token.mjs b/module/documents/token.mjs index 317f3acf..4ac29264 100644 --- a/module/documents/token.mjs +++ b/module/documents/token.mjs @@ -536,10 +536,4 @@ export default class DHToken extends CONFIG.Token.documentClass { }; } //#endregion - - async _preDelete() { - if (this.actor && !this.actor.prototypeToken?.actorLink) { - game.system.registeredTriggers.unregisterItemTriggers(this.actor.items); - } - } } diff --git a/src/packs/items/weapons/weapon_Advanced_Greatstaff_4UzxqfkwF8gDSdu7.json b/src/packs/items/weapons/weapon_Advanced_Greatstaff_4UzxqfkwF8gDSdu7.json index c66354c2..6ce54823 100644 --- a/src/packs/items/weapons/weapon_Advanced_Greatstaff_4UzxqfkwF8gDSdu7.json +++ b/src/packs/items/weapons/weapon_Advanced_Greatstaff_4UzxqfkwF8gDSdu7.json @@ -113,7 +113,18 @@ "name": "Powerful", "description": "On a successful attack, roll an additional damage die and discard the lowest result.", "img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp", - "changes": [], + "changes": [ + { + "key": "system.bonuses.damage.primaryWeapon.extraDice", + "mode": 2, + "value": "1" + }, + { + "key": "system.rules.weapon.dropLowestDamageDice", + "mode": 5, + "value": "1" + } + ], "_id": "sGVVxSM68Fmr1sSM", "type": "base", "system": {}, diff --git a/src/packs/items/weapons/weapon_Advanced_Greatsword_MAC6YWTo4lzSotQc.json b/src/packs/items/weapons/weapon_Advanced_Greatsword_MAC6YWTo4lzSotQc.json index 71226630..fe3fff0e 100644 --- a/src/packs/items/weapons/weapon_Advanced_Greatsword_MAC6YWTo4lzSotQc.json +++ b/src/packs/items/weapons/weapon_Advanced_Greatsword_MAC6YWTo4lzSotQc.json @@ -118,6 +118,16 @@ "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" } ], "_id": "E0PjC15OP55vIype", diff --git a/src/packs/items/weapons/weapon_Double_Flail_xm1yU7k58fMgXxRR.json b/src/packs/items/weapons/weapon_Double_Flail_xm1yU7k58fMgXxRR.json index a118b399..2e00f9c1 100644 --- a/src/packs/items/weapons/weapon_Double_Flail_xm1yU7k58fMgXxRR.json +++ b/src/packs/items/weapons/weapon_Double_Flail_xm1yU7k58fMgXxRR.json @@ -113,7 +113,18 @@ "name": "Powerful", "description": "On a successful attack, roll an additional damage die and discard the lowest result.", "img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp", - "changes": [], + "changes": [ + { + "key": "system.bonuses.damage.primaryWeapon.extraDice", + "mode": 2, + "value": "1" + }, + { + "key": "system.rules.weapon.dropLowestDamageDice", + "mode": 5, + "value": "1" + } + ], "_id": "DCie5eR1dZH2Qvln", "type": "base", "system": {}, diff --git a/src/packs/items/weapons/weapon_Elder_Bow_JdWcn9W1edhAEInL.json b/src/packs/items/weapons/weapon_Elder_Bow_JdWcn9W1edhAEInL.json index 35659402..b6437781 100644 --- a/src/packs/items/weapons/weapon_Elder_Bow_JdWcn9W1edhAEInL.json +++ b/src/packs/items/weapons/weapon_Elder_Bow_JdWcn9W1edhAEInL.json @@ -113,7 +113,18 @@ "name": "Powerful", "description": "On a successful attack, roll an additional damage die and discard the lowest result.", "img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp", - "changes": [], + "changes": [ + { + "key": "system.bonuses.damage.primaryWeapon.extraDice", + "mode": 2, + "value": "1" + }, + { + "key": "system.rules.weapon.dropLowestDamageDice", + "mode": 5, + "value": "1" + } + ], "_id": "sZ1XotFlGdkPPDG4", "type": "base", "system": {}, diff --git a/src/packs/items/weapons/weapon_Floating_Bladeshards_3vti3xfo0wJND7ew.json b/src/packs/items/weapons/weapon_Floating_Bladeshards_3vti3xfo0wJND7ew.json index 232f26e9..fa7b7d45 100644 --- a/src/packs/items/weapons/weapon_Floating_Bladeshards_3vti3xfo0wJND7ew.json +++ b/src/packs/items/weapons/weapon_Floating_Bladeshards_3vti3xfo0wJND7ew.json @@ -113,7 +113,18 @@ "name": "Powerful", "description": "On a successful attack, roll an additional damage die and discard the lowest result.", "img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp", - "changes": [], + "changes": [ + { + "key": "system.bonuses.damage.primaryWeapon.extraDice", + "mode": 2, + "value": "1" + }, + { + "key": "system.rules.weapon.dropLowestDamageDice", + "mode": 5, + "value": "1" + } + ], "_id": "T831j6kZiMnpMNmv", "type": "base", "system": {}, diff --git a/src/packs/items/weapons/weapon_Gilded_Falchion_VwcOgqnzjf9LBj2S.json b/src/packs/items/weapons/weapon_Gilded_Falchion_VwcOgqnzjf9LBj2S.json index ee8afebc..551dcf56 100644 --- a/src/packs/items/weapons/weapon_Gilded_Falchion_VwcOgqnzjf9LBj2S.json +++ b/src/packs/items/weapons/weapon_Gilded_Falchion_VwcOgqnzjf9LBj2S.json @@ -113,7 +113,18 @@ "name": "Powerful", "description": "On a successful attack, roll an additional damage die and discard the lowest result.", "img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp", - "changes": [], + "changes": [ + { + "key": "system.bonuses.damage.primaryWeapon.extraDice", + "mode": 2, + "value": "1" + }, + { + "key": "system.rules.weapon.dropLowestDamageDice", + "mode": 5, + "value": "1" + } + ], "_id": "ir4iKLIQ4CH1Qckn", "type": "base", "system": {}, diff --git a/src/packs/items/weapons/weapon_Greatbow_MXBpbqQsZFln4rZk.json b/src/packs/items/weapons/weapon_Greatbow_MXBpbqQsZFln4rZk.json index f56e77c7..f97e5432 100644 --- a/src/packs/items/weapons/weapon_Greatbow_MXBpbqQsZFln4rZk.json +++ b/src/packs/items/weapons/weapon_Greatbow_MXBpbqQsZFln4rZk.json @@ -113,7 +113,18 @@ "name": "Powerful", "description": "On a successful attack, roll an additional damage die and discard the lowest result.", "img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp", - "changes": [], + "changes": [ + { + "key": "system.bonuses.damage.primaryWeapon.extraDice", + "mode": 2, + "value": "1" + }, + { + "key": "system.rules.weapon.dropLowestDamageDice", + "mode": 5, + "value": "1" + } + ], "_id": "K4VgrDjVj1U1m9Ie", "type": "base", "system": {}, diff --git a/src/packs/items/weapons/weapon_Greatstaff_Yk8pTEmyLLi4095S.json b/src/packs/items/weapons/weapon_Greatstaff_Yk8pTEmyLLi4095S.json index 66c12e5e..0fbfc2b4 100644 --- a/src/packs/items/weapons/weapon_Greatstaff_Yk8pTEmyLLi4095S.json +++ b/src/packs/items/weapons/weapon_Greatstaff_Yk8pTEmyLLi4095S.json @@ -113,7 +113,18 @@ "name": "Powerful", "description": "On a successful attack, roll an additional damage die and discard the lowest result.", "img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp", - "changes": [], + "changes": [ + { + "key": "system.bonuses.damage.primaryWeapon.extraDice", + "mode": 2, + "value": "1" + }, + { + "key": "system.rules.weapon.dropLowestDamageDice", + "mode": 5, + "value": "1" + } + ], "_id": "904orawScurM9GjG", "type": "base", "system": {}, diff --git a/src/packs/items/weapons/weapon_Greatsword_70ysaFJDREwTgvZa.json b/src/packs/items/weapons/weapon_Greatsword_70ysaFJDREwTgvZa.json index f60e438d..4707e397 100644 --- a/src/packs/items/weapons/weapon_Greatsword_70ysaFJDREwTgvZa.json +++ b/src/packs/items/weapons/weapon_Greatsword_70ysaFJDREwTgvZa.json @@ -118,6 +118,16 @@ "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" } ], "_id": "cffkpiwGpEGhjiUC", diff --git a/src/packs/items/weapons/weapon_Improved_Greatstaff_LCuTrYXi4lhg6LqW.json b/src/packs/items/weapons/weapon_Improved_Greatstaff_LCuTrYXi4lhg6LqW.json index cf1bdf63..5faa0b0e 100644 --- a/src/packs/items/weapons/weapon_Improved_Greatstaff_LCuTrYXi4lhg6LqW.json +++ b/src/packs/items/weapons/weapon_Improved_Greatstaff_LCuTrYXi4lhg6LqW.json @@ -113,7 +113,18 @@ "name": "Powerful", "description": "On a successful attack, roll an additional damage die and discard the lowest result.", "img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp", - "changes": [], + "changes": [ + { + "key": "system.bonuses.damage.primaryWeapon.extraDice", + "mode": 2, + "value": "1" + }, + { + "key": "system.rules.weapon.dropLowestDamageDice", + "mode": 5, + "value": "1" + } + ], "_id": "hnayB09P25ZW3gVY", "type": "base", "system": {}, diff --git a/src/packs/items/weapons/weapon_Improved_Greatsword_FPX4ouDrxXiQ5MDf.json b/src/packs/items/weapons/weapon_Improved_Greatsword_FPX4ouDrxXiQ5MDf.json index f71e5ea6..f8407b13 100644 --- a/src/packs/items/weapons/weapon_Improved_Greatsword_FPX4ouDrxXiQ5MDf.json +++ b/src/packs/items/weapons/weapon_Improved_Greatsword_FPX4ouDrxXiQ5MDf.json @@ -118,6 +118,16 @@ "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" } ], "_id": "2nl35v8sPAudiOIb", diff --git a/src/packs/items/weapons/weapon_Legendary_Greatstaff_jDtvEabkHY1GFgfc.json b/src/packs/items/weapons/weapon_Legendary_Greatstaff_jDtvEabkHY1GFgfc.json index a5ea82f9..0d317f0d 100644 --- a/src/packs/items/weapons/weapon_Legendary_Greatstaff_jDtvEabkHY1GFgfc.json +++ b/src/packs/items/weapons/weapon_Legendary_Greatstaff_jDtvEabkHY1GFgfc.json @@ -113,7 +113,18 @@ "name": "Powerful", "description": "On a successful attack, roll an additional damage die and discard the lowest result.", "img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp", - "changes": [], + "changes": [ + { + "key": "system.bonuses.damage.primaryWeapon.extraDice", + "mode": 2, + "value": "1" + }, + { + "key": "system.rules.weapon.dropLowestDamageDice", + "mode": 5, + "value": "1" + } + ], "_id": "OV1Ly7vX4owBUgLQ", "type": "base", "system": {}, diff --git a/src/packs/items/weapons/weapon_Legendary_Greatsword_zMZ46F9VR7zdTxb9.json b/src/packs/items/weapons/weapon_Legendary_Greatsword_zMZ46F9VR7zdTxb9.json index 840e7ec7..fb7a2ed3 100644 --- a/src/packs/items/weapons/weapon_Legendary_Greatsword_zMZ46F9VR7zdTxb9.json +++ b/src/packs/items/weapons/weapon_Legendary_Greatsword_zMZ46F9VR7zdTxb9.json @@ -118,6 +118,16 @@ "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" } ], "_id": "oRCiXSElN5xufUfn", diff --git a/src/packs/items/weapons/weapon_Mage_Orb_XKBmBUEoGLdLcuqQ.json b/src/packs/items/weapons/weapon_Mage_Orb_XKBmBUEoGLdLcuqQ.json index 3b5983f5..8d3fd741 100644 --- a/src/packs/items/weapons/weapon_Mage_Orb_XKBmBUEoGLdLcuqQ.json +++ b/src/packs/items/weapons/weapon_Mage_Orb_XKBmBUEoGLdLcuqQ.json @@ -113,7 +113,18 @@ "name": "Powerful", "description": "On a successful attack, roll an additional damage die and discard the lowest result.", "img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp", - "changes": [], + "changes": [ + { + "key": "system.bonuses.damage.primaryWeapon.extraDice", + "mode": 2, + "value": "1" + }, + { + "key": "system.rules.weapon.dropLowestDamageDice", + "mode": 5, + "value": "1" + } + ], "_id": "2J6vzNUel78JFypp", "type": "base", "system": {}, diff --git a/styles/less/global/chat.less b/styles/less/global/chat.less index dc671e44..69ee369a 100644 --- a/styles/less/global/chat.less +++ b/styles/less/global/chat.less @@ -2,18 +2,20 @@ @import '../utils/fonts.less'; @import '../utils/mixin.less'; -.daggerheart.chat-sidebar.theme-light, -#interface.theme-light { - .chat-log .chat-message { - background-image: url('../assets/parchments/dh-parchment-light.png'); +.theme-light { + .daggerheart.chat-sidebar .chat-log, + #chat-notifications .chat-log { + .chat-message { + background-image: url('../assets/parchments/dh-parchment-light.png'); - .message-header .message-header-metadata .message-metadata, - .message-header .message-header-main .message-sub-header-container { - color: @dark; - } + .message-header .message-header-metadata .message-metadata, + .message-header .message-header-main .message-sub-header-container { + color: @dark; + } - .message-header .message-header-main .message-sub-header-container h4 { - color: @dark-blue; + .message-header .message-header-main .message-sub-header-container h4 { + color: @dark-blue; + } } } } diff --git a/styles/less/ui/chat/ability-use.less b/styles/less/ui/chat/ability-use.less index b590911d..88302d0d 100644 --- a/styles/less/ui/chat/ability-use.less +++ b/styles/less/ui/chat/ability-use.less @@ -2,7 +2,6 @@ @import '../../utils/fonts.less'; @import '../../utils/spacing.less'; -.daggerheart.chat-sidebar.theme-light, #interface.theme-light { .daggerheart.chat.domain-card { .domain-card-move .domain-card-header { diff --git a/styles/less/ui/chat/action.less b/styles/less/ui/chat/action.less index a3d2f3cc..8d309cfe 100644 --- a/styles/less/ui/chat/action.less +++ b/styles/less/ui/chat/action.less @@ -2,7 +2,6 @@ @import '../../utils/fonts.less'; @import '../../utils/spacing.less'; -.daggerheart.chat-sidebar.theme-light, #interface.theme-light { .daggerheart.chat.action { .action-move .action-section { diff --git a/styles/less/ui/chat/chat.less b/styles/less/ui/chat/chat.less index 57e9fd57..6f0e5e85 100644 --- a/styles/less/ui/chat/chat.less +++ b/styles/less/ui/chat/chat.less @@ -2,9 +2,9 @@ @import '../../utils/fonts.less'; @import '../../utils/spacing.less'; -.daggerheart.chat-sidebar.theme-light, #interface.theme-light { - .chat-log { + .daggerheart.chat-sidebar .chat-log, + #chat-notifications .chat-log { --text-color: @dark-blue; --bg-color: @dark-blue-40; diff --git a/styles/less/ui/chat/damage-summary.less b/styles/less/ui/chat/damage-summary.less index b47cd41f..3fea45e5 100644 --- a/styles/less/ui/chat/damage-summary.less +++ b/styles/less/ui/chat/damage-summary.less @@ -1,6 +1,5 @@ @import '../../utils/colors.less'; -.daggerheart.chat-sidebar.theme-light, #interface.theme-light { .daggerheart.chat.damage-summary .token-target-container { &:hover { diff --git a/styles/less/ui/chat/downtime.less b/styles/less/ui/chat/downtime.less index ca0cd090..2875ea10 100644 --- a/styles/less/ui/chat/downtime.less +++ b/styles/less/ui/chat/downtime.less @@ -2,7 +2,6 @@ @import '../../utils/fonts.less'; @import '../../utils/spacing.less'; -.daggerheart.chat-sidebar.theme-light, #interface.theme-light { .daggerheart.chat.downtime { .downtime-moves-list .downtime-move { diff --git a/styles/less/ui/chat/effect-summary.less b/styles/less/ui/chat/effect-summary.less index 87d53eeb..3d72571d 100644 --- a/styles/less/ui/chat/effect-summary.less +++ b/styles/less/ui/chat/effect-summary.less @@ -1,6 +1,5 @@ @import '../../utils/colors.less'; -.daggerheart.chat-sidebar.theme-light, #interface.theme-light { .daggerheart.chat.effect-summary { .effect-header, diff --git a/styles/less/ui/chat/group-roll.less b/styles/less/ui/chat/group-roll.less index 9ed87220..02b8e312 100644 --- a/styles/less/ui/chat/group-roll.less +++ b/styles/less/ui/chat/group-roll.less @@ -125,9 +125,9 @@ .group-roll-trait { padding: 2px 8px; - border: 1px solid light-dark(@dark-blue, white); + border: 1px solid light-dark(white, white); border-radius: 6px; - color: light-dark(@dark-blue, white); + color: light-dark(white, white); background: light-dark(@beige-80, @beige-80); } } diff --git a/styles/less/ui/chat/sheet.less b/styles/less/ui/chat/sheet.less index b632db35..3d47a9b5 100644 --- a/styles/less/ui/chat/sheet.less +++ b/styles/less/ui/chat/sheet.less @@ -1,7 +1,6 @@ @import '../../utils/colors.less'; @import '../../utils/fonts.less'; -.daggerheart.chat-sidebar.theme-light, #interface.theme-light { .chat-message:not(.duality) .message-content { color: @dark; diff --git a/styles/less/ui/sidebar/daggerheartMenu.less b/styles/less/ui/sidebar/daggerheartMenu.less index 677214d7..80eda9a1 100644 --- a/styles/less/ui/sidebar/daggerheartMenu.less +++ b/styles/less/ui/sidebar/daggerheartMenu.less @@ -5,8 +5,6 @@ display: flex; flex-direction: column; gap: 8px; - overflow: auto; - height: 100%; } h2 { diff --git a/system.json b/system.json index 50a9c83b..43f82f06 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "id": "daggerheart", "title": "Daggerheart", "description": "An unofficial implementation of the Daggerheart system", - "version": "1.5.2", + "version": "1.5.0", "compatibility": { "minimum": "13.346", "verified": "13.351", diff --git a/templates/settings/automation-settings/general.hbs b/templates/settings/automation-settings/general.hbs index bd91b2b1..d49ef9b8 100644 --- a/templates/settings/automation-settings/general.hbs +++ b/templates/settings/automation-settings/general.hbs @@ -18,6 +18,7 @@ {{formGroup settingFields.schema.fields.hordeDamage value=settingFields._source.hordeDamage localize=true}} {{formGroup settingFields.schema.fields.effects.fields.rangeDependent value=settingFields._source.effects.rangeDependent localize=true}} {{formGroup settingFields.schema.fields.levelupAuto value=settingFields._source.levelupAuto localize=true}} + {{formGroup settingFields.schema.fields.playerCanEditSheet value=settingFields._source.playerCanEditSheet localize=true}} {{formGroup settingFields.schema.fields.damageReductionRulesDefault value=settingFields._source.damageReductionRulesDefault localize=true}} {{formGroup settingFields.schema.fields.resourceScrollTexts value=settingFields._source.resourceScrollTexts localize=true}} diff --git a/templates/sheets/actors/character/header.hbs b/templates/sheets/actors/character/header.hbs index 87319dbb..1459e10b 100644 --- a/templates/sheets/actors/character/header.hbs +++ b/templates/sheets/actors/character/header.hbs @@ -123,7 +123,9 @@ {{/each}} - {{#> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }} - + {{#> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' showSettings=showSettings }} + {{#if ../showSettings}} + + {{/if}} {{/'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} \ No newline at end of file