Skip to content

Commit

Permalink
Merge pull request #93 from morepurplemorebetter/main
Browse files Browse the repository at this point in the history
Fix issues #88, #90, #91, #92, #94 & Improve item info, info-tooltips
  • Loading branch information
Larkinabout authored Jun 7, 2024
2 parents e8ebc11 + ca660b6 commit 623ff42
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 76 deletions.
179 changes: 104 additions & 75 deletions scripts/action-handler.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// System Module Imports
import { ACTIVATION_TYPE_ICON, ACTION_TYPE, CONDITION, PREPARED_ICON, PROFICIENCY_LEVEL_ICON, RARITY, WEAPON_PROPERTY } from './constants.js'
import { ACTIVATION_TYPE_ICON, ACTION_TYPE, CONCENTRATION_ICON, CONDITION, PREPARED_ICON, PROFICIENCY_LEVEL_ICON, RARITY, WEAPON_PROPERTY } from './constants.js'
import { Utils } from './utils.js'

export let ActionHandler = null
Expand Down Expand Up @@ -557,6 +557,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {

// Iterate effects and add to a map based on the isTemporary value
for (const [effectId, effect] of effects.entries()) {
if (effect.isSuppressed || (effect.parent?.system?.identified === false && !game.user.isGM)) continue
const isTemporary = effect.isTemporary
if (isTemporary) {
temporaryEffects.set(effectId, effect)
Expand Down Expand Up @@ -1168,14 +1169,9 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
const encodedValue = [actionType, id].join(this.delimiter)
const img = coreModule.api.Utils.getImage(entity)
const icon1 = this.#getActivationTypeIcon(entity?.system?.activation?.type)
let icon2 = null
let info = null
if (entity.type === 'spell') {
icon2 = this.#getPreparedIcon(entity)
if (this.displaySpellInfo) info = this.#getSpellInfo(entity)
} else {
info = this.#getItemInfo(entity)
}
const icon2 = this.#getPreparedIcon(entity)
const icon3 = this.#getConcentrationIcon(entity)
const info = this.#getItemInfo(entity)
const info1 = info?.info1
const info2 = info?.info2
const info3 = info?.info3
Expand All @@ -1189,6 +1185,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
img,
icon1,
icon2,
icon3,
info1,
info2,
info3,
Expand Down Expand Up @@ -1266,54 +1263,43 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
* @returns {object}
*/
#getItemInfo (item) {
const quantityData = this.#getQuantityData(item)
const usesData = this.#getUsesData(item)
const consumeData = this.#getConsumeData(item)
const info1 = item.type === 'spell' ? this.#getSpellInfo(item) : this.#getQuantityData(item)
const info2 = this.#getUsesData(item)
const info3 = this.#getConsumeData(item)

return {
info1: { text: quantityData },
info2: { text: usesData },
info3: { text: consumeData }
}
return { info1, info2, info3 }
}

/**
* Add spell info
* @param {object} spell
*/
#getSpellInfo (spell) {
const components = spell.system.properties

if (!this.displaySpellInfo) return null
const info = { text: '' }
const componentsArray = []
const info1 = {}
const info2 = {}
const info3 = {}

// Components
if (components?.vocal) componentsArray.push(coreModule.api.Utils.i18n('DND5E.ComponentVerbal'))
if (components?.somatic) componentsArray.push(coreModule.api.Utils.i18n('DND5E.ComponentSomatic'))
if (components?.material) componentsArray.push(coreModule.api.Utils.i18n('DND5E.ComponentMaterial'))

if (componentsArray.length) {
info1.title = componentsArray.join(', ')
info1.text = componentsArray.map(component => component.charAt(0).toUpperCase()).join('')
}

// Concentration
if (components?.concentration) {
const title = coreModule.api.Utils.i18n('DND5E.Concentration')
info2.title = title
info2.text = title.charAt(0).toUpperCase()
}
const components = spell.system?.properties
const componentTypes = [
['vocal', 'DND5E.ComponentVerbal'],
['somatic', 'DND5E.ComponentSomatic'],
['material', 'DND5E.ComponentMaterial']
]
componentTypes.forEach(component => {
if (components?.has(component[0])) {
componentsArray.push(coreModule.api.Utils.i18n(component[1]))
info.text += coreModule.api.Utils.i18n(`${component[1]}Abbr`)
}
})

// Ritual
if (components?.ritual) {
const title = coreModule.api.Utils.i18n('DND5E.Ritual')
info3.title = title
info3.text = title.charAt(0).toUpperCase()
if (components?.has('ritual')) {
componentsArray.push(`[${coreModule.api.Utils.i18n('DND5E.Ritual')}]`)
info.text += ` [${coreModule.api.Utils.i18n('DND5E.RitualAbbr')}]`
}

return { info1, info2, info3 }
info.title = componentsArray.join(', ')

return info
}

/**
Expand Down Expand Up @@ -1356,19 +1342,32 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
*/
#getQuantityData (item) {
const quantity = item?.system?.quantity ?? 0
return (quantity > 1) ? quantity : ''
return {
text: (quantity > 1) ? quantity : '',
title: `${coreModule.api.Utils.i18n('DND5E.Quantity')}: ${quantity}`
}
}

/**
* Get uses
* @private
* @param {object} item
* @param {string} consumeName
* @param {integer} consumeAmount
* @returns {string}
*/
#getUsesData (item) {
#getUsesData (item, consumeName, consumeAmount) {
const uses = item?.system?.uses
if (!uses) return ''
return (uses.value > 0 || uses.max > 0) ? `${uses.value ?? '0'}${(uses.max > 0) ? `/${uses.max}` : ''}` : ''
if (uses?.per && (uses.value > 0 || uses.max > 0)) {
const of = coreModule.api.Utils.i18n('DND5E.of')
const per = coreModule.api.Utils.i18n('DND5E.per')
const period = CONFIG.DND5E.limitedUsePeriods[`${uses.per}`].label
const amount = consumeAmount !== undefined ? consumeAmount : uses.amount
const text = `${amount > 1 ? `${amount} ${of} ` : ''}${uses.value ?? '0'}${uses.max > 0 ? `/${uses.max}` : ''}`
const title = `${uses.amount > 1 ? `/${uses.max}` : ''}${text} ${per} ${period}${consumeName ? ` (${of} ${consumeName})` : ''}`
return { text, title }
}
return {}
}

/**
Expand All @@ -1382,29 +1381,41 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
// Get consume target and type
const consumeId = item?.system?.consume?.target
const consumeType = item?.system?.consume?.type
const consumeAmount = item?.system?.consume?.amount

if (consumeId === item.id) return ''
if (!consumeId || consumeId === item.id) return {}

// Return resources
if (consumeType === 'attribute') {
if (!consumeId) return ''
const parentId = consumeId.substr(0, consumeId.lastIndexOf('.'))
const target = this.actor.system[parentId]

return (target) ? `${target.value ?? '0'}${(target.max) ? `/${target.max}` : ''}` : ''
}
const target = foundry.utils.getProperty(this.actor.system, parentId)

const target = this.items.get(consumeId)
if (target) {
const text = `${target.value ?? '0'}${target.max ? `/${target.max}` : ''}`
return {
text,
title: `${text} ${target.label ?? ''}`
}
}
} else {
const target = this.items.get(consumeId)

// Return charges
if (consumeType === 'charges') {
const uses = target?.system.uses
// Return charges
if (consumeType === 'charges') {
return this.#getUsesData(target, target.name, consumeAmount)
}

return (uses?.value) ? `${uses.value}${(uses.max) ? `/${uses.max}` : ''}` : ''
// Return quantity
if (target?.system?.quantity) {
const text = `${consumeAmount > 1 ? `${consumeAmount} ${coreModule.api.Utils.i18n('DND5E.of')} ` : ''}${target.system.quantity}`
return {
text,
title: `${text} ${target.name}`
}
}
}

// Return quantity
return target?.system?.quantity ?? ''
return {}
}

/**
Expand Down Expand Up @@ -1458,21 +1469,35 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
if (icon) return `<i class="${icon}" title="${title}"></i>`
}

/**
* Get icon for concentration type
* @private
* @param {object} spell
* @returns {string}
*/
#getConcentrationIcon (spell) {
if (spell?.type !== 'spell' || !this.displaySpellInfo || !spell.system?.properties?.has('concentration')) return null
const title = coreModule.api.Utils.i18n('DND5E.Scroll.RequiresConcentration')
const icon = CONCENTRATION_ICON
return `<i class="${icon}" title="${title}"></i>`
}

/**
* Get icon for a prepared spell
* @private
* @param {boolean} prepararation
* @param {object} spell
* @returns
*/
#getPreparedIcon (spell) {
if (spell?.type !== 'spell' || !this.showUnpreparedSpells) return null
const level = spell.system.level
const preparationMode = spell.system.preparation.mode
const prepared = spell.system.preparation.prepared
const icon = (prepared) ? PREPARED_ICON : `${PREPARED_ICON} tah-icon-disabled`
const title = (prepared) ? coreModule.api.Utils.i18n('DND5E.SpellPrepared') : coreModule.api.Utils.i18n('DND5E.SpellUnprepared')
const icon = prepared ? PREPARED_ICON : `${PREPARED_ICON} tah-icon-disabled`
const title = preparationMode === 'always' ? coreModule.api.Utils.i18n('DND5E.SpellPrepAlways') : prepared ? coreModule.api.Utils.i18n('DND5E.SpellPrepared') : coreModule.api.Utils.i18n('DND5E.SpellUnprepared')

// Return icon if the preparation mode is 'prepared' and the spell is not a cantrip
return (preparationMode === 'prepared' && level !== 0) ? `<i class="${icon}" title="${title}"></i>` : ''
// Return icon if the preparation mode is 'prepared' or 'always' and the spell is not a cantrip
return ((preparationMode === 'prepared' || preparationMode === 'always') && level !== 0) ? `<i class="${icon}" title="${title}"></i>` : null
}

async #getTooltipData (entity) {
Expand All @@ -1482,15 +1507,19 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {

if (this.tooltipsSetting === 'nameOnly') return name

const description = (typeof entity?.system?.description === 'string') ? entity?.system?.description : entity?.system?.description?.value ?? ''
const modifiers = entity?.modifiers ?? null
const properties = [
...entity.system?.chatProperties ?? [],
...entity.system?.equippableItemCardProperties ?? [],
...entity.system?.activatedEffectCardProperties ?? []
].filter(p => p)
const rarity = entity?.rarity ?? null
const traits = (entity?.type === 'weapon') ? this.#getWeaponProperties(entity?.system?.properties) : null
const unidentified = entity.system?.identified === false
const description = (typeof entity?.system?.description === 'string') ? entity?.system?.description : (unidentified ? entity?.system?.unidentified?.description : entity?.system?.description?.value) ?? ''
let modifiers, properties, rarity, traits
if (!unidentified) {
modifiers = entity?.modifiers ?? null
properties = [
...entity.system?.chatProperties ?? [],
...entity.system?.equippableItemCardProperties ?? [],
...entity.system?.activatedEffectCardProperties ?? []
].filter(p => p)
rarity = unidentified ? null : entity?.rarity ?? null
traits = (entity?.type === 'weapon') ? this.#getWeaponProperties(entity?.system?.properties) : null
}
return { name, description, modifiers, properties, rarity, traits }
}

Expand Down
2 changes: 1 addition & 1 deletion scripts/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const ACTIVATION_TYPE_ICON = {
/**
* Concentration icon
*/
export const CONCENTRATION_ICON = 'fas fa-circle-c'
export const CONCENTRATION_ICON = 'fas fa-head-side-brain'

/**
* Conditions
Expand Down

0 comments on commit 623ff42

Please sign in to comment.