Combat/automation enhancements !
All checks were successful
Release Creation / build (release) Successful in 58s

This commit is contained in:
2025-11-13 13:59:02 +01:00
parent 6ad8226265
commit 2c25820152
26 changed files with 233 additions and 220 deletions

View File

@@ -1,6 +1,7 @@
// System Module Imports
import { Utils } from './utils.js'
import { SYSTEM } from "../../config/system.mjs"
import CthulhuEternalUtils from '../../utils.mjs'
export let ActionHandler = null
@@ -53,7 +54,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
async buildCharacteristics() {
const actions = []
for (const key in this.actor.system.characteristics) {
const encodedValue = [coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.characteristics'), key].join(this.delimiter)
const encodedValue = ['characteristics', key].join(this.delimiter)
const tooltip = {
content: String(this.actor.system.characteristics[key].value * 5),
class: 'tah-system-tooltip',
@@ -94,7 +95,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
if (typeof this.actor.system?.san?.value !== 'undefined') {
const actions = []
const groupData = {
id: 'other_sanity',
id: 'other_san',
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.SAN'),
type: 'system'
}
@@ -106,29 +107,29 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
}
actions.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.SAN'),
id: 'sanity',
id: 'san',
info1: this.#showValue() ? { text: tooltip.content } : null,
tooltip,
encodedValue: ['characteristics', 'sanity'].join(this.delimiter)
encodedValue: ['characteristics', 'san'].join(this.delimiter)
},
{
name: '+',
id: 'sanity_add',
id: 'san_add',
tooltip,
encodedValue: ['characteristics', 'sanity_add'].join(this.delimiter)
encodedValue: ['characteristics', 'san_add'].join(this.delimiter)
},
{
name: '-',
id: 'sanity_subtract',
id: 'san_subtract',
tooltip,
encodedValue: ['characteristics', 'sanity_subtract'].join(this.delimiter)
encodedValue: ['characteristics', 'san_subtract'].join(this.delimiter)
})
await this.addActions(actions, { id: 'other_sanity', type: 'system' })
await this.addActions(actions, { id: 'other_san', type: 'system' })
}
if (typeof this.actor.system.hp.value !== 'undefined') {
const actions = []
const groupData = {
id: 'other_health',
id: 'other_hp',
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.HP'),
type: 'system'
}
@@ -140,24 +141,24 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
}
actions.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.HP'),
id: 'health',
id: 'hp',
info1: this.#showValue() ? { text: tooltip.content } : null,
tooltip,
encodedValue: ['characteristics', 'health'].join(this.delimiter)
encodedValue: ['characteristics', 'hp'].join(this.delimiter)
},
{
name: '+',
id: 'health_add',
id: 'hp_add',
tooltip,
encodedValue: ['characteristics', 'health_add'].join(this.delimiter)
encodedValue: ['characteristics', 'hp_add'].join(this.delimiter)
},
{
name: '-',
id: 'health_subtract',
id: 'hp_subtract',
tooltip,
encodedValue: ['characteristics', 'health_subtract'].join(this.delimiter)
encodedValue: ['characteristics', 'hp_subtract'].join(this.delimiter)
})
await this.addActions(actions, { id: 'other_health', type: 'system' })
await this.addActions(actions, { id: 'other_hp', type: 'system' })
}
if (typeof this.actor.system.wp.value !== 'undefined') {
const actions = []
@@ -197,12 +198,15 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
async buildSkills() {
const actions = []
for (const item of this.actor.items) {
if (item.type !== 'skill') continue;
if (item.type === 'skill' && item.system.skillTotal > 0) {
const skill = item
// Build alpha sorted skill list
let skills = this.actor.items.filter(i => i.type === 'skill')
skills = skills.sort((a, b) => a.name.localeCompare(b.name))
console.log('Building skills actions for skills:', skills)
for (const skill of skills) {
console.log('Processing skill item:', skill)
if (skill.system.skillTotal > 0) {
const tooltip = {
content: String(item.system.skillTotal),
content: String(skill.system.skillTotal),
direction: 'LEFT'
}
actions.push({
@@ -218,56 +222,55 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
}
async buildEquipment() {
let era = game.settings.get("fvtt-cthulhu-eternal", "settings-era")
// const rituals = []
for (const item of this.actor.items) {
// Push the weapon name as a new group
const groupData = {
id: 'weapons_' + item._id,
id: `weapons_${item._id}`,
name: item.name,
type: 'system'
}
this.addGroup(groupData, { id: 'weapons', type: 'system' }, true)
if (item.type === 'weapon') {
const weapons = []
let skill = CthulhuEternalUtils.getWeaponSkill(this.actor, item, era)
item.skillTotal = skill ? skill.system.skillTotal : 0
let weapons = []
const tooltip = {
content: String(item.system.skillTotal),
content: String(item.skillTotal),
direction: 'LEFT'
}
console.log('Weapon skill total for', item.name, 'is', item.skillTotal, item._id)
weapons.push({
name: item.name,
id: item._id,
name: `${item.name} (${item.skillTotal})`,
id: `weapon_${item._id}`,
info1: this.#showValue() ? { text: tooltip.content } : null,
encodedValue: ['weapons', item._id].join(this.delimiter),
tooltip
})
let damage = ''
if (item.system.lethality > 0) {
damage = `L:${item.system.lethality}%`
} else {
damage = item.system.damage
}
const damageTooltip = {
content: String(item.system.damage),
content: String(damage),
direction: 'LEFT'
}
if (item.system.damage !== '') {
weapons.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Damage'),
id: item._id,
name: `${coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Damage')} (${damage})`,
id: `damage_${item._id}`,
info1: this.#showValue() ? { text: damageTooltip.content } : null,
encodedValue: ['damage', item._id].join(this.delimiter),
tooltip: damageTooltip
})
}
if (item.system.lethality > 0) {
const lethalityTooltip = {
content: String(item.system.lethality),
direction: 'LEFT'
}
weapons.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Lethality'),
id: item._id,
info1: this.#showValue() ? { text: lethalityTooltip.content } : null,
encodedValue: ['lethality', item._id].join(this.delimiter),
tooltip: lethalityTooltip
})
}
console.log('Adding weapon actions for', item.name, weapons)
await this.addActions(weapons, {
id: 'weapons_' + item._id,
id: `weapons_${item._id}`,
type: 'system'
})
}/* else if (item.type === 'ritual') {

View File

@@ -22,7 +22,7 @@ export const REQUIRED_CORE_MODULE_VERSION = '2.0'
*/
export const ACTION_TYPE = {
characteristics: 'CTHULHUETERNAL.Label.characteristics',
skills: 'CTHULHUETERNAL.Label.skills',
skills: 'CTHULHUETERNAL.Label.Skills',
equipment: 'CTHULHUETERNAL.Label.gear'
}
@@ -33,7 +33,7 @@ export const GROUP = {
characteristics: { id: 'characteristics', name: 'CTHULHUETERNAL.Label.characteristics', type: 'system' },
luck: { id: 'luck', name: 'CTHULHUETERNAL.Label.luck', type: 'system' },
other: { id: 'other', name: 'CTHULHUETERNAL.Label.other', type: 'system' },
skills: { id: 'skills', name: 'CTHULHUETERNAL.Label.skills', type: 'system' },
skills: { id: 'skills', name: 'CTHULHUETERNAL.Label.Skills', type: 'system' },
weapons: { id: 'weapons', name: 'CTHULHUETERNAL.Label.weapons', type: 'system' },
rituals: { id: 'rituals', name: 'CTHULHUETERNAL.Label.rituals', type: 'system' }
}

View File

@@ -17,7 +17,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
{
nestId: 'statistics',
id: 'statistics',
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.characteristics'),
name: game.i18n.localize('CTHULHUETERNAL.Label.characteristics'),
groups: [
{ ...groups.characteristics, nestId: 'statistics_characteristics' },
{ ...groups.other, nestId: 'statistics_other' },
@@ -27,7 +27,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
{
nestId: 'skills',
id: 'skills',
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.skills'),
name: game.i18n.localize('CTHULHUETERNAL.Label.skills'),
groups: [
{ ...groups.skills, nestId: 'skills_skills' }
]
@@ -35,7 +35,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
{
nestId: 'equipment',
id: 'equipment',
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.gear'),
name: game.i18n.localize('CTHULHUETERNAL.Label.gear'),
groups: [
{ ...groups.weapons, nestId: 'equipment_weapons' },
{ ...groups.rituals, nestId: 'equipment_rituals' }

View File

@@ -1,14 +0,0 @@
import { SystemManager } from './system-manager.js'
import { MODULE, REQUIRED_CORE_MODULE_VERSION } from './constants.js'
Hooks.on('tokenActionHudCoreApiReady', async () => {
/**
* Return the SystemManager and requiredCoreModuleVersion to Token Action HUD Core
*/
const module = game.modules.get(MODULE.ID)
module.api = {
requiredCoreModuleVersion: REQUIRED_CORE_MODULE_VERSION,
SystemManager
}
Hooks.call('tokenActionHudSystemReady', module)
})

View File

@@ -66,9 +66,10 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
* @param {string} actionId The actionId
*/
async #handleAction(event, actor, token, actionTypeId, actionId) {
console.log('Handling action', actionId, 'of type', actionTypeId, 'for actor', actor.name)
switch (actionTypeId) {
case 'attributes':
await this.#handleAttributesAction(event, actor, actionId)
case 'characteristics':
await this.#handleCharacteristicsAction(event, actor, actionId)
break
case 'skills':
await this.#handleSkillsAction(event, actor, actionId)
@@ -92,18 +93,20 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
}
/**
* Handle Attribute action
* Handle Characteristic action
* @private
* @param {object} event The event
* @param {object} actor The actor
* @param {string} actionId The action id
*/
async #handleAttributesAction(event, actor, actionId) {
async #handleCharacteristicsAction(event, actor, actionId) {
let rollType
if (actionId === 'wp' || actionId === 'health') return
if (actionId === 'wp' || actionId === 'hp') return
if (actionId.includes('_add') || actionId.includes('_subtract')) {
const attr = actionId.split('_')[0]
const action = actionId.split('_')[1]
console.log('Updating', attr, 'with action', action)
const update = {}
update.system = {}
update.system[attr] = {}
@@ -111,21 +114,23 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
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
if (actionId === 'san') {
let item = foundry.utils.duplicate(actor.system.san)
item.name = game.i18n.localize("CTHULHUETERNAL.Label.SAN")
item.targetScore = item.value
await actor.system.roll('san', item)
} else if (actionId === 'luck') {
rollType = actionId
let item = foundry.utils.duplicate(actor.system.characteristics.int)
item.name = game.i18n.localize("CTHULHUETERNAL.Label.Luck")
item.value = 10
item.targetScore = 50
await actor.system.roll('luck', item)
} else {
rollType = 'stat'
let item = foundry.utils.duplicate(actor.system.characteristics[actionId])
item.name = game.i18n.localize(`CTHULHUETERNAL.Label.${actionId}Long`)
item.targetScore = item.value * 5
await actor.system.roll('char', item)
}
const options = {
actor: this.actor,
rollType,
key: actionId
}
/*const roll = new DGPercentileRoll('1D100', {}, options)
return await this.actor.sheet.processRoll(event, roll)*/
}
/**
@@ -136,18 +141,9 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
* @param {string} actionId The action id
*/
async #handleSkillsAction(event, actor, actionId) {
const options = {
actor: this.actor,
rollType: 'skill',
key: actionId
}
const skill = this.actor.items.find(i => i.type === 'skill' && i.id === actionId)
if (!skill) return ui.notifications.warn('Bad skill name in HUD.')
/** TO FIX
const roll = new DGPercentileRoll('1D100', {}, options)
await this.actor.sheet.processRoll(event, roll)*/
const skill = actor.items.find(i => i.type === 'skill' && i.id === actionId)
if (!skill) return ui.notifications.warn(`Skill not found for action id '${actionId}'`)
await actor.system.roll('skill', skill)
}
@@ -159,16 +155,10 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
* @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
}
/* TO FIX
const roll = new DGPercentileRoll('1D100', {}, options)
await this.actor.sheet.processRoll(event, roll)*/
let weapon = actor.items.find(i => i.type === 'weapon' && i.id === actionId)
weapon.damageFormula = weapon.system.damage
weapon.damageBonus = actor.system.damageBonus
await actor.system.roll('weapon', weapon)
}
/**
@@ -179,22 +169,10 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
* @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
}
/* TOFIX
const roll = new DGDamageRoll(item.system.damage, {}, options)
await this.actor.sheet.processRoll(event, roll)*/
}
let weapon = actor.items.find(i => i.type === 'weapon' && i.id === actionId)
weapon.damageFormula = weapon.system.damage
weapon.damageBonus = actor.system.damageBonus
await actor.system.roll('damage', weapon)
}
/**

View File

@@ -463,6 +463,13 @@ export default class CthulhuEternalUtils {
static async damageRoll(rollMessage, formula = null) {
let rollData = rollMessage.rolls[0]?.options?.rollData
if (!rollData) {
rollData = rollMessage.getFlag("fvtt-cthulhu-eternal", "rollData")
}
if (!rollData) {
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Label.noRollDataFound"))
return
}
let actor = game.actors.get(rollData.actorId)
if (!actor) {
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Label.noActorFound"))