Refonte complète du système Anomalies

- DataModel : renommage value→level (1-4), ajout usesRemaining (0-4), suppression scores/notes
- Config : ajout ANOMALY_DEFINITIONS avec compétences applicables par type (8 anomalies)
- Fiche item anomalie : header avec level/uses visuels (dots), barre de compétences applicables,
  2 onglets Description + Technique/Narratif (suppression onglet Scores)
- Fiche PJ onglet Domaines : bloc anomalie proéminent unique avec:
  - Nom + sous-type + icône
  - Dots niveau (●●○○)
  - Dots usages + bouton Utiliser + bouton Réinitialiser
  - Chips des domaines applicables
- Actions : useAnomaly (décrémente usesRemaining), resetAnomalyUses (reset au niveau)
- Contrainte : max 1 anomalie par personnage (drop + createAnomaly)
- Helpers HBS : lte, gte, lt ajoutés
- i18n : nouvelles clés Anomaly.* (level, usesRemaining, use, resetUses, etc.)
- CSS : .anomaly-block sur fiche PJ, dots animés, .anomaly-uses-row sur fiche item

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-03-28 18:15:06 +01:00
parent cff700bd3d
commit f9ddcdf9da
11 changed files with 474 additions and 41 deletions

View File

@@ -8,10 +8,12 @@ export default class CelestopolCharacterSheet extends CelestopolActorSheet {
position: { width: 920, height: 660 },
window: { contentClasses: ["character-content"] },
actions: {
createAnomaly: CelestopolCharacterSheet.#onCreateAnomaly,
createAspect: CelestopolCharacterSheet.#onCreateAspect,
createAttribute: CelestopolCharacterSheet.#onCreateAttribute,
createEquipment: CelestopolCharacterSheet.#onCreateEquipment,
createAnomaly: CelestopolCharacterSheet.#onCreateAnomaly,
createAspect: CelestopolCharacterSheet.#onCreateAspect,
createAttribute: CelestopolCharacterSheet.#onCreateAttribute,
createEquipment: CelestopolCharacterSheet.#onCreateEquipment,
useAnomaly: CelestopolCharacterSheet.#onUseAnomaly,
resetAnomalyUses: CelestopolCharacterSheet.#onResetAnomalyUses,
},
}
@@ -64,9 +66,21 @@ export default class CelestopolCharacterSheet extends CelestopolActorSheet {
case "competences":
context.tab = context.tabs.competences
context.anomalies = doc.itemTypes.anomaly
context.anomaly = doc.itemTypes.anomaly[0] ?? null
context.aspects = doc.itemTypes.aspect
context.attributes = doc.itemTypes.attribute
if (context.anomaly) {
const def = SYSTEM.ANOMALY_DEFINITIONS[context.anomaly.system.subtype] ?? SYSTEM.ANOMALY_DEFINITIONS.none
context.anomalySkillLabels = def.technicalSkills.map(key => {
if (key === "lune") return game.i18n.localize("CELESTOPOL.Anomaly.moonDie")
for (const skills of Object.values(SYSTEM.SKILLS)) {
if (skills[key]) return game.i18n.localize(skills[key].label)
}
return key
})
} else {
context.anomalySkillLabels = []
}
break
case "blessures":
@@ -91,6 +105,10 @@ export default class CelestopolCharacterSheet extends CelestopolActorSheet {
}
static #onCreateAnomaly() {
if (this.document.itemTypes.anomaly.length > 0) {
ui.notifications.warn(game.i18n.localize("CELESTOPOL.Anomaly.maxAnomaly"))
return
}
this.document.createEmbeddedDocuments("Item", [{
name: game.i18n.localize("CELESTOPOL.Item.newAnomaly"), type: "anomaly",
}])
@@ -113,4 +131,23 @@ export default class CelestopolCharacterSheet extends CelestopolActorSheet {
name: game.i18n.localize("CELESTOPOL.Item.newEquipment"), type: "equipment",
}])
}
static async #onUseAnomaly(event, target) {
const itemId = target.dataset.itemId
const anomaly = this.document.items.get(itemId)
if (!anomaly) return
const current = anomaly.system.usesRemaining
if (current <= 0) {
ui.notifications.warn(game.i18n.localize("CELESTOPOL.Anomaly.noUsesLeft"))
return
}
await anomaly.update({ "system.usesRemaining": current - 1 })
}
static async #onResetAnomalyUses(event, target) {
const itemId = target.dataset.itemId
const anomaly = this.document.items.get(itemId)
if (!anomaly) return
await anomaly.update({ "system.usesRemaining": anomaly.system.level })
}
}