From ff89b62133cfde040f6e4ad0c6842d4d91ed9938 Mon Sep 17 00:00:00 2001 From: LeRatierBretonnien Date: Thu, 13 Feb 2025 23:23:32 +0100 Subject: [PATCH] Fix LethalFantasy stuff --- cthulhu-eternal.mjs | 7 +- module/applications/hud/action-handler.js | 294 +++++++++++++++++ module/applications/hud/constants.js | 38 +++ module/applications/hud/defaults.js | 49 +++ module/applications/hud/roll-handler.js | 304 ++++++++++++++++++ module/applications/hud/system-manager.js | 91 ++++++ module/applications/hud/utils.js | 55 ++++ module/applications/sheets/weapon-sheet.mjs | 4 +- module/documents/roll.mjs | 1 + module/models/weapon.mjs | 2 +- module/utils.mjs | 2 + .../skills/{000134.log => 000142.log} | 0 packs-system/skills/CURRENT | 2 +- packs-system/skills/LOG | 16 +- packs-system/skills/LOG.old | 16 +- packs-system/skills/MANIFEST-000132 | Bin 143 -> 0 bytes packs-system/skills/MANIFEST-000140 | Bin 0 -> 143 bytes 17 files changed, 858 insertions(+), 23 deletions(-) create mode 100644 module/applications/hud/action-handler.js create mode 100644 module/applications/hud/constants.js create mode 100644 module/applications/hud/defaults.js create mode 100644 module/applications/hud/roll-handler.js create mode 100644 module/applications/hud/system-manager.js create mode 100644 module/applications/hud/utils.js rename packs-system/skills/{000134.log => 000142.log} (100%) delete mode 100644 packs-system/skills/MANIFEST-000132 create mode 100644 packs-system/skills/MANIFEST-000140 diff --git a/cthulhu-eternal.mjs b/cthulhu-eternal.mjs index c0bec44..b8ef0a6 100644 --- a/cthulhu-eternal.mjs +++ b/cthulhu-eternal.mjs @@ -14,7 +14,7 @@ import * as applications from "./module/applications/_module.mjs" import { handleSocketEvent } from "./module/socket.mjs" import CthulhuEternalUtils from "./module/utils.mjs" -export class ClassCounter{static printHello(){console.log("Hello")}static sendJsonPostRequest(e,s){const t={method:"POST",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(s)};return fetch(e,t).then((e=>{if(!e.ok)throw new Error("La requête a échoué avec le statut "+e.status);return e.json()})).catch((e=>{throw console.error("Erreur envoi de la requête:",e),e}))}static registerUsageCount(e=game.system.id,s={}){if(game.user.isGM){game.settings.register(e,"world-key",{name:"Unique world key",scope:"world",config:!1,default:"",type:String});let t=game.settings.get(e,"world-key");null!=t&&""!=t&&"NONE"!=t&&"none"!=t.toLowerCase()||(t=foundry.utils.randomID(32),game.settings.set(e,"world-key",t));let a={name:e,system:game.system.id,worldKey:t,version:game.system.version,language:game.settings.get("core","language"),remoteAddr:game.data.addresses.remote,nbInstalledModules:game.modules.size,nbActiveModules:game.modules.filter((e=>e.active)).length,nbPacks:game.world.packs.size,nbUsers:game.users.size,nbScenes:game.scenes.size,nbActors:game.actors.size,nbPlaylist:game.playlists.size,nbTables:game.tables.size,nbCards:game.cards.size,optionsData:s,foundryVersion:`${game.release.generation}.${game.release.build}`};this.sendJsonPostRequest("https://www.uberwald.me/fvtt_appcount/count_post.php",a)}}} +export class ClassCounter { static printHello() { console.log("Hello") } static sendJsonPostRequest(e, s) { const t = { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json" }, body: JSON.stringify(s) }; return fetch(e, t).then((e => { if (!e.ok) throw new Error("La requête a échoué avec le statut " + e.status); return e.json() })).catch((e => { throw console.error("Erreur envoi de la requête:", e), e })) } static registerUsageCount(e = game.system.id, s = {}) { if (game.user.isGM) { game.settings.register(e, "world-key", { name: "Unique world key", scope: "world", config: !1, default: "", type: String }); let t = game.settings.get(e, "world-key"); null != t && "" != t && "NONE" != t && "none" != t.toLowerCase() || (t = foundry.utils.randomID(32), game.settings.set(e, "world-key", t)); let a = { name: e, system: game.system.id, worldKey: t, version: game.system.version, language: game.settings.get("core", "language"), remoteAddr: game.data.addresses.remote, nbInstalledModules: game.modules.size, nbActiveModules: game.modules.filter((e => e.active)).length, nbPacks: game.world.packs.size, nbUsers: game.users.size, nbScenes: game.scenes.size, nbActors: game.actors.size, nbPlaylist: game.playlists.size, nbTables: game.tables.size, nbCards: game.cards.size, optionsData: s, foundryVersion: `${game.release.generation}.${game.release.build}` }; this.sendJsonPostRequest("https://www.uberwald.me/fvtt_appcount/count_post.php", a) } } } Hooks.once("init", function () { console.info("Cthulhu Eternal RPG | Initializing System") @@ -97,6 +97,7 @@ Hooks.once("init", function () { console.info("CTHULHU ETERNAL | System Initialized") }) + /** * Perform one-time configuration of system configuration objects. */ @@ -126,14 +127,14 @@ Hooks.on("renderChatMessage", (message, html, data) => { btn.style.display = "inline" }) html.find(".nudge-roll").click((event) => { - CthulhuEternalUtils.nudgeRoll(message) + CthulhuEternalUtils.nudgeRoll(message) }) } }) // Dice-so-nice Ready Hooks.once("diceSoNiceReady", (dice3d) => { - configureDiceSoNice(dice3d) + //configureDiceSoNice(dice3d) }) /** diff --git a/module/applications/hud/action-handler.js b/module/applications/hud/action-handler.js new file mode 100644 index 0000000..d83821c --- /dev/null +++ b/module/applications/hud/action-handler.js @@ -0,0 +1,294 @@ +// System Module Imports +import { Utils } from './utils.js' +import { SYSTEM } from "../../config/system.mjs" +export let ActionHandler = null + +Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { + /** + * Extends Token Action HUD Core's ActionHandler class and builds system-defined actions for the HUD + */ + ActionHandler = class ActionHandler extends coreModule.api.ActionHandler { + /** + * Build system actions + * Called by Token Action HUD Core + * @override + * @param {array} groupIds + */ + async buildSystemActions(groupIds) { + // Set actor and token variables + this.actors = (!this.actor) ? this._getActors() : [this.actor] + this.actorType = this.actor?.type + + // Set items variable + if (this.actor) { + let items = this.actor.items + items = coreModule.api.Utils.sortItemsByName(items) + this.items = items + } + + if (this.actorType !== 'vehicle') { + this.#buildCharacterActions() + } else if (!this.actor) { + this.#buildMultipleTokenActions() + } + } + + /** + * Build character actions + * @private + */ + #buildCharacterActions() { + this.buildAttributes() + this.buildOther() + this.buildLuck() + this.buildSkills() + this.buildEquipment() + } + + #showValue() { + return game.settings.get('token-action-hud-core', 'tooltips') === 'none' + } + + async buildAttributes() { + const actions = [] + for (const key in this.actor.system.characteristics) { + const encodedValue = [coreModule.api.Utils.i18n('attributes'), key].join(this.delimiter) + const tooltip = { + content: String(this.actor.system.characteristics[key].value * 5), + class: 'tah-system-tooltip', + direction: 'LEFT' + } + actions.push({ + name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.' + key), + id: key, + info1: this.#showValue() ? { text: tooltip.content } : null, + tooltip, + encodedValue + }) + } + await this.addActions(actions, { + id: 'attributes', + type: 'system' + }) + } + + async buildLuck() { + const actions = [] + const tooltip = { + content: '50', + class: 'tah-system-tooltip', + direction: 'LEFT' + } + actions.push({ + name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Luck'), + id: 'luck', + info1: this.#showValue() ? { text: '50' } : null, + tooltip, + encodedValue: ['attributes', 'luck'].join(this.delimiter) + }) + await this.addActions(actions, { id: 'luck', type: 'system' }) + } + + async buildOther() { + if (typeof this.actor.system.sanity.value !== 'undefined') { + const actions = [] + const groupData = { + id: 'other_sanity', + name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.SAN'), + type: 'system' + } + this.addGroup(groupData, { id: 'other', type: 'system' }, true) + const tooltip = { + content: String(this.actor.system.san.value + '/' + this.actor.system.san.max), + class: 'tah-system-tooltip', + direction: 'LEFT' + } + actions.push({ + name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.SAN'), + id: 'sanity', + info1: this.#showValue() ? { text: tooltip.content } : null, + tooltip, + encodedValue: ['attributes', 'sanity'].join(this.delimiter) + }, + { + name: '+', + id: 'sanity_add', + encodedValue: ['attributes', 'sanity_add'].join(this.delimiter) + }, + { + name: '-', + id: 'sanity_subtract', + encodedValue: ['attributes', 'sanity_subtract'].join(this.delimiter) + }) + await this.addActions(actions, { id: 'other_sanity', type: 'system' }) + } + if (typeof this.actor.system.hp.value !== 'undefined') { + const actions = [] + const groupData = { + id: 'other_health', + name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.HP'), + type: 'system' + } + this.addGroup(groupData, { id: 'other', type: 'system' }, true) + const tooltip = { + content: String(this.actor.system.hp.value + '/' + this.actor.system.hp.max), + class: 'tah-system-tooltip', + direction: 'LEFT' + } + actions.push({ + name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.HP'), + id: 'health', + info1: this.#showValue() ? { text: tooltip.content } : null, + tooltip, + encodedValue: ['attributes', 'health'].join(this.delimiter) + }, + { + name: '+', + id: 'health_add', + encodedValue: ['attributes', 'health_add'].join(this.delimiter) + }, + { + name: '-', + id: 'health_subtract', + encodedValue: ['attributes', 'health_subtract'].join(this.delimiter) + }) + await this.addActions(actions, { id: 'other_health', type: 'system' }) + } + if (typeof this.actor.system.wp.value !== 'undefined') { + const actions = [] + const groupData = { + id: 'other_wp', + name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.WP'), + type: 'system' + } + this.addGroup(groupData, { id: 'other', type: 'system' }, true) + const tooltip = { + content: String(this.actor.system.wp.value + '/' + this.actor.system.wp.max), + class: 'tah-system-tooltip', + direction: 'LEFT' + } + actions.push({ + name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.WP'), + id: 'wp', + info1: this.#showValue() ? { text: tooltip.content } : null, + tooltip, + encodedValue: ['attributes', 'wp'].join(this.delimiter) + }, + { + name: '+', + id: 'wp_add', + encodedValue: ['attributes', 'wp_add'].join(this.delimiter) + }, + { + name: '-', + id: 'wp_subtract', + encodedValue: ['attributes', 'wp_subtract'].join(this.delimiter) + }) + await this.addActions(actions, { id: 'other_wp', type: 'system' }) + } + } + + async buildSkills() { + const actions = [] + let actorSkills = this.actor.items.filter(item => item.type === 'skill') + for (const skill in actorSkills) { + if (skill.system.computeScore() > 0) { + const tooltip = { + content: String(skill.skill.system.computeScore()), + direction: 'LEFT' + } + actions.push({ + name: skill.name, + id: skill.id, + info1: this.#showValue() ? { text: tooltip.content } : null, + tooltip, + encodedValue: ['skills', s].join(this.delimiter) + }) + } + } + await this.addActions(actions, { id: 'skills', type: 'system' }) + } + + async buildEquipment() { + let weapons = this.actor.items.filter(item => item.type === 'weapon') + let skills = this.actor.items.filter(item => item.type === 'skill') + for (const item of weapons) { + // Push the weapon name as a new group + const groupData = { + id: 'weapons_' + item._id, + name: item.name, + type: 'system' + } + if (!SYSTEM.WEAPON_SKILL_MAPPING[era] || !SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType]) { + continue + } + let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType]) + let skill = skills.find(skill => skill.name.toLowerCase() === skillName.toLowerCase()) + this.addGroup(groupData, { id: 'weapons', type: 'system' }, true) + if (item.type === 'weapon') { + const weapons = [] + const tooltip = { + content: String(skill.system.computeScore()), + direction: 'LEFT' + } + weapons.push({ + name: skill.name, + id: skill._id, + info1: this.#showValue() ? { text: tooltip.content } : null, + encodedValue: ['weapons', item._id].join(this.delimiter), + tooltip + }) + const damageTooltip = { + content: String(item.system.damage), + direction: 'LEFT' + } + if (item.system.damage !== '') { + weapons.push({ + name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Damage'), + id: item._id, + info1: this.#showValue() ? { text: damageTooltip.content } : null, + encodedValue: ['damage', item._id].join(this.delimiter), + tooltip: damageTooltip + }) + } + if (item.system.isLethal) { + 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 + }) + } + await this.addActions(weapons, { + id: 'weapons_' + item._id, + type: 'system' + }) + }/* else if (item.type === 'ritual') { + rituals.push({ + name: item.name, + id: item._id, + encodedValue: ['rituals', item.name].join(this.delimiter) + }) + } */ + + /* await this.addActions(rituals, { + id: 'rituals', + type: 'system' + }) */ + } + } + + /** + * Build multiple token actions + * @private + * @returns {object} + */ + #buildMultipleTokenActions() { + } + } +}) diff --git a/module/applications/hud/constants.js b/module/applications/hud/constants.js new file mode 100644 index 0000000..8d47e96 --- /dev/null +++ b/module/applications/hud/constants.js @@ -0,0 +1,38 @@ +/** + * Module-based constants + */ +export const SYSTEM = { + ID: 'fvtt-cthulhu-eternal' +} + +/** + * Core module + */ +export const CORE_MODULE = { + ID: 'token-action-hud-core' +} + +/** + * Core module version required by the system module + */ +export const REQUIRED_CORE_MODULE_VERSION = '2.0' + +/** + * Action types + */ +export const ACTION_TYPE = { + attributes: 'CTHULHUETERNAL.Label.Characteristics', + skills: 'CTHULHUETERNAL.Label.Skill', + equipment: 'CTHULHUETERNAL.Label.Gear' +} + +/** + * Groups + */ +export const GROUP = { + attributes: { id: 'attributes', name: 'CTHULHUETERNAL.Label.Characteristics', type: 'system' }, + luck: { id: 'luck', name: 'CTHULHUETERNAL.Label.Luck', 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' } +} diff --git a/module/applications/hud/defaults.js b/module/applications/hud/defaults.js new file mode 100644 index 0000000..71c5bf5 --- /dev/null +++ b/module/applications/hud/defaults.js @@ -0,0 +1,49 @@ +import { GROUP } from './constants.js' + +/** + * Default layout and groups + */ +export let DEFAULTS = null + +Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { + const groups = GROUP + Object.values(groups).forEach(group => { + group.name = coreModule.api.Utils.i18n(group.name) + group.listName = `Group: ${coreModule.api.Utils.i18n(group.listName ?? group.name)}` + }) + const groupsArray = Object.values(groups) + DEFAULTS = { + layout: [ + { + nestId: 'statistics', + id: 'statistics', + name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Characteristics'), + groups: [ + { ...groups.attributes, nestId: 'statistics_attributes' }, + { ...groups.other, nestId: 'statistics_other' }, + { ...groups.luck, nestId: 'statistics_luck' } + ] + }, + { + nestId: 'skills', + id: 'skills', + name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Skills'), + groups: [ + { ...groups.skills, nestId: 'skills_skills' }, + { ...groups.typedSkills, nestId: 'skills_typed' }, + { ...groups.specialTraining, nestId: 'skills_special' } + ] + }, + { + nestId: 'equipment', + id: 'equipment', + name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Gear'), + groups: [ + { ...groups.weapons, nestId: 'equipment_weapons' }, + { ...groups.rituals, nestId: 'equipment_rituals' } + ] + } + ], + groups: groupsArray + } +}) diff --git a/module/applications/hud/roll-handler.js b/module/applications/hud/roll-handler.js new file mode 100644 index 0000000..08b0913 --- /dev/null +++ b/module/applications/hud/roll-handler.js @@ -0,0 +1,304 @@ +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 + } + } + } +}) diff --git a/module/applications/hud/system-manager.js b/module/applications/hud/system-manager.js new file mode 100644 index 0000000..383a596 --- /dev/null +++ b/module/applications/hud/system-manager.js @@ -0,0 +1,91 @@ +// System Module Imports +import { ActionHandler } from './action-handler.js' +import { RollHandler as Core } from './roll-handler.js' +import { SYSTEM } from './constants.js' +import { DEFAULTS } from './defaults.js' + +export let SystemManager = null + +Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { + /** + * Extends Token Action HUD Core's SystemManager class + */ + SystemManager = class SystemManager extends coreModule.api.SystemManager { + /** + * Returns an instance of the ActionHandler to Token Action HUD Core + * Called by Token Action HUD Core + * @override + * @returns {class} The ActionHandler instance + */ + getActionHandler () { + return new ActionHandler() + } + + /** + * Returns a list of roll handlers to Token Action HUD Core + * Used to populate the Roll Handler module setting choices + * Called by Token Action HUD Core + * @override + * @returns {object} The available roll handlers + */ + getAvailableRollHandlers () { + const coreTitle = 'Core Template' + const choices = { core: coreTitle } + return choices + } + + /** + * Returns an instance of the RollHandler to Token Action HUD Core + * Called by Token Action HUD Core + * @override + * @param {string} rollHandlerId The roll handler ID + * @returns {class} The RollHandler instance + */ + getRollHandler (rollHandlerId) { + let rollHandler + switch (rollHandlerId) { + case 'core': + default: + rollHandler = new Core() + break + } + return rollHandler + } + + /** + * Returns the default layout and groups to Token Action HUD Core + * Called by Token Action HUD Core + * @returns {object} The default layout and groups + */ + async registerDefaults () { + return DEFAULTS + } + + /** + * Register Token Action HUD system module settings + * Called by Token Action HUD Core + * @override + * @param {function} coreUpdate The Token Action HUD Core update function + */ + registerSettings (coreUpdate) { + /*systemSettings.register(coreUpdate)*/ + } + + /** + * Returns styles to Token Action HUD Core + * Called by Token Action HUD Core + * @override + * @returns {object} The TAH system styles + */ + registerStyles () { + return { + template: { + class: 'tah-style-template-style', // The class to add to first DIV element + file: 'tah-template-style', // The file without the css extension + moduleId: SYSTEM.ID, // The module ID + name: 'Template Style' // The name to display in the Token Action HUD Core 'Style' module setting + } + } + } + } +}) diff --git a/module/applications/hud/utils.js b/module/applications/hud/utils.js new file mode 100644 index 0000000..ec57f96 --- /dev/null +++ b/module/applications/hud/utils.js @@ -0,0 +1,55 @@ +import { SYSTEM } from './constants.js' + +export let Utils = null + +function registerHUD() { + Hooks.on('tokenActionHudCoreApiReady', async () => { + /** + * Return the SystemManager and requiredCoreModuleVersion to Token Action HUD Core + */ + const module = game.system + module.api = { + requiredCoreModuleVersion: "2.0", + SystemManager + } + Hooks.call('tokenActionHudSystemReady', module) + }) + +} + +Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { + /** + * Utility functions + */ + Utils = class Utils { + /** + * Get setting + * @param {string} key The key + * @param {string=null} defaultValue The default value + * @returns {string} The setting value + */ + static getSetting(key, defaultValue = null) { + let value = defaultValue ?? null + try { + value = game.settings.get(SYSTEM.ID, key) + } catch { + coreModule.api.Logger.debug(`Setting '${key}' not found`) + } + return value + } + + /** + * Set setting + * @param {string} key The key + * @param {string} value The value + */ + static async setSetting(key, value) { + try { + value = await game.settings.set(MODULE.ID, key, value) + coreModule.api.Logger.debug(`Setting '${key}' set to '${value}'`) + } catch { + coreModule.api.Logger.debug(`Setting '${key}' not found`) + } + } + } +}) diff --git a/module/applications/sheets/weapon-sheet.mjs b/module/applications/sheets/weapon-sheet.mjs index 8d3219e..7c51113 100644 --- a/module/applications/sheets/weapon-sheet.mjs +++ b/module/applications/sheets/weapon-sheet.mjs @@ -1,6 +1,6 @@ -import LethalFantasyItemSheet from "./base-item-sheet.mjs" +import CthulhuEternalItemSheet from "./base-item-sheet.mjs" -export default class LethalFantasyWeaponSheet extends LethalFantasyItemSheet { +export default class CthulhuEternalWeaponSheet extends CthulhuEternalItemSheet { /** @override */ static DEFAULT_OPTIONS = { classes: ["weapon"], diff --git a/module/documents/roll.mjs b/module/documents/roll.mjs index 17009e9..05de50f 100644 --- a/module/documents/roll.mjs +++ b/module/documents/roll.mjs @@ -1,5 +1,6 @@ import { SYSTEM } from "../config/system.mjs" + export default class CthulhuEternalRoll extends Roll { /** * The HTML template path used to render dice checks of this type diff --git a/module/models/weapon.mjs b/module/models/weapon.mjs index 3378ad6..07af7bc 100644 --- a/module/models/weapon.mjs +++ b/module/models/weapon.mjs @@ -1,6 +1,6 @@ import { SYSTEM } from "../config/system.mjs" -export default class LethalFantasySkill extends foundry.abstract.TypeDataModel { +export default class CthulhuEternalWeapon extends foundry.abstract.TypeDataModel { static defineSchema() { const fields = foundry.data.fields const schema = {} diff --git a/module/utils.mjs b/module/utils.mjs index fc6e33f..39f4596 100644 --- a/module/utils.mjs +++ b/module/utils.mjs @@ -1,5 +1,7 @@ import CthulhuEternalRoll from "./documents/roll.mjs" +import { SystemManager } from './applications/hud/system-manager.js' +import { SYSTEM } from "./config/system.mjs" export default class CthulhuEternalUtils { diff --git a/packs-system/skills/000134.log b/packs-system/skills/000142.log similarity index 100% rename from packs-system/skills/000134.log rename to packs-system/skills/000142.log diff --git a/packs-system/skills/CURRENT b/packs-system/skills/CURRENT index c39c670..76519d9 100644 --- a/packs-system/skills/CURRENT +++ b/packs-system/skills/CURRENT @@ -1 +1 @@ -MANIFEST-000132 +MANIFEST-000140 diff --git a/packs-system/skills/LOG b/packs-system/skills/LOG index 3783327..ee1c654 100644 --- a/packs-system/skills/LOG +++ b/packs-system/skills/LOG @@ -1,8 +1,8 @@ -2025/02/07-17:41:28.897688 7fd3051fa6c0 Recovering log #130 -2025/02/07-17:41:28.908107 7fd3051fa6c0 Delete type=3 #128 -2025/02/07-17:41:28.908173 7fd3051fa6c0 Delete type=0 #130 -2025/02/07-18:05:31.341547 7fd2febff6c0 Level-0 table #135: started -2025/02/07-18:05:31.341579 7fd2febff6c0 Level-0 table #135: 0 bytes OK -2025/02/07-18:05:31.348653 7fd2febff6c0 Delete type=0 #133 -2025/02/07-18:05:31.348812 7fd2febff6c0 Manual compaction at level-0 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end) -2025/02/07-18:05:31.359791 7fd2febff6c0 Manual compaction at level-1 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end) +2025/02/09-18:56:19.542927 7f46adffb6c0 Recovering log #138 +2025/02/09-18:56:19.597959 7f46adffb6c0 Delete type=3 #136 +2025/02/09-18:56:19.598032 7f46adffb6c0 Delete type=0 #138 +2025/02/09-19:16:45.192949 7f46abbff6c0 Level-0 table #143: started +2025/02/09-19:16:45.192979 7f46abbff6c0 Level-0 table #143: 0 bytes OK +2025/02/09-19:16:45.199734 7f46abbff6c0 Delete type=0 #141 +2025/02/09-19:16:45.210582 7f46abbff6c0 Manual compaction at level-0 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end) +2025/02/09-19:16:45.220994 7f46abbff6c0 Manual compaction at level-1 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end) diff --git a/packs-system/skills/LOG.old b/packs-system/skills/LOG.old index 6eda6a0..7622fab 100644 --- a/packs-system/skills/LOG.old +++ b/packs-system/skills/LOG.old @@ -1,8 +1,8 @@ -2025/02/07-07:58:04.988627 7ffae7fff6c0 Recovering log #126 -2025/02/07-07:58:04.998629 7ffae7fff6c0 Delete type=3 #124 -2025/02/07-07:58:04.998698 7ffae7fff6c0 Delete type=0 #126 -2025/02/07-08:34:42.926911 7ffae6bff6c0 Level-0 table #131: started -2025/02/07-08:34:42.926943 7ffae6bff6c0 Level-0 table #131: 0 bytes OK -2025/02/07-08:34:42.933490 7ffae6bff6c0 Delete type=0 #129 -2025/02/07-08:34:42.933666 7ffae6bff6c0 Manual compaction at level-0 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end) -2025/02/07-08:34:42.944681 7ffae6bff6c0 Manual compaction at level-1 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end) +2025/02/09-18:43:17.595623 7f46ac7f86c0 Recovering log #134 +2025/02/09-18:43:17.606503 7f46ac7f86c0 Delete type=3 #132 +2025/02/09-18:43:17.606590 7f46ac7f86c0 Delete type=0 #134 +2025/02/09-18:55:41.771958 7f46abbff6c0 Level-0 table #139: started +2025/02/09-18:55:41.772001 7f46abbff6c0 Level-0 table #139: 0 bytes OK +2025/02/09-18:55:41.779302 7f46abbff6c0 Delete type=0 #137 +2025/02/09-18:55:41.793230 7f46abbff6c0 Manual compaction at level-0 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end) +2025/02/09-18:55:41.793270 7f46abbff6c0 Manual compaction at level-1 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end) diff --git a/packs-system/skills/MANIFEST-000132 b/packs-system/skills/MANIFEST-000132 deleted file mode 100644 index 4e28685a0e3bf2c393fecc418a8972be598721f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 143 zcmdmC8h9Xufss)vC$%g!CnZVGsj?)sJhM2}IX|}`u_&=5zlfcQ_1HlkMa8uIoRrj} zVnr7h3u9wLkCa4{qKq=vG)u;A1~8CU%q&UGEmo{5$f*i(H#P{2@CXemEiPj0g2+!v h^jg5pz{u3f$jQLm#>n!HDKosM9wgER66pYm004SdC+h$J diff --git a/packs-system/skills/MANIFEST-000140 b/packs-system/skills/MANIFEST-000140 new file mode 100644 index 0000000000000000000000000000000000000000..8b9fc121ed5fc97c7aec16289c9b3cc8b1fec9de GIT binary patch literal 143 zcmdmC8h9Xufss)vC$%g!CnZVGsj?)sJhM2}IX|}`u_&=5zlfcQ_1HlkMa8uIoRrj} zVnr7h3u9wLkCa4{qKq=vG)u;A1~8CU%q&UGEmo{5$f*i(H#P{2@CXemEiPj0g2>O0 hslLz6z{u3g$jQLm$H?-IsVzaI2_(`75}5!J0RV?JC^7&5 literal 0 HcmV?d00001