From e545e3f0308d4e967ffe6d621201471e15495fc5 Mon Sep 17 00:00:00 2001 From: Johannes Loher Date: Mon, 29 Mar 2021 21:20:08 +0200 Subject: [PATCH] Refactor for better readability (addressed CR comments) --- src/lang/de.json | 4 +-- src/module/actor/actor.ts | 14 +++++----- src/module/macros/helpers.ts | 21 +++++++++++++++ src/module/macros/roll-check.ts | 46 +++++++++++++++++++-------------- src/module/macros/roll-item.ts | 44 +++++++++++++++++-------------- 5 files changed, 80 insertions(+), 49 deletions(-) create mode 100644 src/module/macros/helpers.ts diff --git a/src/lang/de.json b/src/lang/de.json index 1da1dea..aa8c268 100644 --- a/src/lang/de.json +++ b/src/lang/de.json @@ -197,8 +197,8 @@ "DS4.ErrorUnexpectedAttackType": "Unerwartete Angriffsart '{actualType}', erwartete Angriffarten: {expectedTypes}", "DS4.ErrorCanvasIsNotInitialized": "Canvas ist noch nicht initialisiert.", "DS4.WarningItemMustBeEquippedToBeRolled": "Um für das Item '{name}' ({id}) vom Typ '{type}' zu würfeln, muss es ausgerüstet sein.", - "DS4.WarningMustControlActorToUseRollItemMacro": "Um ein ein Item Würfel Makro zu nutzen muss ein Aktor kontolliert werden.", - "DS4.WarningMustControlActorToUseRollCheckMacro": "Um ein ein Proben Würfel Makro zu nutzen muss ein Aktor kontolliert werden.", + "DS4.WarningMustControlActorToUseRollItemMacro": "Um ein ein Item-Würfel-Makro zu nutzen muss ein Aktor kontrolliert werden.", + "DS4.WarningMustControlActorToUseRollCheckMacro": "Um ein ein Proben-Würfel-Makro zu nutzen muss ein Aktor kontrolliert werden.", "DS4.WarningControlledActorDoesNotHaveItem": "Der kontrollierte Aktor '{actorName}' ({actorId}) hat kein Item mit der ID '{itemId}'.", "DS4.WarningItemIsNotRollable": "Für das Item '{name}' ({id}) vom Typ '{type}' kann nicht gewürfelt werden.", "DS4.WarningMacrosCanOnlyBeCreatedForOwnedItems": "Makros können nur für besessene Items angelegt werden.", diff --git a/src/module/actor/actor.ts b/src/module/actor/actor.ts index 1cf678f..17b03b9 100644 --- a/src/module/actor/actor.ts +++ b/src/module/actor/actor.ts @@ -116,13 +116,13 @@ export class DS4Actor extends Actor * The list of properties that are derived from others, given in dot notation. */ get derivedDataProperties(): Array { - return Object.keys(DS4.i18n.combatValues) - .map((combatValue) => `data.combatValues.${combatValue}.total`) - .concat( - Object.keys(DS4.i18n.checks) - .filter((check) => check !== "defend") - .map((check) => `data.checks.${check}`), - ); + const combatValueProperties = Object.keys(DS4.i18n.combatValues).map( + (combatValue) => `data.combatValues.${combatValue}.total`, + ); + const checkProperties = Object.keys(DS4.i18n.checks) + .filter((check) => check !== "defend") + .map((check) => `data.checks.${check}`); + return combatValueProperties.concat(checkProperties); } /** diff --git a/src/module/macros/helpers.ts b/src/module/macros/helpers.ts new file mode 100644 index 0000000..73ee809 --- /dev/null +++ b/src/module/macros/helpers.ts @@ -0,0 +1,21 @@ +import { DS4Actor } from "../actor/actor"; +import { getCanvas } from "../helpers"; + +/** + * Gets the currently active actor based on how {@link ChatMessage} determines + * the current speaker. + * @returns The currently active {@link DS4Actor} if any, and `undefined` otherwise. + */ +export function getActiveActor(): DS4Actor | undefined { + const speaker = ChatMessage.getSpeaker(); + + const speakerToken = speaker.token ? getCanvas().tokens.get(speaker.token) : undefined; + if (speakerToken) { + return speakerToken.actor as DS4Actor; + } + + const speakerActor = speaker.actor ? game.actors?.get(speaker.actor) : undefined; + if (speakerActor) { + return speakerActor as DS4Actor; + } +} diff --git a/src/module/macros/roll-check.ts b/src/module/macros/roll-check.ts index 93bcd40..e6d191b 100644 --- a/src/module/macros/roll-check.ts +++ b/src/module/macros/roll-check.ts @@ -1,8 +1,7 @@ -import { DS4Actor } from "../actor/actor"; import { Check } from "../actor/actor-prepared-data"; import { DS4 } from "../config"; -import { getCanvas } from "../helpers"; import notifications from "../ui/notifications"; +import { getActiveActor } from "./helpers"; /** * Creates a macro from a check drop. @@ -11,33 +10,40 @@ import notifications from "../ui/notifications"; * @param slot - The hotbar slot to use. */ export async function createRollCheckMacro(check: Check, slot: string): Promise { - const command = `game.ds4.macros.rollCheck("${check}");`; - const macro = - game.macros?.entities.find((m) => m.name === DS4.i18n.checks[check] && m.data.command === command) ?? - (await Macro.create( - { - command, - name: DS4.i18n.checks[check], - type: "script", - // TODO: img, should be addressed in https://git.f3l.de/dungeonslayers/ds4/-/issues/79 - flags: { "ds4.checkMacro": true }, - }, - { displaySheet: false }, - )); + const macro = await getOrCreateRollCheckMacro(check); game.user?.assignHotbarMacro(macro, slot); } +async function getOrCreateRollCheckMacro(check: Check): Promise { + const command = `game.ds4.macros.rollCheck("${check}");`; + + const existingMacro = game.macros?.entities.find( + (m) => m.name === DS4.i18n.checks[check] && m.data.command === command, + ); + if (existingMacro) { + return existingMacro; + } + + return Macro.create( + { + command, + name: DS4.i18n.checks[check], + type: "script", + // TODO: img, should be addressed in https://git.f3l.de/dungeonslayers/ds4/-/issues/79 + flags: { "ds4.checkMacro": true }, + }, + { displaySheet: false }, + ); +} + /** * Executes the roll check macro for the given check. */ export async function rollCheck(check: Check): Promise { - const speaker = ChatMessage.getSpeaker(); - const actor = (getCanvas().tokens.get(speaker.token ?? "")?.actor ?? game.actors?.get(speaker.actor ?? "")) as - | DS4Actor - | null - | undefined; + const actor = getActiveActor(); if (!actor) { return notifications.warn(game.i18n.localize("DS4.WarningMustControlActorToUseRollCheckMacro")); } + return actor.rollCheck(check); } diff --git a/src/module/macros/roll-item.ts b/src/module/macros/roll-item.ts index 3dac24b..ec85fdd 100644 --- a/src/module/macros/roll-item.ts +++ b/src/module/macros/roll-item.ts @@ -1,7 +1,6 @@ -import { DS4Actor } from "../actor/actor"; -import { getCanvas } from "../helpers"; import { DS4ItemData } from "../item/item-data"; import notifications from "../ui/notifications"; +import { getActiveActor } from "./helpers"; /** * Creates a macro from an item drop. @@ -10,34 +9,39 @@ import notifications from "../ui/notifications"; * @param slot - The hotbar slot to use */ export async function createRollItemMacro(itemData: DS4ItemData, slot: string): Promise { - const command = `game.ds4.macros.rollItem("${itemData._id}");`; - const macro = - game.macros?.entities.find((m) => m.name === itemData.name && m.data.command === command) ?? - (await Macro.create( - { - command, - name: itemData.name, - type: "script", - img: itemData.img, - flags: { "ds4.itemMacro": true }, - }, - { displaySheet: false }, - )); + const macro = await getOrCreateRollItemMacro(itemData); game.user?.assignHotbarMacro(macro, slot); } +async function getOrCreateRollItemMacro(itemData: DS4ItemData): Promise { + const command = `game.ds4.macros.rollItem("${itemData._id}");`; + + const existingMacro = game.macros?.entities.find((m) => m.name === itemData.name && m.data.command === command); + if (existingMacro) { + return existingMacro; + } + + return Macro.create( + { + command, + name: itemData.name, + type: "script", + img: itemData.img, + flags: { "ds4.itemMacro": true }, + }, + { displaySheet: false }, + ); +} + /** * Executes the roll item macro for the given itemId. */ export async function rollItem(itemId: string): Promise { - const speaker = ChatMessage.getSpeaker(); - const actor = (getCanvas().tokens.get(speaker.token ?? "")?.actor ?? game.actors?.get(speaker.actor ?? "")) as - | DS4Actor - | null - | undefined; + const actor = getActiveActor(); if (!actor) { return notifications.warn(game.i18n.localize("DS4.WarningMustControlActorToUseRollItemMacro")); } + const item = actor.items?.get(itemId); if (!item) { return notifications.warn(