Import de jeu : catégories conditionnelles (mode alternatif)
Build and Publish Docker Image / build-and-push-image (push) Successful in 1m2s

- ScoringCategory.requiresOption : une catégorie n'apparaît/compte que si
  l'option booléenne correspondante est activée (mode/extension déclaratif)
- toGameConfig génère getScoringCategories filtrant selon les options
- Gabarit harmonies-esprits.json : mode "Esprits de la nature" activable
  ajoutant la catégorie "Animaux spirituels" au décompte
- Doc à jour

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Zed
2026-07-22 18:12:54 +02:00
parent dacb5b49cb
commit 9352bb08d9
4 changed files with 47 additions and 0 deletions
+1
View File
@@ -248,6 +248,7 @@ Le score de la manche = **somme des catégories**.
| `label` | Libellé affiché. |
| `icon` | *(optionnel)* nom d'icône **lucide** affichée à côté de la catégorie. |
| `color` | *(optionnel)* teinte hex de l'icône. |
| `requiresOption` | *(optionnel)* `id` d'une option booléenne : la catégorie n'apparaît (et n'est comptée) **que si cette option est activée**. Idéal pour un mode/extension (ex : « Animaux spirituels »). |
> Généralement associé à `fixedRounds: 1` (un seul décompte final réparti en
> catégories).
@@ -0,0 +1,36 @@
{
"schemaVersion": 1,
"id": "harmonies-esprits",
"name": "Harmonies — Esprits",
"minPlayers": 1,
"maxPlayers": 4,
"scoreType": "positive",
"scoreFormula": { "strategy": "sum_rounds" },
"fixedRounds": 1,
"description": "Harmonies avec le mode alternatif « Esprits de la nature » (activable avant la partie).",
"icon": "TreePine",
"colors": { "primary": "#065f46" },
"options": [
{
"id": "esprits_nature",
"label": "Mode : Esprits de la nature",
"type": "boolean",
"defaultValue": false
}
],
"scoringCategories": [
{ "id": "arbres", "label": "Arbres", "icon": "TreePine", "color": "#16a34a" },
{ "id": "montagnes", "label": "Montagnes", "icon": "Mountain", "color": "#64748b" },
{ "id": "champs", "label": "Champs", "icon": "Wheat", "color": "#d97706" },
{ "id": "batiments", "label": "Bâtiments", "icon": "Building2", "color": "#dc2626" },
{ "id": "eau", "label": "Rivière", "icon": "Waves", "color": "#0ea5e9" },
{ "id": "animaux", "label": "Animaux", "icon": "Rabbit", "color": "#a16207" },
{
"id": "animaux_spirituels",
"label": "Animaux spirituels",
"icon": "Sparkles",
"color": "#8b5cf6",
"requiresOption": "esprits_nature"
}
]
}
+1
View File
@@ -6,6 +6,7 @@ export interface ScoringCategory {
label: string;
icon?: string; // nom d'icône lucide (ex: "TreePine") — visuel de la catégorie
color?: string; // teinte d'accent hex pour l'icône
requiresOption?: string; // n'apparaît que si cette option (booléenne) est activée
}
export interface GameConfig {
+9
View File
@@ -7,6 +7,7 @@ const scoringCategorySchema = z.object({
label: z.string(),
icon: z.string().max(40).optional(),
color: z.string().max(30).optional(),
requiresOption: z.string().max(60).optional(),
});
const gameOptionSchema = z.object({
@@ -132,6 +133,14 @@ export function toGameConfig(def: ImportedGameDefinition): GameConfig {
}
}
// Option-dependent categories (e.g. an alternative game mode). If any category
// is gated by an option, expose them through getScoringCategories.
if (def.scoringCategories?.some((c) => c.requiresOption)) {
const cats = def.scoringCategories;
config.getScoringCategories = (options) =>
cats.filter((c) => !c.requiresOption || !!options?.[c.requiresOption]);
}
// Score aggregation
if (def.scoreFormula.strategy === "sum_rounds_with_reset") {
const { resetThreshold, resetTo, oncePerPlayer } = def.scoreFormula;