diff --git a/scss/components/shared/_ruler.scss b/scss/components/shared/_ruler.scss new file mode 100644 index 00000000..58593411 --- /dev/null +++ b/scss/components/shared/_ruler.scss @@ -0,0 +1,49 @@ +/* + * SPDX-FileCopyrightText: 2025 Alexander Minges + * + * SPDX-License-Identifier: MIT + */ + +/* Token Ruler Waypoint Styling with Color-Coded Movement Ranges */ + +:root { + --ds4-movement-normal: inherit; + --ds4-movement-dash: #ffcc00; + --ds4-movement-impossible: #e83031; +} + +.system-ds4 .waypoint-label { + .distance { + &.move-range { + color: var(--ds4-movement-normal); + } + + &.dash-range { + color: var(--ds4-movement-dash); + font-weight: bold; + } + + &.out-of-range { + color: var(--ds4-movement-impossible); + font-weight: bold; + } + } + + .delta { + opacity: 0.8; + font-size: 0.9em; + } + + .elevation { + font-style: italic; + opacity: 0.9; + } +} + +/* Dark mode support */ +@media (prefers-color-scheme: dark) { + :root { + --ds4-movement-dash: #ffd700; + --ds4-movement-impossible: #ff4444; + } +} diff --git a/scss/ds4.scss b/scss/ds4.scss index 4f533640..53760d31 100644 --- a/scss/ds4.scss +++ b/scss/ds4.scss @@ -19,6 +19,7 @@ @import "components/shared/embedded_document_list"; @import "components/shared/form_group"; @import "components/shared/rollable_image"; +@import "components/shared/ruler"; @import "components/shared/sheet_body"; @import "components/shared/sheet_form"; @import "components/shared/sheet_tab_nav"; diff --git a/src/apps/ruler/token-ruler.js b/src/apps/ruler/token-ruler.js new file mode 100644 index 00000000..3d48362a --- /dev/null +++ b/src/apps/ruler/token-ruler.js @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025 Alexander Minges +// +// SPDX-License-Identifier: MIT + +/** + * DS4 Token Ruler implementation with color-coded movement ranges + * Based on actor movement combat value + */ +export class DS4TokenRuler extends foundry.canvas.placeables.tokens.TokenRuler { + + static WAYPOINT_LABEL_TEMPLATE = "systems/ds4/templates/partials/waypoint-label.hbs"; + + + + /** + * Enhance waypoint label context with movement range information + * @param {object} waypoint - The waypoint data + * @param {object} state - The current ruler state + * @returns {object} Enhanced context with range class + */ + _getWaypointLabelContext(waypoint, state) { + const context = super._getWaypointLabelContext(waypoint, state); + + // Only apply movement coloring for distance measurements in meters + if (context?.cost?.units === "m" || context?.distance?.units === "m") { + const movement = this.token?.actor?.system?.combatValues?.movement?.total; + + if (movement) { + const total = Number(context.cost?.total || context.distance?.total || 0); + + // DS4 movement rules: + // - Normal movement: up to movement value + // - Dash: up to 2x movement value (requires action) + // - Beyond 2x: impossible in single turn + if (total > 2 * movement) { + context.rangeClass = "out-of-range"; + } else if (total <= movement) { + context.rangeClass = "move-range"; + } else { + context.rangeClass = "dash-range"; + } + } + } + + return context; + } +} diff --git a/src/documents/actor/actor.js b/src/documents/actor/actor.js index 8e17b936..a7d0b2c3 100644 --- a/src/documents/actor/actor.js +++ b/src/documents/actor/actor.js @@ -492,7 +492,7 @@ export class DS4Actor extends Actor { }), ok: { label: getGame().i18n.localize("DS4.GenericOkButton"), - callback: (_event, button, _dialog) => { + callback: (_event, button) => { const selectedAttribute = button.form.elements[attributeIdentifier].value; if (!isAttribute(selectedAttribute)) { throw new Error( diff --git a/src/handlebars/handlebars-partials.js b/src/handlebars/handlebars-partials.js index 70cd1e35..0e7aec6e 100644 --- a/src/handlebars/handlebars-partials.js +++ b/src/handlebars/handlebars-partials.js @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2021 Johannes Loher // SPDX-FileCopyrightText: 2021 Oliver Rümpelein // SPDX-FileCopyrightText: 2021 Gesina Schwalbe +// SPDX-FileCopyrightText: 2025 Alexander Minges // // SPDX-License-Identifier: MIT @@ -55,6 +56,7 @@ export async function registerHandlebarsPartials() { "systems/ds4/templates/sheets/shared/components/add-button.hbs", "systems/ds4/templates/sheets/shared/components/control-button-group.hbs", "systems/ds4/templates/sheets/shared/components/rollable-image.hbs", + "systems/ds4/templates/partials/waypoint-label.hbs", ]; await foundry.applications.handlebars.loadTemplates(templatePaths); } diff --git a/src/hooks/hooks.ts b/src/hooks/hooks.ts index b69fbb1f..684a04db 100644 --- a/src/hooks/hooks.ts +++ b/src/hooks/hooks.ts @@ -9,6 +9,8 @@ import { registerForReadyHook } from "./ready"; import { registerForRenderHooks } from "./render"; import { registerForSetupHook } from "./setup"; + + export function registerForHooks(): void { registerForHotbarDropHook(); registerForPreCreateItemHook(); diff --git a/src/hooks/init.js b/src/hooks/init.js index 0f339af2..a063a9f5 100644 --- a/src/hooks/init.js +++ b/src/hooks/init.js @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2021 Johannes Loher // SPDX-FileCopyrightText: 2021 Oliver Rümpelein // SPDX-FileCopyrightText: 2021 Gesina Schwalbe +// SPDX-FileCopyrightText: 2025 Alexander Minges // // SPDX-License-Identifier: MIT @@ -8,6 +9,7 @@ import { DS4ActiveEffectConfig } from "../apps/active-effect-config"; import { DS4CharacterActorSheet } from "../apps/actor/character-sheet"; import { DS4CreatureActorSheet } from "../apps/actor/creature-sheet"; import { DS4ItemSheet } from "../apps/item-sheet"; +import { DS4TokenRuler } from "../apps/ruler/token-ruler"; import { DS4 } from "../config"; import { DS4Check } from "../dice/check"; import { createCheckRoll } from "../dice/check-factory"; @@ -51,6 +53,8 @@ async function init() { CONFIG.ChatMessage.documentClass = DS4ChatMessage; CONFIG.Token.documentClass = DS4TokenDocument; + CONFIG.Token.rulerClass = DS4TokenRuler; + CONFIG.ActiveEffect.legacyTransferral = false; CONFIG.Actor.typeLabels = DS4.i18n.actorTypes; diff --git a/templates/partials/waypoint-label.hbs b/templates/partials/waypoint-label.hbs new file mode 100644 index 00000000..58983d5c --- /dev/null +++ b/templates/partials/waypoint-label.hbs @@ -0,0 +1,39 @@ +{{!-- +SPDX-FileCopyrightText: 2025 Alexander Minges + +SPDX-License-Identifier: MIT +--}} + +{{!-- +!-- Waypoint label template with color-coded movement ranges +!-- Based on DS4 movement combat values +--}} +