Remplace le système de quêtes par des déclencheurs, ajoute l'action variable et le chaînage
Supprime le concept de "quête" au profit d'un onglet unique "Déclencheurs"
portant toute la logique (dialogue, condition, marquage terminé) directement
sur l'objet de scène. Ajoute une nouvelle action "Modifier une variable"
(réutilisant le vocabulaire du graphe de flow) utilisable après une
collision, une interaction ou une branche de condition, ainsi qu'un
chaînage d'actions ("then") permettant d'enchaîner plusieurs actions à la
suite et d'étendre un déclencheur déjà posé sans le recréer.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
c504ace167
commit
d664ed5637
+165
-32
@@ -725,7 +725,7 @@ body.builderBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; d
|
||||
static/js/play/dialogue-box-controller.js) : header/body/footer,
|
||||
toujours VISIBLE dans l'éditeur (texte d'exemple, pour le positionner/
|
||||
styliser) mais masqué par défaut EN JEU tant qu'aucune règle de
|
||||
collision "quete" n'a de réplique à afficher. */
|
||||
collision "dialogue" n'a de réplique à afficher. */
|
||||
.dialogueBoxWidget{
|
||||
display:flex; flex-direction:column; border-radius:10px; overflow:hidden;
|
||||
box-shadow:0 6px 18px rgba(0,0,0,.35); pointer-events:auto;
|
||||
@@ -740,14 +740,6 @@ body.builderBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; d
|
||||
border-radius:6px; padding:5px 12px; font:inherit; font-size:12px; cursor:pointer;
|
||||
}
|
||||
.dialogueBoxNextBtn:hover{ background:rgba(255,255,255,.28); }
|
||||
/* Écran d'offre de quête (voir forgeShowQuestOffer, dialogue-box-controller.js) :
|
||||
Accepter/Refuser remplacent le "Suivant" habituel dans le pied de la
|
||||
boîte — verts/rouges pour rester lisibles sur n'importe quelle couleur
|
||||
de pied choisie par l'auteur (voir "🎨 Style"). */
|
||||
.dialogueBoxAcceptBtn{ background:#2ecc71; border-color:#2ecc71; color:#0b1a10; font-weight:700; }
|
||||
.dialogueBoxAcceptBtn:hover{ background:#3ddb80; }
|
||||
.dialogueBoxDeclineBtn{ background:rgba(224,82,77,.25); border-color:#e0524d; }
|
||||
.dialogueBoxDeclineBtn:hover{ background:rgba(224,82,77,.4); }
|
||||
|
||||
/* Widget "❓ Boîte à quiz" (voir screens/rendering/dialogue_box_style.py,
|
||||
static/js/play/dialogue-box-controller.js) : même squelette que
|
||||
@@ -942,6 +934,14 @@ body.builderBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; d
|
||||
.collisionWizardChoice:hover{ transform:translateY(-3px) scale(1.02); border-color:var(--accent); box-shadow:0 8px 18px rgba(0,0,0,.25); }
|
||||
.collisionWizardChoice .emoji{ font-size:22px; }
|
||||
|
||||
/* Étape "condition" de l'assistant (voir renderCollisionWizardConditionStep,
|
||||
collision-rules-editor.js) : variable / opérateur / valeur sur une
|
||||
ligne — les <select>/<input> reprennent déjà le style générique
|
||||
(voir plus haut, input[type=text]/select). */
|
||||
.collisionWizardConditionForm{ display:flex; gap:8px; flex-wrap:wrap; }
|
||||
.collisionWizardConditionForm select{ flex:1.3; min-width:120px; }
|
||||
.collisionWizardConditionForm input{ flex:0.7; min-width:80px; }
|
||||
|
||||
/* Bulle "Appuie sur X" (voir forgeShowCollisionInteractBubble,
|
||||
collision-rules-controller.js) : SŒUR de l'objet dans son parent
|
||||
(.sceneWorld/.sceneUI, déjà position:relative) plutôt qu'ENFANT
|
||||
@@ -956,10 +956,9 @@ body.builderBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; d
|
||||
white-space:nowrap; pointer-events:none; z-index:20;
|
||||
}
|
||||
|
||||
/* ---- Éditeur de quêtes (onglet "🗺️ Quêtes" à côté de "🧩 Collision",
|
||||
templates/scene_edit.html + modale de dialogue partagée avec
|
||||
l'assistant "+ Action" de l'éditeur de collision, voir
|
||||
static/js/quests/quest-editor.js) ---- */
|
||||
/* ---- Reliquat de l'ancien onglet "🗺️ Quêtes" (retiré, voir onglet
|
||||
"Déclencheurs" et static/js/triggers/trigger-editor.js) — règles
|
||||
orphelines gardées telles quelles, aucune ne s'applique plus. ---- */
|
||||
.questListRow{ cursor:pointer; }
|
||||
.questPill{ display:inline-flex; align-items:center; border-radius:999px; padding:3px 10px; font-size:11.5px; font-weight:700; }
|
||||
.questPill-score{ background:rgba(242,153,74,.18); color:#f2994a; }
|
||||
@@ -984,33 +983,166 @@ body.builderBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; d
|
||||
.questDialogueModal{ z-index:61; }
|
||||
.questDialogueModal .modal-content{ width:100vw; height:100vh; max-width:100vw; max-height:100vh; margin:0; }
|
||||
/* La modale entière est une colonne flex (jamais un scroll global, voir
|
||||
overflow:hidden ici) : le header/la fiche restent fixes en haut, les 3
|
||||
colonnes de répliques se partagent TOUT le reste de la hauteur
|
||||
(demandé explicitement) et défilent CHACUNE indépendamment (voir
|
||||
.questDialogueColumnBubbles plus bas), jamais toute la page. */
|
||||
overflow:hidden ici) : le header reste fixe en haut, le panneau de
|
||||
déclencheurs prend TOUT le reste de la hauteur. */
|
||||
.questDialogueModal .box{ width:100%; height:100%; border-radius:0; overflow:hidden; display:flex; flex-direction:column; }
|
||||
.questDialogueModalContent{ width:100%; height:100%; max-width:100%; }
|
||||
#questDialogueModalBody{ display:flex; flex-direction:column; flex:1; min-height:0; }
|
||||
/* Onglet "Déclencheurs" (templates/scene_edit.html, #triggersTabPanel) —
|
||||
MÊME comportement que #questDialogueModalBody ci-dessus (juste déplacé
|
||||
hors de la modale plein écran dans un onglet, demande explicite :
|
||||
"sans rien toucher au style en place") : colonne flex qui prend tout
|
||||
l'espace du panneau d'onglet actif (voir .builderTabPanel.active). */
|
||||
#triggersTabPanelBody{ display:flex; flex-direction:column; flex:1; min-height:0; }
|
||||
.questDialogueModalHeader{ flex:0 0 auto; margin-bottom:10px; }
|
||||
.questFieldsGrid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(160px, 1fr)); gap:10px; margin-bottom:14px; }
|
||||
.questField{ display:flex; flex-direction:column; gap:4px; font-size:12px; font-weight:600; }
|
||||
.questField-wide{ grid-column:span 2; }
|
||||
.questDialogueColumns{ flex:1; min-height:0; display:grid; grid-template-columns:repeat(3, minmax(220px, 1fr)); gap:14px; }
|
||||
/* La modale de dialogue d'une quête est un GRAPHE DE LOGIQUE lu par
|
||||
déclencheur (demande explicite : "un RH doit le comprendre, un visuel
|
||||
global") : UN SEUL panneau (.questDialogueColumn, 90% de largeur,
|
||||
centré, TOUTE LA HAUTEUR disponible) — les déclencheurs de la quête
|
||||
côte à côte (voir .questTriggersSlot plus bas), chacun avec SON PROPRE
|
||||
dialogue édité EN LIGNE (voir .dialogueBox plus bas), PUIS les 3
|
||||
boutons Réplique/Question/Action TOUJOURS tout en bas — ils ajoutent
|
||||
dans le dialogue du déclencheur ACTIF (voir .questTriggerCol.active),
|
||||
jamais dans une liste séparée. */
|
||||
.questDialogueColumns{ flex:1; min-height:0; display:flex; }
|
||||
.questDialogueColumn{
|
||||
background:rgba(0,0,0,.15); border:1px solid var(--border); border-radius:12px; padding:10px;
|
||||
display:flex; flex-direction:column; gap:8px; height:100%; min-height:0;
|
||||
width:90%; margin:0 auto; height:100%; min-height:0; display:flex; flex-direction:column; gap:8px;
|
||||
background:var(--panel2); border:1px solid var(--border); border-radius:12px; padding:12px;
|
||||
}
|
||||
.questDialogueColumnTitle{ flex:0 0 auto; margin:0 0 2px; font-size:13px; text-align:center; }
|
||||
/* Bulles alignées VERTICALEMENT, centrées dans la colonne, reliées par un
|
||||
trait entre chacune (voir ::before sur .questBubbleRow ci-dessous) —
|
||||
demandé explicitement plutôt qu'un alignement gauche/droite. Seule
|
||||
CETTE zone défile (flex:1 + overflow-y:auto) — le titre de colonne et
|
||||
le bouton "+ Réplique" restent fixes, en haut/en bas. */
|
||||
.questDialogueColumnBubbles{ display:flex; flex-direction:column; align-items:center; flex:1; min-height:0; overflow-y:auto; padding-top:4px; }
|
||||
.questDialogueColumnButtons{ flex:0 0 auto; display:flex; gap:8px; justify-content:center; margin-top:4px; }
|
||||
.questDialogueColumnBody{ display:flex; flex-direction:column; align-items:center; flex:1; min-height:0; overflow-y:auto; gap:14px; padding-top:4px; }
|
||||
.questDialogueColumnButtons{ flex:0 0 auto; display:flex; gap:8px; justify-content:center; flex-wrap:wrap; }
|
||||
.questDialogueAddBtn{ align-self:center; padding:6px 14px; font-size:12px; }
|
||||
.questQuestionAddBtn{ background:linear-gradient(135deg, #e0b93d, #b8890f); }
|
||||
|
||||
/* TOUS les déclencheurs du jeu (voir screens/rendering/
|
||||
trigger_graph.py::list_all_triggers) : réutilise TELLES QUELLES
|
||||
.collisionRuleChain/.collisionRuleLink (collision-rules-editor.js) pour
|
||||
la chaîne de pastilles, juste une petite fiche objet au-dessus. Vit dans le MÊME
|
||||
flux que les répliques (.questDialogueColumnBody ci-dessus), aucun
|
||||
scroll ni cadre séparé ici — plusieurs chaînes possibles côte à côte
|
||||
(flex-wrap). */
|
||||
.questTriggersSlot{ width:100%; display:flex; flex-wrap:wrap; gap:20px; justify-content:center; }
|
||||
.questTriggersSlot:empty::before{ content:"Aucun déclencheur pour l'instant — ajoutes-en un avec le bouton ci-dessous."; color:var(--muted); font-size:13px; }
|
||||
|
||||
/* Carte objet + pastilles empilées VERTICALEMENT, reliées par des flèches
|
||||
(maquette validée avec l'utilisateur) — PAS la chaîne horizontale en
|
||||
chevrons de l'éditeur de collision : deux présentations volontairement
|
||||
différentes pour le même modèle de données sous-jacent. */
|
||||
.questTriggerCol{ position:relative; display:flex; flex-direction:column; align-items:center; width:70%; }
|
||||
/* Modale d'ajout de déclencheur (voir static/js/triggers/trigger-editor.js::
|
||||
openAddTriggerModal) — au-dessus de l'onglet "Déclencheurs", jamais
|
||||
recouverte. */
|
||||
.questTriggerModal{ z-index:62; }
|
||||
.questTriggerDelete{
|
||||
position:absolute; top:-8px; right:2px; width:20px; height:20px; border-radius:50%;
|
||||
background:var(--panel2); border:1px solid var(--border); color:var(--muted, #8b95a7);
|
||||
font-size:10px; display:flex; align-items:center; justify-content:center; cursor:pointer; z-index:2;
|
||||
}
|
||||
.questTriggerDelete:hover{ background:#e0524d; color:#fff; border-color:#e0524d; }
|
||||
.questTriggerObjectCard{
|
||||
width:100%; background:var(--panel2); border:1px solid var(--border); border-radius:12px;
|
||||
padding:10px; display:flex; flex-direction:column; align-items:center; gap:6px; cursor:pointer;
|
||||
}
|
||||
.questTriggerObjectCard img{ width:36px; height:36px; border-radius:8px; object-fit:cover; }
|
||||
.questTriggerObjectCard .questTriggerObjectName{ font-weight:700; font-size:12.5px; text-align:center; }
|
||||
/* Déclencheur ACTIF (voir questClickTriggerObjectCard) : c'est LUI qui
|
||||
reçoit les prochaines répliques/questions ajoutées par les boutons du
|
||||
bas de la colonne — surligné pour que ce soit visible sans avoir à
|
||||
deviner. */
|
||||
.questTriggerCol.active .questTriggerObjectCard{ border-color:#3bb3c9; box-shadow:0 0 0 2px rgba(59,179,201,.35); }
|
||||
/* Accordéon (demande explicite : "ça retracte toute la logique associée") :
|
||||
replié = seule la carte objet reste visible, chevron tourné. */
|
||||
.questTriggerCol.collapsed{ width:auto; min-width:140px; }
|
||||
.questTriggerObjectCard .questTriggerCollapseChevron{ font-size:10px; color:var(--muted); transition:transform .15s ease; }
|
||||
.questTriggerCol.collapsed .questTriggerCollapseChevron{ transform:rotate(-90deg); }
|
||||
.questTriggerConnector{ width:2px; height:16px; background:var(--border); position:relative; flex-shrink:0; }
|
||||
.questTriggerConnector::after{
|
||||
content:""; position:absolute; bottom:0; left:50%; transform:translate(-50%,45%);
|
||||
border:5px solid transparent; border-top-color:var(--border);
|
||||
}
|
||||
/* Flèche menant à une condition — plus grande que les connecteurs
|
||||
ordinaires (demande explicite : "la flèche qui part de interagir vers
|
||||
le losange doit être plus grande"). */
|
||||
.questTriggerConnector.tall{ height:32px; width:3px; }
|
||||
.questTriggerConnector.tall::after{ border-width:7px; }
|
||||
.questTriggerPill{ width:100%; border-radius:100px; padding:8px 14px; font-size:12px; font-weight:700; text-align:center; }
|
||||
.questTriggerPill.trigger{ background:#f2994a; color:#1a1002; }
|
||||
.questTriggerPill.interagir{ background:#d4a72c; color:#1a1002; }
|
||||
.questTriggerPill.quete{ background:#9b59b6; color:#fff; }
|
||||
.questTriggerPill.none{ background:transparent; border:1.5px dashed var(--border); color:var(--muted, #8b95a7); }
|
||||
|
||||
/* Rectangle "dialogue" — même largeur que le reste de la chaîne (100% de
|
||||
son conteneur, comme les pastilles, maquette validée : "le rectangle
|
||||
doit avoir la même width que les autres éléments"). Un bouton "+" en
|
||||
haut à droite ajoute une réplique DIRECTEMENT dedans (voir
|
||||
static/js/triggers/trigger-editor.js::triggerInlineAddBubble) — chaque
|
||||
occurrence de "Déclencher ce dialogue" porte le sien, édité ici même,
|
||||
à l'endroit où la flèche pointe (plus de colonne séparée). */
|
||||
.dialogueBox{
|
||||
width:100%; background:rgba(0,0,0,.18); border:1.5px solid #3bb3c9; border-radius:14px;
|
||||
padding:10px; display:flex; flex-direction:column; gap:8px;
|
||||
}
|
||||
.dialogueBoxHeader{ display:flex; align-items:center; justify-content:space-between; gap:8px; }
|
||||
.dialogueBoxTitle{ font-size:11px; font-weight:800; color:#3bb3c9; text-transform:uppercase; letter-spacing:.04em; }
|
||||
.dialogueBoxActions{ display:flex; gap:4px; }
|
||||
.addReplyBtn{
|
||||
background:#3bb3c9; color:#04222a; border:none; border-radius:999px; padding:5px 14px;
|
||||
font-size:12px; font-weight:800; line-height:1.4; cursor:pointer; flex-shrink:0;
|
||||
}
|
||||
.addReplyBtn:hover{ filter:brightness(1.1); }
|
||||
.addQuestionBtn{ background:linear-gradient(135deg, #e0b93d, #b8890f); color:#1a1002; }
|
||||
|
||||
/* Feuille "Modifier une variable" (voir screens/rendering/collision_rules.py
|
||||
::"variable") — même famille visuelle que .dialogueBox (rectangle
|
||||
pleine largeur), bordure jaune pour la distinguer d'un dialogue au
|
||||
premier coup d'œil, pas de bulles dedans. */
|
||||
.questVariableAction{ border-color:#e0b93d; }
|
||||
.questVariableActionLabel{ margin:0; font-size:13px; color:var(--text); }
|
||||
/* "+ Ajouter une action" en bout de chaîne (demande explicite : "pouvoir
|
||||
modifier un déclencheur pour lui ajouter des actions") — même largeur
|
||||
que le reste de la chaîne, discret (pointillés) tant qu'on ne survole
|
||||
pas. */
|
||||
.questTriggerAddChainedActionBtn{
|
||||
width:100%; background:transparent; border:1.5px dashed var(--border); color:var(--muted, #8b95a7);
|
||||
}
|
||||
.questTriggerAddChainedActionBtn:hover{ border-color:var(--accent); color:var(--accent); }
|
||||
|
||||
/* Losange "condition" — lecture ENTIÈREMENT VERTICALE (demande explicite :
|
||||
"il faut tout mettre verticalement", le losange lui-même ne change
|
||||
pas) : le losange reste petit et centré, la branche qui MÈNE à cette
|
||||
quête descend tout droit en premier (flèche verte ou rouge selon
|
||||
Vrai/Faux) vers "Déclencher ce dialogue" (pleine largeur, comme un
|
||||
déclencheur sans condition) puis son rectangle de dialogue, PUIS
|
||||
l'autre branche descend à son tour vers "Ne rien faire" — jamais deux
|
||||
branches côte à côte. */
|
||||
.questCondColumn{ width:100%; display:flex; flex-direction:column; align-items:center; }
|
||||
/* Un VRAI losange (carré tourné à 45°, pas un rectangle aplati) — voir
|
||||
demande explicite "je veut un vrai losange comme avant". */
|
||||
.questCondDiamond{
|
||||
width:150px; height:150px; margin:16px 0; transform:rotate(45deg);
|
||||
background:#3bb3c9; color:#04222a; display:flex; align-items:center; justify-content:center; border-radius:16%;
|
||||
box-shadow:0 4px 14px rgba(59,179,201,.35);
|
||||
}
|
||||
.questCondDiamond span{ transform:rotate(-45deg); font-size:11.5px; font-weight:800; text-align:center; line-height:1.3; padding:0 12px; }
|
||||
/* Flèches Vrai/Faux plus grandes — demande explicite "c'est trop petit
|
||||
trop tassé". */
|
||||
.questCondArrowWrap{ position:relative; display:flex; flex-direction:column; align-items:center; width:100%; height:68px; }
|
||||
.questCondArrowWrap svg{ width:34px; height:100%; overflow:visible; }
|
||||
.questCondArrowLabel{
|
||||
position:absolute; left:calc(50% + 26px); top:14px; z-index:2; border-radius:999px; padding:6px 16px;
|
||||
font-size:12.5px; font-weight:800; white-space:nowrap;
|
||||
}
|
||||
.questCondArrowLabel.yes{ background:rgba(46,204,113,.18); color:#2ecc71; border:1px solid rgba(46,204,113,.4); }
|
||||
.questCondArrowLabel.no{ background:rgba(224,82,77,.18); color:#e0524d; border:1px solid rgba(224,82,77,.4); }
|
||||
|
||||
.questTriggerObjectThumb{ width:40px; height:40px; border-radius:8px; overflow:hidden; background:var(--panel2); display:flex; align-items:center; justify-content:center; }
|
||||
.questTriggerObjectThumb img{ width:100%; height:100%; object-fit:cover; }
|
||||
.questTriggerObjectChoice{ align-items:center; }
|
||||
.questTriggerObjectChoice.is-selected{ border-color:var(--accent); box-shadow:0 0 0 2px var(--accent); }
|
||||
|
||||
.questBubbleRow{ display:flex; justify-content:center; width:100%; position:relative; }
|
||||
.questBubbleRow:not(:first-child)::before{
|
||||
content:''; position:absolute; top:-14px; left:50%; transform:translateX(-50%);
|
||||
@@ -1029,14 +1161,15 @@ body.builderBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; d
|
||||
.questBubble-pnj .questBubbleBody{ background:rgba(47,111,237,.16); }
|
||||
.questBubble-joueur .questBubbleHeader{ background:#1e9e57; }
|
||||
.questBubble-joueur .questBubbleBody{ background:rgba(46,204,113,.16); }
|
||||
/* "❓ Question" (voir questQuestionBubbleHtml, static/js/quests/
|
||||
quest-editor.js) — bulle JAUNE distincte des répliques de dialogue,
|
||||
/* "❓ Question" (voir triggerQuestionBubbleHtml, static/js/triggers/
|
||||
trigger-editor.js) — bulle JAUNE distincte des répliques de dialogue,
|
||||
même chaîne/alignement vertical (.questBubbleRow). */
|
||||
.questBubble-question .questBubbleHeader{ background:#b8890f; flex-wrap:wrap; row-gap:4px; }
|
||||
.questBubble-question .questBubbleBody{ background:rgba(224,185,61,.14); }
|
||||
.questQuestionHeaderField{
|
||||
display:inline-flex; align-items:center; gap:4px; font-size:11px; font-weight:700; color:#fff; white-space:nowrap;
|
||||
display:inline-flex; align-items:center; gap:6px; font-size:11px; font-weight:700; color:#fff; white-space:nowrap;
|
||||
}
|
||||
.questQuestionHeaderFieldLabel{ font-weight:700; text-transform:uppercase; font-size:10px; letter-spacing:.02em; opacity:.85; }
|
||||
.questQuestionHeaderField input{
|
||||
width:44px; background:rgba(0,0,0,.25); border:1px solid rgba(255,255,255,.3); border-radius:4px;
|
||||
color:#fff; font:inherit; font-size:11px; padding:2px 4px;
|
||||
@@ -1196,7 +1329,7 @@ code{ background:var(--panel2); border:1px solid var(--border); border-radius:4p
|
||||
.builderTabBtn.active{ color:var(--accent); border-bottom-color:var(--accent); font-weight:600; }
|
||||
|
||||
/* overflow-y:auto : contrairement à "screen" (voir .canvasFrame plus haut,
|
||||
qui défile LUI-MÊME), "collision-rules"/"quests"/"events" n'ont pas de
|
||||
qui défile LUI-MÊME), "triggers"/"events" n'ont pas de
|
||||
sous-conteneur dédié au défilement — sans ça, une liste plus haute que
|
||||
l'espace disponible restait simplement coupée par .builderCanvasArea
|
||||
(overflow:hidden), au lieu de défiler. */
|
||||
|
||||
Reference in New Issue
Block a user