diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs index 2a02ba01..f8d2697f 100644 --- a/module/applications/sheets/api/application-mixin.mjs +++ b/module/applications/sheets/api/application-mixin.mjs @@ -333,6 +333,20 @@ export default function DHApplicationMixin(Base) { const doc = getDocFromElementSync(target); return doc?.system?.attack?.damage.parts.length || doc?.damage?.parts.length; }, + callback: async (target, event) => { + const doc = await getDocFromElement(target), + action = doc?.system?.attack ?? doc; + return action && action.use(event, { byPassRoll: true }) + } + }); + + options.unshift({ + name: 'DAGGERHEART.APPLICATIONS.ContextMenu.useItem', + icon: 'fa-solid fa-burst', + condition: target => { + const doc = getDocFromElementSync(target); + return doc?.system?.attack?.damage.parts.length || doc?.damage?.parts.length; + }, callback: async (target, event) => { const doc = await getDocFromElement(target), action = doc?.system?.attack ?? doc; diff --git a/module/applications/ui/chatLog.mjs b/module/applications/ui/chatLog.mjs index fd9ab096..79d5e468 100644 --- a/module/applications/ui/chatLog.mjs +++ b/module/applications/ui/chatLog.mjs @@ -33,14 +33,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 +130,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), diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index 070864da..516419b9 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,9 @@ 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; + if(config.hasTarget) config.targetSelection = config.targets.length > 0; await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config); } } @@ -180,7 +179,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(), @@ -248,8 +246,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 +369,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/chat-message/adversaryRoll.mjs b/module/data/chat-message/adversaryRoll.mjs index fa6e48a6..5e1835c0 100644 --- a/module/data/chat-message/adversaryRoll.mjs +++ b/module/data/chat-message/adversaryRoll.mjs @@ -25,7 +25,6 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel { 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 }), @@ -63,24 +62,14 @@ 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; } set targetMode(mode) { this.targetSelection = mode; - this.updateTargets(); this.registerTargetHook(); - this.parent.update({ - system: { - targetSelection: this.targetSelection, - oldTargets: this.oldTargets - } - }); + this.updateTargets(); } get hitTargets() { @@ -88,29 +77,25 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel { } 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); + if(!ui.chat.collection.get(this.parent.id)) return; + let targets; + if(this.targetSelection) + targets = this.targets; + else + targets = Array.from(game.user.targets).map(t => game.system.api.fields.ActionFields.TargetField.formatTarget(t)); + + this.parent.setFlag(game.system.id, "targets", targets); + await this.parent.updateSource({ + system: { + targetSelection: this.targetSelection } - } + }); } registerTargetHook() { - if (this.targetSelection && this.targetHook !== null) { - Hooks.off('targetToken', this.targetHook); + if(!this.parent.isAuthor) return; + 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)); @@ -120,35 +105,35 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel { prepareDerivedData() { if (this.hasTarget) { this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0; - this.updateTargets(); - this.registerTargetHook(); - if (this.targetSelection === true) { - this.targetShort = this.targets.reduce( - (a, c) => { - if (c.hit) a.hit += 1; - else a.miss += 1; - return a; - }, - { hit: 0, miss: 0 } - ); + this.currentTargets = this.getTargetList(); + this. registerTargetHook(); + + if(this.targetSelection === true && this.hasRoll) { + this.targetShort = this.targets.reduce((a,c) => { + if(c.hit) a.hit += 1; + else a.miss += 1; + return a; + }, {hit: 0, miss: 0}) } if (this.hasSave) this.setPendingSaves(); } 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.targetSelection && 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() { 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..9300a02e 100644 --- a/module/data/fields/actionField.mjs +++ b/module/data/fields/actionField.mjs @@ -285,6 +285,7 @@ export function ActionMixin(Base) { } }; + ChatMessage.applyRollMode(msg, game.settings.get('core', 'rollMode')); cls.create(msg); } } diff --git a/module/dice/d20Roll.mjs b/module/dice/d20Roll.mjs index 45471532..d636fd27 100644 --- a/module/dice/d20Roll.mjs +++ b/module/dice/d20Roll.mjs @@ -139,17 +139,17 @@ 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 = config.targets.some(target => target.hit) + } 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..31458516 100644 --- a/module/dice/damageRoll.mjs +++ b/module/dice/damageRoll.mjs @@ -30,16 +30,16 @@ 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 }); } } diff --git a/module/dice/dhRoll.mjs b/module/dice/dhRoll.mjs index 1b490921..710a2728 100644 --- a/module/dice/dhRoll.mjs +++ b/module/dice/dhRoll.mjs @@ -2,7 +2,7 @@ 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; } @@ -15,6 +15,8 @@ export default class DHRoll extends Roll { static messageType = 'adversaryRoll'; + static CHAT_TEMPLATE = 'systems/daggerheart/templates/ui/chat/roll.hbs'; + static DefaultDialog = D20RollDialog; static async build(config = {}, message = {}) { @@ -92,9 +94,36 @@ export default class DHRoll extends Roll { system: config, rolls: [roll] }; + 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) diff --git a/module/dice/dualityRoll.mjs b/module/dice/dualityRoll.mjs index 35bae725..030b4df2 100644 --- a/module/dice/dualityRoll.mjs +++ b/module/dice/dualityRoll.mjs @@ -149,7 +149,7 @@ export default class DualityRoll extends D20Roll { } if (this.rallyFaces) this.terms.push( - new foundry.dice.terms.OperatorTerm({ operator: this.hasDisadvantage ? '-' : '+' }), + new foundry.dice.terms.OperatorTerm({ operator: '+' }), new foundry.dice.terms.Die({ faces: this.rallyFaces }) ); } diff --git a/module/documents/chatMessage.mjs b/module/documents/chatMessage.mjs index 302ba1d8..06a9f147 100644 --- a/module/documents/chatMessage.mjs +++ b/module/documents/chatMessage.mjs @@ -1,21 +1,31 @@ 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 - }); - const actor = game.actors.get(this.speaker.actor); - const actorData = actor ?? { + 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; + } + + 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 +39,9 @@ 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 }); - } - - 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,6 +49,16 @@ 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() { @@ -146,4 +139,30 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { if (action) action.consume(this.system, true); } } + + 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); + } + + onTargetSelection(event) { + event.stopPropagation(); + this.system.targetMode = Boolean(event.target.dataset.targetHit); + } } 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/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/ui/chat/chat.less b/styles/less/ui/chat/chat.less index 9afa32d3..6ffd00cf 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,19 @@ --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 +85,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 +123,6 @@ flex-direction: column; align-items: center; gap: 5px; - padding: 5px 0; .dice-tooltip { width: 100%; @@ -489,6 +161,7 @@ color: var(--text-color); font-weight: 700; font-family: 'Cinzel', sans-serif; + line-height: .75; .roll-result-value { font-size: var(--font-size-24); @@ -503,10 +176,6 @@ } } } - - .roll-difficulty { - margin-top: -5px; - } } } @@ -580,7 +249,7 @@ .button-target-selection { flex: 1; text-align: center; - padding: 5px 0; + margin: -5px 0; } .button-target-selection:hover, @@ -600,6 +269,11 @@ width: 100%; gap: 10px; align-items: center; + border-radius: 3px; + + &:hover { + background-color: rgba(255,255,255,.1); + } .target-img { border-radius: 50%; @@ -640,6 +314,7 @@ padding: 3px 5px; width: fit-content; margin: auto; + white-space: nowrap; } .roll-difficulty, @@ -706,6 +381,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/templates/dialogs/dice-roll/costSelection.hbs b/templates/dialogs/dice-roll/costSelection.hbs index 765fbaf9..84bc3399 100644 --- a/templates/dialogs/dice-roll/costSelection.hbs +++ b/templates/dialogs/dice-roll/costSelection.hbs @@ -5,25 +5,25 @@
  • - - + +
    - +
  • {{/if}} {{#each costs as | cost index |}}
  • - - + +
    {{#if (and scalable maxStep)}} {{/if}} - +
  • {{/each}} diff --git a/templates/ui/chat/chat-message.hbs b/templates/ui/chat/chat-message.hbs index 85cf03e2..94527f16 100644 --- a/templates/ui/chat/chat-message.hbs +++ b/templates/ui/chat/chat-message.hbs @@ -3,17 +3,19 @@
    - {{#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/roll-part.hbs b/templates/ui/chat/parts/roll-part.hbs index d4e46b1f..1d7f3d2b 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"}}
    @@ -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..51b9e79c 100644 --- a/templates/ui/chat/parts/target-part.hbs +++ b/templates/ui/chat/parts/target-part.hbs @@ -14,7 +14,7 @@
    - {{#if targets.length}} + {{#if (and parent.isAuthor targets.length)}}
    @@ -29,7 +29,7 @@
    -
    {{name}}
    +
    {{name}}
    {{#if (and ../targetSelection ../hasRoll)}}
    {{#if hit}} @@ -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