From edeedb6b3d0d41d9fade74c72605ab1984abbfa6 Mon Sep 17 00:00:00 2001 From: fabres Date: Sat, 8 Aug 2026 17:31:50 +0200 Subject: [PATCH] =?UTF-8?q?fix(creation):=20fallback=20=C3=A9quipement=20a?= =?UTF-8?q?rch=C3=A9type,=20ergonomie=20et=20r=C3=A9capitulatif?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - équipements non retrouvés dans les compendiums recopiés depuis l'archétype (fallback fromArchetype) : liste, budget, création d'items et conteneurs OK - correction du spread system qui écrasait quantite/cout/encombrement - fenêtre +10% de hauteur, titres et boutons de navigation compactés - formulaire remplit la fenêtre v13 : boutons calés en bas sur toutes les étapes - textes du récapitulatif en brun (--wizard-text-body), caracs en pastilles --- css/foundryvtt-reve-de-dragon.css | 160 +++++++++++++---- less/colors.less | 1 + less/foundryvtt-reve-de-dragon.less | 164 ++++++++++++++---- .../creation/creation-personnage-wizard.mjs | 111 ++++++++---- templates/actor/creation/wizard-main.hbs | 22 ++- 5 files changed, 356 insertions(+), 102 deletions(-) diff --git a/css/foundryvtt-reve-de-dragon.css b/css/foundryvtt-reve-de-dragon.css index 2e66d55a..1d28afe3 100644 --- a/css/foundryvtt-reve-de-dragon.css +++ b/css/foundryvtt-reve-de-dragon.css @@ -123,6 +123,7 @@ body { --wizard-accent-magic: #9370DB; --wizard-text-primary: #F5F5DC; --wizard-text-secondary: #D2B48C; + --wizard-text-body: #8B6914; --wizard-border: rgba(191, 149, 63, 0.4); --wizard-step-active: rgba(212, 175, 55, 0.3); --wizard-step-done: rgba(106, 90, 205, 0.4); @@ -8343,10 +8344,13 @@ body { /* Arriere-plan global avec effets de rêve */ background: var(--wizard-bg-primary); background-image: radial-gradient(circle at 10% 20%, rgba(212, 175, 55, 0.05) 0%, transparent 30%), radial-gradient(circle at 90% 80%, rgba(106, 90, 205, 0.05) 0%, transparent 30%); - min-height: 80vh; + min-height: 60vh; + max-height: calc(100vh - 3rem); display: flex; flex-direction: column; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); + /* Zone interne de la fenêtre v13 : plein écran, colonne flex + (sinon .wizard-content ne remplit pas la hauteur disponible) */ /* ==================== EN-TETE DU WIZARD ==================== */ /* ==================== BARRE DE PROGRESSION ==================== */ /* ==================== CONTENU PRINCIPAL ==================== */ @@ -8358,9 +8362,20 @@ body { /* Tooltips contextuelles */ /* Form group styling - Supprimé pour réduire espacements */ } +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .window-content { + display: flex; + flex-direction: column; + flex: 1; + min-height: 0; + /* Le formulaire (même classe que la fenêtre) doit remplir la zone */ +} +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .window-content > form.rdd-creation-personnage { + flex: 1 1 0%; + min-height: 0; +} .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-header { background: linear-gradient(135deg, var(--gradient-gold), var(--gradient-violet)); - padding: 1rem; + padding: 0.5rem 1rem; border-bottom: 2px solid var(--wizard-border); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); align-items: center; @@ -8368,7 +8383,7 @@ body { } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-header h2 { font-family: "MedievalSharp", serif; - font-size: 1.8rem; + font-size: 1.3rem; color: var(--wizard-accent-gold); text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); margin: 0; @@ -8396,7 +8411,7 @@ body { } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-progress { background: var(--wizard-bg-secondary); - padding: 1rem; + padding: 0.4rem 1rem; border-bottom: 1px solid var(--wizard-border); position: relative; justify-content: space-between; @@ -8420,33 +8435,36 @@ body { display: flex; flex-direction: column; align-items: center; - padding: 0.5rem; + padding: 0.2rem 0.5rem; flex: 1; /* Etat ACTIF */ /* Etat TERMINE */ /* Etat EN ATTENTE */ /* Effet de survol */ } +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-progress .wizard-step .step-icon { + display: none; +} .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-progress .wizard-step .step-num { display: inline-flex; align-items: center; justify-content: center; - width: 2rem; - height: 2rem; + width: 1.5rem; + height: 1.5rem; border-radius: 50%; background: var(--wizard-bg-secondary); - border: 2px solid var(--wizard-border); + border: 1px solid var(--wizard-border); color: var(--wizard-text-secondary); font-family: "GrenzeGotisch", serif; font-weight: bold; - font-size: 1.1rem; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); + font-size: 0.85rem; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); transition: all 0.3s ease; - margin-bottom: 0.3rem; + margin-bottom: 0.15rem; } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-progress .wizard-step .step-label { font-family: "CaslonAntique", serif; - font-size: 0.85rem; + font-size: 0.7rem; color: var(--wizard-text-secondary); white-space: nowrap; text-align: center; @@ -8490,7 +8508,8 @@ body { .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content { flex: 1; padding-right: 0.5rem; - max-height: calc(100vh - 14rem); + display: flex; + flex-direction: column; overflow-y: auto; /* Fond avec texture subtile */ background: var(--wizard-bg-primary); @@ -8507,14 +8526,16 @@ body { /* Budget et indicateurs - style "compteur de rêves" */ /* Listes de compétences et sorts */ /* Grille d'attributs */ + /* Biographie / Description : occuper toute la hauteur restante + (boutons précédent/suivant calés en bas comme les autres étapes) */ } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content h3 { font-family: "MedievalSharp", serif; color: var(--wizard-accent-gold); - font-size: 1.5rem; + font-size: 1.15rem; border-bottom: 1px solid var(--wizard-border); - padding-bottom: 0.5rem; - margin: 0; + padding-bottom: 0.25rem; + margin: 0.25rem 0 0.5rem; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3); } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content h4 { @@ -8525,7 +8546,7 @@ body { } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content p { font-family: "CaslonAntique", serif; - color: var(--wizard-text-secondary); + color: var(--wizard-text-body); font-size: 1rem; line-height: 1.6; margin: 0.8rem 0; @@ -8603,7 +8624,8 @@ body { margin: 0; padding: 0; overflow-y: auto; - max-height: calc(60vh - 7rem); + flex: 1; + min-height: 0; background: rgba(0, 0, 0, 0.05); border-radius: 4px; } @@ -8639,6 +8661,20 @@ body { background: linear-gradient(135deg, rgba(106, 90, 205, 0.15), rgba(147, 112, 219, 0.1)); border-left: 3px solid var(--wizard-accent-dream); } +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .liste-competences-creation .list-item.xp-depense, +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .liste-sorts-creation .list-item.xp-depense { + background: rgba(212, 175, 55, 0.15); + box-shadow: inset 3px 0 0 var(--wizard-accent-gold); +} +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .liste-competences-creation .list-item.xp-depense .comp-nom::before, +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .liste-sorts-creation .list-item.xp-depense .comp-nom::before { + content: "✦ "; + color: var(--wizard-accent-gold); +} +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .liste-competences-creation .list-item.xp-depense .comp-cout, +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .liste-sorts-creation .list-item.xp-depense .comp-cout { + color: #FFD700; +} .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .liste-competences-creation .comp-nom, .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .liste-sorts-creation .comp-nom, .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .liste-competences-creation .sort-nom, @@ -8694,17 +8730,19 @@ body { .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .attr-grid { display: grid; grid-template-columns: repeat(2, 1fr); - gap: 1rem; + gap: 0.6rem 1rem; } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .attr-grid .form-group { display: flex; - flex-direction: column; - gap: 0.3rem; + flex-direction: row; + align-items: center; + gap: 0.5rem; } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .attr-grid .form-group label { font-family: "CaslonAntique", serif; - color: var(--wizard-text-primary); + color: var(--wizard-text-body); font-weight: 500; + flex: 0 0 7.5rem; } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .attr-grid .form-group input, .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .attr-grid .form-group select { @@ -8712,9 +8750,10 @@ body { border: 1px solid var(--wizard-border); color: var(--wizard-text-primary); font-family: "CaslonAntique", serif; - padding: 0.5rem; + padding: 0.3rem 0.5rem; border-radius: 4px; - width: 100%; + flex: 1; + min-width: 0; box-sizing: border-box; } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .attr-grid .form-group input:focus, @@ -8737,6 +8776,24 @@ body { .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content textarea.attr-input { box-sizing: border-box; } +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content > .form-group:has(textarea) { + display: flex; + flex-direction: column; + gap: 0.3rem; + flex: 1; + min-height: 0; +} +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content > .form-group:has(textarea) textarea { + flex: 1; + min-height: 80px; + resize: none; + width: 100%; +} +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content > .form-group > label { + font-family: "CaslonAntique", serif; + color: var(--wizard-text-body); + font-weight: 500; +} .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .archetype-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); @@ -8798,6 +8855,11 @@ body { .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .equip-filtres input { flex: 1; } +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .equip-arborescence { + flex: 1; + min-height: 12rem; + overflow-y: auto; +} .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-content .equip-arborescence .equip-type { margin-bottom: 0.3rem; } @@ -8876,6 +8938,9 @@ body { } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-warning { margin: 0.5rem 0; + max-height: 6rem; + overflow-y: auto; + flex-shrink: 0; } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-warning ul { margin: 0; @@ -8900,17 +8965,17 @@ body { } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-buttons { background: var(--wizard-bg-secondary); - padding: 1rem; + padding: 0.4rem 0.6rem; border-top: 1px solid var(--wizard-border); justify-content: flex-end; - gap: 0.8rem; - margin-top: 0.5rem; + gap: 0.5rem; + margin-top: 0.25rem; } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .wizard-buttons button { font-family: "MedievalSharp", serif; - font-size: 1.1rem; - letter-spacing: 1px; - padding: 0.6rem 2rem; + font-size: 0.9rem; + letter-spacing: 0.5px; + padding: 0.25rem 1rem; border: 1px solid var(--wizard-border); border-radius: 4px; cursor: pointer; @@ -8953,6 +9018,7 @@ body { border-radius: 4px; padding: 1rem; margin-bottom: 1.5rem; + /* Caractéristiques en "pastilles" (style tableau de rune) */ } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .recap-section h4 { font-family: "MedievalSharp", serif; @@ -8969,15 +9035,45 @@ body { padding: 0.3rem 0; border-bottom: 1px solid rgba(191, 149, 63, 0.1); font-family: "CaslonAntique", serif; - color: var(--wizard-text-secondary); + color: var(--wizard-text-body); } .system-foundryvtt-reve-de-dragon .rdd-creation-personnage .recap-section p { font-family: "CaslonAntique", serif; - color: var(--wizard-text-secondary); + color: var(--wizard-text-body); font-size: 1rem; line-height: 1.6; margin: 0.5rem 0; } +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .recap-section .recup-caracs, +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .recap-section .recap-derivees { + flex-wrap: wrap; + gap: 0.4rem; + margin: 0.4rem 0; +} +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .recap-section .recup-caracs .recap-chip, +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .recap-section .recap-derivees .recap-chip { + display: flex; + align-items: center; + gap: 0.4rem; + background: rgba(0, 0, 0, 0.15); + border: 1px solid var(--wizard-border); + border-radius: 4px; + padding: 0.25rem 0.6rem; + font-family: "CaslonAntique", serif; +} +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .recap-section .recup-caracs .recap-chip .recap-chip-label, +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .recap-section .recap-derivees .recap-chip .recap-chip-label { + color: var(--wizard-text-body); + font-weight: 500; +} +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .recap-section .recup-caracs .recap-chip .recap-chip-value, +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .recap-section .recap-derivees .recap-chip .recap-chip-value { + color: var(--wizard-text-body); + font-weight: bold; +} +.system-foundryvtt-reve-de-dragon .rdd-creation-personnage .recap-section .recap-derivees { + margin-top: 0.6rem; +} @keyframes pulse-glow { 0% { box-shadow: 0 0 5px rgba(212, 175, 55, 0.5); diff --git a/less/colors.less b/less/colors.less index 573ece6c..258d434e 100644 --- a/less/colors.less +++ b/less/colors.less @@ -73,6 +73,7 @@ body { --wizard-accent-magic: #9370DB; --wizard-text-primary: #F5F5DC; --wizard-text-secondary: #D2B48C; + --wizard-text-body: #8B6914; --wizard-border: rgba(191, 149, 63, 0.4); --wizard-step-active: rgba(212, 175, 55, 0.3); --wizard-step-done: rgba(106, 90, 205, 0.4); diff --git a/less/foundryvtt-reve-de-dragon.less b/less/foundryvtt-reve-de-dragon.less index d5322466..12dfaae1 100644 --- a/less/foundryvtt-reve-de-dragon.less +++ b/less/foundryvtt-reve-de-dragon.less @@ -3155,15 +3155,31 @@ background-image: radial-gradient(circle at 10% 20%, rgba(212, 175, 55, 0.05) 0%, transparent 30%), radial-gradient(circle at 90% 80%, rgba(106, 90, 205, 0.05) 0%, transparent 30%); - min-height: 80vh; + min-height: 60vh; + max-height: calc(100vh - 3rem); display: flex; flex-direction: column; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); + /* Zone interne de la fenêtre v13 : plein écran, colonne flex + (sinon .wizard-content ne remplit pas la hauteur disponible) */ + .window-content { + display: flex; + flex-direction: column; + flex: 1; + min-height: 0; + + /* Le formulaire (même classe que la fenêtre) doit remplir la zone */ + > form.rdd-creation-personnage { + flex: 1 1 0%; + min-height: 0; + } + } + /* ==================== EN-TETE DU WIZARD ==================== */ .wizard-header { background: linear-gradient(135deg, var(--gradient-gold), var(--gradient-violet)); - padding: 1rem; + padding: 0.5rem 1rem; border-bottom: 2px solid var(--wizard-border); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); align-items: center; @@ -3171,7 +3187,7 @@ h2 { font-family: "MedievalSharp", serif; - font-size: 1.8rem; + font-size: 1.3rem; color: var(--wizard-accent-gold); text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); margin: 0; @@ -3205,7 +3221,7 @@ /* ==================== BARRE DE PROGRESSION ==================== */ .wizard-progress { background: var(--wizard-bg-secondary); - padding: 1rem; + padding: 0.4rem 1rem; border-bottom: 1px solid var(--wizard-border); position: relative; justify-content: space-between; @@ -3231,30 +3247,34 @@ display: flex; flex-direction: column; align-items: center; - padding: 0.5rem; + padding: 0.2rem 0.5rem; flex: 1; + .step-icon { + display: none; + } + .step-num { display: inline-flex; align-items: center; justify-content: center; - width: 2rem; - height: 2rem; + width: 1.5rem; + height: 1.5rem; border-radius: 50%; background: var(--wizard-bg-secondary); - border: 2px solid var(--wizard-border); + border: 1px solid var(--wizard-border); color: var(--wizard-text-secondary); font-family: "GrenzeGotisch", serif; font-weight: bold; - font-size: 1.1rem; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); + font-size: 0.85rem; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); transition: all 0.3s ease; - margin-bottom: 0.3rem; + margin-bottom: 0.15rem; } .step-label { font-family: "CaslonAntique", serif; - font-size: 0.85rem; + font-size: 0.7rem; color: var(--wizard-text-secondary); white-space: nowrap; text-align: center; @@ -3316,7 +3336,8 @@ .wizard-content { flex: 1; padding-right: 0.5rem; - max-height: calc(100vh - 14rem); + display: flex; + flex-direction: column; overflow-y: auto; /* Fond avec texture subtile */ @@ -3334,10 +3355,10 @@ h3 { font-family: "MedievalSharp", serif; color: var(--wizard-accent-gold); - font-size: 1.5rem; + font-size: 1.15rem; border-bottom: 1px solid var(--wizard-border); - padding-bottom: 0.5rem; - margin: 0; + padding-bottom: 0.25rem; + margin: 0.25rem 0 0.5rem; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3); } @@ -3350,7 +3371,7 @@ p { font-family: "CaslonAntique", serif; - color: var(--wizard-text-secondary); + color: var(--wizard-text-body); font-size: 1rem; line-height: 1.6; margin: 0.8rem 0; @@ -3439,7 +3460,8 @@ margin: 0; padding: 0; overflow-y: auto; - max-height: calc(60vh - 7rem); + flex: 1; + min-height: 0; background: rgba(0, 0, 0, 0.05); border-radius: 4px; @@ -3474,6 +3496,20 @@ rgba(106, 90, 205, 0.15), rgba(147, 112, 219, 0.1)); border-left: 3px solid var(--wizard-accent-dream); } + + &.xp-depense { + background: rgba(212, 175, 55, 0.15); + box-shadow: inset 3px 0 0 var(--wizard-accent-gold); + + .comp-nom::before { + content: "✦ "; + color: var(--wizard-accent-gold); + } + + .comp-cout { + color: #FFD700; + } + } } .comp-nom, .sort-nom { @@ -3518,17 +3554,19 @@ .attr-grid { display: grid; grid-template-columns: repeat(2, 1fr); - gap: 1rem; + gap: 0.6rem 1rem; .form-group { display: flex; - flex-direction: column; - gap: 0.3rem; + flex-direction: row; + align-items: center; + gap: 0.5rem; label { font-family: "CaslonAntique", serif; - color: var(--wizard-text-primary); + color: var(--wizard-text-body); font-weight: 500; + flex: 0 0 7.5rem; } input, select { @@ -3536,9 +3574,10 @@ border: 1px solid var(--wizard-border); color: var(--wizard-text-primary); font-family: "CaslonAntique", serif; - padding: 0.5rem; + padding: 0.3rem 0.5rem; border-radius: 4px; - width: 100%; + flex: 1; + min-width: 0; box-sizing: border-box; &:focus { @@ -3560,6 +3599,29 @@ .attr-input { width: 100%; } textarea.attr-input { box-sizing: border-box; } + /* Biographie / Description : occuper toute la hauteur restante + (boutons précédent/suivant calés en bas comme les autres étapes) */ + > .form-group:has(textarea) { + display: flex; + flex-direction: column; + gap: 0.3rem; + flex: 1; + min-height: 0; + + textarea { + flex: 1; + min-height: 80px; + resize: none; + width: 100%; + } + } + + > .form-group > label { + font-family: "CaslonAntique", serif; + color: var(--wizard-text-body); + font-weight: 500; + } + .archetype-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); @@ -3617,6 +3679,9 @@ input { flex: 1; } } .equip-arborescence { + flex: 1; + min-height: 12rem; + overflow-y: auto; .equip-type { margin-bottom: 0.3rem; &.hidden { display: none; } @@ -3675,6 +3740,9 @@ /* ==================== ERREURS ==================== */ .wizard-warning { margin: 0.5rem 0; + max-height: 6rem; + overflow-y: auto; + flex-shrink: 0; ul { margin: 0; padding-left: 1.2rem; @@ -3702,17 +3770,17 @@ /* ==================== BOUTONS DE NAVIGATION ==================== */ .wizard-buttons { background: var(--wizard-bg-secondary); - padding: 1rem; + padding: 0.4rem 0.6rem; border-top: 1px solid var(--wizard-border); justify-content: flex-end; - gap: 0.8rem; - margin-top: 0.5rem; + gap: 0.5rem; + margin-top: 0.25rem; button { font-family: "MedievalSharp", serif; - font-size: 1.1rem; - letter-spacing: 1px; - padding: 0.6rem 2rem; + font-size: 0.9rem; + letter-spacing: 0.5px; + padding: 0.25rem 1rem; border: 1px solid var(--wizard-border); border-radius: 4px; cursor: pointer; @@ -3778,17 +3846,49 @@ padding: 0.3rem 0; border-bottom: 1px solid rgba(191, 149, 63, 0.1); font-family: "CaslonAntique", serif; - color: var(--wizard-text-secondary); + color: var(--wizard-text-body); } } p { font-family: "CaslonAntique", serif; - color: var(--wizard-text-secondary); + color: var(--wizard-text-body); font-size: 1rem; line-height: 1.6; margin: 0.5rem 0; } + + /* Caractéristiques en "pastilles" (style tableau de rune) */ + .recup-caracs, .recap-derivees { + flex-wrap: wrap; + gap: 0.4rem; + margin: 0.4rem 0; + + .recap-chip { + display: flex; + align-items: center; + gap: 0.4rem; + background: rgba(0, 0, 0, 0.15); + border: 1px solid var(--wizard-border); + border-radius: 4px; + padding: 0.25rem 0.6rem; + font-family: "CaslonAntique", serif; + + .recap-chip-label { + color: var(--wizard-text-body); + font-weight: 500; + } + + .recap-chip-value { + color: var(--wizard-text-body); + font-weight: bold; + } + } + } + + .recap-derivees { + margin-top: 0.6rem; + } } /* ==================== ANIMATIONS ==================== */ diff --git a/module/actor/creation/creation-personnage-wizard.mjs b/module/actor/creation/creation-personnage-wizard.mjs index 8eb8b1a2..f6430a1c 100644 --- a/module/actor/creation/creation-personnage-wizard.mjs +++ b/module/actor/creation/creation-personnage-wizard.mjs @@ -60,7 +60,7 @@ export class CreationPersonnageWizard extends HandlebarsApplicationMixin(foundry static DEFAULT_OPTIONS = { classes: ['rdd-creation-personnage'], window: { title: "Création de personnage" }, - position: { width: 760, height: 'fit-content' }, + position: { width: 760, height: 792 }, }; constructor(options = {}) { @@ -250,33 +250,44 @@ export class CreationPersonnageWizard extends HandlebarsApplicationMixin(foundry } } - // Équipement : mapper par nom, fortune = total monnaies de l'archétype. + // Équipement : mapper par nom ; à défaut, recopier l'item de l'archétype + // tel quel (il n'existe pas dans le compendium équipement). // La structure (dont le contenu des conteneurs) est prise depuis l'item - // du voyageur, les coûts/encombrements depuis le compendium équipement. + // du voyageur, les coûts/encombrements depuis le compendium équipement + // (ou depuis l'item lui-même en fallback). this.data.equipement.selection = {}; this._archetypeIdMap = new Map(); const itemsEquip = voyageur.items.filter(i => ![ITEM_TYPES.competence, ITEM_TYPES.monnaie, ITEM_TYPES.sort, ITEM_TYPES.tete].includes(i.type)); for (const item of itemsEquip) { const equip = this._equipement.find(e => Grammar.equalsInsensitive(e.name, item.name)); + const quantite = Number(item.system.quantite ?? 1); + if (quantite <= 0) continue; + const structure = { ...item.system }; + delete structure._id; if (equip) { - const quantite = Number(item.system.quantite ?? 1); - if (quantite > 0) { - const structure = { ...item.system }; - delete structure._id; - this._archetypeIdMap.set(item.id, equip._id); - this.data.equipement.selection[equip._id] = { - item: { ...equip, structure }, - quantite, - }; - } + this._archetypeIdMap.set(item.id, equip._id); + this.data.equipement.selection[equip._id] = { + item: { ...equip, structure }, + quantite, + }; } else { - this.data.equipement.nonMappes.push(item.name); + this._archetypeIdMap.set(item.id, item._id); + this.data.equipement.selection[item._id] = { + item: { + _id: item._id, + name: item.name, + type: item.type, + img: item.img, + structure, + cout: Number(item.system.cout ?? 0), + encombrement: Number(item.system.encombrement ?? 0), + fromArchetype: true, + }, + quantite, + }; } } - const fortune = voyageur.items - .filter(i => i.type === ITEM_TYPES.monnaie) - .reduce((sum, m) => sum + (Number(m.system.cout ?? 0) * Number(m.system.quantite ?? 0)), 0); - this.data.equipement.fortune = Number(fortune.toFixed(2)); + this.data.equipement.fortune = FORTUNE_DEFAUT; // Token / image this._archetypeImg = voyageur.img; @@ -338,21 +349,34 @@ export class CreationPersonnageWizard extends HandlebarsApplicationMixin(foundry break; case ETAPE_CARACTERISTIQUES: - el.querySelectorAll("input.carac-input").forEach(inp => - inp.addEventListener("input", event => { - const carac = event.target.dataset.carac; - const min = carac === 'beaute' ? 10 : 6; - const max = carac === 'beaute' ? 16 : 15; - const raw = Number(event.target.value); - const val = Math.max(min, Math.min(max, Number.isNaN(raw) ? min : raw)); - event.target.value = val; + el.querySelectorAll("input.carac-input").forEach(inp => { + const min = () => inp.dataset.carac === 'beaute' ? 10 : 6; + const max = () => inp.dataset.carac === 'beaute' ? 16 : 15; + const lire = () => { + const carac = inp.dataset.carac; + const raw = Number(inp.value); + const val = Math.max(min(), Math.min(max(), Number.isNaN(raw) ? min() : raw)); + return { carac, val }; + }; + const stocker = ({ carac, val }) => { if (carac === 'beaute') { this.data.beaute = val; } else { this.data.caracs[carac] = val; } this._mettreAJourBudget(el); - })); + }; + inp.addEventListener("input", () => { + // On ne réécrit pas le champ pendant la frappe (sinon taper + // "12" donnerait "1" -> clamp 6 -> puis "62" -> clamp 15). + stocker(lire()); + }); + inp.addEventListener("change", () => { + const { carac, val } = lire(); + inp.value = val; + stocker({ carac, val }); + }); + }); break; case ETAPE_COMPETENCES: { @@ -377,6 +401,7 @@ export class CreationPersonnageWizard extends HandlebarsApplicationMixin(foundry comp.system.xp = 0; const li = event.target.closest(".list-item"); if (li) { + li.classList.toggle("xp-depense", nouveauNiveau > comp.system.base); const coutEl = li.querySelector(".comp-cout"); if (coutEl) coutEl.textContent = coutApres; } @@ -468,14 +493,19 @@ export class CreationPersonnageWizard extends HandlebarsApplicationMixin(foundry } _changerQuantite(el, itemId, delta) { - const item = this._equipement.find(it => it._id === itemId); + const item = this._getEquipementItem(itemId); if (!item) return; const actuel = this.data.equipement.selection[itemId]?.quantite ?? 0; this._setQuantite(el, itemId, actuel + delta); } + _getEquipementItem(itemId) { + return this._equipement.find(it => it._id === itemId) + ?? this.data.equipement.selection[itemId]?.item; + } + _setQuantite(el, itemId, quantite) { - const item = this._equipement.find(it => it._id === itemId); + const item = this._getEquipementItem(itemId); if (!item) return; quantite = Math.max(0, quantite); if (quantite === 0) { @@ -536,6 +566,7 @@ export class CreationPersonnageWizard extends HandlebarsApplicationMixin(foundry setColor("#budget-competences-restant", bp.restant); set("#budget-sorts-depense", bs.depense); setColor("#budget-sorts-restant", bs.restant); + setColor("#budget-pool-restant", bp.restant); set("#budget-equip-fortune", be.fortune.toFixed(2)); set("#budget-equip-depense", be.depense.toFixed(2)); setColor("#budget-equip-restant", be.restant); @@ -739,6 +770,19 @@ export class CreationPersonnageWizard extends HandlebarsApplicationMixin(foundry depense: selection ? selection.quantite * item.cout : 0, }); } + for (const sel of Object.values(this.data.equipement.selection)) { + if (!sel.item.fromArchetype) continue; + if (this._equipement.some(it => it._id === sel.item._id)) continue; + const item = sel.item; + if (filtre !== "tous" && filtre !== item.type) continue; + if (recherche && !item.name.toLowerCase().includes(recherche)) continue; + if (!groupes[item.type]) groupes[item.type] = []; + groupes[item.type].push({ + ...item, + quantite: sel.quantite, + depense: sel.quantite * item.cout, + }); + } return Object.entries(groupes).map(([type, items]) => ({ type, items })); } @@ -884,13 +928,13 @@ export class CreationPersonnageWizard extends HandlebarsApplicationMixin(foundry // la hiérarchie des conteneurs. const itemsCrees = []; for (const sel of selection) { - const item = this._equipement.find(it => it._id === sel.item._id); + const item = this._getEquipementItem(sel.item._id); if (!item) continue; const system = { + ...(item.structure ? { ...item.structure } : {}), quantite: sel.quantite, cout: item.cout, encombrement: item.encombrement, - ...(item.structure ? { ...item.structure } : {}), }; delete system.contenu; // recréé après le mapping delete system._id; @@ -980,7 +1024,10 @@ export class CreationPersonnageWizard extends HandlebarsApplicationMixin(foundry } _typesEquipement() { - const types = [...new Set(this._equipement.map(it => it.type))].sort(); + const types = [...new Set([ + ...this._equipement.map(it => it.type), + ...Object.values(this.data.equipement.selection).map(sel => sel.item.type), + ])].sort(); return types; } diff --git a/templates/actor/creation/wizard-main.hbs b/templates/actor/creation/wizard-main.hbs index 180fece8..767c2e7d 100644 --- a/templates/actor/creation/wizard-main.hbs +++ b/templates/actor/creation/wizard-main.hbs @@ -100,7 +100,7 @@ Coût {{#each competences}} -
  • +
  • {{this.name}} {{this.system.categorie}} {{this.system.base}} @@ -122,8 +122,9 @@

    Sorts et rituels (max 300 points)

    Les sorts coûtent leur difficulté × 10 (Annulation de magie : 70 points). Un sort n'est accessible que si sa difficulté ne dépasse pas le niveau de Draconic + 3. Maximum 300 points sur les 3000.

    - Sorts dépensé : {{budgetSorts.depense}} - Restant : {{budgetSorts.restant}} + Sorts dépensé : {{budgetSorts.depense}} / {{MAX_XP_SORTS}} + Restant (cap sorts) : {{budgetSorts.restant}} + Restant XP disponible (avec sorts) : {{budgetCompetences.restant}}