Rework complet des fiches et dialog de jets

This commit is contained in:
2026-03-28 08:47:13 +01:00
parent 1b51a81919
commit a9e902ed78
59 changed files with 2342 additions and 305 deletions

View File

@@ -17,7 +17,7 @@ export default class SpellDataModel extends foundry.abstract.TypeDataModel {
effects: htmlField(""),
examples: htmlField(""),
notes: htmlField(""),
discipline: stringField("cinabre"),
discipline: stringField("internalcinnabar"),
heiType: stringField("yin"),
heiCost: new fields.NumberField({ required: true, nullable: false, integer: true, min: 0, initial: 1 }),
difficulty: new fields.NumberField({ required: true, nullable: false, integer: true, min: 0, initial: 1 }),

View File

@@ -46,4 +46,58 @@ export function registerHandlebarsHelpers() {
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.png",
alchemy: "/systems/fvtt-chroniques-de-l-etrange/images/cde_eau.png",
masteryoftheway: "/systems/fvtt-chroniques-de-l-etrange/images/cde_terre.png",
exorcism: "/systems/fvtt-chroniques-de-l-etrange/images/cde_feu.png",
geomancy: "/systems/fvtt-chroniques-de-l-etrange/images/cde_bois.png",
}
return icons[magic] ?? ""
})
Handlebars.registerHelper("getElementIcon", function (aspect) {
const icons = {
metal: "/systems/fvtt-chroniques-de-l-etrange/images/cde_metal.png",
eau: "/systems/fvtt-chroniques-de-l-etrange/images/cde_eau.png",
terre: "/systems/fvtt-chroniques-de-l-etrange/images/cde_terre.png",
feu: "/systems/fvtt-chroniques-de-l-etrange/images/cde_feu.png",
bois: "/systems/fvtt-chroniques-de-l-etrange/images/cde_bois.png",
}
return icons[aspect] ?? ""
})
Handlebars.registerHelper("getOrientationIcon", function (orientation) {
const icons = {
yin: "/systems/fvtt-chroniques-de-l-etrange/images/cde_yin.png",
yang: "/systems/fvtt-chroniques-de-l-etrange/images/cde_yang.png",
yinyang: "/systems/fvtt-chroniques-de-l-etrange/images/yin_yang.png",
}
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")
})
}

View File

@@ -59,17 +59,21 @@ export class CDEBaseActorSheet extends HandlebarsApplicationMixin(foundry.applic
supernatural: "CDE.SupernaturalNew",
}
const name = game.i18n.localize(labels[type] ?? "CDE.ItemNew")
return cls.create({ name, type }, { parent: this.document })
const systemData = {}
if (type === "spell" && target.dataset.discipline) {
systemData.discipline = target.dataset.discipline
}
return cls.create({ name, type, system: systemData }, { parent: this.document })
}
static #onItemEdit(event, target) {
const itemId = target.closest(".item")?.dataset.itemId
const itemId = target.dataset.itemId ?? target.closest("[data-item-id]")?.dataset.itemId
const item = this.document.items.get(itemId)
if (item) item.sheet.render(true)
}
static #onItemDelete(event, target) {
const itemId = target.closest(".item")?.dataset.itemId
const itemId = target.dataset.itemId ?? target.closest("[data-item-id]")?.dataset.itemId
const item = this.document.items.get(itemId)
if (item) item.delete()
}

View File

@@ -24,6 +24,37 @@ export class CDECharacterSheet extends CDEBaseActorSheet {
context.spells = context.items.filter((item) => item.type === "spell")
context.kungfus = context.items.filter((item) => item.type === "kungfu")
context.CDE = { MAGICS, SUBTYPES }
// Group spells by discipline key (matches MAGICS keys)
const spellsByDiscipline = {}
for (const spell of context.spells) {
const disc = spell.system?.discipline ?? "internalcinnabar"
if (!spellsByDiscipline[disc]) spellsByDiscipline[disc] = []
spellsByDiscipline[disc].push(spell)
}
// Build magicsDisplay: only include the 5 relevant specialities per magic type + grimoire
const systemMagics = context.systemData.magics ?? {}
context.magicsDisplay = Object.fromEntries(
Object.entries(MAGICS).map(([magicKey, magicDef]) => {
const magicData = systemMagics[magicKey] ?? {}
return [
magicKey,
{
value: magicData.value ?? 0,
visible: magicData.visible ?? false,
speciality: Object.fromEntries(
Object.keys(magicDef.speciality).map((specKey) => [
specKey,
{ check: magicData.speciality?.[specKey]?.check ?? false },
])
),
grimoire: spellsByDiscipline[magicKey] ?? [],
},
]
})
)
return context
}
@@ -32,6 +63,7 @@ export class CDECharacterSheet extends CDEBaseActorSheet {
this.#bindInitiativeControls()
this.#bindPrefs()
this.#bindRollButtons()
this.#bindComponentRandomize()
}
#bindInitiativeControls() {
@@ -109,4 +141,33 @@ export class CDECharacterSheet extends CDEBaseActorSheet {
})
})
}
#bindComponentRandomize() {
const btn = this.element?.querySelector("[data-action='randomize-component']")
if (!btn) return
btn.addEventListener("click", async () => {
const roll = new Roll("1d10")
await roll.evaluate()
const face = roll.total === 10 ? 0 : roll.total
const COMPONENT_KEYS = { 1:"one", 2:"two", 3:"three", 4:"four", 5:"five",
6:"six", 7:"seven", 8:"eight", 9:"nine", 0:"zero" }
const componentKey = COMPONENT_KEYS[face]
const componentValue = this.document.system.component?.[componentKey]?.value ?? ""
const label = componentValue
? `<strong>${componentValue}</strong>`
: `<em>${game.i18n.localize("CDE.Component")}${face}</em>`
const content = `
<div class="cde-chat-random-component">
<span class="cde-chat-component-label">${game.i18n.localize("CDE.ChanceThrowResult")}</span>
<span class="cde-chat-component-value">${label}</span>
</div>`
await ChatMessage.create({
user: game.user.id,
speaker: ChatMessage.getSpeaker({ actor: this.document }),
content,
rolls: [roll],
rollMode: "roll",
})
})
}
}