diff --git a/changelog.md b/changelog.md index 10cd62c..ba8923d 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,11 @@ # Changelog +## [1.1.5] 2021-06-26 +### Bugfix +- DND5e fixes for a variety of issues thanks to benbarbour +### Changed +- SW5e update thanks to jtljac + ## [1.1.4] 2021-06-22 ### Bugfix - Fix call for token id resulting in error messages, thanks to jessev14 diff --git a/scripts/actions/dnd5e/dnd5e-actions.js b/scripts/actions/dnd5e/dnd5e-actions.js index ff9754d..5a7daf7 100644 --- a/scripts/actions/dnd5e/dnd5e-actions.js +++ b/scripts/actions/dnd5e/dnd5e-actions.js @@ -195,7 +195,7 @@ export class ActionHandler5e extends ActionHandler { /** @private */ _buildSpellsCategory(token) { const actor = token.actor; - if (actor.data.type !== 'vehicle') return; + if (actor.data.type === 'vehicle') return; let validSpells = this._filterLongerActions(actor.data.items.filter(i => i.type === 'spell')); validSpells = this._filterExpendedItems(validSpells); @@ -418,7 +418,7 @@ export class ActionHandler5e extends ActionHandler { /** @private */ _buildSkillsCategory(token) { const actor = token.actor; - if (actor.data.type !== 'vehicle') return; + if (actor.data.type === 'vehicle') return; const skills = actor.data.data.skills; @@ -433,7 +433,7 @@ export class ActionHandler5e extends ActionHandler { let skillId = e[0]; let name = abbr ? skillId : game.dnd5e.config.skills[skillId]; name = name.charAt(0).toUpperCase() + name.slice(1); - let encodedValue = [macroType, tokenId, e[0]].join(this.delimiter); + let encodedValue = [macroType, token.id, e[0]].join(this.delimiter); let icon = this._getProficiencyIcon(skills[skillId].value); return { name: name, id: e[0], encodedValue: encodedValue, icon: icon }; } catch (error) { @@ -743,7 +743,7 @@ export class ActionHandler5e extends ActionHandler { const itemId = item.id ?? item._id; let encodedValue = [macroType, tokenId, itemId].join(this.delimiter); let img = this._getImage(item); - let icon = this._getActionIcon(item.data?.activation?.type); + let icon = this._getActionIcon(item.data?.data?.activation?.type); let result = { name: item.name, id: itemId, encodedValue: encodedValue, img: img, icon: icon } if (itemData.recharge && !itemData.recharge.charged && itemData.recharge.value) { diff --git a/scripts/actions/sw5e/sw5e-actions.js b/scripts/actions/sw5e/sw5e-actions.js index 7832f25..728f74a 100644 --- a/scripts/actions/sw5e/sw5e-actions.js +++ b/scripts/actions/sw5e/sw5e-actions.js @@ -98,7 +98,7 @@ export class ActionHandlerSw5e extends ActionHandler { /** @private */ _getItemList(actor, tokenId) { - let validItems = this._filterLongerActions(actor.data.items.filter(i => i.data.quantity > 0)); + let validItems = this._filterLongerActions(actor.data.items.filter(i => i.data.data.quantity > 0)); let sortedItems = this._sortByItemSort(validItems); let macroType = 'item'; @@ -106,7 +106,7 @@ export class ActionHandlerSw5e extends ActionHandler { if (actor.data.type === 'npc') { equipped = sortedItems.filter(i => i.type !== 'consumable' && i.type !== 'power' && i.type !== 'feat'); } else { - equipped = sortedItems.filter(i => i.type !== 'consumable' && i.data.equipped); + equipped = sortedItems.filter(i => i.type !== 'consumable' && i.data.data.equipped); } let activeEquipped = this._getActiveEquipment(equipped); @@ -167,10 +167,10 @@ export class ActionHandlerSw5e extends ActionHandler { const activationTypes = Object.keys(game.sw5e.config.abilityActivationTypes); let activeEquipment = equipment.filter(e => { - if (!e.data.activation) + if (!e.data.data.activation) return false; - return activationTypes.includes(e.data.activation.type) + return activationTypes.includes(e.data.data.activation.type) }); return activeEquipment; @@ -229,7 +229,7 @@ export class ActionHandlerSw5e extends ActionHandler { }) let dispose = powers.reduce(function (dispose, p) { - let prep = p.data.preparation.mode; + let prep = p.data.data.preparation.mode; const prepType = game.sw5e.config.powerPreparationModes[prep]; var level = p.data.level; @@ -329,7 +329,7 @@ export class ActionHandlerSw5e extends ActionHandler { let legendary = this.initializeEmptySubcategory(); let dispose = feats.reduce(function (dispose, f) { - const activationType = f.data.activation.type; + const activationType = f.data.data.activation.type; const macroType = 'feat'; let feat = this._buildItem(tokenId, actor, macroType, f); @@ -470,6 +470,8 @@ export class ActionHandlerSw5e extends ActionHandler { let rests = this.initializeEmptySubcategory() let utility = this.initializeEmptySubcategory(); + this._addIntiativeSubcategory(macroType, result, tokenId); + if (actor.data.type === 'character') { let shortRestValue = [macroType, tokenId, 'shortRest'].join(this.delimiter); rests.actions.push({id:'shortRest', encodedValue: shortRestValue, name: this.i18n('tokenactionhud.shortRest')}) @@ -498,10 +500,13 @@ export class ActionHandlerSw5e extends ActionHandler { _addMultiUtilities(list, tokenId, actors) { let category = this.initializeEmptyCategory('utility'); let macroType = 'utility'; + + this._addMultiIntiativeSubcategory(macroType, tokenId, category); let rests = this.initializeEmptySubcategory(); let utility = this.initializeEmptySubcategory(); + if (actors.every(a => a.data.type === 'character')) { let shortRestValue = [macroType, tokenId, 'shortRest'].join(this.delimiter); rests.actions.push({id:'shortRest', encodedValue: shortRestValue, name: this.i18n('tokenactionhud.shortRest')}) @@ -543,7 +548,7 @@ export class ActionHandlerSw5e extends ActionHandler { availableConditions.forEach(c => { const name = this.i18n(c.label); const encodedValue = [macroType, tokenId, c.id].join(this.delimiter); - const cssClass = actor.effects.entries.some(e => e.data.flags.core?.statusId === c.id) ? 'active' : ''; + const cssClass = Object.entries(actor.effects).some((k, e) => e.data.flags.core?.statusId === c.id) ? 'active' : ''; const image = c.icon; const action = {name: name, id: c.id, encodedValue: encodedValue, img: image, cssClass: cssClass} @@ -552,6 +557,56 @@ export class ActionHandlerSw5e extends ActionHandler { this._combineSubcategoryWithCategory(category, this.i18n('tokenactionhud.conditions'), conditions); } + + /** @private */ + _addIntiativeSubcategory(macroType, category, tokenId) { + const combat = game.combat; + let combatant, currentInitiative; + if (combat) { + combatant = combat.combatants.find(c => c.tokenId === tokenId); + currentInitiative = combatant?.initiative; + } + + let initiative = this.initializeEmptySubcategory(); + + let initiativeValue = [macroType, tokenId, 'initiative'].join(this.delimiter); + let initiativeName = `${this.i18n('tokenactionhud.rollInitiative')}`; + + let initiativeAction = {id:'rollInitiative', encodedValue: initiativeValue, name: initiativeName}; + + if (currentInitiative) + initiativeAction.info1 = currentInitiative; + initiativeAction.cssClass = currentInitiative ? 'active' : ''; + + initiative.actions.push(initiativeAction); + + this._combineSubcategoryWithCategory(category, this.i18n('tokenactionhud.initiative'), initiative); + } + + /** @private */ + _addMultiIntiativeSubcategory(macroType, tokenId, category) { + const combat = game.combat; + + let initiative = this.initializeEmptySubcategory(); + + let initiativeValue = [macroType, tokenId, 'initiative'].join(this.delimiter); + let initiativeName = `${this.i18n('tokenactionhud.rollInitiative')}`; + + let initiativeAction = {id:'rollInitiative', encodedValue: initiativeValue, name: initiativeName}; + + let isActive; + if (combat) { + let tokenIds = canvas.tokens.controlled.map(t => t.id); + let tokenCombatants = tokenIds.map(id => combat.combatants.find(c => c.tokenId === id)); + isActive = tokenCombatants.every(c => !!c?.initiative) + } + + initiativeAction.cssClass = isActive ? 'active' : ''; + + initiative.actions.push(initiativeAction); + + this._combineSubcategoryWithCategory(category, this.i18n('tokenactionhud.initiative'), initiative); + } /** @private */ _addMultiConditions(list, tokenId) { @@ -569,7 +624,7 @@ export class ActionHandlerSw5e extends ActionHandler { availableConditions.forEach(c => { const name = this.i18n(c.label); const encodedValue = [macroType, tokenId, c.id].join(this.delimiter); - const cssClass = actors.every(actor => actor.effects.entries.some(e => e.data.flags.core?.statusId === c.id)) ? 'active' : ''; + const cssClass = actors.every(actor => Object.entries(actor.effects).some(e => e.data.flags.core?.statusId === c.id)) ? 'active' : ''; const image = c.icon; const action = {name: name, id: c.id, encodedValue: encodedValue, img: image, cssClass: cssClass} diff --git a/scripts/rollHandlers/sw5e/sw5e-base.js b/scripts/rollHandlers/sw5e/sw5e-base.js index 2b9208e..c03aabf 100644 --- a/scripts/rollHandlers/sw5e/sw5e-base.js +++ b/scripts/rollHandlers/sw5e/sw5e-base.js @@ -57,7 +57,7 @@ export class RollHandlerBaseSw5e extends RollHandler { this.rollItemMacro(event, tokenId, actionId); break; case "utility": - this.performUtilityMacro(event, tokenId, actionId); + await this.performUtilityMacro(event, tokenId, actionId); break; case 'effect': await this.toggleEffect(event, tokenId, actionId); @@ -108,7 +108,7 @@ export class RollHandlerBaseSw5e extends RollHandler { return (item.data.data.recharge && !item.data.data.recharge.charged && item.data.data.recharge.value); } - performUtilityMacro(event, tokenId, actionId) { + async performUtilityMacro(event, tokenId, actionId) { let actor = super.getActor(tokenId); let token = super.getToken(tokenId); @@ -133,10 +133,21 @@ export class RollHandlerBaseSw5e extends RollHandler { case 'deathSave': actor.rollDeathSave({event}); break; + case 'initiative': + await this.performInitiativeMacro(tokenId); + break; } } + + async performInitiativeMacro(tokenId) { + let actor = super.getActor(tokenId); + + await actor.rollInitiative({createCombatants: true}); + + Hooks.callAll('forceUpdateTokenActionHUD') + } - async toggleCondition(event, tokenId, effectId) { + async toggleCondition(event, tokenId, effectId) { const token = super.getToken(tokenId); const isRightClick = this.isRightClick(event); if (effectId.includes('combat-utility-belt.') && game.cub && !isRightClick) {