}
* @private
*/
-function _remapEffects(effects) {
+function _remapEffects(effects, removeFrightenedEffect = false) {
let m = new Map()
// Active Auras module support
effects = game.modules.get('ActiveAuras')?.active ? effects.filter(e => !e.flags?.ActiveAuras || foundry.utils.getProperty(e, `flags.ActiveAuras.isAura`) === undefined) : effects
+ effects = removeFrightenedEffect ? effects.filter(e => e.name != game.i18n.localize('DL.frightened')) : effects
effects.forEach(effect =>
effect.changes.forEach(change => {
const obj = {
@@ -90,13 +91,16 @@ const changeListToMsgDefender = (m, keys, title, anonymize, f = plusify) => {
* @returns {*}
*/
export function buildAttackEffectsMessage(attacker, defender, item, attackAttribute, defenseAttribute, inputBoons, plus20, inputModifier) {
+ const applyBane = attacker.getTargetAttackBane(defender)
+ const baneValue = applyBane <= 1 ? applyBane : 3
+ // We remove Frightened Effect from ChatCard, because source is already frightened from target and later we add the correct effect name
+ const removeFrightenedEffect = baneValue === 3 && (defender?.system.frightening || defender?.system.horrifying) ? true : false
const attackerEffects = Array.from(attacker.allApplicableEffects()).filter(effect => !effect.disabled)
- let m = _remapEffects(attackerEffects)
+ let m = _remapEffects(attackerEffects, removeFrightenedEffect)
const defenderEffects = defender ? Array.from(defender.allApplicableEffects()).filter(effect => !effect.disabled) : []
let d = _remapEffects(defenderEffects)
let defenderBoonsArray = [`system.bonuses.defense.boons.${defenseAttribute}`,"system.bonuses.defense.boons.all"]
- const applyHorrifyingBane = attacker.getTargetAttackBane(defender)
let otherBoons = ''
let modifiers = ''
let inputBoonsMsg = inputBoons ? _toMsg(game.i18n.localize('DL.DialogInput'), plusify(inputBoons)) : ''
@@ -154,27 +158,45 @@ export function buildAttackEffectsMessage(attacker, defender, item, attackAttrib
let attributeText = 'DL.Attribute' + capitalize(attackAttribute)
let attributeModMsg = attributeMod ? _toMsg(`${game.i18n.localize(attributeText)}`, plusify(attributeMod)) : ''
- let revealHorrifyingBane = game.settings.get('demonlord', 'optionalRuleRevealHorrifyingBane')
- let creatureType
-
- if (!game.settings.get('demonlord', 'optionalRuleTraitMode2025'))
- creatureType = game.i18n.localize('DL.CreatureHorrifying')
- else
- creatureType =
- defender?.system.frightening && defender?.system.horrifying
- ? game.i18n.localize('DL.CreatureHorrifying')
- : defender?.system.frightening
- ? game.i18n.localize('DL.CreatureFrightening')
- : defender?.system.horrifying
- ? game.i18n.localize('DL.CreatureHorrifying')
- : ''
-
- const horrifyingText = applyHorrifyingBane > 1 ? game.i18n.localize('DL.CanSeeSoureOfAffliction') : `${game.i18n.localize(creatureType)} [${game.i18n.localize('DL.ActionTarget')}]`
- let horrifyingHTMLPlayer = revealHorrifyingBane
- ? '' + _toMsg(horrifyingText, applyHorrifyingBane*-1) + '
'
- : '' + _toMsg(`${game.i18n.localize('DL.OtherUnknown')} [${game.i18n.localize('DL.ActionTarget')}]`, applyHorrifyingBane*-1) + '
'
+ let creatureType = ''
+ const isFrightening = defender?.system.frightening
+ const isHorrifying = defender?.system.horrifying
+ const isTraitMode2025 = game.settings.get('demonlord', 'optionalRuleTraitMode2025')
+
+ if ((isFrightening || isHorrifying) && isTraitMode2025) {
+ creatureType = isHorrifying ? game.i18n.localize('DL.CreatureHorrifying') : game.i18n.localize('DL.CreatureFrightening')
+ } else if (isFrightening && isHorrifying) {
+ creatureType = game.i18n.localize('DL.CreatureHorrifying') + '/' + game.i18n.localize('DL.CreatureFrightening')
+ } else if (isHorrifying) {
+ creatureType = game.i18n.localize('DL.CreatureHorrifying')
+ }
- let horrifyingHTMLGM = '' + _toMsg(horrifyingText, applyHorrifyingBane*-1) + '
'
+ const revealHorrifyingBane = game.settings.get('demonlord', 'optionalRuleRevealHorrifyingBane')
+ // We add the correct effect and its bane(s) to the chatcard.
+ const horrifyingTextGM =
+ baneValue > 1
+ ? game.i18n.localize('DL.CanSeeSoureOfAffliction')
+ : `${game.i18n.localize(creatureType)} [${game.i18n.localize('DL.ActionTarget')}]`
+ let horrifyingHTMLGM
+ if (game.settings.get('demonlord', 'optionalRuleTraitMode2025'))
+ horrifyingHTMLGM =
+ baneValue > 1
+ ? _toMsg(horrifyingTextGM, baneValue * -1) +
+ _toMsg(`${game.i18n.localize(creatureType)} [${game.i18n.localize('DL.ActionTarget')}]`, -1)
+ : _toMsg(horrifyingTextGM, baneValue * -1)
+ else if (creatureType !== game.i18n.localize('DL.CreatureFrightening'))
+ horrifyingHTMLGM =
+ baneValue > 1
+ ? _toMsg(horrifyingTextGM, baneValue * -1) +
+ _toMsg(`${game.i18n.localize(creatureType)} [${game.i18n.localize('DL.ActionTarget')}]`, -1)
+ : _toMsg(horrifyingTextGM, baneValue * -1)
+ else horrifyingHTMLGM = _toMsg(horrifyingTextGM, baneValue * -1)
+
+ horrifyingHTMLGM = '' + horrifyingHTMLGM + '
'
+ const creatureTypeUnknown = game.i18n.localize('DL.OtherUnknown')
+ const horrifyingHTMLPlayer = revealHorrifyingBane
+ ? '' + _toMsg(horrifyingTextGM, baneValue * -1) + '
'
+ : '' + _toMsg(horrifyingTextGM, baneValue * -1).replace(creatureType, creatureTypeUnknown) + '
'
let gmOnlyResult = changeListToMsgDefender(d, defenderBoonsArray, '', false)
let playerOnlyResult = changeListToMsgDefender(d, defenderBoonsArray, '', true)
@@ -185,8 +207,8 @@ export function buildAttackEffectsMessage(attacker, defender, item, attackAttrib
(itemAttributePenalty ? _toMsg(itemAttributeRequirement, plusify(itemAttributePenalty)) : '') +
changeListToMsg(m, [`system.bonuses.attack.boons.${attackAttribute}`, "system.bonuses.attack.boons.all"], '') +
otherBoons +
- (applyHorrifyingBane ? horrifyingHTMLPlayer : '') +
- (applyHorrifyingBane ? horrifyingHTMLGM : '') +
+ (applyBane ? horrifyingHTMLPlayer : '') +
+ (applyBane ? horrifyingHTMLGM : '') +
(playerOnlyMsg ? playerOnlyMsg : '') +
(gmOnlyMsg ? gmOnlyMsg : '')
boonsMsg = boonsMsg+inputBoonsMsg ? ` ${game.i18n.localize('DL.TalentAttackBoonsBanes')}
` + boonsMsg+inputBoonsMsg : ''
diff --git a/src/module/chat/roll-messages.js b/src/module/chat/roll-messages.js
index 6cbd0c63..acfd9d60 100644
--- a/src/module/chat/roll-messages.js
+++ b/src/module/chat/roll-messages.js
@@ -610,6 +610,7 @@ export async function postCustomTextToChat(actor, roll, options, attribute = {})
break
}
+ data['resultBoxClass'] = roll?.total ? roll.total >= targetNumber ? 'SUCCESS' : 'FAILURE' : ''
data['actorInfo'] = buildActorInfo(actor)
const rollMode = game.settings.get('core', 'rollMode')
const chatData = getChatBaseData(actor, rollMode)
diff --git a/src/module/combat/combat-tracker.js b/src/module/combat/combat-tracker.js
index 06a0957b..158b1307 100644
--- a/src/module/combat/combat-tracker.js
+++ b/src/module/combat/combat-tracker.js
@@ -238,6 +238,14 @@ calculateEncounterDifficulty(combatants) {
}
}
+ const trackerHeader = html.querySelector(".combat-tracker-header")
+ if (this.initiativeMethod === 's') {
+ if (game.combat?.turn === null)
+ trackerHeader.innerHTML = trackerHeader.innerHTML + `${game.i18n.localize('DL.TurnChooseTurn')}
`
+ else
+ trackerHeader.innerHTML = trackerHeader.innerHTML + `
`
+ }
+
html.querySelectorAll('.combatant')?.forEach(el => {
// For each combatant in the tracker, change the initiative selector
const combId = el.getAttribute('data-combatant-id')
@@ -246,6 +254,8 @@ calculateEncounterDifficulty(combatants) {
const multipleCombatants = game.combat.getCombatantsByToken(combatant.token)
+ const title = (game.user.isGM || combatant.actor.isOwner) && game.combat?.turn === null ? i18n('DL.TurnChangeTurn') : ''
+ const style = (game.user.isGM || combatant.actor.isOwner) && game.combat?.turn === null ? 'font-weight: bold; cursor: pointer;' : 'font-weight: normal; cursor: auto; opacity: 0.5;'
if (combatant.actor?.system.fastAndSlowTurn && multipleCombatants.length == 2) {
// The combatant has a double initiative, so we display "Fast" and "Slow"
@@ -261,7 +271,7 @@ calculateEncounterDifficulty(combatants) {
// Change initiative by clicking on the name
if (this.initiativeMethod === 's') el.getElementsByClassName('token-initiative')[0].innerHTML =
- `${init}`
+ `${init}`
}
if (this.initiativeMethod === 'h' && game.user.isGM)
@@ -346,8 +356,7 @@ calculateEncounterDifficulty(combatants) {
const combId = li.dataset.combatantId
const combatant = combatants.get(combId)
if (!combatant) return
-
- if (game.user.isGM || combatant.actor.isOwner) {
+ if (game.user.isGM || (combatant.actor.isOwner && game.combat?.turn === null)) {
await combatant.actor.update({'system.fastturn': !combatant.actor.system.fastturn})
const initChatMessage = await createInitChatMessage(combatant, {})
if (initChatMessage) ChatMessage.create(initChatMessage)
diff --git a/src/module/combat/combat.js b/src/module/combat/combat.js
index c9a2147b..46c4c575 100644
--- a/src/module/combat/combat.js
+++ b/src/module/combat/combat.js
@@ -256,10 +256,26 @@ async rollInitiativeGroup(ids, { formula = null, updateTurn = true, messageOptio
})
}
+ async allowTurnOrderChangeInTurns(_updated) {
+ if (game.settings.get('demonlord', 'optionalRuleInitiativeMode') !== 's') return
+ if (game.combat.getFlag('demonlord', 'allowTurnOrderChange') == undefined && _updated.current.turn === 0)
+ {
+ await game.combat.update({turn : null})
+ game.combat.setFlag('demonlord', 'allowTurnOrderChange', true)
+ } else if (_updated.current.turn > 0) game.combat.unsetFlag('demonlord', 'allowTurnOrderChange')
+ }
+
+ async allowTurnOrderChangeInRounds() {
+ if (game.settings.get('demonlord', 'optionalRuleInitiativeMode') !== 's') return
+ await game.combat.update({turn : null})
+ game.combat.setFlag('demonlord', 'allowTurnOrderChange', true)
+ }
+
/** @override */
async nextTurn() {
const _updatedTurn = await super.nextTurn()
await this._handleTurnEffects()
+ await this.allowTurnOrderChangeInTurns(_updatedTurn)
return _updatedTurn
}
@@ -267,6 +283,7 @@ async rollInitiativeGroup(ids, { formula = null, updateTurn = true, messageOptio
async previousTurn() {
const _updatedTurn = await super.previousTurn()
await this._handleTurnEffects()
+ await this.allowTurnOrderChangeInTurns(_updatedTurn)
return _updatedTurn
}
@@ -282,6 +299,7 @@ async rollInitiativeGroup(ids, { formula = null, updateTurn = true, messageOptio
}
const _updatedRound = await super.nextRound()
await this._handleTurnEffects()
+ await this.allowTurnOrderChangeInRounds()
return _updatedRound
}
diff --git a/src/module/config.js b/src/module/config.js
index 9a7df087..2d8d383c 100644
--- a/src/module/config.js
+++ b/src/module/config.js
@@ -125,3 +125,5 @@ DL.defaultItemIcons = {
creaturerole: 'icons/equipment/back/cape-layered-blue-accent.webp',
relic: 'icons/commodities/treasure/sceptre-jeweled-gold.webp'
}
+
+DL.difficultyScale = [1,5,10,25,50,100,250,500,750,1000,1500]
\ No newline at end of file
diff --git a/src/module/dialog/roll-dialog.js b/src/module/dialog/roll-dialog.js
index 36f72675..abf7e2a4 100644
--- a/src/module/dialog/roll-dialog.js
+++ b/src/module/dialog/roll-dialog.js
@@ -37,10 +37,10 @@ function prepareReminderHTML(text)
if (game.settings.get('demonlord', 'launchDialogReminder')) {
if (targets.length === 1 && (targets[0]?.actor.system.horrifying || targets[0]?.actor.system.frightening)) {
if (actor.isFrightenedFrom(targets[0]?.actor)) content += ``
- else if (actor.isImmuneToTarget(targets[0]?.actor)) {
- if (!game.settings.get('demonlord', 'optionalRuleTraitMode2025')) content += prepareReminderHTML(game.i18n.localize('DL.YouCannotBeAffectedUntilYouCompleteARest'))
- else {
- const immuneArray = actor.appliedEffects.filter(x => x.name === game.i18n.format('DL.ImmuneToTarget', {
+ else if (actor.isFearRollCompleted(targets[0]?.actor)) {
+ if (game.settings.get('demonlord', 'optionalRuleTraitMode2025'))
+ {
+ const immuneArray = actor.appliedEffects.filter(x => x.name === game.i18n.format('DL.FearRollAgainst', {
creature: targets[0].actor.name
}))
let effect
@@ -49,12 +49,12 @@ if (game.settings.get('demonlord', 'launchDialogReminder')) {
}
if (game.combat) {
const remainingRounds = calcEffectRemainingRounds(effect, game.combat.round)
- const immuneText = (remainingRounds === 1) ? game.i18n.localize('DL.ImmunityLastsUntilTheEndOfNextRound') : (remainingRounds === 0) ? game.i18n.localize('DL.ImmunityLastsUntilTheEndOfTheRound') : game.i18n.format('DL.ImmunityLastsRounds', {
+ const immuneText = (remainingRounds === 1) ? game.i18n.localize('DL.FearRollLastsUntilTheEndOfNextRound') : (remainingRounds === 0) ? game.i18n.localize('DL.FearRollLastsUntilTheEndOfTheRound') : game.i18n.format('DL.FearRollLastsRounds', {
rounds: remainingRounds
})
content += prepareReminderHTML(immuneText)
} else {
- content += prepareReminderHTML(game.i18n.format('DL.ImmunityLastsSeconds', {
+ content += prepareReminderHTML(game.i18n.format('DL.FearRollLastsSeconds', {
seconds: calcEffectRemainingSeconds(effect, game.time.worldTime)
}))
}
@@ -62,7 +62,7 @@ if (game.settings.get('demonlord', 'launchDialogReminder')) {
}
const ignoreLevelDependentBane = (game.settings.get('demonlord', 'optionalRuleLevelDependentBane') && ((actor.system?.level >= 3 && actor.system?.level <= 6 && targets[0]?.actor.system?.difficulty <= 25) || (actor.system?.level >= 7 && targets[0]?.actor.system?.difficulty <= 50))) ? false : true
- if (!actor.isFrightenedFrom(targets[0]?.actor) && !actor.isImmuneToTarget(targets[0]?.actor) && !actor.isImmuneToAffliction('frightened') && ignoreLevelDependentBane) {
+ if (!actor.isFrightenedFrom(targets[0]?.actor) && !actor.isFearRollCompleted(targets[0]?.actor) && !actor.isImmuneToAffliction('frightened') && ignoreLevelDependentBane) {
if (game.settings.get('demonlord', 'optionalRuleTraitMode2025') && targets[0]?.actor.system.horrifying)
content += prepareReminderHTML(game.i18n.localize('DL.YouHaventMadeWillChallengeRollAgainstTarget'))
else if (
diff --git a/src/module/item-macro/ItemMacro.js b/src/module/item-macro/ItemMacro.js
new file mode 100644
index 00000000..4e635f93
--- /dev/null
+++ b/src/module/item-macro/ItemMacro.js
@@ -0,0 +1,66 @@
+/**
+ * Modified version of the awesome https://github.com/Foundry-Workshop/Item-Macro
+ * Big thanks to Forien & Kekilla0
+ */
+
+export class DLItemMacro extends Macro {
+ constructor(data, context) {
+ super(data, context)
+
+ this.item = context.item
+ }
+
+ #executeChat(speaker) {
+ return ui.chat.processMessage(this.command, { speaker }).catch(err => {
+ Hooks.onError('Macro#_executeChat', err, {
+ msg: 'There was an error in your chat message syntax.',
+ log: 'error',
+ notify: 'error',
+ command: this.command,
+ })
+ })
+ }
+
+ async #executeScript(args = null) {
+ const item = this.item
+ const speaker = ChatMessage.getSpeaker({ actor: item.actor })
+ const actor = item.actor ?? game.actors.get(speaker.actor)
+
+ /* MMH@TODO Check the types returned by linked and unlinked */
+ const token = canvas.tokens?.get(speaker.token)
+ const character = game.user.character
+
+ //build script execution
+ const scriptFunction = Object.getPrototypeOf(async function () {}).constructor
+ const body = this.command
+
+ if (game.user.isGM) {
+ const fn = new scriptFunction('item', 'speaker', 'actor', 'token', 'character', 'args', body)
+
+ //attempt script execution
+ try {
+ return await fn.bind(this)(item, speaker, actor, token, character, args)
+ } catch (err) {
+ ui.notifications.error('DLItemMacro Execution failed')
+ }
+ } else {
+ game.socket.emit('system.demonlord', {
+ request: 'runMacro',
+ itemuuid : item.uuid,
+ speaker : speaker,
+ actoruuid: actor.uuid,
+ characteruuid: character.uuid,
+ args: args
+ })
+ }
+ }
+
+ execute(scope = {}, args = null) {
+ switch (this.type) {
+ case 'chat':
+ return this.#executeChat(scope.speaker)
+ case 'script':
+ return this.#executeScript(args)
+ }
+ }
+}
diff --git a/src/module/item-macro/ItemMacroConfig.js b/src/module/item-macro/ItemMacroConfig.js
new file mode 100644
index 00000000..d7ea3d50
--- /dev/null
+++ b/src/module/item-macro/ItemMacroConfig.js
@@ -0,0 +1,54 @@
+/**
+ * Modified version of the awesome https://github.com/Foundry-Workshop/Item-Macro
+ * Big thanks to Forien & Kekilla0
+ */
+import { DLItemMacro } from "./ItemMacro"
+/**
+ * @extends {MacroConfig}
+ */
+export class DLItemMacroConfig extends foundry.applications.sheets.MacroConfig {
+ /** @override */
+ static DEFAULT_OPTIONS = {
+ actions: {
+ execute: DLItemMacroConfig._onExecute
+ },
+ }
+
+ /** @override */
+ // eslint-disable-next-line no-shadow
+ constructor({document, item}, ...args) {
+ super({document}, ...args)
+ this.item = item
+ }
+
+ static async openConfig(item) {
+ const macro = new DLItemMacroConfig({document: item.getDLMacro(), item})
+ macro.render(true)
+ }
+
+ /** @override */
+ async _processSubmitData(event, form, submitData) {
+ await this.updateMacro(submitData)
+ }
+
+ static async _onExecute(event) {
+ await this.submit()
+ this.item.executeDLMacro(event)
+ }
+
+ async updateMacro({command, type}) {
+ const item = this.item
+
+ const newMacro = new DLItemMacro({
+ name: item.name,
+ type,
+ scope: "global",
+ command,
+ author: game.user.id,
+ }, {item})
+
+ await item.setDLMacro(newMacro)
+
+ this.object = newMacro
+ }
+}
\ No newline at end of file
diff --git a/src/module/item/item.js b/src/module/item/item.js
index fe5f9f34..45bec2fa 100644
--- a/src/module/item/item.js
+++ b/src/module/item/item.js
@@ -2,6 +2,7 @@ import {deleteActorNestedItems, PathLevel} from './nested-objects'
import {DemonlordActor} from '../actor/actor'
import { DLEndOfRound } from '../dialog/endofround'
import { getChatBaseData } from '../chat/base-messages'
+import { DLItemMacro } from '../item-macro/ItemMacro'
export class DemonlordItem extends Item {
/** @override */
@@ -215,4 +216,29 @@ export class DemonlordItem extends Item {
return ancestry
}
+
+ getDLMacro() {
+ const hasMacro = this.hasDLMacro()
+ const flag = this.getFlag('demonlord', 'macro')
+ if (hasMacro) return new DLItemMacro(flag, { item: this })
+ return new DLItemMacro({ img: this.img, name: this.name, scope: 'global', type: 'script' }, { item: this })
+ }
+
+ hasDLMacro() {
+ const flag = this.getFlag('demonlord', 'macro')
+ return !!flag?.command
+ }
+
+ async setDLMacro(macro) {
+ if (macro instanceof DLItemMacro) {
+ const data = macro.toObject()
+ return await this.setFlag('demonlord', 'macro', data)
+ }
+ }
+
+ executeDLMacro(scope = {}, args = null) {
+ if (!this.hasDLMacro()) return
+ return this.getDLMacro().execute(scope, args)
+ }
+
}
diff --git a/src/module/item/sheets/base-item-sheet.js b/src/module/item/sheets/base-item-sheet.js
index 230f1e5b..bfe113f2 100644
--- a/src/module/item/sheets/base-item-sheet.js
+++ b/src/module/item/sheets/base-item-sheet.js
@@ -18,6 +18,7 @@ import {
DamageType
} from '../nested-objects';
import { DLStatEditor } from '../../dialog/stat-editor'
+import { DLItemMacroConfig } from '../../item-macro/ItemMacroConfig'
const { TextEditor } = foundry.applications.ux //eslint-disable-line no-shadow
@@ -722,6 +723,23 @@ export default class DLBaseItemSheet extends HandlebarsApplicationMixin(ItemShee
// Autoselect text in inputs when focused
e.querySelectorAll('input')?.forEach(el => el.addEventListener('focus', ev => ev.currentTarget.select()))
+
+ if (game.user.isGM && game.settings.get('demonlord', 'enableItemMacro')) {
+ const hasMacro = this.document.hasDLMacro()
+ const macroLink = {
+ style: hasMacro ? 'color: darkorange;text-shadow: 0 0 8px darkorange; cursor: pointer;' : 'color: var(--button-text-color); text-shadow: 0 0 8px var(--button-text-color); cursor: pointer;',
+ icon: "fa-solid fa-code",
+ tooltip: hasMacro ? game.i18n.localize("MACRO.Edit") : game.i18n.localize("SIDEBAR.ACTIONS.CREATE.Macro")
+ }
+
+ let macroLinkIndicator = ``
+ e.querySelector("macrolink")?.remove()
+ e.querySelector(".header-control")?.insertAdjacentHTML("beforebegin", macroLinkIndicator)
+ // eslint-disable-next-line no-unused-vars
+ e.querySelector("macrolink")?.addEventListener('click', async ev => {
+ DLItemMacroConfig.openConfig(this.document)
+ })
+ }
}
/* -------------------------------------------- */
diff --git a/src/module/settings.js b/src/module/settings.js
index 9dd94fbe..85274c44 100644
--- a/src/module/settings.js
+++ b/src/module/settings.js
@@ -979,4 +979,12 @@ export const registerSettings = function () {
type: Boolean,
config: true,
})
+ game.settings.register('demonlord', 'enableItemMacro', {
+ name: game.i18n.localize('DL.SettingEnableItemMacro'),
+ hint: game.i18n.localize('DL.SettingEnableItemMacroHint'),
+ default: false,
+ scope: 'world',
+ type: Boolean,
+ config: true,
+ })
}
diff --git a/src/module/utils/handlebars-helpers.js b/src/module/utils/handlebars-helpers.js
index 048454d8..75d1d93a 100644
--- a/src/module/utils/handlebars-helpers.js
+++ b/src/module/utils/handlebars-helpers.js
@@ -120,6 +120,21 @@ export function registerHandlebarsHelpers() {
else return game.i18n.localize(tooltip)
})
+ Handlebars.registerHelper('dLocalizeWithSuffix', function (groupName, str) {
+ let result
+ switch (groupName) {
+ case 'WeaponHands':
+ if (!str.length) result = ''
+ else result = i18n(`DL.WeaponHands${str.capitalize()}`)
+ break
+ case 'SpellType':
+ if (!str.length) result = '―'
+ else result = i18n(`DL.SpellType${str.capitalize()}`)
+ break
+ }
+ return result
+ })
+
Handlebars.registerHelper('enrichHTMLUnrolled', async (x) => await TextEditor.enrichHTML(x, { unrolled: true }))
Handlebars.registerHelper('lookupAttributeModifier', (attributeName, actorData) =>
actorData?.system?.attributes[attributeName.toLowerCase()]?.modifier
diff --git a/src/module/utils/socket.js b/src/module/utils/socket.js
index 765b9ecb..c37a0c52 100644
--- a/src/module/utils/socket.js
+++ b/src/module/utils/socket.js
@@ -1,22 +1,53 @@
/* global fromUuidSync */
+import { DLItemMacro } from '../item-macro/ItemMacro'
export function activateSocketListener() {
game.socket.on('system.demonlord', async (...[message]) => {
- let actor = fromUuidSync(message.tokenuuid).actor
// Execute it once if multiple GMs are connected.
if (game.users.activeGM?.isSelf) {
switch (message.request) {
case 'createEffect':
- await actor.createEmbeddedDocuments('ActiveEffect', [message.effectData])
+ {
+ let actor = fromUuidSync(message.tokenuuid).actor
+ await actor.createEmbeddedDocuments('ActiveEffect', [message.effectData])
+ }
break
case 'deleteEffect':
- await actor.deleteEmbeddedDocuments('ActiveEffect', message.effectData)
+ {
+ let actor = fromUuidSync(message.tokenuuid).actor
+ await actor.deleteEmbeddedDocuments('ActiveEffect', message.effectData)
+ }
break
case 'increaseDamage':
- await actor.increaseDamage(message.increment)
- break
- default:
+ {
+ let actor = fromUuidSync(message.tokenuuid).actor
+ await actor.increaseDamage(message.increment)
+ }
break
+ case 'runMacro': {
+ const item = fromUuidSync(message.itemuuid)
+ const actor = fromUuidSync(message.actoruuid)
+ const character = fromUuidSync(message.characteruuid)
+ // eslint-disable-next-line no-unused-vars
+ const token = canvas.tokens?.get(message.speaker.token)
+ const body = item.getDLMacro()?.command
+ const scriptFunction = Object.getPrototypeOf(async function () {}).constructor
+ const fn = new scriptFunction('item', 'speaker', 'actor', 'token', 'character', 'args', body)
+ //attempt script execution
+ try {
+ return await fn.bind(DLItemMacro)(
+ item,
+ message.speaker,
+ actor,
+ message.token,
+ character,
+ message.args,
+ body,
+ )
+ } catch (err) {
+ ui.notifications.error('DLItemMacro Execution failed')
+ }
+ }
}
}
})
-}
\ No newline at end of file
+}
diff --git a/src/styles/components/_chat.scss b/src/styles/components/_chat.scss
index 8ff5755d..e034e825 100644
--- a/src/styles/components/_chat.scss
+++ b/src/styles/components/_chat.scss
@@ -171,7 +171,7 @@
.tooltiptext {
visibility: hidden;
width: 260px;
- background-color: rgba(0, 0, 0, 0.9);
+ background-color: rgba(0, 0, 0, 0.85);
color: #fff;
text-align: left;
border: 1px solid rgba(0, 0, 0, 0.5);
@@ -180,7 +180,7 @@
position: absolute;
z-index: 1;
left: 7px;
- top: 24px;
+ top: -7px;
}
}
@@ -243,7 +243,7 @@
.tooltiptext {
display: block;
width: 260px;
- background-color: rgba(0, 0, 0, 0.5);
+ background-color: rgba(0, 0, 0, 0.85);
color: #fff;
text-align: left;
border: 1px solid rgba(0, 0, 0, 0.5);
@@ -252,7 +252,7 @@
position: relative;
z-index: 1;
left: -30px;
- top: 10px;
+ top: -30px;
}
}
diff --git a/src/styles/v2/_actors.scss b/src/styles/v2/_actors.scss
index 7ed6dd22..58a609fb 100644
--- a/src/styles/v2/_actors.scss
+++ b/src/styles/v2/_actors.scss
@@ -154,6 +154,9 @@ aside {
position: absolute;
top: 40px;
left: 0px;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ width: 80px;
}
}
@@ -164,6 +167,9 @@ aside {
position: absolute;
top: 40px;
right: 0px;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ width: 80px;
}
}
diff --git a/src/styles/v2/_sheets.scss b/src/styles/v2/_sheets.scss
index d7e111d2..29f89c80 100644
--- a/src/styles/v2/_sheets.scss
+++ b/src/styles/v2/_sheets.scss
@@ -951,6 +951,13 @@ span.text-vs {
&.off {
opacity: 1;
}
+ &.on_disabled {
+ opacity: 0;
+ }
+
+ &.off_disabled {
+ opacity: 0.5;
+ }
}
.toggleInput:checked ~ .toggleText {
@@ -961,5 +968,12 @@ span.text-vs {
&.off {
opacity: 0;
}
+ &.on_disabled {
+ opacity: 0.5;
+ }
+
+ &.off_disabled {
+ opacity: 0;
+ }
}
}
diff --git a/src/templates/actor/parts/character-sheet-sidemenu.hbs b/src/templates/actor/parts/character-sheet-sidemenu.hbs
index cab9e270..23a299e6 100644
--- a/src/templates/actor/parts/character-sheet-sidemenu.hbs
+++ b/src/templates/actor/parts/character-sheet-sidemenu.hbs
@@ -91,7 +91,7 @@
{{ifThen (gte ownership 2) system.characteristics.insanity.max '?'}}
{{ifThen (gte ownership 2) system.characteristics.insanity.value '?'}}
{{#if (gte ownership 2)}}
-
+
{{/if}}
{{else}}
–
@@ -156,10 +156,15 @@
diff --git a/src/templates/actor/tabs/combat.hbs b/src/templates/actor/tabs/combat.hbs
index 41fe1d9f..4d5336d7 100644
--- a/src/templates/actor/tabs/combat.hbs
+++ b/src/templates/actor/tabs/combat.hbs
@@ -73,7 +73,7 @@
{{/if}}
{{#if system.hands}}
- {{localize "DL.WeaponHands"}} {{system.hands}}
+ {{localize "DL.WeaponHands"}} {{dLocalizeWithSuffix "WeaponHands" system.hands}}
{{/if}}
{{#if system.description}}
diff --git a/src/templates/actor/tabs/magic.hbs b/src/templates/actor/tabs/magic.hbs
index f25fb26b..926f801b 100644
--- a/src/templates/actor/tabs/magic.hbs
+++ b/src/templates/actor/tabs/magic.hbs
@@ -32,7 +32,7 @@
- {{defaultValue system.spelltype "―"}}
+ {{dLocalizeWithSuffix "SpellType" system.spelltype}}
{{system.rank}}
{{defaultValue (plusify system.action.boonsbanes) 0}}
@@ -60,7 +60,7 @@
{{spell.name}}
- {{spellbook.tradition}} {{system.spelltype}} {{system.rank}}
+ {{spellbook.tradition}} {{dLocalizeWithSuffix "SpellType" system.spelltype}} {{system.rank}}
diff --git a/src/templates/chat/text.hbs b/src/templates/chat/text.hbs
index 3bbf11f5..027907b8 100644
--- a/src/templates/chat/text.hbs
+++ b/src/templates/chat/text.hbs
@@ -14,7 +14,7 @@