forked from public/fvtt-cthulhu-eternal
305 lines
11 KiB
JavaScript
305 lines
11 KiB
JavaScript
|
import { SYSTEM } from "../../config/system.mjs"
|
||
|
import CthulhuEternalRoll from '../../documents/roll.mjs'
|
||
|
|
||
|
export let RollHandler = null
|
||
|
|
||
|
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||
|
/**
|
||
|
* Extends Token Action HUD Core's RollHandler class and handles action events triggered when an action is clicked
|
||
|
*/
|
||
|
RollHandler = class RollHandler extends coreModule.api.RollHandler {
|
||
|
/**
|
||
|
* Handle action click
|
||
|
* Called by Token Action HUD Core when an action is left or right-clicked
|
||
|
* @override
|
||
|
* @param {object} event The event
|
||
|
* @param {string} encodedValue The encoded value
|
||
|
*/
|
||
|
async handleActionClick (event, encodedValue) {
|
||
|
const [actionTypeId, actionId] = encodedValue.split('|')
|
||
|
|
||
|
const knownCharacters = ['character']
|
||
|
|
||
|
// If single actor is selected
|
||
|
if (this.actor) {
|
||
|
await this.#handleAction(event, this.actor, this.token, actionTypeId, actionId)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
const controlledTokens = canvas.tokens.controlled
|
||
|
.filter((token) => knownCharacters.includes(token.actor?.type))
|
||
|
|
||
|
// If multiple actors are selected
|
||
|
for (const token of controlledTokens) {
|
||
|
const actor = token.actor
|
||
|
await this.#handleAction(event, actor, token, actionTypeId, actionId)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle action hover
|
||
|
* Called by Token Action HUD Core when an action is hovered on or off
|
||
|
* @override
|
||
|
* @param {object} event The event
|
||
|
* @param {string} encodedValue The encoded value
|
||
|
*/
|
||
|
async handleActionHover (event, encodedValue) {
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle group click
|
||
|
* Called by Token Action HUD Core when a group is right-clicked while the HUD is locked
|
||
|
* @override
|
||
|
* @param {object} event The event
|
||
|
* @param {object} group The group
|
||
|
*/
|
||
|
async handleGroupClick (event, group) {
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle action
|
||
|
* @private
|
||
|
* @param {object} event The event
|
||
|
* @param {object} actor The actor
|
||
|
* @param {object} token The token
|
||
|
* @param {string} actionTypeId The action type id
|
||
|
* @param {string} actionId The actionId
|
||
|
*/
|
||
|
async #handleAction (event, actor, token, actionTypeId, actionId) {
|
||
|
switch (actionTypeId) {
|
||
|
case 'attributes':
|
||
|
await this.#handleAttributesAction(event, actor, actionId)
|
||
|
break
|
||
|
case 'skills':
|
||
|
await this.#handleSkillsAction(event, actor, actionId)
|
||
|
break
|
||
|
case 'weapons':
|
||
|
await this.#handleWeaponsAction(event, actor, actionId)
|
||
|
break
|
||
|
case 'damage':
|
||
|
await this.#handleDamageAction(event, actor, actionId)
|
||
|
break
|
||
|
case 'lethality':
|
||
|
await this.#handleLethalityAction(event, actor, actionId)
|
||
|
break
|
||
|
case 'specialTraining':
|
||
|
await this.#handleSpecialTrainingAction(event, actor, actionId)
|
||
|
break
|
||
|
case 'typedSkills':
|
||
|
await this.#handleCustomTypedAction(event, actor, actionId)
|
||
|
break
|
||
|
/* case 'rituals':
|
||
|
await this.#handleRitualsAction(event, actor, actionId)
|
||
|
break */
|
||
|
case 'utility':
|
||
|
await this.#handleUtilityAction(token, actionId)
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle Attribute action
|
||
|
* @private
|
||
|
* @param {object} event The event
|
||
|
* @param {object} actor The actor
|
||
|
* @param {string} actionId The action id
|
||
|
*/
|
||
|
async #handleAttributesAction (event, actor, actionId) {
|
||
|
let rollType
|
||
|
if (actionId === 'wp' || actionId === 'health') return
|
||
|
if (actionId.includes('_add') || actionId.includes('_subtract')) {
|
||
|
const attr = actionId.split('_')[0]
|
||
|
const action = actionId.split('_')[1]
|
||
|
const update = {}
|
||
|
update.system = {}
|
||
|
update.system[attr] = {}
|
||
|
update.system[attr].value = action === 'add' ? this.actor.system[attr].value + 1 : this.actor.system[attr].value - 1
|
||
|
if (update.system[attr].value > this.actor.system[attr].max || update.system[attr].value < this.actor.system[attr].min) return
|
||
|
return await this.actor.update(update)
|
||
|
}
|
||
|
if (actionId === 'sanity') {
|
||
|
rollType = actionId
|
||
|
} else if (actionId === 'luck') {
|
||
|
rollType = actionId
|
||
|
} else {
|
||
|
rollType = 'stat'
|
||
|
}
|
||
|
const options = {
|
||
|
actor: this.actor,
|
||
|
rollType,
|
||
|
key: actionId
|
||
|
}
|
||
|
|
||
|
const roll = new DGPercentileRoll('1D100', {}, options)
|
||
|
return await this.actor.sheet.processRoll(event, roll)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle Skill action
|
||
|
* @private
|
||
|
* @param {object} event The event
|
||
|
* @param {object} actor The actor
|
||
|
* @param {string} actionId The action id
|
||
|
*/
|
||
|
async #handleSkillsAction (event, actor, actionId) {
|
||
|
const options = {
|
||
|
actor: this.actor,
|
||
|
rollType: 'skill',
|
||
|
key: actionId
|
||
|
}
|
||
|
|
||
|
const skill = this.actor.system.skills[actionId]
|
||
|
if (!skill) return ui.notifications.warn('Bad skill name in HUD.')
|
||
|
|
||
|
const roll = new DGPercentileRoll('1D100', {}, options)
|
||
|
await this.actor.sheet.processRoll(event, roll)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle Typed/Custom skills action
|
||
|
* @private
|
||
|
* @param {object} event The event
|
||
|
* @param {object} actor The actor
|
||
|
* @param {string} actionId The action id
|
||
|
*/
|
||
|
async #handleCustomTypedAction (event, actor, actionId) {
|
||
|
const options = {
|
||
|
actor: this.actor,
|
||
|
rollType: 'skill',
|
||
|
key: actionId
|
||
|
}
|
||
|
const roll = new DGPercentileRoll('1D100', {}, options)
|
||
|
await this.actor.sheet.processRoll(event, roll)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle SoecialTraining action
|
||
|
* @private
|
||
|
* @param {object} event The event
|
||
|
* @param {object} actor The actor
|
||
|
* @param {string} actionId The action id
|
||
|
*/
|
||
|
async #handleSpecialTrainingAction (event, actor, actionId) {
|
||
|
const attr = this.actor.system.specialTraining.find(a => a.name === actionId).attribute
|
||
|
let target = 0
|
||
|
if (DG.statistics.includes(attr)) {
|
||
|
target = this.actor.system.statistics[attr].x5
|
||
|
} else if (DG.skills.includes(attr)) {
|
||
|
target = this.actor.system.skills[attr].proficiency
|
||
|
} else {
|
||
|
target = this.actor.system.typedSkills[attr].proficiency
|
||
|
}
|
||
|
const options = {
|
||
|
actor: this.actor,
|
||
|
rollType: 'special-training',
|
||
|
key: attr,
|
||
|
specialTrainingName: actionId,
|
||
|
target
|
||
|
}
|
||
|
const roll = new DGPercentileRoll('1D100', {}, options)
|
||
|
await this.actor.sheet.processRoll(event, roll)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle Weapon action
|
||
|
* @private
|
||
|
* @param {object} event The event
|
||
|
* @param {object} actor The actor
|
||
|
* @param {string} actionId The action id
|
||
|
*/
|
||
|
async #handleWeaponsAction (event, actor, actionId) {
|
||
|
const item = this.actor.items.get(actionId)
|
||
|
const options = {
|
||
|
actor: this.actor,
|
||
|
rollType: 'weapon',
|
||
|
key: item.system.skill,
|
||
|
item
|
||
|
}
|
||
|
const roll = new DGPercentileRoll('1D100', {}, options)
|
||
|
await this.actor.sheet.processRoll(event, roll)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle Damage action
|
||
|
* @private
|
||
|
* @param {object} event The event
|
||
|
* @param {object} actor The actor
|
||
|
* @param {string} actionId The action id
|
||
|
*/
|
||
|
async #handleDamageAction (event, actor, actionId) {
|
||
|
const item = this.actor.items.get(actionId)
|
||
|
if (item.system.lethality > 0 && event.ctrlKey) {
|
||
|
// Toggle on/off lethality
|
||
|
const isLethal = !item.system.isLethal
|
||
|
await item.update({ 'system.isLethal': isLethal })
|
||
|
} else {
|
||
|
const options = {
|
||
|
actor: this.actor,
|
||
|
rollType: 'damage',
|
||
|
key: item.system.damage,
|
||
|
item
|
||
|
}
|
||
|
const roll = new DGDamageRoll(item.system.damage, {}, options)
|
||
|
await this.actor.sheet.processRoll(event, roll)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle Lethality action
|
||
|
* @private
|
||
|
* @param {object} event The event
|
||
|
* @param {object} actor The actor
|
||
|
* @param {string} actionId The action id
|
||
|
*/
|
||
|
async #handleLethalityAction (event, actor, actionId) {
|
||
|
const item = await this.actor.items.get(actionId)
|
||
|
if (item.system.damage !== '' && event.ctrlKey) {
|
||
|
const isLethal = !item.system.isLethal
|
||
|
await item.update({ 'system.isLethal': isLethal })
|
||
|
} else {
|
||
|
const options = {
|
||
|
actor: this.actor,
|
||
|
rollType: 'lethality',
|
||
|
key: item.system.lethality,
|
||
|
item
|
||
|
}
|
||
|
const roll = new DGLethalityRoll(item.system.damage, {}, options)
|
||
|
await this.actor.sheet.processRoll(event, roll)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle Ritual action
|
||
|
* @private
|
||
|
* @param {object} event The event
|
||
|
* @param {object} actor The actor
|
||
|
* @param {string} actionId The action id
|
||
|
*/
|
||
|
async #handleRitualsAction (event, actor, actionId) {
|
||
|
const options = {
|
||
|
actor: this.actor,
|
||
|
rollType: 'ritual',
|
||
|
key: actionId
|
||
|
}
|
||
|
const roll = new DGPercentileRoll('1D100', {}, options)
|
||
|
await this.actor.sheet.processRoll(event, roll)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle utility action
|
||
|
* @private
|
||
|
* @param {object} token The token
|
||
|
* @param {string} actionId The action id
|
||
|
*/
|
||
|
async #handleUtilityAction (token, actionId) {
|
||
|
switch (actionId) {
|
||
|
case 'endTurn':
|
||
|
if (game.combat?.current?.tokenId === token.id) {
|
||
|
await game.combat?.nextTurn()
|
||
|
}
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
})
|