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:
cthangoverandClaude Opus 5.5 committed 2026-10-24 10:01:11 +02:00
1 parent dde5262aa0
commit 68ed11cadc
14 files changed
+542 -3

No files matched your search

+29
View File
@@ -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
+29
View File
@@ -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
+29
View File
@@ -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"。空なら常に
+29
View File
@@ -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". 비우면 항상
+29
View File
@@ -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"; пусто — всегда
+29
View File
@@ -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
+29
View File
@@ -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";留空——总是显示
+164
View File
@@ -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) &gt;= 5 &amp;&amp; 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(':');
}
}
+4 -1
View File
@@ -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;
}
+17 -2
View File
@@ -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();
+59
View File
@@ -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();
}
}
}
}
+42
View File
@@ -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");
}
}
}
}