diff --git a/css/fvtt-cthulhu-eternal.css b/css/fvtt-cthulhu-eternal.css index d3495c5..03188f4 100644 --- a/css/fvtt-cthulhu-eternal.css +++ b/css/fvtt-cthulhu-eternal.css @@ -3087,21 +3087,6 @@ i.fvtt-cthulhu-eternal { font-family: var(--font-primary); font-size: calc(var(--font-size-standard) * 1); } -.dice-roll .intro-chat .intro-right ul .nudge-roll { - font-size: calc(var(--font-size-standard) * 1); - margin-left: 2rem; - display: none; -} -.dice-roll .intro-chat .intro-right ul .healing-roll { - font-size: calc(var(--font-size-standard) * 1); - margin-left: 2rem; - display: none; -} -.dice-roll .intro-chat .intro-right ul .roll-damage { - font-size: calc(var(--font-size-standard) * 1); - margin-left: 2rem; - display: none; -} .dice-roll .intro-chat .intro-right ul .result-success { color: var(--color-success); font-family: var(--font-title); @@ -3136,3 +3121,197 @@ i.fvtt-cthulhu-eternal { font-size: calc(var(--font-size-standard) * 1.2); text-shadow: 0 0 10px var(--color-shadow-primary); } +.dice-roll .chat-actions { + display: flex; + flex-wrap: wrap; + gap: 0.375rem; + padding: 0.5rem; + margin-top: 0.5rem; + border-top: 1px solid var(--color-border-light-primary); + background: rgba(0, 0, 0, 0.05); + border-radius: 0 0 5px 5px; + justify-content: center; +} +.dice-roll .chat-actions .chat-action-button { + display: inline-flex !important; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + padding: 0 !important; + margin: 0 !important; + background: var(--color-dark-6); + color: var(--color-light-1); + border: 1px solid var(--color-border-light-primary); + border-radius: 3px; + cursor: pointer; + transition: all 0.2s ease; + text-decoration: none; + line-height: 1; +} +.dice-roll .chat-actions .chat-action-button:hover { + background: var(--color-dark-5); + border-color: var(--color-border-dark); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); + transform: translateY(-1px); +} +.dice-roll .chat-actions .chat-action-button i { + font-size: 1rem !important; + line-height: 1; + display: block; + margin: 0; +} +.dice-roll .chat-actions .nudge-roll, +.dice-roll .chat-actions .damage-roll, +.dice-roll .chat-actions .healing-roll, +.dice-roll .chat-actions .opposed-roll { + display: none; +} +.opposed-roll-result { + padding: 1rem; + background: rgba(0, 0, 0, 0.05); + border-radius: 5px; + font-family: var(--font-primary); +} +.opposed-roll-result .opposed-header { + text-align: center; + margin-bottom: 1rem; + padding-bottom: 0.5rem; + border-bottom: 2px solid var(--color-border-light-primary); +} +.opposed-roll-result .opposed-header h3 { + margin: 0; + font-family: var(--font-title); + font-size: calc(var(--font-size-standard) * 1.2); + color: var(--color-dark-1); +} +.opposed-roll-result .opposed-content { + display: flex; + flex-direction: column; + gap: 1rem; + margin-bottom: 1rem; +} +.opposed-roll-result .opposed-winner, +.opposed-roll-result .opposed-loser { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.75rem; + border-radius: 5px; +} +.opposed-roll-result .opposed-winner { + background: rgba(34, 139, 34, 0.1); + border: 2px solid var(--color-success); +} +.opposed-roll-result .opposed-loser { + background: rgba(220, 20, 60, 0.1); + border: 2px solid var(--color-failure); +} +.opposed-roll-result .character-info { + display: flex; + align-items: center; + gap: 0.75rem; +} +.opposed-roll-result .character-info img { + width: 48px; + height: 48px; + border-radius: 50%; + border: 2px solid var(--color-border-light-primary); +} +.opposed-roll-result .character-info .character-name { + display: flex; + flex-direction: column; + gap: 0.25rem; +} +.opposed-roll-result .character-info .character-name strong { + font-size: calc(var(--font-size-standard) * 0.85); + text-transform: uppercase; + color: var(--color-dark-2); +} +.opposed-roll-result .character-info .character-name .winner-name { + font-size: calc(var(--font-size-standard) * 1.1); + font-weight: bold; + color: var(--color-success); +} +.opposed-roll-result .character-info .character-name .loser-name { + font-size: calc(var(--font-size-standard) * 1.1); + font-weight: bold; + color: var(--color-failure); +} +.opposed-roll-result .roll-result { + display: flex; + align-items: center; + gap: 0.5rem; +} +.opposed-roll-result .roll-result .roll-value { + font-size: calc(var(--font-size-standard) * 1.5); + font-weight: bold; + font-family: var(--font-title); +} +.opposed-roll-result .roll-result .critical-badge { + padding: 0.25rem 0.5rem; + border-radius: 3px; + font-size: calc(var(--font-size-standard) * 0.8); + font-weight: bold; + text-transform: uppercase; + background: var(--color-critical-success); + color: white; +} +.opposed-roll-result .winner-result .roll-value { + color: var(--color-success); +} +.opposed-roll-result .loser-result .roll-value { + color: var(--color-failure); +} +.opposed-roll-result .versus-separator { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 0.5rem 0; + font-size: calc(var(--font-size-standard) * 1.1); + font-weight: bold; + color: var(--color-dark-2); +} +.opposed-roll-result .versus-separator i { + font-size: calc(var(--font-size-standard) * 1.3); +} +.opposed-roll-result .chat-actions { + display: flex; + justify-content: center; + gap: 0.375rem; + padding: 0.75rem; + margin-top: 0.5rem; + border-top: 1px solid var(--color-border-light-primary); + background: rgba(0, 0, 0, 0.05); + border-radius: 0 0 5px 5px; +} +.opposed-roll-result .chat-actions .chat-action-button { + display: inline-flex !important; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + padding: 0 !important; + margin: 0 !important; + background: var(--color-dark-6); + color: var(--color-light-1); + border: 1px solid var(--color-border-light-primary); + border-radius: 3px; + cursor: pointer; + transition: all 0.2s ease; + text-decoration: none; + line-height: 1; +} +.opposed-roll-result .chat-actions .chat-action-button:hover { + background: var(--color-dark-5); + border-color: var(--color-border-dark); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); + transform: translateY(-1px); +} +.opposed-roll-result .chat-actions .chat-action-button i { + font-size: 1rem !important; + line-height: 1; + display: block; + margin: 0; +} diff --git a/cthulhu-eternal.mjs b/cthulhu-eternal.mjs index 9bbbceb..3db0839 100644 --- a/cthulhu-eternal.mjs +++ b/cthulhu-eternal.mjs @@ -14,6 +14,9 @@ import * as applications from "./module/applications/_module.mjs" import { handleSocketEvent } from "./module/socket.mjs" import CthulhuEternalUtils from "./module/utils.mjs" +import { SystemManager } from './module/applications/hud/system-manager.js' +import { MODULE, REQUIRED_CORE_MODULE_VERSION } from './module/applications/hud/constants.js' + 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 () { @@ -142,9 +145,22 @@ Hooks.once("ready", function () { }) + +Hooks.on('tokenActionHudCoreApiReady', async () => { + /** + * Return the SystemManager and requiredCoreModuleVersion to Token Action HUD Core + */ + let module = {} // game.modules.get(MODULE.ID) + module.api = { + requiredCoreModuleVersion: REQUIRED_CORE_MODULE_VERSION, + SystemManager + } + Hooks.call('tokenActionHudSystemReady', module) +}) + Hooks.on("renderChatMessageHTML", (message, html, data) => { // Affichage des boutons de jet de dés uniquement pour les joueurs - if (message.author.id === game.user.id) { + if (message.author.id === game.user.id || game.user.isGM) { $(html).find(".nudge-roll").each((i, btn) => { btn.style.display = "inline" }) @@ -154,6 +170,11 @@ Hooks.on("renderChatMessageHTML", (message, html, data) => { $(html).find(".healing-roll").each((i, btn) => { btn.style.display = "inline" }) + if (game.user.isGM) { + $(html).find(".opposed-roll").each((i, btn) => { + btn.style.display = "inline" + }) + } $(html).find(".nudge-roll").click((event) => { CthulhuEternalUtils.nudgeRoll(message) }) @@ -170,6 +191,9 @@ Hooks.on("renderChatMessageHTML", (message, html, data) => { $(html).find(".san-type").click((event) => { CthulhuEternalUtils.applySANType(message, event) }) + $(html).find(".opposed-roll").click((event) => { + CthulhuEternalUtils.opposedRollManagement(message, event) + }) } if (game.user.isGM) { $(html).find(".li-apply-wounds").each((i, btn) => { diff --git a/lang/en.json b/lang/en.json index 1521482..f03b5dd 100644 --- a/lang/en.json +++ b/lang/en.json @@ -736,7 +736,11 @@ "rangedRange": "Range", "aimingLastRound": "Aiming Last Round (+20)", "aimingWithSight": "Aiming with Sight (+20)", - "applyWounds": "Apply To" + "applyWounds": "Apply To", + "opposedRollWinner": "Opposed Roll Winner", + "opposedRollResult": "Opposed Roll Result", + "defeats": "defeats", + "critical": "Critical" }, "ChatMessage": { "exhausted": "Your protagonist is exhausted. He loses [[/r 1d6]] Willpower Points." @@ -775,7 +779,9 @@ "NoAmmo": "No more ammo for this weapon. ", "noRollDataFound": "No roll data found", "noActorFound": "No actor found for this item.", - "noSanLossFound": "No SAN loss value found." + "noSanLossFound": "No SAN loss value found.", + "opposedRollFirstStored": "First opposed roll stored. Perform and store the second roll to resolve the opposed roll.", + "opposedRollSecondStored": "Second opposed roll stored. The opposed roll is now being resolved." } } } diff --git a/lang/fr.json b/lang/fr.json index 4009483..40f29da 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -618,7 +618,7 @@ "Unarmed": "Désarmé", "Cured": "Soigné", "Uncured": "Non soigné", - "nudgedRoll": "Modifier le jeu", + "nudgedRoll": "Jet modifié : ", "selectNewValue": "Sélectionner une nouvelle valeur", "wpCost": "Cout en PVO", "Hand": "A portée de main", @@ -740,7 +740,10 @@ "stunnedWarning": "Votre protagoniste est étourdi. Il ne peut pas agir tant qu'il n'a pas réussi un test de CON x 5.", "deadWarning": "Votre protagoniste est mourrant. Il mourra s'il n'est pas soigné dans les {con} minutes", "unconsciousWarning": "Votre protagoniste est inconscient. Il ne peut pas agir tant qu'il n'a pas atteint 3 PV.", - "Luck": "Chance", + "luck": "Chance", + "Other": "Autre", + "Skills": "Compétences", + "WP": "PVO", "titleLuck": "Jet de Chance", "healingRoll": "Jet de soin, PV soignés", "healingRollFailure": "Jet de soin échoué critique, PV perdus", @@ -757,7 +760,18 @@ "rangedRange": "Portée", "aimingLastRound": "Visée lors du dernier round (+20)", "aimingWithSight": "Visée avec lunette (+20)", - "applyWounds": "Appliquer à" + "applyWounds": "Appliquer à", + "opposedRollWinner": "Gagnant du jet opposé", + "opposedRollResult": "Résultat du jet opposé", + "defeats": "Défait", + "critical": "Critique", + "other": "Autre", + "str": "FOR", + "dex": "DEX", + "int": "INT", + "pow": "POU", + "con": "CON", + "cha": "CHA" }, "ChatMessage": { "exhausted": "Votre protagoniste est épuisé. Il perd [[/r 1d6]] Points de Volonté." @@ -796,7 +810,9 @@ "NoAmmo": "Aucune munition disponible pour cette arme.", "noRollDataFound": "Aucune donnée de jet trouvée.", "noActorFound": "Aucun protagoniste trouvé.", - "noSanLossFound": "Aucune valeur de perte de SAN trouvée." + "noSanLossFound": "Aucune valeur de perte de SAN trouvée.", + "opposedRollFirstStored": "Premier jet opposé enregistré. Effectuez et enregistrez le deuxième jet pour résoudre le jet opposé.", + "opposedRollSecondStored": "Deuxième jet opposé enregistré. Le jet opposé est maintenant en cours de résolution." } } } diff --git a/module/applications/hud/action-handler.js b/module/applications/hud/action-handler.js index d83821c..a8e2dd8 100644 --- a/module/applications/hud/action-handler.js +++ b/module/applications/hud/action-handler.js @@ -1,6 +1,7 @@ // System Module Imports import { Utils } from './utils.js' import { SYSTEM } from "../../config/system.mjs" + export let ActionHandler = null Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { @@ -38,7 +39,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { * @private */ #buildCharacterActions() { - this.buildAttributes() + this.buildCharacteristics() this.buildOther() this.buildLuck() this.buildSkills() @@ -49,17 +50,17 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { return game.settings.get('token-action-hud-core', 'tooltips') === 'none' } - async buildAttributes() { + async buildCharacteristics() { const actions = [] for (const key in this.actor.system.characteristics) { - const encodedValue = [coreModule.api.Utils.i18n('attributes'), key].join(this.delimiter) + const encodedValue = [coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.characteristics'), 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), + name: coreModule.api.Utils.i18n(`CTHULHUETERNAL.Label.${key}`), id: key, info1: this.#showValue() ? { text: tooltip.content } : null, tooltip, @@ -67,7 +68,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { }) } await this.addActions(actions, { - id: 'attributes', + id: 'characteristics', type: 'system' }) } @@ -80,17 +81,17 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { direction: 'LEFT' } actions.push({ - name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Luck'), + name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.luck'), id: 'luck', info1: this.#showValue() ? { text: '50' } : null, tooltip, - encodedValue: ['attributes', 'luck'].join(this.delimiter) + encodedValue: ['characteristics', 'luck'].join(this.delimiter) }) await this.addActions(actions, { id: 'luck', type: 'system' }) } async buildOther() { - if (typeof this.actor.system.sanity.value !== 'undefined') { + if (typeof this.actor.system?.san?.value !== 'undefined') { const actions = [] const groupData = { id: 'other_sanity', @@ -99,7 +100,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { } this.addGroup(groupData, { id: 'other', type: 'system' }, true) const tooltip = { - content: String(this.actor.system.san.value + '/' + this.actor.system.san.max), + content: `${this.actor.system.san.value}/${this.actor.system.san.max}`, class: 'tah-system-tooltip', direction: 'LEFT' } @@ -108,17 +109,19 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { id: 'sanity', info1: this.#showValue() ? { text: tooltip.content } : null, tooltip, - encodedValue: ['attributes', 'sanity'].join(this.delimiter) + encodedValue: ['characteristics', 'sanity'].join(this.delimiter) }, { name: '+', id: 'sanity_add', - encodedValue: ['attributes', 'sanity_add'].join(this.delimiter) + tooltip, + encodedValue: ['characteristics', 'sanity_add'].join(this.delimiter) }, { name: '-', id: 'sanity_subtract', - encodedValue: ['attributes', 'sanity_subtract'].join(this.delimiter) + tooltip, + encodedValue: ['characteristics', 'sanity_subtract'].join(this.delimiter) }) await this.addActions(actions, { id: 'other_sanity', type: 'system' }) } @@ -131,7 +134,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { } this.addGroup(groupData, { id: 'other', type: 'system' }, true) const tooltip = { - content: String(this.actor.system.hp.value + '/' + this.actor.system.hp.max), + content: `${this.actor.system.hp.value}/${this.actor.system.hp.max}`, class: 'tah-system-tooltip', direction: 'LEFT' } @@ -140,17 +143,19 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { id: 'health', info1: this.#showValue() ? { text: tooltip.content } : null, tooltip, - encodedValue: ['attributes', 'health'].join(this.delimiter) + encodedValue: ['characteristics', 'health'].join(this.delimiter) }, { name: '+', id: 'health_add', - encodedValue: ['attributes', 'health_add'].join(this.delimiter) + tooltip, + encodedValue: ['characteristics', 'health_add'].join(this.delimiter) }, { name: '-', id: 'health_subtract', - encodedValue: ['attributes', 'health_subtract'].join(this.delimiter) + tooltip, + encodedValue: ['characteristics', 'health_subtract'].join(this.delimiter) }) await this.addActions(actions, { id: 'other_health', type: 'system' }) } @@ -163,7 +168,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { } this.addGroup(groupData, { id: 'other', type: 'system' }, true) const tooltip = { - content: String(this.actor.system.wp.value + '/' + this.actor.system.wp.max), + content: `${this.actor.system.wp.value}/${this.actor.system.wp.max}`, class: 'tah-system-tooltip', direction: 'LEFT' } @@ -172,17 +177,19 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { id: 'wp', info1: this.#showValue() ? { text: tooltip.content } : null, tooltip, - encodedValue: ['attributes', 'wp'].join(this.delimiter) + encodedValue: ['characteristics', 'wp'].join(this.delimiter) }, { name: '+', id: 'wp_add', - encodedValue: ['attributes', 'wp_add'].join(this.delimiter) + tooltip, + encodedValue: ['characteristics', 'wp_add'].join(this.delimiter) }, { name: '-', id: 'wp_subtract', - encodedValue: ['attributes', 'wp_subtract'].join(this.delimiter) + tooltip, + encodedValue: ['characteristics', 'wp_subtract'].join(this.delimiter) }) await this.addActions(actions, { id: 'other_wp', type: 'system' }) } @@ -190,19 +197,20 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { async buildSkills() { const actions = [] - let actorSkills = this.actor.items.filter(item => item.type === 'skill') - for (const skill in actorSkills) { - if (skill.system.computeScore() > 0) { + for (const item of this.actor.items) { + if (item.type !== 'skill') continue; + if (item.type === 'skill' && item.system.skillTotal > 0) { + const skill = item const tooltip = { - content: String(skill.skill.system.computeScore()), + content: String(item.system.skillTotal), direction: 'LEFT' } actions.push({ - name: skill.name, + name: `${skill.name} (${skill.system.skillTotal})`, id: skill.id, info1: this.#showValue() ? { text: tooltip.content } : null, tooltip, - encodedValue: ['skills', s].join(this.delimiter) + encodedValue: ['skills', skill.id].join(this.delimiter) }) } } @@ -210,30 +218,24 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { } 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) { + // const rituals = [] + for (const item of this.actor.items) { // 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()), + content: String(item.system.skillTotal), direction: 'LEFT' } weapons.push({ - name: skill.name, - id: skill._id, + name: item.name, + id: item._id, info1: this.#showValue() ? { text: tooltip.content } : null, encodedValue: ['weapons', item._id].join(this.delimiter), tooltip @@ -251,7 +253,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { tooltip: damageTooltip }) } - if (item.system.isLethal) { + if (item.system.lethality > 0) { const lethalityTooltip = { content: String(item.system.lethality), direction: 'LEFT' diff --git a/module/applications/hud/constants.js b/module/applications/hud/constants.js index 8d47e96..8922f46 100644 --- a/module/applications/hud/constants.js +++ b/module/applications/hud/constants.js @@ -1,15 +1,15 @@ /** * Module-based constants */ -export const SYSTEM = { - ID: 'fvtt-cthulhu-eternal' +export const MODULE = { + ID: 'token-action-hud-cthulhu-eternal' } /** * Core module */ export const CORE_MODULE = { - ID: 'token-action-hud-core' + ID: 'token-action-hud-core' } /** @@ -21,18 +21,19 @@ 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' + characteristics: 'CTHULHUETERNAL.Label.characteristics', + skills: 'CTHULHUETERNAL.Label.skills', + 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' } + 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' }, + 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 index 71c5bf5..231718c 100644 --- a/module/applications/hud/defaults.js +++ b/module/applications/hud/defaults.js @@ -6,44 +6,42 @@ import { GROUP } from './constants.js' 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 - } + 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.characteristics, nestId: 'statistics_characteristics' }, + { ...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' } + ] + }, + { + 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/init.js b/module/applications/hud/init.js new file mode 100644 index 0000000..1da4257 --- /dev/null +++ b/module/applications/hud/init.js @@ -0,0 +1,14 @@ +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) +}) diff --git a/module/applications/hud/roll-handler.js b/module/applications/hud/roll-handler.js index 08b0913..06e86ac 100644 --- a/module/applications/hud/roll-handler.js +++ b/module/applications/hud/roll-handler.js @@ -1,304 +1,258 @@ + 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 { /** - * Extends Token Action HUD Core's RollHandler class and handles action events triggered when an action is clicked + * 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 */ - 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('|') + async handleActionClick(event, encodedValue) { + const [actionTypeId, actionId] = encodedValue.split('|') - const knownCharacters = ['character'] + const knownCharacters = ['protagonist', 'creature'] - // If single actor is selected - if (this.actor) { - await this.#handleAction(event, this.actor, this.token, actionTypeId, actionId) - return - } + // 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)) + 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 - } - } + // 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 '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.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)*/ + } + + + /** + * 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 + } + /* TO FIX + 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 + } + /* TOFIX + 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 + } + /* TOFIX + 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/settings.js b/module/applications/hud/settings.js new file mode 100644 index 0000000..ba7f3a7 --- /dev/null +++ b/module/applications/hud/settings.js @@ -0,0 +1,9 @@ +import { MODULE } from './constants.js' + +/** + * Register module settings + * Called by Token Action HUD Core to register Token Action HUD system module settings + * @param {function} coreUpdate Token Action HUD Core update function + */ +export function register (coreUpdate) { +} diff --git a/module/applications/hud/system-manager.js b/module/applications/hud/system-manager.js index 383a596..17dd900 100644 --- a/module/applications/hud/system-manager.js +++ b/module/applications/hud/system-manager.js @@ -1,91 +1,92 @@ // System Module Imports import { ActionHandler } from './action-handler.js' import { RollHandler as Core } from './roll-handler.js' -import { SYSTEM } from './constants.js' +import { MODULE } from './constants.js' import { DEFAULTS } from './defaults.js' +import * as systemSettings from './settings.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 { /** - * Extends Token Action HUD Core's SystemManager class + * Returns an instance of the ActionHandler to Token Action HUD Core + * Called by Token Action HUD Core + * @override + * @returns {class} The ActionHandler instance */ - 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 - } - } - } + 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: MODULE.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 index ec57f96..3f389c0 100644 --- a/module/applications/hud/utils.js +++ b/module/applications/hud/utils.js @@ -1,22 +1,7 @@ -import { SYSTEM } from './constants.js' +import { MODULE } 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 @@ -31,7 +16,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => { static getSetting(key, defaultValue = null) { let value = defaultValue ?? null try { - value = game.settings.get(SYSTEM.ID, key) + value = game.settings.get(MODULE.ID, key) } catch { coreModule.api.Logger.debug(`Setting '${key}' not found`) } diff --git a/module/applications/sheets/base-item-sheet.mjs b/module/applications/sheets/base-item-sheet.mjs index 21acdb3..0805abc 100644 --- a/module/applications/sheets/base-item-sheet.mjs +++ b/module/applications/sheets/base-item-sheet.mjs @@ -94,7 +94,7 @@ export default class CthulhuEternalItemSheet extends HandlebarsApplicationMixin( dragover: this._onDragOver.bind(this), drop: this._onDrop.bind(this), } - return new DragDrop(d) + return new foundry.applications.ux.DragDrop.implementation(d) }) } @@ -141,14 +141,14 @@ export default class CthulhuEternalItemSheet extends HandlebarsApplicationMixin( * @param {DragEvent} event The originating DragEvent * @protected */ - _onDragOver(event) {} + _onDragOver(event) { } /** * Callback actions which occur when a dragged element is dropped on a target. * @param {DragEvent} event The originating DragEvent * @protected */ - async _onDrop(event) {} + async _onDrop(event) { } // #endregion diff --git a/module/config/system.mjs b/module/config/system.mjs index 4062d26..22003f6 100644 --- a/module/config/system.mjs +++ b/module/config/system.mjs @@ -43,167 +43,167 @@ export const INSANITY = { export const ERA_CSS = { jazz: { primaryFont: "RozhaOne", secondaryFont: "RozhaOne", titleFont: "Broadway", baseFontSize: "0.95rem", titleFontSize: "1.2rem", imgFilter: "brightness(0) saturate(100%) invert(52%) sepia(9%) saturate(2368%) hue-rotate(360deg) brightness(86%) contrast(84%)" }, - modern: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "Georama", baseFontSize: "1.0rem", titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(92%) sepia(11%) saturate(1214%) hue-rotate(51deg) brightness(93%) contrast(86%)" }, - future: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "Seabreed", baseFontSize: "1.0rem", titleFontSize: "2.0rem",imgFilter: "invert(90%) sepia(6%) saturate(1818%) hue-rotate(152deg) brightness(91%) contrast(91%)" }, - victorian: { primaryFont: "Volkhov", secondaryFont: "Volkhov", titleFont: "Excelsior", baseFontSize: "1.0rem", titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(100%) sepia(59%) saturate(1894%) hue-rotate(337deg) brightness(88%) contrast(98%)" }, - coldwar: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "TopSecret", baseFontSize: "0.9rem", titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(81%) sepia(14%) saturate(2508%) hue-rotate(202deg) brightness(99%) contrast(105%)"}, - revolution: { primaryFont: "IMFell", secondaryFont: "IMFell", titleFont: "Dominican", baseFontSize: "1.0rem",titleFontSize: "1.3rem",imgFilter: "brightness(0) saturate(100%) invert(81%) sepia(25%) saturate(386%) hue-rotate(7deg) brightness(101%) contrast(84%)" }, - medieval: { primaryFont: "Skranji", secondaryFont: "UncialAntiqua", titleFont: "Luminari", baseFontSize: "0.9rem",titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(93%) sepia(46%) saturate(354%) hue-rotate(321deg) brightness(93%) contrast(87%)"}, - ww2: { primaryFont: "SairaStencilOne", secondaryFont: "SairaStencilOne", titleFont: "Armalite", baseFontSize: "0.9rem",titleFontSize: "1.2rem",imgFilter: "filter: invert(44%) sepia(8%) saturate(2657%) hue-rotate(40deg) brightness(96%) contrast(75%)"}, - ww1: { primaryFont: "CarterOne", secondaryFont: "CarterOne", titleFont: "SigmarOne", baseFontSize: "0.9rem",titleFontSize: "1.1rem",imgFilter: "invert(28%) sepia(27%) saturate(475%) hue-rotate(76deg) brightness(95%) contrast(93%)"}, - ageofsail: { primaryFont: "SailRegular", secondaryFont: "SailRegular", titleFont: "P22Operina", baseFontSize: "1.1rem",titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(43%) sepia(74%) saturate(3154%) hue-rotate(336deg) brightness(95%) contrast(83%)" }, - classical: { primaryFont: "ChantelliAntiqua", secondaryFont: "ChantelliAntiqua", titleFont: "TrajanPro", baseFontSize: "0.9rem",titleFontSize: "1.1rem",imgFilter: "brightness(0) saturate(100%) invert(52%) sepia(32%) saturate(7492%) hue-rotate(265deg) brightness(89%) contrast(95%)" }, - postapo: { primaryFont: "Teko", secondaryFont: "Teko", titleFont: "Teko", baseFontSize: "1.35rem",titleFontSize: "1.5rem",imgFilter: "brightness(0) saturate(100%) invert(44%) sepia(55%) saturate(2341%) hue-rotate(329deg) brightness(122%) contrast(103%))" } + modern: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "Georama", baseFontSize: "1.0rem", titleFontSize: "1.2rem", imgFilter: "brightness(0) saturate(100%) invert(92%) sepia(11%) saturate(1214%) hue-rotate(51deg) brightness(93%) contrast(86%)" }, + future: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "Seabreed", baseFontSize: "1.0rem", titleFontSize: "2.0rem", imgFilter: "invert(90%) sepia(6%) saturate(1818%) hue-rotate(152deg) brightness(91%) contrast(91%)" }, + victorian: { primaryFont: "Volkhov", secondaryFont: "Volkhov", titleFont: "Excelsior", baseFontSize: "1.0rem", titleFontSize: "1.2rem", imgFilter: "brightness(0) saturate(100%) invert(100%) sepia(59%) saturate(1894%) hue-rotate(337deg) brightness(88%) contrast(98%)" }, + coldwar: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "TopSecret", baseFontSize: "0.9rem", titleFontSize: "1.2rem", imgFilter: "brightness(0) saturate(100%) invert(81%) sepia(14%) saturate(2508%) hue-rotate(202deg) brightness(99%) contrast(105%)" }, + revolution: { primaryFont: "IMFell", secondaryFont: "IMFell", titleFont: "Dominican", baseFontSize: "1.0rem", titleFontSize: "1.3rem", imgFilter: "brightness(0) saturate(100%) invert(81%) sepia(25%) saturate(386%) hue-rotate(7deg) brightness(101%) contrast(84%)" }, + medieval: { primaryFont: "Skranji", secondaryFont: "UncialAntiqua", titleFont: "Luminari", baseFontSize: "0.9rem", titleFontSize: "1.2rem", imgFilter: "brightness(0) saturate(100%) invert(93%) sepia(46%) saturate(354%) hue-rotate(321deg) brightness(93%) contrast(87%)" }, + ww2: { primaryFont: "SairaStencilOne", secondaryFont: "SairaStencilOne", titleFont: "Armalite", baseFontSize: "0.9rem", titleFontSize: "1.2rem", imgFilter: "filter: invert(44%) sepia(8%) saturate(2657%) hue-rotate(40deg) brightness(96%) contrast(75%)" }, + ww1: { primaryFont: "CarterOne", secondaryFont: "CarterOne", titleFont: "SigmarOne", baseFontSize: "0.9rem", titleFontSize: "1.1rem", imgFilter: "invert(28%) sepia(27%) saturate(475%) hue-rotate(76deg) brightness(95%) contrast(93%)" }, + ageofsail: { primaryFont: "SailRegular", secondaryFont: "SailRegular", titleFont: "P22Operina", baseFontSize: "1.1rem", titleFontSize: "1.2rem", imgFilter: "brightness(0) saturate(100%) invert(43%) sepia(74%) saturate(3154%) hue-rotate(336deg) brightness(95%) contrast(83%)" }, + classical: { primaryFont: "ChantelliAntiqua", secondaryFont: "ChantelliAntiqua", titleFont: "TrajanPro", baseFontSize: "0.9rem", titleFontSize: "1.1rem", imgFilter: "brightness(0) saturate(100%) invert(52%) sepia(32%) saturate(7492%) hue-rotate(265deg) brightness(89%) contrast(95%)" }, + postapo: { primaryFont: "Teko", secondaryFont: "Teko", titleFont: "Teko", baseFontSize: "1.35rem", titleFontSize: "1.5rem", imgFilter: "brightness(0) saturate(100%) invert(44%) sepia(55%) saturate(2341%) hue-rotate(329deg) brightness(122%) contrast(103%))" } } export const RESOURCE_RATING = { jazz: { - 0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"}, - 4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 700, assets: "CTHULHUETERNAL.Resource.PoorJazz"}, - 8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 3000, assets: "CTHULHUETERNAL.Resource.AverageJazz"}, - 12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 5000, assets: "CTHULHUETERNAL.Resource.AboveAverageJazz"}, - 16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 10000, assets: "CTHULHUETERNAL.Resource.WellOffJazz"}, - 18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 15000, assets: "CTHULHUETERNAL.Resource.RichJazz"}, - 19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 50000, assets: "CTHULHUETERNAL.Resource.VeryRichJazz"}, - 20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 100000, assets: "CTHULHUETERNAL.Resource.SuperRichJazz"} + 0: { name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets" }, + 4: { name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 700, assets: "CTHULHUETERNAL.Resource.PoorJazz" }, + 8: { name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 3000, assets: "CTHULHUETERNAL.Resource.AverageJazz" }, + 12: { name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 5000, assets: "CTHULHUETERNAL.Resource.AboveAverageJazz" }, + 16: { name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 10000, assets: "CTHULHUETERNAL.Resource.WellOffJazz" }, + 18: { name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 15000, assets: "CTHULHUETERNAL.Resource.RichJazz" }, + 19: { name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 50000, assets: "CTHULHUETERNAL.Resource.VeryRichJazz" }, + 20: { name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 100000, assets: "CTHULHUETERNAL.Resource.SuperRichJazz" } }, modern: { - 0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"}, - 4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorModern"}, - 8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageModern"}, - 12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageModern"}, - 16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffModern"}, - 18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 20000, assets: "CTHULHUETERNAL.Resource.RichModern"}, - 19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichModern"}, - 20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichModern"} + 0: { name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets" }, + 4: { name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorModern" }, + 8: { name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageModern" }, + 12: { name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageModern" }, + 16: { name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffModern" }, + 18: { name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 20000, assets: "CTHULHUETERNAL.Resource.RichModern" }, + 19: { name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichModern" }, + 20: { name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichModern" } }, future: { - 0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"}, - 4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorModern"}, - 8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageModern"}, - 12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageModern"}, - 16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffModern"}, - 18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 20000, assets: "CTHULHUETERNAL.Resource.RichModern"}, - 19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichModern"}, - 20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichModern"} + 0: { name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets" }, + 4: { name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorModern" }, + 8: { name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageModern" }, + 12: { name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageModern" }, + 16: { name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffModern" }, + 18: { name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 20000, assets: "CTHULHUETERNAL.Resource.RichModern" }, + 19: { name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichModern" }, + 20: { name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichModern" } }, coldwar: { - 0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"}, - 4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"}, - 8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"}, - 12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"}, - 16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"}, - 18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"}, - 19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"}, - 20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"} + 0: { name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets" }, + 4: { name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar" }, + 8: { name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar" }, + 12: { name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar" }, + 16: { name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar" }, + 18: { name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar" }, + 19: { name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar" }, + 20: { name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar" } }, ww1: { - 0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"}, - 4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"}, - 8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"}, - 12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"}, - 16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"}, - 18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"}, - 19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"}, - 20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"} + 0: { name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets" }, + 4: { name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar" }, + 8: { name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar" }, + 12: { name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar" }, + 16: { name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar" }, + 18: { name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar" }, + 19: { name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar" }, + 20: { name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar" } }, ww2: { - 0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"}, - 4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"}, - 8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"}, - 12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"}, - 16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"}, - 18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"}, - 19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"}, - 20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"} + 0: { name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets" }, + 4: { name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar" }, + 8: { name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar" }, + 12: { name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar" }, + 16: { name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar" }, + 18: { name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar" }, + 19: { name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar" }, + 20: { name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar" } }, medieval: { - 0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"}, - 4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"}, - 8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"}, - 12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"}, - 16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"}, - 18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"}, - 19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"}, - 20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"} + 0: { name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets" }, + 4: { name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar" }, + 8: { name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar" }, + 12: { name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar" }, + 16: { name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar" }, + 18: { name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar" }, + 19: { name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar" }, + 20: { name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar" } }, revolution: { - 0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"}, - 4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"}, - 8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"}, - 12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"}, - 16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"}, - 18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"}, - 19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"}, - 20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"} + 0: { name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets" }, + 4: { name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar" }, + 8: { name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar" }, + 12: { name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar" }, + 16: { name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar" }, + 18: { name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar" }, + 19: { name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar" }, + 20: { name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar" } }, ageofsail: { - 0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"}, - 4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"}, - 8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"}, - 12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"}, - 16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"}, - 18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"}, - 19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"}, - 20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"} + 0: { name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets" }, + 4: { name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar" }, + 8: { name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar" }, + 12: { name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar" }, + 16: { name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar" }, + 18: { name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar" }, + 19: { name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar" }, + 20: { name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar" } }, classical: { - 0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"}, - 4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"}, - 8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"}, - 12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"}, - 16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"}, - 18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"}, - 19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"}, - 20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"} + 0: { name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets" }, + 4: { name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar" }, + 8: { name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar" }, + 12: { name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar" }, + 16: { name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar" }, + 18: { name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar" }, + 19: { name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar" }, + 20: { name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar" } }, postapo: { - 0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"}, - 4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"}, - 8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"}, - 12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"}, - 16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"}, - 18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"}, - 19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"}, - 20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"} + 0: { name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets" }, + 4: { name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar" }, + 8: { name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar" }, + 12: { name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar" }, + 16: { name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar" }, + 18: { name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar" }, + 19: { name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar" }, + 20: { name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar" } }, victorian: { - 0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"}, - 4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 30, assets: "CTHULHUETERNAL.Resource.PoorVictorian"}, - 8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 90, assets: "CTHULHUETERNAL.Resource.AverageVictorian"}, - 12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 400, assets: "CTHULHUETERNAL.Resource.AboveAverageVictorian"}, - 16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 1500, assets: "CTHULHUETERNAL.Resource.WellOffVictorian"}, - 18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 5000, assets: "CTHULHUETERNAL.Resource.RichVictorian"}, - 19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 40000, assets: "CTHULHUETERNAL.Resource.VeryRichVictorian"}, - 20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 200000, assets: "CTHULHUETERNAL.Resource.SuperRichVictorian"} + 0: { name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets" }, + 4: { name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 30, assets: "CTHULHUETERNAL.Resource.PoorVictorian" }, + 8: { name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 90, assets: "CTHULHUETERNAL.Resource.AverageVictorian" }, + 12: { name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 400, assets: "CTHULHUETERNAL.Resource.AboveAverageVictorian" }, + 16: { name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 1500, assets: "CTHULHUETERNAL.Resource.WellOffVictorian" }, + 18: { name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 5000, assets: "CTHULHUETERNAL.Resource.RichVictorian" }, + 19: { name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 40000, assets: "CTHULHUETERNAL.Resource.VeryRichVictorian" }, + 20: { name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 200000, assets: "CTHULHUETERNAL.Resource.SuperRichVictorian" } } } export const RESOURCE_BREAKDOWN = [ - { value: 0, hand: 0, stowed: 0, storage: 0, checks: 0}, - { value: 1, hand: 1, stowed: 0, storage: 0, checks: 1}, - { value: 2, hand: 2, stowed: 0, storage: 0, checks: 1}, - { value: 3, hand: 3, stowed: 0, storage: 0, checks: 1}, - { value: 4, hand: 4, stowed: 0, storage: 0, checks: 1}, - { value: 5, hand: 5, stowed: 0, storage: 0, checks: 1}, - { value: 6, hand: 6, stowed: 0, storage: 0, checks: 1}, - { value: 7, hand: 6, stowed: 1, storage: 0, checks: 2}, - { value: 8, hand: 6, stowed: 2, storage: 0, checks: 2}, - { value: 9, hand: 6, stowed: 3, storage: 0, checks: 2}, - { value: 10, hand: 6, stowed: 4, storage: 0, checks: 2}, - { value: 11, hand: 6, stowed: 5, storage: 0, checks: 2}, - { value: 12, hand: 6, stowed: 6, storage: 0, checks: 2}, - { value: 13, hand: 6, stowed: 6, storage: 1, checks: 3}, - { value: 14, hand: 6, stowed: 6, storage: 2, checks: 3}, - { value: 15, hand: 6, stowed: 6, storage: 3, checks: 3}, - { value: 16, hand: 6, stowed: 6, storage: 4, checks: 3}, - { value: 17, hand: 6, stowed: 6, storage: 5, checks: 3}, - { value: 18, hand: 6, stowed: 6, storage: 6, checks: 3}, - { value: 19, hand: 6, stowed: 6, storage: 7, checks: 3}, - { value: 20, hand: 6, stowed: 6, storage: 8, checks: 3} + { value: 0, hand: 0, stowed: 0, storage: 0, checks: 0 }, + { value: 1, hand: 1, stowed: 0, storage: 0, checks: 1 }, + { value: 2, hand: 2, stowed: 0, storage: 0, checks: 1 }, + { value: 3, hand: 3, stowed: 0, storage: 0, checks: 1 }, + { value: 4, hand: 4, stowed: 0, storage: 0, checks: 1 }, + { value: 5, hand: 5, stowed: 0, storage: 0, checks: 1 }, + { value: 6, hand: 6, stowed: 0, storage: 0, checks: 1 }, + { value: 7, hand: 6, stowed: 1, storage: 0, checks: 2 }, + { value: 8, hand: 6, stowed: 2, storage: 0, checks: 2 }, + { value: 9, hand: 6, stowed: 3, storage: 0, checks: 2 }, + { value: 10, hand: 6, stowed: 4, storage: 0, checks: 2 }, + { value: 11, hand: 6, stowed: 5, storage: 0, checks: 2 }, + { value: 12, hand: 6, stowed: 6, storage: 0, checks: 2 }, + { value: 13, hand: 6, stowed: 6, storage: 1, checks: 3 }, + { value: 14, hand: 6, stowed: 6, storage: 2, checks: 3 }, + { value: 15, hand: 6, stowed: 6, storage: 3, checks: 3 }, + { value: 16, hand: 6, stowed: 6, storage: 4, checks: 3 }, + { value: 17, hand: 6, stowed: 6, storage: 5, checks: 3 }, + { value: 18, hand: 6, stowed: 6, storage: 6, checks: 3 }, + { value: 19, hand: 6, stowed: 6, storage: 7, checks: 3 }, + { value: 20, hand: 6, stowed: 6, storage: 8, checks: 3 } ] -export const DAMAGE_BONUS = [ -2, -2, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2] +export const DAMAGE_BONUS = [-2, -2, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2] export const VEHICLE_SPEED = { "none": "CTHULHUETERNAL.Label.None", @@ -330,10 +330,10 @@ export const MULTIPLIER_CHOICES = { } export const WEAPON_SELECTIVE_FIRE_CHOICES = { - "shortburst": { id: "shortburst", label: "CTHULHUETERNAL.Weapon.SelectiveFire.shortburst", ammoUsed: 3, lethality: 10, killRadius: 0}, - "longburst": { id: "longburst", label: "CTHULHUETERNAL.Weapon.SelectiveFire.longburst", ammoUsed: 5, lethality: 10, killRadius: 1}, - "shortspray": { id: "shortspray", label: "CTHULHUETERNAL.Weapon.SelectiveFire.shortspray", ammoUsed: 10, lethality: 10, killRadius: 2}, - "longspray": { id: "longspray", label: "CTHULHUETERNAL.Weapon.SelectiveFire.longspray", ammoUsed: 20, lethality: 10, killRadius: 3}, + "shortburst": { id: "shortburst", label: "CTHULHUETERNAL.Weapon.SelectiveFire.shortburst", ammoUsed: 3, lethality: 10, killRadius: 0 }, + "longburst": { id: "longburst", label: "CTHULHUETERNAL.Weapon.SelectiveFire.longburst", ammoUsed: 5, lethality: 10, killRadius: 1 }, + "shortspray": { id: "shortspray", label: "CTHULHUETERNAL.Weapon.SelectiveFire.shortspray", ammoUsed: 10, lethality: 10, killRadius: 2 }, + "longspray": { id: "longspray", label: "CTHULHUETERNAL.Weapon.SelectiveFire.longspray", ammoUsed: 20, lethality: 10, killRadius: 3 }, } // Melee stuff diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 59c3833..44914e1 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -69,6 +69,7 @@ export default class CthulhuEternalActor extends Actor { if (this.system.hp.value !== hp) { this.update({ "system.hp.value": hp }) } + console.log("Applying wounds", { woundData, totalArmor, effectiveWounds }) // Chat message for GM only if (game.user.isGM) { let armorText = totalArmor > 0 ? game.i18n.format("CTHULHUETERNAL.Chat.armorAbsorbed", { armor: totalArmor }) : game.i18n.localize("CTHULHUETERNAL.Chat.noArmor") diff --git a/module/documents/roll.mjs b/module/documents/roll.mjs index 4efd0b1..8fa9112 100644 --- a/module/documents/roll.mjs +++ b/module/documents/roll.mjs @@ -142,7 +142,7 @@ export default class CthulhuEternalRoll extends Roll { let combatants = [] if (game?.combat?.combatants) { for (let c of game.combat.combatants) { - if (c.actor.id !== actor.id) { + if (c.actorid !== actor.id) { combatants.push({ id: c.id, name: c.name }) } } @@ -210,8 +210,8 @@ export default class CthulhuEternalRoll extends Roll { modifier += SYSTEM.WEAPON_VISIBILITY[rollData.visibilityChoice]?.modifier || 0 modifier += SYSTEM.WEAPON_ATTACKER_STATE[rollData.attackerStateChoice]?.modifier || 0 modifier += SYSTEM.WEAPON_TARGET_SIZE[rollData.targetSizeChoice]?.modifier || 0 - modifier += (rollData.aimingLastRound) ? 20 : 0 - modifier += (rollData.aimingWithSight) ? 20 : 0 + modifier += (rollData.aimingLastRoundFlag) ? 20 : 0 + modifier += (rollData.aimingWithSightFlag) ? 20 : 0 return modifier } @@ -298,9 +298,9 @@ export default class CthulhuEternalRoll extends Roll { console.log("WP Not found", era, options.rollItem.system.weaponType) return } - if (!target) { + /*if (!target) { ui.notifications.warn(game.i18n.localize("CTHULHUETERNAL.Notifications.AttackNoTarget")) - } + }*/ // Check if the weapon has enouth ammo in case of a firearm if (options.rollItem.system.isFireArm() && options.rollItem.system.ammo.value <= 0) { ui.notifications.warn(game.i18n.localize("CTHULHUETERNAL.Notifications.NoAmmo")) @@ -308,20 +308,9 @@ export default class CthulhuEternalRoll extends Roll { } options.weapon = options.rollItem - if (options.rollItem.system.hasDirectSkill) { - let skillName = options.rollItem.name - options.rollItem = { type: "skill", name: skillName, system: { base: 0, bonus: options.weapon.system.directSkillValue } } - options.initialScore = options.weapon.system.directSkillValue - } else { - let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType]) - options.rollItem = actor.items.find(i => i.type === "skill" && i.name.toLowerCase() === skillName.toLowerCase()) - if (!options.rollItem) { - ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.NoWeaponSkill")) - return - } - options.initialScore = options.rollItem.system.computeScore() - console.log("WEAPON", skillName, era, options.rollItem) - } + options.rollItem = CthulhuEternalUtils.getWeaponSkill(actor, options.rollItem, era) + options.initialScore = options.rollItem.system.skillTotal + console.log("WEAPON", era, options.rollItem) } break default: @@ -374,8 +363,8 @@ export default class CthulhuEternalRoll extends Roll { visibilityChoice: "clear", attackerStateChoice: "normal", targetSizeChoice: "normal", - aimingLastRound: false, - aimingWithSight: false, + aimingLastRoundFlag: false, + aimingWithSightFlag: false, modifier, formula, targetName: target?.name, @@ -424,6 +413,14 @@ export default class CthulhuEternalRoll extends Roll { options.multiplier = Number(event.target.value) this.updateResourceDialog(options) }) + $(".aimingLastRound").change(event => { + options.aimingLastRoundFlag = event.target.checked + this.updateResourceDialog(options) + }) + $(".aimingWithSight").change(event => { + options.aimingWithSightFlag = event.target.checked + this.updateResourceDialog(options) + }) } }) @@ -526,6 +523,8 @@ export default class CthulhuEternalRoll extends Roll { rollData.isFailure = this.options.isFailure rollData.isCritical = this.options.isCritical rollData.resultType = resultType + rollData.rollResult = this.total + rollData.total = this.total this.options.rollData = foundry.utils.duplicate(rollData) // Keep track of the last defense roll for the actor @@ -553,7 +552,7 @@ export default class CthulhuEternalRoll extends Roll { compareRolls(attackRoll, defenseRoll) { if (!defenseRoll || defenseRoll.round !== game?.combat?.round) { - ui.notifications.info(game.i18n.localize("CTHULHUETERNAL.Notifications.NoDefenseRoll")) + // ui.notifications.info(game.i18n.localize("CTHULHUETERNAL.Notifications.NoDefenseRoll")) return } if (attackRoll.isFailure) { @@ -677,7 +676,7 @@ export default class CthulhuEternalRoll extends Roll { * @returns {Promise} - A promise that resolves when the message is created. */ async toMessage(messageData = {}, { rollMode, create = true } = {}) { - super.toMessage( + let rollMsg = await super.toMessage( { isFailure: this.resultType === "failure", actingCharName: this.actorName, @@ -688,10 +687,11 @@ export default class CthulhuEternalRoll extends Roll { }, { rollMode: rollMode }, ) - - // Manage the skill evolution if the roll is a failure let rollData = this.options.rollData || this.options let rollItem = this.options.rollItem + await rollMsg.setFlag("fvtt-cthulhu-eternal", "rollData", rollData) + + // Manage the skill evolution if the roll is a failure if (rollData.resultType.includes("failure") && rollItem.type === "skill") { // Is the skill able to progress if (rollItem.system.diceEvolved && !rollItem.system.rollFailed) { diff --git a/module/models/protagonist.mjs b/module/models/protagonist.mjs index c386315..adef3df 100644 --- a/module/models/protagonist.mjs +++ b/module/models/protagonist.mjs @@ -52,7 +52,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData insanity: new fields.StringField({ required: true, nullable: false, initial: "none", choices: SYSTEM.INSANITY }), }) - schema.damageBonus = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) + schema.damageBonus = new fields.NumberField({ ...requiredInteger, initial: 0, min: -2 }) schema.resources = new fields.SchemaField({ value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }), // Unused but kept for compatibility @@ -129,7 +129,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData dmgBonus = -1 } else if (this.characteristics.str.value <= 16) { dmgBonus = 1 - } else if (this.characteristics.str.value <= 20) { + } else if (this.characteristics.str.value <= 40) { dmgBonus = 2 } if (this.damageBonus !== dmgBonus) { diff --git a/module/utils.mjs b/module/utils.mjs index c702d57..fe83f45 100644 --- a/module/utils.mjs +++ b/module/utils.mjs @@ -16,6 +16,14 @@ export default class CthulhuEternalUtils { config: true, onChange: _ => window.location.reload() }); + game.settings.register("fvtt-cthulhu-eternal", "roll-opposed-store", { + name: "Roll Opposed Store", + hint: "Whether to store opposed roll results for later use", + default: { roll1: null, roll2: null }, + scope: "world", + type: Object, + config: false + }); } static async loadCompendiumData(compendium) { @@ -180,6 +188,53 @@ export default class CthulhuEternalUtils { }); } + /* -------------------------------------------- */ + static removeChatMessageId(messageId) { + if (messageId) { + game.messages.get(messageId)?.delete(); + } + } + + static findChatMessageId(current) { + return HawkmoonUtility.getChatMessageId(HawkmoonUtility.findChatMessage(current)); + } + + static getChatMessageId(node) { + return node?.attributes.getNamedItem('data-message-id')?.value; + } + + static findChatMessage(current) { + return HawkmoonUtility.findNodeMatching(current, it => it.classList.contains('chat-message') && it.attributes.getNamedItem('data-message-id')) + } + + static findNodeMatching(current, predicate) { + if (current) { + if (predicate(current)) { + return current; + } + return HawkmoonUtility.findNodeMatching(current.parentElement, predicate); + } + return undefined; + } + + /* -------------------------------------------- */ + static getWeaponSkill(actor, weapon, era) { + let skill + if (weapon.system.hasDirectSkill) { + let skillName = weapon.name + skill = { type: "skill", name: skillName, system: { base: 0, bonus: weapon.system.directSkillValue, skillTotal: weapon.system.directSkillValue } } + } else { + let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][weapon.system.weaponType]) + skill = actor.items.find(i => i.type === "skill" && i.name.toLowerCase() === skillName.toLowerCase()) + if (!skill) { + ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.NoWeaponSkill")) + return + } + } + return skill + } + + /* -------------------------------------------- */ static async applySANType(rollMessage, event) { let rollData = rollMessage.getFlag("fvtt-cthulhu-eternal", "rollData") if (!rollData) { @@ -248,6 +303,134 @@ export default class CthulhuEternalUtils { }) } + static async opposedRollManagement(rollMessage, event) { + let rollData = rollMessage.getFlag("fvtt-cthulhu-eternal", "rollData") + if (!rollData) { + ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.noRollDataFound")) + return + } + + // Get the store + let store = game.settings.get("fvtt-cthulhu-eternal", "roll-opposed-store") + if (!store.roll1) { + store.roll1 = { + rollData: rollData, + messageId: rollMessage.id + } + await game.settings.set("fvtt-cthulhu-eternal", "roll-opposed-store", store) + ui.notifications.info(game.i18n.localize("CTHULHUETERNAL.Notifications.opposedRollFirstStored")) + } + else if (!store.roll2) { + store.roll2 = { + rollData: rollData, + messageId: rollMessage.id + } + await game.settings.set("fvtt-cthulhu-eternal", "roll-opposed-store", store) + ui.notifications.info(game.i18n.localize("CTHULHUETERNAL.Notifications.opposedRollSecondStored")) + // Now perform the opposed roll resolution + await this.resolveOpposedRolls(store.roll1, store.roll2) + // Clear the store + store.roll1 = null + store.roll2 = null + await game.settings.set("fvtt-cthulhu-eternal", "roll-opposed-store", store) + } + else { + ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.opposedRollStoreFull")) + } + } + + static async resolveOpposedRolls(roll1, roll2) { + // Get actors + let actor1 = game.actors.get(roll1.rollData.actorId) + let actor2 = game.actors.get(roll2.rollData.actorId) + if (!actor1 || !actor2) { + ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.noActorFound")) + return + } + // Determine winner + let winner = null + let loser = null + // If there critical success/failure, apply them first (remark : this d100 results) + roll1.rollData.rollCompare = roll1.rollData.rollResult + roll2.rollData.rollCompare = roll2.rollData.rollResult + if (roll1.rollData.resultType === "successCritical") { + roll1.rollData.rollCompare = -roll1.rollData.rollResult + } + if (roll2.rollData.resultType === "failureCritical") { + roll2.rollData.rollCompare = 100 + roll2.rollData.rollResult + } + if (roll2.rollData.resultType === "successCritical") { + roll2.rollData.rollCompare = -roll2.rollData.rollResult + } + if (roll1.rollData.resultType === "failureCritical") { + roll1.rollData.rollCompare = roll1.rollData.rollResult * 2 + } + if (roll1.rollData.isSuccess && roll2.rollData.isFailure) { + winner = { actor: actor1, rollData: roll1.rollData, messageId: roll1.messageId } + loser = { actor: actor2, rollData: roll2.rollData, messageId: roll2.messageId } + } + else if (roll2.rollData.isSuccess && roll1.rollData.isFailure) { + winner = { actor: actor2, rollData: roll2.rollData, messageId: roll2.messageId } + loser = { actor: actor1, rollData: roll1.rollData, messageId: roll1.messageId } + } + else if (roll1.rollData.rollCompare < roll2.rollData.rollCompare) { + winner = { actor: actor1, rollData: roll1.rollData, messageId: roll1.messageId } + loser = { actor: actor2, rollData: roll2.rollData, messageId: roll2.messageId } + } + else { + winner = { actor: actor2, rollData: roll2.rollData, messageId: roll2.messageId } + loser = { actor: actor1, rollData: roll1.rollData, messageId: roll1.messageId } + } + + console.log("Opposed roll result", winner, loser) + + // Check if winner was attacking with a weapon that can apply damage + let canApplyDamage = winner && winner.rollData?.weapon && winner.rollData.weapon.system + + // Prepare data for the template + let msgData = { + winner: { + actor: { + name: winner.actor.name, + img: winner.actor.img + }, + rollData: { + rollResult: winner.rollData.rollResult || winner.rollData.total, + isCritical: winner.rollData.isCritical, + weapon: winner.rollData.weapon + } + }, + loser: { + actor: { + name: loser.actor.name, + img: loser.actor.img + }, + rollData: { + rollResult: loser.rollData.rollResult || loser.rollData.total, + isCritical: loser.rollData.isCritical + } + }, + canApplyDamage: canApplyDamage + } + + // Render the template + let content = await foundry.applications.handlebars.renderTemplate( + "systems/fvtt-cthulhu-eternal/templates/chat-opposed-result.hbs", + msgData + ) + + // Display the result in chat + let chatMsg = await ChatMessage.create({ + speaker: ChatMessage.getSpeaker({ actor: winner.actor.id }), + content: content + }) + + // Store the winner's roll data for damage roll if applicable + if (canApplyDamage) { + await chatMsg.setFlag("fvtt-cthulhu-eternal", "rollData", winner.rollData) + } + } + static translateRangeUnit(range) { if (typeof range === 'string') { return game.i18n.localize(`CTHULHUETERNAL.Label.${range}`) @@ -285,6 +468,7 @@ export default class CthulhuEternalUtils { ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Label.noActorFound")) return } + console.log("Damage roll data", rollData) rollData.weapon.resultType = rollData.resultType // Keep the result type from the roll message rollData.weapon.selectiveFireChoice = rollData.selectiveFireChoice // Keep the selected fire choice from the roll message @@ -357,6 +541,10 @@ export default class CthulhuEternalUtils { roll.toMessage() actor.system.modifyWP(-dialogContext.wpCost) + + // Delete the initial roll message + await rollMessage.delete() + } static setupCSSRootVariables() { @@ -395,6 +583,10 @@ export default class CthulhuEternalUtils { ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.noActorFound")) return } + console.log("Applying wounds", woundData) + // Remove the chat message + this.removeChatMessageId(message.id) + // Get the targetted actorId from the HTML select event let targetCombatantId = event.target.value let combatant = game.combat.combatants.get(targetCombatantId) diff --git a/packs-system/rituals/000263.log b/packs-system/rituals/000267.log similarity index 100% rename from packs-system/rituals/000263.log rename to packs-system/rituals/000267.log diff --git a/packs-system/rituals/CURRENT b/packs-system/rituals/CURRENT index 1aa57fc..f10934b 100644 --- a/packs-system/rituals/CURRENT +++ b/packs-system/rituals/CURRENT @@ -1 +1 @@ -MANIFEST-000261 +MANIFEST-000265 diff --git a/packs-system/rituals/LOG b/packs-system/rituals/LOG index 2f2be1b..eaf0059 100644 --- a/packs-system/rituals/LOG +++ b/packs-system/rituals/LOG @@ -1,7 +1,7 @@ -2025/10/08-22:08:44.664871 7f77151f96c0 Recovering log #259 -2025/10/08-22:08:44.675676 7f77151f96c0 Delete type=3 #257 -2025/10/08-22:08:44.675773 7f77151f96c0 Delete type=0 #259 -2025/10/08-23:43:02.763720 7f770f3ff6c0 Level-0 table #264: started -2025/10/08-23:43:02.763751 7f770f3ff6c0 Level-0 table #264: 0 bytes OK -2025/10/08-23:43:02.770330 7f770f3ff6c0 Delete type=0 #262 -2025/10/08-23:43:02.770574 7f770f3ff6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end) +2025/11/12-23:40:11.531092 7f47827fc6c0 Recovering log #263 +2025/11/12-23:40:11.541025 7f47827fc6c0 Delete type=0 #263 +2025/11/12-23:40:11.541091 7f47827fc6c0 Delete type=3 #261 +2025/11/12-23:40:47.861546 7f4780bff6c0 Level-0 table #268: started +2025/11/12-23:40:47.861580 7f4780bff6c0 Level-0 table #268: 0 bytes OK +2025/11/12-23:40:47.867844 7f4780bff6c0 Delete type=0 #266 +2025/11/12-23:40:47.874806 7f4780bff6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end) diff --git a/packs-system/rituals/LOG.old b/packs-system/rituals/LOG.old index fb11b64..2f2be1b 100644 --- a/packs-system/rituals/LOG.old +++ b/packs-system/rituals/LOG.old @@ -1,7 +1,7 @@ -2025/10/01-17:34:00.770173 7fc4987f86c0 Recovering log #255 -2025/10/01-17:34:00.786532 7fc4987f86c0 Delete type=3 #253 -2025/10/01-17:34:00.786591 7fc4987f86c0 Delete type=0 #255 -2025/10/01-20:52:25.677932 7fc497ff76c0 Level-0 table #260: started -2025/10/01-20:52:25.677997 7fc497ff76c0 Level-0 table #260: 0 bytes OK -2025/10/01-20:52:26.027584 7fc497ff76c0 Delete type=0 #258 -2025/10/01-20:52:26.508239 7fc497ff76c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end) +2025/10/08-22:08:44.664871 7f77151f96c0 Recovering log #259 +2025/10/08-22:08:44.675676 7f77151f96c0 Delete type=3 #257 +2025/10/08-22:08:44.675773 7f77151f96c0 Delete type=0 #259 +2025/10/08-23:43:02.763720 7f770f3ff6c0 Level-0 table #264: started +2025/10/08-23:43:02.763751 7f770f3ff6c0 Level-0 table #264: 0 bytes OK +2025/10/08-23:43:02.770330 7f770f3ff6c0 Delete type=0 #262 +2025/10/08-23:43:02.770574 7f770f3ff6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end) diff --git a/packs-system/rituals/MANIFEST-000261 b/packs-system/rituals/MANIFEST-000265 similarity index 73% rename from packs-system/rituals/MANIFEST-000261 rename to packs-system/rituals/MANIFEST-000265 index 67f5316..d7cd285 100644 Binary files a/packs-system/rituals/MANIFEST-000261 and b/packs-system/rituals/MANIFEST-000265 differ diff --git a/packs-system/skills/000432.log b/packs-system/skills/000436.log similarity index 100% rename from packs-system/skills/000432.log rename to packs-system/skills/000436.log diff --git a/packs-system/skills/CURRENT b/packs-system/skills/CURRENT index dfab211..f9a97cb 100644 --- a/packs-system/skills/CURRENT +++ b/packs-system/skills/CURRENT @@ -1 +1 @@ -MANIFEST-000430 +MANIFEST-000434 diff --git a/packs-system/skills/LOG b/packs-system/skills/LOG index 23d8c40..46f6b98 100644 --- a/packs-system/skills/LOG +++ b/packs-system/skills/LOG @@ -1,7 +1,7 @@ -2025/10/08-22:08:44.633139 7f77159fa6c0 Recovering log #428 -2025/10/08-22:08:44.643368 7f77159fa6c0 Delete type=3 #426 -2025/10/08-22:08:44.643480 7f77159fa6c0 Delete type=0 #428 -2025/10/08-23:43:02.756716 7f770f3ff6c0 Level-0 table #433: started -2025/10/08-23:43:02.756789 7f770f3ff6c0 Level-0 table #433: 0 bytes OK -2025/10/08-23:43:02.763557 7f770f3ff6c0 Delete type=0 #431 -2025/10/08-23:43:02.770557 7f770f3ff6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end) +2025/11/12-23:40:11.502931 7f4781ffb6c0 Recovering log #432 +2025/11/12-23:40:11.512928 7f4781ffb6c0 Delete type=0 #432 +2025/11/12-23:40:11.512984 7f4781ffb6c0 Delete type=3 #430 +2025/11/12-23:40:47.855365 7f4780bff6c0 Level-0 table #437: started +2025/11/12-23:40:47.855411 7f4780bff6c0 Level-0 table #437: 0 bytes OK +2025/11/12-23:40:47.861414 7f4780bff6c0 Delete type=0 #435 +2025/11/12-23:40:47.874794 7f4780bff6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end) diff --git a/packs-system/skills/LOG.old b/packs-system/skills/LOG.old index 646481e..23d8c40 100644 --- a/packs-system/skills/LOG.old +++ b/packs-system/skills/LOG.old @@ -1,7 +1,7 @@ -2025/10/01-17:34:00.727436 7fc499ffb6c0 Recovering log #424 -2025/10/01-17:34:00.744993 7fc499ffb6c0 Delete type=3 #422 -2025/10/01-17:34:00.745065 7fc499ffb6c0 Delete type=0 #424 -2025/10/01-20:52:26.571766 7fc497ff76c0 Level-0 table #429: started -2025/10/01-20:52:26.571816 7fc497ff76c0 Level-0 table #429: 0 bytes OK -2025/10/01-20:52:26.607301 7fc497ff76c0 Delete type=0 #427 -2025/10/01-20:52:26.607477 7fc497ff76c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end) +2025/10/08-22:08:44.633139 7f77159fa6c0 Recovering log #428 +2025/10/08-22:08:44.643368 7f77159fa6c0 Delete type=3 #426 +2025/10/08-22:08:44.643480 7f77159fa6c0 Delete type=0 #428 +2025/10/08-23:43:02.756716 7f770f3ff6c0 Level-0 table #433: started +2025/10/08-23:43:02.756789 7f770f3ff6c0 Level-0 table #433: 0 bytes OK +2025/10/08-23:43:02.763557 7f770f3ff6c0 Delete type=0 #431 +2025/10/08-23:43:02.770557 7f770f3ff6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end) diff --git a/packs-system/skills/MANIFEST-000430 b/packs-system/skills/MANIFEST-000434 similarity index 71% rename from packs-system/skills/MANIFEST-000430 rename to packs-system/skills/MANIFEST-000434 index 38fe1d7..2a474b4 100644 Binary files a/packs-system/skills/MANIFEST-000430 and b/packs-system/skills/MANIFEST-000434 differ diff --git a/packs-system/weapons/000078.log b/packs-system/weapons/000082.log similarity index 100% rename from packs-system/weapons/000078.log rename to packs-system/weapons/000082.log diff --git a/packs-system/weapons/CURRENT b/packs-system/weapons/CURRENT index f24fe8e..e73ded3 100644 --- a/packs-system/weapons/CURRENT +++ b/packs-system/weapons/CURRENT @@ -1 +1 @@ -MANIFEST-000076 +MANIFEST-000080 diff --git a/packs-system/weapons/LOG b/packs-system/weapons/LOG index 262e1bf..722ae6c 100644 --- a/packs-system/weapons/LOG +++ b/packs-system/weapons/LOG @@ -1,7 +1,7 @@ -2025/10/08-22:08:44.648914 7f770ffff6c0 Recovering log #74 -2025/10/08-22:08:44.660220 7f770ffff6c0 Delete type=3 #72 -2025/10/08-22:08:44.660388 7f770ffff6c0 Delete type=0 #74 -2025/10/08-23:43:02.832863 7f770f3ff6c0 Level-0 table #79: started -2025/10/08-23:43:02.832918 7f770f3ff6c0 Level-0 table #79: 0 bytes OK -2025/10/08-23:43:02.839997 7f770f3ff6c0 Delete type=0 #77 -2025/10/08-23:43:02.852551 7f770f3ff6c0 Manual compaction at level-0 from '!folders!0DI3T2jve3nsmsfZ' @ 72057594037927935 : 1 .. '!items!zyxA9DhO36t5OBDv' @ 0 : 0; will stop at (end) +2025/11/12-23:40:11.517421 7f4782ffd6c0 Recovering log #78 +2025/11/12-23:40:11.527038 7f4782ffd6c0 Delete type=0 #78 +2025/11/12-23:40:11.527106 7f4782ffd6c0 Delete type=3 #76 +2025/11/12-23:40:47.867960 7f4780bff6c0 Level-0 table #83: started +2025/11/12-23:40:47.867984 7f4780bff6c0 Level-0 table #83: 0 bytes OK +2025/11/12-23:40:47.874660 7f4780bff6c0 Delete type=0 #81 +2025/11/12-23:40:47.874816 7f4780bff6c0 Manual compaction at level-0 from '!folders!0DI3T2jve3nsmsfZ' @ 72057594037927935 : 1 .. '!items!zyxA9DhO36t5OBDv' @ 0 : 0; will stop at (end) diff --git a/packs-system/weapons/LOG.old b/packs-system/weapons/LOG.old index af5e0d0..262e1bf 100644 --- a/packs-system/weapons/LOG.old +++ b/packs-system/weapons/LOG.old @@ -1,7 +1,7 @@ -2025/10/01-17:34:00.750882 7fc4997fa6c0 Recovering log #70 -2025/10/01-17:34:00.765634 7fc4997fa6c0 Delete type=3 #68 -2025/10/01-17:34:00.765703 7fc4997fa6c0 Delete type=0 #70 -2025/10/01-20:52:26.472838 7fc497ff76c0 Level-0 table #75: started -2025/10/01-20:52:26.472892 7fc497ff76c0 Level-0 table #75: 0 bytes OK -2025/10/01-20:52:26.508046 7fc497ff76c0 Delete type=0 #73 -2025/10/01-20:52:26.508280 7fc497ff76c0 Manual compaction at level-0 from '!folders!0DI3T2jve3nsmsfZ' @ 72057594037927935 : 1 .. '!items!zyxA9DhO36t5OBDv' @ 0 : 0; will stop at (end) +2025/10/08-22:08:44.648914 7f770ffff6c0 Recovering log #74 +2025/10/08-22:08:44.660220 7f770ffff6c0 Delete type=3 #72 +2025/10/08-22:08:44.660388 7f770ffff6c0 Delete type=0 #74 +2025/10/08-23:43:02.832863 7f770f3ff6c0 Level-0 table #79: started +2025/10/08-23:43:02.832918 7f770f3ff6c0 Level-0 table #79: 0 bytes OK +2025/10/08-23:43:02.839997 7f770f3ff6c0 Delete type=0 #77 +2025/10/08-23:43:02.852551 7f770f3ff6c0 Manual compaction at level-0 from '!folders!0DI3T2jve3nsmsfZ' @ 72057594037927935 : 1 .. '!items!zyxA9DhO36t5OBDv' @ 0 : 0; will stop at (end) diff --git a/packs-system/weapons/MANIFEST-000076 b/packs-system/weapons/MANIFEST-000080 similarity index 73% rename from packs-system/weapons/MANIFEST-000076 rename to packs-system/weapons/MANIFEST-000080 index b28ff79..f31eb11 100644 Binary files a/packs-system/weapons/MANIFEST-000076 and b/packs-system/weapons/MANIFEST-000080 differ diff --git a/styles/roll.less b/styles/roll.less index 6713c16..9f40cd6 100644 --- a/styles/roll.less +++ b/styles/roll.less @@ -97,21 +97,6 @@ font-family: var(--font-primary); font-size: calc(var(--font-size-standard) * 1); } - .nudge-roll { - font-size: calc(var(--font-size-standard) * 1); - margin-left: 2rem; - display: none; - } - .healing-roll { - font-size: calc(var(--font-size-standard) * 1); - margin-left: 2rem; - display: none; - } - .roll-damage { - font-size: calc(var(--font-size-standard) * 1); - margin-left: 2rem; - display: none; - } .result-success { color: var(--color-success); font-family: var(--font-title); @@ -149,4 +134,227 @@ font-size: calc(var(--font-size-standard) * 1.2); text-shadow: 0 0 10px var(--color-shadow-primary); } + + .chat-actions { + display: flex; + flex-wrap: wrap; + gap: 0.375rem; + padding: 0.5rem; + margin-top: 0.5rem; + border-top: 1px solid var(--color-border-light-primary); + background: rgba(0, 0, 0, 0.05); + border-radius: 0 0 5px 5px; + justify-content: center; + + .chat-action-button { + display: inline-flex !important; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + padding: 0 !important; + margin: 0 !important; + background: var(--color-dark-6); + color: var(--color-light-1); + border: 1px solid var(--color-border-light-primary); + border-radius: 3px; + cursor: pointer; + transition: all 0.2s ease; + text-decoration: none; + line-height: 1; + + &:hover { + background: var(--color-dark-5); + border-color: var(--color-border-dark); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); + transform: translateY(-1px); + } + + i { + font-size: 1rem !important; + line-height: 1; + display: block; + margin: 0; + } + } + + .nudge-roll, + .damage-roll, + .healing-roll, + .opposed-roll { + display: none; + } + } +} + +.opposed-roll-result { + padding: 1rem; + background: rgba(0, 0, 0, 0.05); + border-radius: 5px; + font-family: var(--font-primary); + + .opposed-header { + text-align: center; + margin-bottom: 1rem; + padding-bottom: 0.5rem; + border-bottom: 2px solid var(--color-border-light-primary); + + h3 { + margin: 0; + font-family: var(--font-title); + font-size: calc(var(--font-size-standard) * 1.2); + color: var(--color-dark-1); + } + } + + .opposed-content { + display: flex; + flex-direction: column; + gap: 1rem; + margin-bottom: 1rem; + } + + .opposed-winner, + .opposed-loser { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.75rem; + border-radius: 5px; + } + + .opposed-winner { + background: rgba(34, 139, 34, 0.1); + border: 2px solid var(--color-success); + } + + .opposed-loser { + background: rgba(220, 20, 60, 0.1); + border: 2px solid var(--color-failure); + } + + .character-info { + display: flex; + align-items: center; + gap: 0.75rem; + + img { + width: 48px; + height: 48px; + border-radius: 50%; + border: 2px solid var(--color-border-light-primary); + } + + .character-name { + display: flex; + flex-direction: column; + gap: 0.25rem; + + strong { + font-size: calc(var(--font-size-standard) * 0.85); + text-transform: uppercase; + color: var(--color-dark-2); + } + + .winner-name { + font-size: calc(var(--font-size-standard) * 1.1); + font-weight: bold; + color: var(--color-success); + } + + .loser-name { + font-size: calc(var(--font-size-standard) * 1.1); + font-weight: bold; + color: var(--color-failure); + } + } + } + + .roll-result { + display: flex; + align-items: center; + gap: 0.5rem; + + .roll-value { + font-size: calc(var(--font-size-standard) * 1.5); + font-weight: bold; + font-family: var(--font-title); + } + + .critical-badge { + padding: 0.25rem 0.5rem; + border-radius: 3px; + font-size: calc(var(--font-size-standard) * 0.8); + font-weight: bold; + text-transform: uppercase; + background: var(--color-critical-success); + color: white; + } + } + + .winner-result .roll-value { + color: var(--color-success); + } + + .loser-result .roll-value { + color: var(--color-failure); + } + + .versus-separator { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 0.5rem 0; + font-size: calc(var(--font-size-standard) * 1.1); + font-weight: bold; + color: var(--color-dark-2); + + i { + font-size: calc(var(--font-size-standard) * 1.3); + } + } + + .chat-actions { + display: flex; + justify-content: center; + gap: 0.375rem; + padding: 0.75rem; + margin-top: 0.5rem; + border-top: 1px solid var(--color-border-light-primary); + background: rgba(0, 0, 0, 0.05); + border-radius: 0 0 5px 5px; + + .chat-action-button { + display: inline-flex !important; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + padding: 0 !important; + margin: 0 !important; + background: var(--color-dark-6); + color: var(--color-light-1); + border: 1px solid var(--color-border-light-primary); + border-radius: 3px; + cursor: pointer; + transition: all 0.2s ease; + text-decoration: none; + line-height: 1; + + &:hover { + background: var(--color-dark-5); + border-color: var(--color-border-dark); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); + transform: translateY(-1px); + } + + i { + font-size: 1rem !important; + line-height: 1; + display: block; + margin: 0; + } + } + } } diff --git a/templates/chat-message.hbs b/templates/chat-message.hbs index 70b23f5..255f8f5 100644 --- a/templates/chat-message.hbs +++ b/templates/chat-message.hbs @@ -6,6 +6,7 @@
+ {{#if isDamage}}
{{#if (and isGM hasTarget)}} @@ -221,4 +142,86 @@ {{{tooltip}}}
{{/unless}} + + {{! Zone d'actions regroupées }} +
+ {{#if isSuccess}} + {{#if isNudge}} + + + + {{/if}} + + {{#if (eq rollType "weapon")}} + {{#if (eq weapon.system.weaponType "rangedfirearm")}} + {{#if weapon.system.hasDamageDistance}} + {{#each weapon.system.damageDistance as |damageDistance|}} + {{#if (gt damageDistance.distance 0)}} + + + + {{/if}} + {{/each}} + {{else}} + + + + {{/if}} + {{else}} + + + + {{/if}} + {{/if}} + + {{#if (eq rollType "skill")}} + {{#if rollItem.system.isHealing}} + + + + {{/if}} + {{/if}} + {{/if}} + + {{#if isFailure}} + {{#if isNudge}} + + + + {{/if}} + {{/if}} + + + + +
\ No newline at end of file diff --git a/templates/chat-opposed-result.hbs b/templates/chat-opposed-result.hbs new file mode 100644 index 0000000..a008fd0 --- /dev/null +++ b/templates/chat-opposed-result.hbs @@ -0,0 +1,64 @@ +w{{! Template for opposed roll result }} +
+
+

{{localize "CTHULHUETERNAL.Label.opposedRollResult"}}

+
+ +
+
+
+ {{winner.actor.name}} +
+ {{localize "CTHULHUETERNAL.Label.opposedRollWinner"}} + {{winner.actor.name}} +
+
+
+ {{winner.rollData.rollResult}} + {{#if winner.rollData.isCritical}} + {{localize + "CTHULHUETERNAL.Label.critical" + }} + {{/if}} +
+
+ +
+ + {{localize "CTHULHUETERNAL.Label.defeats"}} +
+ +
+
+ {{loser.actor.name}} +
+ {{loser.actor.name}} +
+
+
+ {{loser.rollData.rollResult}} + {{#if loser.rollData.isCritical}} + {{localize + "CTHULHUETERNAL.Label.critical" + }} + {{/if}} +
+
+
+ + {{#if canApplyDamage}} +
+ + {{#if (eq winner.rollData.weapon.system.weaponType "rangedfirearm")}} + + {{else}} + + {{/if}} + +
+ {{/if}} +
\ No newline at end of file diff --git a/templates/roll-dialog.hbs b/templates/roll-dialog.hbs index 2a5dac7..0a3416d 100644 --- a/templates/roll-dialog.hbs +++ b/templates/roll-dialog.hbs @@ -1,135 +1,214 @@
{{#if (eq rollType "skill")}} - {{localize "CTHULHUETERNAL.Label.skill"}} + {{localize "CTHULHUETERNAL.Label.skill"}} {{/if}} {{#if (eq rollType "char")}} - {{localize "CTHULHUETERNAL.Label.characteristic"}} + {{localize "CTHULHUETERNAL.Label.characteristic"}} {{/if}} {{#if (eq rollType "resource")}} - {{localize "CTHULHUETERNAL.Label.resourceRating"}} -
{{rollItem.name}} : {{initialScore}} ({{mul initialScore - 5}}%)
-
{{localize "CTHULHUETERNAL.Label.Hand"}} : {{rollItem.hand}}
-
{{localize "CTHULHUETERNAL.Label.Stowed"}} : {{rollItem.stowed}}
-
- {{localize "CTHULHUETERNAL.Label.Storage"}} : {{rollItem.storage}} - -
+ {{localize "CTHULHUETERNAL.Label.resourceRating"}} +
{{rollItem.name}} + : + {{initialScore}} + ({{mul initialScore 5}}%)
+
{{localize "CTHULHUETERNAL.Label.Hand"}} + : + {{rollItem.hand}} +
+
{{localize "CTHULHUETERNAL.Label.Stowed"}} + : + {{rollItem.stowed}} +
+
+ {{localize "CTHULHUETERNAL.Label.Storage"}} + : + {{rollItem.storage}} + +
{{else}} -
{{rollItem.name}} : {{initialScore}}%
+
{{rollItem.name}} : {{initialScore}}%
{{/if}} {{#if weapon}} -
{{localize "CTHULHUETERNAL.Label.Weapon"}} : {{weapon.name}}
+
{{localize "CTHULHUETERNAL.Label.Weapon"}} + : + {{weapon.name}}
- {{#if targetName}} -
{{localize "CTHULHUETERNAL.Label.Target"}} : {{targetName}}
- {{/if}} + {{#if targetName}} +
{{localize "CTHULHUETERNAL.Label.Target"}} + : + {{targetName}}
+ {{/if}} + {{#if (eq weapon.system.weaponType "melee")}} +
+ {{localize "CTHULHUETERNAL.Label.targetMove"}} + +
+ {{/if}} + {{#if isRangedWeapon}} +
+ {{localize "CTHULHUETERNAL.Label.rangedRange"}} + +
+
+ {{localize "CTHULHUETERNAL.Label.targetMove"}} + +
- {{#if (eq weapon.system.weaponType "melee")}} -
- {{localize "CTHULHUETERNAL.Label.targetMove"}} - -
- {{/if}} - {{#if isRangedWeapon}} -
- {{localize "CTHULHUETERNAL.Label.rangedRange"}} - -
-
- {{localize "CTHULHUETERNAL.Label.targetMove"}} - -
+
+ {{localize "CTHULHUETERNAL.Label.aimingLastRound"}} + +
+ {{#if weapon.system.hasSight}} +
+ {{localize "CTHULHUETERNAL.Label.aimingWithSight"}} + +
+ {{/if}} -
- {{localize "CTHULHUETERNAL.Label.aimingLastRound"}} - -
- {{#if weapon.system.hasSight}} -
- {{localize "CTHULHUETERNAL.Label.aimingWithSight"}} - -
- {{/if}} + {{/if}} - {{/if}} +
+ {{localize "CTHULHUETERNAL.Label.visibility"}} + +
+
+ {{localize "CTHULHUETERNAL.Label.attackerState"}} + +
+
+ {{localize "CTHULHUETERNAL.Label.targetSize"}} + +
-
- {{localize "CTHULHUETERNAL.Label.visibility"}} - -
-
- {{localize "CTHULHUETERNAL.Label.attackerState"}} - -
-
- {{localize "CTHULHUETERNAL.Label.targetSize"}} - -
- - {{#if weapon.system.hasSelectiveFire}} -
Selective Fire : - -
- {{/if}} + {{#if weapon.system.hasSelectiveFire}} +
Selective Fire : + +
+ {{/if}} {{/if}} {{#if isZeroWP}} -
{{localize "CTHULHUETERNAL.Label.ZeroWP"}}
+
{{localize + "CTHULHUETERNAL.Label.ZeroWP" + }}
{{else}} - {{#if isLowWP}} -
{{localize "CTHULHUETERNAL.Label.LowWP"}} : -20%
- {{/if}} + {{#if isLowWP}} +
{{localize + "CTHULHUETERNAL.Label.LowWP" + }} + : -20%
+ {{/if}} {{/if}} {{#if isExhausted}} -
{{localize "CTHULHUETERNAL.Label.Exhausted"}} : -20%
+
{{localize + "CTHULHUETERNAL.Label.Exhausted" + }} + : -20%
{{/if}}
- {{#if hasModifier}} -
- {{localize "CTHULHUETERNAL.Label.modifier"}} - -
+
+ {{localize "CTHULHUETERNAL.Label.modifier"}} + +
{{/if}} {{#if hasMultiplier}} -
- {{localize "CTHULHUETERNAL.Label.multiplier"}} - -
+
+ {{localize "CTHULHUETERNAL.Label.multiplier"}} + +
{{/if}}