Quêtes/collision : personnages nommés, dialogues qui parlent, boîte de dialogue en jeu
- "ℹ️ Informations" (propriétés d'un personnage) : nom éditable, réutilisé comme "qui parle" dans l'éditeur de dialogue de quête (menu déroulant, plus "Joueur" toujours disponible) — remplace l'ancien choix binaire joueur/pnj. db.sanitize_quest_dialogues accepte maintenant un nom libre. - Nouveau menu "🖥️ Interface" (palette d'objets) avec le premier widget : "💬 Boîte de dialogue" (kind="dialogue_box", screens/rendering/ dialogue_box_style.py) — position/taille comme tout objet de scène, panneau "🎨 Style" dédié (police, taille, épaisseur, couleur du texte, couleur header/body/footer). Rendu en <div> à 3 zones, jamais soumis à la collision ni à l'éditeur de collision (exclu partout : obstacles, liste des règles, payload). Rendu côté jeu dans .sceneUI, une couche FIXE au viewport (jamais .sceneWorld, qui défile avec la caméra). - static/js/play/dialogue-box-controller.js : fait le lien moteur entre l'action "quete" de l'éditeur de collision et ce widget — affiche la réplique en cours du dialogue correspondant au STATUT ACTUEL de la quête (gameData.quests, désormais exposé game-wide par full_game_payload.py), avance au clic sur "Suivant" (header = qui parle, body = texte, footer = bouton), se masque à la dernière réplique. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
390ee831ca
commit
2347a70c45
@@ -15,6 +15,9 @@
|
||||
#canvas (son ancêtre positionné le plus proche), en double du
|
||||
décalage déjà appliqué par .canvasElement. */
|
||||
.canvasElementInner > img{ position:static !important; left:auto !important; top:auto !important; width:100% !important; height:100% !important; z-index:auto !important; }
|
||||
/* Même correctif que ci-dessus, pour le widget "💬 Boîte de dialogue"
|
||||
(screens/scenes/render_scene_object.py, un <div>, pas un <img>). */
|
||||
.canvasElementInner > .dialogueBoxWidget{ position:static !important; left:auto !important; top:auto !important; width:100% !important; height:100% !important; z-index:auto !important; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
@@ -87,6 +90,20 @@
|
||||
</div>
|
||||
</details>
|
||||
{% endif %}
|
||||
<!-- "🖥️ Interface" — l'UI du jeu (voir screens/rendering/
|
||||
dialogue_box_style.py) : pour l'instant un seul widget, "💬 Boîte
|
||||
de dialogue", gérée AUTOMATIQUEMENT par le moteur (affiche la
|
||||
réplique en cours de la quête déclenchée par une règle de
|
||||
collision "quete", voir static/js/play/dialogue-box-controller.js) —
|
||||
l'auteur ne fait que la poser où il veut et la styliser (panneau
|
||||
de propriétés de droite, une fois sélectionnée). -->
|
||||
<details class="propGroup">
|
||||
<summary>🖥️ Interface</summary>
|
||||
<div class="propGroupBody">
|
||||
<button type="button" class="button is-small is-fullwidth" onclick="addSceneObject('dialogue_box')">💬 Boîte de dialogue</button>
|
||||
<p class="help">Affiche automatiquement le dialogue de la quête en cours (voir l'onglet "🗺️ Quêtes") — position et style réglables une fois posée.</p>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -107,7 +124,7 @@
|
||||
onmousedown="onSceneObjectMouseDown(event, {{ o.id }})">
|
||||
<div class="canvasElementInner">{{ o.rendered_html|safe }}</div>
|
||||
<div class="resizeHandle" onmousedown="onSceneObjectResizeMouseDown(event, {{ o.id }})"></div>
|
||||
{% if o.id == selected_id and o.kind != 'fond' %}
|
||||
{% if o.id == selected_id and o.kind not in ('fond', 'dialogue_box') %}
|
||||
<!-- Boîte de collision (voir screens/rendering/collision_settings.py) :
|
||||
aperçu visuel + réglable directement au glisser — seulement pour
|
||||
l'objet SÉLECTIONNÉ (celui dont le panneau "🧱 Collision" est ouvert),
|
||||
@@ -245,12 +262,28 @@
|
||||
<div class="hint" style="padding:20px 0;">Sélectionne un objet (sur la scène ou dans la liste) pour voir et modifier ses propriétés ici.</div>
|
||||
{% else %}
|
||||
<div class="fieldRow" style="align-items:center; justify-content:space-between;">
|
||||
<h2 class="subtitle is-6" style="margin:0;">{{ '🏃' if obj.kind == 'personnage' else '🖼️' }} {{ obj.name or ('Personnage' if obj.kind == 'personnage' else 'Décor') }}</h2>
|
||||
<h2 class="subtitle is-6" style="margin:0;">{{ '🏃' if obj.kind == 'personnage' else ('💬' if obj.kind == 'dialogue_box' else '🖼️') }} {{ obj.name or ('Personnage' if obj.kind == 'personnage' else ('Boîte de dialogue' if obj.kind == 'dialogue_box' else 'Décor')) }}</h2>
|
||||
<form method="post" action="{{ url_for('scene_object_delete', slug=game.slug, object_id=obj.id) }}" onsubmit="return confirm('Supprimer cet objet ?');">
|
||||
<button type="submit" class="button is-small is-danger">🗑️</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% if obj.kind == 'personnage' %}
|
||||
<!-- "ℹ️ Informations" : le nom donné au personnage (voir
|
||||
screens/scenes/set_scene_object_name.py) — c'est CE nom qui est
|
||||
ensuite proposé comme "qui parle" dans l'éditeur de dialogue de
|
||||
quête (voir "🗺️ Quêtes", static/js/quests/quest-editor.js). -->
|
||||
<details class="propGroup" open>
|
||||
<summary>ℹ️ Informations</summary>
|
||||
<div class="propGroupBody">
|
||||
<div class="field">
|
||||
<label class="label is-small">Nom du personnage</label>
|
||||
<div class="control"><input class="input is-small" type="text" id="scene-obj-name" value="{{ obj.name or '' }}" placeholder="ex. Le Sorcier" onchange="saveSceneObjectName({{ obj.id }}, this.value)"></div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
{% endif %}
|
||||
|
||||
<details class="propGroup" open>
|
||||
<summary>Position & taille (pixels)</summary>
|
||||
<div class="propGroupBody">
|
||||
@@ -279,7 +312,65 @@
|
||||
</div>
|
||||
</details>
|
||||
|
||||
{% if obj.kind != 'fond' %}
|
||||
{% if obj.kind == 'dialogue_box' %}
|
||||
<!-- "🎨 Style" (voir screens/rendering/dialogue_box_style.py) : le
|
||||
widget "💬 Boîte de dialogue" n'a ni collision ni animation,
|
||||
juste une apparence — police, couleur du texte, couleur de
|
||||
chaque zone (header/body/footer). -->
|
||||
<details class="propGroup" open>
|
||||
<summary>🎨 Style</summary>
|
||||
<div class="propGroupBody" data-element-id="{{ obj.id }}">
|
||||
<div class="field">
|
||||
<label class="label is-small">Police</label>
|
||||
<div class="control">
|
||||
<input class="input is-small" type="text" id="dbox-font-family" value="{{ dialogue_box_style.font_family }}" placeholder="ex. Georgia, serif" onchange="saveDialogueBoxStyle({{ obj.id }})">
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns is-multiline posGrid">
|
||||
<div class="column is-half">
|
||||
<div class="field"><label class="label is-small">Taille (px)</label>
|
||||
<div class="control"><input class="input is-small" type="number" id="dbox-font-size" min="8" max="48" value="{{ dialogue_box_style.font_size }}" onchange="saveDialogueBoxStyle({{ obj.id }})"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-half">
|
||||
<div class="field"><label class="label is-small">Épaisseur</label>
|
||||
<div class="control">
|
||||
<select class="input is-small" id="dbox-font-weight" onchange="saveDialogueBoxStyle({{ obj.id }})">
|
||||
{% for w in dialogue_box_font_weight_choices %}
|
||||
<option value="{{ w }}" {{ 'selected' if dialogue_box_style.font_weight == w else '' }}>{{ 'Gras' if w == 'bold' else 'Normal' }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns is-multiline posGrid">
|
||||
<div class="column is-half">
|
||||
<div class="field"><label class="label is-small">Texte</label>
|
||||
<div class="control"><input class="input is-small" type="color" id="dbox-text-color" value="{{ dialogue_box_style.text_color }}" onchange="saveDialogueBoxStyle({{ obj.id }})"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-half">
|
||||
<div class="field"><label class="label is-small">Header</label>
|
||||
<div class="control"><input class="input is-small" type="color" id="dbox-header-bg" value="{{ dialogue_box_style.header_bg }}" onchange="saveDialogueBoxStyle({{ obj.id }})"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-half">
|
||||
<div class="field"><label class="label is-small">Corps</label>
|
||||
<div class="control"><input class="input is-small" type="color" id="dbox-body-bg" value="{{ dialogue_box_style.body_bg }}" onchange="saveDialogueBoxStyle({{ obj.id }})"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-half">
|
||||
<div class="field"><label class="label is-small">Pied</label>
|
||||
<div class="control"><input class="input is-small" type="color" id="dbox-footer-bg" value="{{ dialogue_box_style.footer_bg }}" onchange="saveDialogueBoxStyle({{ obj.id }})"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
{% endif %}
|
||||
|
||||
{% if obj.kind not in ('fond', 'dialogue_box') %}
|
||||
<!-- Boîte de collision (voir screens/rendering/collision_settings.py,
|
||||
static/js/play/conditions.js::elementsOverlap) : posée AUTOMATIQUEMENT
|
||||
sur tout objet (= sa boîte visuelle par défaut, tant que rien
|
||||
@@ -464,6 +555,9 @@
|
||||
// avant collision-rules-editor.js : l'action "quete" de l'assistant
|
||||
// "+ Action" ouvre directement cet éditeur (renderQuestPickerStep).
|
||||
var QUESTS_JSON = {{ quests_json|safe }};
|
||||
// "qui parle" dans l'éditeur de dialogue (voir "ℹ️ Informations" +
|
||||
// static/js/quests/quest-editor.js::questSpeakerOptions).
|
||||
var PERSONNAGE_NAMES_JSON = {{ personnage_names_json|safe }};
|
||||
</script>
|
||||
<script src="{{ url_for('static', filename='js/screen_edit/tree-panels.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/screen_edit/panel-init.js') }}"></script>
|
||||
|
||||
Reference in New Issue
Block a user