Scenario conditions in dialogs: option if= hides choices, when moved here from stat checks; command schemas
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
dde5262aa0
commit
68ed11cadc
14 files changed
+542
-3
No files matched your search
@@ -0,0 +1,29 @@
|
||||
dialog/schema/builtin/text = Line
|
||||
dialog/schema/builtin/text_desc = A dialog line; the locale key is optional
|
||||
dialog/schema/field/text = Text
|
||||
dialog/schema/field/locale_key = Locale key
|
||||
dialog/schema/builtin/ptext = Narration
|
||||
dialog/schema/builtin/ptext_desc = The narrator text, fills ${var}
|
||||
dialog/schema/builtin/flag = Story flag
|
||||
dialog/schema/builtin/flag_desc = A saved mark that conditions react to
|
||||
dialog/schema/field/flag = Flag
|
||||
dialog/schema/field/value = Value
|
||||
dialog/schema/builtin/switch_scene = Switch scene
|
||||
dialog/schema/builtin/switch_scene_desc = A novel scene or a map — a map is a scene too
|
||||
dialog/schema/field/scene = Scene
|
||||
dialog/schema/builtin/goto = Go to a label
|
||||
dialog/schema/builtin/goto_desc = An unconditional jump
|
||||
dialog/schema/field/label = Label
|
||||
dialog/schema/builtin/end = End the dialog
|
||||
dialog/schema/builtin/end_desc = Closes the dialog box
|
||||
dialog/schema/checks/when = When — jump
|
||||
dialog/schema/checks/when_desc = A conditional jump on the shared condition language: flags, quests, stats, gear
|
||||
dialog/schema/checks/arrow_true = When true, go to
|
||||
dialog/schema/field/condition = Condition
|
||||
dialog/schema/field/else = Else label
|
||||
dialog/schema/builtin/select = Choice
|
||||
dialog/schema/builtin/select_desc = The question before the answers; option lines follow
|
||||
dialog/schema/builtin/option = Answer
|
||||
dialog/schema/builtin/option_desc = An answer and the label it leads to; with a condition it is shown only while it holds
|
||||
dialog/schema/field/option_if = Show if
|
||||
dialog/schema/builtin/option_if_desc = For example archetype(rogue) or "stat(cha) >= 5"; empty — always
|
||||
@@ -0,0 +1,29 @@
|
||||
dialog/schema/builtin/text = Réplica
|
||||
dialog/schema/builtin/text_desc = Una línea de diálogo; la clave de traducción es opcional
|
||||
dialog/schema/field/text = Texto
|
||||
dialog/schema/field/locale_key = Clave de traducción
|
||||
dialog/schema/builtin/ptext = Narración
|
||||
dialog/schema/builtin/ptext_desc = El texto del narrador, rellena ${var}
|
||||
dialog/schema/builtin/flag = Marca de historia
|
||||
dialog/schema/builtin/flag_desc = Una marca guardada a la que reaccionan las condiciones
|
||||
dialog/schema/field/flag = Marca
|
||||
dialog/schema/field/value = Valor
|
||||
dialog/schema/builtin/switch_scene = Cambiar de escena
|
||||
dialog/schema/builtin/switch_scene_desc = Una escena de novela o un mapa: un mapa también es una escena
|
||||
dialog/schema/field/scene = Escena
|
||||
dialog/schema/builtin/goto = Ir a una etiqueta
|
||||
dialog/schema/builtin/goto_desc = Un salto incondicional
|
||||
dialog/schema/field/label = Etiqueta
|
||||
dialog/schema/builtin/end = Fin del diálogo
|
||||
dialog/schema/builtin/end_desc = Cierra el cuadro de diálogo
|
||||
dialog/schema/checks/when = Si — saltar
|
||||
dialog/schema/checks/when_desc = Un salto condicional según el lenguaje común de condiciones: marcas, misiones, estadísticas, equipo
|
||||
dialog/schema/checks/arrow_true = Si es cierto, ir a
|
||||
dialog/schema/field/condition = Condición
|
||||
dialog/schema/field/else = Etiqueta si no
|
||||
dialog/schema/builtin/select = Elección
|
||||
dialog/schema/builtin/select_desc = La pregunta antes de las respuestas; siguen las líneas option
|
||||
dialog/schema/builtin/option = Respuesta
|
||||
dialog/schema/builtin/option_desc = Una respuesta y la etiqueta a la que lleva; con condición solo se muestra mientras se cumple
|
||||
dialog/schema/field/option_if = Mostrar si
|
||||
dialog/schema/builtin/option_if_desc = Por ejemplo archetype(rogue) o "stat(cha) >= 5"; vacío: siempre
|
||||
@@ -0,0 +1,29 @@
|
||||
dialog/schema/builtin/text = セリフ
|
||||
dialog/schema/builtin/text_desc = 会話の一行。翻訳キーは任意
|
||||
dialog/schema/field/text = テキスト
|
||||
dialog/schema/field/locale_key = 翻訳キー
|
||||
dialog/schema/builtin/ptext = 地の文
|
||||
dialog/schema/builtin/ptext_desc = 語りの文。${var} を埋め込む
|
||||
dialog/schema/builtin/flag = ストーリーフラグ
|
||||
dialog/schema/builtin/flag_desc = 保存される印。条件がそれに反応する
|
||||
dialog/schema/field/flag = フラグ
|
||||
dialog/schema/field/value = 値
|
||||
dialog/schema/builtin/switch_scene = シーン切り替え
|
||||
dialog/schema/builtin/switch_scene_desc = ノベルのシーンかマップ——マップもシーン
|
||||
dialog/schema/field/scene = シーン
|
||||
dialog/schema/builtin/goto = ラベルへ移動
|
||||
dialog/schema/builtin/goto_desc = 無条件のジャンプ
|
||||
dialog/schema/field/label = ラベル
|
||||
dialog/schema/builtin/end = 会話の終わり
|
||||
dialog/schema/builtin/end_desc = 会話ウィンドウを閉じる
|
||||
dialog/schema/checks/when = もし——ジャンプ
|
||||
dialog/schema/checks/when_desc = 共通の条件言語による条件ジャンプ:フラグ、クエスト、ステータス、装備
|
||||
dialog/schema/checks/arrow_true = 真のときのラベル
|
||||
dialog/schema/field/condition = 条件
|
||||
dialog/schema/field/else = それ以外のラベル
|
||||
dialog/schema/builtin/select = 選択肢
|
||||
dialog/schema/builtin/select_desc = 選択肢の前の問い。続けて option 行
|
||||
dialog/schema/builtin/option = 選択肢
|
||||
dialog/schema/builtin/option_desc = 答えと行き先のラベル。条件付きなら成り立つ間だけ表示
|
||||
dialog/schema/field/option_if = 表示条件
|
||||
dialog/schema/builtin/option_if_desc = 例:archetype(rogue) や "stat(cha) >= 5"。空なら常に
|
||||
@@ -0,0 +1,29 @@
|
||||
dialog/schema/builtin/text = 대사
|
||||
dialog/schema/builtin/text_desc = 대화 한 줄. 번역 키는 선택
|
||||
dialog/schema/field/text = 텍스트
|
||||
dialog/schema/field/locale_key = 번역 키
|
||||
dialog/schema/builtin/ptext = 서술
|
||||
dialog/schema/builtin/ptext_desc = 서술자 텍스트. ${var}를 채움
|
||||
dialog/schema/builtin/flag = 스토리 플래그
|
||||
dialog/schema/builtin/flag_desc = 저장되는 표시. 조건이 반응합니다
|
||||
dialog/schema/field/flag = 플래그
|
||||
dialog/schema/field/value = 값
|
||||
dialog/schema/builtin/switch_scene = 장면 전환
|
||||
dialog/schema/builtin/switch_scene_desc = 노벨 장면이나 맵 — 맵도 장면입니다
|
||||
dialog/schema/field/scene = 장면
|
||||
dialog/schema/builtin/goto = 라벨로 이동
|
||||
dialog/schema/builtin/goto_desc = 무조건 이동
|
||||
dialog/schema/field/label = 라벨
|
||||
dialog/schema/builtin/end = 대화 끝
|
||||
dialog/schema/builtin/end_desc = 대화창을 닫음
|
||||
dialog/schema/checks/when = 조건 — 이동
|
||||
dialog/schema/checks/when_desc = 공통 조건 언어로 하는 조건 이동: 플래그, 퀘스트, 능력치, 장비
|
||||
dialog/schema/checks/arrow_true = 참이면 이동
|
||||
dialog/schema/field/condition = 조건
|
||||
dialog/schema/field/else = 아니면 라벨
|
||||
dialog/schema/builtin/select = 선택
|
||||
dialog/schema/builtin/select_desc = 답 앞의 질문. 뒤에 option 줄이 옵니다
|
||||
dialog/schema/builtin/option = 선택지
|
||||
dialog/schema/builtin/option_desc = 답과 이어지는 라벨. 조건이 있으면 참일 때만 보입니다
|
||||
dialog/schema/field/option_if = 표시 조건
|
||||
dialog/schema/builtin/option_if_desc = 예: archetype(rogue) 또는 "stat(cha) >= 5". 비우면 항상
|
||||
@@ -0,0 +1,29 @@
|
||||
dialog/schema/builtin/text = Реплика
|
||||
dialog/schema/builtin/text_desc = Строка диалога; ключ перевода — по желанию
|
||||
dialog/schema/field/text = Текст
|
||||
dialog/schema/field/locale_key = Ключ перевода
|
||||
dialog/schema/builtin/ptext = Повествование
|
||||
dialog/schema/builtin/ptext_desc = Текст рассказчика, подставляет ${var}
|
||||
dialog/schema/builtin/flag = Флаг сюжета
|
||||
dialog/schema/builtin/flag_desc = Сохраняемая отметка, по ней срабатывают условия
|
||||
dialog/schema/field/flag = Флаг
|
||||
dialog/schema/field/value = Значение
|
||||
dialog/schema/builtin/switch_scene = Сменить сцену
|
||||
dialog/schema/builtin/switch_scene_desc = Сцена новеллы или карта — карта тоже сцена
|
||||
dialog/schema/field/scene = Сцена
|
||||
dialog/schema/builtin/goto = Перейти к метке
|
||||
dialog/schema/builtin/goto_desc = Безусловный переход
|
||||
dialog/schema/field/label = Метка
|
||||
dialog/schema/builtin/end = Конец диалога
|
||||
dialog/schema/builtin/end_desc = Закрывает окно диалога
|
||||
dialog/schema/checks/when = Если — переход
|
||||
dialog/schema/checks/when_desc = Условный переход по общему языку условий: флаги, квесты, статы, снаряжение
|
||||
dialog/schema/checks/arrow_true = Если верно — метка
|
||||
dialog/schema/field/condition = Условие
|
||||
dialog/schema/field/else = Иначе — метка
|
||||
dialog/schema/builtin/select = Выбор
|
||||
dialog/schema/builtin/select_desc = Вопрос перед вариантами ответа; дальше идут строки option
|
||||
dialog/schema/builtin/option = Вариант ответа
|
||||
dialog/schema/builtin/option_desc = Вариант выбора и метка, куда он ведёт; с условием — показывается, только пока оно верно
|
||||
dialog/schema/field/option_if = Показывать, если
|
||||
dialog/schema/builtin/option_if_desc = Например archetype(rogue) или "stat(cha) >= 5"; пусто — всегда
|
||||
@@ -0,0 +1,29 @@
|
||||
dialog/schema/builtin/text = Lời thoại
|
||||
dialog/schema/builtin/text_desc = Một dòng hội thoại; khóa dịch tùy chọn
|
||||
dialog/schema/field/text = Văn bản
|
||||
dialog/schema/field/locale_key = Khóa dịch
|
||||
dialog/schema/builtin/ptext = Lời dẫn
|
||||
dialog/schema/builtin/ptext_desc = Lời người kể, điền ${var}
|
||||
dialog/schema/builtin/flag = Cờ cốt truyện
|
||||
dialog/schema/builtin/flag_desc = Một dấu được lưu, điều kiện sẽ phản ứng theo
|
||||
dialog/schema/field/flag = Cờ
|
||||
dialog/schema/field/value = Giá trị
|
||||
dialog/schema/builtin/switch_scene = Chuyển cảnh
|
||||
dialog/schema/builtin/switch_scene_desc = Cảnh tiểu thuyết hoặc bản đồ — bản đồ cũng là cảnh
|
||||
dialog/schema/field/scene = Cảnh
|
||||
dialog/schema/builtin/goto = Đến nhãn
|
||||
dialog/schema/builtin/goto_desc = Bước nhảy vô điều kiện
|
||||
dialog/schema/field/label = Nhãn
|
||||
dialog/schema/builtin/end = Kết thúc hội thoại
|
||||
dialog/schema/builtin/end_desc = Đóng hộp hội thoại
|
||||
dialog/schema/checks/when = Nếu — nhảy
|
||||
dialog/schema/checks/when_desc = Bước nhảy có điều kiện theo ngôn ngữ điều kiện chung: cờ, nhiệm vụ, chỉ số, trang bị
|
||||
dialog/schema/checks/arrow_true = Nếu đúng, đến
|
||||
dialog/schema/field/condition = Điều kiện
|
||||
dialog/schema/field/else = Nhãn nếu không
|
||||
dialog/schema/builtin/select = Lựa chọn
|
||||
dialog/schema/builtin/select_desc = Câu hỏi trước các đáp án; sau đó là các dòng option
|
||||
dialog/schema/builtin/option = Đáp án
|
||||
dialog/schema/builtin/option_desc = Một đáp án và nhãn nó dẫn tới; có điều kiện thì chỉ hiện khi điều kiện đúng
|
||||
dialog/schema/field/option_if = Hiện nếu
|
||||
dialog/schema/builtin/option_if_desc = Ví dụ archetype(rogue) hoặc "stat(cha) >= 5"; để trống — luôn hiện
|
||||
@@ -0,0 +1,29 @@
|
||||
dialog/schema/builtin/text = 台词
|
||||
dialog/schema/builtin/text_desc = 一句对白;翻译键可选
|
||||
dialog/schema/field/text = 文本
|
||||
dialog/schema/field/locale_key = 翻译键
|
||||
dialog/schema/builtin/ptext = 旁白
|
||||
dialog/schema/builtin/ptext_desc = 旁白文本,会代入 ${var}
|
||||
dialog/schema/builtin/flag = 剧情标记
|
||||
dialog/schema/builtin/flag_desc = 会被保存的标记,条件据此触发
|
||||
dialog/schema/field/flag = 标记
|
||||
dialog/schema/field/value = 数值
|
||||
dialog/schema/builtin/switch_scene = 切换场景
|
||||
dialog/schema/builtin/switch_scene_desc = 小说场景或地图——地图也是场景
|
||||
dialog/schema/field/scene = 场景
|
||||
dialog/schema/builtin/goto = 跳到标签
|
||||
dialog/schema/builtin/goto_desc = 无条件跳转
|
||||
dialog/schema/field/label = 标签
|
||||
dialog/schema/builtin/end = 结束对话
|
||||
dialog/schema/builtin/end_desc = 关闭对话框
|
||||
dialog/schema/checks/when = 如果——跳转
|
||||
dialog/schema/checks/when_desc = 依据通用条件语言的条件跳转:标记、任务、属性、装备
|
||||
dialog/schema/checks/arrow_true = 为真时跳转
|
||||
dialog/schema/field/condition = 条件
|
||||
dialog/schema/field/else = 否则跳转
|
||||
dialog/schema/builtin/select = 选择
|
||||
dialog/schema/builtin/select_desc = 回答前的问题;后面跟着 option 行
|
||||
dialog/schema/builtin/option = 回答选项
|
||||
dialog/schema/builtin/option_desc = 一个回答及其跳转标签;带条件时仅在条件成立时显示
|
||||
dialog/schema/field/option_if = 显示条件
|
||||
dialog/schema/builtin/option_if_desc = 例如 archetype(rogue) 或 "stat(cha) >= 5";留空——总是显示
|
||||
@@ -0,0 +1,164 @@
|
||||
{
|
||||
"Commands": [
|
||||
{
|
||||
"Id": "text",
|
||||
"Name": "dialog/schema/builtin/text",
|
||||
"Description": "dialog/schema/builtin/text_desc",
|
||||
"Category": "dialog",
|
||||
"Positional": [
|
||||
{
|
||||
"Key": "text",
|
||||
"Type": "text",
|
||||
"Required": true,
|
||||
"Name": "dialog/schema/field/text"
|
||||
}
|
||||
],
|
||||
"Params": [
|
||||
{
|
||||
"Key": "key",
|
||||
"Type": "text",
|
||||
"Name": "dialog/schema/field/locale_key"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Id": "ptext",
|
||||
"Name": "dialog/schema/builtin/ptext",
|
||||
"Description": "dialog/schema/builtin/ptext_desc",
|
||||
"Category": "dialog",
|
||||
"Positional": [
|
||||
{
|
||||
"Key": "text",
|
||||
"Type": "text",
|
||||
"Required": true,
|
||||
"Name": "dialog/schema/field/text"
|
||||
}
|
||||
],
|
||||
"Params": [
|
||||
{
|
||||
"Key": "key",
|
||||
"Type": "text",
|
||||
"Name": "dialog/schema/field/locale_key"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Id": "flag",
|
||||
"Name": "dialog/schema/builtin/flag",
|
||||
"Description": "dialog/schema/builtin/flag_desc",
|
||||
"Category": "flow",
|
||||
"Positional": [
|
||||
{
|
||||
"Key": "name",
|
||||
"Type": "flag",
|
||||
"Required": true,
|
||||
"Name": "dialog/schema/field/flag"
|
||||
},
|
||||
{
|
||||
"Key": "value",
|
||||
"Type": "text",
|
||||
"Required": true,
|
||||
"Default": "1",
|
||||
"Name": "dialog/schema/field/value"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Id": "switch_scene",
|
||||
"Name": "dialog/schema/builtin/switch_scene",
|
||||
"Description": "dialog/schema/builtin/switch_scene_desc",
|
||||
"Category": "flow",
|
||||
"Positional": [
|
||||
{
|
||||
"Key": "scene",
|
||||
"Type": "scene",
|
||||
"Required": true,
|
||||
"Name": "dialog/schema/field/scene"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Id": "goto",
|
||||
"Name": "dialog/schema/builtin/goto",
|
||||
"Description": "dialog/schema/builtin/goto_desc",
|
||||
"Category": "flow",
|
||||
"Arrow": "dialog/schema/field/label"
|
||||
},
|
||||
{
|
||||
"Id": "end",
|
||||
"Name": "dialog/schema/builtin/end",
|
||||
"Description": "dialog/schema/builtin/end_desc",
|
||||
"Category": "flow"
|
||||
},
|
||||
{
|
||||
"Id": "when",
|
||||
"Name": "dialog/schema/checks/when",
|
||||
"Description": "dialog/schema/checks/when_desc",
|
||||
"Category": "flow",
|
||||
"Arrow": "dialog/schema/checks/arrow_true",
|
||||
"Positional": [
|
||||
{
|
||||
"Key": "condition",
|
||||
"Type": "condition",
|
||||
"Required": true,
|
||||
"Name": "dialog/schema/field/condition"
|
||||
}
|
||||
],
|
||||
"Params": [
|
||||
{
|
||||
"Key": "else",
|
||||
"Type": "label",
|
||||
"Name": "dialog/schema/field/else"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Id": "select",
|
||||
"Name": "dialog/schema/builtin/select",
|
||||
"Description": "dialog/schema/builtin/select_desc",
|
||||
"Category": "dialog",
|
||||
"Positional": [
|
||||
{
|
||||
"Key": "text",
|
||||
"Type": "text",
|
||||
"Name": "dialog/schema/field/text"
|
||||
}
|
||||
],
|
||||
"Params": [
|
||||
{
|
||||
"Key": "key",
|
||||
"Type": "text",
|
||||
"Name": "dialog/schema/field/locale_key"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Id": "option",
|
||||
"Name": "dialog/schema/builtin/option",
|
||||
"Description": "dialog/schema/builtin/option_desc",
|
||||
"Category": "dialog",
|
||||
"Arrow": "dialog/schema/field/label",
|
||||
"Positional": [
|
||||
{
|
||||
"Key": "text",
|
||||
"Type": "text",
|
||||
"Required": true,
|
||||
"Name": "dialog/schema/field/text"
|
||||
}
|
||||
],
|
||||
"Params": [
|
||||
{
|
||||
"Key": "key",
|
||||
"Type": "text",
|
||||
"Name": "dialog/schema/field/locale_key"
|
||||
},
|
||||
{
|
||||
"Key": "if",
|
||||
"Type": "condition",
|
||||
"Name": "dialog/schema/field/option_if",
|
||||
"Description": "dialog/schema/builtin/option_if_desc"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
namespace Cthangover.Mods.Dialog.Scenarios
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using Cthangover.Core.Localization;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Mods.Dialog;
|
||||
|
||||
/// <summary>
|
||||
/// A conditional jump in the middle of a dialog:
|
||||
/// <code>when "stat(cha) >= 5 && door == 'open'" -> :persuaded [else=refused]</code>
|
||||
/// evaluates the shared condition language (flags, quests, stats, equipment, GDScript
|
||||
/// conditions — everything mods registered) at the moment the line runs, and jumps to
|
||||
/// the arrow label when it holds, to <c>else</c> when it does not (or goes on).
|
||||
/// <para/>
|
||||
/// It is the RPG Maker "Conditional Branch" without a new syntax: the condition is the
|
||||
/// same text a scenario header's <c>condition:</c> takes. Several words without quotes
|
||||
/// are joined back with spaces, so short conditions need no quotes.
|
||||
/// </summary>
|
||||
public class WhenCommandStrategy : IScenarioCommandStrategy, IScenarioCommandSpec
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string Command => "when";
|
||||
|
||||
/// <inheritdoc />
|
||||
public int MinPositional => 1;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<string> AllowedNamed => new[] { "else" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public string JumpTargetNamedKey => "else";
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Execute(DialogQueue dlg, List<string> positional, Dictionary<string, string> named, string arrowTarget, ILocalizationProvider locale)
|
||||
{
|
||||
var condition = string.Join(" ", positional);
|
||||
named.TryGetValue("else", out var otherwise);
|
||||
dlg.IfGoTo(() => ScenarioCondition.Evaluate(condition), Label(arrowTarget), Label(otherwise));
|
||||
}
|
||||
|
||||
private static string Label(string target) => string.IsNullOrWhiteSpace(target) ? null : target.Trim().TrimStart(':');
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,10 @@ namespace Cthangover.Mods.Dialog.Scenarios
|
||||
|
||||
if (pendingSelect.Variants == null)
|
||||
pendingSelect.Variants = new List<SelectVariant>();
|
||||
pendingSelect.Variants.Add(SelectVariant.New(optText, goTo));
|
||||
var variant = SelectVariant.New(optText, goTo);
|
||||
if (named.TryGetValue("if", out var condition))
|
||||
variant.Condition = condition;
|
||||
pendingSelect.Variants.Add(variant);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cthangover.Core.Utils;
|
||||
using Cthangover.Mods.Dialog.Action;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
@@ -35,16 +37,29 @@ namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
public override WaitType WaitType { get; set; } = WaitType.WaitSelect;
|
||||
|
||||
/// <summary>Substitutes variables in the variants and context text, then shows the answer box; the runtime stays paused until a variant is picked.</summary>
|
||||
/// <summary>
|
||||
/// Offers the options whose conditions hold now. When none does, the choice is
|
||||
/// skipped and the dialog goes on with the next line, so a choice of only gated
|
||||
/// options never leaves the player stuck.
|
||||
/// </summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
var dialogBox = runtime.DialogBox;
|
||||
if (dialogBox == null)
|
||||
return;
|
||||
|
||||
foreach (var variant in Variants)
|
||||
var shown = Variants.Where(v => v.IsShown()).ToList();
|
||||
WaitType = shown.Count == 0 ? WaitType.NoWait : WaitType.WaitSelect;
|
||||
if (shown.Count == 0)
|
||||
{
|
||||
GameLogger.Log("DIALOG", "select: no option is shown (all conditions false), going on", LogLevel.Debug);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var variant in shown)
|
||||
variant.Text = runtime.ProcessText(variant.Text);
|
||||
|
||||
dialogBox.SetVariants(Variants);
|
||||
dialogBox.SetVariants(shown);
|
||||
dialogBox.SetText(runtime.ProcessText(Text));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,16 @@ namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
/// <summary>Target action ID to jump to via <see cref="DialogRuntime.TryGoTo"/> when this variant is selected.</summary>
|
||||
public string GoTo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Condition of the shared condition language (<c>option "…" if=… -> :label</c>); the
|
||||
/// option is shown only while it holds. Null = always shown. Evaluated each time the
|
||||
/// choice appears, so a stat, a flag or an item gained a moment ago counts.
|
||||
/// </summary>
|
||||
public string Condition { get; set; }
|
||||
|
||||
/// <summary>Whether the option is offered now.</summary>
|
||||
public bool IsShown() => string.IsNullOrWhiteSpace(Condition) || ScenarioCondition.Evaluate(Condition);
|
||||
|
||||
/// <summary>Generates a new unique action ID for use as a GoTo target (e.g. with <see cref="DialogQueue.Point"/>).</summary>
|
||||
public static string Point => Guid.NewGuid().ToString();
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
namespace Cthangover.Mods.Dialog.Tests
|
||||
{
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Cthangover.Core.Mods.Testing;
|
||||
using Cthangover.Mods.Dialog.Action.Impls;
|
||||
using Cthangover.Mods.Dialog.Scenarios;
|
||||
|
||||
/// <summary>
|
||||
/// <c>option … if=…</c>: an option is offered only while its condition holds; a choice whose
|
||||
/// options are all hidden is skipped, so the dialog never waits for an answer nobody can give.
|
||||
/// </summary>
|
||||
public class OptionConditionTests
|
||||
{
|
||||
[ModTest("options/parser_keeps_the_condition")]
|
||||
static void ParserKeepsTheCondition(ModTestContext ctx)
|
||||
{
|
||||
var dlg = ScenarioParser.Parse("select \"?\"\noption \"A\" -> :a\noption \"B\" \"if=door == 'open' && !false\" -> :b\n:a\nend\n:b\nend\n");
|
||||
var select = dlg.Queue.OfType<ActionSelect>().Single();
|
||||
ModAssert.Null(select.Variants[0].Condition, "a plain option has no condition");
|
||||
ModAssert.Equal("door == 'open' && !false", select.Variants[1].Condition, "the quoted pair keeps spaces");
|
||||
ModAssert.Equal("b", select.Variants[1].GoTo, "the jump target stays");
|
||||
}
|
||||
|
||||
[ModTest("options/hidden_options_are_not_offered", TimeoutSeconds = 10)]
|
||||
static async Task HiddenOptionsAreNotOffered(ModTestContext ctx)
|
||||
{
|
||||
var stage = await DialogStage.Create();
|
||||
try
|
||||
{
|
||||
var dlg = ScenarioParser.Parse("select \"?\"\noption \"A\" if=false -> :a\noption \"B\" if=true -> :b\noption \"C\" -> :c\n:a\nend\n:b\nend\n:c\nend\n");
|
||||
ModAssert.True(stage.Box.SetDialogQueueAndRun(dlg, null, 0, null), "dialog starts");
|
||||
ModAssert.True(stage.Box.IsWaitingAnswer, "waits for an answer");
|
||||
ModAssert.Equal(2, stage.Box.AnswerVariantCount, "the false option is hidden");
|
||||
}
|
||||
finally
|
||||
{
|
||||
stage.Free();
|
||||
}
|
||||
}
|
||||
|
||||
[ModTest("options/all_hidden_skips_the_choice", TimeoutSeconds = 10)]
|
||||
static async Task AllHiddenSkipsTheChoice(ModTestContext ctx)
|
||||
{
|
||||
var stage = await DialogStage.Create();
|
||||
try
|
||||
{
|
||||
var dlg = ScenarioParser.Parse("select \"?\"\noption \"A\" if=false -> :a\n\nset outcome skipped\nend\n:a\nset outcome a\nend\n");
|
||||
stage.Box.SetDialogQueueAndRun(dlg, null, 0, null);
|
||||
ModAssert.False(stage.Box.IsWaitingAnswer, "no answer is awaited");
|
||||
ModAssert.Equal("skipped", stage.Box.Runtime.GetVariable("outcome"), "the dialog went on past the choice");
|
||||
}
|
||||
finally
|
||||
{
|
||||
stage.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
namespace Cthangover.Mods.Dialog.Tests
|
||||
{
|
||||
using Cthangover.Core.Mods.Testing;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Mods.Dialog.Scenarios;
|
||||
|
||||
/// <summary><c>when</c> jumps on the shared condition language, evaluated when the line runs.</summary>
|
||||
public class WhenCommandStrategyTests
|
||||
{
|
||||
private static string Outcome(string scenario)
|
||||
{
|
||||
var dlg = ScenarioParser.Parse(scenario);
|
||||
var runtime = new DialogRuntime();
|
||||
runtime.SetDialogQueueAndRun(null, dlg.Queue, null);
|
||||
runtime.Run();
|
||||
return runtime.GetVariable("outcome");
|
||||
}
|
||||
|
||||
[ModTest("when/true_false_and_else")]
|
||||
static void TrueFalseAndElse(ModTestContext ctx)
|
||||
{
|
||||
ModAssert.Equal("yes", Outcome("when true -> :yes\nset outcome no\nend\n:yes\nset outcome yes\nend\n"), "true jumps");
|
||||
ModAssert.Equal("no", Outcome("when false -> :yes\nset outcome no\nend\n:yes\nset outcome yes\nend\n"), "false falls through");
|
||||
ModAssert.Equal("other", Outcome("when false -> :yes else=other\nset outcome no\nend\n:yes\nset outcome yes\nend\n:other\nset outcome other\nend\n"), "false takes else");
|
||||
}
|
||||
|
||||
[ModTest("when/reads_state_when_the_line_runs")]
|
||||
static void ReadsStateWhenTheLineRuns(ModTestContext ctx)
|
||||
{
|
||||
ScenarioCondition.SetFlag("test_when_flag", "0");
|
||||
try
|
||||
{
|
||||
const string scenario = "flag test_when_flag 2\nwhen \"test_when_flag >= 2 && !false\" -> :yes\nset outcome no\nend\n:yes\nset outcome yes\nend\n";
|
||||
ModAssert.Equal("yes", Outcome(scenario), "a flag set two lines earlier counts");
|
||||
}
|
||||
finally
|
||||
{
|
||||
ScenarioCondition.SetFlag("test_when_flag", "0");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user