From e34cc1e5136cc5fe3526f1ad2ec99b90b684bd58 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Tue, 18 Oct 2022 22:53:21 +0200 Subject: [PATCH 01/36] porting all new tests --- script/test.ts | 40 +++++++++++++++++++ src/engine/Story.ts | 2 +- src/engine/StoryState.ts | 6 ++- .../compiled/choices/tags_in_choice.ink.json | 1 + ...onwards_to_variable_divert_target.ink.json | 1 + .../contains_empty_list_always_false.ink.json | 1 + .../compiled/tags/tag_on_choice.ink.json | 1 - .../tags/tags_dynamic_content.ink.json | 1 + .../compiled/tags/tags_in_seq.ink.json | 1 + .../compiled/tags/tags_on_choice.ink.json | 1 - .../original/choices/tags_in_choice.ink | 1 + ...nnel_onwards_to_variable_divert_target.ink | 10 +++++ .../contains_empty_list_always_false.ink | 4 ++ .../inkfiles/original/tags/tag_on_choice.ink | 1 - .../original/tags/tags_dynamic_content.ink | 1 + .../inkfiles/original/tags/tags_in_seq.ink | 4 ++ src/tests/specs/common.ts | 25 ++++++++++++ src/tests/specs/ink/Choices.spec.ts | 21 ++++++++++ src/tests/specs/ink/Diverts.spec.ts | 14 +++++++ src/tests/specs/ink/Lists.spec.ts | 7 ++++ src/tests/specs/ink/Tags.spec.ts | 34 +++++++++++----- 21 files changed, 161 insertions(+), 16 deletions(-) create mode 100644 script/test.ts create mode 100644 src/tests/inkfiles/compiled/choices/tags_in_choice.ink.json create mode 100644 src/tests/inkfiles/compiled/diverts/tunnel_onwards_to_variable_divert_target.ink.json create mode 100644 src/tests/inkfiles/compiled/lists/contains_empty_list_always_false.ink.json delete mode 100644 src/tests/inkfiles/compiled/tags/tag_on_choice.ink.json create mode 100644 src/tests/inkfiles/compiled/tags/tags_dynamic_content.ink.json create mode 100644 src/tests/inkfiles/compiled/tags/tags_in_seq.ink.json delete mode 100644 src/tests/inkfiles/compiled/tags/tags_on_choice.ink.json create mode 100644 src/tests/inkfiles/original/choices/tags_in_choice.ink create mode 100644 src/tests/inkfiles/original/diverts/tunnel_onwards_to_variable_divert_target.ink create mode 100644 src/tests/inkfiles/original/lists/contains_empty_list_always_false.ink delete mode 100644 src/tests/inkfiles/original/tags/tag_on_choice.ink create mode 100644 src/tests/inkfiles/original/tags/tags_dynamic_content.ink create mode 100644 src/tests/inkfiles/original/tags/tags_in_seq.ink diff --git a/script/test.ts b/script/test.ts new file mode 100644 index 000000000..a83cf9ef2 --- /dev/null +++ b/script/test.ts @@ -0,0 +1,40 @@ +// import { PRNG } from '../src/engine/PRNG'; + + + +// const clamp = (minInt: number, maxInt: number) => (next: number) => { +// let randomRange = maxInt - minInt + 1; +// let chosenValue = (next % randomRange) + minInt; +// return chosenValue; +// } + +// const listClamp = (count: number) => (next: number) => next % count; + + +// //const clamper = clamp(0,7); +// const clamper = listClamp(7); +// const n = 0 + +// for (let i = n; i < n + 100; i++) { +// const random = new PRNG(i) +// const nextRandom = random.next() +// let chosen = clamper(nextRandom); +// console.log(nextRandom, chosen); +// } + + +import { Compiler } from '../src/compiler/Compiler'; + +const mainInk = ` +{~1|2|3|4|5|6|7} +LIST lst = (a),(b),(c),(d),(e),(f),(g) +{LIST_RANDOM(lst)} +`; + +const c = new Compiler(mainInk) +const rstory = c.Compile(); + +while(rstory.canContinue){ + const t = rstory.Continue(); + console.log(t); +} \ No newline at end of file diff --git a/src/engine/Story.ts b/src/engine/Story.ts index 2f4949e5b..a30212097 100644 --- a/src/engine/Story.ts +++ b/src/engine/Story.ts @@ -50,7 +50,7 @@ if (!Number.isInteger) { } export class Story extends InkObject { - public static inkVersionCurrent = 20; + public static inkVersionCurrent = 21; public inkVersionMinimumCompatible = 18; diff --git a/src/engine/StoryState.ts b/src/engine/StoryState.ts index 94453377e..98ce3d75a 100644 --- a/src/engine/StoryState.ts +++ b/src/engine/StoryState.ts @@ -25,7 +25,11 @@ import { Flow } from "./Flow"; import { InkList } from "./InkList"; export class StoryState { - public readonly kInkSaveStateVersion = 9; + + // Backward compatible changes since v8: + // v10: dynamic tags + // v9: multi-flows + public readonly kInkSaveStateVersion = 10; public readonly kMinCompatibleLoadVersion = 8; public onDidLoadState: (() => void) | null = null; diff --git a/src/tests/inkfiles/compiled/choices/tags_in_choice.ink.json b/src/tests/inkfiles/compiled/choices/tags_in_choice.ink.json new file mode 100644 index 000000000..bec3c3ea7 --- /dev/null +++ b/src/tests/inkfiles/compiled/choices/tags_in_choice.ink.json @@ -0,0 +1 @@ +{"inkVersion":21,"root":[[["ev",{"^->":"0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","str","^two ","#","^two","/#out","/str","/ev",{"*":"0.c-0","flg":6},{"s":["^one ","#","^one ","/#out",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":"0.0.s"},[{"#n":"$r2"}],"^ three ","#","^three ","/#","end","\n",{"->":"0.g-0"},{"#f":5}],"g-0":["done",{"#f":5}]}],"done",{"#f":1}],"listDefs":{}} \ No newline at end of file diff --git a/src/tests/inkfiles/compiled/diverts/tunnel_onwards_to_variable_divert_target.ink.json b/src/tests/inkfiles/compiled/diverts/tunnel_onwards_to_variable_divert_target.ink.json new file mode 100644 index 000000000..6bdf6ed74 --- /dev/null +++ b/src/tests/inkfiles/compiled/diverts/tunnel_onwards_to_variable_divert_target.ink.json @@ -0,0 +1 @@ +{"inkVersion":21,"root":[[{"->t->":"outer"},["done",{"#f":5,"#n":"g-0"}],null],"done",{"outer":["^This is outer","\n","ev",{"^->":"the_esc"},"/ev",{"->":"cut_to"},{"#f":1}],"cut_to":[{"temp=":"escape"},"ev",{"VAR?":"escape"},"/ev","->->",{"#f":1}],"the_esc":["^This is the_esc","\n","end",{"#f":3}],"#f":1}],"listDefs":{}} \ No newline at end of file diff --git a/src/tests/inkfiles/compiled/lists/contains_empty_list_always_false.ink.json b/src/tests/inkfiles/compiled/lists/contains_empty_list_always_false.ink.json new file mode 100644 index 000000000..4b1376912 --- /dev/null +++ b/src/tests/inkfiles/compiled/lists/contains_empty_list_always_false.ink.json @@ -0,0 +1 @@ +{"inkVersion":21,"root":[["ev",{"VAR?":"list"},{"list":{}},"?","out","/ev","\n","ev",{"list":{}},{"list":{}},"?","out","/ev","\n","ev",{"list":{}},{"VAR?":"list"},"?","out","/ev","\n",["done",{"#f":5,"#n":"g-0"}],null],"done",{"global decl":["ev",{"list":{"list.a":1}},{"VAR=":"list"},"/ev","end",null],"#f":1}],"listDefs":{"list":{"a":1,"b":2}}} \ No newline at end of file diff --git a/src/tests/inkfiles/compiled/tags/tag_on_choice.ink.json b/src/tests/inkfiles/compiled/tags/tag_on_choice.ink.json deleted file mode 100644 index fd8ace9e4..000000000 --- a/src/tests/inkfiles/compiled/tags/tag_on_choice.ink.json +++ /dev/null @@ -1 +0,0 @@ -{"inkVersion":20,"root":[["ev","str","^Hi","/str","/ev",{"*":"0.c-0","flg":20},{"c-0":["^ Hello ",{"#":"hey"},"end","\n",{"->":"0.g-0"},{"#f":5}],"g-0":["done",null]}],"done",null],"listDefs":{}} \ No newline at end of file diff --git a/src/tests/inkfiles/compiled/tags/tags_dynamic_content.ink.json b/src/tests/inkfiles/compiled/tags/tags_dynamic_content.ink.json new file mode 100644 index 000000000..c8592555b --- /dev/null +++ b/src/tests/inkfiles/compiled/tags/tags_dynamic_content.ink.json @@ -0,0 +1 @@ +{"inkVersion":21,"root":[["^tag ","#","^pic","ev",5,3,"+","out","/ev",["ev","visit",1,"MIN","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"nop",{"s0":["pop","^red",{"->":"0.9.17"},null],"s1":["pop","^blue",{"->":"0.9.17"},null],"#f":5}],"^.jpg","/#","\n",["done",{"#f":5,"#n":"g-0"}],null],"done",{"#f":1}],"listDefs":{}} \ No newline at end of file diff --git a/src/tests/inkfiles/compiled/tags/tags_in_seq.ink.json b/src/tests/inkfiles/compiled/tags/tags_in_seq.ink.json new file mode 100644 index 000000000..8dbf64619 --- /dev/null +++ b/src/tests/inkfiles/compiled/tags/tags_in_seq.ink.json @@ -0,0 +1 @@ +{"inkVersion":21,"root":[[{"->t->":"knot"},{"->t->":"knot"},["done",{"#f":5,"#n":"g-0"}],null],"done",{"knot":["^A ",["ev","visit",3,"MIN","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"ev","du",2,"==","/ev",{"->":".^.s2","c":true},"ev","du",3,"==","/ev",{"->":".^.s3","c":true},"nop",{"s0":["pop","^red ","#","^red",{"->":".^.^.29"},null],"s1":["pop","^white ","/#","#","^white",{"->":".^.^.29"},null],"s2":["pop","^blue ","/#","#","^blue",{"->":".^.^.29"},null],"s3":["pop","^green ","/#","#","^green",{"->":".^.^.29"},null],"#f":5}],"/#","^ sequence.","\n","ev","void","/ev","->->",{"#f":1}],"#f":1}],"listDefs":{}} \ No newline at end of file diff --git a/src/tests/inkfiles/compiled/tags/tags_on_choice.ink.json b/src/tests/inkfiles/compiled/tags/tags_on_choice.ink.json deleted file mode 100644 index fd8ace9e4..000000000 --- a/src/tests/inkfiles/compiled/tags/tags_on_choice.ink.json +++ /dev/null @@ -1 +0,0 @@ -{"inkVersion":20,"root":[["ev","str","^Hi","/str","/ev",{"*":"0.c-0","flg":20},{"c-0":["^ Hello ",{"#":"hey"},"end","\n",{"->":"0.g-0"},{"#f":5}],"g-0":["done",null]}],"done",null],"listDefs":{}} \ No newline at end of file diff --git a/src/tests/inkfiles/original/choices/tags_in_choice.ink b/src/tests/inkfiles/original/choices/tags_in_choice.ink new file mode 100644 index 000000000..77be22bd8 --- /dev/null +++ b/src/tests/inkfiles/original/choices/tags_in_choice.ink @@ -0,0 +1 @@ ++ one #one [two #two] three #three -> END \ No newline at end of file diff --git a/src/tests/inkfiles/original/diverts/tunnel_onwards_to_variable_divert_target.ink b/src/tests/inkfiles/original/diverts/tunnel_onwards_to_variable_divert_target.ink new file mode 100644 index 000000000..2d2aec9ad --- /dev/null +++ b/src/tests/inkfiles/original/diverts/tunnel_onwards_to_variable_divert_target.ink @@ -0,0 +1,10 @@ +-> outer -> +== outer +This is outer +-> cut_to(-> the_esc) +=== cut_to(-> escape) + ->-> escape + +== the_esc +This is the_esc +-> END \ No newline at end of file diff --git a/src/tests/inkfiles/original/lists/contains_empty_list_always_false.ink b/src/tests/inkfiles/original/lists/contains_empty_list_always_false.ink new file mode 100644 index 000000000..7a7b67e29 --- /dev/null +++ b/src/tests/inkfiles/original/lists/contains_empty_list_always_false.ink @@ -0,0 +1,4 @@ +LIST list = (a), b +{list ? ()} +{() ? ()} +{() ? list} \ No newline at end of file diff --git a/src/tests/inkfiles/original/tags/tag_on_choice.ink b/src/tests/inkfiles/original/tags/tag_on_choice.ink deleted file mode 100644 index a5403464c..000000000 --- a/src/tests/inkfiles/original/tags/tag_on_choice.ink +++ /dev/null @@ -1 +0,0 @@ -* [Hi] Hello -> END #hey diff --git a/src/tests/inkfiles/original/tags/tags_dynamic_content.ink b/src/tests/inkfiles/original/tags/tags_dynamic_content.ink new file mode 100644 index 000000000..63576b9ae --- /dev/null +++ b/src/tests/inkfiles/original/tags/tags_dynamic_content.ink @@ -0,0 +1 @@ +tag # pic{5+3}{red|blue}.jpg \ No newline at end of file diff --git a/src/tests/inkfiles/original/tags/tags_in_seq.ink b/src/tests/inkfiles/original/tags/tags_in_seq.ink new file mode 100644 index 000000000..b39f74d33 --- /dev/null +++ b/src/tests/inkfiles/original/tags/tags_in_seq.ink @@ -0,0 +1,4 @@ +-> knot -> knot -> +== knot +A {red #red|white #white|blue #blue|green #green} sequence. +->-> \ No newline at end of file diff --git a/src/tests/specs/common.ts b/src/tests/specs/common.ts index 976b8bc39..3f9ae2a21 100644 --- a/src/tests/specs/common.ts +++ b/src/tests/specs/common.ts @@ -115,6 +115,31 @@ export class TestContext { }; } +/* + * Simplified Test Context when testing directly from a precompiled json file + * Useful when updating the runtime before having the compiler ready + */ +export function fromJsonTestContext( + name: string, + category: string, + testingErrors: boolean = false +){ + let context = new TestContext(testingErrors); + + let rootDir: string; + if (category) { + rootDir = path.join(inkBaselinePath, category); + } else { + rootDir = path.join(inkBaselinePath); + } + + let jsonContent = loadJSONFile(name, category); + context.story = new Story(jsonContent); + context.bytecode = context.story.ToJson(); + + return context; +} + export function makeDefaultTestContext( name: string, category: string, diff --git a/src/tests/specs/ink/Choices.spec.ts b/src/tests/specs/ink/Choices.spec.ts index 5194dea99..afbe21283 100644 --- a/src/tests/specs/ink/Choices.spec.ts +++ b/src/tests/specs/ink/Choices.spec.ts @@ -3,6 +3,13 @@ import * as testsUtils from "../common"; describe("Choices", () => { let context: testsUtils.TestContext; + function loadStory(name: any) { + context = testsUtils.fromJsonTestContext( + name, + "choices" + ) + } + function compileStory( name: string, countAllVisits: boolean = false, @@ -264,4 +271,18 @@ describe("Choices", () => { expect(context.warningMessages).toContainStringContaining("Blank choice"); }); + + //TestTagsInChoice + it("tests dynamic tags in choice", () => { + loadStory("tags_in_choice"); + + context.story.Continue(); + expect(context.story.currentTags).toEqual(["one","two"]) + expect(context.story.choices.length).toBe(2) + expect(context.story.currentChoices[0].tags).toEqual(["one", "two"]) + + context.story.ChooseChoiceIndex(0); + expect(context.story.Continue()).toBe("one three") + expect(context.story.currentTags).toEqual(["one","three"]) + }) }); diff --git a/src/tests/specs/ink/Diverts.spec.ts b/src/tests/specs/ink/Diverts.spec.ts index 38e1c1802..e1f002357 100644 --- a/src/tests/specs/ink/Diverts.spec.ts +++ b/src/tests/specs/ink/Diverts.spec.ts @@ -3,6 +3,13 @@ import * as testsUtils from "../common"; describe("Diverts", () => { let context: testsUtils.TestContext; + function loadStory(name: any) { + context = testsUtils.fromJsonTestContext( + name, + "diverts" + ) + } + function compileStory( name: string, countAllVisits: boolean = false, @@ -171,4 +178,11 @@ describe("Diverts", () => { "Empty diverts (->) are only valid on choices" ); }); + + + // TestTunnelOnwardsToVariableDivertTarget + it("tests variable divert target in tunnel onward", () => { + loadStory("tunnel_onwards_to_variable_divert_target") + expect(context.story.ContinueMaximally()).toMatch("This is outer\nThis is the_esc\n"); + }) }); diff --git a/src/tests/specs/ink/Lists.spec.ts b/src/tests/specs/ink/Lists.spec.ts index 35d20920c..e291009ec 100644 --- a/src/tests/specs/ink/Lists.spec.ts +++ b/src/tests/specs/ink/Lists.spec.ts @@ -90,4 +90,11 @@ describe("Lists", () => { expect(context.story.ContinueMaximally()).toBe("1\nl\nn\nl, m\nn\n"); }); + + // TestContainsEmptyListAlwaysFalse + it("tests list doest not contain empty list", () => { + compileStory("contains_empty_list_always_false"); + + expect(context.story.ContinueMaximally()).toBe("false\nfalse\nfalse\n"); + }); }); diff --git a/src/tests/specs/ink/Tags.spec.ts b/src/tests/specs/ink/Tags.spec.ts index bacc7ba14..a1b9370a7 100644 --- a/src/tests/specs/ink/Tags.spec.ts +++ b/src/tests/specs/ink/Tags.spec.ts @@ -3,6 +3,13 @@ import * as testsUtils from "../common"; describe("Tags", () => { let context: testsUtils.TestContext; + function loadStory(name: any) { + context = testsUtils.fromJsonTestContext( + name, + "tags" + ) + } + function compileStory( name: string, countAllVisits: boolean = false, @@ -45,18 +52,23 @@ describe("Tags", () => { expect(context.story.currentTags).toEqual(knotTagsWhenContinuedTwiceTags); }); - // TestTagOnChoice - it("tests tag on choice", () => { - compileStory("tag_on_choice"); + //TestTagsInSeq + it("tests tags in a sequence", () => { + loadStory("tags_in_seq"); - context.story.Continue(); - context.story.ChooseChoiceIndex(0); + expect(context.story.Continue()).toBe("A red sequence.\n"); + expect(context.story.currentTags).toEqual(["red"]) + + expect(context.story.Continue()).toBe("A white sequence.\n"); + expect(context.story.currentTags).toEqual(["white"]) + }) - let txt = context.story.Continue(); - let tags = context.story.currentTags; + //TestTagsDynamicContent + it("tests dynamic content in tags", () => { + loadStory("tags_dynamic_content"); + + expect(context.story.Continue()).toBe("tag\n"); + expect(context.story.currentTags).toEqual(["pic8red.jpg"]) + }) - expect(txt).toEqual("Hello"); - expect(tags.length).toEqual(1); - expect(tags[0]).toEqual("hey"); - }); }); From c86068d1f35cc41fe9e7cade6a5125a58955addc Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Tue, 18 Oct 2022 22:54:47 +0200 Subject: [PATCH 02/36] linter --- src/engine/StoryState.ts | 1 - src/tests/specs/common.ts | 4 ++-- src/tests/specs/ink/Choices.spec.ts | 19 ++++++++----------- src/tests/specs/ink/Diverts.spec.ts | 14 ++++++-------- src/tests/specs/ink/Tags.spec.ts | 18 +++++++----------- 5 files changed, 23 insertions(+), 33 deletions(-) diff --git a/src/engine/StoryState.ts b/src/engine/StoryState.ts index 98ce3d75a..3c5fcf8f4 100644 --- a/src/engine/StoryState.ts +++ b/src/engine/StoryState.ts @@ -25,7 +25,6 @@ import { Flow } from "./Flow"; import { InkList } from "./InkList"; export class StoryState { - // Backward compatible changes since v8: // v10: dynamic tags // v9: multi-flows diff --git a/src/tests/specs/common.ts b/src/tests/specs/common.ts index 3f9ae2a21..3a4b427f4 100644 --- a/src/tests/specs/common.ts +++ b/src/tests/specs/common.ts @@ -118,12 +118,12 @@ export class TestContext { /* * Simplified Test Context when testing directly from a precompiled json file * Useful when updating the runtime before having the compiler ready - */ + */ export function fromJsonTestContext( name: string, category: string, testingErrors: boolean = false -){ +) { let context = new TestContext(testingErrors); let rootDir: string; diff --git a/src/tests/specs/ink/Choices.spec.ts b/src/tests/specs/ink/Choices.spec.ts index afbe21283..ec8b949fb 100644 --- a/src/tests/specs/ink/Choices.spec.ts +++ b/src/tests/specs/ink/Choices.spec.ts @@ -4,10 +4,7 @@ describe("Choices", () => { let context: testsUtils.TestContext; function loadStory(name: any) { - context = testsUtils.fromJsonTestContext( - name, - "choices" - ) + context = testsUtils.fromJsonTestContext(name, "choices"); } function compileStory( @@ -275,14 +272,14 @@ describe("Choices", () => { //TestTagsInChoice it("tests dynamic tags in choice", () => { loadStory("tags_in_choice"); - + context.story.Continue(); - expect(context.story.currentTags).toEqual(["one","two"]) - expect(context.story.choices.length).toBe(2) - expect(context.story.currentChoices[0].tags).toEqual(["one", "two"]) + expect(context.story.currentTags).toEqual(["one", "two"]); + expect(context.story.currentChoices.length).toBe(2); + expect(context.story.currentChoices[0].tags).toEqual(["one", "two"]); context.story.ChooseChoiceIndex(0); - expect(context.story.Continue()).toBe("one three") - expect(context.story.currentTags).toEqual(["one","three"]) - }) + expect(context.story.Continue()).toBe("one three"); + expect(context.story.currentTags).toEqual(["one", "three"]); + }); }); diff --git a/src/tests/specs/ink/Diverts.spec.ts b/src/tests/specs/ink/Diverts.spec.ts index e1f002357..ac215ad25 100644 --- a/src/tests/specs/ink/Diverts.spec.ts +++ b/src/tests/specs/ink/Diverts.spec.ts @@ -4,10 +4,7 @@ describe("Diverts", () => { let context: testsUtils.TestContext; function loadStory(name: any) { - context = testsUtils.fromJsonTestContext( - name, - "diverts" - ) + context = testsUtils.fromJsonTestContext(name, "diverts"); } function compileStory( @@ -179,10 +176,11 @@ describe("Diverts", () => { ); }); - // TestTunnelOnwardsToVariableDivertTarget it("tests variable divert target in tunnel onward", () => { - loadStory("tunnel_onwards_to_variable_divert_target") - expect(context.story.ContinueMaximally()).toMatch("This is outer\nThis is the_esc\n"); - }) + loadStory("tunnel_onwards_to_variable_divert_target"); + expect(context.story.ContinueMaximally()).toMatch( + "This is outer\nThis is the_esc\n" + ); + }); }); diff --git a/src/tests/specs/ink/Tags.spec.ts b/src/tests/specs/ink/Tags.spec.ts index a1b9370a7..a5cb64d2c 100644 --- a/src/tests/specs/ink/Tags.spec.ts +++ b/src/tests/specs/ink/Tags.spec.ts @@ -4,10 +4,7 @@ describe("Tags", () => { let context: testsUtils.TestContext; function loadStory(name: any) { - context = testsUtils.fromJsonTestContext( - name, - "tags" - ) + context = testsUtils.fromJsonTestContext(name, "tags"); } function compileStory( @@ -57,18 +54,17 @@ describe("Tags", () => { loadStory("tags_in_seq"); expect(context.story.Continue()).toBe("A red sequence.\n"); - expect(context.story.currentTags).toEqual(["red"]) - + expect(context.story.currentTags).toEqual(["red"]); + expect(context.story.Continue()).toBe("A white sequence.\n"); - expect(context.story.currentTags).toEqual(["white"]) - }) + expect(context.story.currentTags).toEqual(["white"]); + }); //TestTagsDynamicContent it("tests dynamic content in tags", () => { loadStory("tags_dynamic_content"); expect(context.story.Continue()).toBe("tag\n"); - expect(context.story.currentTags).toEqual(["pic8red.jpg"]) - }) - + expect(context.story.currentTags).toEqual(["pic8red.jpg"]); + }); }); From ca0173abb657f46ae3a1e0986ffe58575a9fa704 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Tue, 18 Oct 2022 23:12:13 +0200 Subject: [PATCH 03/36] fix list contains 0 --- src/engine/InkList.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/engine/InkList.ts b/src/engine/InkList.ts index b0d906653..d7e89ad4d 100644 --- a/src/engine/InkList.ts +++ b/src/engine/InkList.ts @@ -391,7 +391,13 @@ export class InkList extends Map { return result; } - public Contains(otherList: InkList) { + + public Contains(key: string): boolean; + public Contains(otherList: InkList): boolean; + public Contains(what: string | InkList): boolean { + if (typeof what == "string") return this.ContainsItemNamed(what); + const otherList = what; + if (otherList.size == 0 || this.size == 0) return false; for (let [key] of otherList) { if (!this.has(key)) return false; } From 7a618c59bf4d162fd6c004ae606ff98682e140d4 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Tue, 18 Oct 2022 23:16:29 +0200 Subject: [PATCH 04/36] added HasIntersection --- src/engine/InkList.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/engine/InkList.ts b/src/engine/InkList.ts index d7e89ad4d..150776b62 100644 --- a/src/engine/InkList.ts +++ b/src/engine/InkList.ts @@ -383,6 +383,12 @@ export class InkList extends Map { return intersection; } + public HasIntersection(otherList: InkList): boolean { + for (let [key] of this) { + if (otherList.Contains(key)) return true; + } + return false; + } public Without(listToRemove: InkList) { let result = new InkList(this); for (let [key] of listToRemove) { From aa909137c1ddb55acf58ec48d29865cbf195ccfa Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Tue, 18 Oct 2022 23:20:15 +0200 Subject: [PATCH 05/36] Contains -> has --- src/engine/InkList.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/InkList.ts b/src/engine/InkList.ts index 150776b62..f8df6da43 100644 --- a/src/engine/InkList.ts +++ b/src/engine/InkList.ts @@ -385,7 +385,7 @@ export class InkList extends Map { } public HasIntersection(otherList: InkList): boolean { for (let [key] of this) { - if (otherList.Contains(key)) return true; + if (otherList.has(key)) return true; } return false; } From f1fccf94e98fd7e8e9202bb77058e6cdce57a458 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Tue, 18 Oct 2022 23:40:29 +0200 Subject: [PATCH 06/36] port 2 Command Controls definition files --- src/engine/ControlCommand.ts | 36 ++++++++++++++++++++++----------- src/engine/JsonSerialisation.ts | 4 ++++ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/engine/ControlCommand.ts b/src/engine/ControlCommand.ts index 3e763995e..68ddd0dae 100644 --- a/src/engine/ControlCommand.ts +++ b/src/engine/ControlCommand.ts @@ -89,6 +89,15 @@ export class ControlCommand extends InkObject { public static ListRandom() { return new ControlCommand(ControlCommand.CommandType.ListRandom); } + public static BeginTag() { + return new ControlCommand(ControlCommand.CommandType.BeginTag); + } + public static EndTag() { + return new ControlCommand(ControlCommand.CommandType.EndTag); + } + public static EndTagAndPushToStack() { + return new ControlCommand(ControlCommand.CommandType.EndTagAndPushToStack); + } public toString() { return this.commandType.toString(); } @@ -97,7 +106,7 @@ export class ControlCommand extends InkObject { export namespace ControlCommand { export enum CommandType { NotSet = -1, - EvalStart, // 0 + EvalStart, // 0 EvalOutput, // 1 EvalEnd, // 2 Duplicate, // 3 @@ -110,17 +119,20 @@ export namespace ControlCommand { ChoiceCount, // 10 Turns, // 11 TurnsSince, // 12 - Random, // 13 - SeedRandom, // 14 - VisitIndex, // 15 - SequenceShuffleIndex, // 16 - StartThread, // 17 - Done, // 18 - End, // 19 - ListFromInt, // 20 - ListRange, // 21 - ListRandom, // 22 - ReadCount, // 23 + ReadCount, // 13 + Random, // 14 + SeedRandom, // 15 + VisitIndex, // 16 + SequenceShuffleIndex, // 17 + StartThread, // 18 + Done, // 19 + End, // 20 + ListFromInt, // 21 + ListRange, // 22 + ListRandom, // 23 + BeginTag, // 24 + EndTag, // 25 + EndTagAndPushToStack, // 26 TOTAL_VALUES, } diff --git a/src/engine/JsonSerialisation.ts b/src/engine/JsonSerialisation.ts index d8a003b6b..01d6536d7 100644 --- a/src/engine/JsonSerialisation.ts +++ b/src/engine/JsonSerialisation.ts @@ -719,6 +719,10 @@ export class JsonSerialisation { _controlCommandNames[ControlCommand.CommandType.ListFromInt] = "listInt"; _controlCommandNames[ControlCommand.CommandType.ListRange] = "range"; _controlCommandNames[ControlCommand.CommandType.ListRandom] = "lrnd"; + _controlCommandNames[ControlCommand.CommandType.BeginTag] = "#"; + _controlCommandNames[ControlCommand.CommandType.EndTag] = "/#"; + _controlCommandNames[ControlCommand.CommandType.EndTagAndPushToStack] = + "/#out"; for (let i = 0; i < ControlCommand.CommandType.TOTAL_VALUES; ++i) { if (_controlCommandNames[i] == null) From d0799ce607e8ec03d00f314937a6d0f6c7de8513 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Tue, 18 Oct 2022 23:57:12 +0200 Subject: [PATCH 07/36] port choice class --- src/compiler/Parser/ParsedHierarchy/Choice.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/Parser/ParsedHierarchy/Choice.ts b/src/compiler/Parser/ParsedHierarchy/Choice.ts index f3cc83a50..9d71e339c 100644 --- a/src/compiler/Parser/ParsedHierarchy/Choice.ts +++ b/src/compiler/Parser/ParsedHierarchy/Choice.ts @@ -45,6 +45,7 @@ export class Choice extends ParsedObject implements IWeavePoint, INamedContent { } public onceOnly: boolean; public isInvisibleDefault: boolean = false; + public tags: string[] | null = null; public indentationDepth: number; public hasWeaveStyleInlineBrackets: boolean = false; From da980d64afcbc0321e5e3045de871b94210b197d Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Tue, 18 Oct 2022 23:59:13 +0200 Subject: [PATCH 08/36] oops wrong file --- src/compiler/Parser/ParsedHierarchy/Choice.ts | 1 - src/engine/Choice.ts | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/Parser/ParsedHierarchy/Choice.ts b/src/compiler/Parser/ParsedHierarchy/Choice.ts index 9d71e339c..f3cc83a50 100644 --- a/src/compiler/Parser/ParsedHierarchy/Choice.ts +++ b/src/compiler/Parser/ParsedHierarchy/Choice.ts @@ -45,7 +45,6 @@ export class Choice extends ParsedObject implements IWeavePoint, INamedContent { } public onceOnly: boolean; public isInvisibleDefault: boolean = false; - public tags: string[] | null = null; public indentationDepth: number; public hasWeaveStyleInlineBrackets: boolean = false; diff --git a/src/engine/Choice.ts b/src/engine/Choice.ts index 7153e0213..d29a9e962 100644 --- a/src/engine/Choice.ts +++ b/src/engine/Choice.ts @@ -10,6 +10,7 @@ export class Choice extends InkObject { public sourcePath: string = ""; public targetPath: Path | null = null; public isInvisibleDefault: boolean = false; + public tags: string[] | null = null; public originalThreadIndex: number = 0; get pathStringOnChoice(): string { From 530d557182f14376100edb8c5e77b696937203c4 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Wed, 19 Oct 2022 16:15:55 +0200 Subject: [PATCH 09/36] merge in --- src/engine/Story.ts | 130 ++++++++++++++++++++++++++++++------ src/engine/StoryState.ts | 91 ++++++++++++++++++++++--- src/engine/StringBuilder.ts | 4 ++ src/engine/Tag.ts | 8 +++ 4 files changed, 206 insertions(+), 27 deletions(-) diff --git a/src/engine/Story.ts b/src/engine/Story.ts index a30212097..0a0fed4b0 100644 --- a/src/engine/Story.ts +++ b/src/engine/Story.ts @@ -92,6 +92,14 @@ export class Story extends InkObject { return this.state.currentFlowName; } + get currentFlowIsDefaultFlow() { + return this.state.currentFlowIsDefaultFlow; + } + + get aliveFlowNames() { + return this.state.aliveFlowNames; + } + get hasError() { return this.state.hasError; } @@ -875,6 +883,21 @@ export class Story extends InkObject { } } + public PopChoiceStringAndTags(tags: string[]|null){ + let choiceOnlyStrVal = asOrThrows( + this.state.PopEvaluationStack(), + StringValue + ); + + while (this.state.evaluationStack.length > 0 + && asOrNull(this.state.PeekEvaluationStack(), Tag)) { + if( tags == null ) tags = []; + let tag = asOrNull(this.state.PopEvaluationStack(), Tag); + if(tag) tags.unshift(tag.text); + } + return choiceOnlyStrVal.value + } + public ProcessChoice(choicePoint: ChoicePoint) { let showChoice = true; @@ -888,23 +911,14 @@ export class Story extends InkObject { let startText = ""; let choiceOnlyText = ""; + let tags = null; if (choicePoint.hasChoiceOnlyContent) { - // var choiceOnlyStrVal = state.PopEvaluationStack () as StringValue; - let choiceOnlyStrVal = asOrThrows( - this.state.PopEvaluationStack(), - StringValue - ); - choiceOnlyText = choiceOnlyStrVal.value || ""; + choiceOnlyText = this.PopChoiceStringAndTags(tags) || ""; } if (choicePoint.hasStartContent) { - // var startStrVal = state.PopEvaluationStack () as StringValue; - let startStrVal = asOrThrows( - this.state.PopEvaluationStack(), - StringValue - ); - startText = startStrVal.value || ""; + startText = this.PopChoiceStringAndTags(tags) || ""; } // Don't create choice if player has already read this content @@ -929,6 +943,7 @@ export class Story extends InkObject { choice.sourcePath = choicePoint.path.toString(); choice.isInvisibleDefault = choicePoint.isInvisibleDefault; choice.threadAtGeneration = this.state.callStack.ForkThread(); + choice.tags = tags; choice.text = (startText + choiceOnlyText).replace(/^[ \t]+|[ \t]+$/g, ""); @@ -1148,9 +1163,61 @@ export class Story extends InkObject { ); this.state.inExpressionEvaluation = false; break; + + // Leave it to story.currentText and story.currentTags to sort out the text from the tags + // This is mostly because we can't rely on the existence of EndTag, and we don't want + // to try and flatten dynamic tags to strings every time \n is pushed to output + case ControlCommand.CommandType.BeginTag: + case ControlCommand.CommandType.EndTag: + this.state.PushToOutputStream(evalCommand); + break; + + case ControlCommand.CommandType.EndTagAndPushToStack:{ + let contentStackForTag: InkObject[] = []; + let outputCountConsumed = 0; + for (let i = this.state.outputStream.length - 1; i >= 0; --i) { + let obj = this.state.outputStream[i]; + + outputCountConsumed++; - case ControlCommand.CommandType.EndString: + // var command = obj as ControlCommand; + let command = asOrNull(obj, ControlCommand); + if (command){ + if( command.commandType == ControlCommand.CommandType.BeginTag ) { + break; + } else { + this.Error("Unexpected ControlCommand while extracting tag from choice"); + break; + } + } + if (obj instanceof StringValue) { + contentStackForTag.push(obj); + } + } + // Consume the content that was produced for this string + this.state.PopFromOutputStream (outputCountConsumed); + + // Build string out of the content we collected + let sb = new StringBuilder(); + for (let c of contentStackForTag) { + sb.Append(c.toString()); + } + + let choiceTag = new Tag(this.state.CleanOutputWhitespace(sb.toString())); + + // Pushing to the evaluation stack means it gets picked up + // when a Choice is generated from the next Choice Point. + this.state.PushEvaluationStack(choiceTag); + + // But we also push it to general output in case people + // want to get the tag from there. + this.state.PushToOutputStream (choiceTag); + break; + } + + case ControlCommand.CommandType.EndString:{ let contentStackForString: InkObject[] = []; + let contentToRetain: InkObject[] = []; let outputCountConsumed = 0; for (let i = this.state.outputStream.length - 1; i >= 0; --i) { @@ -1166,7 +1233,9 @@ export class Story extends InkObject { ) { break; } - + if( obj instanceof Tag ){ + contentToRetain.push(obj); + } if (obj instanceof StringValue) { contentStackForString.push(obj); } @@ -1175,6 +1244,13 @@ export class Story extends InkObject { // Consume the content that was produced for this string this.state.PopFromOutputStream(outputCountConsumed); + // Rescue the tags that we want actually to keep on the output stack + // rather than consume as part of the string we're building. + // At the time of writing, this only applies to Tag objects generated + // by choices, which are pushed to the stack during string generation. + for (let rescuedTag of contentToRetain) + this.state.PushToOutputStream(rescuedTag); + // The C# version uses a Stack for contentStackForString, but we're // using a simple array, so we need to reverse it before using it contentStackForString = contentStackForString.reverse(); @@ -1189,6 +1265,7 @@ export class Story extends InkObject { this.state.inExpressionEvaluation = true; this.state.PushEvaluationStack(new StringValue(sb.toString())); break; + } case ControlCommand.CommandType.ChoiceCount: let choiceCount = this.state.generatedChoices.length; @@ -2054,15 +2131,30 @@ export class Story extends InkObject { else break; } + let inTag = false; let tags: string[] | null = null; for (let c of flowContainer.content) { // var tag = c as Runtime.Tag; - let tag = asOrNull(c, Tag); - if (tag) { - if (tags == null) tags = []; - tags.push(tag.text); - } else break; + let command = asOrNull(c, ControlCommand); + + if (command != null) { + if( command.commandType == ControlCommand.CommandType.BeginTag ) { + inTag = true; + } else if( command.commandType == ControlCommand.CommandType.EndTag ) { + inTag = false; + } + } else if (inTag){ + let str = asOrNull(c, StringValue); + if( str !== null ) { + if( tags === null ) tags = []; + if(str.value !== null) tags.push(str.value); + } else { + this.Error("Tag contained non-text content. Only plain text is allowed when using globalTags or TagsAtContentPath. If you want to evaluate dynamic content, you need to use story.Continue()."); + } + } else { + break; + } } return tags; diff --git a/src/engine/StoryState.ts b/src/engine/StoryState.ts index 3c5fcf8f4..90eab79ec 100644 --- a/src/engine/StoryState.ts +++ b/src/engine/StoryState.ts @@ -259,11 +259,22 @@ export class StoryState { if (this._outputStreamTextDirty) { let sb = new StringBuilder(); + let inTag:boolean = false; + for (let outputObj of this.outputStream) { // var textContent = outputObj as StringValue; let textContent = asOrNull(outputObj, StringValue); - if (textContent !== null) { + if (!inTag && textContent !== null) { sb.Append(textContent.value); + }else{ + let controlCommand = asOrNull(outputObj, ControlCommand); + if( controlCommand !== null ) { + if( controlCommand.commandType == ControlCommand.CommandType.BeginTag ) { + inTag = true; + } else if( controlCommand.commandType == ControlCommand.CommandType.EndTag ) { + inTag = false; + } + } } } @@ -311,15 +322,49 @@ export class StoryState { get currentTags() { if (this._outputStreamTagsDirty) { this._currentTags = []; + let inTag: boolean = false; + let sb = new StringBuilder (); for (let outputObj of this.outputStream) { - // var tag = outputObj as Tag; - let tag = asOrNull(outputObj, Tag); - if (tag !== null) { - this._currentTags.push(tag.text); + let controlCommand = asOrNull(outputObj, ControlCommand); + if( controlCommand != null ) { + + if( controlCommand.commandType == ControlCommand.CommandType.BeginTag ) { + if( inTag && sb.Length > 0 ) { + var txt = this.CleanOutputWhitespace(sb.toString()); + this._currentTags.push(txt); + sb.Clear(); + } + inTag = true; + } + + else if( controlCommand.commandType == ControlCommand.CommandType.EndTag ) { + if( sb.Length > 0 ) { + var txt = this.CleanOutputWhitespace(sb.toString()); + this._currentTags.push(txt); + sb.Clear(); + } + inTag = false; + } + }else if( inTag ) { + let strVal = asOrNull(outputObj, StringValue) + if( strVal !== null ) { + sb.Append(strVal.value); + } + }else { + var tag = outputObj as Tag; + if (tag != null && tag.text != null && tag.text.length > 0) { + this._currentTags.push (tag.text); // tag.text has whitespae already cleaned + } } } + if( sb.Length > 0 ) { + var txt = this.CleanOutputWhitespace(sb.toString()); + this._currentTags.push(txt); + sb.Clear(); + } + this._outputStreamTagsDirty = false; } @@ -331,6 +376,29 @@ export class StoryState { return this._currentFlow.name; } + get currentFlowIsDefaultFlow() { + return this._currentFlow.name == this.kDefaultFlowName; + } + + get aliveFlowNames(): string[]{ + if( this._aliveFlowNamesDirty ) { + this._aliveFlowNames = []; + + if (this._namedFlows != null) + { + for (let flowName of this._namedFlows.keys()) { + if (flowName != this.kDefaultFlowName) { + this._aliveFlowNames.push(flowName); + } + } + } + + this._aliveFlowNamesDirty = false; + } + + return this._aliveFlowNames; + } + get inExpressionEvaluation() { return this.callStack.currentElement.inExpressionEvaluation; } @@ -344,6 +412,7 @@ export class StoryState { this._currentFlow = new Flow(this.kDefaultFlowName, story); this.OutputStreamDirty(); + this._aliveFlowNamesDirty = true; this._evaluationStack = []; this._variablesState = new VariablesState( @@ -388,6 +457,7 @@ export class StoryState { } else { flow = new Flow(flowName, this.story); this._namedFlows.set(flowName, flow); + this._aliveFlowNamesDirty = true; } this._currentFlow = flow; @@ -414,6 +484,7 @@ export class StoryState { if (this._namedFlows === null) return throwNullException("this._namedFlows"); this._namedFlows.delete(flowName); + this._aliveFlowNamesDirty = true; } public CopyAndStartPatching() { @@ -431,6 +502,7 @@ export class StoryState { copy._namedFlows = new Map(); for (let [namedFlowKey, namedFlowValue] of this._namedFlows) { copy._namedFlows.set(namedFlowKey, namedFlowValue); + copy._aliveFlowNamesDirty = true; } copy._namedFlows.set(this._currentFlow.name, copy._currentFlow); } @@ -629,6 +701,7 @@ export class StoryState { } this.OutputStreamDirty(); + this._aliveFlowNamesDirty = true; this.variablesState.SetJsonToken(jObject["variablesState"]); this.variablesState.callStack = this._currentFlow.callStack; @@ -1048,12 +1121,12 @@ export class StoryState { if (args !== null) { for (let i = 0; i < args.length; i++) { if ( - !(typeof args[i] === "number" || typeof args[i] === "string") || + !(typeof args[i] === "number" || typeof args[i] === "string" || typeof args[i] === "boolean" || args[i] instanceof InkList - ) { + )) { throw new Error( "ink arguments when calling EvaluateFunction / ChoosePathStringWithParameters must be" + - "number, string or InkList. Argument was " + + "number, string, bool or InkList. Argument was " + (nullIfUndefined(arguments[i]) === null) ? "null" : arguments[i].constructor.name @@ -1145,6 +1218,8 @@ export class StoryState { private _patch: StatePatch | null = null; private _currentFlow: Flow; + private _aliveFlowNames: string[] | null = null; private _namedFlows: Map | null = null; private readonly kDefaultFlowName = "DEFAULT_FLOW"; + private _aliveFlowNamesDirty: boolean = true; } diff --git a/src/engine/StringBuilder.ts b/src/engine/StringBuilder.ts index ef91c9f94..cae68a5f6 100644 --- a/src/engine/StringBuilder.ts +++ b/src/engine/StringBuilder.ts @@ -26,4 +26,8 @@ export class StringBuilder { public toString(): string { return this.string; } + + public Clear(){ + this.string = ""; + } } diff --git a/src/engine/Tag.ts b/src/engine/Tag.ts index e3cd3d9e6..b7dd909f5 100644 --- a/src/engine/Tag.ts +++ b/src/engine/Tag.ts @@ -1,5 +1,13 @@ import { InkObject } from "./Object"; +// New version of tags is dynamic - it constructs the tags +// at runtime based on BeginTag and EndTag control commands. +// Plain text that's in the output stream is turned into tags +// when you do story.currentTags. +// The only place this is used is when flattening tags down +// to string in advance, during dynamic string generation if +// there's a tag embedded in it. See how ControlCommand.EndString +// is implemented in Story.cs for more details + comment export class Tag extends InkObject { public readonly text: string; From 7b20a01455d05d80db55096d2ccd4bdc039774cc Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Wed, 19 Oct 2022 17:58:22 +0200 Subject: [PATCH 10/36] avengers assemble --- src/engine/Story.ts | 6 +++--- src/engine/StoryState.ts | 2 +- src/tests/inkfiles/compiled/inkjs/tests.ink.json | 2 +- src/tests/inkfiles/compiled/tags/tags.ink.json | 2 +- src/tests/specs/ink/Choices.spec.ts | 5 +++-- src/tests/specs/ink/Tags.spec.ts | 2 +- src/tests/specs/inkjs/engine/Tags.spec.ts | 11 ++++------- 7 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/engine/Story.ts b/src/engine/Story.ts index 0a0fed4b0..330c19904 100644 --- a/src/engine/Story.ts +++ b/src/engine/Story.ts @@ -883,7 +883,7 @@ export class Story extends InkObject { } } - public PopChoiceStringAndTags(tags: string[]|null){ + public PopChoiceStringAndTags(tags: string[]){ let choiceOnlyStrVal = asOrThrows( this.state.PopEvaluationStack(), StringValue @@ -891,7 +891,6 @@ export class Story extends InkObject { while (this.state.evaluationStack.length > 0 && asOrNull(this.state.PeekEvaluationStack(), Tag)) { - if( tags == null ) tags = []; let tag = asOrNull(this.state.PopEvaluationStack(), Tag); if(tag) tags.unshift(tag.text); } @@ -911,7 +910,7 @@ export class Story extends InkObject { let startText = ""; let choiceOnlyText = ""; - let tags = null; + let tags:string[] = []; if (choicePoint.hasChoiceOnlyContent) { choiceOnlyText = this.PopChoiceStringAndTags(tags) || ""; @@ -943,6 +942,7 @@ export class Story extends InkObject { choice.sourcePath = choicePoint.path.toString(); choice.isInvisibleDefault = choicePoint.isInvisibleDefault; choice.threadAtGeneration = this.state.callStack.ForkThread(); + choice.tags = tags; choice.text = (startText + choiceOnlyText).replace(/^[ \t]+|[ \t]+$/g, ""); diff --git a/src/engine/StoryState.ts b/src/engine/StoryState.ts index 90eab79ec..55e8b47af 100644 --- a/src/engine/StoryState.ts +++ b/src/engine/StoryState.ts @@ -380,7 +380,7 @@ export class StoryState { return this._currentFlow.name == this.kDefaultFlowName; } - get aliveFlowNames(): string[]{ + get aliveFlowNames(){ if( this._aliveFlowNamesDirty ) { this._aliveFlowNames = []; diff --git a/src/tests/inkfiles/compiled/inkjs/tests.ink.json b/src/tests/inkfiles/compiled/inkjs/tests.ink.json index 325a88e89..67133d4f0 100644 --- a/src/tests/inkfiles/compiled/inkjs/tests.ink.json +++ b/src/tests/inkfiles/compiled/inkjs/tests.ink.json @@ -1 +1 @@ -{"inkVersion":20,"root":[[{"#":"global tag"},{"->":"glue.diverted_glue"},"^Ouside content","\n",{"#":"not a global tag"},["done",{"#f":5,"#n":"g-0"}],null],"done",{"fn_ext":[{"temp=":"c"},{"temp=":"b"},{"temp=":"a"},"ev",{"VAR?":"a"},"/ev","~ret",{"#f":1}],"gameInc":[{"temp=":"x"},"ev",{"VAR?":"x"},1,"+","/ev","~ret",{"#f":1}],"knot":["^Knot content","\n","done",{"stitch":["^Stitch content","\n","done",{"#f":1}],"#f":1}],"content":[{"->":".^.simple"},{"simple":["^Simple content inside a knot","\n","done",{"#f":1}],"multiline":["^First line","\n","^Second line","\n","done",{"#f":1}],"variable_text":["ev","str","^variable text","/str","/ev",{"temp=":"VARIABLETEXT"},"ev",{"VAR?":"VARIABLETEXT"},"out","/ev","\n","done",{"#f":1}],"if_text_truthy":["ev",true,"/ev",{"temp=":"met_blofeld"},"^I… ","ev",{"VAR?":"met_blofeld"},"/ev",[{"->":".^.b","c":true},{"b":["^ I saw him. Only for a moment.",{"->":".^.^.^.9"},null]}],"nop","\n","done",{"#f":1}],"if_text_falsy":["ev",false,"/ev",{"temp=":"met_blofeld"},"^I… ","ev",{"VAR?":"met_blofeld"},"/ev",[{"->":".^.b","c":true},{"b":["^ I saw him. Only for a moment.",{"->":".^.^.^.9"},null]}],"nop","\n","done",{"#f":1}],"if_else_text":["ev",true,"/ev",{"temp=":"met_blofeld"},"ev",{"VAR?":"met_blofeld"},"/ev",[{"->":".^.b","c":true},{"b":["^ I saw him. Only for a moment.",{"->":".^.^.^.9"},null]}],[{"->":".^.b"},{"b":["^I missed him. Was he particularly evil?",{"->":".^.^.^.9"},null]}],"nop","\n","ev",false,"/ev",{"temp=":"met_blofeld","re":true},"ev",{"VAR?":"met_blofeld"},"/ev",[{"->":".^.b","c":true},{"b":["^ I saw him. Only for a moment.",{"->":".^.^.^.20"},null]}],[{"->":".^.b"},{"b":["^I missed him. Was he particularly evil?",{"->":".^.^.^.20"},null]}],"nop","\n","done",{"#f":1}],"#f":1}],"glue":[{"->":".^.simple"},{"simple":["^Simple ","<>","\n","^glue","\n","done",{"#f":1}],"diverted_glue":["^More ","<>",{"->":"glue.diverted_glue_target"},"\n",{"#f":1}],"diverted_glue_target":["^glue","\n","done",{"#f":1}],"#f":1}],"divert":[{"->":".^.divert_knot"},{"divert_knot":[{"->":"divert_knot_target"},{"#f":1}],"divert_stitch":[{"->":"divert_knot_target.divert_stitch_target"},{"#f":1}],"internal_stitch":[{"->":".^.^.internal_stitch_target"},{"#f":1}],"divert_var":["ev",{"^->":"divert_knot_target.divert_var_target"},"/ev",{"temp=":"destination"},{"->":"destination","var":true},{"#f":1}],"internal_stitch_target":["^Diverted to internal stitch","\n","done",{"#f":1}],"#f":1}],"divert_knot_target":["^Diverted to a knot","\n","done",{"divert_stitch_target":["^Diverted to a stitch","\n","done",{"#f":1}],"divert_var_target":["^Diverted with a variable","\n","done",{"#f":3}],"#f":1}],"tags":[{"#":"knot tag"},"done",{"line_by_Line":["^A line of content ",{"#":"a tag"},"\n","^Another line of content ",{"#":"tag1"},{"#":"tag2"},"\n",{"#":"tag above"},"^Content after a tag ",{"#":"tag after"},"\n",{"#":"tag below"},"done",{"#f":1}],"choice":[[["ev",{"^->":"tags.choice.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^a choice ",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"tags.choice.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],{"#":"a tag"},"\n","done",{"#f":5}]}],{"#f":1}],"weird":[{"#":"space around"},{"#":""},{"#":""},{"#":""},{"#":"0"},"done",{"#f":1}],"#f":1}],"simple_lists":[{"->":".^.sequence"},{"sequence":[["ev","visit",3,"MIN","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"ev","du",2,"==","/ev",{"->":".^.s2","c":true},"ev","du",3,"==","/ev",{"->":".^.s3","c":true},"nop",{"s0":["pop","^one",{"->":".^.^.29"},null],"s1":["pop","^two",{"->":".^.^.29"},null],"s2":["pop","^three",{"->":".^.^.29"},null],"s3":["pop","^final",{"->":".^.^.29"},null],"#f":5}],"\n","done",{"#f":1}],"cycle":[["ev","visit",3,"%","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"ev","du",2,"==","/ev",{"->":".^.s2","c":true},"nop",{"s0":["pop","^one",{"->":".^.^.23"},null],"s1":["pop","^two",{"->":".^.^.23"},null],"s2":["pop","^three",{"->":".^.^.23"},null],"#f":5}],"\n","done",{"#f":1}],"once":[["ev","visit",3,"MIN","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"ev","du",2,"==","/ev",{"->":".^.s2","c":true},"ev","du",3,"==","/ev",{"->":".^.s3","c":true},"nop",{"s0":["pop","^one",{"->":".^.^.29"},null],"s1":["pop","^two",{"->":".^.^.29"},null],"s2":["pop","^three",{"->":".^.^.29"},null],"s3":["pop",{"->":".^.^.29"},null],"#f":5}],"\n","done",{"#f":1}],"shuffle":[["ev","visit",2,"seq","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"nop",{"s0":["pop","^heads",{"->":".^.^.17"},null],"s1":["pop","^tails",{"->":".^.^.17"},null],"#f":5}],"\n","done",{"#f":1}],"blanks":[["ev","visit",3,"MIN","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"ev","du",2,"==","/ev",{"->":".^.s2","c":true},"ev","du",3,"==","/ev",{"->":".^.s3","c":true},"nop",{"s0":["pop",{"->":".^.^.29"},null],"s1":["pop",{"->":".^.^.29"},null],"s2":["pop",{"->":".^.^.29"},null],"s3":["pop","^end",{"->":".^.^.29"},null],"#f":5}],"\n","done",{"#f":1}],"#f":1}],"choices":[{"->":".^.basic_choice"},{"basic_choice":[[["ev",{"^->":"choices.basic_choice.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^a choice",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"choices.basic_choice.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n","done",{"#f":5}]}],{"#f":1}],"multiple_choices":[[["ev",{"^->":"choices.multiple_choices.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^choice 1",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.multiple_choices.0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^choice 2",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.multiple_choices.0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-2","flg":18},{"s":["^choice 3",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"choices.multiple_choices.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"choices.multiple_choices.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-2":["ev",{"^->":"choices.multiple_choices.0.c-2.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["done",{"#f":5}]}],{"#f":1}],"choice_text":[[["ev",{"^->":"choices.choice_text.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","str","^choice only","/str","/ev",{"*":".^.^.c-0","flg":22},{"s":["^always ",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"choices.choice_text.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"^output only","\n","done",{"#f":5}]}],{"#f":1}],"suppression":[[["ev",{"^->":"choices.suppression.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^choice 1",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.suppression.0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^choice 2",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"choices.suppression.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"choices.suppression.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["done",{"#f":5}]}],{"#f":1}],"fallback":[[["ev",{"^->":"choices.fallback.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^choice 1",{"->":"$r","var":true},null]}],{"*":".^.c-1","flg":24},{"c-0":["ev",{"^->":"choices.fallback.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n","done",{"#f":5}],"c-1":["done","\n",{"#f":5}]}],{"#f":1}],"sticky":[[["ev",{"^->":"choices.sticky.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^disapears",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.sticky.0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":2},{"s":["^stays",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"choices.sticky.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n","done",{"#f":5}],"c-1":["ev",{"^->":"choices.sticky.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","done",{"#f":5}]}],{"#f":1}],"conditional":[["ev",true,"/ev",{"temp=":"truthy"},"ev",true,"/ev",{"temp=":"truthy2"},"ev",false,"/ev",{"temp=":"falsy"},["ev",{"^->":"choices.conditional.0.12.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^no condition",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.conditional.0.13.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str",{"VAR?":"truthy"},"/ev",{"*":".^.^.c-1","flg":19},{"s":["^available",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.conditional.0.14.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str",{"VAR?":"falsy"},"/ev",{"*":".^.^.c-2","flg":19},{"s":["^not available",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.conditional.0.15.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str",{"VAR?":"truthy"},{"VAR?":"truthy2"},"&&","/ev",{"*":".^.^.c-3","flg":19},{"s":["^multi condition available",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.conditional.0.16.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str",{"VAR?":"truthy"},{"VAR?":"falsy"},"&&","/ev",{"*":".^.^.c-4","flg":19},{"s":["^multi condition not available",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"choices.conditional.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.12.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"choices.conditional.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.13.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-2":["ev",{"^->":"choices.conditional.0.c-2.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.14.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-3":["ev",{"^->":"choices.conditional.0.c-3.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.15.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-4":["ev",{"^->":"choices.conditional.0.c-4.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.16.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["done",{"#f":5}]}],{"#f":1}],"#f":1}],"logic":[{"->":".^.vardef"},{"vardef":["^variables defined: ","ev","str","^Emilia","/str","out","/ev","^ ","ev",521,"out","/ev","^ ","ev",52.1,"out","/ev","\n","done",{"#f":1}],"casts":["ev",{"VAR?":"intvar"},0.5,"+","out","/ev","\n","ev",{"VAR?":"intvar"},"str","^hello","/str","+","out","/ev","\n","ev",{"VAR?":"floatvar"},"/ev",[{"->":".^.b","c":true},{"b":["^float var is truthy",{"->":".^.^.^.21"},null]}],[{"->":".^.b"},{"b":["^is falsy and broken",{"->":".^.^.^.21"},null]}],"nop","\n","ev",{"VAR?":"floatvar"},"str","^hello","/str","+","out","/ev","\n","ev",{"VAR?":"stringvar"},"/ev",[{"->":".^.b","c":true},{"b":["^string var is truthy",{"->":".^.^.^.37"},null]}],[{"->":".^.b"},{"b":["^is falsy and broken",{"->":".^.^.^.37"},null]}],"nop","\n","done",{"#f":1}],"logic_divert_dest":["done",{"#f":3}],"math":["ev",5,"/ev",{"temp=":"int"},"ev",1,1,"+","out","/ev","\n","ev",1,1,"-","out","/ev","\n","ev",{"VAR?":"int"},"_","out","/ev","\n","ev",1,2,"*","out","/ev","\n","ev",10,2,"/","out","/ev","\n","ev",11,2,"%","out","/ev","\n","ev",1,1,"==","/ev",[{"->":".^.b","c":true},{"b":["^int truthy equal",{"->":".^.^.^.52"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.52"},null]}],"nop","\n","ev",1,2,"==","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.61"},null]}],[{"->":".^.b"},{"b":["^int falsy equal",{"->":".^.^.^.61"},null]}],"nop","\n","ev",2,1,">","/ev",[{"->":".^.b","c":true},{"b":["^int truthy greater",{"->":".^.^.^.70"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.70"},null]}],"nop","\n","ev",1,2,">","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.79"},null]}],[{"->":".^.b"},{"b":["^int falsy greater",{"->":".^.^.^.79"},null]}],"nop","\n","ev",1,2,"<","/ev",[{"->":".^.b","c":true},{"b":["^int truthy lesser",{"->":".^.^.^.88"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.88"},null]}],"nop","\n","ev",2,1,"<","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.97"},null]}],[{"->":".^.b"},{"b":["^int falsy lesser",{"->":".^.^.^.97"},null]}],"nop","\n","ev",2,1,">=","/ev",[{"->":".^.b","c":true},{"b":["^int truthy greater or equal",{"->":".^.^.^.106"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.106"},null]}],"nop","\n","ev",1,2,">=","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.115"},null]}],[{"->":".^.b"},{"b":["^int falsy greater or equal",{"->":".^.^.^.115"},null]}],"nop","\n","ev",1,2,"<=","/ev",[{"->":".^.b","c":true},{"b":["^int truthy lesser or equal",{"->":".^.^.^.124"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.124"},null]}],"nop","\n","ev",2,1,"<=","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.133"},null]}],[{"->":".^.b"},{"b":["^int falsy lesser or equal",{"->":".^.^.^.133"},null]}],"nop","\n","ev",2,1,"!=","/ev",[{"->":".^.b","c":true},{"b":["^int truthy not equal",{"->":".^.^.^.142"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.142"},null]}],"nop","\n","ev",1,1,"!=","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.151"},null]}],[{"->":".^.b"},{"b":["^int falsy not equal",{"->":".^.^.^.151"},null]}],"nop","\n","ev",1,"/ev",{"temp=":"one"},"ev",0,"/ev",{"temp=":"zero"},["ev",{"VAR?":"zero"},"!","/ev",{"->":".^.b","c":true},{"b":["\n","^int truthy not","\n",{"->":".^.^.^.163"},null]}],[{"->":".^.b"},{"b":["\n","^broken","\n",{"->":".^.^.^.163"},null]}],"nop","\n",["ev",{"VAR?":"one"},"!","/ev",{"->":".^.b","c":true},{"b":["\n","^broken","\n",{"->":".^.^.^.167"},null]}],[{"->":".^.b"},{"b":["\n","^int falsy not","\n",{"->":".^.^.^.167"},null]}],"nop","\n","ev",1,1,"&&","/ev",[{"->":".^.b","c":true},{"b":["^int truthy and",{"->":".^.^.^.176"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.176"},null]}],"nop","\n","ev",1,0,"&&","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.185"},null]}],[{"->":".^.b"},{"b":["^int falsy and",{"->":".^.^.^.185"},null]}],"nop","\n","ev",1,0,"||","/ev",[{"->":".^.b","c":true},{"b":["^int truthy or",{"->":".^.^.^.194"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.194"},null]}],"nop","\n","ev",0,0,"||","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.203"},null]}],[{"->":".^.b"},{"b":["^int falsy or",{"->":".^.^.^.203"},null]}],"nop","\n","ev",5.2,"/ev",{"temp=":"float"},"ev",1.3,1.3,"+","out","/ev","\n","ev",1.3,1.3,"-","out","/ev","\n","ev",{"VAR?":"float"},"_","out","/ev","\n","ev",1.5,2.4,"*","out","/ev","\n","ev",10.5,2.5,"/","out","/ev","\n","ev",11.5,2.5,"%","out","/ev","\n","ev",1.3,1.3,"==","/ev",[{"->":".^.b","c":true},{"b":["^float truthy equal",{"->":".^.^.^.257"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.257"},null]}],"nop","\n","ev",1.3,2.3,"==","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.266"},null]}],[{"->":".^.b"},{"b":["^float falsy equal",{"->":".^.^.^.266"},null]}],"nop","\n","ev",2.3,1.3,">","/ev",[{"->":".^.b","c":true},{"b":["^float truthy greater",{"->":".^.^.^.275"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.275"},null]}],"nop","\n","ev",1.3,2.3,">","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.284"},null]}],[{"->":".^.b"},{"b":["^float falsy greater",{"->":".^.^.^.284"},null]}],"nop","\n","ev",1.3,2.3,"<","/ev",[{"->":".^.b","c":true},{"b":["^float truthy lesser",{"->":".^.^.^.293"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.293"},null]}],"nop","\n","ev",2.3,1.3,"<","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.302"},null]}],[{"->":".^.b"},{"b":["^float falsy lesser",{"->":".^.^.^.302"},null]}],"nop","\n","ev",2.3,1.3,">=","/ev",[{"->":".^.b","c":true},{"b":["^float truthy greater or equal",{"->":".^.^.^.311"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.311"},null]}],"nop","\n","ev",1.3,2.3,">=","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.320"},null]}],[{"->":".^.b"},{"b":["^float falsy greater or equal",{"->":".^.^.^.320"},null]}],"nop","\n","ev",1.3,2.3,"<=","/ev",[{"->":".^.b","c":true},{"b":["^float truthy lesser or equal",{"->":".^.^.^.329"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.329"},null]}],"nop","\n","ev",2.3,1.3,"<=","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.338"},null]}],[{"->":".^.b"},{"b":["^float falsy lesser or equal",{"->":".^.^.^.338"},null]}],"nop","\n","ev",2.3,1.3,"!=","/ev",[{"->":".^.b","c":true},{"b":["^float truthy not equal",{"->":".^.^.^.347"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.347"},null]}],"nop","\n","ev",1.3,1.3,"!=","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.356"},null]}],[{"->":".^.b"},{"b":["^float falsy not equal",{"->":".^.^.^.356"},null]}],"nop","\n","ev",1.2,"/ev",{"temp=":"onepointtwo"},["ev",{"VAR?":"onepointtwo"},"!","/ev",{"->":".^.b","c":true},{"b":["\n","^broken","\n",{"->":".^.^.^.364"},null]}],[{"->":".^.b"},{"b":["\n","^float falsy not","\n",{"->":".^.^.^.364"},null]}],"nop","\n","ev",1.3,1.3,"&&","/ev",[{"->":".^.b","c":true},{"b":["^float truthy and",{"->":".^.^.^.373"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.373"},null]}],"nop","\n","ev",1.3,0,"&&","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.382"},null]}],[{"->":".^.b"},{"b":["^float falsy and",{"->":".^.^.^.382"},null]}],"nop","\n","ev",1.3,0,"||","/ev",[{"->":".^.b","c":true},{"b":["^float truthy or",{"->":".^.^.^.391"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.391"},null]}],"nop","\n","ev",0,0,"||","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.400"},null]}],[{"->":".^.b"},{"b":["^float falsy or",{"->":".^.^.^.400"},null]}],"nop","\n","ev","str","^hello","/str","str","^hello","/str","==","/ev",[{"->":".^.b","c":true},{"b":["^truthy string equal",{"->":".^.^.^.413"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.413"},null]}],"nop","\n","ev","str","^hello","/str","str","^world","/str","==","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.426"},null]}],[{"->":".^.b"},{"b":["^falsy string equal",{"->":".^.^.^.426"},null]}],"nop","\n","ev","str","^hello","/str","str","^world","/str","!=","/ev",[{"->":".^.b","c":true},{"b":["^truthy string not equal",{"->":".^.^.^.439"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.439"},null]}],"nop","\n","ev","str","^hello","/str","str","^hello","/str","!=","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.452"},null]}],[{"->":".^.b"},{"b":["^falsy string not equal",{"->":".^.^.^.452"},null]}],"nop","\n","ev",{"^->":"logic.ifelse"},{"^->":"logic.ifelse"},"==","/ev",[{"->":".^.b","c":true},{"b":["^truthy divert equal",{"->":".^.^.^.461"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.461"},null]}],"nop","\n","ev",{"^->":"logic.ifelse"},{"^->":"logic.stitch_param"},"==","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.470"},null]}],[{"->":".^.b"},{"b":["^falsy divert equal",{"->":".^.^.^.470"},null]}],"nop","\n","done",{"#f":1}],"ifelse":[["ev",{"VAR?":"intvar"},521,"==","/ev",{"->":".^.b","c":true},{"b":["\n","^if text","\n",{"->":".^.^.^.2"},null]}],[{"->":".^.b"},{"b":["\n","^else text","\n",{"->":".^.^.^.2"},null]}],"nop","\n",["ev",{"VAR?":"intvar"},521,"<","/ev",{"->":".^.b","c":true},{"b":["\n","^if text","\n",{"->":".^.^.^.6"},null]}],[{"->":".^.b"},{"b":["\n","^else text","\n",{"->":".^.^.^.6"},null]}],"nop","\n",["ev",{"VAR?":"intvar"},521,"<","/ev",{"->":".^.b","c":true},{"b":["\n","^if text","\n",{"->":".^.^.^.11"},null]}],["ev",{"VAR?":"intvar"},1,">","/ev",{"->":".^.b","c":true},{"b":["\n","^elseif text","\n",{"->":".^.^.^.11"},null]}],[{"->":".^.b"},{"b":["\n","^else text","\n",{"->":".^.^.^.11"},null]}],"nop","\n","done",{"#f":3}],"stitch_param":["ev","str","^param","/str","/ev",{"->":".^.^.stitch_with_param"},"done",{"#f":3}],"stitch_with_param":[{"temp=":"what"},"^Called with ","ev",{"VAR?":"what"},"out","/ev","\n","done",{"#f":1}],"constants":["^constants defined: ","ev","str","^Emilia","/str","out","/ev","^ ","ev",521,"out","/ev","^ ","ev",52.1,"out","/ev","\n","done",{"#f":1}],"simple_functions":["ev",{"f()":"fn_with_return"},"out","/ev","\n","ev",{"f()":"fn_print"},"out","/ev","\n","ev",{"f()":"fn_calls_other"},"out","/ev","\n","^Function called inline and ","ev",{"f()":"fn_with_return"},"out","/ev","^ something","\n","done",{"#f":1}],"param_functions":["ev",{"VAR?":"fnParamA"},{"VAR?":"fnParamB"},{"f()":"fn_params"},"out","/ev","\n","ev",{"^var":"fnParamA","ci":-1},{"^var":"fnParamB","ci":-1},{"f()":"fn_params_ref"},"out","/ev","\n","done",{"#f":1}],"void_function":["ev",{"f()":"fn_without_return"},"out","/ev","\n","done",{"#f":1}],"random":["ev",25,"srnd","pop","/ev","\n","ev",0,100,"rnd","out","/ev","\n","ev",-50,50,"rnd","out","/ev","\n","done",{"#f":1}],"#f":1}],"fn_with_return":["ev","str","^returned","/str","/ev","~ret",{"#f":1}],"fn_without_return":["ev",1,"/ev",{"temp=":"a"},{"#f":1}],"fn_print":["^function called","\n",{"#f":1}],"fn_params":[{"temp=":"b"},{"temp=":"a"},"ev","str","^was a","/str","/ev",{"temp=":"a","re":true},"ev","str","^was b","/str","/ev",{"temp=":"b","re":true},"ev",{"VAR?":"a"},"/ev","~ret",{"#f":1}],"fn_params_ref":[{"temp=":"b"},{"temp=":"a"},"ev","str","^was a","/str","/ev",{"temp=":"a","re":true},"ev","str","^was b","/str","/ev",{"temp=":"b","re":true},"ev",{"VAR?":"a"},"/ev","~ret",{"#f":1}],"fn_calls_other":["ev",{"f()":"fn_called"},"/ev","~ret","\n",{"#f":1}],"fn_called":["ev","str","^nested function called","/str","/ev","~ret",{"#f":1}],"fn_echo":[{"temp=":"a"},"ev",{"VAR?":"a"},"out","/ev","\n","ev",{"VAR?":"a"},"/ev","~ret",{"#f":1}],"integration":[{"->":".^.variable_observer"},{"variable_observer":["^declared","\n","ev",3,"/ev",{"VAR=":"observedVar1","re":true},"^mutated 1","\n","ev",4,"/ev",{"VAR=":"observedVar1","re":true},"ev",5,"/ev",{"VAR=":"observedVar2","re":true},"^mutated 2","\n","done",{"#f":1}],"visit_count":["^visited","\n","done",{"#f":1}],"external":["ev",1,2,3,{"x()":"fn_ext","exArgs":3},"out","/ev","\n","ev",1.1,2.2,3.3,{"x()":"fn_ext","exArgs":3},"out","/ev","\n","ev","str","^a","/str","str","^b","/str","str","^c","/str",{"x()":"fn_ext","exArgs":3},"out","/ev","\n","ev","str","^a","/str",1,2.2,{"x()":"fn_ext","exArgs":3},"out","/ev","\n","done",{"#f":1}],"#f":1}],"topExternal":[{"temp=":"x"},"^In top external","\n","ev",{"VAR?":"x"},{"x()":"gameInc","exArgs":1},"/ev","~ret","\n",{"#f":1}],"inkInc":[{"temp=":"x"},"ev",{"VAR?":"x"},1,"+","/ev","~ret",{"#f":1}],"game_queries":[{"->":".^.choicecount"},{"choicecount":[[["ev",{"^->":"game_queries.choicecount.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^count ","ev","choiceCnt","out","/ev",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"game_queries.choicecount.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":[["ev",{"^->":"game_queries.choicecount.0.g-0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^1 choice",{"->":"$r","var":true},null]}],["ev",{"^->":"game_queries.choicecount.0.g-0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-2","flg":18},{"s":["^count ","ev","choiceCnt","out","/ev",{"->":"$r","var":true},null]}],{"c-1":["ev",{"^->":"game_queries.choicecount.0.g-0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-2":["ev",{"^->":"game_queries.choicecount.0.g-0.c-2.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-1"},{"#f":5}],"#f":5}],"g-1":[["ev",{"^->":"game_queries.choicecount.0.g-1.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-3","flg":18},{"s":["^1 choice",{"->":"$r","var":true},null]}],["ev",{"^->":"game_queries.choicecount.0.g-1.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-4","flg":18},{"s":["^2 choices",{"->":"$r","var":true},null]}],["ev",{"^->":"game_queries.choicecount.0.g-1.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-5","flg":18},{"s":["^count ","ev","choiceCnt","out","/ev",{"->":"$r","var":true},null]}],{"c-3":["ev",{"^->":"game_queries.choicecount.0.g-1.c-3.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-4":["ev",{"^->":"game_queries.choicecount.0.g-1.c-4.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-5":["ev",{"^->":"game_queries.choicecount.0.g-1.c-5.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-2"},{"#f":5}],"#f":5}],"g-2":[["ev",{"^->":"game_queries.choicecount.0.g-2.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-6","flg":18},{"s":["^1 choice",{"->":"$r","var":true},null]}],["ev",{"^->":"game_queries.choicecount.0.g-2.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-7","flg":18},{"s":["^count ","ev","choiceCnt","out","/ev",{"->":"$r","var":true},null]}],["ev",{"^->":"game_queries.choicecount.0.g-2.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-8","flg":18},{"s":["^2 choices",{"->":"$r","var":true},null]}],["ev",{"^->":"game_queries.choicecount.0.g-2.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-9","flg":18},{"s":["^count ","ev","choiceCnt","out","/ev",{"->":"$r","var":true},null]}],{"c-6":["ev",{"^->":"game_queries.choicecount.0.g-2.c-6.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-3"},{"#f":5}],"c-7":["ev",{"^->":"game_queries.choicecount.0.g-2.c-7.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-3"},{"#f":5}],"c-8":["ev",{"^->":"game_queries.choicecount.0.g-2.c-8.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-3"},{"#f":5}],"c-9":["ev",{"^->":"game_queries.choicecount.0.g-2.c-9.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-3"},{"#f":5}],"#f":5}],"g-3":["done",{"#f":5}]}],{"#f":1}],"turnssince_before":["ev",{"^->":"game_queries.turnssince"},"turns","out","/ev","\n",{"->":".^.^.turnssince"},{"#f":1}],"turnssince":[["ev",{"^->":"game_queries.turnssince"},"turns","out","/ev","\n","ev","str","^advance","/str","/ev",{"*":".^.c-0","flg":20},{"c-0":["^ ",{"->":".^.^.^.^.turnssince_1"},"\n",{"#f":5}]}],{"#f":3}],"turnssince_1":[["ev",{"^->":"game_queries.turnssince"},"turns","out","/ev","\n","ev","str","^advance","/str","/ev",{"*":".^.c-0","flg":20},{"c-0":["^ ",{"->":".^.^.^.^.turnssince_2"},"\n",{"#f":5}]}],{"#f":1}],"turnssince_2":["ev",{"^->":"game_queries.turnssince"},"turns","out","/ev","\n","done",{"#f":1}],"#f":1}],"saveload":["^a bit of content","\n","^the next bit","\n","done",{"choicepoint":[[["ev",{"^->":"saveload.choicepoint.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^choice 1",{"->":"$r","var":true},null]}],["ev",{"^->":"saveload.choicepoint.0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^choice 2",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"saveload.choicepoint.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"saveload.choicepoint.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["done",{"#f":5}]}],{"#f":1}],"#f":1}],"flow_control":[{"->":".^.tunnel"},{"tunnel":["^tunnel end","\n","ev","void","/ev","->->",{"#f":1}],"tunnel_call":[{"->t->":".^.^.tunnel"},"done",{"#f":1}],"thread":["^thread start","\n","thread",{"->":".^.^.threaded_text"},"thread",{"->":".^.^.threaded_choice_1"},"thread",{"->":".^.^.threaded_choice_2"},"^thread end","\n","done",{"#f":1}],"threaded_text":["^threaded text","\n","done",{"#f":1}],"threaded_choice_1":[[["ev",{"^->":"flow_control.threaded_choice_1.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^first threaded choice",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"flow_control.threaded_choice_1.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n","done",{"#f":5}]}],{"#f":1}],"threaded_choice_2":[[["ev",{"^->":"flow_control.threaded_choice_2.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^second threaded choice",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"flow_control.threaded_choice_2.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n","done",{"#f":5}]}],{"#f":1}],"#f":1}],"lists":[{"->":".^.basic_list"},{"basic_list":["ev",{"VAR?":"kettleState"},"out","/ev","\n","ev",{"VAR?":"boiling"},"/ev",{"VAR=":"kettleState","re":true},"ev",{"VAR?":"kettleState"},"out","/ev","\n","done",{"#f":1}],"increment":["ev",{"VAR?":"cold"},"/ev",{"VAR=":"kettleState","re":true},"ev",{"VAR?":"kettleState"},"out","/ev","\n","ev",{"VAR?":"kettleState"},1,"+",{"VAR=":"kettleState","re":true},"/ev","ev",{"VAR?":"kettleState"},"out","/ev","\n","ev",{"VAR?":"kettleState"},1,"+",{"VAR=":"kettleState","re":true},"/ev","ev",{"VAR?":"kettleState"},"out","/ev","\n","ev",{"VAR?":"kettleState"},1,"-",{"VAR=":"kettleState","re":true},"/ev","ev",{"VAR?":"kettleState"},"out","/ev","\n","ev",{"VAR?":"kettleState"},1,"-",{"VAR=":"kettleState","re":true},"/ev","ev",{"VAR?":"kettleState"},"out","/ev","\n","done",{"#f":1}],"list_value":["ev",{"VAR?":"cold"},"/ev",{"VAR=":"kettleState","re":true},"ev",{"VAR?":"kettleState"},"LIST_VALUE","out","/ev","\n","ev",{"VAR?":"kettleState"},1,"+",{"VAR=":"kettleState","re":true},"/ev","ev",{"VAR?":"kettleState"},"LIST_VALUE","out","/ev","\n","ev",{"VAR?":"kettleState"},1,"+",{"VAR=":"kettleState","re":true},"/ev","ev",{"VAR?":"kettleState"},"LIST_VALUE","out","/ev","\n","done",{"#f":1}],"value_from_number":["ev","^kettleState",1,"listInt","/ev",{"VAR=":"kettleStateVar","re":true},"\n","ev",{"VAR?":"kettleStateVar"},"out","/ev","\n","ev","^kettleState",2,"listInt","/ev",{"VAR=":"kettleStateVar","re":true},"\n","ev",{"VAR?":"kettleStateVar"},"out","/ev","\n","ev","^kettleState",3,"listInt","/ev",{"VAR=":"kettleStateVar","re":true},"\n","ev",{"VAR?":"kettleStateVar"},"out","/ev","\n","done",{"#f":1}],"defined_value":["ev",{"VAR?":"primeNumbers"},"LIST_VALUE","out","/ev","\n","ev",{"VAR?":"primeNumbers"},1,"+",{"VAR=":"primeNumbers","re":true},"/ev","ev",{"VAR?":"primeNumbers"},"LIST_VALUE","out","/ev","\n","ev",{"VAR?":"primeNumbers"},1,"+",{"VAR=":"primeNumbers","re":true},"/ev","ev",{"VAR?":"primeNumbers"},"LIST_VALUE","out","/ev","\n","done",{"#f":1}],"multivalue":["ev",{"VAR?":"DoctorsInSurgery"},"out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Denver":4}},"+",{"VAR=":"DoctorsInSurgery","re":true},"/ev","ev",{"VAR?":"DoctorsInSurgery"},"out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},{"VAR?":"Eamonn"},"-",{"VAR=":"DoctorsInSurgery","re":true},"/ev","ev",{"VAR?":"DoctorsInSurgery"},"out","/ev","\n","ev",{"list":{}},"/ev",{"VAR=":"DoctorsInSurgery","re":true},"ev",{"VAR?":"DoctorsInSurgery"},"out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},{"VAR?":"Eamonn"},"-",{"VAR=":"DoctorsInSurgery","re":true},"/ev","ev",{"VAR?":"DoctorsInSurgery"},{"VAR?":"Eamonn"},"-",{"VAR=":"DoctorsInSurgery","re":true},"/ev","ev",{"VAR?":"DoctorsInSurgery"},"out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},{"VAR?":"Eamonn"},"+",{"VAR=":"DoctorsInSurgery","re":true},"/ev","ev",{"VAR?":"DoctorsInSurgery"},{"VAR?":"Eamonn"},"+",{"VAR=":"DoctorsInSurgery","re":true},"/ev","ev",{"VAR?":"DoctorsInSurgery"},"out","/ev","\n","done",{"#f":1}],"listqueries":["ev",{"list":{}},"/ev",{"VAR=":"DoctorsInSurgery","re":true},"ev",{"VAR?":"DoctorsInSurgery"},"/ev",[{"->":".^.b","c":true},{"b":["^list is not empty ",{"->":".^.^.^.9"},null]}],[{"->":".^.b"},{"b":["^list is empty",{"->":".^.^.^.9"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Denver":4}},"+",{"VAR=":"DoctorsInSurgery","re":true},"/ev","ev",{"VAR?":"DoctorsInSurgery"},"LIST_COUNT","out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},"LIST_MIN","out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},"LIST_MAX","out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},"/ev",[{"->":".^.b","c":true},{"b":["^list is not empty",{"->":".^.^.^.40"},null]}],[{"->":".^.b"},{"b":["^list is empty",{"->":".^.^.^.40"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Denver":4}},"==","/ev",[{"->":".^.b","c":true},{"b":["^exact equality",{"->":".^.^.^.48"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5}},"==","/ev",[{"->":".^.b","c":true},{"b":["^exact equality broken",{"->":".^.^.^.57"},null]}],[{"->":".^.b"},{"b":["^falsy exact equality",{"->":".^.^.^.57"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5}},"!=","/ev",[{"->":".^.b","c":true},{"b":["^exact inequality",{"->":".^.^.^.65"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Denver":4}},"!=","/ev",[{"->":".^.b","c":true},{"b":["^exact inequality broken",{"->":".^.^.^.74"},null]}],[{"->":".^.b"},{"b":["^exact inequality works",{"->":".^.^.^.74"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"VAR?":"Eamonn"},"?","/ev",[{"->":".^.b","c":true},{"b":["^has Eamonn",{"->":".^.^.^.82"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"VAR?":"Cartwright"},"?","/ev",[{"->":".^.b","c":true},{"b":["^has is broke ",{"->":".^.^.^.91"},null]}],[{"->":".^.b"},{"b":["^has falsy works",{"->":".^.^.^.91"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Cartwright":3}},"!?","/ev",[{"->":".^.b","c":true},{"b":["^has not",{"->":".^.^.^.99"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Denver":4}},"!?","/ev",[{"->":".^.b","c":true},{"b":["^has not broken",{"->":".^.^.^.108"},null]}],[{"->":".^.b"},{"b":["^falsy has not",{"->":".^.^.^.108"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},"LIST_ALL","out","/ev","\n","ev",{"list":{}},"/ev",{"VAR=":"DoctorsInSurgery","re":true},"ev",{"VAR?":"DoctorsInSurgery"},"LIST_MAX","out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},"LIST_MIN","out","/ev","\n","ev",{"list":{"DoctorsInSurgery.Cartwright":3}},"/ev",{"VAR=":"DoctorsInSurgery","re":true},"ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Adams":1}},">","/ev",[{"->":".^.b","c":true},{"b":["^truthy greater than",{"->":".^.^.^.142"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5}},">","/ev",[{"->":".^.b","c":true},{"b":["^broken greater than",{"->":".^.^.^.151"},null]}],[{"->":".^.b"},{"b":["^falsy greater than",{"->":".^.^.^.151"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{}},">","/ev",[{"->":".^.b","c":true},{"b":["^greater than empty",{"->":".^.^.^.159"},null]}],"nop","\n","ev",{"list":{}},{"VAR?":"DoctorsInSurgery"},">","/ev",[{"->":".^.b","c":true},{"b":["^broken empty greater than",{"->":".^.^.^.168"},null]}],[{"->":".^.b"},{"b":["^empty greater than",{"->":".^.^.^.168"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5}},"<","/ev",[{"->":".^.b","c":true},{"b":["^truthy smaller than",{"->":".^.^.^.176"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Adams":1}},"<","/ev",[{"->":".^.b","c":true},{"b":["^broken smaller than",{"->":".^.^.^.185"},null]}],[{"->":".^.b"},{"b":["^falsy smaller than",{"->":".^.^.^.185"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{}},"<","/ev",[{"->":".^.b","c":true},{"b":["^broken smaller than empty",{"->":".^.^.^.194"},null]}],[{"->":".^.b"},{"b":["^smaller than empty",{"->":".^.^.^.194"},null]}],"nop","\n","ev",{"list":{}},{"VAR?":"DoctorsInSurgery"},"<","/ev",[{"->":".^.b","c":true},{"b":["^empty smaller than",{"->":".^.^.^.203"},null]}],[{"->":".^.b"},{"b":["^broken empty smaller than",{"->":".^.^.^.203"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Adams":1}},">=","/ev",[{"->":".^.b","c":true},{"b":["^truthy greater than or equal",{"->":".^.^.^.211"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Cartwright":3}},">=","/ev",[{"->":".^.b","c":true},{"b":["^truthy greater than or equal",{"->":".^.^.^.219"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5}},">=","/ev",[{"->":".^.b","c":true},{"b":["^broken greater than or equal",{"->":".^.^.^.228"},null]}],[{"->":".^.b"},{"b":["^falsy greater than or equal",{"->":".^.^.^.228"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{}},">=","/ev",[{"->":".^.b","c":true},{"b":["^greater than or equals empty",{"->":".^.^.^.236"},null]}],"nop","\n","ev",{"list":{}},{"VAR?":"DoctorsInSurgery"},">=","/ev",[{"->":".^.b","c":true},{"b":["^broken empty greater than or equals",{"->":".^.^.^.245"},null]}],[{"->":".^.b"},{"b":["^empty greater than or equals",{"->":".^.^.^.245"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5}},"<=","/ev",[{"->":".^.b","c":true},{"b":["^truthy smaller than or equal",{"->":".^.^.^.253"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Cartwright":3}},"<=","/ev",[{"->":".^.b","c":true},{"b":["^truthy smaller than or equal",{"->":".^.^.^.261"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Adams":1}},"<=","/ev",[{"->":".^.b","c":true},{"b":["^broken smaller than or equal",{"->":".^.^.^.270"},null]}],[{"->":".^.b"},{"b":["^falsy smaller than or equal",{"->":".^.^.^.270"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{}},"<=","/ev",[{"->":".^.b","c":true},{"b":["^broken smaller than or equals empty",{"->":".^.^.^.279"},null]}],[{"->":".^.b"},{"b":["^smaller than or equals empty",{"->":".^.^.^.279"},null]}],"nop","\n","ev",{"list":{}},{"VAR?":"DoctorsInSurgery"},"<=","/ev",[{"->":".^.b","c":true},{"b":["^empty smaller than or equals",{"->":".^.^.^.288"},null]}],[{"->":".^.b"},{"b":["^broken empty smaller than or equals",{"->":".^.^.^.288"},null]}],"nop","\n","ev",{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Cartwright":3}},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Cartwright":3}},"&&","/ev",[{"->":".^.b","c":true},{"b":["^truthy list AND",{"->":".^.^.^.297"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.297"},null]}],"nop","\n","ev",{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Cartwright":3}},{"list":{}},"&&","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.306"},null]}],[{"->":".^.b"},{"b":["^falsy list AND",{"->":".^.^.^.306"},null]}],"nop","\n","ev",{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Cartwright":3}},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Cartwright":3}},"||","/ev",[{"->":".^.b","c":true},{"b":["^truthy list OR",{"->":".^.^.^.315"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.315"},null]}],"nop","\n","ev",{"list":{}},{"list":{}},"||","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.324"},null]}],[{"->":".^.b"},{"b":["^falsy list OR",{"->":".^.^.^.324"},null]}],"nop","\n","ev",{"list":{}},"!","/ev",[{"->":".^.b","c":true},{"b":["^truthy list not",{"->":".^.^.^.332"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.332"},null]}],"nop","\n","ev",{"list":{"DoctorsInSurgery.Eamonn":5}},"!","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.340"},null]}],[{"->":".^.b"},{"b":["^falsy list not",{"->":".^.^.^.340"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},"LIST_ALL",{"VAR?":"Bernard"},{"VAR?":"Denver"},"range","out","/ev","\n","ev",{"VAR?":"GuardsOnDuty"},"out","/ev","\n","ev",{"VAR?":"GuardsOnDuty"},"LIST_INVERT","/ev",{"VAR=":"GuardsOnDuty","re":true},"\n","ev",{"VAR?":"GuardsOnDuty"},"out","/ev","\n","ev",{"VAR?":"desiredValues"},{"VAR?":"actualValues"},"L^","out","/ev","\n","done",{"#f":1}],"#f":1}],"global decl":["ev","str","^Emilia","/str",{"VAR=":"stringvar"},521,{"VAR=":"intvar"},52.1,{"VAR=":"floatvar"},{"^->":"logic.logic_divert_dest"},{"VAR=":"divertvar"},"str","^a","/str",{"VAR=":"fnParamA"},"str","^b","/str",{"VAR=":"fnParamB"},1,{"VAR=":"observedVar1"},2,{"VAR=":"observedVar2"},{"list":{"kettleState.cold":1}},{"VAR=":"kettleState"},{"VAR?":"cold"},{"VAR=":"kettleStateVar"},{"list":{"primeNumbers.two":2}},{"VAR=":"primeNumbers"},{"list":{},"origins":["DoctorsInSurgery"]},{"VAR=":"DoctorsInSurgery"},{"list":{"GuardsOnDuty.Smith":1,"GuardsOnDuty.Jones":2}},{"VAR=":"GuardsOnDuty"},{"list":{},"origins":["CoreValues"]},{"VAR=":"CoreValues"},{"list":{"CoreValues.strength":1,"CoreValues.courage":2,"CoreValues.compassion":3,"CoreValues.self_belief":6}},{"VAR=":"desiredValues"},{"list":{"CoreValues.greed":4,"CoreValues.nepotism":5,"CoreValues.self_belief":6,"CoreValues.delusions_of_godhood":7}},{"VAR=":"actualValues"},"/ev","end",null],"#f":1}],"listDefs":{"kettleState":{"cold":1,"boiling":2,"evaporated":3},"primeNumbers":{"two":2,"three":3,"five":5},"DoctorsInSurgery":{"Adams":1,"Bernard":2,"Cartwright":3,"Denver":4,"Eamonn":5},"GuardsOnDuty":{"Smith":1,"Jones":2,"Carter":3,"Braithwaite":4},"CoreValues":{"strength":1,"courage":2,"compassion":3,"greed":4,"nepotism":5,"self_belief":6,"delusions_of_godhood":7}}} \ No newline at end of file +{"inkVersion":21,"root":[["#","^global tag","/#",{"->":"glue.diverted_glue"},"^Ouside content","\n","#","^not a global tag","/#",["done",{"#f":5,"#n":"g-0"}],null],"done",{"fn_ext":[{"temp=":"c"},{"temp=":"b"},{"temp=":"a"},"ev",{"VAR?":"a"},"/ev","~ret",{"#f":1}],"gameInc":[{"temp=":"x"},"ev",{"VAR?":"x"},1,"+","/ev","~ret",{"#f":1}],"knot":["^Knot content","\n","done",{"stitch":["^Stitch content","\n","done",{"#f":1}],"#f":1}],"content":[{"->":".^.simple"},{"simple":["^Simple content inside a knot","\n","done",{"#f":1}],"multiline":["^First line","\n","^Second line","\n","done",{"#f":1}],"variable_text":["ev","str","^variable text","/str","/ev",{"temp=":"VARIABLETEXT"},"ev",{"VAR?":"VARIABLETEXT"},"out","/ev","\n","done",{"#f":1}],"if_text_truthy":["ev",true,"/ev",{"temp=":"met_blofeld"},"^I… ","ev",{"VAR?":"met_blofeld"},"/ev",[{"->":".^.b","c":true},{"b":["^ I saw him. Only for a moment.",{"->":".^.^.^.9"},null]}],"nop","\n","done",{"#f":1}],"if_text_falsy":["ev",false,"/ev",{"temp=":"met_blofeld"},"^I… ","ev",{"VAR?":"met_blofeld"},"/ev",[{"->":".^.b","c":true},{"b":["^ I saw him. Only for a moment.",{"->":".^.^.^.9"},null]}],"nop","\n","done",{"#f":1}],"if_else_text":["ev",true,"/ev",{"temp=":"met_blofeld"},"ev",{"VAR?":"met_blofeld"},"/ev",[{"->":".^.b","c":true},{"b":["^ I saw him. Only for a moment.",{"->":".^.^.^.9"},null]}],[{"->":".^.b"},{"b":["^I missed him. Was he particularly evil?",{"->":".^.^.^.9"},null]}],"nop","\n","ev",false,"/ev",{"temp=":"met_blofeld","re":true},"ev",{"VAR?":"met_blofeld"},"/ev",[{"->":".^.b","c":true},{"b":["^ I saw him. Only for a moment.",{"->":".^.^.^.20"},null]}],[{"->":".^.b"},{"b":["^I missed him. Was he particularly evil?",{"->":".^.^.^.20"},null]}],"nop","\n","done",{"#f":1}],"#f":1}],"glue":[{"->":".^.simple"},{"simple":["^Simple ","<>","\n","^glue","\n","done",{"#f":1}],"diverted_glue":["^More ","<>",{"->":"glue.diverted_glue_target"},"\n",{"#f":1}],"diverted_glue_target":["^glue","\n","done",{"#f":1}],"#f":1}],"divert":[{"->":".^.divert_knot"},{"divert_knot":[{"->":"divert_knot_target"},{"#f":1}],"divert_stitch":[{"->":"divert_knot_target.divert_stitch_target"},{"#f":1}],"internal_stitch":[{"->":".^.^.internal_stitch_target"},{"#f":1}],"divert_var":["ev",{"^->":"divert_knot_target.divert_var_target"},"/ev",{"temp=":"destination"},{"->":"destination","var":true},{"#f":1}],"internal_stitch_target":["^Diverted to internal stitch","\n","done",{"#f":1}],"#f":1}],"divert_knot_target":["^Diverted to a knot","\n","done",{"divert_stitch_target":["^Diverted to a stitch","\n","done",{"#f":1}],"divert_var_target":["^Diverted with a variable","\n","done",{"#f":3}],"#f":1}],"tags":["#","^knot tag","/#","done",{"line_by_Line":["^A line of content ","#","^a tag","/#","\n","^Another line of content ","#","^tag1 ","/#","#","^tag2","/#","\n","#","^tag above","/#","^Content after a tag ","#","^tag after","/#","\n","#","^tag below","/#","done",{"#f":1}],"choice":[[["ev",{"^->":"tags.choice.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^a choice ","#","^a tag",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"tags.choice.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"/#out","\n","done",{"#f":5}]}],{"#f":1}],"weird":["#","^space around","/#","#","/#","#","/#","#","/#","#","^0","/#","done",{"#f":1}],"#f":1}],"simple_lists":[{"->":".^.sequence"},{"sequence":[["ev","visit",3,"MIN","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"ev","du",2,"==","/ev",{"->":".^.s2","c":true},"ev","du",3,"==","/ev",{"->":".^.s3","c":true},"nop",{"s0":["pop","^one",{"->":".^.^.29"},null],"s1":["pop","^two",{"->":".^.^.29"},null],"s2":["pop","^three",{"->":".^.^.29"},null],"s3":["pop","^final",{"->":".^.^.29"},null],"#f":5}],"\n","done",{"#f":1}],"cycle":[["ev","visit",3,"%","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"ev","du",2,"==","/ev",{"->":".^.s2","c":true},"nop",{"s0":["pop","^one",{"->":".^.^.23"},null],"s1":["pop","^two",{"->":".^.^.23"},null],"s2":["pop","^three",{"->":".^.^.23"},null],"#f":5}],"\n","done",{"#f":1}],"once":[["ev","visit",3,"MIN","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"ev","du",2,"==","/ev",{"->":".^.s2","c":true},"ev","du",3,"==","/ev",{"->":".^.s3","c":true},"nop",{"s0":["pop","^one",{"->":".^.^.29"},null],"s1":["pop","^two",{"->":".^.^.29"},null],"s2":["pop","^three",{"->":".^.^.29"},null],"s3":["pop",{"->":".^.^.29"},null],"#f":5}],"\n","done",{"#f":1}],"shuffle":[["ev","visit",2,"seq","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"nop",{"s0":["pop","^heads",{"->":".^.^.17"},null],"s1":["pop","^tails",{"->":".^.^.17"},null],"#f":5}],"\n","done",{"#f":1}],"blanks":[["ev","visit",3,"MIN","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"ev","du",2,"==","/ev",{"->":".^.s2","c":true},"ev","du",3,"==","/ev",{"->":".^.s3","c":true},"nop",{"s0":["pop",{"->":".^.^.29"},null],"s1":["pop",{"->":".^.^.29"},null],"s2":["pop",{"->":".^.^.29"},null],"s3":["pop","^end",{"->":".^.^.29"},null],"#f":5}],"\n","done",{"#f":1}],"#f":1}],"choices":[{"->":".^.basic_choice"},{"basic_choice":[[["ev",{"^->":"choices.basic_choice.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^a choice",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"choices.basic_choice.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n","done",{"#f":5}]}],{"#f":1}],"multiple_choices":[[["ev",{"^->":"choices.multiple_choices.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^choice 1",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.multiple_choices.0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^choice 2",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.multiple_choices.0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-2","flg":18},{"s":["^choice 3",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"choices.multiple_choices.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"choices.multiple_choices.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-2":["ev",{"^->":"choices.multiple_choices.0.c-2.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["done",{"#f":5}]}],{"#f":1}],"choice_text":[[["ev",{"^->":"choices.choice_text.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","str","^choice only","/str","/ev",{"*":".^.^.c-0","flg":22},{"s":["^always ",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"choices.choice_text.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"^output only","\n","done",{"#f":5}]}],{"#f":1}],"suppression":[[["ev",{"^->":"choices.suppression.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^choice 1",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.suppression.0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^choice 2",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"choices.suppression.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"choices.suppression.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["done",{"#f":5}]}],{"#f":1}],"fallback":[[["ev",{"^->":"choices.fallback.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^choice 1",{"->":"$r","var":true},null]}],{"*":".^.c-1","flg":24},{"c-0":["ev",{"^->":"choices.fallback.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n","done",{"#f":5}],"c-1":["done","\n",{"#f":5}]}],{"#f":1}],"sticky":[[["ev",{"^->":"choices.sticky.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^disapears",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.sticky.0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":2},{"s":["^stays",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"choices.sticky.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n","done",{"#f":5}],"c-1":["ev",{"^->":"choices.sticky.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","done",{"#f":5}]}],{"#f":1}],"conditional":[["ev",true,"/ev",{"temp=":"truthy"},"ev",true,"/ev",{"temp=":"truthy2"},"ev",false,"/ev",{"temp=":"falsy"},["ev",{"^->":"choices.conditional.0.12.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^no condition",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.conditional.0.13.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str",{"VAR?":"truthy"},"/ev",{"*":".^.^.c-1","flg":19},{"s":["^available",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.conditional.0.14.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str",{"VAR?":"falsy"},"/ev",{"*":".^.^.c-2","flg":19},{"s":["^not available",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.conditional.0.15.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str",{"VAR?":"truthy"},{"VAR?":"truthy2"},"&&","/ev",{"*":".^.^.c-3","flg":19},{"s":["^multi condition available",{"->":"$r","var":true},null]}],["ev",{"^->":"choices.conditional.0.16.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str",{"VAR?":"truthy"},{"VAR?":"falsy"},"&&","/ev",{"*":".^.^.c-4","flg":19},{"s":["^multi condition not available",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"choices.conditional.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.12.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"choices.conditional.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.13.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-2":["ev",{"^->":"choices.conditional.0.c-2.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.14.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-3":["ev",{"^->":"choices.conditional.0.c-3.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.15.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-4":["ev",{"^->":"choices.conditional.0.c-4.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.16.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["done",{"#f":5}]}],{"#f":1}],"#f":1}],"logic":[{"->":".^.vardef"},{"vardef":["^variables defined: ","ev","str","^Emilia","/str","out","/ev","^ ","ev",521,"out","/ev","^ ","ev",52.1,"out","/ev","\n","done",{"#f":1}],"casts":["ev",{"VAR?":"intvar"},0.5,"+","out","/ev","\n","ev",{"VAR?":"intvar"},"str","^hello","/str","+","out","/ev","\n","ev",{"VAR?":"floatvar"},"/ev",[{"->":".^.b","c":true},{"b":["^float var is truthy",{"->":".^.^.^.21"},null]}],[{"->":".^.b"},{"b":["^is falsy and broken",{"->":".^.^.^.21"},null]}],"nop","\n","ev",{"VAR?":"floatvar"},"str","^hello","/str","+","out","/ev","\n","ev",{"VAR?":"stringvar"},"/ev",[{"->":".^.b","c":true},{"b":["^string var is truthy",{"->":".^.^.^.37"},null]}],[{"->":".^.b"},{"b":["^is falsy and broken",{"->":".^.^.^.37"},null]}],"nop","\n","done",{"#f":1}],"logic_divert_dest":["done",{"#f":3}],"math":["ev",5,"/ev",{"temp=":"int"},"ev",1,1,"+","out","/ev","\n","ev",1,1,"-","out","/ev","\n","ev",{"VAR?":"int"},"_","out","/ev","\n","ev",1,2,"*","out","/ev","\n","ev",10,2,"/","out","/ev","\n","ev",11,2,"%","out","/ev","\n","ev",1,1,"==","/ev",[{"->":".^.b","c":true},{"b":["^int truthy equal",{"->":".^.^.^.52"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.52"},null]}],"nop","\n","ev",1,2,"==","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.61"},null]}],[{"->":".^.b"},{"b":["^int falsy equal",{"->":".^.^.^.61"},null]}],"nop","\n","ev",2,1,">","/ev",[{"->":".^.b","c":true},{"b":["^int truthy greater",{"->":".^.^.^.70"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.70"},null]}],"nop","\n","ev",1,2,">","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.79"},null]}],[{"->":".^.b"},{"b":["^int falsy greater",{"->":".^.^.^.79"},null]}],"nop","\n","ev",1,2,"<","/ev",[{"->":".^.b","c":true},{"b":["^int truthy lesser",{"->":".^.^.^.88"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.88"},null]}],"nop","\n","ev",2,1,"<","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.97"},null]}],[{"->":".^.b"},{"b":["^int falsy lesser",{"->":".^.^.^.97"},null]}],"nop","\n","ev",2,1,">=","/ev",[{"->":".^.b","c":true},{"b":["^int truthy greater or equal",{"->":".^.^.^.106"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.106"},null]}],"nop","\n","ev",1,2,">=","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.115"},null]}],[{"->":".^.b"},{"b":["^int falsy greater or equal",{"->":".^.^.^.115"},null]}],"nop","\n","ev",1,2,"<=","/ev",[{"->":".^.b","c":true},{"b":["^int truthy lesser or equal",{"->":".^.^.^.124"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.124"},null]}],"nop","\n","ev",2,1,"<=","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.133"},null]}],[{"->":".^.b"},{"b":["^int falsy lesser or equal",{"->":".^.^.^.133"},null]}],"nop","\n","ev",2,1,"!=","/ev",[{"->":".^.b","c":true},{"b":["^int truthy not equal",{"->":".^.^.^.142"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.142"},null]}],"nop","\n","ev",1,1,"!=","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.151"},null]}],[{"->":".^.b"},{"b":["^int falsy not equal",{"->":".^.^.^.151"},null]}],"nop","\n","ev",1,"/ev",{"temp=":"one"},"ev",0,"/ev",{"temp=":"zero"},["ev",{"VAR?":"zero"},"!","/ev",{"->":".^.b","c":true},{"b":["\n","^int truthy not","\n",{"->":".^.^.^.163"},null]}],[{"->":".^.b"},{"b":["\n","^broken","\n",{"->":".^.^.^.163"},null]}],"nop","\n",["ev",{"VAR?":"one"},"!","/ev",{"->":".^.b","c":true},{"b":["\n","^broken","\n",{"->":".^.^.^.167"},null]}],[{"->":".^.b"},{"b":["\n","^int falsy not","\n",{"->":".^.^.^.167"},null]}],"nop","\n","ev",1,1,"&&","/ev",[{"->":".^.b","c":true},{"b":["^int truthy and",{"->":".^.^.^.176"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.176"},null]}],"nop","\n","ev",1,0,"&&","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.185"},null]}],[{"->":".^.b"},{"b":["^int falsy and",{"->":".^.^.^.185"},null]}],"nop","\n","ev",1,0,"||","/ev",[{"->":".^.b","c":true},{"b":["^int truthy or",{"->":".^.^.^.194"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.194"},null]}],"nop","\n","ev",0,0,"||","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.203"},null]}],[{"->":".^.b"},{"b":["^int falsy or",{"->":".^.^.^.203"},null]}],"nop","\n","ev",5.2,"/ev",{"temp=":"float"},"ev",1.3,1.3,"+","out","/ev","\n","ev",1.3,1.3,"-","out","/ev","\n","ev",{"VAR?":"float"},"_","out","/ev","\n","ev",1.5,2.4,"*","out","/ev","\n","ev",10.5,2.5,"/","out","/ev","\n","ev",11.5,2.5,"%","out","/ev","\n","ev",1.3,1.3,"==","/ev",[{"->":".^.b","c":true},{"b":["^float truthy equal",{"->":".^.^.^.257"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.257"},null]}],"nop","\n","ev",1.3,2.3,"==","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.266"},null]}],[{"->":".^.b"},{"b":["^float falsy equal",{"->":".^.^.^.266"},null]}],"nop","\n","ev",2.3,1.3,">","/ev",[{"->":".^.b","c":true},{"b":["^float truthy greater",{"->":".^.^.^.275"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.275"},null]}],"nop","\n","ev",1.3,2.3,">","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.284"},null]}],[{"->":".^.b"},{"b":["^float falsy greater",{"->":".^.^.^.284"},null]}],"nop","\n","ev",1.3,2.3,"<","/ev",[{"->":".^.b","c":true},{"b":["^float truthy lesser",{"->":".^.^.^.293"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.293"},null]}],"nop","\n","ev",2.3,1.3,"<","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.302"},null]}],[{"->":".^.b"},{"b":["^float falsy lesser",{"->":".^.^.^.302"},null]}],"nop","\n","ev",2.3,1.3,">=","/ev",[{"->":".^.b","c":true},{"b":["^float truthy greater or equal",{"->":".^.^.^.311"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.311"},null]}],"nop","\n","ev",1.3,2.3,">=","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.320"},null]}],[{"->":".^.b"},{"b":["^float falsy greater or equal",{"->":".^.^.^.320"},null]}],"nop","\n","ev",1.3,2.3,"<=","/ev",[{"->":".^.b","c":true},{"b":["^float truthy lesser or equal",{"->":".^.^.^.329"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.329"},null]}],"nop","\n","ev",2.3,1.3,"<=","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.338"},null]}],[{"->":".^.b"},{"b":["^float falsy lesser or equal",{"->":".^.^.^.338"},null]}],"nop","\n","ev",2.3,1.3,"!=","/ev",[{"->":".^.b","c":true},{"b":["^float truthy not equal",{"->":".^.^.^.347"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.347"},null]}],"nop","\n","ev",1.3,1.3,"!=","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.356"},null]}],[{"->":".^.b"},{"b":["^float falsy not equal",{"->":".^.^.^.356"},null]}],"nop","\n","ev",1.2,"/ev",{"temp=":"onepointtwo"},["ev",{"VAR?":"onepointtwo"},"!","/ev",{"->":".^.b","c":true},{"b":["\n","^broken","\n",{"->":".^.^.^.364"},null]}],[{"->":".^.b"},{"b":["\n","^float falsy not","\n",{"->":".^.^.^.364"},null]}],"nop","\n","ev",1.3,1.3,"&&","/ev",[{"->":".^.b","c":true},{"b":["^float truthy and",{"->":".^.^.^.373"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.373"},null]}],"nop","\n","ev",1.3,0,"&&","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.382"},null]}],[{"->":".^.b"},{"b":["^float falsy and",{"->":".^.^.^.382"},null]}],"nop","\n","ev",1.3,0,"||","/ev",[{"->":".^.b","c":true},{"b":["^float truthy or",{"->":".^.^.^.391"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.391"},null]}],"nop","\n","ev",0,0,"||","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.400"},null]}],[{"->":".^.b"},{"b":["^float falsy or",{"->":".^.^.^.400"},null]}],"nop","\n","ev","str","^hello","/str","str","^hello","/str","==","/ev",[{"->":".^.b","c":true},{"b":["^truthy string equal",{"->":".^.^.^.413"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.413"},null]}],"nop","\n","ev","str","^hello","/str","str","^world","/str","==","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.426"},null]}],[{"->":".^.b"},{"b":["^falsy string equal",{"->":".^.^.^.426"},null]}],"nop","\n","ev","str","^hello","/str","str","^world","/str","!=","/ev",[{"->":".^.b","c":true},{"b":["^truthy string not equal",{"->":".^.^.^.439"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.439"},null]}],"nop","\n","ev","str","^hello","/str","str","^hello","/str","!=","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.452"},null]}],[{"->":".^.b"},{"b":["^falsy string not equal",{"->":".^.^.^.452"},null]}],"nop","\n","ev",{"^->":"logic.ifelse"},{"^->":"logic.ifelse"},"==","/ev",[{"->":".^.b","c":true},{"b":["^truthy divert equal",{"->":".^.^.^.461"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.461"},null]}],"nop","\n","ev",{"^->":"logic.ifelse"},{"^->":"logic.stitch_param"},"==","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.470"},null]}],[{"->":".^.b"},{"b":["^falsy divert equal",{"->":".^.^.^.470"},null]}],"nop","\n","done",{"#f":1}],"ifelse":[["ev",{"VAR?":"intvar"},521,"==","/ev",{"->":".^.b","c":true},{"b":["\n","^if text","\n",{"->":".^.^.^.2"},null]}],[{"->":".^.b"},{"b":["\n","^else text","\n",{"->":".^.^.^.2"},null]}],"nop","\n",["ev",{"VAR?":"intvar"},521,"<","/ev",{"->":".^.b","c":true},{"b":["\n","^if text","\n",{"->":".^.^.^.6"},null]}],[{"->":".^.b"},{"b":["\n","^else text","\n",{"->":".^.^.^.6"},null]}],"nop","\n",["ev",{"VAR?":"intvar"},521,"<","/ev",{"->":".^.b","c":true},{"b":["\n","^if text","\n",{"->":".^.^.^.11"},null]}],["ev",{"VAR?":"intvar"},1,">","/ev",{"->":".^.b","c":true},{"b":["\n","^elseif text","\n",{"->":".^.^.^.11"},null]}],[{"->":".^.b"},{"b":["\n","^else text","\n",{"->":".^.^.^.11"},null]}],"nop","\n","done",{"#f":3}],"stitch_param":["ev","str","^param","/str","/ev",{"->":".^.^.stitch_with_param"},"done",{"#f":3}],"stitch_with_param":[{"temp=":"what"},"^Called with ","ev",{"VAR?":"what"},"out","/ev","\n","done",{"#f":1}],"constants":["^constants defined: ","ev","str","^Emilia","/str","out","/ev","^ ","ev",521,"out","/ev","^ ","ev",52.1,"out","/ev","\n","done",{"#f":1}],"simple_functions":["ev",{"f()":"fn_with_return"},"out","/ev","\n","ev",{"f()":"fn_print"},"out","/ev","\n","ev",{"f()":"fn_calls_other"},"out","/ev","\n","^Function called inline and ","ev",{"f()":"fn_with_return"},"out","/ev","^ something","\n","done",{"#f":1}],"param_functions":["ev",{"VAR?":"fnParamA"},{"VAR?":"fnParamB"},{"f()":"fn_params"},"out","/ev","\n","ev",{"^var":"fnParamA","ci":-1},{"^var":"fnParamB","ci":-1},{"f()":"fn_params_ref"},"out","/ev","\n","done",{"#f":1}],"void_function":["ev",{"f()":"fn_without_return"},"out","/ev","\n","done",{"#f":1}],"random":["ev",25,"srnd","pop","/ev","\n","ev",0,100,"rnd","out","/ev","\n","ev",-50,50,"rnd","out","/ev","\n","done",{"#f":1}],"#f":1}],"fn_with_return":["ev","str","^returned","/str","/ev","~ret",{"#f":1}],"fn_without_return":["ev",1,"/ev",{"temp=":"a"},{"#f":1}],"fn_print":["^function called","\n",{"#f":1}],"fn_params":[{"temp=":"b"},{"temp=":"a"},"ev","str","^was a","/str","/ev",{"temp=":"a","re":true},"ev","str","^was b","/str","/ev",{"temp=":"b","re":true},"ev",{"VAR?":"a"},"/ev","~ret",{"#f":1}],"fn_params_ref":[{"temp=":"b"},{"temp=":"a"},"ev","str","^was a","/str","/ev",{"temp=":"a","re":true},"ev","str","^was b","/str","/ev",{"temp=":"b","re":true},"ev",{"VAR?":"a"},"/ev","~ret",{"#f":1}],"fn_calls_other":["ev",{"f()":"fn_called"},"/ev","~ret","\n",{"#f":1}],"fn_called":["ev","str","^nested function called","/str","/ev","~ret",{"#f":1}],"fn_echo":[{"temp=":"a"},"ev",{"VAR?":"a"},"out","/ev","\n","ev",{"VAR?":"a"},"/ev","~ret",{"#f":1}],"integration":[{"->":".^.variable_observer"},{"variable_observer":["^declared","\n","ev",3,"/ev",{"VAR=":"observedVar1","re":true},"^mutated 1","\n","ev",4,"/ev",{"VAR=":"observedVar1","re":true},"ev",5,"/ev",{"VAR=":"observedVar2","re":true},"^mutated 2","\n","done",{"#f":1}],"visit_count":["^visited","\n","done",{"#f":1}],"external":["ev",1,2,3,{"x()":"fn_ext","exArgs":3},"out","/ev","\n","ev",1.1,2.2,3.3,{"x()":"fn_ext","exArgs":3},"out","/ev","\n","ev","str","^a","/str","str","^b","/str","str","^c","/str",{"x()":"fn_ext","exArgs":3},"out","/ev","\n","ev","str","^a","/str",1,2.2,{"x()":"fn_ext","exArgs":3},"out","/ev","\n","done",{"#f":1}],"#f":1}],"topExternal":[{"temp=":"x"},"^In top external","\n","ev",{"VAR?":"x"},{"x()":"gameInc","exArgs":1},"/ev","~ret","\n",{"#f":1}],"inkInc":[{"temp=":"x"},"ev",{"VAR?":"x"},1,"+","/ev","~ret",{"#f":1}],"game_queries":[{"->":".^.choicecount"},{"choicecount":[[["ev",{"^->":"game_queries.choicecount.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^count ","ev","choiceCnt","out","/ev",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"game_queries.choicecount.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":[["ev",{"^->":"game_queries.choicecount.0.g-0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^1 choice",{"->":"$r","var":true},null]}],["ev",{"^->":"game_queries.choicecount.0.g-0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-2","flg":18},{"s":["^count ","ev","choiceCnt","out","/ev",{"->":"$r","var":true},null]}],{"c-1":["ev",{"^->":"game_queries.choicecount.0.g-0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-2":["ev",{"^->":"game_queries.choicecount.0.g-0.c-2.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-1"},{"#f":5}],"#f":5}],"g-1":[["ev",{"^->":"game_queries.choicecount.0.g-1.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-3","flg":18},{"s":["^1 choice",{"->":"$r","var":true},null]}],["ev",{"^->":"game_queries.choicecount.0.g-1.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-4","flg":18},{"s":["^2 choices",{"->":"$r","var":true},null]}],["ev",{"^->":"game_queries.choicecount.0.g-1.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-5","flg":18},{"s":["^count ","ev","choiceCnt","out","/ev",{"->":"$r","var":true},null]}],{"c-3":["ev",{"^->":"game_queries.choicecount.0.g-1.c-3.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-4":["ev",{"^->":"game_queries.choicecount.0.g-1.c-4.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-5":["ev",{"^->":"game_queries.choicecount.0.g-1.c-5.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-2"},{"#f":5}],"#f":5}],"g-2":[["ev",{"^->":"game_queries.choicecount.0.g-2.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-6","flg":18},{"s":["^1 choice",{"->":"$r","var":true},null]}],["ev",{"^->":"game_queries.choicecount.0.g-2.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-7","flg":18},{"s":["^count ","ev","choiceCnt","out","/ev",{"->":"$r","var":true},null]}],["ev",{"^->":"game_queries.choicecount.0.g-2.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-8","flg":18},{"s":["^2 choices",{"->":"$r","var":true},null]}],["ev",{"^->":"game_queries.choicecount.0.g-2.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-9","flg":18},{"s":["^count ","ev","choiceCnt","out","/ev",{"->":"$r","var":true},null]}],{"c-6":["ev",{"^->":"game_queries.choicecount.0.g-2.c-6.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-3"},{"#f":5}],"c-7":["ev",{"^->":"game_queries.choicecount.0.g-2.c-7.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-3"},{"#f":5}],"c-8":["ev",{"^->":"game_queries.choicecount.0.g-2.c-8.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-3"},{"#f":5}],"c-9":["ev",{"^->":"game_queries.choicecount.0.g-2.c-9.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.^.g-3"},{"#f":5}],"#f":5}],"g-3":["done",{"#f":5}]}],{"#f":1}],"turnssince_before":["ev",{"^->":"game_queries.turnssince"},"turns","out","/ev","\n",{"->":".^.^.turnssince"},{"#f":1}],"turnssince":[["ev",{"^->":"game_queries.turnssince"},"turns","out","/ev","\n","ev","str","^advance","/str","/ev",{"*":".^.c-0","flg":20},{"c-0":["^ ",{"->":".^.^.^.^.turnssince_1"},"\n",{"#f":5}]}],{"#f":3}],"turnssince_1":[["ev",{"^->":"game_queries.turnssince"},"turns","out","/ev","\n","ev","str","^advance","/str","/ev",{"*":".^.c-0","flg":20},{"c-0":["^ ",{"->":".^.^.^.^.turnssince_2"},"\n",{"#f":5}]}],{"#f":1}],"turnssince_2":["ev",{"^->":"game_queries.turnssince"},"turns","out","/ev","\n","done",{"#f":1}],"#f":1}],"saveload":["^a bit of content","\n","^the next bit","\n","done",{"choicepoint":[[["ev",{"^->":"saveload.choicepoint.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^choice 1",{"->":"$r","var":true},null]}],["ev",{"^->":"saveload.choicepoint.0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^choice 2",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"saveload.choicepoint.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"saveload.choicepoint.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["done",{"#f":5}]}],{"#f":1}],"#f":1}],"flow_control":[{"->":".^.tunnel"},{"tunnel":["^tunnel end","\n","ev","void","/ev","->->",{"#f":1}],"tunnel_call":[{"->t->":".^.^.tunnel"},"done",{"#f":1}],"thread":["^thread start","\n","thread",{"->":".^.^.threaded_text"},"thread",{"->":".^.^.threaded_choice_1"},"thread",{"->":".^.^.threaded_choice_2"},"^thread end","\n","done",{"#f":1}],"threaded_text":["^threaded text","\n","done",{"#f":1}],"threaded_choice_1":[[["ev",{"^->":"flow_control.threaded_choice_1.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^first threaded choice",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"flow_control.threaded_choice_1.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n","done",{"#f":5}]}],{"#f":1}],"threaded_choice_2":[[["ev",{"^->":"flow_control.threaded_choice_2.0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^second threaded choice",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"flow_control.threaded_choice_2.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n","done",{"#f":5}]}],{"#f":1}],"#f":1}],"lists":[{"->":".^.basic_list"},{"basic_list":["ev",{"VAR?":"kettleState"},"out","/ev","\n","ev",{"VAR?":"boiling"},"/ev",{"VAR=":"kettleState","re":true},"ev",{"VAR?":"kettleState"},"out","/ev","\n","done",{"#f":1}],"increment":["ev",{"VAR?":"cold"},"/ev",{"VAR=":"kettleState","re":true},"ev",{"VAR?":"kettleState"},"out","/ev","\n","ev",{"VAR?":"kettleState"},1,"+",{"VAR=":"kettleState","re":true},"/ev","ev",{"VAR?":"kettleState"},"out","/ev","\n","ev",{"VAR?":"kettleState"},1,"+",{"VAR=":"kettleState","re":true},"/ev","ev",{"VAR?":"kettleState"},"out","/ev","\n","ev",{"VAR?":"kettleState"},1,"-",{"VAR=":"kettleState","re":true},"/ev","ev",{"VAR?":"kettleState"},"out","/ev","\n","ev",{"VAR?":"kettleState"},1,"-",{"VAR=":"kettleState","re":true},"/ev","ev",{"VAR?":"kettleState"},"out","/ev","\n","done",{"#f":1}],"list_value":["ev",{"VAR?":"cold"},"/ev",{"VAR=":"kettleState","re":true},"ev",{"VAR?":"kettleState"},"LIST_VALUE","out","/ev","\n","ev",{"VAR?":"kettleState"},1,"+",{"VAR=":"kettleState","re":true},"/ev","ev",{"VAR?":"kettleState"},"LIST_VALUE","out","/ev","\n","ev",{"VAR?":"kettleState"},1,"+",{"VAR=":"kettleState","re":true},"/ev","ev",{"VAR?":"kettleState"},"LIST_VALUE","out","/ev","\n","done",{"#f":1}],"value_from_number":["ev","^kettleState",1,"listInt","/ev",{"VAR=":"kettleStateVar","re":true},"\n","ev",{"VAR?":"kettleStateVar"},"out","/ev","\n","ev","^kettleState",2,"listInt","/ev",{"VAR=":"kettleStateVar","re":true},"\n","ev",{"VAR?":"kettleStateVar"},"out","/ev","\n","ev","^kettleState",3,"listInt","/ev",{"VAR=":"kettleStateVar","re":true},"\n","ev",{"VAR?":"kettleStateVar"},"out","/ev","\n","done",{"#f":1}],"defined_value":["ev",{"VAR?":"primeNumbers"},"LIST_VALUE","out","/ev","\n","ev",{"VAR?":"primeNumbers"},1,"+",{"VAR=":"primeNumbers","re":true},"/ev","ev",{"VAR?":"primeNumbers"},"LIST_VALUE","out","/ev","\n","ev",{"VAR?":"primeNumbers"},1,"+",{"VAR=":"primeNumbers","re":true},"/ev","ev",{"VAR?":"primeNumbers"},"LIST_VALUE","out","/ev","\n","done",{"#f":1}],"multivalue":["ev",{"VAR?":"DoctorsInSurgery"},"out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Denver":4}},"+",{"VAR=":"DoctorsInSurgery","re":true},"/ev","ev",{"VAR?":"DoctorsInSurgery"},"out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},{"VAR?":"Eamonn"},"-",{"VAR=":"DoctorsInSurgery","re":true},"/ev","ev",{"VAR?":"DoctorsInSurgery"},"out","/ev","\n","ev",{"list":{}},"/ev",{"VAR=":"DoctorsInSurgery","re":true},"ev",{"VAR?":"DoctorsInSurgery"},"out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},{"VAR?":"Eamonn"},"-",{"VAR=":"DoctorsInSurgery","re":true},"/ev","ev",{"VAR?":"DoctorsInSurgery"},{"VAR?":"Eamonn"},"-",{"VAR=":"DoctorsInSurgery","re":true},"/ev","ev",{"VAR?":"DoctorsInSurgery"},"out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},{"VAR?":"Eamonn"},"+",{"VAR=":"DoctorsInSurgery","re":true},"/ev","ev",{"VAR?":"DoctorsInSurgery"},{"VAR?":"Eamonn"},"+",{"VAR=":"DoctorsInSurgery","re":true},"/ev","ev",{"VAR?":"DoctorsInSurgery"},"out","/ev","\n","done",{"#f":1}],"listqueries":["ev",{"list":{}},"/ev",{"VAR=":"DoctorsInSurgery","re":true},"ev",{"VAR?":"DoctorsInSurgery"},"/ev",[{"->":".^.b","c":true},{"b":["^list is not empty ",{"->":".^.^.^.9"},null]}],[{"->":".^.b"},{"b":["^list is empty",{"->":".^.^.^.9"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Denver":4}},"+",{"VAR=":"DoctorsInSurgery","re":true},"/ev","ev",{"VAR?":"DoctorsInSurgery"},"LIST_COUNT","out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},"LIST_MIN","out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},"LIST_MAX","out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},"/ev",[{"->":".^.b","c":true},{"b":["^list is not empty",{"->":".^.^.^.40"},null]}],[{"->":".^.b"},{"b":["^list is empty",{"->":".^.^.^.40"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Denver":4}},"==","/ev",[{"->":".^.b","c":true},{"b":["^exact equality",{"->":".^.^.^.48"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5}},"==","/ev",[{"->":".^.b","c":true},{"b":["^exact equality broken",{"->":".^.^.^.57"},null]}],[{"->":".^.b"},{"b":["^falsy exact equality",{"->":".^.^.^.57"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5}},"!=","/ev",[{"->":".^.b","c":true},{"b":["^exact inequality",{"->":".^.^.^.65"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Denver":4}},"!=","/ev",[{"->":".^.b","c":true},{"b":["^exact inequality broken",{"->":".^.^.^.74"},null]}],[{"->":".^.b"},{"b":["^exact inequality works",{"->":".^.^.^.74"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"VAR?":"Eamonn"},"?","/ev",[{"->":".^.b","c":true},{"b":["^has Eamonn",{"->":".^.^.^.82"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"VAR?":"Cartwright"},"?","/ev",[{"->":".^.b","c":true},{"b":["^has is broke ",{"->":".^.^.^.91"},null]}],[{"->":".^.b"},{"b":["^has falsy works",{"->":".^.^.^.91"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Cartwright":3}},"!?","/ev",[{"->":".^.b","c":true},{"b":["^has not",{"->":".^.^.^.99"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Denver":4}},"!?","/ev",[{"->":".^.b","c":true},{"b":["^has not broken",{"->":".^.^.^.108"},null]}],[{"->":".^.b"},{"b":["^falsy has not",{"->":".^.^.^.108"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},"LIST_ALL","out","/ev","\n","ev",{"list":{}},"/ev",{"VAR=":"DoctorsInSurgery","re":true},"ev",{"VAR?":"DoctorsInSurgery"},"LIST_MAX","out","/ev","\n","ev",{"VAR?":"DoctorsInSurgery"},"LIST_MIN","out","/ev","\n","ev",{"list":{"DoctorsInSurgery.Cartwright":3}},"/ev",{"VAR=":"DoctorsInSurgery","re":true},"ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Adams":1}},">","/ev",[{"->":".^.b","c":true},{"b":["^truthy greater than",{"->":".^.^.^.142"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5}},">","/ev",[{"->":".^.b","c":true},{"b":["^broken greater than",{"->":".^.^.^.151"},null]}],[{"->":".^.b"},{"b":["^falsy greater than",{"->":".^.^.^.151"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{}},">","/ev",[{"->":".^.b","c":true},{"b":["^greater than empty",{"->":".^.^.^.159"},null]}],"nop","\n","ev",{"list":{}},{"VAR?":"DoctorsInSurgery"},">","/ev",[{"->":".^.b","c":true},{"b":["^broken empty greater than",{"->":".^.^.^.168"},null]}],[{"->":".^.b"},{"b":["^empty greater than",{"->":".^.^.^.168"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5}},"<","/ev",[{"->":".^.b","c":true},{"b":["^truthy smaller than",{"->":".^.^.^.176"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Adams":1}},"<","/ev",[{"->":".^.b","c":true},{"b":["^broken smaller than",{"->":".^.^.^.185"},null]}],[{"->":".^.b"},{"b":["^falsy smaller than",{"->":".^.^.^.185"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{}},"<","/ev",[{"->":".^.b","c":true},{"b":["^broken smaller than empty",{"->":".^.^.^.194"},null]}],[{"->":".^.b"},{"b":["^smaller than empty",{"->":".^.^.^.194"},null]}],"nop","\n","ev",{"list":{}},{"VAR?":"DoctorsInSurgery"},"<","/ev",[{"->":".^.b","c":true},{"b":["^empty smaller than",{"->":".^.^.^.203"},null]}],[{"->":".^.b"},{"b":["^broken empty smaller than",{"->":".^.^.^.203"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Adams":1}},">=","/ev",[{"->":".^.b","c":true},{"b":["^truthy greater than or equal",{"->":".^.^.^.211"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Cartwright":3}},">=","/ev",[{"->":".^.b","c":true},{"b":["^truthy greater than or equal",{"->":".^.^.^.219"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5}},">=","/ev",[{"->":".^.b","c":true},{"b":["^broken greater than or equal",{"->":".^.^.^.228"},null]}],[{"->":".^.b"},{"b":["^falsy greater than or equal",{"->":".^.^.^.228"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{}},">=","/ev",[{"->":".^.b","c":true},{"b":["^greater than or equals empty",{"->":".^.^.^.236"},null]}],"nop","\n","ev",{"list":{}},{"VAR?":"DoctorsInSurgery"},">=","/ev",[{"->":".^.b","c":true},{"b":["^broken empty greater than or equals",{"->":".^.^.^.245"},null]}],[{"->":".^.b"},{"b":["^empty greater than or equals",{"->":".^.^.^.245"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Eamonn":5}},"<=","/ev",[{"->":".^.b","c":true},{"b":["^truthy smaller than or equal",{"->":".^.^.^.253"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Cartwright":3}},"<=","/ev",[{"->":".^.b","c":true},{"b":["^truthy smaller than or equal",{"->":".^.^.^.261"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{"DoctorsInSurgery.Adams":1}},"<=","/ev",[{"->":".^.b","c":true},{"b":["^broken smaller than or equal",{"->":".^.^.^.270"},null]}],[{"->":".^.b"},{"b":["^falsy smaller than or equal",{"->":".^.^.^.270"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},{"list":{}},"<=","/ev",[{"->":".^.b","c":true},{"b":["^broken smaller than or equals empty",{"->":".^.^.^.279"},null]}],[{"->":".^.b"},{"b":["^smaller than or equals empty",{"->":".^.^.^.279"},null]}],"nop","\n","ev",{"list":{}},{"VAR?":"DoctorsInSurgery"},"<=","/ev",[{"->":".^.b","c":true},{"b":["^empty smaller than or equals",{"->":".^.^.^.288"},null]}],[{"->":".^.b"},{"b":["^broken empty smaller than or equals",{"->":".^.^.^.288"},null]}],"nop","\n","ev",{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Cartwright":3}},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Cartwright":3}},"&&","/ev",[{"->":".^.b","c":true},{"b":["^truthy list AND",{"->":".^.^.^.297"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.297"},null]}],"nop","\n","ev",{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Cartwright":3}},{"list":{}},"&&","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.306"},null]}],[{"->":".^.b"},{"b":["^falsy list AND",{"->":".^.^.^.306"},null]}],"nop","\n","ev",{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Cartwright":3}},{"list":{"DoctorsInSurgery.Eamonn":5,"DoctorsInSurgery.Cartwright":3}},"||","/ev",[{"->":".^.b","c":true},{"b":["^truthy list OR",{"->":".^.^.^.315"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.315"},null]}],"nop","\n","ev",{"list":{}},{"list":{}},"||","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.324"},null]}],[{"->":".^.b"},{"b":["^falsy list OR",{"->":".^.^.^.324"},null]}],"nop","\n","ev",{"list":{}},"!","/ev",[{"->":".^.b","c":true},{"b":["^truthy list not",{"->":".^.^.^.332"},null]}],[{"->":".^.b"},{"b":["^broken",{"->":".^.^.^.332"},null]}],"nop","\n","ev",{"list":{"DoctorsInSurgery.Eamonn":5}},"!","/ev",[{"->":".^.b","c":true},{"b":["^broken",{"->":".^.^.^.340"},null]}],[{"->":".^.b"},{"b":["^falsy list not",{"->":".^.^.^.340"},null]}],"nop","\n","ev",{"VAR?":"DoctorsInSurgery"},"LIST_ALL",{"VAR?":"Bernard"},{"VAR?":"Denver"},"range","out","/ev","\n","ev",{"VAR?":"GuardsOnDuty"},"out","/ev","\n","ev",{"VAR?":"GuardsOnDuty"},"LIST_INVERT","/ev",{"VAR=":"GuardsOnDuty","re":true},"\n","ev",{"VAR?":"GuardsOnDuty"},"out","/ev","\n","ev",{"VAR?":"desiredValues"},{"VAR?":"actualValues"},"L^","out","/ev","\n","done",{"#f":1}],"#f":1}],"global decl":["ev","str","^Emilia","/str",{"VAR=":"stringvar"},521,{"VAR=":"intvar"},52.1,{"VAR=":"floatvar"},{"^->":"logic.logic_divert_dest"},{"VAR=":"divertvar"},"str","^a","/str",{"VAR=":"fnParamA"},"str","^b","/str",{"VAR=":"fnParamB"},1,{"VAR=":"observedVar1"},2,{"VAR=":"observedVar2"},{"list":{"kettleState.cold":1}},{"VAR=":"kettleState"},{"VAR?":"cold"},{"VAR=":"kettleStateVar"},{"list":{"primeNumbers.two":2}},{"VAR=":"primeNumbers"},{"list":{},"origins":["DoctorsInSurgery"]},{"VAR=":"DoctorsInSurgery"},{"list":{"GuardsOnDuty.Smith":1,"GuardsOnDuty.Jones":2}},{"VAR=":"GuardsOnDuty"},{"list":{},"origins":["CoreValues"]},{"VAR=":"CoreValues"},{"list":{"CoreValues.strength":1,"CoreValues.courage":2,"CoreValues.compassion":3,"CoreValues.self_belief":6}},{"VAR=":"desiredValues"},{"list":{"CoreValues.greed":4,"CoreValues.nepotism":5,"CoreValues.self_belief":6,"CoreValues.delusions_of_godhood":7}},{"VAR=":"actualValues"},"/ev","end",null],"#f":1}],"listDefs":{"kettleState":{"cold":1,"boiling":2,"evaporated":3},"primeNumbers":{"two":2,"three":3,"five":5},"DoctorsInSurgery":{"Adams":1,"Bernard":2,"Cartwright":3,"Denver":4,"Eamonn":5},"GuardsOnDuty":{"Smith":1,"Jones":2,"Carter":3,"Braithwaite":4},"CoreValues":{"strength":1,"courage":2,"compassion":3,"greed":4,"nepotism":5,"self_belief":6,"delusions_of_godhood":7}}} \ No newline at end of file diff --git a/src/tests/inkfiles/compiled/tags/tags.ink.json b/src/tests/inkfiles/compiled/tags/tags.ink.json index e7156cee3..b56c517be 100644 --- a/src/tests/inkfiles/compiled/tags/tags.ink.json +++ b/src/tests/inkfiles/compiled/tags/tags.ink.json @@ -1 +1 @@ -{"inkVersion":20,"root":[[{"#":"author: Joe"},{"#":"title: My Great Story"},"^This is the content","\n",["done",{"#n":"g-0"}],null],"done",{"knot":[{"#":"knot tag"},"^Knot content","\n",{"#":"end of knot tag"},"end",{"stitch":[{"#":"stitch tag"},"^Stitch content","\n",{"#":"this tag is below some content so isn't included in the static tags for the stitch"},"end",null]}],"global decl":["ev",2,{"VAR=":"x"},"/ev","end",null]}],"listDefs":{}} \ No newline at end of file +{"inkVersion":21,"root":[["#","^author: Joe","/#","#","^title: My Great Story","/#","^This is the content","\n",["done",{"#f":5,"#n":"g-0"}],null],"done",{"knot":["#","^knot tag","/#","^Knot content","\n","#","^end of knot tag","/#","end",{"stitch":["#","^stitch tag","/#","^Stitch content","\n","#","^this tag is below some content so isn't included in the static tags for the stitch","/#","end",{"#f":1}],"#f":1}],"global decl":["ev",2,{"VAR=":"x"},"/ev","end",null],"#f":1}],"listDefs":{}} \ No newline at end of file diff --git a/src/tests/specs/ink/Choices.spec.ts b/src/tests/specs/ink/Choices.spec.ts index ec8b949fb..7fc6f7dfe 100644 --- a/src/tests/specs/ink/Choices.spec.ts +++ b/src/tests/specs/ink/Choices.spec.ts @@ -271,11 +271,12 @@ describe("Choices", () => { //TestTagsInChoice it("tests dynamic tags in choice", () => { + loadStory("tags_in_choice"); - context.story.Continue(); + expect(context.story.currentTags).toEqual(["one", "two"]); - expect(context.story.currentChoices.length).toBe(2); + expect(context.story.currentChoices.length).toBe(1); expect(context.story.currentChoices[0].tags).toEqual(["one", "two"]); context.story.ChooseChoiceIndex(0); diff --git a/src/tests/specs/ink/Tags.spec.ts b/src/tests/specs/ink/Tags.spec.ts index a5cb64d2c..c119b13fa 100644 --- a/src/tests/specs/ink/Tags.spec.ts +++ b/src/tests/specs/ink/Tags.spec.ts @@ -26,7 +26,7 @@ describe("Tags", () => { // TestTags it("tests string constants", () => { - compileStory("tags"); + loadStory("tags"); let globalTags = ["author: Joe", "title: My Great Story"]; let knotTags = ["knot tag"]; diff --git a/src/tests/specs/inkjs/engine/Tags.spec.ts b/src/tests/specs/inkjs/engine/Tags.spec.ts index 335bf8c5d..7209ba8c0 100644 --- a/src/tests/specs/inkjs/engine/Tags.spec.ts +++ b/src/tests/specs/inkjs/engine/Tags.spec.ts @@ -4,7 +4,7 @@ describe("Tags", () => { let context: testsUtils.TestContext; beforeEach(() => { - context = testsUtils.makeDefaultTestContext("tests", "inkjs", true); + context = testsUtils.fromJsonTestContext("tests", "inkjs"); context.story.allowExternalFunctionFallbacks = true; }); @@ -51,7 +51,7 @@ describe("Tags", () => { context.story.Continue(); expect(context.story.currentChoices.length).toEqual(1); - expect(context.story.currentChoices[0].text).toEqual("a choice"); + expect(context.story.currentChoices[0].text).toEqual("a choice a tag"); //weird https://discord.com/channels/329929050866843648/1032209859749359646/1032306385200877710 expect(context.story.currentTags.length).toEqual(0); context.story.ChooseChoiceIndex(0); @@ -67,11 +67,8 @@ describe("Tags", () => { let tags = context.story.currentTags; - expect(tags.length).toBe(5); + expect(tags.length).toBe(2); expect(tags[0]).toEqual("space around"); - expect(tags[1]).toEqual(""); - expect(tags[2]).toEqual(""); - expect(tags[3]).toEqual(""); - expect(tags[4]).toEqual("0"); + expect(tags[1]).toEqual("0"); }); }); From e77b13e41b26665f07436d5e7d0712669725416d Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Wed, 19 Oct 2022 17:59:36 +0200 Subject: [PATCH 11/36] linter --- src/engine/ControlCommand.ts | 2 +- src/engine/Story.ts | 68 ++++++++++-------- src/engine/StoryState.ts | 104 +++++++++++++++------------- src/engine/StringBuilder.ts | 2 +- src/tests/specs/ink/Choices.spec.ts | 3 +- 5 files changed, 97 insertions(+), 82 deletions(-) diff --git a/src/engine/ControlCommand.ts b/src/engine/ControlCommand.ts index 68ddd0dae..e2decca88 100644 --- a/src/engine/ControlCommand.ts +++ b/src/engine/ControlCommand.ts @@ -106,7 +106,7 @@ export class ControlCommand extends InkObject { export namespace ControlCommand { export enum CommandType { NotSet = -1, - EvalStart, // 0 + EvalStart, // 0 EvalOutput, // 1 EvalEnd, // 2 Duplicate, // 3 diff --git a/src/engine/Story.ts b/src/engine/Story.ts index 330c19904..f8de177bb 100644 --- a/src/engine/Story.ts +++ b/src/engine/Story.ts @@ -883,18 +883,20 @@ export class Story extends InkObject { } } - public PopChoiceStringAndTags(tags: string[]){ + public PopChoiceStringAndTags(tags: string[]) { let choiceOnlyStrVal = asOrThrows( this.state.PopEvaluationStack(), StringValue ); - while (this.state.evaluationStack.length > 0 - && asOrNull(this.state.PeekEvaluationStack(), Tag)) { + while ( + this.state.evaluationStack.length > 0 && + asOrNull(this.state.PeekEvaluationStack(), Tag) + ) { let tag = asOrNull(this.state.PopEvaluationStack(), Tag); - if(tag) tags.unshift(tag.text); + if (tag) tags.unshift(tag.text); } - return choiceOnlyStrVal.value + return choiceOnlyStrVal.value; } public ProcessChoice(choicePoint: ChoicePoint) { @@ -910,7 +912,7 @@ export class Story extends InkObject { let startText = ""; let choiceOnlyText = ""; - let tags:string[] = []; + let tags: string[] = []; if (choicePoint.hasChoiceOnlyContent) { choiceOnlyText = this.PopChoiceStringAndTags(tags) || ""; @@ -1163,7 +1165,7 @@ export class Story extends InkObject { ); this.state.inExpressionEvaluation = false; break; - + // Leave it to story.currentText and story.currentTags to sort out the text from the tags // This is mostly because we can't rely on the existence of EndTag, and we don't want // to try and flatten dynamic tags to strings every time \n is pushed to output @@ -1171,8 +1173,8 @@ export class Story extends InkObject { case ControlCommand.CommandType.EndTag: this.state.PushToOutputStream(evalCommand); break; - - case ControlCommand.CommandType.EndTagAndPushToStack:{ + + case ControlCommand.CommandType.EndTagAndPushToStack: { let contentStackForTag: InkObject[] = []; let outputCountConsumed = 0; for (let i = this.state.outputStream.length - 1; i >= 0; --i) { @@ -1182,12 +1184,14 @@ export class Story extends InkObject { // var command = obj as ControlCommand; let command = asOrNull(obj, ControlCommand); - if (command){ - if( command.commandType == ControlCommand.CommandType.BeginTag ) { + if (command) { + if (command.commandType == ControlCommand.CommandType.BeginTag) { break; } else { - this.Error("Unexpected ControlCommand while extracting tag from choice"); - break; + this.Error( + "Unexpected ControlCommand while extracting tag from choice" + ); + break; } } if (obj instanceof StringValue) { @@ -1195,7 +1199,7 @@ export class Story extends InkObject { } } // Consume the content that was produced for this string - this.state.PopFromOutputStream (outputCountConsumed); + this.state.PopFromOutputStream(outputCountConsumed); // Build string out of the content we collected let sb = new StringBuilder(); @@ -1203,19 +1207,21 @@ export class Story extends InkObject { sb.Append(c.toString()); } - let choiceTag = new Tag(this.state.CleanOutputWhitespace(sb.toString())); - + let choiceTag = new Tag( + this.state.CleanOutputWhitespace(sb.toString()) + ); + // Pushing to the evaluation stack means it gets picked up // when a Choice is generated from the next Choice Point. this.state.PushEvaluationStack(choiceTag); // But we also push it to general output in case people // want to get the tag from there. - this.state.PushToOutputStream (choiceTag); + this.state.PushToOutputStream(choiceTag); break; } - case ControlCommand.CommandType.EndString:{ + case ControlCommand.CommandType.EndString: { let contentStackForString: InkObject[] = []; let contentToRetain: InkObject[] = []; @@ -1233,7 +1239,7 @@ export class Story extends InkObject { ) { break; } - if( obj instanceof Tag ){ + if (obj instanceof Tag) { contentToRetain.push(obj); } if (obj instanceof StringValue) { @@ -1249,7 +1255,7 @@ export class Story extends InkObject { // At the time of writing, this only applies to Tag objects generated // by choices, which are pushed to the stack during string generation. for (let rescuedTag of contentToRetain) - this.state.PushToOutputStream(rescuedTag); + this.state.PushToOutputStream(rescuedTag); // The C# version uses a Stack for contentStackForString, but we're // using a simple array, so we need to reverse it before using it @@ -2139,22 +2145,24 @@ export class Story extends InkObject { let command = asOrNull(c, ControlCommand); if (command != null) { - if( command.commandType == ControlCommand.CommandType.BeginTag ) { - inTag = true; - } else if( command.commandType == ControlCommand.CommandType.EndTag ) { - inTag = false; + if (command.commandType == ControlCommand.CommandType.BeginTag) { + inTag = true; + } else if (command.commandType == ControlCommand.CommandType.EndTag) { + inTag = false; } - } else if (inTag){ + } else if (inTag) { let str = asOrNull(c, StringValue); - if( str !== null ) { - if( tags === null ) tags = []; - if(str.value !== null) tags.push(str.value); + if (str !== null) { + if (tags === null) tags = []; + if (str.value !== null) tags.push(str.value); } else { - this.Error("Tag contained non-text content. Only plain text is allowed when using globalTags or TagsAtContentPath. If you want to evaluate dynamic content, you need to use story.Continue()."); + this.Error( + "Tag contained non-text content. Only plain text is allowed when using globalTags or TagsAtContentPath. If you want to evaluate dynamic content, you need to use story.Continue()." + ); } } else { break; - } + } } return tags; diff --git a/src/engine/StoryState.ts b/src/engine/StoryState.ts index 55e8b47af..b955f53b5 100644 --- a/src/engine/StoryState.ts +++ b/src/engine/StoryState.ts @@ -259,19 +259,23 @@ export class StoryState { if (this._outputStreamTextDirty) { let sb = new StringBuilder(); - let inTag:boolean = false; + let inTag: boolean = false; for (let outputObj of this.outputStream) { // var textContent = outputObj as StringValue; let textContent = asOrNull(outputObj, StringValue); if (!inTag && textContent !== null) { sb.Append(textContent.value); - }else{ + } else { let controlCommand = asOrNull(outputObj, ControlCommand); - if( controlCommand !== null ) { - if( controlCommand.commandType == ControlCommand.CommandType.BeginTag ) { + if (controlCommand !== null) { + if ( + controlCommand.commandType == ControlCommand.CommandType.BeginTag + ) { inTag = true; - } else if( controlCommand.commandType == ControlCommand.CommandType.EndTag ) { + } else if ( + controlCommand.commandType == ControlCommand.CommandType.EndTag + ) { inTag = false; } } @@ -323,46 +327,47 @@ export class StoryState { if (this._outputStreamTagsDirty) { this._currentTags = []; let inTag: boolean = false; - let sb = new StringBuilder (); + let sb = new StringBuilder(); for (let outputObj of this.outputStream) { let controlCommand = asOrNull(outputObj, ControlCommand); - if( controlCommand != null ) { - - if( controlCommand.commandType == ControlCommand.CommandType.BeginTag ) { - if( inTag && sb.Length > 0 ) { - var txt = this.CleanOutputWhitespace(sb.toString()); - this._currentTags.push(txt); - sb.Clear(); - } - inTag = true; + if (controlCommand != null) { + if ( + controlCommand.commandType == ControlCommand.CommandType.BeginTag + ) { + if (inTag && sb.Length > 0) { + let txt = this.CleanOutputWhitespace(sb.toString()); + this._currentTags.push(txt); + sb.Clear(); + } + inTag = true; + } else if ( + controlCommand.commandType == ControlCommand.CommandType.EndTag + ) { + if (sb.Length > 0) { + let txt = this.CleanOutputWhitespace(sb.toString()); + this._currentTags.push(txt); + sb.Clear(); + } + inTag = false; } - - else if( controlCommand.commandType == ControlCommand.CommandType.EndTag ) { - if( sb.Length > 0 ) { - var txt = this.CleanOutputWhitespace(sb.toString()); - this._currentTags.push(txt); - sb.Clear(); - } - inTag = false; + } else if (inTag) { + let strVal = asOrNull(outputObj, StringValue); + if (strVal !== null) { + sb.Append(strVal.value); } - }else if( inTag ) { - let strVal = asOrNull(outputObj, StringValue) - if( strVal !== null ) { - sb.Append(strVal.value); - } - }else { - var tag = outputObj as Tag; + } else { + let tag = outputObj as Tag; if (tag != null && tag.text != null && tag.text.length > 0) { - this._currentTags.push (tag.text); // tag.text has whitespae already cleaned + this._currentTags.push(tag.text); // tag.text has whitespae already cleaned } } } - if( sb.Length > 0 ) { - var txt = this.CleanOutputWhitespace(sb.toString()); - this._currentTags.push(txt); - sb.Clear(); + if (sb.Length > 0) { + let txt = this.CleanOutputWhitespace(sb.toString()); + this._currentTags.push(txt); + sb.Clear(); } this._outputStreamTagsDirty = false; @@ -380,18 +385,17 @@ export class StoryState { return this._currentFlow.name == this.kDefaultFlowName; } - get aliveFlowNames(){ - if( this._aliveFlowNamesDirty ) { + get aliveFlowNames() { + if (this._aliveFlowNamesDirty) { this._aliveFlowNames = []; - if (this._namedFlows != null) - { - for (let flowName of this._namedFlows.keys()) { - if (flowName != this.kDefaultFlowName) { - this._aliveFlowNames.push(flowName); - } - } - } + if (this._namedFlows != null) { + for (let flowName of this._namedFlows.keys()) { + if (flowName != this.kDefaultFlowName) { + this._aliveFlowNames.push(flowName); + } + } + } this._aliveFlowNamesDirty = false; } @@ -1121,9 +1125,13 @@ export class StoryState { if (args !== null) { for (let i = 0; i < args.length; i++) { if ( - !(typeof args[i] === "number" || typeof args[i] === "string" || typeof args[i] === "boolean" || - args[i] instanceof InkList - )) { + !( + typeof args[i] === "number" || + typeof args[i] === "string" || + typeof args[i] === "boolean" || + args[i] instanceof InkList + ) + ) { throw new Error( "ink arguments when calling EvaluateFunction / ChoosePathStringWithParameters must be" + "number, string, bool or InkList. Argument was " + diff --git a/src/engine/StringBuilder.ts b/src/engine/StringBuilder.ts index cae68a5f6..6739241e0 100644 --- a/src/engine/StringBuilder.ts +++ b/src/engine/StringBuilder.ts @@ -27,7 +27,7 @@ export class StringBuilder { return this.string; } - public Clear(){ + public Clear() { this.string = ""; } } diff --git a/src/tests/specs/ink/Choices.spec.ts b/src/tests/specs/ink/Choices.spec.ts index 7fc6f7dfe..dcce75539 100644 --- a/src/tests/specs/ink/Choices.spec.ts +++ b/src/tests/specs/ink/Choices.spec.ts @@ -271,10 +271,9 @@ describe("Choices", () => { //TestTagsInChoice it("tests dynamic tags in choice", () => { - loadStory("tags_in_choice"); context.story.Continue(); - + expect(context.story.currentTags).toEqual(["one", "two"]); expect(context.story.currentChoices.length).toBe(1); expect(context.story.currentChoices[0].tags).toEqual(["one", "two"]); From c88de92cc2863eae4bc3ec76f822e247ad32411e Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 11:35:50 +0200 Subject: [PATCH 12/36] porting 1131145 --- src/engine/ControlCommand.ts | 4 -- src/engine/JsonSerialisation.ts | 2 - src/engine/Story.ts | 113 ++++++++++++++++++++------------ 3 files changed, 70 insertions(+), 49 deletions(-) diff --git a/src/engine/ControlCommand.ts b/src/engine/ControlCommand.ts index e2decca88..bae14fa09 100644 --- a/src/engine/ControlCommand.ts +++ b/src/engine/ControlCommand.ts @@ -95,9 +95,6 @@ export class ControlCommand extends InkObject { public static EndTag() { return new ControlCommand(ControlCommand.CommandType.EndTag); } - public static EndTagAndPushToStack() { - return new ControlCommand(ControlCommand.CommandType.EndTagAndPushToStack); - } public toString() { return this.commandType.toString(); } @@ -132,7 +129,6 @@ export namespace ControlCommand { ListRandom, // 23 BeginTag, // 24 EndTag, // 25 - EndTagAndPushToStack, // 26 TOTAL_VALUES, } diff --git a/src/engine/JsonSerialisation.ts b/src/engine/JsonSerialisation.ts index 01d6536d7..4fdce2813 100644 --- a/src/engine/JsonSerialisation.ts +++ b/src/engine/JsonSerialisation.ts @@ -721,8 +721,6 @@ export class JsonSerialisation { _controlCommandNames[ControlCommand.CommandType.ListRandom] = "lrnd"; _controlCommandNames[ControlCommand.CommandType.BeginTag] = "#"; _controlCommandNames[ControlCommand.CommandType.EndTag] = "/#"; - _controlCommandNames[ControlCommand.CommandType.EndTagAndPushToStack] = - "/#out"; for (let i = 0; i < ControlCommand.CommandType.TOTAL_VALUES; ++i) { if (_controlCommandNames[i] == null) diff --git a/src/engine/Story.ts b/src/engine/Story.ts index f8de177bb..411be469f 100644 --- a/src/engine/Story.ts +++ b/src/engine/Story.ts @@ -566,6 +566,7 @@ export class Story extends InkObject { let newlineStillExists = currText.length >= prevText.length && + prevText.length > 0 && currText.charAt(prevText.length - 1) == "\n"; if ( prevTagCount == currTagCount && @@ -1167,58 +1168,84 @@ export class Story extends InkObject { break; // Leave it to story.currentText and story.currentTags to sort out the text from the tags - // This is mostly because we can't rely on the existence of EndTag, and we don't want + // This is mostly because we can't always rely on the existence of EndTag, and we don't want // to try and flatten dynamic tags to strings every time \n is pushed to output case ControlCommand.CommandType.BeginTag: - case ControlCommand.CommandType.EndTag: this.state.PushToOutputStream(evalCommand); break; - case ControlCommand.CommandType.EndTagAndPushToStack: { - let contentStackForTag: InkObject[] = []; - let outputCountConsumed = 0; - for (let i = this.state.outputStream.length - 1; i >= 0; --i) { - let obj = this.state.outputStream[i]; - - outputCountConsumed++; - - // var command = obj as ControlCommand; - let command = asOrNull(obj, ControlCommand); - if (command) { - if (command.commandType == ControlCommand.CommandType.BeginTag) { - break; - } else { - this.Error( - "Unexpected ControlCommand while extracting tag from choice" - ); - break; + // EndTag has 2 modes: + // - When in string evaluation (for choices) + // - Normal + // + // The only way you could have an EndTag in the middle of + // string evaluation is if we're currently generating text for a + // choice, such as: + // + // + choice # tag + // + // In the above case, the ink will be run twice: + // - First, to generate the choice text. String evaluation + // will be on, and the final string will be pushed to the + // evaluation stack, ready to be popped to make a Choice + // object. + // - Second, when ink generates text after choosing the choice. + // On this ocassion, it's not in string evaluation mode. + // + // On the writing side, we disallow manually putting tags within + // strings like this: + // + // {"hello # world"} + // + // So we know that the tag must be being generated as part of + // choice content. Therefore, when the tag has been generated, + // we push it onto the evaluation stack in the exact same way + // as the string for the choice content. + case ControlCommand.CommandType.EndTag: { + if (this.state.inStringEvaluation) { + let contentStackForTag: InkObject[] = []; + let outputCountConsumed = 0; + for (let i = this.state.outputStream.length - 1; i >= 0; --i) { + let obj = this.state.outputStream[i]; + outputCountConsumed++; + + // var command = obj as ControlCommand; + let command = asOrNull(obj, ControlCommand); + if (command != null) { + if ( + command.commandType == ControlCommand.CommandType.BeginTag + ) { + break; + } else { + this.Error( + "Unexpected ControlCommand while extracting tag from choice" + ); + break; + } + } + if (obj instanceof StringValue) { + contentStackForTag.push(obj); } } - if (obj instanceof StringValue) { - contentStackForTag.push(obj); - } - } - // Consume the content that was produced for this string - this.state.PopFromOutputStream(outputCountConsumed); - // Build string out of the content we collected - let sb = new StringBuilder(); - for (let c of contentStackForTag) { - sb.Append(c.toString()); + // Consume the content that was produced for this string + this.state.PopFromOutputStream(outputCountConsumed); + // Build string out of the content we collected + let sb = new StringBuilder(); + for (let strVal of contentStackForTag) { + sb.Append(strVal.toString()); + } + let choiceTag = new Tag( + this.state.CleanOutputWhitespace(sb.toString()) + ); + // Pushing to the evaluation stack means it gets picked up + // when a Choice is generated from the next Choice Point. + this.state.PushToOutputStream(choiceTag); + } else { + // Otherwise! Simply push EndTag, so that in the output stream we + // have a structure of: [BeginTag, "the tag content", EndTag] + this.state.PushToOutputStream(evalCommand); } - - let choiceTag = new Tag( - this.state.CleanOutputWhitespace(sb.toString()) - ); - - // Pushing to the evaluation stack means it gets picked up - // when a Choice is generated from the next Choice Point. - this.state.PushEvaluationStack(choiceTag); - - // But we also push it to general output in case people - // want to get the tag from there. - this.state.PushToOutputStream(choiceTag); - break; } case ControlCommand.CommandType.EndString: { From c34457f8e7e02a13eab6ae43da7a0fedb0aa2319 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 11:42:14 +0200 Subject: [PATCH 13/36] compiler/InkParser/InkParser.cs --- src/compiler/Parser/CustomFlags.ts | 1 + src/compiler/Parser/InkParser.ts | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/compiler/Parser/CustomFlags.ts b/src/compiler/Parser/CustomFlags.ts index 0f98e8bfe..7913db171 100644 --- a/src/compiler/Parser/CustomFlags.ts +++ b/src/compiler/Parser/CustomFlags.ts @@ -1,3 +1,4 @@ export enum CustomFlags { ParsingString = 0x1, + TagActive = 0x2, } diff --git a/src/compiler/Parser/InkParser.ts b/src/compiler/Parser/InkParser.ts index 518db9947..3f648f64b 100644 --- a/src/compiler/Parser/InkParser.ts +++ b/src/compiler/Parser/InkParser.ts @@ -227,6 +227,14 @@ export class InkParser extends StringParser { this.SetFlag(Number(CustomFlags.ParsingString), value); } + get tagActive(): boolean{ + return this.GetFlag(Number(CustomFlags.TagActive)); + } + + set tagActive(value: boolean){ + this.SetFlag(Number(CustomFlags.TagActive), value); + } + public readonly OnStringParserError = ( message: string, index: number, From 53b1b06ae16d7874d5d0a1d522e13a429b97d3e7 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 12:06:59 +0200 Subject: [PATCH 14/36] compiler/ParsedHierarchy/Tag.cs --- src/compiler/Parser/ParsedHierarchy/Tag.ts | 32 ++++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/compiler/Parser/ParsedHierarchy/Tag.ts b/src/compiler/Parser/ParsedHierarchy/Tag.ts index 44eda0324..019aa2052 100644 --- a/src/compiler/Parser/ParsedHierarchy/Tag.ts +++ b/src/compiler/Parser/ParsedHierarchy/Tag.ts @@ -1,11 +1,33 @@ -import { Tag as RuntimeTag } from "../../../engine/Tag"; -import { Wrap } from "./Wrap"; +import { ParsedObject } from "./Object"; +import { ControlCommand } from "../../../engine/ControlCommand"; +import { InkObject as RuntimeObject } from "../../../engine/Object"; -export class Tag extends Wrap { - constructor(tag: RuntimeTag) { - super(tag); +export class Tag extends ParsedObject { + + public isStart: boolean; + public inChoice: boolean; + + constructor(isStart: boolean, inChoice: boolean = false) { + super(); + this.isStart = isStart; + this.inChoice = inChoice; } get typeName(): string { return "Tag"; } + public readonly GenerateRuntimeObject = (): RuntimeObject => { + if(this.isStart){ + return ControlCommand.BeginTag() + }else{ + return ControlCommand.EndTag() + } + } + + public readonly toString = () => { + if(this.isStart){ + return "#StartTag"; + }else{ + return "#EndTag"; + } + } } From 3dbb4548d9e825ad544d41e569445d5c3ee3e253 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 12:08:38 +0200 Subject: [PATCH 15/36] compiler/ParsedHierarchy/Wrap.cs --- src/compiler/Parser/ParsedHierarchy/Tag.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/compiler/Parser/ParsedHierarchy/Tag.ts b/src/compiler/Parser/ParsedHierarchy/Tag.ts index 019aa2052..003daaabb 100644 --- a/src/compiler/Parser/ParsedHierarchy/Tag.ts +++ b/src/compiler/Parser/ParsedHierarchy/Tag.ts @@ -31,3 +31,15 @@ export class Tag extends ParsedObject { } } } + +import { Tag as RuntimeTag } from "../../../engine/Tag"; +import { Wrap } from "./Wrap"; +export class LegacyTag extends Wrap { + constructor(tag: RuntimeTag) { + super(tag); + } + get typeName(): string { + return "Tag"; + } +} + From 2b3de5e5d353bb7e1f5441703627ec7373b58e05 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 12:09:07 +0200 Subject: [PATCH 16/36] linter --- src/compiler/Parser/ParsedHierarchy/Tag.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/compiler/Parser/ParsedHierarchy/Tag.ts b/src/compiler/Parser/ParsedHierarchy/Tag.ts index 003daaabb..06a3e8003 100644 --- a/src/compiler/Parser/ParsedHierarchy/Tag.ts +++ b/src/compiler/Parser/ParsedHierarchy/Tag.ts @@ -3,7 +3,6 @@ import { ControlCommand } from "../../../engine/ControlCommand"; import { InkObject as RuntimeObject } from "../../../engine/Object"; export class Tag extends ParsedObject { - public isStart: boolean; public inChoice: boolean; @@ -16,20 +15,20 @@ export class Tag extends ParsedObject { return "Tag"; } public readonly GenerateRuntimeObject = (): RuntimeObject => { - if(this.isStart){ - return ControlCommand.BeginTag() - }else{ - return ControlCommand.EndTag() + if (this.isStart) { + return ControlCommand.BeginTag(); + } else { + return ControlCommand.EndTag(); } - } + }; public readonly toString = () => { - if(this.isStart){ + if (this.isStart) { return "#StartTag"; - }else{ + } else { return "#EndTag"; } - } + }; } import { Tag as RuntimeTag } from "../../../engine/Tag"; @@ -42,4 +41,3 @@ export class LegacyTag extends Wrap { return "Tag"; } } - From 452f8a19d5ffb977153a2aeae2c2d397afd75db5 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 12:10:32 +0200 Subject: [PATCH 17/36] compiler/InkParser/InkParser_Tags.cs --- src/compiler/Parser/InkParser.ts | 68 ++++++++++++++++---------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/compiler/Parser/InkParser.ts b/src/compiler/Parser/InkParser.ts index 3f648f64b..02d8a2629 100644 --- a/src/compiler/Parser/InkParser.ts +++ b/src/compiler/Parser/InkParser.ts @@ -227,11 +227,11 @@ export class InkParser extends StringParser { this.SetFlag(Number(CustomFlags.ParsingString), value); } - get tagActive(): boolean{ + get tagActive(): boolean { return this.GetFlag(Number(CustomFlags.TagActive)); } - set tagActive(value: boolean){ + set tagActive(value: boolean) { this.SetFlag(Number(CustomFlags.TagActive), value); } @@ -3212,50 +3212,50 @@ export class InkParser extends StringParser { * Begin Tags section. */ - private _endOfTagCharSet: CharacterSet = new CharacterSet("#\n\r\\"); - - public readonly Tag = (): Tag | null => { + public readonly StartTag = (): ParsedObject | null => { this.Whitespace(); if (this.ParseString("#") === null) { return null; } - this.Whitespace(); - - let sb = ""; - do { - // Read up to another #, end of input or newline - const tagText: string = - this.ParseUntilCharactersFromCharSet(this._endOfTagCharSet) || ""; - sb += tagText; - - // Escape character - if (this.ParseString("\\") !== null) { - const c: string = this.ParseSingleCharacter(); - if (c !== "\0") { - sb += c; - } - - continue; - } + if (this.parsingStringExpression) { + this.Error( + "Tags aren't allowed inside of strings. Please use \\# if you want a hash symbol." + ); + } - break; - } while (true); + let result: ParsedObject | null = null; + if (this.tagActive) { + let contentList = new ContentList(); + contentList.AddContent(new Tag(/*isStart:*/ false)); + contentList.AddContent(new Tag(/*isStart:*/ true)); + result = contentList; + } else { + result = new Tag(/*isStart:*/ true); + } + this.tagActive = true; - const fullTagText = sb.trim(); + this.Whitespace(); - return new Tag(new RuntimeTag(fullTagText)); + return result; }; - public readonly Tags = (): Tag[] | null => { - const tags = this.OneOrMore(this.Tag) as Tag[]; - if (tags === null) { - return null; + public EndTagIfNecessary(outputContentList: ParsedObject[]): void; + public EndTagIfNecessary(outputContentList: ContentList): void; + public EndTagIfNecessary( + outputContentList: ParsedObject[] | ContentList + ): void { + if (this.tagActive) { + if (outputContentList != null) { + if (outputContentList instanceof ContentList) { + outputContentList.AddContent(new Tag(/*isStart:*/ false )); + } else { + outputContentList.push(new Tag(/*isStart:*/ false)); + } + } } - - return tags; - }; + } /** * End Tags section. From 9e0ab8a36fb93dcaf62d8280c005a99b2143be6d Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 12:11:06 +0200 Subject: [PATCH 18/36] linter --- src/compiler/Parser/InkParser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/Parser/InkParser.ts b/src/compiler/Parser/InkParser.ts index 02d8a2629..f74665937 100644 --- a/src/compiler/Parser/InkParser.ts +++ b/src/compiler/Parser/InkParser.ts @@ -3249,7 +3249,7 @@ export class InkParser extends StringParser { if (this.tagActive) { if (outputContentList != null) { if (outputContentList instanceof ContentList) { - outputContentList.AddContent(new Tag(/*isStart:*/ false )); + outputContentList.AddContent(new Tag(/*isStart:*/ false)); } else { outputContentList.push(new Tag(/*isStart:*/ false)); } From 33a44b363f9715622c60cc21cb20e20deddb116a Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 12:18:48 +0200 Subject: [PATCH 19/36] compiler/InkParser/InkParser_Choices.cs --- src/compiler/Parser/InkParser.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/compiler/Parser/InkParser.ts b/src/compiler/Parser/InkParser.ts index f74665937..5d5a4eea8 100644 --- a/src/compiler/Parser/InkParser.ts +++ b/src/compiler/Parser/InkParser.ts @@ -449,6 +449,8 @@ export class InkParser extends StringParser { // * "Hello[."]," he said. const hasWeaveStyleInlineBrackets: boolean = this.ParseString("[") !== null; if (hasWeaveStyleInlineBrackets) { + this.EndTagIfNecessary(startContent); + const optionOnlyTextAndLogic = this.Parse( this.MixedTextAndLogic ) as ParsedObject[]; @@ -459,6 +461,8 @@ export class InkParser extends StringParser { this.Expect(this.String("]"), "closing ']' for weave-style option"); + this.EndTagIfNecessary(startContent); + let innerTextAndLogic = this.Parse( this.MixedTextAndLogic ) as ParsedObject[]; @@ -469,6 +473,8 @@ export class InkParser extends StringParser { this.Whitespace(); + this.EndTagIfNecessary(innerContent ?? startContent); + // Finally, now we know we're at the end of the main choice body, parse // any diverts separately. const diverts: ParsedObject[] = this.Parse( @@ -500,10 +506,7 @@ export class InkParser extends StringParser { innerContent = new ContentList(); } - const tags = this.Parse(this.Tags) as ParsedObject[]; - if (tags !== null) { - innerContent.AddContent(tags); - } + this.EndTagIfNecessary(innerContent); // Normal diverts on the end of a choice - simply add to the normal content if (diverts !== null) { @@ -3241,10 +3244,10 @@ export class InkParser extends StringParser { return result; }; - public EndTagIfNecessary(outputContentList: ParsedObject[]): void; - public EndTagIfNecessary(outputContentList: ContentList): void; + public EndTagIfNecessary(outputContentList: ParsedObject[] | null): void; + public EndTagIfNecessary(outputContentList: ContentList | null): void; public EndTagIfNecessary( - outputContentList: ParsedObject[] | ContentList + outputContentList: ParsedObject[] | ContentList | null ): void { if (this.tagActive) { if (outputContentList != null) { @@ -3254,6 +3257,7 @@ export class InkParser extends StringParser { outputContentList.push(new Tag(/*isStart:*/ false)); } } + this.tagActive = false; } } From 895e8006f4b7d3f8a2b2361f70911a5271b73c93 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 12:22:38 +0200 Subject: [PATCH 20/36] compiler/InkParser/InkParser_Content.cs --- src/compiler/Parser/InkParser.ts | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/compiler/Parser/InkParser.ts b/src/compiler/Parser/InkParser.ts index 5d5a4eea8..336a37675 100644 --- a/src/compiler/Parser/InkParser.ts +++ b/src/compiler/Parser/InkParser.ts @@ -1022,20 +1022,6 @@ export class InkParser extends StringParser { this.MixedTextAndLogic ) as ParsedObject[]; - // Terminating tag - let onlyTags: boolean = false; - const tags = this.Parse(this.Tags) as ParsedObject[]; - if (tags) { - if (!result) { - result = tags; - onlyTags = true; - } else { - for (const tag of tags) { - result.push(tag); - } - } - } - if (!result || !result.length) { return null; } @@ -1057,9 +1043,15 @@ export class InkParser extends StringParser { this.TrimEndWhitespace(result, false); } - // Add newline since it's the end of the line - // (so long as it's a line with only tags) - if (!onlyTags) { + this.EndTagIfNecessary(result); + + // If the line doens't actually contain any normal text content + // but is in fact entirely a tag, then let's not append + // a newline, since we want the tag (or tags) to be associated + // with the line below rather than being completely independent. + let lineIsPureTag = result.length > 0 && result[0] instanceof Tag && result[0].isStart; + + if(lineIsPureTag){ result.push(new Text("\n")); } @@ -1079,7 +1071,7 @@ export class InkParser extends StringParser { // Either, or both interleaved let results: ParsedObject[] = this.Interleave( this.Optional(this.ContentText), - this.Optional(this.InlineLogicOrGlue) + this.Optional(this.InlineLogicOrGlueOrStartTag) ); // Terminating divert? @@ -1094,6 +1086,9 @@ export class InkParser extends StringParser { if (results === null) { results = []; } + + // End previously active tag if necessary + this.EndTagIfNecessary(results); this.TrimEndWhitespace(results, true); From 073b0ed076aa635373c0bbeedbf2e39a8c90dd87 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 12:23:17 +0200 Subject: [PATCH 21/36] compiler/InkParser/InkParser_Divert.cs --- src/compiler/Parser/InkParser.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/compiler/Parser/InkParser.ts b/src/compiler/Parser/InkParser.ts index 336a37675..67ebd776b 100644 --- a/src/compiler/Parser/InkParser.ts +++ b/src/compiler/Parser/InkParser.ts @@ -1230,6 +1230,8 @@ export class InkParser extends StringParser { diverts = []; + this.EndTagIfNecessary(diverts); + // Possible patterns: // -> -- explicit gather // ->-> -- tunnel onwards From d41248922cacba96cfbb12e961fdd40dba3576e8 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 12:27:02 +0200 Subject: [PATCH 22/36] compiler/InkParser/InkParser_Logic.cs --- src/compiler/Parser/InkParser.ts | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/compiler/Parser/InkParser.ts b/src/compiler/Parser/InkParser.ts index 67ebd776b..c3c2009e5 100644 --- a/src/compiler/Parser/InkParser.ts +++ b/src/compiler/Parser/InkParser.ts @@ -2624,8 +2624,8 @@ export class InkParser extends StringParser { return result; }; - public readonly InlineLogicOrGlue = (): ParsedObject => - this.OneOf([this.InlineLogic, this.Glue]) as ParsedObject; + public readonly InlineLogicOrGlueOrStartTag = (): ParsedObject => + this.OneOf([this.InlineLogic, this.Glue, this.StartTag]) as ParsedObject; public readonly Glue = (): Glue | null => { // Don't want to parse whitespace, since it might be important @@ -2643,6 +2643,9 @@ export class InkParser extends StringParser { return null; } + let wasParsingString = this.parsingStringExpression; + let wasTagActive = this.tagActive; + this.Whitespace(); const logic = this.Expect( @@ -2651,6 +2654,7 @@ export class InkParser extends StringParser { ) as ParsedObject; if (logic === null) { + this.parsingStringExpression = wasParsingString return null; } @@ -2665,6 +2669,19 @@ export class InkParser extends StringParser { this.Expect(this.String("}"), "closing brace '}' for inline logic"); + // Allow nested strings and logic + this.parsingStringExpression = wasParsingString; + + // Difference between: + // + // 1) A thing # {image}.jpg + // 2) A {red #red|blue #blue} sequence. + // + // When logic ends in (1) we still want tag to continue. + // When logic ends in (2) we want to auto-end the tag. + // Side note: we simply disallow tags within strings. + if( !wasTagActive ) this.EndTagIfNecessary(contentList); + return contentList; }; @@ -2718,6 +2735,8 @@ export class InkParser extends StringParser { this.InnerExpression, ]; + let wasTagActiveAtStartOfScope = this.tagActive; + // Adapted from "OneOf" structuring rule except that in // order for the rule to succeed, it has to maximally // cover the entire string within the { }. Used to From 85d2d5a5120bb0d8ce862d6bf11782aa16c9841e Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 12:28:21 +0200 Subject: [PATCH 23/36] compiler/StringParser/StringParserState.cs --- src/compiler/Parser/StringParser/StringParserElement.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/Parser/StringParser/StringParserElement.ts b/src/compiler/Parser/StringParser/StringParserElement.ts index ba7fa18be..7ea1d76de 100644 --- a/src/compiler/Parser/StringParser/StringParserElement.ts +++ b/src/compiler/Parser/StringParser/StringParserElement.ts @@ -29,5 +29,6 @@ export class StringParserElement { this.characterInLineIndex = fromElement.characterInLineIndex; this.lineIndex = fromElement.lineIndex; this.reportedErrorInScope = fromElement.reportedErrorInScope; + this.customFlags = fromElement.customFlags; }; } From 455177add521bef38aa03c3a90706ffaccd19b8c Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 15:10:45 +0200 Subject: [PATCH 24/36] compiler/ParsedHierarchy/TunnelOnwards.cs --- .../Parser/ParsedHierarchy/TunnelOnwards.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/compiler/Parser/ParsedHierarchy/TunnelOnwards.ts b/src/compiler/Parser/ParsedHierarchy/TunnelOnwards.ts index 47387f6af..62ce149a3 100644 --- a/src/compiler/Parser/ParsedHierarchy/TunnelOnwards.ts +++ b/src/compiler/Parser/ParsedHierarchy/TunnelOnwards.ts @@ -1,11 +1,14 @@ import { Container as RuntimeContainer } from "../../../engine/Container"; import { ControlCommand as RuntimeControlCommand } from "../../../engine/ControlCommand"; import { Divert } from "./Divert/Divert"; +import { Divert as RuntimeDivert } from "../../../engine/Divert"; import { DivertTargetValue } from "../../../engine/Value"; import { ParsedObject } from "./Object"; import { InkObject as RuntimeObject } from "../../../engine/Object"; import { Story } from "./Story"; import { Void } from "../../../engine/Void"; +import { asOrNull } from "../../../engine/TypeAssertion"; +import { VariableReference } from "../../../engine/VariableReference"; export class TunnelOnwards extends ParsedObject { private _overrideDivertTarget: DivertTargetValue | null = null; @@ -72,10 +75,17 @@ export class TunnelOnwards extends ParsedObject { } } } - - // Finally, divert to the requested target - this._overrideDivertTarget = new DivertTargetValue(); - container.AddContent(this._overrideDivertTarget); + // Supply the divert target for the tunnel onwards target, either variable or more commonly, the explicit name + // var returnDivertObj = returnRuntimeObj as Runtime.Divert; + let returnDivertObj = asOrNull(returnRuntimeObj, RuntimeDivert) + if( returnDivertObj != null && returnDivertObj.hasVariableTarget ) { + var runtimeVarRef = new VariableReference (returnDivertObj.variableDivertName); + container.AddContent(runtimeVarRef); + } else { + this._overrideDivertTarget = new DivertTargetValue (); + container.AddContent (this._overrideDivertTarget); + } + } else { // No divert after tunnel onwards container.AddContent(new Void()); From 00b61bbe05b8a5c5e39130a1deac7cbf1664c919 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 15:54:31 +0200 Subject: [PATCH 25/36] typos --- src/compiler/Parser/InkParser.ts | 13 +++++++------ .../Parser/ParsedHierarchy/TunnelOnwards.ts | 15 ++++++++------- src/engine/Story.ts | 2 +- src/tests/specs/ink/Choices.spec.ts | 4 ++-- src/tests/specs/ink/Diverts.spec.ts | 3 ++- src/tests/specs/ink/Tags.spec.ts | 8 ++++---- src/tests/specs/inkjs/engine/Tags.spec.ts | 5 +++-- 7 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/compiler/Parser/InkParser.ts b/src/compiler/Parser/InkParser.ts index c3c2009e5..be555f2e6 100644 --- a/src/compiler/Parser/InkParser.ts +++ b/src/compiler/Parser/InkParser.ts @@ -461,7 +461,7 @@ export class InkParser extends StringParser { this.Expect(this.String("]"), "closing ']' for weave-style option"); - this.EndTagIfNecessary(startContent); + this.EndTagIfNecessary(optionOnlyContent); let innerTextAndLogic = this.Parse( this.MixedTextAndLogic @@ -1049,9 +1049,10 @@ export class InkParser extends StringParser { // but is in fact entirely a tag, then let's not append // a newline, since we want the tag (or tags) to be associated // with the line below rather than being completely independent. - let lineIsPureTag = result.length > 0 && result[0] instanceof Tag && result[0].isStart; + let lineIsPureTag = + result.length > 0 && result[0] instanceof Tag && result[0].isStart; - if(lineIsPureTag){ + if (!lineIsPureTag) { result.push(new Text("\n")); } @@ -1086,7 +1087,7 @@ export class InkParser extends StringParser { if (results === null) { results = []; } - + // End previously active tag if necessary this.EndTagIfNecessary(results); @@ -2654,7 +2655,7 @@ export class InkParser extends StringParser { ) as ParsedObject; if (logic === null) { - this.parsingStringExpression = wasParsingString + this.parsingStringExpression = wasParsingString; return null; } @@ -2680,7 +2681,7 @@ export class InkParser extends StringParser { // When logic ends in (1) we still want tag to continue. // When logic ends in (2) we want to auto-end the tag. // Side note: we simply disallow tags within strings. - if( !wasTagActive ) this.EndTagIfNecessary(contentList); + if (!wasTagActive) this.EndTagIfNecessary(contentList); return contentList; }; diff --git a/src/compiler/Parser/ParsedHierarchy/TunnelOnwards.ts b/src/compiler/Parser/ParsedHierarchy/TunnelOnwards.ts index 62ce149a3..2f482dcc5 100644 --- a/src/compiler/Parser/ParsedHierarchy/TunnelOnwards.ts +++ b/src/compiler/Parser/ParsedHierarchy/TunnelOnwards.ts @@ -77,15 +77,16 @@ export class TunnelOnwards extends ParsedObject { } // Supply the divert target for the tunnel onwards target, either variable or more commonly, the explicit name // var returnDivertObj = returnRuntimeObj as Runtime.Divert; - let returnDivertObj = asOrNull(returnRuntimeObj, RuntimeDivert) - if( returnDivertObj != null && returnDivertObj.hasVariableTarget ) { - var runtimeVarRef = new VariableReference (returnDivertObj.variableDivertName); - container.AddContent(runtimeVarRef); + let returnDivertObj = asOrNull(returnRuntimeObj, RuntimeDivert); + if (returnDivertObj != null && returnDivertObj.hasVariableTarget) { + let runtimeVarRef = new VariableReference( + returnDivertObj.variableDivertName + ); + container.AddContent(runtimeVarRef); } else { - this._overrideDivertTarget = new DivertTargetValue (); - container.AddContent (this._overrideDivertTarget); + this._overrideDivertTarget = new DivertTargetValue(); + container.AddContent(this._overrideDivertTarget); } - } else { // No divert after tunnel onwards container.AddContent(new Void()); diff --git a/src/engine/Story.ts b/src/engine/Story.ts index 411be469f..39c951f0d 100644 --- a/src/engine/Story.ts +++ b/src/engine/Story.ts @@ -895,7 +895,7 @@ export class Story extends InkObject { asOrNull(this.state.PeekEvaluationStack(), Tag) ) { let tag = asOrNull(this.state.PopEvaluationStack(), Tag); - if (tag) tags.unshift(tag.text); + if (tag) tags.push(tag.text); } return choiceOnlyStrVal.value; } diff --git a/src/tests/specs/ink/Choices.spec.ts b/src/tests/specs/ink/Choices.spec.ts index dcce75539..66c2c3fd5 100644 --- a/src/tests/specs/ink/Choices.spec.ts +++ b/src/tests/specs/ink/Choices.spec.ts @@ -271,10 +271,10 @@ describe("Choices", () => { //TestTagsInChoice it("tests dynamic tags in choice", () => { - loadStory("tags_in_choice"); + compileStory("tags_in_choice"); context.story.Continue(); - expect(context.story.currentTags).toEqual(["one", "two"]); + expect(context.story.currentTags.length).toBe(0); expect(context.story.currentChoices.length).toBe(1); expect(context.story.currentChoices[0].tags).toEqual(["one", "two"]); diff --git a/src/tests/specs/ink/Diverts.spec.ts b/src/tests/specs/ink/Diverts.spec.ts index ac215ad25..b3ea1b60c 100644 --- a/src/tests/specs/ink/Diverts.spec.ts +++ b/src/tests/specs/ink/Diverts.spec.ts @@ -178,7 +178,8 @@ describe("Diverts", () => { // TestTunnelOnwardsToVariableDivertTarget it("tests variable divert target in tunnel onward", () => { - loadStory("tunnel_onwards_to_variable_divert_target"); + compileStory("tunnel_onwards_to_variable_divert_target"); + expect(context.story.ContinueMaximally()).toMatch( "This is outer\nThis is the_esc\n" ); diff --git a/src/tests/specs/ink/Tags.spec.ts b/src/tests/specs/ink/Tags.spec.ts index c119b13fa..31b4ee4a8 100644 --- a/src/tests/specs/ink/Tags.spec.ts +++ b/src/tests/specs/ink/Tags.spec.ts @@ -26,7 +26,7 @@ describe("Tags", () => { // TestTags it("tests string constants", () => { - loadStory("tags"); + compileStory("tags"); let globalTags = ["author: Joe", "title: My Great Story"]; let knotTags = ["knot tag"]; @@ -51,7 +51,7 @@ describe("Tags", () => { //TestTagsInSeq it("tests tags in a sequence", () => { - loadStory("tags_in_seq"); + compileStory("tags_in_seq"); expect(context.story.Continue()).toBe("A red sequence.\n"); expect(context.story.currentTags).toEqual(["red"]); @@ -62,9 +62,9 @@ describe("Tags", () => { //TestTagsDynamicContent it("tests dynamic content in tags", () => { - loadStory("tags_dynamic_content"); + compileStory("tags_dynamic_content"); expect(context.story.Continue()).toBe("tag\n"); expect(context.story.currentTags).toEqual(["pic8red.jpg"]); }); -}); +}); \ No newline at end of file diff --git a/src/tests/specs/inkjs/engine/Tags.spec.ts b/src/tests/specs/inkjs/engine/Tags.spec.ts index 7209ba8c0..2c0a55aff 100644 --- a/src/tests/specs/inkjs/engine/Tags.spec.ts +++ b/src/tests/specs/inkjs/engine/Tags.spec.ts @@ -4,7 +4,8 @@ describe("Tags", () => { let context: testsUtils.TestContext; beforeEach(() => { - context = testsUtils.fromJsonTestContext("tests", "inkjs"); + // context = testsUtils.fromJsonTestContext("tests", "inkjs"); + context = testsUtils.makeDefaultTestContext("tests", "inkjs", true); context.story.allowExternalFunctionFallbacks = true; }); @@ -51,7 +52,7 @@ describe("Tags", () => { context.story.Continue(); expect(context.story.currentChoices.length).toEqual(1); - expect(context.story.currentChoices[0].text).toEqual("a choice a tag"); //weird https://discord.com/channels/329929050866843648/1032209859749359646/1032306385200877710 + expect(context.story.currentChoices[0].text).toEqual("a choice"); expect(context.story.currentTags.length).toEqual(0); context.story.ChooseChoiceIndex(0); From 952ab96f2ff8a3869392cd9335c8b5525a44eff4 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 16:07:59 +0200 Subject: [PATCH 26/36] C# --- src/engine/StoryState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/StoryState.ts b/src/engine/StoryState.ts index b955f53b5..366085317 100644 --- a/src/engine/StoryState.ts +++ b/src/engine/StoryState.ts @@ -357,7 +357,7 @@ export class StoryState { sb.Append(strVal.value); } } else { - let tag = outputObj as Tag; + let tag = asOrNull(outputObj, Tag); if (tag != null && tag.text != null && tag.text.length > 0) { this._currentTags.push(tag.text); // tag.text has whitespae already cleaned } From d17354e9dd619b1428fef450e087dbb773222bd1 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 16:09:46 +0200 Subject: [PATCH 27/36] linter --- src/tests/specs/ink/Diverts.spec.ts | 2 +- src/tests/specs/ink/Tags.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/specs/ink/Diverts.spec.ts b/src/tests/specs/ink/Diverts.spec.ts index b3ea1b60c..6c6bb1ef1 100644 --- a/src/tests/specs/ink/Diverts.spec.ts +++ b/src/tests/specs/ink/Diverts.spec.ts @@ -179,7 +179,7 @@ describe("Diverts", () => { // TestTunnelOnwardsToVariableDivertTarget it("tests variable divert target in tunnel onward", () => { compileStory("tunnel_onwards_to_variable_divert_target"); - + expect(context.story.ContinueMaximally()).toMatch( "This is outer\nThis is the_esc\n" ); diff --git a/src/tests/specs/ink/Tags.spec.ts b/src/tests/specs/ink/Tags.spec.ts index 31b4ee4a8..96ea29439 100644 --- a/src/tests/specs/ink/Tags.spec.ts +++ b/src/tests/specs/ink/Tags.spec.ts @@ -67,4 +67,4 @@ describe("Tags", () => { expect(context.story.Continue()).toBe("tag\n"); expect(context.story.currentTags).toEqual(["pic8red.jpg"]); }); -}); \ No newline at end of file +}); From 3f47dcfa93f3a02bcbafdb41bf5efd36f2a08394 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 19:07:36 +0200 Subject: [PATCH 28/36] fixed all tests --- src/engine/Story.ts | 9 ++++----- .../inkfiles/compiled/choices/tags_in_choice.ink.json | 2 +- src/tests/specs/ink/Choices.spec.ts | 6 +++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/engine/Story.ts b/src/engine/Story.ts index 39c951f0d..0d395ff8b 100644 --- a/src/engine/Story.ts +++ b/src/engine/Story.ts @@ -892,7 +892,7 @@ export class Story extends InkObject { while ( this.state.evaluationStack.length > 0 && - asOrNull(this.state.PeekEvaluationStack(), Tag) + asOrNull(this.state.PeekEvaluationStack(), Tag) != null ) { let tag = asOrNull(this.state.PopEvaluationStack(), Tag); if (tag) tags.push(tag.text); @@ -945,9 +945,7 @@ export class Story extends InkObject { choice.sourcePath = choicePoint.path.toString(); choice.isInvisibleDefault = choicePoint.isInvisibleDefault; choice.threadAtGeneration = this.state.callStack.ForkThread(); - - choice.tags = tags; - + choice.tags = tags.reverse(); //C# is a stack choice.text = (startText + choiceOnlyText).replace(/^[ \t]+|[ \t]+$/g, ""); return choice; @@ -1240,12 +1238,13 @@ export class Story extends InkObject { ); // Pushing to the evaluation stack means it gets picked up // when a Choice is generated from the next Choice Point. - this.state.PushToOutputStream(choiceTag); + this.state.PushEvaluationStack(choiceTag); } else { // Otherwise! Simply push EndTag, so that in the output stream we // have a structure of: [BeginTag, "the tag content", EndTag] this.state.PushToOutputStream(evalCommand); } + break; } case ControlCommand.CommandType.EndString: { diff --git a/src/tests/inkfiles/compiled/choices/tags_in_choice.ink.json b/src/tests/inkfiles/compiled/choices/tags_in_choice.ink.json index bec3c3ea7..e38791b8d 100644 --- a/src/tests/inkfiles/compiled/choices/tags_in_choice.ink.json +++ b/src/tests/inkfiles/compiled/choices/tags_in_choice.ink.json @@ -1 +1 @@ -{"inkVersion":21,"root":[[["ev",{"^->":"0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","str","^two ","#","^two","/#out","/str","/ev",{"*":"0.c-0","flg":6},{"s":["^one ","#","^one ","/#out",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":"0.0.s"},[{"#n":"$r2"}],"^ three ","#","^three ","/#","end","\n",{"->":"0.g-0"},{"#f":5}],"g-0":["done",{"#f":5}]}],"done",{"#f":1}],"listDefs":{}} \ No newline at end of file +{"inkVersion":21,"root":[[["ev",{"^->":"0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","str","^two ","#","^two","/#","/str","/ev",{"*":"0.c-0","flg":6},{"s":["^one ","#","^one ","/#",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":"0.0.s"},[{"#n":"$r2"}],"^ three ","#","^three ","/#","end","\n",{"->":"0.g-0"},{"#f":5}],"g-0":["done",{"#f":5}]}],"done",{"#f":1}],"listDefs":{}} \ No newline at end of file diff --git a/src/tests/specs/ink/Choices.spec.ts b/src/tests/specs/ink/Choices.spec.ts index 66c2c3fd5..ee0679c3c 100644 --- a/src/tests/specs/ink/Choices.spec.ts +++ b/src/tests/specs/ink/Choices.spec.ts @@ -270,10 +270,10 @@ describe("Choices", () => { }); //TestTagsInChoice - it("tests dynamic tags in choice", () => { - compileStory("tags_in_choice"); + it("tests tags in choice", () => { + compileStory("tags_in_choice", true); context.story.Continue(); - + expect(context.story.currentTags.length).toBe(0); expect(context.story.currentChoices.length).toBe(1); expect(context.story.currentChoices[0].tags).toEqual(["one", "two"]); From 7422bb9509e059fa89f73679c5f7f52255fe5ed9 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Thu, 20 Oct 2022 19:07:55 +0200 Subject: [PATCH 29/36] linter --- src/tests/specs/ink/Choices.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/specs/ink/Choices.spec.ts b/src/tests/specs/ink/Choices.spec.ts index ee0679c3c..bd2ca6ba5 100644 --- a/src/tests/specs/ink/Choices.spec.ts +++ b/src/tests/specs/ink/Choices.spec.ts @@ -273,7 +273,7 @@ describe("Choices", () => { it("tests tags in choice", () => { compileStory("tags_in_choice", true); context.story.Continue(); - + expect(context.story.currentTags.length).toBe(0); expect(context.story.currentChoices.length).toBe(1); expect(context.story.currentChoices[0].tags).toEqual(["one", "two"]); From e47d7eb6cb459867d9314f4462ed6a0350cbbc17 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Fri, 21 Oct 2022 14:24:54 +0200 Subject: [PATCH 30/36] version + fix inkjs-compiler --- package.json | 2 +- script/inkjs-compiler.ts | 44 +++++++++++++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index fb7d04441..2b0862ec0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "inkjs", - "version": "2.1.0", + "version": "2.2.0", "description": "A javascript port of inkle's ink scripting language (http://www.inklestudios.com/ink/)", "main": "dist/ink-full.js", "types": "ink.d.ts", diff --git a/script/inkjs-compiler.ts b/script/inkjs-compiler.ts index 36da922ae..4ae0a3ac2 100644 --- a/script/inkjs-compiler.ts +++ b/script/inkjs-compiler.ts @@ -55,10 +55,19 @@ if(jsonStory && write){ } if(jsonStory && play){ - const prompt = readline.createInterface({ + const rl = readline.createInterface({ input: process.stdin, //or fileStream output: process.stdout }); + + const prompt = () => { + return new Promise((resolve, reject) => { + rl.question('?> ', (answer: string) => { + resolve(answer) + }) + }) + } + const play = async () =>{ const story = new Story(jsonStory); @@ -78,18 +87,39 @@ if(jsonStory && play){ for (let i=0; i 0){ + process.stdout.write( " # tags: " + story.currentChoices[i].tags!.join(", ") ); + } + process.stdout.write("\n") } process.stdout.write("?> "); - for await (const line of prompt) { - const choiceIndex = parseInt(line) - 1; - story.ChooseChoiceIndex(choiceIndex); - } + do{ + const answer: string = await prompt(); + if(answer.startsWith("->")){ + const target = answer.slice(2).trim() + try{ + story.ChoosePathString(target) + break; + }catch(e){ + process.stdout.write(e.message + '\n'); + } + }else{ + const choiceIndex = parseInt(answer) - 1; + try{ + story.ChooseChoiceIndex(choiceIndex); + break; + }catch(e){ + process.stdout.write(e.message + '\n'); + } + } + }while(true); }while(true); } play().then(()=>{ - process.stdout.write("\nDONE.") + process.stdout.write("DONE.\n") process.exit(0); }); From 3aef5e4fd32a3a6bf7763684b778bfa6de9d4e2f Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Fri, 21 Oct 2022 15:13:47 +0200 Subject: [PATCH 31/36] port lookAheadSafe = true --- src/engine/Story.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/Story.ts b/src/engine/Story.ts index 0d395ff8b..ca71ed0b6 100644 --- a/src/engine/Story.ts +++ b/src/engine/Story.ts @@ -1932,7 +1932,7 @@ export class Story extends InkObject { public BindExternalFunction( funcName: string, func: Story.ExternalFunction, - lookaheadSafe: boolean + lookaheadSafe: boolean = true ) { this.Assert(func != null, "Can't bind a null function"); From a511db78c136c246d851b0240f090e964fc849ee Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Fri, 21 Oct 2022 15:25:52 +0200 Subject: [PATCH 32/36] from 13 to 6 linter warnings --- src/compiler/Parser/InkParser.ts | 1 - src/tests/specs/common.ts | 8 -------- src/tests/specs/ink/Choices.spec.ts | 4 ---- src/tests/specs/ink/Conditions.spec.ts | 1 - src/tests/specs/ink/Diverts.spec.ts | 4 ---- src/tests/specs/ink/Parser.spec.ts | 2 -- src/tests/specs/ink/Tags.spec.ts | 4 ---- 7 files changed, 24 deletions(-) diff --git a/src/compiler/Parser/InkParser.ts b/src/compiler/Parser/InkParser.ts index be555f2e6..2fe60fcf2 100644 --- a/src/compiler/Parser/InkParser.ts +++ b/src/compiler/Parser/InkParser.ts @@ -48,7 +48,6 @@ import { } from "./StringParser/StringParser"; import { StringParserElement } from "./StringParser/StringParserElement"; import { Tag } from "./ParsedHierarchy/Tag"; -import { Tag as RuntimeTag } from "../../engine/Tag"; import { Text } from "./ParsedHierarchy/Text"; import { TunnelOnwards } from "./ParsedHierarchy/TunnelOnwards"; import { VariableAssignment } from "./ParsedHierarchy/Variable/VariableAssignment"; diff --git a/src/tests/specs/common.ts b/src/tests/specs/common.ts index 3a4b427f4..26407a274 100644 --- a/src/tests/specs/common.ts +++ b/src/tests/specs/common.ts @@ -125,14 +125,6 @@ export function fromJsonTestContext( testingErrors: boolean = false ) { let context = new TestContext(testingErrors); - - let rootDir: string; - if (category) { - rootDir = path.join(inkBaselinePath, category); - } else { - rootDir = path.join(inkBaselinePath); - } - let jsonContent = loadJSONFile(name, category); context.story = new Story(jsonContent); context.bytecode = context.story.ToJson(); diff --git a/src/tests/specs/ink/Choices.spec.ts b/src/tests/specs/ink/Choices.spec.ts index bd2ca6ba5..cf4c31d02 100644 --- a/src/tests/specs/ink/Choices.spec.ts +++ b/src/tests/specs/ink/Choices.spec.ts @@ -3,10 +3,6 @@ import * as testsUtils from "../common"; describe("Choices", () => { let context: testsUtils.TestContext; - function loadStory(name: any) { - context = testsUtils.fromJsonTestContext(name, "choices"); - } - function compileStory( name: string, countAllVisits: boolean = false, diff --git a/src/tests/specs/ink/Conditions.spec.ts b/src/tests/specs/ink/Conditions.spec.ts index 740abf64a..f62d146ae 100644 --- a/src/tests/specs/ink/Conditions.spec.ts +++ b/src/tests/specs/ink/Conditions.spec.ts @@ -1,5 +1,4 @@ import * as testsUtils from "../common"; -import { CompilerOptions } from "../../../compiler/CompilerOptions"; describe("Conditions", () => { let context: testsUtils.TestContext; diff --git a/src/tests/specs/ink/Diverts.spec.ts b/src/tests/specs/ink/Diverts.spec.ts index 6c6bb1ef1..826c600d2 100644 --- a/src/tests/specs/ink/Diverts.spec.ts +++ b/src/tests/specs/ink/Diverts.spec.ts @@ -3,10 +3,6 @@ import * as testsUtils from "../common"; describe("Diverts", () => { let context: testsUtils.TestContext; - function loadStory(name: any) { - context = testsUtils.fromJsonTestContext(name, "diverts"); - } - function compileStory( name: string, countAllVisits: boolean = false, diff --git a/src/tests/specs/ink/Parser.spec.ts b/src/tests/specs/ink/Parser.spec.ts index de1d85487..58c26f83b 100644 --- a/src/tests/specs/ink/Parser.spec.ts +++ b/src/tests/specs/ink/Parser.spec.ts @@ -1,5 +1,3 @@ -import * as testsUtils from "../common"; - import { InkParser } from "../../../compiler/Parser/InkParser"; import { StringParser } from "../../../compiler/Parser/StringParser/StringParser"; import { CharacterRange } from "../../../compiler/Parser/CharacterRange"; diff --git a/src/tests/specs/ink/Tags.spec.ts b/src/tests/specs/ink/Tags.spec.ts index 96ea29439..11c56c5a3 100644 --- a/src/tests/specs/ink/Tags.spec.ts +++ b/src/tests/specs/ink/Tags.spec.ts @@ -3,10 +3,6 @@ import * as testsUtils from "../common"; describe("Tags", () => { let context: testsUtils.TestContext; - function loadStory(name: any) { - context = testsUtils.fromJsonTestContext(name, "tags"); - } - function compileStory( name: string, countAllVisits: boolean = false, From 84fe3b1204351e5d024eabae3d58c63ffa6b39c5 Mon Sep 17 00:00:00 2001 From: Ju / smwhr Date: Fri, 21 Oct 2022 15:41:25 +0200 Subject: [PATCH 33/36] port lookAhead default params --- src/engine/Story.ts | 4 ++-- src/tests/specs/ink/Bindings.spec.ts | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/engine/Story.ts b/src/engine/Story.ts index ca71ed0b6..95a05e228 100644 --- a/src/engine/Story.ts +++ b/src/engine/Story.ts @@ -1908,7 +1908,7 @@ export class Story extends InkObject { public BindExternalFunctionGeneral( funcName: string, func: Story.ExternalFunction, - lookaheadSafe: boolean + lookaheadSafe: boolean = true ) { this.IfAsyncWeCant("bind an external function"); this.Assert( @@ -1932,7 +1932,7 @@ export class Story extends InkObject { public BindExternalFunction( funcName: string, func: Story.ExternalFunction, - lookaheadSafe: boolean = true + lookaheadSafe: boolean = false ) { this.Assert(func != null, "Can't bind a null function"); diff --git a/src/tests/specs/ink/Bindings.spec.ts b/src/tests/specs/ink/Bindings.spec.ts index 52c8a98a0..a8e490400 100644 --- a/src/tests/specs/ink/Bindings.spec.ts +++ b/src/tests/specs/ink/Bindings.spec.ts @@ -97,6 +97,8 @@ describe("Bindings", () => { // SAFE Lookahead compileStory("lookup_safe_or_not"); + // Lookahead SAFE - should get multiple calls to the ext function, + // one for lookahead on first line, one "for real" on second line. let callCount = 0; context.story.BindExternalFunction( "myAction", @@ -109,7 +111,8 @@ describe("Bindings", () => { context.story.ContinueMaximally(); expect(callCount).toBe(2); - // UNSAFE Lookahead + // Lookahead UNSAFE - when it sees the function, it should break out early + // and stop lookahead, making sure that the action is only called for the second line. callCount = 0; context.story.ResetState(); context.story.UnbindExternalFunction("myAction"); From a6b81f838c4df33ee28f834ed87b4ad1ed1b356d Mon Sep 17 00:00:00 2001 From: Ju/Smwhr Date: Fri, 21 Oct 2022 15:55:02 +0200 Subject: [PATCH 34/36] Update version comparison table --- README.md | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 979eeab93..ab751b9f9 100644 --- a/README.md +++ b/README.md @@ -155,21 +155,22 @@ See [Differences with the C# Compiler](docs/compiler-differences.md). ## Compatibility table -| _inklecate_ version | _inkjs_ version | -| :-----------------: | :-------------: | -| 0.3.5 – 0.4.0 | 1.0.0 – 1.1.0 | -| 0.4.1 – 0.5.0 | 1.1.1 – 1.1.3 | -| 0.5.1 | 1.2.0 | -| 0.6.0 | 1.3.0 | -| 0.6.1 | 1.4.0 – 1.4.1 | -| 0.6.2 | 1.4.2 | -| 0.6.3 | 1.4.3 | -| 0.6.4 | 1.4.4 – 1.4.6 | -| 0.7.0 | 1.5.0 – 1.5.1 | -| 0.7.1 | 1.5.2 | -| 0.7.2 – 0.7.4 | 1.6.0 | -| 0.8.0 – 0.8.1 | 1.7.1 – 1.7.2 | -| 0.8.2 | 1.8.0 – 1.9.0 | -| 0.8.3 | 1.10.0 – 1.10.5 | -| 0.9.0 | 1.11.0 | -| 1.0.0 | 2.0.0 | +| _inklecate_ version | _inkjs_ version | _json_ version | +| :-----------------: | :-------------: | :------------: | +| 0.3.5 – 0.4.0 | 1.0.0 – 1.1.0 | 18 | +| 0.4.1 – 0.5.0 | 1.1.1 – 1.1.3 | | +| 0.5.1 | 1.2.0 | | +| 0.6.0 | 1.3.0 | | +| 0.6.1 | 1.4.0 – 1.4.1 | | +| 0.6.2 | 1.4.2 | | +| 0.6.3 | 1.4.3 | | +| 0.6.4 | 1.4.4 – 1.4.6 | | +| 0.7.0 | 1.5.0 – 1.5.1 | | +| 0.7.1 | 1.5.2 | | +| 0.7.2 – 0.7.4 | 1.6.0 | | +| 0.8.0 – 0.8.1 | 1.7.1 – 1.7.2 | | +| 0.8.2 | 1.8.0 – 1.9.0 | | +| 0.8.3 | 1.10.0 – 1.10.5 | | +| 0.9.0 | 1.11.0 | 19 | +| 1.0.0 | 2.0.0 | 20 | +| 1.1.1 | 2.2.0 | 21 | From 7c5b97ff70911705767ff350bb516e6739e45173 Mon Sep 17 00:00:00 2001 From: Ju/Smwhr Date: Fri, 21 Oct 2022 15:56:05 +0200 Subject: [PATCH 35/36] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ab751b9f9..2af5ca4d1 100644 --- a/README.md +++ b/README.md @@ -172,5 +172,5 @@ See [Differences with the C# Compiler](docs/compiler-differences.md). | 0.8.2 | 1.8.0 – 1.9.0 | | | 0.8.3 | 1.10.0 – 1.10.5 | | | 0.9.0 | 1.11.0 | 19 | -| 1.0.0 | 2.0.0 | 20 | +| 1.0.0 | 2.0.0 - 2.1.0 | 20 | | 1.1.1 | 2.2.0 | 21 | From 53e806f56e3baec50ee9b25af978c7177f8d7a02 Mon Sep 17 00:00:00 2001 From: Ju/Smwhr Date: Fri, 21 Oct 2022 16:07:12 +0200 Subject: [PATCH 36/36] Delete test.ts --- script/test.ts | 40 ---------------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 script/test.ts diff --git a/script/test.ts b/script/test.ts deleted file mode 100644 index a83cf9ef2..000000000 --- a/script/test.ts +++ /dev/null @@ -1,40 +0,0 @@ -// import { PRNG } from '../src/engine/PRNG'; - - - -// const clamp = (minInt: number, maxInt: number) => (next: number) => { -// let randomRange = maxInt - minInt + 1; -// let chosenValue = (next % randomRange) + minInt; -// return chosenValue; -// } - -// const listClamp = (count: number) => (next: number) => next % count; - - -// //const clamper = clamp(0,7); -// const clamper = listClamp(7); -// const n = 0 - -// for (let i = n; i < n + 100; i++) { -// const random = new PRNG(i) -// const nextRandom = random.next() -// let chosen = clamper(nextRandom); -// console.log(nextRandom, chosen); -// } - - -import { Compiler } from '../src/compiler/Compiler'; - -const mainInk = ` -{~1|2|3|4|5|6|7} -LIST lst = (a),(b),(c),(d),(e),(f),(g) -{LIST_RANDOM(lst)} -`; - -const c = new Compiler(mainInk) -const rstory = c.Compile(); - -while(rstory.canContinue){ - const t = rstory.Continue(); - console.log(t); -} \ No newline at end of file