fix: tests complets - onglets, message de tchat, scores bonus/malus

- Onglets item (Anomalie/Aspect/Attribut): correction tabGroups + data-group sur chaque <a> et <section>
- Onglets acteur (PJ/PNJ): tab.cssClass dans les templates pour l'état actif initial
- Message de tchat: alignement des noms de variables _getChatCardData <-> chat-message.hbs
  - actorName, actorImg, success/failure, diceResults, statLabel/skillLabel localisés
  - difficultyLabel et moonPhaseLabel localisés depuis SYSTEM
- Dialogue de jet (roll-dialog.hbs): correction noms variables + min/max modificateur
- lang/fr.json: ajout Roll.title, Roll.roll, clés Moon (minuscules), Difficulty (unknown/ardu)
- character.mjs: passage statLabel à CelestopolRoll.prompt()
- global.less: padding + overflow-y sur .tab pour contenu visible
- item-scores.hbs: passage system=system au partial + suppression garde isEditable
- Templates anomaly/aspect/attribute: passage system=system au partial item-scores
- chat-message.mjs: getHTML() → renderHTML() (dépréciation FVTT v13)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-03-28 11:09:17 +01:00
parent 64e23271df
commit ea3064d7a2
35 changed files with 150 additions and 92 deletions

View File

@@ -1,4 +1,16 @@
{
"TYPES": {
"Actor": {
"character": "Personnage",
"npc": "PNJ"
},
"Item": {
"anomaly": "Anomalie",
"aspect": "Aspect",
"attribute": "Attribut",
"equipment": "Équipement"
}
},
"CELESTOPOL": {
"Actor": {
"name": "Nom",
@@ -36,14 +48,14 @@
"Anomaly": {
"type": "Type d'anomalie",
"none": "Aucune",
"charnel": "Charnel",
"mecanique": "Mécanique",
"spectral": "Spectral",
"onirique": "Onirique",
"telepath": "Télépathique",
"alchimique": "Alchimique",
"cosmique": "Cosmique",
"temporel": "Temporel"
"entropie": "Entropie",
"communicationaveclesmorts": "Communication avec les morts",
"illusion": "Illusion",
"suggestion": "Suggestion",
"tarotdivinatoire": "Tarot divinatoire",
"telekinesie": "Télékinésie",
"telepathie": "Télépathie",
"voyageastral": "Voyage astral"
},
"Attribut": {
"entregent": "Entregent",
@@ -92,24 +104,28 @@
"criticalSuccess": "Succès critique !",
"criticalFailure": "Échec critique !",
"moonBonus": "Bonus de lune",
"title": "Jet de dés",
"roll": "Lancer !",
"rollTitle": "Lancer les dés"
},
"Moon": {
"nouvelleLune": "Nouvelle Lune",
"croissantDebutant": "Croissant débutant",
"croissantMontant": "Croissant montant",
"gibbeuseMontante": "Gibbeuse montante",
"pleineLune": "Pleine Lune",
"gibbeuseDecroissante": "Gibbeuse décroissante",
"croissantDecroissant": "Croissant décroissant",
"croissantFinissant": "Croissant finissant"
"none": "Aucune phase",
"nouvellelune": "Nouvelle Lune",
"premiercroissant": "Premier Croissant",
"premierquartier": "Premier Quartier",
"lunegibbeuse": "Lune Gibbeuse",
"lunevoutee": "Lune Voûtée",
"derniercroissant": "Dernier Croissant",
"dernierquartier": "Dernier Quartier",
"pleinelune": "Pleine Lune"
},
"Difficulty": {
"unknown": "Aucun seuil",
"facile": "Facile",
"normal": "Normal",
"difficile": "Difficile",
"extreme": "Extrême",
"impossible": "Impossible"
"ardu": "Ardu",
"extreme": "Extrême"
},
"Item": {
"anomalies": "Anomalies",
@@ -134,13 +150,11 @@
"weight": "Poids"
},
"Equipment": {
"type": {
"general": "Général",
"autre": "Autre",
"arme": "Arme",
"armure": "Armure",
"protection": "Protection / Armure",
"vehicule": "Véhicule",
"gadget": "Gadget"
}
"type": "Type d'équipement"
},
"Sheet": {
"editMode": "Mode édition",

View File

@@ -12,6 +12,9 @@ export default class CelestopolItemSheet extends HandlebarsApplicationMixin(foun
},
}
/** Default tab group for item sheets */
tabGroups = { "item-tabs": "description" }
/** @override */
async _prepareContext() {
return {
@@ -21,9 +24,21 @@ export default class CelestopolItemSheet extends HandlebarsApplicationMixin(foun
system: this.document.system,
source: this.document.toObject(),
isEditable: this.isEditable,
activeTab: this.tabGroups["item-tabs"] ?? "description",
}
}
/** @override */
_onRender(context, options) {
// Wire up tab navigation for inline item tabs
this.element.querySelectorAll('.item-tabs [data-tab]').forEach(tabEl => {
tabEl.addEventListener('click', () => {
const group = "item-tabs"
this.changeTab(tabEl.dataset.tab, group)
})
})
}
static async #onEditImage(event, target) {
const attr = target.dataset.edit
const current = foundry.utils.getProperty(this.document, attr)

View File

@@ -37,6 +37,7 @@ export default class CelestopolNPCSheet extends CelestopolActorSheet {
context.tabs = this.#getTabs()
context.stats = SYSTEM.STATS
context.skills = SYSTEM.SKILLS
context.anomalyTypes = SYSTEM.ANOMALY_TYPES
context.woundLevels = SYSTEM.WOUND_LEVELS
return context
}

View File

@@ -1,7 +1,6 @@
export default class CelestopolChatMessage extends ChatMessage {
/** @override */
async getHTML() {
const html = await super.getHTML()
return html
async renderHTML(options = {}) {
return super.renderHTML(options)
}
}

View File

@@ -35,9 +35,11 @@ export class CelestopolRoll extends Roll {
const dialogContext = {
actorName: options.actorName,
statLabel: options.statLabel,
skillLabel: options.skillLabel,
skillValue: options.skillValue,
woundMalus: options.woundMalus ?? 0,
nbDice: Math.max(1, options.skillValue ?? 1),
difficultyChoices:SYSTEM.DIFFICULTY_CHOICES,
moonPhaseChoices: SYSTEM.MOON_DICE_PHASES,
defaultDifficulty:options.difficulty ?? "normal",
@@ -135,25 +137,33 @@ export class CelestopolRoll extends Roll {
}
async _getChatCardData(isPrivate) {
const statLabel = this.options.statLabel
const skillLabel = this.options.skillLabel
const resultType = this.resultType
const diceResults = this.dice[0]?.results?.map(r => r.result) ?? []
return {
css: [SYSTEM.id, "dice-roll"],
cssClass: [SYSTEM.id, "dice-roll"].join(" "),
actorId: this.actorId,
actingCharName: this.actorName,
actingCharImg: this.actorImage,
skillLabel: this.skillLabel,
actorName: this.actorName,
actorImg: this.actorImage,
statLabel: statLabel ? game.i18n.localize(statLabel) : "",
skillLabel: skillLabel ? game.i18n.localize(skillLabel) : "",
formula: this.formula,
total: this.total,
resultType: this.resultType,
isSuccess: this.isSuccess,
isFailure: this.isFailure,
resultType,
resultClass: resultType === "success" ? "success" : resultType === "failure" ? "failure" : "",
success: this.isSuccess,
failure: this.isFailure,
difficulty: this.options.difficulty,
difficultyValue:this.options.difficultyValue,
difficultyLabel:game.i18n.localize(SYSTEM.DIFFICULTY_CHOICES[this.options.difficulty]?.label ?? ""),
moonPhase: this.options.moonPhase,
moonPhaseLabel: game.i18n.localize(SYSTEM.MOON_DICE_PHASES[this.options.moonPhase]?.label ?? ""),
moonBonus: this.moonBonus,
modifier: this.options.modifier,
isPrivate,
tooltip: isPrivate ? "" : await this.getTooltip(),
results: this.dice[0]?.results ?? [],
diceResults,
}
}

View File

@@ -165,6 +165,7 @@ export default class CelestopolCharacter extends foundry.abstract.TypeDataModel
actorImage: this.parent.img,
statId,
skillId,
statLabel: SYSTEM.STATS[statId]?.label,
skillLabel: skill.label,
skillValue: skill.value,
woundMalus: this.getWoundMalus(),

View File

View File

@@ -0,0 +1 @@
MANIFEST-000002

View File

View File

@@ -0,0 +1 @@
2026/03/28-09:47:34.669467 7f0018fff6c0 Delete type=3 #1

Binary file not shown.

View File

View File

@@ -0,0 +1 @@
MANIFEST-000002

View File

1
packs-system/aspects/LOG Normal file
View File

@@ -0,0 +1 @@
2026/03/28-09:47:34.653497 7effcaffd6c0 Delete type=3 #1

Binary file not shown.

View File

@@ -2,7 +2,7 @@
// ─── Character sheet specifics ───────────────────────────────────────────────
.celestopol.character-sheet {
.fvtt-celestopol.character {
// Attributs perso (Entregent, Fortune, Rêve, Vision)
.perso-attributs {

View File

@@ -1,5 +1,9 @@
// ─── Variables CSS (couleurs + typo) ────────────────────────────────────────
// ─── FVTT-wide type label fix ────────────────────────────────────────────────
// Override window title color for celestopol sheets
.fvtt-celestopol .window-title { color: var(--cel-orange, #e07b00); }
:root {
--cel-green: rgb(12, 76, 12);
--cel-green-light: rgb(20, 110, 20);
@@ -17,7 +21,7 @@
// ─── Sheet base layout ───────────────────────────────────────────────────────
.celestopol {
.fvtt-celestopol {
&.sheet {
background: var(--cel-cream);
font-family: var(--cel-font-body);
@@ -154,5 +158,10 @@
padding: 8px;
}
.tab { display: none; &.active { display: block; } }
.tab {
display: none;
padding: 8px;
overflow-y: auto;
&.active { display: block; }
}
}

View File

@@ -2,7 +2,7 @@
// ─── Item sheets shared ───────────────────────────────────────────────────────
.celestopol.item-sheet {
.fvtt-celestopol.item {
.item-header {
display: flex;
@@ -147,7 +147,7 @@
}
// Equipment-specific
&.equipment-sheet {
&.equipment {
.equipment-stats {
display: grid;
grid-template-columns: repeat(3, 1fr);

View File

@@ -2,7 +2,7 @@
// ─── NPC sheet specifics ─────────────────────────────────────────────────────
.celestopol.npc-sheet {
.fvtt-celestopol.npc {
.stats-grid {
display: grid;

View File

@@ -7,7 +7,9 @@
<input type="text" name="name" value="{{item.name}}" {{#unless isEditable}}disabled{{/unless}}>
<div class="item-meta">
<select name="system.subtype" {{#unless isEditable}}disabled{{/unless}}>
{{selectOptions systemFields.subtype.choices selected=system.subtype localize=true}}
{{#each anomalyTypes as |atype key|}}
<option value="{{key}}" {{#if (eq key ../system.subtype)}}selected{{/if}}>{{localize atype.label}}</option>
{{/each}}
</select>
<div class="item-value-field">
<label>{{localize "CELESTOPOL.Item.value"}}</label>
@@ -19,12 +21,12 @@
</header>
<nav class="item-tabs sheet-tabs tabs" data-group="item-tabs">
<a class="item active" data-tab="description">{{localize "CELESTOPOL.Tab.description"}}</a>
<a class="item" data-tab="technique">{{localize "CELESTOPOL.Tab.technique"}}</a>
<a class="item" data-tab="scores">{{localize "CELESTOPOL.Item.scores"}}</a>
<a class="item active" data-group="item-tabs" data-tab="description">{{localize "CELESTOPOL.Tab.description"}}</a>
<a class="item" data-group="item-tabs" data-tab="technique">{{localize "CELESTOPOL.Tab.technique"}}</a>
<a class="item" data-group="item-tabs" data-tab="scores">{{localize "CELESTOPOL.Item.scores"}}</a>
</nav>
<section class="tab active" data-tab="description">
<section class="tab active" data-group="item-tabs" data-tab="description">
<div class="form-group">
{{editor system.description target="system.description" button=true editable=isEditable}}
</div>
@@ -35,7 +37,7 @@
</div>
</section>
<section class="tab" data-tab="technique">
<section class="tab" data-group="item-tabs" data-tab="technique">
<div class="form-group">
<label>{{localize "CELESTOPOL.Item.technique"}}</label>
{{editor system.technique target="system.technique" button=true editable=isEditable}}
@@ -46,7 +48,7 @@
</div>
</section>
<section class="tab" data-tab="scores">
{{> "systems/fvtt-celestopol/templates/partials/item-scores.hbs" skills=skills stats=stats}}
<section class="tab" data-group="item-tabs" data-tab="scores">
{{> "systems/fvtt-celestopol/templates/partials/item-scores.hbs" skills=skills stats=stats system=system}}
</section>
</div>

View File

@@ -13,20 +13,20 @@
</div>
</header>
<nav class="item-tabs sheet-tabs tabs" data-group="item-tabs">
<a class="item active" data-tab="description">{{localize "CELESTOPOL.Tab.description"}}</a>
<a class="item" data-tab="technique">{{localize "CELESTOPOL.Tab.technique"}}</a>
<a class="item" data-tab="scores">{{localize "CELESTOPOL.Item.scores"}}</a>
<a class="item active" data-group="item-tabs" data-tab="description">{{localize "CELESTOPOL.Tab.description"}}</a>
<a class="item" data-group="item-tabs" data-tab="technique">{{localize "CELESTOPOL.Tab.technique"}}</a>
<a class="item" data-group="item-tabs" data-tab="scores">{{localize "CELESTOPOL.Item.scores"}}</a>
</nav>
<section class="tab active" data-tab="description">
<section class="tab active" data-group="item-tabs" data-tab="description">
{{editor system.description target="system.description" button=true editable=isEditable}}
<label>{{localize "CELESTOPOL.Item.reference"}}</label>
<input type="text" name="system.reference" value="{{system.reference}}" {{#unless isEditable}}disabled{{/unless}}>
</section>
<section class="tab" data-tab="technique">
<section class="tab" data-group="item-tabs" data-tab="technique">
{{editor system.technique target="system.technique" button=true editable=isEditable}}
{{editor system.narratif target="system.narratif" button=true editable=isEditable}}
</section>
<section class="tab" data-tab="scores">
{{> "systems/fvtt-celestopol/templates/partials/item-scores.hbs" skills=skills}}
<section class="tab" data-group="item-tabs" data-tab="scores">
{{> "systems/fvtt-celestopol/templates/partials/item-scores.hbs" skills=skills system=system}}
</section>
</div>

View File

@@ -13,20 +13,20 @@
</div>
</header>
<nav class="item-tabs sheet-tabs tabs" data-group="item-tabs">
<a class="item active" data-tab="description">{{localize "CELESTOPOL.Tab.description"}}</a>
<a class="item" data-tab="technique">{{localize "CELESTOPOL.Tab.technique"}}</a>
<a class="item" data-tab="scores">{{localize "CELESTOPOL.Item.scores"}}</a>
<a class="item active" data-group="item-tabs" data-tab="description">{{localize "CELESTOPOL.Tab.description"}}</a>
<a class="item" data-group="item-tabs" data-tab="technique">{{localize "CELESTOPOL.Tab.technique"}}</a>
<a class="item" data-group="item-tabs" data-tab="scores">{{localize "CELESTOPOL.Item.scores"}}</a>
</nav>
<section class="tab active" data-tab="description">
<section class="tab active" data-group="item-tabs" data-tab="description">
{{editor system.description target="system.description" button=true editable=isEditable}}
<label>{{localize "CELESTOPOL.Item.reference"}}</label>
<input type="text" name="system.reference" value="{{system.reference}}" {{#unless isEditable}}disabled{{/unless}}>
</section>
<section class="tab" data-tab="technique">
<section class="tab" data-group="item-tabs" data-tab="technique">
{{editor system.technique target="system.technique" button=true editable=isEditable}}
{{editor system.narratif target="system.narratif" button=true editable=isEditable}}
</section>
<section class="tab" data-tab="scores">
{{> "systems/fvtt-celestopol/templates/partials/item-scores.hbs" skills=skills}}
<section class="tab" data-group="item-tabs" data-tab="scores">
{{> "systems/fvtt-celestopol/templates/partials/item-scores.hbs" skills=skills system=system}}
</section>
</div>

View File

@@ -1,4 +1,4 @@
<div class="tab biography" data-group="sheet" data-tab="biography">
<div class="tab biography {{tab.cssClass}}" data-group="sheet" data-tab="biography">
{{!-- Équipements --}}
<div class="equipments-section">
<div class="section-header">

View File

@@ -1,4 +1,4 @@
<div class="tab blessures" data-group="sheet" data-tab="blessures">
<div class="tab blessures {{tab.cssClass}}" data-group="sheet" data-tab="blessures">
{{!-- Blessures --}}
<section class="track-section">
<div class="track-header">

View File

@@ -1,4 +1,4 @@
<div class="tab competences" data-group="sheet" data-tab="competences">
<div class="tab competences {{tab.cssClass}}" data-group="sheet" data-tab="competences">
{{!-- Grille des 4 stats × 4 compétences --}}
<div class="stats-grid">
{{#each stats as |stat statId|}}

View File

@@ -1,4 +1,4 @@
<div class="tab factions" data-group="sheet" data-tab="factions">
<div class="tab factions {{tab.cssClass}}" data-group="sheet" data-tab="factions">
<table class="factions-table">
<thead>
<tr>

View File

@@ -27,7 +27,9 @@
<label>{{localize "CELESTOPOL.Actor.anomaly"}}</label>
{{#if isEditMode}}
<select name="system.anomaly.type">
{{selectOptions systemFields.anomaly.fields.type.choices selected=system.anomaly.type localize=true}}
{{#each anomalyTypes as |atype key|}}
<option value="{{key}}" {{#if (eq key ../system.anomaly.type)}}selected{{/if}}>{{localize atype.label}}</option>
{{/each}}
</select>
<input type="number" name="system.anomaly.value" value="{{system.anomaly.value}}" min="0" max="8" class="anomaly-value">
{{else}}

View File

@@ -33,7 +33,7 @@
<div class="roll-total-line">
<span class="total-label">{{localize "CELESTOPOL.Roll.total"}}</span>
<span class="total-value">{{total}}</span>
<span class="vs-difficulty">vs {{difficulty}}</span>
<span class="vs-difficulty">vs {{difficultyLabel}}</span>
</div>
</div>

View File

@@ -7,7 +7,9 @@
<input type="text" name="name" value="{{item.name}}" {{#unless isEditable}}disabled{{/unless}}>
<div class="item-meta">
<select name="system.subtype" {{#unless isEditable}}disabled{{/unless}}>
{{selectOptions systemFields.subtype.choices selected=system.subtype localize=true}}
{{#each equipmentTypes as |etype key|}}
<option value="{{key}}" {{#if (eq key ../system.subtype)}}selected{{/if}}>{{localize etype.label}}</option>
{{/each}}
</select>
<div class="item-qty">
<label>{{localize "CELESTOPOL.Item.quantity"}}</label>

View File

@@ -1,4 +1,4 @@
<div class="tab blessures" data-group="sheet" data-tab="blessures">
<div class="tab blessures {{tab.cssClass}}" data-group="sheet" data-tab="blessures">
<section class="track-section">
<div class="track-header">
<span class="track-title">{{localize "CELESTOPOL.Track.blessures"}}</span>

View File

@@ -1,4 +1,4 @@
<div class="tab competences" data-group="sheet" data-tab="competences">
<div class="tab competences {{tab.cssClass}}" data-group="sheet" data-tab="competences">
<div class="stats-grid">
{{#each stats as |stat statId|}}
<div class="stat-block">

View File

@@ -28,7 +28,9 @@
<label>{{localize "CELESTOPOL.Actor.anomaly"}}</label>
{{#if isEditMode}}
<select name="system.anomaly.type">
{{selectOptions systemFields.anomaly.fields.type.choices selected=system.anomaly.type localize=true}}
{{#each anomalyTypes as |atype key|}}
<option value="{{key}}" {{#if (eq key ../system.anomaly.type)}}selected{{/if}}>{{localize atype.label}}</option>
{{/each}}
</select>
<input type="number" name="system.anomaly.value" value="{{system.anomaly.value}}" min="0" max="8" class="small-input">
{{else}}

View File

@@ -10,14 +10,12 @@
{{#each statSkills as |skill skillId|}}
<div class="score-row">
<span class="score-skill-name">{{localize skill.label}}</span>
{{#if ../isEditable}}
<input type="number" name="system.scores.{{statId}}.{{skillId}}.bonus"
value="{{lookup (lookup (lookup ../system.scores statId) skillId) 'bonus'}}"
value="{{lookup (lookup (lookup ../../system.scores statId) skillId) 'bonus'}}"
min="0" class="score-bonus" title="+bonus">
<input type="number" name="system.scores.{{statId}}.{{skillId}}.malus"
value="{{lookup (lookup (lookup ../system.scores statId) skillId) 'malus'}}"
value="{{lookup (lookup (lookup ../../system.scores statId) skillId) 'malus'}}"
min="0" class="score-malus" title="-malus">
{{/if}}
</div>
{{/each}}
</div>

View File

@@ -1,15 +1,14 @@
<form class="roll-dialog celestopol">
<div class="roll-title">
<span class="stat-label">{{statLabel}}</span>
<span class="separator"></span>
<span class="skill-label">{{skillLabel}}</span>
{{#if statLabel}}<span class="stat-label">{{localize statLabel}}</span><span class="separator"> </span>{{/if}}
<span class="skill-label">{{localize skillLabel}}</span>
</div>
<div class="form-group">
<label for="moonPhase">{{localize "CELESTOPOL.Roll.moonPhase"}}</label>
<select id="moonPhase" name="moonPhase">
{{#each moonPhases as |phase key|}}
<option value="{{key}}" {{#if (eq key ../currentMoonPhase)}}selected{{/if}}>
{{#each moonPhaseChoices as |phase key|}}
<option value="{{key}}" {{#if (eq key ../defaultMoonPhase)}}selected{{/if}}>
{{localize phase.label}} {{#if phase.bonus}}(+{{phase.bonus}}){{else}}(+0){{/if}}
</option>
{{/each}}
@@ -19,9 +18,9 @@
<div class="form-group">
<label for="difficulty">{{localize "CELESTOPOL.Roll.difficulty"}}</label>
<select id="difficulty" name="difficulty">
{{#each difficulties as |diff key|}}
<option value="{{diff.threshold}}" {{#if (eq diff.threshold ../currentDifficulty)}}selected{{/if}}>
{{localize diff.label}} ({{diff.threshold}})
{{#each difficultyChoices as |diff key|}}
<option value="{{key}}" {{#if (eq key ../defaultDifficulty)}}selected{{/if}}>
{{localize diff.label}}{{#if diff.value}} ({{diff.value}}){{/if}}
</option>
{{/each}}
</select>
@@ -29,7 +28,7 @@
<div class="form-group">
<label for="modifier">{{localize "CELESTOPOL.Roll.modifier"}}</label>
<input type="number" id="modifier" name="modifier" value="0">
<input type="number" id="modifier" name="modifier" value="0" min="-10" max="10">
</div>
<div class="dice-preview">