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); + }

§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 000000000..a02d30e0c
Binary files /dev/null and b/inform7/Internal/Inter/DialogueKit/arch-16.interb differ
diff --git a/inform7/Internal/Inter/DialogueKit/arch-16d.interb b/inform7/Internal/Inter/DialogueKit/arch-16d.interb
new file mode 100644
index 000000000..71bd495f9
Binary files /dev/null and b/inform7/Internal/Inter/DialogueKit/arch-16d.interb differ
diff --git a/inform7/Internal/Inter/DialogueKit/arch-32.interb b/inform7/Internal/Inter/DialogueKit/arch-32.interb
new file mode 100644
index 000000000..b9d247615
Binary files /dev/null and b/inform7/Internal/Inter/DialogueKit/arch-32.interb differ
diff --git a/inform7/Internal/Inter/DialogueKit/arch-32d.interb b/inform7/Internal/Inter/DialogueKit/arch-32d.interb
new file mode 100644
index 000000000..67bf802f1
Binary files /dev/null and b/inform7/Internal/Inter/DialogueKit/arch-32d.interb differ
diff --git a/inform7/Internal/Inter/DialogueKit/kinds/Dialogue.neptune b/inform7/Internal/Inter/DialogueKit/kinds/Dialogue.neptune
new file mode 100644
index 000000000..9e2c4abc2
--- /dev/null
+++ b/inform7/Internal/Inter/DialogueKit/kinds/Dialogue.neptune
@@ -0,0 +1,33 @@
+builtin base DIALOGUE_BEAT_TY {
+	conforms-to: ENUMERATED_VALUE_TY
+	singular: dialogue beat
+	plural: dialogue beats
+
+	default-value: 0
+	loop-domain-schema: for (*1=1: *1<=NUMBER_DIALOGUE_BEATS_CREATED: *1++)
+	constant-compilation-method: quantitative
+
+	printing-routine: PrintDialogueBeatName
+
+!	documentation-reference: kind_verb
+!	index-priority: 6
+!	index-default-value: verb be
+	specification-text: A beat of dialogue occurring in a section of dialogue.
+}
+
+builtin base DIALOGUE_LINE_TY {
+	conforms-to: ENUMERATED_VALUE_TY
+	singular: dialogue line
+	plural: dialogue lines
+
+	default-value: 0
+	loop-domain-schema: for (*1=1: *1<=NUMBER_DIALOGUE_LINES_CREATED: *1++)
+	constant-compilation-method: quantitative
+
+	printing-routine: PrintDialogueLineName
+
+!	documentation-reference: kind_verb
+!	index-priority: 6
+!	index-default-value: verb be
+	specification-text: A line of dialogue occurring in a section of dialogue.
+}
diff --git a/inform7/Internal/Inter/DialogueKit/kit_metadata.json b/inform7/Internal/Inter/DialogueKit/kit_metadata.json
new file mode 100644
index 000000000..88eaf8a75
--- /dev/null
+++ b/inform7/Internal/Inter/DialogueKit/kit_metadata.json
@@ -0,0 +1,13 @@
+{
+    "is": {
+        "type": "kit",
+        "title": "DialogueKit",
+        "version": "10.2.0-beta+6V51"
+    },
+    "activates": [ "dialogue" ],
+    "kit-details": {
+        "has-priority": 3,
+        "defines-Main": false,
+        "provides-kinds": [ "Dialogue.neptune" ]
+    }
+}
\ No newline at end of file
diff --git a/inform7/Internal/Inter/EnglishLanguageKit/kit_metadata.json b/inform7/Internal/Inter/EnglishLanguageKit/kit_metadata.json
index d64e20044..3d5c8cd60 100644
--- a/inform7/Internal/Inter/EnglishLanguageKit/kit_metadata.json
+++ b/inform7/Internal/Inter/EnglishLanguageKit/kit_metadata.json
@@ -2,7 +2,7 @@
     "is": {
         "type": "kit",
         "title": "EnglishLanguageKit",
-        "version": "10.2.0-beta+6V51"
+        "version": "10.2.0-beta+6V52"
     },
     "needs": [ {
         "need": {
diff --git a/inform7/Internal/Inter/WorldModelKit/kit_metadata.json b/inform7/Internal/Inter/WorldModelKit/kit_metadata.json
index 44b5d1d87..810519e79 100644
--- a/inform7/Internal/Inter/WorldModelKit/kit_metadata.json
+++ b/inform7/Internal/Inter/WorldModelKit/kit_metadata.json
@@ -2,7 +2,7 @@
     "is": {
         "type": "kit",
         "title": "WorldModelKit",
-        "version": "10.2.0-beta+6V51"
+        "version": "10.2.0-beta+6V52"
     },
     "needs": [ {
         "need": {
diff --git a/inform7/Tests/Test Problems/_Results_Ideal/PM_EmptyDialogueClause.txt b/inform7/Tests/Test Problems/_Results_Ideal/PM_EmptyDialogueClause.txt
index ef88e7e5c..978775e4d 100644
--- a/inform7/Tests/Test Problems/_Results_Ideal/PM_EmptyDialogueClause.txt	
+++ b/inform7/Tests/Test Problems/_Results_Ideal/PM_EmptyDialogueClause.txt	
@@ -7,8 +7,4 @@ Problem__ PM_EmptyDialogueClause
   >--> 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))
 		@;