From 0d6eba5bfd7231fe36eccff7fa7e53f64e630497 Mon Sep 17 00:00:00 2001 From: Graham Nelson Date: Tue, 6 Sep 2022 23:03:04 +0100 Subject: [PATCH] The dawn of DialogueKit --- README.md | 3 +- build.txt | 4 +- colony.txt | 1 + docs-src/html/panels_kits.html | 6 ++ docs/DialogueKit/S-drc.html | 68 +++++++++++++++ docs/DialogueKit/index.html | 64 ++++++++++++++ docs/assertions-module/7-dlg.html | 24 ++++++ docs/assertions-module/8-cu.html | 2 +- docs/core-module/1-inaa.html | 20 +++++ docs/kinds-module/2-fk.html | 4 + docs/runtime-module/2-hrr.html | 14 ++++ docs/runtime-module/5-kc.html | 10 +++ docs/supervisor-module/5-ps2.html | 5 +- docs/syntax-module/2-st.html | 4 +- docs/syntax-module/3-snt.html | 1 + docs/values-module/2-rvl.html | 4 + .../Chapter 5/Project Services.w | 5 +- inform7/Figures/memory-diagnostics.txt | 78 +++++++++--------- inform7/Figures/timings-diagnostics.txt | 62 +++++++------- .../BasicInformExtrasKit/kit_metadata.json | 2 +- .../Inter/BasicInformKit/kit_metadata.json | 2 +- .../Inter/CommandParserKit/kit_metadata.json | 2 +- inform7/Internal/Inter/DialogueKit/Contents.w | 9 ++ .../Inter/DialogueKit/Sections/Director.i6t | 10 +++ .../Internal/Inter/DialogueKit/arch-16.interb | Bin 0 -> 3834 bytes .../Inter/DialogueKit/arch-16d.interb | Bin 0 -> 3855 bytes .../Internal/Inter/DialogueKit/arch-32.interb | Bin 0 -> 3840 bytes .../Inter/DialogueKit/arch-32d.interb | Bin 0 -> 3861 bytes .../Inter/DialogueKit/kinds/Dialogue.neptune | 33 ++++++++ .../Inter/DialogueKit/kit_metadata.json | 13 +++ .../EnglishLanguageKit/kit_metadata.json | 2 +- .../Inter/WorldModelKit/kit_metadata.json | 2 +- .../_Results_Ideal/PM_EmptyDialogueClause.txt | 4 - .../PM_MisbracketedDialogueClause.txt | 8 +- .../assertions-module/Chapter 7/Dialogue.w | 24 ++++++ .../Inform-Only Nodes and Annotations.w | 20 +++++ inform7/runtime-module/Chapter 2/Hierarchy.w | 14 ++++ .../Chapter 5/Kind Constructors.w | 10 +++ inform7/values-module/Chapter 2/Rvalues.w | 4 + scripts/inform.mkscript | 1 + scripts/inform.rmscript | 1 + .../kinds-module/Chapter 2/Familiar Kinds.w | 4 + .../syntax-module/Chapter 2/Syntax Trees.w | 2 + services/syntax-module/Chapter 3/Sentences.w | 1 + 44 files changed, 460 insertions(+), 87 deletions(-) create mode 100644 docs/DialogueKit/S-drc.html create mode 100644 docs/DialogueKit/index.html create mode 100644 inform7/Internal/Inter/DialogueKit/Contents.w create mode 100644 inform7/Internal/Inter/DialogueKit/Sections/Director.i6t create mode 100644 inform7/Internal/Inter/DialogueKit/arch-16.interb create mode 100644 inform7/Internal/Inter/DialogueKit/arch-16d.interb create mode 100644 inform7/Internal/Inter/DialogueKit/arch-32.interb create mode 100644 inform7/Internal/Inter/DialogueKit/arch-32d.interb create mode 100644 inform7/Internal/Inter/DialogueKit/kinds/Dialogue.neptune create mode 100644 inform7/Internal/Inter/DialogueKit/kit_metadata.json diff --git a/README.md b/README.md index 655f2145c..23ea45938 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Inform 7 -[Version](notes/versioning.md): 10.2.0-beta+6V51 'Krypton' (5 September 2022) +[Version](notes/versioning.md): 10.2.0-beta+6V52 'Krypton' (6 September 2022) ## About Inform @@ -121,6 +121,7 @@ The following webs are the source for kits of Inter code shipped with Inform (at * EnglishLanguageKit - Support for English as the natural language used - [★ Web](https://ganelson.github.io/inform/EnglishLanguageKit/index.html) * CommandParserKit - Support for parsing turn-by-turn commands in interactive fiction - [★ Web](https://ganelson.github.io/inform/CommandParserKit/index.html) * BasicInformExtrasKit - Additional support needed only if the Standard Rules are not used - [★ Web](https://ganelson.github.io/inform/BasicInformExtrasKit/index.html) +* DialogueKit - Additional support for dialogue (under construction) - [★ Web](https://ganelson.github.io/inform/DialogueKit/index.html) ### Extensions shipped with Inform diff --git a/build.txt b/build.txt index e67e70655..59ad66649 100644 --- a/build.txt +++ b/build.txt @@ -1,3 +1,3 @@ Prerelease: beta -Build Date: 5 September 2022 -Build Number: 6V51 +Build Date: 6 September 2022 +Build Number: 6V52 diff --git a/colony.txt b/colony.txt index cc58d5369..949d70629 100644 --- a/colony.txt +++ b/colony.txt @@ -63,6 +63,7 @@ web: "EnglishLanguageKit" at "inform7/Internal/Inter/EnglishLanguageKit" in "doc web: "CommandParserKit" at "inform7/Internal/Inter/CommandParserKit" in "docs/CommandParserKit" web: "BasicInformKit" at "inform7/Internal/Inter/BasicInformKit" in "docs/BasicInformKit" web: "BasicInformExtrasKit" at "inform7/Internal/Inter/BasicInformExtrasKit" in "docs/BasicInformExtrasKit" +web: "DialogueKit" at "inform7/Internal/Inter/DialogueKit" in "docs/DialogueKit" breadcrumbs: "Home: //overview//" web: "inblorb" at "inblorb" in "docs/inblorb" diff --git a/docs-src/html/panels_kits.html b/docs-src/html/panels_kits.html index 19713d814..c3c00539f 100644 --- a/docs-src/html/panels_kits.html +++ b/docs-src/html/panels_kits.html @@ -31,4 +31,10 @@

A kit of Inter code providing runtime support for interactive fiction projects with a command parser interface.

+
+ DialogueKit +

DialogueKit

+

A kit of Inter code eventually to provide runtime support for dialogue, an experimental + new feature of Inform which is not yet implemented.

+
diff --git a/docs/DialogueKit/S-drc.html b/docs/DialogueKit/S-drc.html new file mode 100644 index 000000000..c75fef050 --- /dev/null +++ b/docs/DialogueKit/S-drc.html @@ -0,0 +1,68 @@ + + + + Director Template + + + + + + + + + + + + + + + +
+ + +

Run-time support for dialogue.

+ +
+ +

§1. Placeholder.

+ +
+[ DirectorBegin;
+    rfalse;
+];
+
+ + +
+ + + diff --git a/docs/DialogueKit/index.html b/docs/DialogueKit/index.html new file mode 100644 index 000000000..d0d4fbd9c --- /dev/null +++ b/docs/DialogueKit/index.html @@ -0,0 +1,64 @@ + + + DialogueKit + + + + + + + + + + + + + + +
+ +

Inter-level support for dialogue in Inform projects. This is version 1.

+
+
+ +
+
+

Powered by Inweb.

+
+ + + diff --git a/docs/assertions-module/7-dlg.html b/docs/assertions-module/7-dlg.html index 2635a65c3..a037f8a0b 100644 --- a/docs/assertions-module/7-dlg.html +++ b/docs/assertions-module/7-dlg.html @@ -87,6 +87,7 @@ function togglePopup(material_id) { struct wording scene_name; struct parse_node *cue_at; struct heading *under_heading; + struct instance *as_instance; struct dialogue_beat *immediately_after; struct linked_list *some_time_after; of dialogue_beat @@ -99,6 +100,7 @@ function togglePopup(material_id) { typedef struct dialogue_line { struct wording line_name; + struct instance *as_instance; struct parse_node *line_at; struct wording speaker_text; struct wording speech_text; @@ -176,6 +178,17 @@ function togglePopup(material_id) { "which is not allowed. It can be anonymous, but otherwise can only have " "one name (either as a beat or as a scene, and not both)."); } + + wording W = db->beat_name; + if (Wordings::empty(W)) { + TEMPORARY_TEXT(faux_name) + WRITE_TO(faux_name, "beat-%d", db->allocation_id + 1); + W = Feeds::feed_text(faux_name); + DISCARD_TEXT(faux_name) + } + pcalc_prop *prop = Propositions::Abstract::to_create_something(K_dialogue_beat, W); + Assert::true(prop, CERTAIN_CE); + db->as_instance = Instances::latest(); return db; } @@ -326,6 +339,17 @@ function togglePopup(material_id) { precursor_dialogue_lines[L] = dl; for (int i=L+1; i<MAX_DIALOGUE_LINE_NESTING; i++) precursor_dialogue_lines[i] = NULL; + wording W = dl->line_name; + if (Wordings::empty(W)) { + TEMPORARY_TEXT(faux_name) + WRITE_TO(faux_name, "line-%d", dl->allocation_id + 1); + W = Feeds::feed_text(faux_name); + DISCARD_TEXT(faux_name) + } + pcalc_prop *prop = Propositions::Abstract::to_create_something(K_dialogue_line, W); + Assert::true(prop, CERTAIN_CE); + dl->as_instance = Instances::latest(); + return dl; } diff --git a/docs/assertions-module/8-cu.html b/docs/assertions-module/8-cu.html index 099b698b2..52abe2ccf 100644 --- a/docs/assertions-module/8-cu.html +++ b/docs/assertions-module/8-cu.html @@ -78,7 +78,7 @@ their existence. return CreationPredicates::is_a_const_up(Terms::new_variable(0)); } -pcalc_prop *Propositions::Abstract::to_create_something(kind *K, wording W) { +pcalc_prop *Propositions::Abstract::to_create_something(kind *K, wording W) { pcalc_prop *prop = Atoms::QUANTIFIER_new(exists_quantifier, 0, 0); if ((K) && (Kinds::eq(K, K_object) == FALSE)) prop = Propositions::concatenate(prop, diff --git a/docs/core-module/1-inaa.html b/docs/core-module/1-inaa.html index 425fb0f4f..92385d352 100644 --- a/docs/core-module/1-inaa.html +++ b/docs/core-module/1-inaa.html @@ -970,6 +970,8 @@ which compilation unit the node belongs. enum constant_activity_ANNOT activity: for constant values enum constant_binary_predicate_ANNOT binary_predicate: for constant values enum constant_constant_phrase_ANNOT constant_phrase: for constant values +enum constant_dialogue_beat_ANNOT dialogue_beat: for constant values +enum constant_dialogue_line_ANNOT dialogue_line: for constant values enum constant_enumeration_ANNOT int: which one from an enumerated kind enum constant_equation_ANNOT equation: for constant values enum constant_instance_ANNOT instance: for constant values @@ -1005,6 +1007,8 @@ which compilation unit the node belongs. DECLARE_ANNOTATION_FUNCTIONS(constant_activity, activity) DECLARE_ANNOTATION_FUNCTIONS(constant_binary_predicate, binary_predicate) DECLARE_ANNOTATION_FUNCTIONS(constant_constant_phrase, constant_phrase) +DECLARE_ANNOTATION_FUNCTIONS(constant_dialogue_beat, dialogue_beat) +DECLARE_ANNOTATION_FUNCTIONS(constant_dialogue_line, dialogue_line) DECLARE_ANNOTATION_FUNCTIONS(constant_equation, equation) DECLARE_ANNOTATION_FUNCTIONS(constant_instance, instance) DECLARE_ANNOTATION_FUNCTIONS(constant_local_variable, local_variable) @@ -1033,6 +1037,8 @@ which compilation unit the node belongs. MAKE_ANNOTATION_FUNCTIONS(constant_activity, activity) MAKE_ANNOTATION_FUNCTIONS(constant_binary_predicate, binary_predicate) MAKE_ANNOTATION_FUNCTIONS(constant_constant_phrase, constant_phrase) +MAKE_ANNOTATION_FUNCTIONS(constant_dialogue_beat, dialogue_beat) +MAKE_ANNOTATION_FUNCTIONS(constant_dialogue_line, dialogue_line) MAKE_ANNOTATION_FUNCTIONS(constant_equation, equation) MAKE_ANNOTATION_FUNCTIONS(constant_instance, instance) MAKE_ANNOTATION_FUNCTIONS(constant_local_variable, local_variable) @@ -1063,6 +1069,10 @@ which compilation unit the node belongs. Annotations::declare_type( constant_constant_phrase_ANNOT, CoreSyntax::write_constant_constant_phrase_ANNOT); Annotations::declare_type( + constant_dialogue_beat_ANNOT, CoreSyntax::write_constant_dialogue_beat_ANNOT); + Annotations::declare_type( + constant_dialogue_line_ANNOT, CoreSyntax::write_constant_dialogue_line_ANNOT); + Annotations::declare_type( constant_equation_ANNOT, CoreSyntax::write_constant_equation_ANNOT); Annotations::declare_type( constant_instance_ANNOT, CoreSyntax::write_constant_instance_ANNOT); @@ -1141,6 +1151,14 @@ which compilation unit the node belongs. WRITE("}"); } } +void CoreSyntax::write_constant_dialogue_beat_ANNOT(text_stream *OUT, parse_node *p) { + dialogue_beat *db = Node::get_constant_dialogue_beat(p); + if (db) WRITE(" {beat: %W}", db->beat_name); +} +void CoreSyntax::write_constant_dialogue_line_ANNOT(text_stream *OUT, parse_node *p) { + dialogue_line *dl = Node::get_constant_dialogue_line(p); + if (dl) WRITE(" {line: %W}", dl->line_name); +} void CoreSyntax::write_constant_equation_ANNOT(text_stream *OUT, parse_node *p) { equation *eqn = Node::get_constant_equation(p); if (eqn) WRITE(" {equation: %W}", eqn->equation_text); @@ -1305,6 +1323,8 @@ which compilation unit the node belongs. Annotations::allow(CONSTANT_NT, constant_activity_ANNOT); Annotations::allow(CONSTANT_NT, constant_binary_predicate_ANNOT); Annotations::allow(CONSTANT_NT, constant_constant_phrase_ANNOT); + Annotations::allow(CONSTANT_NT, constant_dialogue_beat_ANNOT); + Annotations::allow(CONSTANT_NT, constant_dialogue_line_ANNOT); Annotations::allow(CONSTANT_NT, constant_enumeration_ANNOT); Annotations::allow(CONSTANT_NT, constant_equation_ANNOT); Annotations::allow(CONSTANT_NT, constant_instance_ANNOT); diff --git a/docs/kinds-module/2-fk.html b/docs/kinds-module/2-fk.html index a3eb6c7f2..626050a49 100644 --- a/docs/kinds-module/2-fk.html +++ b/docs/kinds-module/2-fk.html @@ -179,6 +179,8 @@ feature in question is inactive, they will remain
+kind *K_dialogue_beat = NULL;
+kind *K_dialogue_line = NULL;
 kind *K_equation = NULL;
 kind *K_grammatical_gender = NULL;
 kind *K_natural_language = NULL;
@@ -265,6 +267,8 @@ it is. There is no need for speed here.
 
 kind **FamiliarKinds::known_kind(text_stream *sn) {
     IDENTIFIERS_CORRESPOND("ARITHMETIC_VALUE_TY", &K_arithmetic_value);
+    IDENTIFIERS_CORRESPOND("DIALOGUE_BEAT_TY", &K_dialogue_beat);
+    IDENTIFIERS_CORRESPOND("DIALOGUE_LINE_TY", &K_dialogue_line);
     IDENTIFIERS_CORRESPOND("ENUMERATED_VALUE_TY", &K_enumerated_value);
     IDENTIFIERS_CORRESPOND("EQUATION_TY", &K_equation);
     IDENTIFIERS_CORRESPOND("TEXT_TY", &K_text);
diff --git a/docs/runtime-module/2-hrr.html b/docs/runtime-module/2-hrr.html
index 968a00215..72a99edce 100644
--- a/docs/runtime-module/2-hrr.html
+++ b/docs/runtime-module/2-hrr.html
@@ -2063,6 +2063,8 @@ and The Standard Kits (
 enum K_RULEBOOK_OUTCOME_XPACKAGE
 enum K_RESPONSE_XPACKAGE
 enum K_SCENE_XPACKAGE
+enum K_DIALOGUE_BEAT_XPACKAGE
+enum K_DIALOGUE_LINE_XPACKAGE
 enum CAPSHORTNAME_HL
 enum DECIMAL_TOKEN_INNER_HL
 enum TIME_TOKEN_INNER_HL
@@ -2072,6 +2074,8 @@ and The Standard Kits (
 enum PRINT_SOUND_NAME_HL
 enum PRINT_EXTERNAL_FILE_NAME_HL
 enum PRINT_SCENE_HL
+enum PRINT_DIALOGUE_BEAT_HL
+enum PRINT_DIALOGUE_LINE_HL
 

§8.1.52. The rest8.1.52 =

@@ -2112,6 +2116,14 @@ and The Standard Kits ( H_BEGIN(LocationRequirements::this_exotic_package(K_SCENE_XPACKAGE)) H_F_T(PRINT_SCENE_HL, I"print_fn", I"PrintSceneName") H_END + + H_BEGIN(LocationRequirements::this_exotic_package(K_DIALOGUE_BEAT_XPACKAGE)) + H_F_T(PRINT_DIALOGUE_BEAT_HL, I"print_fn", I"PrintDialogueBeatName") + H_END + + H_BEGIN(LocationRequirements::this_exotic_package(K_DIALOGUE_LINE_XPACKAGE)) + H_F_T(PRINT_DIALOGUE_LINE_HL, I"print_fn", I"PrintDialogueLineName") + H_END

§8.2.1. Architectural symbols. These are built-in constants (and one built-in variable, self) which come @@ -2228,6 +2240,8 @@ exotic, but which are locations not easily falling into patterns. Here they are: case K_RULEBOOK_OUTCOME_XPACKAGE: return RTKindConstructors::kind_package(K_rulebook_outcome); case K_RESPONSE_XPACKAGE: return RTKindConstructors::kind_package(K_response); case K_SCENE_XPACKAGE: return RTKindConstructors::kind_package(K_scene); + case K_DIALOGUE_BEAT_XPACKAGE: return RTKindConstructors::kind_package(K_dialogue_beat); + case K_DIALOGUE_LINE_XPACKAGE: return RTKindConstructors::kind_package(K_dialogue_line); } internal_error("unknown exotic package"); return NULL; diff --git a/docs/runtime-module/5-kc.html b/docs/runtime-module/5-kc.html index e463a0e5c..795095b30 100644 --- a/docs/runtime-module/5-kc.html +++ b/docs/runtime-module/5-kc.html @@ -315,6 +315,16 @@ of the kind which the constructor makes: Hierarchy::make_available(K->construct->compilation_data.pr_iname); return K->construct->compilation_data.pr_iname; } + if (Kinds::eq(K, K_dialogue_beat)) { + K->construct->compilation_data.pr_iname = Hierarchy::find(PRINT_DIALOGUE_BEAT_HL); + Hierarchy::make_available(K->construct->compilation_data.pr_iname); + return K->construct->compilation_data.pr_iname; + } + if (Kinds::eq(K, K_dialogue_line)) { + K->construct->compilation_data.pr_iname = Hierarchy::find(PRINT_DIALOGUE_LINE_HL); + Hierarchy::make_available(K->construct->compilation_data.pr_iname); + return K->construct->compilation_data.pr_iname; + } package_request *R = NULL; int external = TRUE; diff --git a/docs/supervisor-module/5-ps2.html b/docs/supervisor-module/5-ps2.html index 032fe47ae..0cf152a61 100644 --- a/docs/supervisor-module/5-ps2.html +++ b/docs/supervisor-module/5-ps2.html @@ -632,8 +632,11 @@ on WorldModelKit, thr inform_language *L = project->language_of_play; if (L) Languages::add_kit_dependencies_to_project(L, project); else internal_error("no language of play"); - if ((no_word_from_JSON) && (forcible_basic_mode == FALSE)) + if ((no_word_from_JSON) && (forcible_basic_mode == FALSE)) { Projects::add_kit_dependency(project, I"CommandParserKit", NULL, NULL, NULL); + if (project->syntax_tree->contains_dialogue) + Projects::add_kit_dependency(project, I"DialogueKit", NULL, NULL, NULL); + }

  • This code is used in §20.

§20.2. We perform this first with parity being TRUE, then FALSE. diff --git a/docs/syntax-module/2-st.html b/docs/syntax-module/2-st.html index 3254c5ff7..88537ada3 100644 --- a/docs/syntax-module/2-st.html +++ b/docs/syntax-module/2-st.html @@ -89,6 +89,7 @@ it includes, will form a single parse_n struct parse_node *bud_parent_stack[MAX_BUD_STACK_SIZE]; struct parse_node *last_sentence; cached position in tree int allow_last_sentence_cacheing; + int contains_dialogue; int trace_sentences; HEADING_TREE_SYNTAX_TYPE *headings; CLASS_DEFINITION @@ -101,6 +102,7 @@ it includes, will form a single parse_n T->last_sentence = NULL; T->allow_last_sentence_cacheing = FALSE; T->trace_sentences = FALSE; + T->contains_dialogue = FALSE; SyntaxTree::push_bud(T, T->root_node); #ifdef NEW_HEADING_TREE_SYNTAX_CALLBACK T->headings = NEW_HEADING_TREE_SYNTAX_CALLBACK(T); @@ -108,7 +110,7 @@ it includes, will form a single parse_n return T; } -

+
  • The structure parse_node_tree is accessed in 2/tv, 3/snt and here.

§3. Buds and grafts. "Buds" are positions in the tree to which new sentence subtrees can be grafted:

diff --git a/docs/syntax-module/3-snt.html b/docs/syntax-module/3-snt.html index f1be560b8..5e10a4af1 100644 --- a/docs/syntax-module/3-snt.html +++ b/docs/syntax-module/3-snt.html @@ -942,6 +942,7 @@ order to catch improbable unmatched-bracket errors with tidy error messages.

+    T->contains_dialogue = TRUE;
     if ((Lexer::word(Wordings::first_wn(W)) == OPENBRACKET_V) &&
         (Lexer::word(Wordings::last_wn(W)) == CLOSEBRACKET_V))
         This is a dialogue cue6.9.9.1;
diff --git a/docs/values-module/2-rvl.html b/docs/values-module/2-rvl.html
index 2189a5313..b7e91596e 100644
--- a/docs/values-module/2-rvl.html
+++ b/docs/values-module/2-rvl.html
@@ -95,6 +95,10 @@ pointers:
         CONV_FROM(binary_predicate, Kinds::base_construction(CON_relation)) }
 parse_node *Rvalues::from_constant_phrase(constant_phrase *val) {
         CONV_FROM(constant_phrase, Kinds::base_construction(CON_phrase)) }
+parse_node *Rvalues::from_dialogue_beat(dialogue_beat *val) {
+        CONV_FROM(dialogue_beat, K_dialogue_beat) }
+parse_node *Rvalues::from_dialogue_line(dialogue_line *val) {
+        CONV_FROM(dialogue_line, K_dialogue_line) }
 parse_node *Rvalues::from_equation(equation *val) {
         CONV_FROM(equation, K_equation) }
 parse_node *Rvalues::from_named_rulebook_outcome(named_rulebook_outcome *val) {
diff --git a/inbuild/supervisor-module/Chapter 5/Project Services.w b/inbuild/supervisor-module/Chapter 5/Project Services.w
index 29c1b6898..4bcea899e 100644
--- a/inbuild/supervisor-module/Chapter 5/Project Services.w	
+++ b/inbuild/supervisor-module/Chapter 5/Project Services.w	
@@ -523,8 +523,11 @@ on //WorldModelKit//, through the if-this-then-that mechanism.
 	inform_language *L = project->language_of_play;
 	if (L) Languages::add_kit_dependencies_to_project(L, project);
 	else internal_error("no language of play");
-	if ((no_word_from_JSON) && (forcible_basic_mode == FALSE))
+	if ((no_word_from_JSON) && (forcible_basic_mode == FALSE)) {
 		Projects::add_kit_dependency(project, I"CommandParserKit", NULL, NULL, NULL);
+		if (project->syntax_tree->contains_dialogue)
+			Projects::add_kit_dependency(project, I"DialogueKit", NULL, NULL, NULL);
+	}
 
 @ We perform this first with |parity| being |TRUE|, then |FALSE|.
 
diff --git a/inform7/Figures/memory-diagnostics.txt b/inform7/Figures/memory-diagnostics.txt
index d91c562d4..c969a1723 100644
--- a/inform7/Figures/memory-diagnostics.txt
+++ b/inform7/Figures/memory-diagnostics.txt
@@ -1,10 +1,10 @@
-Total memory consumption was 123126K = 120 MB
+Total memory consumption was 123143K = 120 MB
 
- ---- was used for 2048105 objects, in 364642 frames in 0 x 800K = 0K = 0 MB:
+ ---- was used for 2048354 objects, in 364792 frames in 0 x 800K = 0K = 0 MB:
 
     33.1%  inter_tree_node_array                    58 x 8192 = 475136 objects, 41813824 bytes
-    20.6%  text_stream_array                        4616 x 100 = 461600 objects, 25997312 bytes
-    19.4%  linked_list                              43886 objects, 24576160 bytes
+    20.6%  text_stream_array                        4617 x 100 = 461700 objects, 26002944 bytes
+    19.5%  linked_list                              43933 objects, 24602480 bytes
     11.1%  inter_symbol_array                       132 x 1024 = 135168 objects, 14061696 bytes
     10.5%  inter_error_stash_array                  101 x 1024 = 103424 objects, 13241504 bytes
      8.2%  parse_node                               129721 objects, 10377680 bytes
@@ -13,7 +13,7 @@ Total memory consumption was 123126K = 120 MB
      2.6%  pcalc_prop_array                         25 x 1000 = 25000 objects, 3400800 bytes
      2.5%  inter_name_array                         67 x 1000 = 67000 objects, 3218144 bytes
      2.0%  kind_array                               66 x 1000 = 66000 objects, 2642112 bytes
-     1.7%  scan_directory                           521 objects, 2150688 bytes
+     1.7%  scan_directory                           528 objects, 2179584 bytes
      1.6%  inter_name_generator_array               51 x 1000 = 51000 objects, 2041632 bytes
      1.5%  inter_schema_token                       13964 objects, 2010816 bytes
      1.4%  package_request                          21143 objects, 1860584 bytes
@@ -36,7 +36,7 @@ Total memory consumption was 123126K = 120 MB
      0.3%  local_variable_array                     47 x 100 = 4700 objects, 452704 bytes
      0.3%  verb_usage                               1128 objects, 388032 bytes
      0.2%  rule                                     470 objects, 368480 bytes
-     0.2%  dictionary                               7585 objects, 364080 bytes
+     0.2%  dictionary                               7588 objects, 364224 bytes
      0.2%  verb_form                                386 objects, 348944 bytes
      0.2%  noun                                     2385 objects, 286200 bytes
      0.2%  compilation_subtask                      3355 objects, 268400 bytes
@@ -44,7 +44,7 @@ Total memory consumption was 123126K = 120 MB
      0.2%  inference_subject                        666 objects, 261072 bytes
      0.1%  vanilla_function                         3684 objects, 235776 bytes
      0.1%  binary_predicate                         322 objects, 170016 bytes
-     0.1%  hierarchy_location                       1124 objects, 161856 bytes
+     0.1%  hierarchy_location                       1126 objects, 162144 bytes
      0.1%  linguistic_stock_item                    3321 objects, 159408 bytes
      0.1%  rule_family_data                         401 objects, 147568 bytes
      0.1%  nonterminal                              762 objects, 140208 bytes
@@ -59,7 +59,7 @@ Total memory consumption was 123126K = 120 MB
      ----  lexical_cluster                          2522 objects, 80704 bytes
      ----  pcalc_term_array                         2 x 1000 = 2000 objects, 80064 bytes
      ----  kind_variable_declaration                1655 objects, 79440 bytes
-     ----  inter_tree                               6 objects, 79344 bytes
+     ----  inter_tree                               6 objects, 79440 bytes
      ----  label_namespace                          1472 objects, 70656 bytes
      ----  rulebook                                 407 objects, 68376 bytes
      ----  spatial_data                             671 objects, 64416 bytes
@@ -99,25 +99,25 @@ Total memory consumption was 123126K = 120 MB
      ----  action_name                              90 objects, 20160 bytes
      ----  nonlocal_variable                        93 objects, 20088 bytes
      ----  property                                 146 objects, 19856 bytes
+     ----  filename                                 490 objects, 19600 bytes
      ----  timed_rules_rfd_data                     401 objects, 19248 bytes
-     ----  filename                                 476 objects, 19040 bytes
      ----  method                                   380 objects, 18240 bytes
      ----  pcalc_prop_deferral                      86 objects, 17888 bytes
      ----  instance                                 167 objects, 17368 bytes
-     ----  parse_node_tree                          19 objects, 16416 bytes
+     ----  JSON_value                               194 objects, 17072 bytes
+     ----  parse_node_tree                          19 objects, 16568 bytes
+     ----  build_vertex                             136 objects, 16320 bytes
      ----  understanding_reference_array            2 x 100 = 200 objects, 16064 bytes
      ----  to_phrase_request                        59 objects, 16048 bytes
-     ----  action_name_list_array                   1 x 1000 objects, 16032 bytes
      ----  match_avinue_array                       1 x 1000 objects, 16032 bytes
-     ----  JSON_value                               182 objects, 16016 bytes
-     ----  build_vertex                             129 objects, 15480 bytes
+     ----  action_name_list_array                   1 x 1000 objects, 16032 bytes
      ----  adjective                                137 objects, 15344 bytes
-     ----  pathname                                 375 objects, 15000 bytes
+     ----  pathname                                 380 objects, 15200 bytes
      ----  booking_list                             407 objects, 13024 bytes
      ----  adjective_iname_holder                   320 objects, 12800 bytes
+     ----  web_bibliographic_datum                  174 objects, 11136 bytes
      ----  uniqueness_count                         453 objects, 10872 bytes
      ----  inter_construct                          30 objects, 10320 bytes
-     ----  web_bibliographic_datum                  145 objects, 9280 bytes
      ----  stopwatch_timer                          115 objects, 9200 bytes
      ----  equation_node                            68 objects, 7616 bytes
      ----  understanding_item_array                 3 x 100 = 300 objects, 7296 bytes
@@ -125,22 +125,22 @@ Total memory consumption was 123126K = 120 MB
      ----  determiner                               22 objects, 7216 bytes
      ----  verb                                     108 objects, 6912 bytes
      ----  hierarchy_attachment_point               77 objects, 6776 bytes
+     ----  inbuild_copy                             55 objects, 6600 bytes
+     ----  inbuild_work                             102 objects, 6528 bytes
      ----  text_literal_holder                      163 objects, 6520 bytes
-     ----  inbuild_copy                             54 objects, 6480 bytes
-     ----  inbuild_work                             101 objects, 6464 bytes
      ----  heading_tree                             19 objects, 5320 bytes
-     ----  inbuild_edition                          72 objects, 5184 bytes
+     ----  inbuild_edition                          73 objects, 5256 bytes
      ----  explicit_action_array                    1 x 100 objects, 4832 bytes
      ----  value_property_data                      84 objects, 4704 bytes
      ----  parsing_pp_data                          96 objects, 4608 bytes
-     ----  section_md                               45 objects, 4320 bytes
-     ----  build_script                             129 objects, 4128 bytes
-     ----  compatibility_specification              83 objects, 3984 bytes
-     ----  activity                                 35 objects, 3920 bytes
+     ----  section_md                               46 objects, 4416 bytes
+     ----  build_script                             136 objects, 4352 bytes
+     ----  compatibility_specification              84 objects, 4032 bytes
      ----  command_line_switch                      49 objects, 3920 bytes
-     ----  parse_node_annotation_type               117 objects, 3744 bytes
-     ----  submodule_request                        84 objects, 3360 bytes
+     ----  activity                                 35 objects, 3920 bytes
+     ----  parse_node_annotation_type               119 objects, 3808 bytes
      ----  property_setting_bp_data                 84 objects, 3360 bytes
+     ----  submodule_request                        84 objects, 3360 bytes
      ----  method_set                               104 objects, 3328 bytes
      ----  kind_constructor_comparison_schema_array 1 x 100 objects, 3232 bytes
      ----  semver_range                             31 objects, 3224 bytes
@@ -157,7 +157,7 @@ Total memory consumption was 123126K = 120 MB
      ----  JSON_type                                31 objects, 2232 bytes
      ----  scene                                    1 object, 2096 bytes
      ----  JSON_single_requirement                  43 objects, 2064 bytes
-     ----  build_step                               24 objects, 1728 bytes
+     ----  build_step                               28 objects, 2016 bytes
      ----  pronoun_usage                            42 objects, 1680 bytes
      ----  table_contribution_array                 1 x 100 objects, 1632 bytes
      ----  inform_pipeline                          24 objects, 1536 bytes
@@ -175,30 +175,30 @@ Total memory consumption was 123126K = 120 MB
      ----  runtime_kind_structure                   13 objects, 1040 bytes
      ----  quantifier                               16 objects, 1024 bytes
      ----  submodule_identity                       31 objects, 992 bytes
-     ----  named_rulebook_outcome                   15 objects, 960 bytes
      ----  pipeline_stage                           20 objects, 960 bytes
+     ----  named_rulebook_outcome                   15 objects, 960 bytes
      ----  control_structure_phrase                 12 objects, 864 bytes
+     ----  web_md                                   6 objects, 864 bytes
      ----  cached_understanding                     21 objects, 840 bytes
      ----  JSON_pair_requirement                    26 objects, 832 bytes
      ----  phrase_option_array                      1 x 100 objects, 824 bytes
      ----  inbuild_search_result                    20 objects, 800 bytes
-     ----  web_md                                   5 objects, 720 bytes
      ----  internal_test                            15 objects, 720 bytes
      ----  relation_guard                           5 objects, 640 bytes
+     ----  inform_kit                               6 objects, 624 bytes
      ----  implication                              13 objects, 624 bytes
      ----  code_generation                          1 object, 576 bytes
      ----  generated_segment                        14 objects, 560 bytes
      ----  inter_warehouse_room                     10 objects, 560 bytes
      ----  rulebook_outcome                         17 objects, 544 bytes
+     ----  chapter_md                               6 objects, 528 bytes
      ----  small_word_set                           11 objects, 528 bytes
-     ----  inform_kit                               5 objects, 520 bytes
-     ----  inform_language                          6 objects, 480 bytes
      ----  equation                                 4 objects, 480 bytes
+     ----  inform_language                          6 objects, 480 bytes
+     ----  module                                   6 objects, 480 bytes
      ----  i6_memory_setting                        14 objects, 448 bytes
      ----  inference_family                         11 objects, 440 bytes
-     ----  chapter_md                               5 objects, 440 bytes
      ----  bp_family                                13 objects, 416 bytes
-     ----  module                                   5 objects, 400 bytes
      ----  inter_annotation_form                    10 objects, 400 bytes
      ----  article_usage                            8 objects, 384 bytes
      ----  source_file                              5 objects, 360 bytes
@@ -208,13 +208,13 @@ Total memory consumption was 123126K = 120 MB
      ----  door_dir_notice                          5 objects, 320 bytes
      ----  pronoun                                  8 objects, 320 bytes
      ----  grammatical_category                     8 objects, 320 bytes
-     ----  tree_inventory                           1 object, 312 bytes
      ----  inter_pipeline                           1 object, 312 bytes
+     ----  tree_inventory                           1 object, 312 bytes
      ----  up_family                                9 objects, 288 bytes
      ----  compilation_unit                         5 objects, 280 bytes
+     ----  contents_entry                           7 objects, 280 bytes
      ----  explicit_bp_data                         5 objects, 280 bytes
      ----  door_to_notice                           5 objects, 280 bytes
-     ----  contents_entry                           7 objects, 280 bytes
      ----  verb_usage_tier                          5 objects, 240 bytes
      ----  inform_project                           1 object, 224 bytes
      ----  adjective_meaning_family                 7 objects, 224 bytes
@@ -222,19 +222,19 @@ Total memory consumption was 123126K = 120 MB
      ----  release_instructions                     1 object, 208 bytes
      ----  code_generator                           5 objects, 200 bytes
      ----  build_skill                              5 objects, 200 bytes
-     ----  plural_dictionary_entry                  4 objects, 192 bytes
      ----  kit_dependency                           4 objects, 192 bytes
+     ----  plural_dictionary_entry                  4 objects, 192 bytes
      ----  inference_subject_family                 5 objects, 160 bytes
+     ----  element_activation                       5 objects, 160 bytes
      ----  imperative_defn_family                   4 objects, 160 bytes
      ----  inter_architecture                       4 objects, 160 bytes
      ----  attachment_instruction                   4 objects, 160 bytes
-     ----  element_activation                       4 objects, 128 bytes
      ----  inbuild_nest                             3 objects, 120 bytes
      ----  local_block_value                        2 objects, 112 bytes
      ----  inform_kit_ittt                          2 objects, 96 bytes
+     ----  compile_task_data                        1 object, 80 bytes
      ----  group_together_function                  2 objects, 80 bytes
      ----  article                                  2 objects, 80 bytes
-     ----  compile_task_data                        1 object, 80 bytes
      ----  build_methodology                        1 object, 56 bytes
      ----  figures_data                             1 object, 56 bytes
      ----  inter_warehouse                          1 object, 56 bytes
@@ -247,8 +247,8 @@ Total memory consumption was 123126K = 120 MB
 
 100.0% was used for memory not allocated for objects:
 
-    57.5%  text stream storage                      72579248 bytes in 479038 claims
-     4.1%  dictionary storage                       5294080 bytes in 7585 claims
+    57.5%  text stream storage                      72595224 bytes in 479193 claims
+     4.1%  dictionary storage                       5295616 bytes in 7588 claims
      ----  sorting                                  1528 bytes in 159 claims
      5.7%  source text                              7200000 bytes in 3 claims
      8.5%  source text details                      10800000 bytes in 2 claims
@@ -265,5 +265,5 @@ Total memory consumption was 123126K = 120 MB
      ----  code generation workspace for objects    3480 bytes in 19 claims
      0.2%  emitter array storage                    280288 bytes in 1999 claims
 
--147.-4% was overhead - -185900280 bytes = -181543K = -177 MB
+-147.-4% was overhead - -185967744 bytes = -181609K = -177 MB
 
diff --git a/inform7/Figures/timings-diagnostics.txt b/inform7/Figures/timings-diagnostics.txt
index d99fafa5a..eff46281a 100644
--- a/inform7/Figures/timings-diagnostics.txt
+++ b/inform7/Figures/timings-diagnostics.txt
@@ -1,33 +1,33 @@
 100.0% in inform7 run
-     71.2% in compilation to Inter
-         50.0% in //Sequence::undertake_queued_tasks//
-          4.9% in //MajorNodes::pre_pass//
-          3.5% in //MajorNodes::pass_1//
-          1.9% in //RTPhrasebook::compile_entries//
-          1.7% in //ImperativeDefinitions::assess_all//
-          1.3% in //RTKindConstructors::compile//
-          1.1% in //Sequence::lint_inter//
-          0.5% in //MajorNodes::pass_2//
-          0.5% in //Sequence::undertake_queued_tasks//
-          0.5% in //World::stage_V//
-          0.3% in //ImperativeDefinitions::compile_first_block//
-          0.3% in //Sequence::undertake_queued_tasks//
-          0.1% in //CompletionModule::compile//
-          0.1% in //InferenceSubjects::emit_all//
-          0.1% in //RTKindConstructors::compile_permissions//
-          0.1% in //Task::make_built_in_kind_constructors//
-          0.1% in //World::stages_II_and_III//
-          2.7% not specifically accounted for
-     25.7% in running Inter pipeline
-         10.0% in step 14/15: generate inform6 -> auto.inf
-          5.7% in step 5/15: load-binary-kits
-          5.3% in step 6/15: make-synoptic-module
-          1.3% in step 9/15: make-identifiers-unique
-          0.3% in step 12/15: eliminate-redundant-operations
-          0.3% in step 4/15: compile-splats
-          0.3% in step 7/15: shorten-wiring
-          0.3% in step 8/15: detect-indirect-calls
-          0.1% in step 11/15: eliminate-redundant-labels
+     70.6% in compilation to Inter
+         49.4% in //Sequence::undertake_queued_tasks//
+          4.8% in //MajorNodes::pre_pass//
+          3.4% in //MajorNodes::pass_1//
+          2.2% in //RTPhrasebook::compile_entries//
+          1.8% in //ImperativeDefinitions::assess_all//
+          1.4% in //RTKindConstructors::compile//
+          1.0% in //Sequence::lint_inter//
+          0.6% in //MajorNodes::pass_2//
+          0.6% in //Sequence::undertake_queued_tasks//
+          0.6% in //World::stage_V//
+          0.4% in //ImperativeDefinitions::compile_first_block//
+          0.4% in //Sequence::undertake_queued_tasks//
+          0.2% in //CompletionModule::compile//
+          0.2% in //InferenceSubjects::emit_all//
+          0.2% in //RTKindConstructors::compile_permissions//
+          0.2% in //Task::make_built_in_kind_constructors//
+          0.2% in //World::stages_II_and_III//
+          2.6% not specifically accounted for
+     26.0% in running Inter pipeline
+         10.1% in step 14/15: generate inform6 -> auto.inf
+          5.9% in step 5/15: load-binary-kits
+          5.4% in step 6/15: make-synoptic-module
+          1.4% in step 9/15: make-identifiers-unique
+          0.4% in step 12/15: eliminate-redundant-operations
+          0.4% in step 4/15: compile-splats
+          0.4% in step 7/15: shorten-wiring
+          0.2% in step 11/15: eliminate-redundant-labels
+          0.2% in step 8/15: detect-indirect-calls
           1.4% not specifically accounted for
-      2.5% in supervisor
-      0.4% not specifically accounted for
+      2.6% in supervisor
+      0.7% not specifically accounted for
diff --git a/inform7/Internal/Inter/BasicInformExtrasKit/kit_metadata.json b/inform7/Internal/Inter/BasicInformExtrasKit/kit_metadata.json
index 4a5163bb9..65554fec0 100644
--- a/inform7/Internal/Inter/BasicInformExtrasKit/kit_metadata.json
+++ b/inform7/Internal/Inter/BasicInformExtrasKit/kit_metadata.json
@@ -2,7 +2,7 @@
     "is": {
         "type": "kit",
         "title": "BasicInformExtrasKit",
-        "version": "10.2.0-beta+6V51"
+        "version": "10.2.0-beta+6V52"
     },
     "kit-details": {
         "has-priority": 1
diff --git a/inform7/Internal/Inter/BasicInformKit/kit_metadata.json b/inform7/Internal/Inter/BasicInformKit/kit_metadata.json
index 1b5567139..d55c5a29e 100644
--- a/inform7/Internal/Inter/BasicInformKit/kit_metadata.json
+++ b/inform7/Internal/Inter/BasicInformKit/kit_metadata.json
@@ -2,7 +2,7 @@
     "is": {
         "type": "kit",
         "title": "BasicInformKit",
-        "version": "10.2.0-beta+6V51"
+        "version": "10.2.0-beta+6V52"
     },
     "needs": [ {
         "unless": {
diff --git a/inform7/Internal/Inter/CommandParserKit/kit_metadata.json b/inform7/Internal/Inter/CommandParserKit/kit_metadata.json
index 923a5f3d7..3ea6247cf 100644
--- a/inform7/Internal/Inter/CommandParserKit/kit_metadata.json
+++ b/inform7/Internal/Inter/CommandParserKit/kit_metadata.json
@@ -2,7 +2,7 @@
     "is": {
         "type": "kit",
         "title": "CommandParserKit",
-        "version": "10.2.0-beta+6V51"
+        "version": "10.2.0-beta+6V52"
     },
     "needs": [ {
         "need": {
diff --git a/inform7/Internal/Inter/DialogueKit/Contents.w b/inform7/Internal/Inter/DialogueKit/Contents.w
new file mode 100644
index 000000000..c9a5789b5
--- /dev/null
+++ b/inform7/Internal/Inter/DialogueKit/Contents.w
@@ -0,0 +1,9 @@
+Title: DialogueKit
+Author: Graham Nelson
+Purpose: Inter-level support for dialogue in Inform projects.
+Language: Inform 6
+Licence: Artistic License 2.0
+Web Syntax Version: 2
+
+Sections
+	Director
diff --git a/inform7/Internal/Inter/DialogueKit/Sections/Director.i6t b/inform7/Internal/Inter/DialogueKit/Sections/Director.i6t
new file mode 100644
index 000000000..122df21f7
--- /dev/null
+++ b/inform7/Internal/Inter/DialogueKit/Sections/Director.i6t
@@ -0,0 +1,10 @@
+Director Template.
+
+Run-time support for dialogue.
+
+@h Placeholder.
+
+=
+[ DirectorBegin;
+	rfalse;
+];
diff --git a/inform7/Internal/Inter/DialogueKit/arch-16.interb b/inform7/Internal/Inter/DialogueKit/arch-16.interb
new file mode 100644
index 0000000000000000000000000000000000000000..a02d30e0cb686e91743886f60bdcb10a63af723b
GIT binary patch
literal 3834
zcmZWsXII=v7JUjGX)<_rXLr`Lb2iZdoWQi9ZIYqE7zbG`Rf7h#)Rxq?`84~}X8#G!
zlXFh&dsR|PKEpX2-FxfBs;3fIPT+y~k;5lQ?V6_hzE!tuJz%CJBd_V(Ow*0Pave#@
zYMNX9kQsrLL8vzx%rTX0zouD^!#u6wxeew8JDQ`{nUX{Az|$QcgQ2&gcA|^t={uTk
znjZ6gIfcrm?N)VLb89u91#%i=i45Ad<(Qh`Hl2WZGW5NtsHt=&o6ENq+B-VCx_f&2
z`u8dFET>dc2%0GXm`J+Vv%uL;*(vuV5V
zhFq#v@YM2|?wIfvARlqpgHIC6jvK(I#C`U-$(+E_ZTJkJr-+48&V>9qWxy>k-8y_h
zMfid1G58Xoz1Z-Wm}o7W|sj
z*fYxyeE2Qt`b4*z41TAab@vH_Klm0fj{l@BFt#k)gui&P1U=@!-Zg;z0NJ8%Rc*`J
zYJv3RgdZ0+@{0_4fhsr29e?hZ{VpF7+c(8hIZf3!+K@`x{?RiS}0R*CadYq
za5QdG9FGM}PfWlqit}N!E^3=2_PB{}B5l$UpWT7{;im6xYoO-e&tT1!g9T)LB#M!2+|lt#I9Hz|#A
zX@d>`uU=o@WP@C}mrz8$`w2y)dyr5>wuf{dvS<8_vJD-tGulTDPg`r)didHs!d=IY
z243#8sN=3{c%N)zYA#f9qUw>Yf#;|3>t8IISi9yos|kr=6@|#EqVC;q*vY_&&s=4wC>@R7vM2BJ^WJOXR2))KN;?3
zlikAUz;9LFaPjkL;B5GqPsO5nk$LjY-dS9pUMX*s$WdKbotq<%0;$?;d1iL1Tmk&N
z^>AUKv|gz!M)E71
z-ud!^wosaxOzQX@EL0|!XG#@q+9zzHUCluu*=C3I!M%ZL
zKJ2bH#WpQxBA@eWI^F^k`3DpEPKwa=j)7KlP*U5WGmhL%X6^5oVee`ebpOq_7yo8Z
zd*t4Ct^4I&`ELRCVMqOmL+Ib_#x$xbK??uqK#&om7J)|*&?8_(z>EMBo)V-9L?n|{
z^RO%74}s@0f((KeiV$9^;mWI22wtZ{@Fo+2w^;<_^hr)QeVRuBj|4tzL%^3lFNmct
z+A#y!e%T@O=U1KL`E{3ge$y@UO1|xpC7ilEeAkPBJihM}&ma0_zVPEdj7=6ly%(nY
z`5%;y694kg2>tqggns)MA#(Wr-;xOR#|Ps1=YK>|f9)4fdQ`eg)1kl8ZErqQDk$~WUeZ{CVKyEUh@qR!2?`kG%*T6keGZhmnI
zXD@1U={6>4wQ_qInS{5QNVvR0RDwdtS1O#xnJcUD^sTPpVib1m4p~M!bZ4FWMPb+P
zawXI4$~{i{k8T+8N^
zTuMs*W^-w2moMu1Hl-~kN59!NS>Bc4e*iMU=LDsX_x6aq5aho=!S*4>lsNvnc9>g`kdx>HJDDxK=^s;>Av?f64nMJ{~wEcX?g$v

literal 0
HcmV?d00001

diff --git a/inform7/Internal/Inter/DialogueKit/arch-16d.interb b/inform7/Internal/Inter/DialogueKit/arch-16d.interb
new file mode 100644
index 0000000000000000000000000000000000000000..71bd495f927e8ee2caf9e47801a2524a672c883d
GIT binary patch
literal 3855
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

literal 0
HcmV?d00001

diff --git a/inform7/Internal/Inter/DialogueKit/arch-32d.interb b/inform7/Internal/Inter/DialogueKit/arch-32d.interb
new file mode 100644
index 0000000000000000000000000000000000000000..67bf802f18c1f896cde3f82f65aecca07ccf5710
GIT binary patch
literal 3861
zcmZWs=T_Uw7T%KOPA@tA2B-H>Qy>io2b`D^FoaY^md2oiEIE>#gkSf*(0z#e0{0Ql
zB0Z<~UUK%Hkt}5$)?(?~-|RknX27(47sQVod_n3|Rn7CvhG}U&Gb9=1y0*nsP4`X5
zmJ%6Nb!s0o-Ivk`wPusqMj|t)s-|r-S8cjZlezx3YHJOa$fC9HYPN^Y&^n=XqlxQk
z+p1<5F7rG&iOh!O)HF+V>UEF#ateKk2;TKY@fL@47`(2lBskio6C1}c6Imk
z_Vo`8?n=lz0LenrYI*PkAXR9XHo~U>`9jOq+-)I0qb1*LFb|#sqzi`m&@>plAlz__
zmgT@pGO3yVBhzD=ZNMvlTqrv(ypAo~jt`%b?6C(eX8WdQ!Dj${1x%D;#^}!}0=B?#
z8t?@r;rWis;7fqcLepiYt-Gv&F5oMGu0qrC{D}HGP%>Dk^i8M~QQuMkY#e3|-vML`
zy2Uh?r0;oSTHYr7AdqFjkECrm&Q_}lKT!n&*S38IKXd272J&r!UjVu>O|hpIvp4)r
z_%+V4$EN3d@LSyUp=Pxh{7x|&&O-)&@D?zR|D+b^o2F&JUp!fYF0;p&?aN`K?C(Isje1Ndc
zI6g>tLl__8Sn!7lTY^8rvEYwVhE6>Se~cDQk^XV24O0ok6963r&Eg~Bo7e|RtFP1nT92`U|?Zq=Qj&Ji&v+mKvb=
zomrkJ?;@4=2nRuk=rB<*9PVwJ!q$ULEK;)KYQU*&
za)ry3Y{ZHDX2@a9W!e_kDe*zW-r~(5LR{emJTiTKlWWXU_jN7EXAYnzzH#k^GSz0V
zy4DIt<0|=ancs571Y9FOAGaDJw+cxQT6hwvN%LfkcOF0fL@ZD_c*B`4-loG3xzb{s
z8xh=6oEsI~^*A>sxaBxEF1VFAHzBwxO-nm254#$tMmV(=r$#w-BTkKRYCTSkbLwWC
zn&8we+5o(IJ#B*xbLMu85%KQC7!mGnj1kf9(S67s^Alz18eV7AM-_KlZCYAz?CxXN
z@zKD`ofb9hx{CM77KY|T4JWD*>gu?ED!=~4qJg=qUaJMmZn^kU;4_t*K^iX}wxq4C&`M$>sT_<;CK3u~JgkrYox@dh`0{r`Oe`#g%fkyjD^dR_BYQWqSYm
z=gSM~LTPq7&f`1SQJr3%EmhUo%4%huUc%%|skn-#Ca+|b+}q`KP|n$~V^~h7l7)_V
z!Clfvw})o<*gI~KZJ72{F6-7cybq>wcc*gQm8M6%EF=V{oSz!zhXbN&NEzL0Sx52=0eK3xOU2BLqxX
zN{}KD3h9iJgB=Nf2t1Jyq!Bz#2;!L%tUON!;6*9`FVg{dl|ev8ud~AF(;O1GCGc4u
z0blyOLo9vKi4jQm%PyIJzv>p>uY1Jzn_ih`@@=0i;r!*`yM6>@@%@1K{xB%>g&%jJ
zZ_@bbogm!L?@~Al{L6bG`t|(~{q_MNGWh*NNx1ssBk}$7Um~f$c8f2a+1*1C9x6n*
zuqVQM_6mojzjt5YorHb+W5WIeG2y_$m~ik=OgMBnCLBHz6OJ5>2}h5`gk#5J!toO^
z;lxQ4Qdlgdb8?t>kl^r$D4FocXoN?{a4-V(vGKP0_(Y^KaVo;6PDl9knFyab8{xB)
z5uTh9yGdcE&Phr;z`64gK7T>MYe%Gf;i81M9PJjFT)c!Pp>Sy$g{=z!_F9>5*EPS8
zXyb*&sQAStoV~EfrRx}=UCQ-klq9^(M8M@05+&#eNJInV$?Q^ww=8LRYu%&}!)F&Rwn>y1ILhi*3t$D$3#I5`HsE
ziubQ3k#jYZO=Oc&{5O+LNjrQ|%jFaKq#XWc^0K@m!T<2$Blv`%^oD*&d@98M0KQEq
zKI7sJ!RKP-lmGs|m&6w&!kd2wb}vaxyb0}I@l}ZwUkez9=ieY#%JHel5&zlSg*no1
zZ1D+S)H^yeoheM3N;SHBGCiq;5LjVxTvf7)Yj)1N|wkeKj@kep--> The text '.' (source text, line 5) appears to be a bracketed clause to
     do with dialogue, but the punctuation looks wrong because it includes an
     empty part.
-Problem__ PM_EmptyDialogueClause
-  >--> The text '()' (source text, line 7) appears to be a bracketed clause to
-    do with dialogue, but the punctuation looks wrong because it includes an
-    empty part.
 Inform 7 has finished.
diff --git a/inform7/Tests/Test Problems/_Results_Ideal/PM_MisbracketedDialogueClause.txt b/inform7/Tests/Test Problems/_Results_Ideal/PM_MisbracketedDialogueClause.txt
index 58a7022ae..e4dfbaccd 100644
--- a/inform7/Tests/Test Problems/_Results_Ideal/PM_MisbracketedDialogueClause.txt	
+++ b/inform7/Tests/Test Problems/_Results_Ideal/PM_MisbracketedDialogueClause.txt	
@@ -10,7 +10,13 @@ Problem__ PM_MisbracketedDialogueClause
     should be just one outer pair of brackets, and inside they can only be used
     to clarify clauses, if necessary.
 Problem__ PM_MisbracketedDialogueClause
-  >--> The text '(going (doolally)' (source text, line 9) appears to be a
+  >--> The text 'slowly, quickly) (erroneously' (source text, line 7) appears
+    to be a bracketed clause to do with dialogue, but the punctuation looks
+    wrong because it uses brackets '(' and ')' in a way which doesn't match.
+    There should be just one outer pair of brackets, and inside they can only
+    be used to clarify clauses, if necessary.
+Problem__ PM_MisbracketedDialogueClause
+  >--> The text 'going (doolally' (source text, line 9) appears to be a
     bracketed clause to do with dialogue, but the punctuation looks wrong
     because it uses brackets '(' and ')' in a way which doesn't match. There
     should be just one outer pair of brackets, and inside they can only be used
diff --git a/inform7/assertions-module/Chapter 7/Dialogue.w b/inform7/assertions-module/Chapter 7/Dialogue.w
index 3bc6d3549..c80b69334 100644
--- a/inform7/assertions-module/Chapter 7/Dialogue.w	
+++ b/inform7/assertions-module/Chapter 7/Dialogue.w	
@@ -29,6 +29,7 @@ typedef struct dialogue_beat {
 	struct wording scene_name;
 	struct parse_node *cue_at;
 	struct heading *under_heading;
+	struct instance *as_instance;
 	
 	struct dialogue_beat *immediately_after;
 	struct linked_list *some_time_after; /* of |dialogue_beat| */
@@ -41,6 +42,7 @@ typedef struct dialogue_beat {
 
 typedef struct dialogue_line {
 	struct wording line_name;
+	struct instance *as_instance;
 	struct parse_node *line_at;
 	struct wording speaker_text;
 	struct wording speech_text;
@@ -117,6 +119,17 @@ dialogue_beat *Dialogue::create_cue(parse_node *PN) {
 			"which is not allowed. It can be anonymous, but otherwise can only have "
 			"one name (either as a beat or as a scene, and not both).");
 	}
+
+	wording W = db->beat_name;
+	if (Wordings::empty(W)) {
+		TEMPORARY_TEXT(faux_name)
+		WRITE_TO(faux_name, "beat-%d", db->allocation_id + 1);
+		W = Feeds::feed_text(faux_name);
+		DISCARD_TEXT(faux_name)
+	}
+	pcalc_prop *prop = Propositions::Abstract::to_create_something(K_dialogue_beat, W);
+	Assert::true(prop, CERTAIN_CE);
+	db->as_instance = Instances::latest();
 	return db;
 }
 
@@ -262,6 +275,17 @@ dialogue_line *Dialogue::create_line(parse_node *PN) {
 	precursor_dialogue_lines[L] = dl;
 	for (int i=L+1; iline_name;
+	if (Wordings::empty(W)) {
+		TEMPORARY_TEXT(faux_name)
+		WRITE_TO(faux_name, "line-%d", dl->allocation_id + 1);
+		W = Feeds::feed_text(faux_name);
+		DISCARD_TEXT(faux_name)
+	}
+	pcalc_prop *prop = Propositions::Abstract::to_create_something(K_dialogue_line, W);
+	Assert::true(prop, CERTAIN_CE);
+	dl->as_instance = Instances::latest();
+
 	return dl;
 }
 
diff --git a/inform7/core-module/Chapter 1/Inform-Only Nodes and Annotations.w b/inform7/core-module/Chapter 1/Inform-Only Nodes and Annotations.w
index fec21cd3e..88b2199c9 100644
--- a/inform7/core-module/Chapter 1/Inform-Only Nodes and Annotations.w	
+++ b/inform7/core-module/Chapter 1/Inform-Only Nodes and Annotations.w	
@@ -850,6 +850,8 @@ void CoreSyntax::grant_code_permissions(void) {
 @e constant_activity_ANNOT /* |activity|: for constant values */
 @e constant_binary_predicate_ANNOT /* |binary_predicate|: for constant values */
 @e constant_constant_phrase_ANNOT /* |constant_phrase|: for constant values */
+@e constant_dialogue_beat_ANNOT /* |dialogue_beat|: for constant values */
+@e constant_dialogue_line_ANNOT /* |dialogue_line|: for constant values */
 @e constant_enumeration_ANNOT /* |int|: which one from an enumerated kind */
 @e constant_equation_ANNOT /* |equation|: for constant values */
 @e constant_instance_ANNOT /* |instance|: for constant values */
@@ -885,6 +887,8 @@ void CoreSyntax::grant_code_permissions(void) {
 DECLARE_ANNOTATION_FUNCTIONS(constant_activity, activity)
 DECLARE_ANNOTATION_FUNCTIONS(constant_binary_predicate, binary_predicate)
 DECLARE_ANNOTATION_FUNCTIONS(constant_constant_phrase, constant_phrase)
+DECLARE_ANNOTATION_FUNCTIONS(constant_dialogue_beat, dialogue_beat)
+DECLARE_ANNOTATION_FUNCTIONS(constant_dialogue_line, dialogue_line)
 DECLARE_ANNOTATION_FUNCTIONS(constant_equation, equation)
 DECLARE_ANNOTATION_FUNCTIONS(constant_instance, instance)
 DECLARE_ANNOTATION_FUNCTIONS(constant_local_variable, local_variable)
@@ -912,6 +916,8 @@ DECLARE_ANNOTATION_FUNCTIONS(tense_marker, grammatical_usage)
 MAKE_ANNOTATION_FUNCTIONS(constant_activity, activity)
 MAKE_ANNOTATION_FUNCTIONS(constant_binary_predicate, binary_predicate)
 MAKE_ANNOTATION_FUNCTIONS(constant_constant_phrase, constant_phrase)
+MAKE_ANNOTATION_FUNCTIONS(constant_dialogue_beat, dialogue_beat)
+MAKE_ANNOTATION_FUNCTIONS(constant_dialogue_line, dialogue_line)
 MAKE_ANNOTATION_FUNCTIONS(constant_equation, equation)
 MAKE_ANNOTATION_FUNCTIONS(constant_instance, instance)
 MAKE_ANNOTATION_FUNCTIONS(constant_local_variable, local_variable)
@@ -941,6 +947,10 @@ void CoreSyntax::declare_spec_annotations(void) {
 		constant_binary_predicate_ANNOT, CoreSyntax::write_constant_binary_predicate_ANNOT);
 	Annotations::declare_type(
 		constant_constant_phrase_ANNOT, CoreSyntax::write_constant_constant_phrase_ANNOT);
+	Annotations::declare_type(
+		constant_dialogue_beat_ANNOT, CoreSyntax::write_constant_dialogue_beat_ANNOT);
+	Annotations::declare_type(
+		constant_dialogue_line_ANNOT, CoreSyntax::write_constant_dialogue_line_ANNOT);
 	Annotations::declare_type(
 		constant_equation_ANNOT, CoreSyntax::write_constant_equation_ANNOT);
 	Annotations::declare_type(
@@ -1020,6 +1030,14 @@ void CoreSyntax::write_constant_constant_phrase_ANNOT(text_stream *OUT, parse_no
 		WRITE("}");
 	}
 }
+void CoreSyntax::write_constant_dialogue_beat_ANNOT(text_stream *OUT, parse_node *p) {
+	dialogue_beat *db = Node::get_constant_dialogue_beat(p);
+	if (db) WRITE(" {beat: %W}", db->beat_name);
+}
+void CoreSyntax::write_constant_dialogue_line_ANNOT(text_stream *OUT, parse_node *p) {
+	dialogue_line *dl = Node::get_constant_dialogue_line(p);
+	if (dl) WRITE(" {line: %W}", dl->line_name);
+}
 void CoreSyntax::write_constant_equation_ANNOT(text_stream *OUT, parse_node *p) {
 	equation *eqn = Node::get_constant_equation(p);
 	if (eqn) WRITE(" {equation: %W}", eqn->equation_text);
@@ -1184,6 +1202,8 @@ void CoreSyntax::grant_spec_permissions(void) {
 	Annotations::allow(CONSTANT_NT, constant_activity_ANNOT);
 	Annotations::allow(CONSTANT_NT, constant_binary_predicate_ANNOT);
 	Annotations::allow(CONSTANT_NT, constant_constant_phrase_ANNOT);
+	Annotations::allow(CONSTANT_NT, constant_dialogue_beat_ANNOT);
+	Annotations::allow(CONSTANT_NT, constant_dialogue_line_ANNOT);
 	Annotations::allow(CONSTANT_NT, constant_enumeration_ANNOT);
 	Annotations::allow(CONSTANT_NT, constant_equation_ANNOT);
 	Annotations::allow(CONSTANT_NT, constant_instance_ANNOT);
diff --git a/inform7/runtime-module/Chapter 2/Hierarchy.w b/inform7/runtime-module/Chapter 2/Hierarchy.w
index ee63d80bc..57ee22a8f 100644
--- a/inform7/runtime-module/Chapter 2/Hierarchy.w	
+++ b/inform7/runtime-module/Chapter 2/Hierarchy.w	
@@ -1895,6 +1895,8 @@ void Hierarchy::establish(void) {
 @e K_RULEBOOK_OUTCOME_XPACKAGE
 @e K_RESPONSE_XPACKAGE
 @e K_SCENE_XPACKAGE
+@e K_DIALOGUE_BEAT_XPACKAGE
+@e K_DIALOGUE_LINE_XPACKAGE
 
 @e CAPSHORTNAME_HL
 @e DECIMAL_TOKEN_INNER_HL
@@ -1906,6 +1908,8 @@ void Hierarchy::establish(void) {
 @e PRINT_SOUND_NAME_HL
 @e PRINT_EXTERNAL_FILE_NAME_HL
 @e PRINT_SCENE_HL
+@e PRINT_DIALOGUE_BEAT_HL
+@e PRINT_DIALOGUE_LINE_HL
 
 @ =
 	H_BEGIN(LocationRequirements::this_exotic_package(K_OBJECT_XPACKAGE))
@@ -1944,6 +1948,14 @@ void Hierarchy::establish(void) {
 		H_F_T(PRINT_SCENE_HL,                 I"print_fn", I"PrintSceneName")
 	H_END
 
+	H_BEGIN(LocationRequirements::this_exotic_package(K_DIALOGUE_BEAT_XPACKAGE))
+		H_F_T(PRINT_DIALOGUE_BEAT_HL,         I"print_fn", I"PrintDialogueBeatName")
+	H_END
+
+	H_BEGIN(LocationRequirements::this_exotic_package(K_DIALOGUE_LINE_XPACKAGE))
+		H_F_T(PRINT_DIALOGUE_LINE_HL,         I"print_fn", I"PrintDialogueLineName")
+	H_END
+
 @h Architectural symbols.
 These are built-in constants (and one built-in variable, |self|) which come
 from the platform we are compiling to. See //building: Large-Scale Structure//.
@@ -2045,6 +2057,8 @@ package_request *Hierarchy::exotic_package(int x) {
 		case K_RULEBOOK_OUTCOME_XPACKAGE: return RTKindConstructors::kind_package(K_rulebook_outcome);
 		case K_RESPONSE_XPACKAGE:         return RTKindConstructors::kind_package(K_response);
 		case K_SCENE_XPACKAGE:            return RTKindConstructors::kind_package(K_scene);
+		case K_DIALOGUE_BEAT_XPACKAGE:    return RTKindConstructors::kind_package(K_dialogue_beat);
+		case K_DIALOGUE_LINE_XPACKAGE:    return RTKindConstructors::kind_package(K_dialogue_line);
 	}
 	internal_error("unknown exotic package");
 	return NULL;
diff --git a/inform7/runtime-module/Chapter 5/Kind Constructors.w b/inform7/runtime-module/Chapter 5/Kind Constructors.w
index b08326a89..b46c1c8cf 100644
--- a/inform7/runtime-module/Chapter 5/Kind Constructors.w	
+++ b/inform7/runtime-module/Chapter 5/Kind Constructors.w	
@@ -253,6 +253,16 @@ inter_name *RTKindConstructors::get_iname(kind *K) {
 		Hierarchy::make_available(K->construct->compilation_data.pr_iname);
 		return K->construct->compilation_data.pr_iname;
 	}
+	if (Kinds::eq(K, K_dialogue_beat))  {
+		K->construct->compilation_data.pr_iname = Hierarchy::find(PRINT_DIALOGUE_BEAT_HL);
+		Hierarchy::make_available(K->construct->compilation_data.pr_iname);
+		return K->construct->compilation_data.pr_iname;
+	}
+	if (Kinds::eq(K, K_dialogue_line))  {
+		K->construct->compilation_data.pr_iname = Hierarchy::find(PRINT_DIALOGUE_LINE_HL);
+		Hierarchy::make_available(K->construct->compilation_data.pr_iname);
+		return K->construct->compilation_data.pr_iname;
+	}
 
 	package_request *R = NULL;
 	int external = TRUE;
diff --git a/inform7/values-module/Chapter 2/Rvalues.w b/inform7/values-module/Chapter 2/Rvalues.w
index 89adc7b7a..17da527e7 100644
--- a/inform7/values-module/Chapter 2/Rvalues.w	
+++ b/inform7/values-module/Chapter 2/Rvalues.w	
@@ -35,6 +35,10 @@ parse_node *Rvalues::from_binary_predicate(binary_predicate *val) {
 		CONV_FROM(binary_predicate, Kinds::base_construction(CON_relation)) }
 parse_node *Rvalues::from_constant_phrase(constant_phrase *val) { 
 		CONV_FROM(constant_phrase, Kinds::base_construction(CON_phrase)) }
+parse_node *Rvalues::from_dialogue_beat(dialogue_beat *val) { 
+		CONV_FROM(dialogue_beat, K_dialogue_beat) }
+parse_node *Rvalues::from_dialogue_line(dialogue_line *val) { 
+		CONV_FROM(dialogue_line, K_dialogue_line) }
 parse_node *Rvalues::from_equation(equation *val) { 
 		CONV_FROM(equation, K_equation) }
 parse_node *Rvalues::from_named_rulebook_outcome(named_rulebook_outcome *val) { 
diff --git a/scripts/inform.mkscript b/scripts/inform.mkscript
index 7f7f2f877..3ac3248de 100644
--- a/scripts/inform.mkscript
+++ b/scripts/inform.mkscript
@@ -153,6 +153,7 @@ INFORM6WEB = inform6
 {component type: web symbol: COMMANDPARSERKIT     webname: CommandParserKit     path: inform7/Internal/Inter/CommandParserKit     set: kits}
 {component type: web symbol: BASICINFORMEXTRASKIT webname: BasicInformExtrasKit path: inform7/Internal/Inter/BasicInformExtrasKit set: kits}
 {component type: web symbol: ENGLISHLANGUAGEKIT   webname: EnglishLanguageKit   path: inform7/Internal/Inter/EnglishLanguageKit   set: kits}
+{component type: web symbol: DIALOGUEKIT          webname: DialogueKit          path: inform7/Internal/Inter/DialogueKit          set: kits}
 
 {component type: web symbol: STANDARDRULES        webname: standard_rules       path: inform7/extensions/standard_rules           set: extensions}
 {component type: web symbol: BASICINFORM          webname: basic_inform         path: inform7/extensions/basic_inform             set: extensions}
diff --git a/scripts/inform.rmscript b/scripts/inform.rmscript
index 1a63a7f2f..defca4a3b 100644
--- a/scripts/inform.rmscript
+++ b/scripts/inform.rmscript
@@ -131,6 +131,7 @@ The following webs are the source for kits of Inter code shipped with Inform (at
 {kit name: EnglishLanguageKit   purpose: Support for English as the natural language used}
 {kit name: CommandParserKit     purpose: Support for parsing turn-by-turn commands in interactive fiction}
 {kit name: BasicInformExtrasKit purpose: Additional support needed only if the Standard Rules are not used}
+{kit name: DialogueKit          purpose: Additional support for dialogue (under construction)}
 
 ### Extensions shipped with Inform
 
diff --git a/services/kinds-module/Chapter 2/Familiar Kinds.w b/services/kinds-module/Chapter 2/Familiar Kinds.w
index 20893563e..8587c4572 100644
--- a/services/kinds-module/Chapter 2/Familiar Kinds.w	
+++ b/services/kinds-module/Chapter 2/Familiar Kinds.w	
@@ -93,6 +93,8 @@ Inform. Some standard kinds follow. Some belong only to features; if the
 feature in question is inactive, they will remain |NULL| and do nothing.
 
 = (early code)
+kind *K_dialogue_beat = NULL;
+kind *K_dialogue_line = NULL;
 kind *K_equation = NULL;
 kind *K_grammatical_gender = NULL;
 kind *K_natural_language = NULL;
@@ -177,6 +179,8 @@ kind_constructor **FamiliarKinds::known_con(text_stream *sn) {
 
 kind **FamiliarKinds::known_kind(text_stream *sn) {
 	IDENTIFIERS_CORRESPOND("ARITHMETIC_VALUE_TY", &K_arithmetic_value);
+	IDENTIFIERS_CORRESPOND("DIALOGUE_BEAT_TY", &K_dialogue_beat);
+	IDENTIFIERS_CORRESPOND("DIALOGUE_LINE_TY", &K_dialogue_line);
 	IDENTIFIERS_CORRESPOND("ENUMERATED_VALUE_TY", &K_enumerated_value);
 	IDENTIFIERS_CORRESPOND("EQUATION_TY", &K_equation);
 	IDENTIFIERS_CORRESPOND("TEXT_TY", &K_text);
diff --git a/services/syntax-module/Chapter 2/Syntax Trees.w b/services/syntax-module/Chapter 2/Syntax Trees.w
index f62689661..7d0fa03f8 100644
--- a/services/syntax-module/Chapter 2/Syntax Trees.w	
+++ b/services/syntax-module/Chapter 2/Syntax Trees.w	
@@ -30,6 +30,7 @@ typedef struct parse_node_tree {
 	struct parse_node *bud_parent_stack[MAX_BUD_STACK_SIZE];
 	struct parse_node *last_sentence; /* cached position in tree */
 	int allow_last_sentence_cacheing;
+	int contains_dialogue;
 	int trace_sentences;
 	HEADING_TREE_SYNTAX_TYPE *headings;
 	CLASS_DEFINITION
@@ -42,6 +43,7 @@ parse_node_tree *SyntaxTree::new(void) {
 	T->last_sentence = NULL;
 	T->allow_last_sentence_cacheing = FALSE;
 	T->trace_sentences = FALSE;
+	T->contains_dialogue = FALSE;
 	SyntaxTree::push_bud(T, T->root_node);
 	#ifdef NEW_HEADING_TREE_SYNTAX_CALLBACK
 	T->headings = NEW_HEADING_TREE_SYNTAX_CALLBACK(T);
diff --git a/services/syntax-module/Chapter 3/Sentences.w b/services/syntax-module/Chapter 3/Sentences.w
index b7bd173b4..e8ae070c0 100644
--- a/services/syntax-module/Chapter 3/Sentences.w	
+++ b/services/syntax-module/Chapter 3/Sentences.w	
@@ -706,6 +706,7 @@ here. This hand-tooled parser is annoyingly long to write out, but only in
 order to catch improbable unmatched-bracket errors with tidy error messages.
 
 @ =
+	T->contains_dialogue = TRUE;
 	if ((Lexer::word(Wordings::first_wn(W)) == OPENBRACKET_V) &&
 		(Lexer::word(Wordings::last_wn(W)) == CLOSEBRACKET_V))
 		@;