132 lines
5.5 KiB
JavaScript
132 lines
5.5 KiB
JavaScript
/**
|
||
* Chroniques de l'Étrange — Système FoundryVTT
|
||
*
|
||
* Chroniques de l'Étrange est un jeu de rôle édité par Antre-Monde Éditions.
|
||
* Ce système FoundryVTT est une implémentation indépendante et n'est pas
|
||
* affilié à Antre-Monde Éditions,
|
||
* mais a été réalisé avec l'autorisation d'Antre-Monde Éditions.
|
||
*
|
||
* @author LeRatierBretonnien
|
||
* @copyright 2024–2026 LeRatierBretonnien
|
||
* @license CC BY-NC-SA 4.0 – https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||
*/
|
||
|
||
import { MAGICS } from "../config/constants.js"
|
||
|
||
export function registerHandlebarsHelpers() {
|
||
const { Handlebars } = globalThis
|
||
if (!Handlebars) return
|
||
|
||
Handlebars.registerHelper("getMagicLabel", function (magic) {
|
||
return game.i18n.localize(MAGICS[magic]?.label ?? "")
|
||
})
|
||
|
||
Handlebars.registerHelper("getMagicAspectLabel", function (magic) {
|
||
return game.i18n.localize(MAGICS[magic]?.aspectlabel ?? "")
|
||
})
|
||
|
||
Handlebars.registerHelper("getMagicSpecialityLabel", function (magic, speciality) {
|
||
return game.i18n.localize(MAGICS[magic]?.speciality?.[speciality]?.label ?? "")
|
||
})
|
||
|
||
Handlebars.registerHelper("getMagicSpecialityClassIcon", function (magic, speciality) {
|
||
return MAGICS[magic]?.speciality?.[speciality]?.classicon ?? ""
|
||
})
|
||
|
||
Handlebars.registerHelper("getMagicSpecialityElementIcon", function (magic, speciality) {
|
||
return MAGICS[magic]?.speciality?.[speciality]?.elementicon ?? ""
|
||
})
|
||
|
||
Handlebars.registerHelper("getMagicSpecialityLabelIcon", function (magic, speciality) {
|
||
return MAGICS[magic]?.speciality?.[speciality]?.labelicon ?? ""
|
||
})
|
||
|
||
Handlebars.registerHelper("getMagicSpecialityLabelElement", function (magic, speciality) {
|
||
return game.i18n.localize(MAGICS[magic]?.speciality?.[speciality]?.labelelement ?? "")
|
||
})
|
||
|
||
Handlebars.registerHelper("getMagicAspectIcon", function (magic) {
|
||
const icons = {
|
||
internalcinnabar: "/systems/fvtt-chroniques-de-l-etrange/images/cde_metal.webp",
|
||
alchemy: "/systems/fvtt-chroniques-de-l-etrange/images/cde_eau.webp",
|
||
masteryoftheway: "/systems/fvtt-chroniques-de-l-etrange/images/cde_terre.webp",
|
||
exorcism: "/systems/fvtt-chroniques-de-l-etrange/images/cde_feu.webp",
|
||
geomancy: "/systems/fvtt-chroniques-de-l-etrange/images/cde_bois.webp",
|
||
}
|
||
return icons[magic] ?? ""
|
||
})
|
||
|
||
Handlebars.registerHelper("getElementIcon", function (aspect) {
|
||
const icons = {
|
||
metal: "/systems/fvtt-chroniques-de-l-etrange/images/cde_metal.webp",
|
||
water: "/systems/fvtt-chroniques-de-l-etrange/images/cde_eau.webp",
|
||
earth: "/systems/fvtt-chroniques-de-l-etrange/images/cde_terre.webp",
|
||
fire: "/systems/fvtt-chroniques-de-l-etrange/images/cde_feu.webp",
|
||
wood: "/systems/fvtt-chroniques-de-l-etrange/images/cde_bois.webp",
|
||
// legacy French keys
|
||
eau: "/systems/fvtt-chroniques-de-l-etrange/images/cde_eau.webp",
|
||
terre: "/systems/fvtt-chroniques-de-l-etrange/images/cde_terre.webp",
|
||
feu: "/systems/fvtt-chroniques-de-l-etrange/images/cde_feu.webp",
|
||
bois: "/systems/fvtt-chroniques-de-l-etrange/images/cde_bois.webp",
|
||
}
|
||
return icons[aspect] ?? ""
|
||
})
|
||
|
||
Handlebars.registerHelper("getOrientationIcon", function (orientation) {
|
||
const icons = {
|
||
yin: "/systems/fvtt-chroniques-de-l-etrange/images/cde_yin.webp",
|
||
yang: "/systems/fvtt-chroniques-de-l-etrange/images/cde_yang.webp",
|
||
yinyang: "/systems/fvtt-chroniques-de-l-etrange/images/yin_yang.webp",
|
||
}
|
||
return icons[orientation] ?? ""
|
||
})
|
||
|
||
Handlebars.registerHelper("getOrientationLabel", function (orientation) {
|
||
const keys = {
|
||
yin: "CDE.OrientationYin",
|
||
yang: "CDE.OrientationYang",
|
||
yinyang: "CDE.OrientationYinYang",
|
||
}
|
||
return game.i18n.localize(keys[orientation] ?? "CDE.Orientation")
|
||
})
|
||
|
||
Handlebars.registerHelper("getActivationLabel", function (activation) {
|
||
const keys = {
|
||
"action-attack": "CDE.ActivationAttack",
|
||
"action-defense": "CDE.ActivationDefense",
|
||
"action-aid": "CDE.ActivationAid",
|
||
"action-attack-defense": "CDE.ActivationAttackOrDefense",
|
||
reaction: "CDE.ActivationReaction",
|
||
dice: "CDE.ActivationDice",
|
||
"damage-inflicted": "CDE.ActivationDamageInflicted",
|
||
"damage-received": "CDE.ActivationDamageReceived",
|
||
}
|
||
return game.i18n.localize(keys[activation] ?? "CDE.Activation")
|
||
})
|
||
|
||
/**
|
||
* Compute the SVG x,y coordinates for a cran on the initiative wheel.
|
||
* Cran 1–24 are arranged counter-clockwise from the bottom (reference at 6 o'clock).
|
||
* angle = 90° + cran * 15° (counter-clockwise = positive in standard math, negative in SVG).
|
||
* In SVG coords: x = cx + r*cos(a), y = cy - r*sin(a) [y-axis is flipped in SVG].
|
||
*/
|
||
Handlebars.registerHelper("cranPosition", function (cran, cx, cy, r) {
|
||
const angleDeg = 90 + cran * 15 // counter-clockwise from bottom
|
||
const angleRad = (angleDeg * Math.PI) / 180
|
||
const x = Math.round(cx + r * Math.cos(angleRad))
|
||
const y = Math.round(cy - r * Math.sin(angleRad))
|
||
return { x, y }
|
||
})
|
||
|
||
/** X offset for overlapping fighters on the same cran. Centres a 30px image on the cran cx. */
|
||
Handlebars.registerHelper("fighterX", function (cx, index, total) {
|
||
const offset = total > 1 ? (index - (total - 1) / 2) * 34 : 0
|
||
return Math.round(cx - 15 + offset)
|
||
})
|
||
|
||
/** Y offset for fighters — positions image just above the cran circle. */
|
||
Handlebars.registerHelper("fighterY", function (cy, index, total) {
|
||
return Math.round(cy - 50)
|
||
})
|
||
}
|