diff --git a/docs/assertions-module/2-ar.html b/docs/assertions-module/2-ar.html index fd76909b6..9a8fbbd1d 100644 --- a/docs/assertions-module/2-ar.html +++ b/docs/assertions-module/2-ar.html @@ -193,7 +193,7 @@ conclusion we would have reached. if (Annotations::node_has(current_sentence, implicit_in_creation_of_ANNOT)) return; #ifdef IF_MODULE - if ((PL::Map::is_a_direction(infsx)) && + if ((Map::subject_is_a_direction(infsx)) && ((InstanceSubjects::to_object_instance(infsx) == NULL) || (InstanceSubjects::to_object_instance(infsy_full)))) infsx = NULL; #endif diff --git a/docs/assertions-module/2-cs.html b/docs/assertions-module/2-cs.html index 1aeb91759..828a0d698 100644 --- a/docs/assertions-module/2-cs.html +++ b/docs/assertions-module/2-cs.html @@ -127,14 +127,13 @@ and we ask the lingu SyntaxTree::graft(Task::syntax_tree(), VP_PN, p); if (SyntaxTree::is_trace_set(Task::syntax_tree())) LOG("$T\n", p); Check that this is allowed, if it occurs in the Options file3.3; - #ifdef IF_MODULE - PL::MapDirections::look_for_direction_creation(p); - #endif PropertySentences::look_for_property_creation(p); Issue problem message if either subject or object contains mismatched brackets3.4; Issue problem message if subject starts with double-quoted literal text3.5; - if ((VP_PN->next) && (VP_PN->next->next) && (Diagrams::is_possessive_RELATIONSHIP(VP_PN->next->next))) + if ((VP_PN->next) && (VP_PN->next->next) && + (Diagrams::is_possessive_RELATIONSHIP(VP_PN->next->next))) Diagram property callings3.6; + PluginCalls::new_assertion_notify(p); } else { LOG("$T\n", p); <no-primary-verb-diagnosis>(W); diff --git a/docs/assertions-module/4-ass.html b/docs/assertions-module/4-ass.html index 48c396e57..f2dc05e9f 100644 --- a/docs/assertions-module/4-ass.html +++ b/docs/assertions-module/4-ass.html @@ -526,7 +526,7 @@ at which point it becomes a P
     #ifdef IF_MODULE
     if ((Node::get_type(px) == PROPER_NOUN_NT) &&
-        (PL::Map::is_a_direction(Node::get_subject(px))) &&
+        (Map::subject_is_a_direction(Node::get_subject(px))) &&
         (Node::get_type(py->down) == PROPER_NOUN_NT)) {
         int np = problem_count;
         Assertions::make_coupling(px, py->down);  A is a B
@@ -1391,10 +1391,10 @@ in this case.
     #ifdef IF_MODULE
     if ((PL::MapDirections::get_mapping_relationship(px)) &&
         (PL::MapDirections::get_mapping_relationship(py))) {
-        PL::Map::enter_one_way_mode();
+        Map::enter_one_way_mode();
         Assertions::make_coupling(px, py->down);
         Assertions::make_coupling(px->down, py);
-        PL::Map::exit_one_way_mode();
+        Map::exit_one_way_mode();
         return;
     }
     #endif
@@ -2082,8 +2082,8 @@ these sentences falls into case 41.
     }
 
     #ifdef IF_MODULE
-    if ((PL::Map::is_a_direction(Node::get_subject(px))) ||
-        (PL::Map::is_a_direction(Node::get_subject(py))))
+    if ((Map::subject_is_a_direction(Node::get_subject(px))) ||
+        (Map::subject_is_a_direction(Node::get_subject(py))))
         This is a map connection referred to metonymically6.3.41.1
     else
     #endif
@@ -2119,7 +2119,7 @@ these sentences falls into case 41.
         return;
     }
     inference_subject *target = Node::get_subject(py), *way = Node::get_subject(px);
-    if (PL::Map::is_a_direction(target)) {
+    if (Map::subject_is_a_direction(target)) {
         target = Node::get_subject(px); way = Node::get_subject(py);
     }
     if (global_pass_state.pass == 2) {
@@ -2130,7 +2130,7 @@ these sentences falls into case 41.
                 "like saying '20 is north'. This is an odd thing "
                 "to say, and makes me think that I've misunderstood you.");
         } else {
-            PL::Map::connect(Anaphora::get_current_subject(), target, way);
+            Map::connect(Anaphora::get_current_subject(), target, way);
         }
     }
 
diff --git a/docs/assertions-module/4-rk.html b/docs/assertions-module/4-rk.html index b945741f5..601bea3e0 100644 --- a/docs/assertions-module/4-rk.html +++ b/docs/assertions-module/4-rk.html @@ -172,9 +172,9 @@ objects or values, but there are two exceptional cases to take care of. if ((iy == NULL) || (id == NULL)) internal_error("malformed directional subtree"); if (Rvalues::is_nothing_object_constant(value)) - PL::Map::connect(iy, NULL, id); + Map::connect(iy, NULL, id); else if (Rvalues::is_object(Node::get_evaluation(value))) - PL::Map::connect(iy, Node::get_subject(value), id); + Map::connect(iy, Node::get_subject(value), id); else { LOG("Val is $P\n", value); StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_MapToNonobject), diff --git a/docs/core-module/1-cp.html b/docs/core-module/1-cp.html index 34bf04b4e..70262bb75 100644 --- a/docs/core-module/1-cp.html +++ b/docs/core-module/1-cp.html @@ -251,6 +251,8 @@ We begin with core itself. enum backdrop_found_in_notice_CLASS enum bp_runtime_implementation_CLASS enum definition_CLASS +enum door_dir_notice_CLASS +enum door_to_notice_CLASS enum dval_written_CLASS enum i6_inclusion_matter_CLASS enum internal_test_case_CLASS @@ -268,6 +270,8 @@ We begin with core itself. DECLARE_CLASS(backdrop_found_in_notice) DECLARE_CLASS(bp_runtime_implementation) DECLARE_CLASS(definition) +DECLARE_CLASS(door_dir_notice) +DECLARE_CLASS(door_to_notice) DECLARE_CLASS(dval_written) DECLARE_CLASS(i6_inclusion_matter) DECLARE_CLASS(internal_test_case) @@ -305,8 +309,6 @@ We begin with core itself. enum command_index_entry_CLASS enum connected_submap_CLASS enum direction_inference_data_CLASS -enum door_dir_notice_CLASS -enum door_to_notice_CLASS enum EPS_map_level_CLASS enum found_in_inference_data_CLASS enum grammar_line_CLASS @@ -342,8 +344,6 @@ We begin with core itself. DECLARE_CLASS(command_index_entry) DECLARE_CLASS(connected_submap) DECLARE_CLASS(direction_inference_data) -DECLARE_CLASS(door_dir_notice) -DECLARE_CLASS(door_to_notice) DECLARE_CLASS(EPS_map_level) DECLARE_CLASS(found_in_inference_data) DECLARE_CLASS(grammar_line) diff --git a/docs/core-module/3-pc.html b/docs/core-module/3-pc.html index 2d2318ffc..c8786d4be 100644 --- a/docs/core-module/3-pc.html +++ b/docs/core-module/3-pc.html @@ -72,7 +72,7 @@ function togglePopup(material_id) {

The interface between the main compiler and its plugins.

-
+

§1. The following set of functions is an API for the main compiler to consult with the plugins; put another way, it is also an API for the plugins to @@ -223,7 +223,19 @@ instance. PLUGINS_CALL(REFINE_IMPLICIT_NOUN_PLUG, p); } -

§11. Called from The Equality Relation Revisited (in assertions) when we have +

§11. Called from Classifying Sentences (in assertions) to give plugins the chance +of an early look at a newly-read assertion. For example, the map plugin uses +this to spot that a sentence will create a new direction. +

+ +
enum NEW_ASSERTION_NOTIFY_PLUG
+
+
+int PluginCalls::new_assertion_notify(parse_node *p) {
+    PLUGINS_CALL(NEW_ASSERTION_NOTIFY_PLUG, p);
+}
+
+

§12. Called from The Equality Relation Revisited (in assertions) when we have to decide if it's valid to ask or declare that two things are the same. Returning TRUE says that it is always valid; returning FALSE leaves it to the regular machinery. This plug can therefore only be used to permit @@ -237,7 +249,7 @@ additional usages, not to restrict existing ones. PLUGINS_CALL(TYPECHECK_EQUALITY_PLUG, K1, K2); } -

§12. Called from Assertions (in assertions) to warn plugins that a variable +

§13. Called from Assertions (in assertions) to warn plugins that a variable is now being assigned a value by an explicit assertion sentence.

@@ -248,7 +260,7 @@ is now being assigned a value by an explicit assertion sentence. PLUGINS_CALL(VARIABLE_VALUE_NOTIFY_PLUG, q, val); } -

§13. Influencing values. Called from Rvalues (in values) to allow plugins to compile rvalues in +

§14. Influencing values. Called from Rvalues (in values) to allow plugins to compile rvalues in eccentric ways of their own: not in fact just for the whimsy of it, but to make it possible for plugins to support base kinds of their own. For example, the "actions" plugin needs this to deal with the "stored action" kind. @@ -261,7 +273,7 @@ the "actions" plugin needs this to deal with the "stored action" kind. PLUGINS_CALL(COMPILE_CONSTANT_PLUG, VH, K, spec); } -

§14. Called from Specifications (in values) to ask if there is some reason why +

§15. Called from Specifications (in values) to ask if there is some reason why a rule about I1 should be thought broader in scope than one about I2. This is used by the regions plugin when one is a sub-region of the other. This is expected to behave as a strcmp-like sorting function, with a positive @@ -275,7 +287,7 @@ return value saying I1 PLUGINS_CALL(MORE_SPECIFIC_PLUG, I1, I2); } -

§15. Called from Constants and Descriptions (in values) to give plugins a chance +

§16. Called from Constants and Descriptions (in values) to give plugins a chance to parse text which might otherwise be meaningless (or mean something different) and make it a "composite noun-quantifier" such as "everywhere" or "nothing". The main compiler does not recognise "everywhere" because it has no concept @@ -290,7 +302,7 @@ of space, but the spatial plugin does, and this is how. PLUGINS_CALL(PARSE_COMPOSITE_NQS_PLUG, W, DW, quantifier_used, some_kind); } -

§16. Influencing knowledge. Called from The Model World (in knowledge) to invite the plugin to participate +

§17. Influencing knowledge. Called from The Model World (in knowledge) to invite the plugin to participate in stages I to V of the completion process. This may involve using contextual reasoning to draw further inferences.

@@ -302,7 +314,7 @@ reasoning to draw further inferences. PLUGINS_CALL(COMPLETE_MODEL_PLUG, stage); } -

§17. Called from Inference Subjects (in knowledge) to invite the plugin to +

§18. Called from Inference Subjects (in knowledge) to invite the plugin to create any additional inference subjects it might want to reason about. In practice, this tends to be used to create preliminary subjects to stand in for significant kinds before those kinds are ready to be created. @@ -315,7 +327,7 @@ for significant kinds before those kinds are ready to be created. PLUGINS_CALLV(CREATE_INFERENCE_SUBJECTS_PLUG); } -

§18. Called from Indefinite Appearance (in knowledge) to ask the plugins what +

§19. Called from Indefinite Appearance (in knowledge) to ask the plugins what inferences, if any, to draw from a double-quoted text standing as an entire sentence. The infs is the subject which was being talked about at the time the text was quoted, and therefore presumably is what the text should describe. @@ -328,7 +340,7 @@ the text was quoted, and therefore presumably is what the text should describe. PLUGINS_CALL(DEFAULT_APPEARANCE_PLUG, infs, txt); } -

§19. Called from Inferences (in knowledge) when an inference is drawn about +

§20. Called from Inferences (in knowledge) when an inference is drawn about something. This does not, of course, necessarily mean that this will actually be the property of something: the inference might turn out to be mistaken. The mapping plugin uses this to infer further that if something is said to be a @@ -342,7 +354,7 @@ map connection to somewhere else, then it is probably a room. PLUGINS_CALL(INFERENCE_DRAWN_NOTIFY_PLUG, I, subj); } -

§20. Called from Kind Subjects (in knowledge). Early in the run, before some kinds +

§21. Called from Kind Subjects (in knowledge). Early in the run, before some kinds are created, placeholder inference subjects are created to stand in for them; this call enables plugins to recognise certain texts as referring to those.

@@ -354,7 +366,7 @@ this call enables plugins to recognise certain texts as referring to those. PLUGINS_CALL(NAME_TO_EARLY_INFS_PLUG, W, infs); } -

§21. Called from Kind Subjects (in knowledge) to warn plugins about a new kind, +

§22. Called from Kind Subjects (in knowledge) to warn plugins about a new kind, which in practice enables them to spot from the name that it is actually a kind they want to provide built-in support for: thus the actions plugin reacts to the name "stored action", for example. K is the newcomer, super its super-kind, @@ -370,7 +382,7 @@ source text (such as "container"). PLUGINS_CALL(NEW_BASE_KIND_NOTIFY_PLUG, K, d, W); } -

§22. Called from Instances (in knowledge) to warn plugins that a new instance has +

§23. Called from Instances (in knowledge) to warn plugins that a new instance has been created. For example, the figures plugin needs to know this so that it can see when a new illustration has been created.

@@ -387,7 +399,7 @@ sure you're not dealing with an object. PLUGINS_CALL(NEW_INSTANCE_NOTIFY_PLUG, nc); } -

§23. Called from Property Permissions (in knowledge) to warn plugins that a subject +

§24. Called from Property Permissions (in knowledge) to warn plugins that a subject has been given permission to hold a property; the parsing plugin, for example, uses this to attach a visibility flag.

@@ -399,7 +411,7 @@ uses this to attach a visibility flag. PLUGINS_CALL(NEW_PERMISSION_NOTIFY_PLUG, pp); } -

§24. Called from Properties (in knowledge) to warn plugins that a property has +

§25. Called from Properties (in knowledge) to warn plugins that a property has been created, which they can use to spot properties with special significance to them.

@@ -411,7 +423,7 @@ to them. PLUGINS_CALL(NEW_PROPERTY_NOTIFY_PLUG, prn); } -

§25. Called from Inference Subjects (in knowledge) to warn plugins that a subject +

§26. Called from Inference Subjects (in knowledge) to warn plugins that a subject has been created, which they can use to spot subjects with special significance to them.

@@ -423,7 +435,7 @@ to them. PLUGINS_CALL(NEW_SUBJECT_NOTIFY_PLUG, subj); } -

§26. Called from Nonlocal Variables (in knowledge) to warn plugins that a new +

§27. Called from Nonlocal Variables (in knowledge) to warn plugins that a new variable has been created, which they can use to spot variables with special significance to them.

@@ -435,7 +447,7 @@ significance to them. PLUGINS_CALL(NEW_VARIABLE_NOTIFY_PLUG, q); } -

§27. Called from Instances (in knowledge) to warn plugins that the kind of an +

§28. Called from Instances (in knowledge) to warn plugins that the kind of an instance is about to be set. This happens most often when the instance is created, but can also happen again, refining the kind to a subkind, when the instance is an object. @@ -448,7 +460,7 @@ the instance is an object. PLUGINS_CALL(SET_KIND_NOTIFY_PLUG, I, k); } -

§28. Called from Kind Subjects (in knowledge) when one kind of object is made a +

§29. Called from Kind Subjects (in knowledge) when one kind of object is made a subkind of another, as for example when "container" is a made a subkind of "thing". The plugin should return TRUE if it wishes to forbid this, and if so, it had better throw a problem message, or the user will be @@ -466,7 +478,7 @@ regions plugin does with the "region" kind. PLUGINS_CALL(SET_SUBKIND_NOTIFY_PLUG, sub, super); } -

§29. Influencing if. Called from Action Patterns (in if) to validate optional parameters on the +

§30. Influencing if. Called from Action Patterns (in if) to validate optional parameters on the "going" action. The mapping plugin uses this.

@@ -478,7 +490,7 @@ regions plugin does with the "region" kind. PLUGINS_CALL(CHECK_GOING_PLUG, from, to, by, through, pushing); } -

§30. Influencing index. Called from Index Physical World (in index) to add something (if it wishes) +

§31. Influencing index. Called from Index Physical World (in index) to add something (if it wishes) to the index description of an instance in the spatial model. For example, the regions plugin uses this to put colour chips next to names of regions.

@@ -490,7 +502,7 @@ the regions plugin uses this to put colour chips next to names of regions. PLUGINS_CALL(ADD_TO_WORLD_INDEX_PLUG, OUT, O); } -

§31. Called from Index Physical World (in index) to add something (if it wishes) +

§32. Called from Index Physical World (in index) to add something (if it wishes) to the textual description of an instance in the spatial model. For example, the mapping plugin uses this to say where a door leads.

diff --git a/docs/if-module/1-im.html b/docs/if-module/1-im.html index 73c6e3f32..1c26bbd04 100644 --- a/docs/if-module/1-im.html +++ b/docs/if-module/1-im.html @@ -166,7 +166,7 @@ nothing except to be a parent to them; it has no activation function. bibliographic_plugin = PluginManager::new(&BibliographicData::start, I"bibliographic data", ifp); chronology_plugin = PluginManager::new(&Chronology::start_plugin, I"chronology", ifp); devices_plugin = PluginManager::new(&PL::Devices::start, I"devices", ifp); - map_plugin = PluginManager::new(&PL::Map::start, I"mapping", ifp); + map_plugin = PluginManager::new(&Map::start, I"mapping", ifp); persons_plugin = PluginManager::new(&PL::Persons::start, I"persons", ifp); player_plugin = PluginManager::new(&Player::start, I"player", ifp); regions_plugin = PluginManager::new(&Regions::start, I"regions", ifp); diff --git a/docs/if-module/2-bd.html b/docs/if-module/2-bd.html index 510fef2e0..e983d18ce 100644 --- a/docs/if-module/2-bd.html +++ b/docs/if-module/2-bd.html @@ -523,10 +523,7 @@ just too short to care overmuch about this.
     int i, pos = STREAM_EXTENT(OUT), whitespace_count=0, black_chars_written = 0;
-    int N = 100;
-    #ifdef IF_MODULE
-    N = BIBLIOGRAPHIC_TEXT_TRUNCATION;
-    #endif
+    int N = BIBLIOGRAPHIC_TEXT_TRUNCATION;
     if (p[0] == '"') p++;
     for (i=0; p[i]; i++) {
         if (STREAM_EXTENT(OUT) - pos >= N) break;
diff --git a/docs/if-module/3-bck.html b/docs/if-module/3-bck.html
index f4e4df0dd..80c70a893 100644
--- a/docs/if-module/3-bck.html
+++ b/docs/if-module/3-bck.html
@@ -258,7 +258,7 @@ can be said to be "everywhere", which nothing else can).
                 The object is found in many rooms or in whole regions, so make it a routine11.4;
             if ((val_of_found_in == NULL) && (Instances::of_kind(I, K_backdrop)))
                 The object is found nowhere, so give it a stub found-in property and mark it absent11.5;
-            if (val_of_found_in) PL::Map::set_found_in(I, val_of_found_in);
+            if (val_of_found_in) Map::set_found_in(I, val_of_found_in);
         }
     }
     return FALSE;
diff --git a/docs/if-module/3-em.html b/docs/if-module/3-em.html
index ccb40df74..8a3f59d9b 100644
--- a/docs/if-module/3-em.html
+++ b/docs/if-module/3-em.html
@@ -409,7 +409,7 @@ If all are null, then the global scope is used.
 

§14.

-int PL::EPSMap::index_map_with_SMF(int task, parse_node *V, wording *NPs) {
+int PL::EPSMap::index_map_with_SMF(int task, parse_node *V, wording *NPs) {
     wording OW = (NPs)?(NPs[1]):EMPTY_WORDING;
     switch (task) {  "Index map with ..."
         case ACCEPT_SMFT:
diff --git a/docs/if-module/3-mcr.html b/docs/if-module/3-mcr.html
index 40c33e5ed..2b1d9ed2a 100644
--- a/docs/if-module/3-mcr.html
+++ b/docs/if-module/3-mcr.html
@@ -73,59 +73,29 @@ function togglePopup(material_id) {
     
 

To define one binary predicate for each map direction, such as "mapped north of".

-
+
-

§1. Family.

+

§1. Family. This section creates a family of implicit relations (implemented as binary +predicates) corresponding to the different directions. +

+ +

For every direction created, a predicate is created for the possibility of +a map connection. For instance, "if Versailles is mapped north of the +Metro" tests the "mapped-north" BP. +

 bp_family *map_connecting_bp_family = NULL;
 
 void PL::MapDirections::start(void) {
     map_connecting_bp_family = BinaryPredicateFamilies::new();
-    METHOD_ADD(map_connecting_bp_family, TYPECHECK_BPF_MTID, PL::MapDirections::typecheck);
-    METHOD_ADD(map_connecting_bp_family, ASSERT_BPF_MTID, PL::MapDirections::assert);
-    METHOD_ADD(map_connecting_bp_family, SCHEMA_BPF_MTID, PL::MapDirections::schema);
-    METHOD_ADD(map_connecting_bp_family, DESCRIBE_FOR_PROBLEMS_BPF_MTID, PL::MapDirections::describe_for_problems);
-    METHOD_ADD(map_connecting_bp_family, DESCRIBE_FOR_INDEX_BPF_MTID, PL::MapDirections::describe_for_index);
+    METHOD_ADD(map_connecting_bp_family, TYPECHECK_BPF_MTID, PL::MapDirections::typecheck);
+    METHOD_ADD(map_connecting_bp_family, ASSERT_BPF_MTID, PL::MapDirections::assert);
+    METHOD_ADD(map_connecting_bp_family, DESCRIBE_FOR_INDEX_BPF_MTID,
+        PL::MapDirections::describe_for_index);
 }
 
-

§2. This section creates a family of implicit relations (implemented as binary -predicates) corresponding to the different directions. -

- -

For every direction created, a predicate is created for the possibility of -a map connection. For instance, "if Versailles is mapped north of the -Metro" tests the "mapped-north" BP. There is also one general relation -built in: -

- -
-binary_predicate *R_adjacency = NULL;
-
-

§3. The adjacency relation. We may as well do this here: creating the relation "X is adjacent to Y". -

- -
-void PL::MapDirections::create_relations(void) {
-    R_adjacency =
-        BinaryPredicates::make_pair(spatial_bp_family,
-            BPTerms::new(infs_room),
-            BPTerms::new(infs_room),
-            I"adjacent-to", I"adjacent-from",
-            NULL, Calculus::Schemas::new("TestAdjacency(*1,*2)"),
-            PreformUtilities::wording(<relation-names>, ADJACENCY_RELATION_NAME));
-
-}
-
-

§4. There is nothing special about asserting this, so we don't intervene: -

- -
-int PL::MapDirections::assert_relations(binary_predicate *relation, instance *I0, instance *I1) {
-    return FALSE;
-}
-
-

§5. Subsequent creations. Every direction created has a relation associated with it: for instance, +

§2. Subsequent creations. Every direction created has a relation associated with it: for instance, "north" has the relation "X is mapped north of Y". Now a direction is a kind of object, but objects aren't created until after relations used to parse sentences are needed. In fact, however, directions are "noticed" @@ -133,13 +103,13 @@ at an earlier stage in Inform's run, so another two-step is needed:

-binary_predicate *PL::MapDirections::create_sketchy_mapping_direction(wording W) {
+binary_predicate *PL::MapDirections::create_sketchy_mapping_direction(wording W) {
     binary_predicate *bp;
-    Create the mapping BP for the new direction5.4;
+    Create the mapping BP for the new direction2.3;
     return bp;
 }
 
-

§5.1. When each direction is created, so are corresponding relations and +

§2.1. When each direction is created, so are corresponding relations and prepositional uses: for example, "northeast" makes "mapping northeast" as a relation, and "mapped northeast of" as a prepositional usage.

@@ -193,7 +163,7 @@ want to allow room names to contain direction names on occasion: ... from
-

§5.2. Two of the directions are special to mapping, because they have to be parsed +

§2.2. Two of the directions are special to mapping, because they have to be parsed slighly differently. (These are the English names; there is no need to translate this to other languages.)

@@ -204,22 +174,14 @@ this to other languages.) outside
-

§5.3. Directions are detected in sentences having the form "D is a direction." This +

§2.3. Directions are detected in sentences having the form "D is a direction." This is intentionally done very early on.

define MAX_DIRECTIONS 100  the Standard Rules define only 12, so this is plenty
+define MAX_MAPPING_RELATION_NAME_LENGTH MAX_WORDS_IN_DIRECTION*MAX_WORD_LENGTH+10
 
-
-parse_node *directions_noticed[MAX_DIRECTIONS];
-binary_predicate *direction_relations_noticed[MAX_DIRECTIONS];
-int no_directions_noticed = 0;
-
-

§5.4.

- -
define MAX_MAPPING_RELATION_NAME_LENGTH MAX_WORDS_IN_DIRECTION*MAX_WORD_LENGTH+10
-
-

Create the mapping BP for the new direction5.4 = +

Create the mapping BP for the new direction2.3 =

@@ -259,29 +221,23 @@ is intentionally done very early on.
 
     DISCARD_TEXT(relname)
 
- -

§6. That was one step, and here's the second. At this point we have created the +

+

§3. That was one step, and here's the second. At this point we have created the instance I for the direction, and given it the kind "direction". That makes it possible to complete the details of the BP.

-

ident can be any string of text which evaluates in I6 to the -object number of the direction object. It seems redundant here because -surely if we know I, we know its runtime representation; but that's not -true — we need to call this routine at a time when the final identifier -names for I6 objects have not yet been settled. -

-
 int mmp_call_counter = 0;
-void PL::MapDirections::make_mapped_predicate(instance *I, inter_name *ident) {
+void PL::MapDirections::make_mapped_predicate(instance *I) {
     wording W = Instances::get_name(I, FALSE);
     if ((Wordings::empty(W)) || (Wordings::length(W) > MAX_WORDS_IN_DIRECTION))
         internal_error("bad direction name");
     binary_predicate *bp = direction_relations_noticed[mmp_call_counter++];
     if (bp == NULL) {
         LOG("Improper text: %W\n", W);
-        StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_ImproperlyMadeDirection),
+        StandardProblems::sentence_problem(Task::syntax_tree(),
+            _p_(PM_ImproperlyMadeDirection),
             "directions must be created by only the simplest possible sentences",
             "in the form 'North-north-west is a direction' only. Using adjectives, "
             "'called', 'which', and so on is not allowed. (In practice this is not "
@@ -293,54 +249,30 @@ names for I6 objects have not yet been settled.
     bp->term_details[0] = BPTerms::new(NULL);
     bp->term_details[1] = BPTerms::new(NULL);
     BinaryPredicates::set_index_details(bp, "room/door", "room/door");
-    bp->task_functions[TEST_ATOM_TASK] = Calculus::Schemas::new("(MapConnection(*2,%n) == *1)", ident);
-    bp->task_functions[NOW_ATOM_TRUE_TASK] = Calculus::Schemas::new("AssertMapConnection(*2,%n,*1)", ident);
-    bp->task_functions[NOW_ATOM_FALSE_TASK] = Calculus::Schemas::new("AssertMapUnconnection(*2,%n,*1)", ident);
+    RTMap::set_map_schemas(bp, I);
     MAP_DATA(I)->direction_relation = bp;
 }
 
-

§7.

- -
-void PL::MapDirections::look_for_direction_creation(parse_node *pn) {
-    if (Node::get_type(pn) != SENTENCE_NT) return;
-    if ((pn->down == NULL) || (pn->down->next == NULL) || (pn->down->next->next == NULL)) return;
-    if (Node::get_type(pn->down) != VERB_NT) return;
-    if (Node::get_type(pn->down->next) != UNPARSED_NOUN_NT) return;
-    if (Node::get_type(pn->down->next->next) != UNPARSED_NOUN_NT) return;
-    current_sentence = pn;
-    pn = pn->down->next;
-    if (!((<notable-map-kinds>(Node::get_text(pn->next)))
-            && (<<r>> == 0))) return;
-    if (no_directions_noticed >= MAX_DIRECTIONS) {
-        StandardProblems::limit_problem(Task::syntax_tree(), _p_(PM_TooManyDirections),
-            "different directions", MAX_DIRECTIONS);
-        return;
-    }
-    direction_relations_noticed[no_directions_noticed] =
-        PL::MapDirections::create_sketchy_mapping_direction(Node::get_text(pn));
-    directions_noticed[no_directions_noticed++] = pn;
-}
-
-

§8. Typechecking. This won't catch everything, but it will do. Run-time checking will pick up +

§4. Typechecking. This won't catch everything, but it will do. Run-time checking will pick up remaining anomalies.

-int PL::MapDirections::typecheck(bp_family *self, binary_predicate *bp,
+int PL::MapDirections::typecheck(bp_family *self, binary_predicate *bp,
         kind **kinds_of_terms, kind **kinds_required, tc_problem_kit *tck) {
     int t;
     for (t=0; t<2; t++)
         if ((Kinds::compatible(kinds_of_terms[t], K_room) == NEVER_MATCH) &&
             (Kinds::compatible(kinds_of_terms[t], K_door) == NEVER_MATCH)) {
         LOG("Term %d is %u but should be a room or door\n", t, kinds_of_terms[t]);
-        Propositions::Checker::issue_bp_typecheck_error(bp, kinds_of_terms[0], kinds_of_terms[1], tck);
+        Propositions::Checker::issue_bp_typecheck_error(bp, kinds_of_terms[0],
+            kinds_of_terms[1], tck);
         return NEVER_MATCH;
     }
     return ALWAYS_MATCH;
 }
 
-

§9. Assertion. Note that the following will infer IS_ROOM_INF for any source of a map +

§5. Assertion. Note that the following will infer IS_ROOM_INF for any source of a map connection — which will include doors. That doesn't matter, because the Spatial plugin uses these inferences only for objects whose kind is not explicitly given in the source text; and doors must always be specified as @@ -348,48 +280,38 @@ such.

-int PL::MapDirections::assert(bp_family *self, binary_predicate *bp,
+int PL::MapDirections::assert(bp_family *self, binary_predicate *bp,
         inference_subject *infs0, parse_node *spec0,
         inference_subject *infs1, parse_node *spec1) {
-    instance *o_dir = PL::MapDirections::get_mapping_direction(bp);
+    instance *o_dir = PL::MapDirections::get_mapping_direction(bp);
     inference_subject *infs_from = infs0;
     inference_subject *infs_to = infs1;
 
     SpatialInferences::infer_is_room(infs_from, prevailing_mood);
     if ((prevailing_mood >= 0) && (infs_to))
         SpatialInferences::infer_is_room(infs_to, LIKELY_CE);
-    PL::Map::infer_direction(infs_from, infs_to, o_dir);
+    Map::infer_direction(infs_from, infs_to, o_dir);
     return TRUE;
 }
 
-

§10. Compilation. We need do nothing special: these relations can be compiled from their schemas. -

+

§6. Indexing.

-int PL::MapDirections::schema(bp_family *self, int task, binary_predicate *bp, annotated_i6_schema *asch) {
-    return FALSE;
-}
-
-

§11. Problem message text.

- -
-int PL::MapDirections::describe_for_problems(bp_family *self, OUTPUT_STREAM, binary_predicate *bp) {
-    return FALSE;
-}
-void PL::MapDirections::describe_for_index(bp_family *self, OUTPUT_STREAM, binary_predicate *bp) {
+void PL::MapDirections::describe_for_index(bp_family *self, OUTPUT_STREAM,
+    binary_predicate *bp) {
     WRITE("map");
 }
 
-

§12. The correspondence with directions. (Speed really does not matter here.) +

§7. The correspondence with directions. Speed really does not matter here.

-binary_predicate *PL::MapDirections::get_mapping_relation(instance *dir) {
+binary_predicate *PL::MapDirections::get_mapping_relation(instance *dir) {
     if (dir == NULL) return NULL;
     return MAP_DATA(dir)->direction_relation;
 }
 
-instance *PL::MapDirections::get_mapping_direction(binary_predicate *bp) {
+instance *PL::MapDirections::get_mapping_direction(binary_predicate *bp) {
     if (bp == NULL) return NULL;
     instance *I;
     LOOP_OVER_INSTANCES(I, K_object)
@@ -401,14 +323,27 @@ such.
 instance *PL::MapDirections::get_mapping_relationship(parse_node *p) {
     binary_predicate *bp = Node::get_relationship(p);
     if ((bp) && (PluginManager::active(map_plugin))) {
-        instance *dir = PL::MapDirections::get_mapping_direction(
+        instance *dir = PL::MapDirections::get_mapping_direction(
             BinaryPredicates::get_reversal(bp));
-        if (dir == NULL) dir = PL::MapDirections::get_mapping_direction(bp);
+        if (dir == NULL) dir = PL::MapDirections::get_mapping_direction(bp);
         return dir;
     }
     return NULL;
 }
 
+

§8. The adjacency relation. There is also one general relation built in, though it belongs to the spatial family: +

+ +
+void PL::MapDirections::create_relations(void) {
+    BinaryPredicates::make_pair(spatial_bp_family,
+        BPTerms::new(infs_room),
+        BPTerms::new(infs_room),
+        I"adjacent-to", I"adjacent-from",
+        NULL, Calculus::Schemas::new("TestAdjacency(*1,*2)"),
+        PreformUtilities::wording(<relation-names>, ADJACENCY_RELATION_NAME));
+}
+
diff --git a/docs/if-module/3-scn.html b/docs/if-module/3-scn.html index e921da939..a16fca6c6 100644 --- a/docs/if-module/3-scn.html +++ b/docs/if-module/3-scn.html @@ -110,7 +110,7 @@ scenes — to express which, the CLASS_DEFINITION } scene; -
  • The structure scene_connector is accessed in 2/ri, 3/mcr, 3/em, 3/tm2, 3/ts, 4/act, 4/anl, 4/ap2, 4/nap, 5/tfg, 5/gl and here.
  • The structure scene is accessed in 3/tm2 and here.
+
  • The structure scene_connector is accessed in 2/ri, 3/tm, 3/em, 3/tm2, 3/ts, 4/act, 4/anl, 4/ap2, 4/nap, 5/tfg, 5/gl and here.
  • The structure scene is accessed in 3/tm2 and here.

§2.

define scenes_data scene
diff --git a/docs/if-module/3-si.html b/docs/if-module/3-si.html
index 9b4d0da38..379875d3c 100644
--- a/docs/if-module/3-si.html
+++ b/docs/if-module/3-si.html
@@ -115,7 +115,7 @@ indications of spatial structure:
 

-void SpatialInferences::infer_is_room(inference_subject *R, int certitude) {
+void SpatialInferences::infer_is_room(inference_subject *R, int certitude) {
     Inferences::join_inference(
         Inferences::create_inference(is_room_inf, NULL_GENERAL_POINTER, certitude), R);
 }
diff --git a/docs/if-module/3-sm.html b/docs/if-module/3-sm.html
index a7c759b33..d36d35529 100644
--- a/docs/if-module/3-sm.html
+++ b/docs/if-module/3-sm.html
@@ -209,7 +209,7 @@ of vehicle, and so on, but this would cause mayhem in the model world. So:
 

-int Spatial::object_is_a_room(instance *I) {
+int Spatial::object_is_a_room(instance *I) {
     if ((K_room) && (I) && (Instances::of_kind(I, K_room))) return TRUE;
     return FALSE;
 }
@@ -984,7 +984,7 @@ when it finishes this will be set to the most recently mentioned.
 
     inference *inf;
     POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), part_of_inf) {
-        if ((Spatial::object_is_a_room(I)) || (PL::Map::object_is_a_door(I))) {
+        if ((Spatial::object_is_a_room(I)) || (Map::instance_is_a_door(I))) {
             StandardProblems::object_problem(_p_(PM_RoomOrDoorAsPart),
                 I,
                 "was set up as being part of something else, which doors and rooms "
diff --git a/docs/if-module/3-sm2.html b/docs/if-module/3-sm2.html
index ac1171d9f..b7e6bb4bc 100644
--- a/docs/if-module/3-sm2.html
+++ b/docs/if-module/3-sm2.html
@@ -257,7 +257,7 @@ won't need them in this section.
 

-void PL::SpatialMap::initialise_mapping_data(map_data *md) {
+void PL::SpatialMap::initialise_mapping_data(map_data *md) {
     md->world_index_colour = NULL;
     md->world_index_text_colour = NULL;
     md->position = Zero_vector;
@@ -322,8 +322,8 @@ for any subsequent story directions to be unshown:
 int story_dir_to_page_dir[MAX_DIRECTIONS];
 
 void PL::SpatialMap::initialise_page_directions(void) {
-    int i;
-    for (i=0; i<registered_directions; i++)
+    int N = Map::number_of_directions();
+    for (int i=0; i<N; i++)
         story_dir_to_page_dir[i] = i;
 }
 
@@ -469,7 +469,7 @@ we use these hard-wired macros instead.
define LOOP_OVER_DIRECTIONS(i)
     for (i=0; i<12; i++)
 define LOOP_OVER_STORY_DIRECTIONS(i)
-    for (i=0; i<registered_directions; i++)
+    for (i=0; i<Map::number_of_directions(); i++)
 define LOOP_OVER_LATTICE_DIRECTIONS(i)
     for (i=0; i<10; i++)
 define LOOP_OVER_NONLATTICE_DIRECTIONS(i)
@@ -576,10 +576,10 @@ door, which we take a note of if asked to do so.
     if (immediate_destination) {
         if (Spatial::object_is_a_room(immediate_destination))
             ultimate_destination = immediate_destination;
-        if (PL::Map::object_is_a_door(immediate_destination)) {
+        if (Map::instance_is_a_door(immediate_destination)) {
             if (via) *via = immediate_destination;
             instance *A = NULL, *B = NULL;
-            PL::Map::get_door_data(immediate_destination, &A, &B);
+            Map::get_door_data(immediate_destination, &A, &B);
             if (A == origin) ultimate_destination = B;
             if (B == origin) ultimate_destination = A;
         }
@@ -3140,7 +3140,7 @@ can make use of the following:
     if ((Instances::of_kind(R, K_direction)) &&
         (MAP_DATA(R)->direction_index >= 12)) {
         wording W = Instances::get_name(R, FALSE);
-        wording OW = Instances::get_name(PL::Map::get_value_of_opposite_property(R), FALSE);
+        wording OW = Instances::get_name(Map::get_value_of_opposite_property(R), FALSE);
         LOG("%+W is a direction. The opposite of %+W is %+W.\n", W, W, OW);
     }
     if (Instances::of_kind(R, K_region)) {
@@ -3211,7 +3211,7 @@ can make use of the following:
                         if (MAP_DATA(dir)->direction_index == i) {
                             wording DW = Instances::get_name(dir, FALSE);
                             LOG("%+W is %W of %+W.\n", OW, DW, RW);
-                            instance *opp = PL::Map::get_value_of_opposite_property(dir);
+                            instance *opp = Map::get_value_of_opposite_property(dir);
                             int od = MAP_DATA(opp)->direction_index;
                             if ((S) && (PL::SpatialMap::room_exit(S, od, NULL) == NULL)) {
                                 wording OPW = Instances::get_name(dir, FALSE);
@@ -3239,12 +3239,12 @@ can make use of the following:
 

-void PL::SpatialMap::index_room_connections(OUTPUT_STREAM, instance *R) {
+void PL::SpatialMap::index_room_connections(OUTPUT_STREAM, instance *R) {
     wording RW = Instances::get_name(R, FALSE);  name of the origin room
     instance *dir;
     LOOP_OVER_INSTANCES(dir, K_direction) {
         int i = MAP_DATA(dir)->direction_index;
-        instance *opp = PL::Map::get_value_of_opposite_property(dir);
+        instance *opp = Map::get_value_of_opposite_property(dir);
         int od = opp?(MAP_DATA(opp)->direction_index):(-1);
         instance *D = NULL;
         instance *S = PL::SpatialMap::room_exit(R, i, &D);
diff --git a/docs/if-module/3-sr.html b/docs/if-module/3-sr.html
index 78581ad9d..f5d922d43 100644
--- a/docs/if-module/3-sr.html
+++ b/docs/if-module/3-sr.html
@@ -123,7 +123,7 @@ MathJax = {
     if (n == 1) {
         Make built-in spatial relationships2.1;
         Make built-in indirect spatial relationships2.2;
-        PL::MapDirections::create_relations();
+        PL::MapDirections::create_relations();
         Regions::create_relations();
     }
 }
@@ -310,7 +310,6 @@ way which isn't symmetrical between the two, and this way round is cleanest.
 
 
     if (Backdrops::assert_relations(bp, I0, I1)) return TRUE;
-    if (PL::MapDirections::assert_relations(bp, I0, I1)) return TRUE;
     if (Regions::assert_relations(bp, I0, I1)) return TRUE;
 
  • This code is used in §4.
diff --git a/docs/if-module/3-tm.html b/docs/if-module/3-tm.html index 108651a5d..282fa1988 100644 --- a/docs/if-module/3-tm.html +++ b/docs/if-module/3-tm.html @@ -87,9 +87,9 @@ MathJax = {

A plugin to provide a geographical model, linking rooms and doors together in oppositely-paired directions.

-
+
-

§1. The map is a complicated data structure, both because it amounts to a +

§1. Introduction. The map is a complicated data structure, both because it amounts to a ternary relation (though being implemented by many binary ones) and because of an ambiguity: a map connection from a room R can lead to another room S, to a door, or to nothing. Doors come in two sorts, one and two-sided, and @@ -97,10 +97,351 @@ checking the physical realism of all this means we need to produce many quite specific problem messages.

-

We will use quite a lot of temporary work-space to put all of this -together, but the details can be ignored. If we expected very large numbers -of objects then it would be worth economising here, but profiling suggests -that it really isn't. +

+void Map::start(void) {
+    Map::create_inference();
+    PluginManager::plug(MAKE_SPECIAL_MEANINGS_PLUG, Map::make_special_meanings);
+    PluginManager::plug(NEW_ASSERTION_NOTIFY_PLUG, Map::look_for_direction_creation);
+    PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, Map::new_base_kind_notify);
+    PluginManager::plug(NEW_SUBJECT_NOTIFY_PLUG, Map::new_subject_notify);
+    PluginManager::plug(SET_KIND_NOTIFY_PLUG, Map::set_kind_notify);
+    PluginManager::plug(SET_SUBKIND_NOTIFY_PLUG, Map::set_subkind_notify);
+    PluginManager::plug(ACT_ON_SPECIAL_NPS_PLUG, Map::act_on_special_NPs);
+    PluginManager::plug(CHECK_GOING_PLUG, Map::check_going);
+    PluginManager::plug(COMPLETE_MODEL_PLUG, Map::complete_model);
+    PluginManager::plug(NEW_PROPERTY_NOTIFY_PLUG, Map::new_property_notify);
+    PluginManager::plug(INFERENCE_DRAWN_NOTIFY_PLUG, Map::inference_drawn);
+    PluginManager::plug(INTERVENE_IN_ASSERTION_PLUG, Map::intervene_in_assertion);
+    PluginManager::plug(ADD_TO_WORLD_INDEX_PLUG, IXMap::add_to_World_index);
+    PluginManager::plug(ANNOTATE_IN_WORLD_INDEX_PLUG, IXMap::annotate_in_World_index);
+    PluginManager::plug(PRODUCTION_LINE_PLUG, Map::production_line);
+}
+
+int Map::production_line(int stage, int debugging, stopwatch_timer *sequence_timer) {
+    if (stage == INTER1_CSEQ) {
+        BENCH(RTMap::compile_model_tables);
+        BENCH(RTMap::write_door_dir_routines);
+        BENCH(RTMap::write_door_to_routines);
+    }
+    return FALSE;
+}
+
+

§2. This special sentence is used as a hint in making map documents; it has no +effect on the world model itself, and so is dealt with elsewhere, in EPS Map. +

+ +
+int Map::make_special_meanings(void) {
+    SpecialMeanings::declare(PL::EPSMap::index_map_with_SMF, I"index-map-with", 4);
+    return FALSE;
+}
+
+

§3. Though it isn't implemented as a special meaning, we do look by hand early +in Inform's run for sentences in the form "X is a direction", so that they can +be "noticed". We need to do that in order to make sense of subsequent sentences +using directions to imply relations, as in "East of Eden is the Land of Nod." +

+ +
+parse_node *directions_noticed[MAX_DIRECTIONS];
+binary_predicate *direction_relations_noticed[MAX_DIRECTIONS];
+int no_directions_noticed = 0;
+
+int Map::look_for_direction_creation(parse_node *pn) {
+    if (Node::get_type(pn) != SENTENCE_NT) return FALSE;
+    if ((pn->down == NULL) || (pn->down->next == NULL) || (pn->down->next->next == NULL))
+        return FALSE;
+    if (Node::get_type(pn->down) != VERB_NT) return FALSE;
+    if (Node::get_type(pn->down->next) != UNPARSED_NOUN_NT) return FALSE;
+    if (Node::get_type(pn->down->next->next) != UNPARSED_NOUN_NT) return FALSE;
+    current_sentence = pn;
+    pn = pn->down->next;
+    if (!((<notable-map-kinds>(Node::get_text(pn->next))) && (<<r>> == 0))) return FALSE;
+    if (no_directions_noticed >= MAX_DIRECTIONS) {
+        StandardProblems::limit_problem(Task::syntax_tree(), _p_(PM_TooManyDirections),
+            "different directions", MAX_DIRECTIONS);
+        return FALSE;
+    }
+    direction_relations_noticed[no_directions_noticed] =
+        PL::MapDirections::create_sketchy_mapping_direction(Node::get_text(pn));
+    directions_noticed[no_directions_noticed++] = pn;
+    return FALSE;
+}
+
+

§4. The direction inference. While we could probably represent map knowledge using relation inferences +in connection with the "mapped D of" relations, it's altogether easier and +makes for more legible code if we use a special inference family of our own: +

+ +
+inference_family *direction_inf = NULL;  100; where do map connections from O lead?
+
+

§5.

+ +
+void Map::create_inference(void) {
+    direction_inf = Inferences::new_family(I"direction_inf");
+    METHOD_ADD(direction_inf, LOG_DETAILS_INF_MTID, Map::log_direction_inf);
+    METHOD_ADD(direction_inf, COMPARE_INF_MTID, Map::cmp_direction_inf);
+}
+
+typedef struct direction_inference_data {
+    struct inference_subject *to;
+    struct inference_subject *dir;
+    CLASS_DEFINITION
+} direction_inference_data;
+
+inference *Map::new_direction_inference(inference_subject *infs_from,
+    inference_subject *infs_to, instance *o_dir) {
+    PROTECTED_MODEL_PROCEDURE;
+    direction_inference_data *data = CREATE(direction_inference_data);
+    data->to = infs_to;
+    data->dir = (o_dir)?(Instances::as_subject(o_dir)):NULL;
+    return Inferences::create_inference(direction_inf,
+        STORE_POINTER_direction_inference_data(data), prevailing_mood);
+}
+
+void Map::infer_direction(inference_subject *infs_from, inference_subject *infs_to,
+    instance *o_dir) {
+    inference *i = Map::new_direction_inference(infs_from, infs_to, o_dir);
+    Inferences::join_inference(i, infs_from);
+}
+
+void Map::log_direction_inf(inference_family *f, inference *inf) {
+    direction_inference_data *data = RETRIEVE_POINTER_direction_inference_data(inf->data);
+    LOG("-to:$j -dir:$j", data->to, data->dir);
+}
+
+
  • The structure direction_inference_data is private to this section.
+

§6. Inferences about different directions from a location are different topics; +but different destinations in the same direction are different in content. +

+ +
+int Map::cmp_direction_inf(inference_family *f, inference *i1, inference *i2) {
+    direction_inference_data *data1 = RETRIEVE_POINTER_direction_inference_data(i1->data);
+    direction_inference_data *data2 = RETRIEVE_POINTER_direction_inference_data(i2->data);
+
+    int c = Inferences::measure_infs(data1->dir) - Inferences::measure_infs(data2->dir);
+    if (c > 0) return CI_DIFFER_IN_TOPIC; if (c < 0) return -CI_DIFFER_IN_TOPIC;
+    c = Inferences::measure_infs(data1->to) - Inferences::measure_infs(data2->to);
+    if (c > 0) return CI_DIFFER_IN_CONTENT; if (c < 0) return -CI_DIFFER_IN_CONTENT;
+
+    c = Inferences::measure_inf(i1) - Inferences::measure_inf(i2);
+    if (c > 0) return CI_DIFFER_IN_COPY_ONLY; if (c < 0) return -CI_DIFFER_IN_COPY_ONLY;
+    return CI_IDENTICAL;
+}
+
+void Map::get_map_references(inference *i,
+    inference_subject **infs1, inference_subject **infs2) {
+    if ((i == NULL) || (i->family != direction_inf))
+        internal_error("not a direction inf");
+    direction_inference_data *data = RETRIEVE_POINTER_direction_inference_data(i->data);
+    if (infs1) *infs1 = data->to; if (infs2) *infs2 = data->dir;
+}
+
+

§7. Special kinds. It's obvious why the kinds direction and door are special. +

+ +
+kind *K_direction = NULL;
+kind *K_door = NULL;
+
+

§8. These are recognised by the English name when defined by the Standard +Rules. (So there is no need to translate this to other languages.) +

+ +
+<notable-map-kinds> ::=
+    direction |
+    door
+
+ +

§9.

+ +
+int Map::new_base_kind_notify(kind *new_base, text_stream *name, wording W) {
+    if (<notable-map-kinds>(W)) {
+        switch (<<r>>) {
+            case 0: K_direction = new_base; return TRUE;
+            case 1: K_door = new_base; return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+

§10. Direction needs to be an abstract object, not a thing or a room, so: +

+ +
+int Map::set_subkind_notify(kind *sub, kind *super) {
+    if ((sub == K_direction) && (super != K_object)) {
+        if (problem_count == 0)
+            StandardProblems::sentence_problem(Task::syntax_tree(),
+                _p_(PM_DirectionAdrift),
+                "'direction' is not allowed to be a kind of anything (other than "
+                "'object')",
+                "because it's too fundamental to the way Inform maps out the "
+                "geography of the physical world.");
+        return TRUE;
+    }
+    if (super == K_direction) {
+        if (problem_count == 0)
+            StandardProblems::sentence_problem(Task::syntax_tree(),
+                _p_(PM_DirectionSubkinded),
+                "'direction' is not allowed to have more specific kinds",
+                "because it's too fundamental to the way Inform maps out the "
+                "geography of the physical world.");
+        return TRUE;
+    }
+    if ((K_backdrop) && (sub == K_door) &&
+        (Kinds::Behaviour::is_object_of_kind(super, K_backdrop))) {
+            StandardProblems::sentence_problem(Task::syntax_tree(),
+                _p_(PM_DoorAdrift),
+                "'door' is not allowed to be a kind of 'backdrop'",
+                "because it's too fundamental to the way Inform maps out the "
+                "geography of the physical world.");
+        return TRUE;
+    }
+    if ((K_backdrop) && (sub == K_backdrop) &&
+        (Kinds::Behaviour::is_object_of_kind(super, K_door))) {
+            StandardProblems::sentence_problem(Task::syntax_tree(),
+                _p_(PM_BackdropAdrift),
+                "'backdrop' is not allowed to be a kind of 'door'",
+                "because it's too fundamental to the way Inform maps out the "
+                "geography of the physical world.");
+        return TRUE;
+    }
+    return FALSE;
+}
+
+

§11. Spotting directions and doors.

+ +
+int Map::subject_is_a_direction(inference_subject *infs) {
+    if (K_direction == NULL) return FALSE;  in particular, if plugin inactive
+    return InferenceSubjects::is_within(infs, KindSubjects::from_kind(K_direction));
+}
+
+int Map::instance_is_a_direction(instance *I) {
+    if ((PluginManager::active(map_plugin)) && (K_direction) && (I) &&
+        (Instances::of_kind(I, K_direction)))
+        return TRUE;
+    return FALSE;
+}
+
+

§12.

+ +
+int Map::subject_is_a_door(inference_subject *infs) {
+    return Map::instance_is_a_door(
+        InstanceSubjects::to_object_instance(infs));
+}
+
+int Map::instance_is_a_door(instance *I) {
+    if ((PluginManager::active(map_plugin)) && (K_door) && (I) &&
+        (Instances::of_kind(I, K_door)))
+        return TRUE;
+    return FALSE;
+}
+
+

§13. Directions and their numbers. Directions play a special role because sentences like "east of the treehouse +is the garden" are parsed differently from sentences like "the nearby place +property of the treehouse is the garden". +

+ +

For reasons to do with creating direction mapping relations, the lengths of +direction names are capped, though very, very few Inform users have ever +realised this: +

+ +
define MAX_WORDS_IN_DIRECTION (MAX_WORDS_IN_ASSEMBLAGE - 4)
+
+

§14. When a new direction comes into existence (i.e., not when the underlying +instance I is created, but when its kind is realised to be "direction"), +we will assign it a number: +

+ +
+int registered_directions = 0;  next direction number to be free
+
+int Map::number_of_directions(void) {
+    return registered_directions;
+}
+
+

§15. "Up" and "down" are not really special among possible direction instances, but +they have linguistic features not shared by lateral directions. "Above the +garden is the treehouse", for instance, does not directly refer to either +direction, but implies both. +

+ +
+instance *I_up = NULL;
+instance *I_down = NULL;
+
+

§16. These are recognised by their English names when defined by the Standard Rules. +(So there is no need to translate this to other languages.) +

+ +
+<notable-map-directions> ::=
+    up |
+    down
+
+ +

§17.

+ +
+int Map::set_kind_notify(instance *I, kind *k) {
+    kind *kw = Instances::to_kind(I);
+    if ((!(Kinds::Behaviour::is_object_of_kind(kw, K_direction))) &&
+        (Kinds::Behaviour::is_object_of_kind(k, K_direction))) {
+        wording IW = Instances::get_name(I, FALSE);
+        Vet the direction name for acceptability17.1;
+        if (<notable-map-directions>(IW)) {
+            switch (<<r>>) {
+                case 0: I_up = I; break;
+                case 1: I_down = I; break;
+            }
+        }
+        Naming::object_takes_definite_article(Instances::as_subject(I));
+        Assign the object a direction number and a mapped-D-of relation17.2;
+    }
+    return FALSE;
+}
+
+

§17.1. Vet the direction name for acceptability17.1 = +

+ +
+    if (Wordings::empty(IW)) {
+        StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_NamelessDirection),
+            "nameless directions are not allowed",
+            "so writing something like 'There is a direction.' is forbidden.");
+        return TRUE;
+    }
+    if (Wordings::length(IW) > MAX_WORDS_IN_DIRECTION) {
+        StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_DirectionTooLong),
+            "although direction names can be really quite long in today's Inform",
+            "they can't be as long as that.");
+        return TRUE;
+    }
+
+
  • This code is used in §17.
+

§17.2. Assign the object a direction number and a mapped-D-of relation17.2 = +

+ +
+    registered_directions++;
+    inter_name *dname = RTMap::new_direction_iname();
+    MAP_DATA(I)->direction_iname = dname;
+    PL::MapDirections::make_mapped_predicate(I);
+
+
  • This code is used in §17.
+

§18. Map data on instances. We will use quite a lot of temporary work-space to put all of this together, +but the details can be ignored. If we expected very large numbers of instances +then it would be worth economising here, but profiling suggests that it really +isn't.

define MAP_DATA(I) PLUGIN_DATA_ON_INSTANCE(map, I)
@@ -138,360 +479,96 @@ that it really isn't.
 } map_data;
 
  • The structure map_data is accessed in 3/mcr, 3/sm2, 3/hm, 3/em and here.
-

§2. It's obvious why the kinds direction and door are special. It's not so -obvious why "up" and "down" are: the answer is that there are linguistic -features of these which aren't shared by lateral directions. "Above the -garden is the treehouse", for instance, does not directly refer to either -direction, but implies both. -

- -
-kind *K_direction = NULL;
-kind *K_door = NULL;
-instance *I_up = NULL;
-instance *I_down = NULL;
-
-

§3. Special properties. The I6 implementation of two-way doors and of what, in -I7, are called backdrops, is quite complicated. See the Inform Designer's Manual, -fourth edition (the "DM4") for explanations. We are essentially trying to -program all of that automatically, which is why these awkward multi-purpose -I6 properties (door_to, found_in, etc.) have no direct I7 equivalents. -

- -
-property *P_door = NULL;  I6 only
-property *P_door_dir = NULL;  I6 only
-property *P_door_to = NULL;  I6 only
-property *P_other_side = NULL;  a value property for the other side of a door
-property *P_opposite = NULL;  a value property for the reverse of a direction
-property *P_room_index = NULL;  I6 only: workspace for path-finding through the map
-property *P_found_in = NULL;  I6 only: needed for multiply-present objects
-
-

§4. While we could probably represent map knowledge using relation inferences -in connection with the "mapped D of" relations, it's altogether easier and -makes for more legible code if we use a special inference type of our own: -

- -
-inference_family *DIRECTION_INF = NULL;  100; where do map connections from O lead?
-
-

§5.

- -
-typedef struct direction_inference_data {
-    struct inference_subject *to;
-    struct inference_subject *dir;
-    CLASS_DEFINITION
-} direction_inference_data;
-
-inference *PL::Map::new_direction_inference(inference_subject *infs_from,
-    inference_subject *infs_to, instance *o_dir) {
-    PROTECTED_MODEL_PROCEDURE;
-    direction_inference_data *data = CREATE(direction_inference_data);
-    data->to = infs_to;
-    data->dir = (o_dir)?(Instances::as_subject(o_dir)):NULL;
-    return Inferences::create_inference(DIRECTION_INF,
-        STORE_POINTER_direction_inference_data(data), prevailing_mood);
-}
-
-void PL::Map::infer_direction(inference_subject *infs_from, inference_subject *infs_to,
-    instance *o_dir) {
-    inference *i = PL::Map::new_direction_inference(infs_from, infs_to, o_dir);
-    Inferences::join_inference(i, infs_from);
-}
-
-void PL::Map::get_map_references(inference *i,
-    inference_subject **infs1, inference_subject **infs2) {
-    if ((i == NULL) || (i->family != DIRECTION_INF))
-        internal_error("not a direction inf");
-    direction_inference_data *data = RETRIEVE_POINTER_direction_inference_data(i->data);
-    if (infs1) *infs1 = data->to; if (infs2) *infs2 = data->dir;
-}
-
-void PL::Map::log_direction_inf(inference_family *f, inference *inf) {
-    direction_inference_data *data = RETRIEVE_POINTER_direction_inference_data(inf->data);
-    LOG("-to:$j -dir:$j", data->to, data->dir);
-}
-
-int PL::Map::cmp_direction_inf(inference_family *f, inference *i1, inference *i2) {
-    direction_inference_data *data1 = RETRIEVE_POINTER_direction_inference_data(i1->data);
-    direction_inference_data *data2 = RETRIEVE_POINTER_direction_inference_data(i2->data);
-
-    int c = Inferences::measure_infs(data1->dir) - Inferences::measure_infs(data2->dir);
-    if (c > 0) return CI_DIFFER_IN_TOPIC; if (c < 0) return -CI_DIFFER_IN_TOPIC;
-    c = Inferences::measure_infs(data1->to) - Inferences::measure_infs(data2->to);
-    if (c > 0) return CI_DIFFER_IN_CONTENT; if (c < 0) return -CI_DIFFER_IN_CONTENT;
-
-    c = Inferences::measure_inf(i1) - Inferences::measure_inf(i2);
-    if (c > 0) return CI_DIFFER_IN_COPY_ONLY; if (c < 0) return -CI_DIFFER_IN_COPY_ONLY;
-    return CI_IDENTICAL;
-}
-
-
  • The structure direction_inference_data is private to this section.
-

§6. One useful constant: -

- -
define MAX_WORDS_IN_DIRECTION (MAX_WORDS_IN_ASSEMBLAGE - 4)
-
-

§7. These little structures are needed to remember routines to compile later: -

- -
-typedef struct door_dir_notice {
-    struct inter_name *ddn_iname;
-    struct instance *door;
-    struct instance *R1;
-    struct instance *D1;
-    struct instance *D2;
-    CLASS_DEFINITION
-} door_dir_notice;
-
-typedef struct door_to_notice {
-    struct inter_name *dtn_iname;
-    struct instance *door;
-    struct instance *R1;
-    struct instance *R2;
-    CLASS_DEFINITION
-} door_to_notice;
-
-
  • The structure door_dir_notice is private to this section.
  • The structure door_to_notice is private to this section.
-

§8. Initialisation.

- -
-void PL::Map::start(void) {
-    DIRECTION_INF = Inferences::new_family(I"DIRECTION_INF");
-    METHOD_ADD(DIRECTION_INF, LOG_DETAILS_INF_MTID, PL::Map::log_direction_inf);
-    METHOD_ADD(DIRECTION_INF, COMPARE_INF_MTID, PL::Map::cmp_direction_inf);
-
-    PluginManager::plug(MAKE_SPECIAL_MEANINGS_PLUG, PL::Map::make_special_meanings);
-    PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, PL::Map::map_new_base_kind_notify);
-    PluginManager::plug(NEW_SUBJECT_NOTIFY_PLUG, PL::Map::map_new_subject_notify);
-    PluginManager::plug(SET_KIND_NOTIFY_PLUG, PL::Map::map_set_kind_notify);
-    PluginManager::plug(SET_SUBKIND_NOTIFY_PLUG, PL::Map::map_set_subkind_notify);
-    PluginManager::plug(ACT_ON_SPECIAL_NPS_PLUG, PL::Map::map_act_on_special_NPs);
-    PluginManager::plug(CHECK_GOING_PLUG, PL::Map::map_check_going);
-    PluginManager::plug(COMPLETE_MODEL_PLUG, PL::Map::map_complete_model);
-    PluginManager::plug(NEW_PROPERTY_NOTIFY_PLUG, PL::Map::map_new_property_notify);
-    PluginManager::plug(INFERENCE_DRAWN_NOTIFY_PLUG, PL::Map::map_inference_drawn);
-    PluginManager::plug(INTERVENE_IN_ASSERTION_PLUG, PL::Map::map_intervene_in_assertion);
-    PluginManager::plug(ADD_TO_WORLD_INDEX_PLUG, PL::Map::map_add_to_World_index);
-    PluginManager::plug(ANNOTATE_IN_WORLD_INDEX_PLUG, PL::Map::map_annotate_in_World_index);
-    PluginManager::plug(PRODUCTION_LINE_PLUG, PL::Map::production_line);
-}
-
-int PL::Map::production_line(int stage, int debugging, stopwatch_timer *sequence_timer) {
-    if (stage == INTER1_CSEQ) {
-        BENCH(PL::Map::map_compile_model_tables);
-        BENCH(PL::Map::write_door_dir_routines);
-        BENCH(PL::Map::write_door_to_routines);
-    }
-    return FALSE;
-}
-
-int PL::Map::make_special_meanings(void) {
-    SpecialMeanings::declare(PL::EPSMap::index_map_with_SMF, I"index-map-with", 4);
-    return FALSE;
-}
-
-

§9.

- -
-map_data *PL::Map::new_data(inference_subject *subj) {
-    map_data *md = CREATE(map_data);
-    md->direction_index = -1;
-    md->direction_relation = NULL;
-
-    int i;
-    for (i=0; i<MAX_DIRECTIONS; i++) {
-        md->exits_set_at[i] = NULL;
-        md->exits[i] = NULL;
-    }
-    md->map_connection_a = NULL; md->map_connection_b = NULL;
-    md->map_direction_a = NULL; md->map_direction_b = NULL;
-
-    PL::SpatialMap::initialise_mapping_data(md);
-    return md;
-}
-
-

§10. Kinds. These are kind names to do with mapping which Inform provides special -support for; it recognises the English name when defined by the Standard -Rules. (So there is no need to translate this to other languages.) -

- -
-<notable-map-kinds> ::=
-    direction |
-    door
-
- -

§11.

- -
-int PL::Map::map_new_base_kind_notify(kind *new_base, text_stream *name, wording W) {
-    if (<notable-map-kinds>(W)) {
-        switch (<<r>>) {
-            case 0: K_direction = new_base; return TRUE;
-            case 1: K_door = new_base; return TRUE;
-        }
-    }
-    return FALSE;
-}
-
-

§12. Direction needs to be an abstract object, not a thing or a room, so: -

- -
-int PL::Map::map_set_subkind_notify(kind *sub, kind *super) {
-    if ((sub == K_direction) && (super != K_object)) {
-        if (problem_count == 0)
-            StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_DirectionAdrift),
-                "'direction' is not allowed to be a kind of anything (other than "
-                "'object')",
-                "because it's too fundamental to the way Inform maps out the "
-                "geography of the physical world.");
-        return TRUE;
-    }
-    if (super == K_direction) {
-        if (problem_count == 0)
-            StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_DirectionSubkinded),
-                "'direction' is not allowed to have more specific kinds",
-                "because it's too fundamental to the way Inform maps out the "
-                "geography of the physical world.");
-        return TRUE;
-    }
-    if ((K_backdrop) && (sub == K_door) && (Kinds::Behaviour::is_object_of_kind(super, K_backdrop))) {
-            StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_DoorAdrift),
-                "'door' is not allowed to be a kind of 'backdrop'",
-                "because it's too fundamental to the way Inform maps out the "
-                "geography of the physical world.");
-        return TRUE;
-    }
-    if ((K_backdrop) && (sub == K_backdrop) && (Kinds::Behaviour::is_object_of_kind(super, K_door))) {
-            StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_BackdropAdrift),
-                "'backdrop' is not allowed to be a kind of 'door'",
-                "because it's too fundamental to the way Inform maps out the "
-                "geography of the physical world.");
-        return TRUE;
-    }
-    return FALSE;
-}
-
-

§13.

- -
-int PL::Map::map_new_subject_notify(inference_subject *subj) {
-    ATTACH_PLUGIN_DATA_TO_SUBJECT(map, subj, PL::Map::new_data(subj));
-    return FALSE;
-}
-
-

§14.

- -
-int PL::Map::object_is_a_direction(instance *I) {
-    if ((PluginManager::active(map_plugin)) && (K_direction) && (I) &&
-        (Instances::of_kind(I, K_direction)))
-        return TRUE;
-    return FALSE;
-}
-
-

§15.

- -
-int PL::Map::object_is_a_door(instance *I) {
-    if ((PluginManager::active(map_plugin)) && (K_door) && (I) &&
-        (Instances::of_kind(I, K_door)))
-        return TRUE;
-    return FALSE;
-}
-
-int PL::Map::subject_is_a_door(inference_subject *infs) {
-    return PL::Map::object_is_a_door(
-        InstanceSubjects::to_object_instance(infs));
-}
-
-

§16. Directions and their numbers. Directions play a special role because sentences like "east of the treehouse -is the garden" are parsed differently from sentences like "the nearby place -property of the treehouse is the garden"; they're also one domain of what -amounts to the ternary map relation, though we actually implement it as a -sheaf of binary relations, one for each direction. Anyway: -

- -
-int PL::Map::is_a_direction(inference_subject *infs) {
-    if (K_direction == NULL) return FALSE;  in particular, if we aren't using the IF model
-    return InferenceSubjects::is_within(infs, KindSubjects::from_kind(K_direction));
-}
-
-

§17. When a new direction comes into existence (i.e., not when the underlying -object I is created, but when its kind is first realised to be "direction"), -we need to assign it a number: -

- -
-int registered_directions = 0;  next direction number to be free
-
-

§18. These are direction names which Inform provides special support for; it -recognises the English names when defined by the Standard Rules. (So there is -no need to translate this to other languages.) -

- -
-<notable-map-directions> ::=
-    up |
-    down
-
-

§19.

-int PL::Map::map_set_kind_notify(instance *I, kind *k) {
-    kind *kw = Instances::to_kind(I);
-    if ((!(Kinds::Behaviour::is_object_of_kind(kw, K_direction))) &&
-        (Kinds::Behaviour::is_object_of_kind(k, K_direction))) {
-        wording IW = Instances::get_name(I, FALSE);
-        Vet the direction name for acceptability19.1;
-        if (<notable-map-directions>(IW)) {
-            switch (<<r>>) {
-                case 0: I_up = I; break;
-                case 1: I_down = I; break;
-            }
+int Map::new_subject_notify(inference_subject *subj) {
+    map_data *md = CREATE(map_data);
+    md->map_connection_a = NULL; md->map_connection_b = NULL;
+    md->map_direction_a = NULL; md->map_direction_b = NULL;
+
+    md->direction_index = -1;
+    md->direction_relation = NULL;
+    md->direction_iname = NULL;
+
+    for (int i=0; i<MAX_DIRECTIONS; i++) {
+        md->exits_set_at[i] = NULL;
+        md->exits[i] = NULL;
+    }
+
+    PL::SpatialMap::initialise_mapping_data(md);
+    ATTACH_PLUGIN_DATA_TO_SUBJECT(map, subj, md);
+    return FALSE;
+}
+
+

§20. Special properties. +These are property names to do with mapping which Inform provides special +support for. Two are visible to I7 authors, and the others are low-level +properties needed for the run-time implementation. +

+ +
+property *P_other_side = NULL;  a value property for the other side of a door
+property *P_opposite = NULL;  a value property for the reverse of a direction
+
+property *P_door = NULL;  Inter only
+property *P_door_dir = NULL;  Inter only
+property *P_door_to = NULL;  Inter only
+property *P_room_index = NULL;  Inter only: workspace for path-finding through the map
+property *P_found_in = NULL;  Inter only: needed for multiply-present objects
+
+

§21. We recognise these by their English names when they are defined by the +Standard Rules. (So there is no need to translate this to other languages.) +

+ +
+<notable-map-properties> ::=
+    opposite |
+    other side
+
+ +

§22.

+ +
+int Map::new_property_notify(property *prn) {
+    if (<notable-map-properties>(prn->name)) {
+        switch (<<r>>) {
+            case 0: P_opposite = prn; break;
+            case 1: P_other_side = prn; break;
         }
-        Naming::object_takes_definite_article(Instances::as_subject(I));
-        Assign the object a direction number and a mapped-D-of relation19.2;
     }
     return FALSE;
 }
 
-

§19.1. Vet the direction name for acceptability19.1 = +

§23. The following is used also by Backdrops, since both plugins use a +shared Inter-level property at run-time. But this function will work even if +the map plugin is inactive; so you can still have backdrops without a map.

-    if (Wordings::empty(IW)) {
-        StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_NamelessDirection),
-            "nameless directions are not allowed",
-            "so writing something like 'There is a direction.' is forbidden.");
-        return TRUE;
-    }
-    if (Wordings::length(IW) > MAX_WORDS_IN_DIRECTION) {
-        StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_DirectionTooLong),
-            "although direction names can be really quite long in today's Inform",
-            "they can't be as long as that.");
-        return TRUE;
-    }
+void Map::set_found_in(instance *I, parse_node *val) {
+    if (P_found_in == NULL)
+        P_found_in = ValueProperties::new_nameless(I"found_in",
+            K_value);
+    if (PropertyInferences::value_of(
+        Instances::as_subject(I), P_found_in))
+            internal_error("rival found_in interpretations");
+    ValueProperties::assert(P_found_in, Instances::as_subject(I), val, CERTAIN_CE);
+}
 
-
  • This code is used in §19.
-

§19.2. Assign the object a direction number and a mapped-D-of relation19.2 = +

§24. This utility returns the "opposite" property for a direction, which is +always another direction: for example, the opposite of northwest is southeast.

-    registered_directions++;
-    package_request *PR = Hierarchy::synoptic_package(DIRECTIONS_HAP);
-    inter_name *dname = Hierarchy::make_iname_in(DIRECTION_HL, PR);
-    MAP_DATA(I)->direction_iname = dname;
-    PL::MapDirections::make_mapped_predicate(I, dname);
+instance *Map::get_value_of_opposite_property(instance *I) {
+    parse_node *val = PropertyInferences::value_of(
+        Instances::as_subject(I), P_opposite);
+    if (val) return Rvalues::to_object_instance(val);
+    return NULL;
+}
 
-
  • This code is used in §19.
-

§20. The exits array. The bulk of the map is stored in the arrays called exits, which hold the +

§25. The exits array. The bulk of the map is stored in the arrays called exits, which hold the map connections fanning out from each room. The direction numbers carefully noted above are keys into these arrays.

@@ -499,14 +576,14 @@ noted above are keys into these arrays.

It might look a little wasteful of I7's memory to expand the direction inferences, a nicely compact representation, into large and sparse arrays. But it's convenient, and profiling suggests that the memory overhead is not -significant. It also means that the World Index mapping code, which contains +significant. It also means that the Spatial Map mapping code, which contains quite crunchy algorithms, has the fastest possible access to the layout.

define MAP_EXIT(X, Y) MAP_DATA(X)->exits[Y]
 
-void PL::Map::build_exits_array(void) {
+void Map::build_exits_array(void) {
     instance *I;
     int d = 0;
     LOOP_OVER_INSTANCES(I, K_object) {
@@ -516,9 +593,9 @@ quite crunchy algorithms, has the fastest possible access to the layout.
     }
     LOOP_OVER_INSTANCES(I, K_object) {
         inference *inf;
-        POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), DIRECTION_INF) {
+        POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), direction_inf) {
             inference_subject *infs1, *infs2;
-            PL::Map::get_map_references(inf, &infs1, &infs2);
+            Map::get_map_references(inf, &infs1, &infs2);
             instance *to = NULL, *dir = NULL;
             if (infs1) to = InstanceSubjects::to_object_instance(infs1);
             if (infs2) dir = InstanceSubjects::to_object_instance(infs2);
@@ -533,80 +610,7 @@ quite crunchy algorithms, has the fastest possible access to the layout.
     }
 }
 
-

§21. This is easy to translate into I6 (though that's partly because I7 doesn't -follow the traditional I6 library way to represent the map): -

- -
-int PL::Map::map_compile_model_tables(void) {
-    Declare I6 constants for the directions21.1;
-    Compile the I6 Map-Storage array21.2;
-    return FALSE;
-}
-
-

§21.1. Declare I6 constants for the directions21.1 = -

- -
-    inter_name *ndi = Hierarchy::find(NO_DIRECTIONS_HL);
-    Emit::named_numeric_constant(ndi, (inter_ti) registered_directions);
-    Hierarchy::make_available(Emit::tree(), ndi);
-
-    instance *I;
-    LOOP_OVER_INSTANCES(I, K_direction) {
-        Emit::named_iname_constant(MAP_DATA(I)->direction_iname, K_object, RTInstances::emitted_iname(I));
-    }
-
-
  • This code is used in §21.
-

§21.2. The Map_Storage array consists only of the exits arrays written out -one after another. It looks wasteful of memory, since it is almost always -going to be filled mostly with 0 entries (meaning: no exit that way). But -the memory needs to be there because map connections can be added dynamically -at run-time, so we can't know now how many we will need. -

- -

Compile the I6 Map-Storage array21.2 = -

- -
-    instance *I;
-    LOOP_OVER_INSTANCES(I, K_object)
-        RTInstances::emitted_iname(I);
-    inter_name *iname = Hierarchy::find(MAP_STORAGE_HL);
-    packaging_state save = Emit::named_array_begin(iname, K_object);
-    int words_used = 0;
-    if (Task::wraps_existing_storyfile()) {
-        Emit::array_divider(I"minimal, as there are no rooms");
-        Emit::array_iname_entry(NULL);
-        Emit::array_iname_entry(NULL);
-        Emit::array_iname_entry(NULL);
-        Emit::array_iname_entry(NULL);
-        words_used = 4;
-    } else {
-        Emit::array_divider(I"one row per room");
-        instance *I;
-        LOOP_OVER_INSTANCES(I, K_object)
-            if (Spatial::object_is_a_room(I)) {
-                int i;
-                for (i=0; i<registered_directions; i++) {
-                    instance *to = MAP_EXIT(I, i);
-                    if (to)
-                        Emit::array_iname_entry(RTInstances::iname(to));
-                    else
-                        Emit::array_numeric_entry(0);
-                }
-                words_used++;
-                TEMPORARY_TEXT(divider)
-                WRITE_TO(divider, "Exits from: %~I", I);
-                Emit::array_divider(divider);
-                DISCARD_TEXT(divider)
-            }
-    }
-    Emit::array_end(save);
-    Hierarchy::make_available(Emit::tree(), iname);
-
-
  • This code is used in §21.
-

§22. Door connectivity. We've seen how most of the map is represented, in the exits arrays. The +

§26. Door connectivity. We've seen how most of the map is represented, in the exits arrays. The missing information has to do with doors. If east of the Carousel Room is the oak door, then Map_Storage reveals only that fact, and not what's on the other side of the door. This will eventually be compiled into the @@ -615,36 +619,12 @@ object has four pieces of data attached:

-void PL::Map::get_door_data(instance *door, instance **c1, instance **c2) {
+void Map::get_door_data(instance *door, instance **c1, instance **c2) {
     if (c1) *c1 = MAP_DATA(door)->map_connection_a;
     if (c2) *c2 = MAP_DATA(door)->map_connection_b;
 }
 
-

§23. Properties. These are property names to do with mapping which Inform provides special -support for; it recognises the English names when they are defined by the -Standard Rules. (So there is no need to translate this to other languages.) -

- -
-<notable-map-properties> ::=
-    opposite |
-    other side
-
- -

§24.

- -
-int PL::Map::map_new_property_notify(property *prn) {
-    if (<notable-map-properties>(prn->name)) {
-        switch (<<r>>) {
-            case 0: P_opposite = prn; break;
-            case 1: P_other_side = prn; break;
-        }
-    }
-    return FALSE;
-}
-
-

§25. We would like to deduce from a sentence like +

§27. We would like to deduce from a sentence like

@@ -652,12 +632,12 @@ Standard Rules. (So there is no need to translate this to other languages.)

that the "Black Holding Area" is a room; otherwise, if it has no map -connections, Inform may well think it's just an object. This is where that +connections, Inform may well think it's just a thing. This is where that deduction is made:

-int PL::Map::map_inference_drawn(inference *I, inference_subject *subj) {
+int Map::inference_drawn(inference *I, inference_subject *subj) {
     property *prn = PropertyInferences::get_property(I);
     if ((prn) && (prn == P_other_side)) {
         parse_node *val = PropertyInferences::get_value(I);
@@ -667,38 +647,6 @@ deduction is made:
     return FALSE;
 }
 
-

§26. The I6 found_in property is a general mechanism for multiply-present -objects. This causes great complications, and I7 simplifies the model world -by hiding it from the author, and using it internally to implement backdrops -and two-sided doors. Two different plugins therefore need access to it (this -one and Backdrops), and this is where they set it. -

- -
-void PL::Map::set_found_in(instance *I, parse_node *val) {
-    if (P_found_in == NULL)
-        P_found_in = ValueProperties::new_nameless(I"found_in",
-            K_value);
-    if (PropertyInferences::value_of(
-        Instances::as_subject(I), P_found_in))
-            internal_error("rival found_in interpretations");
-    ValueProperties::assert(P_found_in, Instances::as_subject(I), val, CERTAIN_CE);
-}
-
-

§27. This utility routine which looks for the "opposite" -property in the linked list of inferences belonging to an object. -(This is a property of directions.) Crude, but not time-sensitive, -and there seems little point in writing this any better. -

- -
-instance *PL::Map::get_value_of_opposite_property(instance *I) {
-    parse_node *val = PropertyInferences::value_of(
-        Instances::as_subject(I), P_opposite);
-    if (val) return Rvalues::to_object_instance(val);
-    return NULL;
-}
-

§28. Linguistic extras. These NPs allow us to refer to the special directions "up" and "down":

@@ -711,7 +659,7 @@ and there seems little point in writing this any better.

§29.

-int PL::Map::map_act_on_special_NPs(parse_node *p) {
+int Map::act_on_special_NPs(parse_node *p) {
     if (<notable-map-noun-phrases>(Node::get_text(p))) {
         switch (<<r>>) {
             case 0:
@@ -735,7 +683,7 @@ and there seems little point in writing this any better.
 

-int PL::Map::map_check_going(parse_node *from, parse_node *to,
+int Map::check_going(parse_node *from, parse_node *to,
     parse_node *by, parse_node *through, parse_node *pushing) {
     if (PL::Actions::Patterns::check_going(from, "from",
         K_room, K_region) == FALSE) return FALSE;
@@ -777,18 +725,19 @@ because, of course, that does set its kind.
 

-int PL::Map::map_intervene_in_assertion(parse_node *px, parse_node *py) {
+int Map::intervene_in_assertion(parse_node *px, parse_node *py) {
     if ((Node::get_type(px) == PROPER_NOUN_NT) &&
         (Node::get_type(py) == COMMON_NOUN_NT)) {
         inference_subject *left_object = Node::get_subject(px);
         inference_subject *right_kind = Node::get_subject(py);
-        if ((PL::Map::is_a_direction(left_object)) &&
-            (PL::Map::is_a_direction(right_kind) == FALSE)) {
+        if ((Map::subject_is_a_direction(left_object)) &&
+            (Map::subject_is_a_direction(right_kind) == FALSE)) {
             Assertions::Creator::convert_instance_to_nounphrase(py, NULL);
             return FALSE;
         }
         if (Annotations::read_int(px, nowhere_ANNOT)) {
-            Problems::Using::assertion_problem(Task::syntax_tree(), _p_(PM_NowhereDescribed),
+            Problems::Using::assertion_problem(Task::syntax_tree(),
+                _p_(PM_NowhereDescribed),
                 "'nowhere' cannot be made specific",
                 "and so cannot have specific properties or be of any given kind.");
             return TRUE;
@@ -809,8 +758,8 @@ make this guess; so we begin with switching in and out.
 
 
 int oneway_map_connections_only = FALSE;
-void PL::Map::enter_one_way_mode(void) { oneway_map_connections_only = TRUE; }
-void PL::Map::exit_one_way_mode(void) { oneway_map_connections_only = FALSE; }
+void Map::enter_one_way_mode(void) { oneway_map_connections_only = TRUE; }
+void Map::exit_one_way_mode(void) { oneway_map_connections_only = FALSE; }
 

§33. Note that, in order to make the conjectural reverse map direction, we need to look up the "opposite" property of the forward one. This relies on all @@ -820,14 +769,14 @@ pairs.

-void PL::Map::connect(inference_subject *i_from, inference_subject *i_to,
+void Map::connect(inference_subject *i_from, inference_subject *i_to,
     inference_subject *i_dir) {
     instance *go_from = InstanceSubjects::to_object_instance(i_from);
     instance *go_to = InstanceSubjects::to_object_instance(i_to);
     instance *forwards_dir = InstanceSubjects::to_object_instance(i_dir);
     if (Instances::of_kind(forwards_dir, K_direction) == FALSE)
         internal_error("unknown direction");
-    instance *reverse_dir = PL::Map::get_value_of_opposite_property(forwards_dir);
+    instance *reverse_dir = Map::get_value_of_opposite_property(forwards_dir);
     if (go_from == NULL) {
         Problems::quote_source(1, current_sentence);
         Problems::quote_object(2, forwards_dir);
@@ -840,12 +789,13 @@ pairs.
         return;
     }
 
-    PL::Map::oneway_map_connection(go_from, go_to, forwards_dir, CERTAIN_CE);
+    Map::oneway_map_connection(go_from, go_to, forwards_dir, CERTAIN_CE);
     if ((reverse_dir) && (go_to) && (oneway_map_connections_only == FALSE)) {
         if (Instances::of_kind(reverse_dir, K_direction) == FALSE) {
             Problems::quote_object(1, forwards_dir);
             Problems::quote_object(2, reverse_dir);
-            StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_OppositeNotDirection));
+            StandardProblems::handmade_problem(Task::syntax_tree(),
+                _p_(PM_OppositeNotDirection));
             Problems::issue_problem_segment(
                 "I'm trying to make a map connection in the %1 direction, "
                 "which means there ought to be map connection back in the "
@@ -853,13 +803,13 @@ pairs.
                 "which doesn't make sense since %2 isn't a direction. (Maybe "
                 "you forgot to say that it was?)");
             Problems::issue_problem_end();
-        } else PL::Map::oneway_map_connection(go_to, go_from, reverse_dir, LIKELY_CE);
+        } else Map::oneway_map_connection(go_to, go_from, reverse_dir, LIKELY_CE);
     }
 }
 
-void PL::Map::oneway_map_connection(instance *go_from, instance *go_to,
+void Map::oneway_map_connection(instance *go_from, instance *go_to,
     instance *forwards_dir, int certainty_level) {
-    binary_predicate *bp = PL::MapDirections::get_mapping_relation(forwards_dir);
+    binary_predicate *bp = PL::MapDirections::get_mapping_relation(forwards_dir);
     if (bp == NULL) internal_error("map connection in non-direction");
     int x = prevailing_mood;
     prevailing_mood = certainty_level;
@@ -874,7 +824,7 @@ the map as might be thought.
 

-int PL::Map::map_complete_model(int stage) {
+int Map::complete_model(int stage) {
     switch (stage) {
         case 2:
             Give each room a room-index property as workspace for route finding34.1;
@@ -891,7 +841,7 @@ the map as might be thought.
             Place any one-sided door inside the room which connects to it34.7;
             Assert found-in, door-to and door-dir properties for doors34.8;
             break;
-        case 4: PL::Map::build_exits_array(); break;
+        case 4: Map::build_exits_array(); break;
     }
     return FALSE;
 }
@@ -928,12 +878,12 @@ checks that various mapping impossibilities do not occur.
     instance *I;
     LOOP_OVER_INSTANCES(I, K_object) {
         inference *inf;
-        POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), DIRECTION_INF) {
+        POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), direction_inf) {
             inference_subject *infs1;
-            PL::Map::get_map_references(inf, &infs1, NULL);
+            Map::get_map_references(inf, &infs1, NULL);
             instance *to = InstanceSubjects::to_object_instance(infs1);
             if ((Spatial::object_is_a_room(I)) && (to) &&
-                (PL::Map::object_is_a_door(to) == FALSE) &&
+                (Map::instance_is_a_door(to) == FALSE) &&
                 (Spatial::object_is_a_room(to) == FALSE))
                 StandardProblems::contradiction_problem(_p_(PM_BadMapCell),
                     Instances::get_creating_sentence(to),
@@ -941,7 +891,7 @@ checks that various mapping impossibilities do not occur.
                     "appears to be something which can be reached via a map "
                     "connection, but it seems to be neither a room nor a door",
                     "and these are the only possibilities allowed by Inform.");
-            if ((PL::Map::object_is_a_door(I)) &&
+            if ((Map::instance_is_a_door(I)) &&
                 (Spatial::object_is_a_room(to) == FALSE))
                 StandardProblems::object_problem(_p_(PM_DoorToNonRoom),
                     I,
@@ -958,15 +908,15 @@ checks that various mapping impossibilities do not occur.
 
     instance *I;
     LOOP_OVER_INSTANCES(I, K_object)
-        if (PL::Map::object_is_a_door(I)) {
+        if (Map::instance_is_a_door(I)) {
             int connections_in = 0;
             inference *inf;
             parse_node *where[3];
             where[0] = NULL; where[1] = NULL; where[2] = NULL;  to placate gcc
             inference *front_side_inf = NULL, *back_side_inf = NULL;
-            POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), DIRECTION_INF) {
+            POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), direction_inf) {
                 inference_subject *infs1, *infs2;
-                PL::Map::get_map_references(inf, &infs1, &infs2);
+                Map::get_map_references(inf, &infs1, &infs2);
                 instance *to = InstanceSubjects::to_object_instance(infs1);
                 instance *dir = InstanceSubjects::to_object_instance(infs2);
                 if (to) {
@@ -1049,18 +999,19 @@ from which there's no way back.)
     LOOP_OVER_INSTANCES(I, K_object)
         if (Spatial::object_is_a_room(I)) {
             inference *inf;
-            POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), DIRECTION_INF) {
+            POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), direction_inf) {
                 inference_subject *infs1;
-                PL::Map::get_map_references(inf, &infs1, NULL);
+                Map::get_map_references(inf, &infs1, NULL);
                 instance *to = InstanceSubjects::to_object_instance(infs1);
-                if (PL::Map::object_is_a_door(to)) {
+                if (Map::instance_is_a_door(to)) {
                     instance *exit1 = MAP_DATA(to)->map_connection_a;
                     instance *exit2 = MAP_DATA(to)->map_connection_b;
                     if ((I != exit1) && (exit2 == NULL)) {
                         Problems::quote_object(1, I);
                         Problems::quote_object(2, to);
                         Problems::quote_object(3, exit1);
-                        StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_RoomTwistyDoor));
+                        StandardProblems::handmade_problem(Task::syntax_tree(),
+                            _p_(PM_RoomTwistyDoor));
                         Problems::issue_problem_segment(
                             "%1, a room, seems to have a map connection which goes "
                             "through %2, a door: but that doesn't seem physically "
@@ -1072,7 +1023,8 @@ from which there's no way back.)
                         Problems::quote_object(2, to);
                         Problems::quote_object(3, exit1);
                         Problems::quote_object(4, exit2);
-                        StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_RoomMissingDoor));
+                        StandardProblems::handmade_problem(Task::syntax_tree(),
+                            _p_(PM_RoomMissingDoor));
                         Problems::issue_problem_segment(
                             "%1, a room, seems to have a map connection which goes "
                             "through %2, a door: but that doesn't seem physically "
@@ -1091,7 +1043,7 @@ from which there's no way back.)
 
     instance *I;
     LOOP_OVER_INSTANCES(I, K_object)
-        if ((PL::Map::object_is_a_door(I)) &&
+        if ((Map::instance_is_a_door(I)) &&
             (MAP_DATA(I)->map_connection_a) &&
             (MAP_DATA(I)->map_connection_b) &&
             (PropertyInferences::value_of(
@@ -1119,7 +1071,7 @@ model at run-time.) This is where we apply the kill-joy rule in question:
 
     instance *I;
     LOOP_OVER_INSTANCES(I, K_object)
-        if ((PL::Map::object_is_a_door(I)) &&
+        if ((Map::instance_is_a_door(I)) &&
             (Spatial::progenitor(I)) &&
             (Spatial::progenitor(I) != MAP_DATA(I)->map_connection_a) &&
             (Spatial::progenitor(I) != MAP_DATA(I)->map_connection_b))
@@ -1140,7 +1092,7 @@ to them.
 
     instance *I;
     LOOP_OVER_INSTANCES(I, K_object)
-        if ((PL::Map::object_is_a_door(I)) &&
+        if ((Map::instance_is_a_door(I)) &&
             (MAP_DATA(I)->map_connection_b == NULL) &&
             (Spatial::progenitor(I) == NULL))
             Spatial::set_progenitor(I, MAP_DATA(I)->map_connection_a, NULL);
@@ -1163,7 +1115,7 @@ trust that there is nothing surprising here.
 
     instance *I;
     LOOP_OVER_INSTANCES(I, K_object)
-        if (PL::Map::object_is_a_door(I)) {
+        if (Map::instance_is_a_door(I)) {
             EitherOrProperties::assert(
                 P_door, Instances::as_subject(I), TRUE, CERTAIN_CE);
             instance *R1 = MAP_DATA(I)->map_connection_a;
@@ -1187,14 +1139,8 @@ trust that there is nothing surprising here.
 

-    package_request *PR = Hierarchy::package_within(INLINE_PROPERTIES_HAP, RTInstances::package(I));
-    inter_name *S = Hierarchy::make_iname_in(INLINE_PROPERTY_HL, PR);
-    packaging_state save = Emit::named_array_begin(S, K_value);
-    Emit::array_iname_entry(RTInstances::iname(R1));
-    Emit::array_iname_entry(RTInstances::iname(R2));
-    Emit::array_end(save);
-    Produce::annotate_i(S, INLINE_ARRAY_IANN, 1);
-    PL::Map::set_found_in(I, Rvalues::from_iname(S));
+    parse_node *val = RTMap::found_in_for_2_sided(I, R1, R2);
+    Map::set_found_in(I, val);
 

§34.8.2. Here door_dir is a routine looking at the current location and returning @@ -1205,14 +1151,8 @@ always the way to the other room — the one we are not in.

-    door_dir_notice *notice = CREATE(door_dir_notice);
-    notice->ddn_iname = Hierarchy::make_iname_in(TSD_DOOR_DIR_FN_HL, RTInstances::package(I));
-    notice->door = I;
-    notice->R1 = R1;
-    notice->D1 = D1;
-    notice->D2 = D2;
-    ValueProperties::assert(P_door_dir, Instances::as_subject(I),
-        Rvalues::from_iname(notice->ddn_iname), CERTAIN_CE);
+    parse_node *val = RTMap::door_dir_for_2_sided(I, R1, D1, D2);
+    ValueProperties::assert(P_door_dir, Instances::as_subject(I), val, CERTAIN_CE);
 

§34.8.3. Here door_to is a routine looking at the current location and returning @@ -1223,13 +1163,8 @@ always the other room — the one we are not in.

-    door_to_notice *notice = CREATE(door_to_notice);
-    notice->dtn_iname = Hierarchy::make_iname_in(TSD_DOOR_TO_FN_HL, RTInstances::package(I));
-    notice->door = I;
-    notice->R1 = R1;
-    notice->R2 = R2;
-    ValueProperties::assert(P_door_to, Instances::as_subject(I),
-        Rvalues::from_iname(notice->dtn_iname), CERTAIN_CE);
+    parse_node *val = RTMap::door_to_for_2_sided(I, R1, R2);
+    ValueProperties::assert(P_door_to, Instances::as_subject(I), val, CERTAIN_CE);
 

§34.8.4. The reversal of direction here looks peculiar, but is correct. Suppose @@ -1249,156 +1184,12 @@ why we don't need to compile

-    instance *backwards = PL::Map::get_value_of_opposite_property(D1);
+    instance *backwards = Map::get_value_of_opposite_property(D1);
     if (backwards)
         ValueProperties::assert(P_door_dir, Instances::as_subject(I),
             Rvalues::from_iname(RTInstances::emitted_iname(backwards)), CERTAIN_CE);
 
-

§35. Redeeming those notices.

- -
-void PL::Map::write_door_dir_routines(void) {
-    door_dir_notice *notice;
-    LOOP_OVER(notice, door_dir_notice) {
-        packaging_state save = Routines::begin(notice->ddn_iname);
-        local_variable *loc = LocalVariables::add_internal_local_c(I"loc", "room of actor");
-        inter_symbol *loc_s = LocalVariables::declare_this(loc, FALSE, 8);
-        Produce::inv_primitive(Emit::tree(), STORE_BIP);
-        Produce::down(Emit::tree());
-            Produce::ref_symbol(Emit::tree(), K_value, loc_s);
-            Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(LOCATION_HL));
-        Produce::up(Emit::tree());
-
-        Produce::inv_primitive(Emit::tree(), IF_BIP);
-        Produce::down(Emit::tree());
-            Produce::inv_primitive(Emit::tree(), EQ_BIP);
-            Produce::down(Emit::tree());
-                Produce::val_symbol(Emit::tree(), K_value, loc_s);
-                Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(THEDARK_HL));
-            Produce::up(Emit::tree());
-            Produce::code(Emit::tree());
-            Produce::down(Emit::tree());
-                Produce::inv_primitive(Emit::tree(), STORE_BIP);
-                Produce::down(Emit::tree());
-                    Produce::ref_symbol(Emit::tree(), K_value, loc_s);
-                    Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(REAL_LOCATION_HL));
-                Produce::up(Emit::tree());
-            Produce::up(Emit::tree());
-        Produce::up(Emit::tree());
-
-        Produce::inv_primitive(Emit::tree(), IF_BIP);
-        Produce::down(Emit::tree());
-            Produce::inv_primitive(Emit::tree(), EQ_BIP);
-            Produce::down(Emit::tree());
-                Produce::val_symbol(Emit::tree(), K_value, loc_s);
-                Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R1));
-            Produce::up(Emit::tree());
-            Produce::code(Emit::tree());
-            Produce::down(Emit::tree());
-                Produce::inv_primitive(Emit::tree(), RETURN_BIP);
-                Produce::down(Emit::tree());
-                    Produce::val_iname(Emit::tree(), K_value,
-                        RTInstances::iname(PL::Map::get_value_of_opposite_property(notice->D1)));
-                Produce::up(Emit::tree());
-            Produce::up(Emit::tree());
-        Produce::up(Emit::tree());
-
-        Produce::inv_primitive(Emit::tree(), RETURN_BIP);
-        Produce::down(Emit::tree());
-            Produce::val_iname(Emit::tree(), K_value,
-                RTInstances::iname(PL::Map::get_value_of_opposite_property(notice->D2)));
-        Produce::up(Emit::tree());
-
-        Routines::end(save);
-    }
-}
-
-void PL::Map::write_door_to_routines(void) {
-    door_to_notice *notice;
-    LOOP_OVER(notice, door_to_notice) {
-        packaging_state save = Routines::begin(notice->dtn_iname);
-        local_variable *loc = LocalVariables::add_internal_local_c(I"loc", "room of actor");
-        inter_symbol *loc_s = LocalVariables::declare_this(loc, FALSE, 8);
-        Produce::inv_primitive(Emit::tree(), STORE_BIP);
-        Produce::down(Emit::tree());
-            Produce::ref_symbol(Emit::tree(), K_value, loc_s);
-            Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(LOCATION_HL));
-        Produce::up(Emit::tree());
-
-        Produce::inv_primitive(Emit::tree(), IF_BIP);
-        Produce::down(Emit::tree());
-            Produce::inv_primitive(Emit::tree(), EQ_BIP);
-            Produce::down(Emit::tree());
-                Produce::val_symbol(Emit::tree(), K_value, loc_s);
-                Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(THEDARK_HL));
-            Produce::up(Emit::tree());
-            Produce::code(Emit::tree());
-            Produce::down(Emit::tree());
-                Produce::inv_primitive(Emit::tree(), STORE_BIP);
-                Produce::down(Emit::tree());
-                    Produce::ref_symbol(Emit::tree(), K_value, loc_s);
-                    Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(REAL_LOCATION_HL));
-                Produce::up(Emit::tree());
-            Produce::up(Emit::tree());
-        Produce::up(Emit::tree());
-
-        Produce::inv_primitive(Emit::tree(), IF_BIP);
-        Produce::down(Emit::tree());
-            Produce::inv_primitive(Emit::tree(), EQ_BIP);
-            Produce::down(Emit::tree());
-                Produce::val_symbol(Emit::tree(), K_value, loc_s);
-                Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R1));
-            Produce::up(Emit::tree());
-            Produce::code(Emit::tree());
-            Produce::down(Emit::tree());
-                Produce::inv_primitive(Emit::tree(), RETURN_BIP);
-                Produce::down(Emit::tree());
-                    Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R2));
-                Produce::up(Emit::tree());
-            Produce::up(Emit::tree());
-        Produce::up(Emit::tree());
-
-        Produce::inv_primitive(Emit::tree(), RETURN_BIP);
-        Produce::down(Emit::tree());
-            Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R1));
-        Produce::up(Emit::tree());
-
-        Routines::end(save);
-    }
-}
-
-

§36. Indexing.

- -
-int PL::Map::map_add_to_World_index(OUTPUT_STREAM, instance *O) {
-    if ((O) && (Instances::of_kind(O, K_room))) {
-        PL::SpatialMap::index_room_connections(OUT, O);
-    }
-    return FALSE;
-}
-
-int PL::Map::map_annotate_in_World_index(OUTPUT_STREAM, instance *O) {
-    if ((O) && (Instances::of_kind(O, K_door))) {
-        instance *A = NULL, *B = NULL;
-        PL::Map::get_door_data(O, &A, &B);
-        if ((A) && (B)) WRITE(" - <i>door to ");
-        else WRITE(" - <i>one-sided door to ");
-        instance *X = A;
-        if (A == Data::Objects::room_being_indexed()) X = B;
-        if (X == NULL) {
-            parse_node *S = PropertyInferences::value_of(
-                Instances::as_subject(O), P_other_side);
-            X = Rvalues::to_object_instance(S);
-        }
-        if (X == NULL) WRITE("nowhere");
-        else IXInstances::index_name(OUT, X);
-        WRITE("</i>");
-        return TRUE;
-    }
-    return FALSE;
-}
-
diff --git a/docs/if-module/4-anl.html b/docs/if-module/4-anl.html index 08e0fef82..8be7cebb5 100644 --- a/docs/if-module/4-anl.html +++ b/docs/if-module/4-anl.html @@ -107,7 +107,7 @@ MathJax = { int delete_this_link; used temporarily during parsing } action_name_list;
-
  • The structure action_name_list is accessed in 2/ri, 3/mcr, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/ap2, 4/nap, 5/tfg, 5/gl and here.
+
  • The structure action_name_list is accessed in 2/ri, 3/tm, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/ap2, 4/nap, 5/tfg, 5/gl and here.

§2. The action name list is the part of an action pattern identifying which actions are allowed: "taking, dropping or examining" for example. The following routine extracts this from a potentially longer diff --git a/docs/if-module/4-ap2.html b/docs/if-module/4-ap2.html index 6372b0c80..ce95fcb04 100644 --- a/docs/if-module/4-ap2.html +++ b/docs/if-module/4-ap2.html @@ -151,7 +151,7 @@ not-really-action APs are used in no other context, and employ the CLASS_DEFINITION } ap_optional_clause;

-
  • The structure action_pattern is accessed in 2/ri, 3/mcr, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/anl, 4/nap, 5/tfg, 5/gl and here.
  • The structure ap_optional_clause is accessed in 2/ri, 3/mcr, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/anl, 4/nap, 5/tfg, 5/gl and here.
+
  • The structure action_pattern is accessed in 2/ri, 3/tm, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/anl, 4/nap, 5/tfg, 5/gl and here.
  • The structure ap_optional_clause is accessed in 2/ri, 3/tm, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/anl, 4/nap, 5/tfg, 5/gl and here.

§2. When we parse action patterns, we record why they fail, in order to make it easier to produce helpful error messages. (We can't simply fire off errors at the time they occur, because text is often parsed in several diff --git a/docs/if-module/5-tfg.html b/docs/if-module/5-tfg.html index ca626458b..901e98c96 100644 --- a/docs/if-module/5-tfg.html +++ b/docs/if-module/5-tfg.html @@ -108,7 +108,7 @@ function togglePopup(material_id) { struct understanding_reference *next; } understanding_reference;

-
  • The structure understanding_item is accessed in 2/ri, 3/mcr, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/anl, 4/ap2, 4/nap, 5/gl and here.
  • The structure understanding_reference is accessed in 2/ri, 3/mcr, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/anl, 4/ap2, 4/nap, 5/gl and here.
+
  • The structure understanding_item is accessed in 2/ri, 3/tm, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/anl, 4/ap2, 4/nap, 5/gl and here.
  • The structure understanding_reference is accessed in 2/ri, 3/tm, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/anl, 4/ap2, 4/nap, 5/gl and here.

§3. New grammar arrives in the system in two ways: primarily by means of explicit Understand sentences in the source text, but also secondarily in the form of table entries or other values used to match against snippets. For example: diff --git a/docs/index-module/2-ins.html b/docs/index-module/2-ins.html index 2ba420731..466a0d032 100644 --- a/docs/index-module/2-ins.html +++ b/docs/index-module/2-ins.html @@ -116,7 +116,7 @@ function togglePopup(material_id) {

-void IXInstances::index_name(OUTPUT_STREAM, instance *I) {
+void IXInstances::index_name(OUTPUT_STREAM, instance *I) {
     wording W = Instances::get_name_in_play(I, FALSE);
     if (Wordings::nonempty(W)) {
         WRITE("%+W", W);
diff --git a/docs/index-module/2-ipw.html b/docs/index-module/2-ipw.html
index ae4ba7858..a97ec446a 100644
--- a/docs/index-module/2-ipw.html
+++ b/docs/index-module/2-ipw.html
@@ -143,7 +143,7 @@ instance) Spatial.
     instance *I;
     LOOP_OVER_INSTANCES(I, K_object)
         if ((IXSpatial::no_detail_index(I))
-            || (PL::Map::object_is_a_direction(I)))
+            || (Map::instance_is_a_direction(I)))
             IXInstances::increment_indexing_count(I);
 
  • This code is used in §2.
@@ -245,11 +245,11 @@ table of Kinds. instance *indexing_room = NULL; int xtras_count = 0; -instance *Data::Objects::room_being_indexed(void) { +instance *Data::Objects::room_being_indexed(void) { return indexing_room; } -void Data::Objects::index(OUTPUT_STREAM, instance *I, kind *K, int depth, int details) { +void Data::Objects::index(OUTPUT_STREAM, instance *I, kind *K, int depth, int details) { if (depth == MAX_OBJECT_INDEX_DEPTH) internal_error("MAX_OBJECT_INDEX_DEPTH exceeded"); noun *nt = NULL; if (I) { @@ -468,7 +468,7 @@ table of Kinds.

§4.

-void Data::Objects::index_instances(OUTPUT_STREAM, kind *K, int depth) {
+void Data::Objects::index_instances(OUTPUT_STREAM, kind *K, int depth) {
     HTML::open_indented_p(OUT, depth, "tight");
     int c = 0;
     instance *I;
diff --git a/docs/index-module/3-bck.html b/docs/index-module/3-bck.html
index 5e0923356..3ddc02aa2 100644
--- a/docs/index-module/3-bck.html
+++ b/docs/index-module/3-bck.html
@@ -119,7 +119,7 @@ adds backdrop contents to a room called 
  • This code is used in §1.
  • diff --git a/docs/index-module/3-bd.html b/docs/index-module/3-bd.html index bf28478a1..d4eff1e00 100644 --- a/docs/index-module/3-bd.html +++ b/docs/index-module/3-bd.html @@ -167,7 +167,7 @@ Contents listing, so: }
    diff --git a/docs/index-module/3-ef.html b/docs/index-module/3-ef.html index ef821e60f..21d6347b3 100644 --- a/docs/index-module/3-ef.html +++ b/docs/index-module/3-ef.html @@ -119,7 +119,7 @@ function togglePopup(material_id) { }
    diff --git a/docs/index-module/3-fgr.html b/docs/index-module/3-fgr.html index db57af468..3ec5ffddf 100644 --- a/docs/index-module/3-fgr.html +++ b/docs/index-module/3-fgr.html @@ -165,7 +165,7 @@ to match this width, preserving the aspect ratio. }
    diff --git a/docs/index-module/3-rgn.html b/docs/index-module/3-rgn.html index 1a49090d5..6795b8a07 100644 --- a/docs/index-module/3-rgn.html +++ b/docs/index-module/3-rgn.html @@ -76,7 +76,7 @@ }
    diff --git a/docs/index-module/3-se.html b/docs/index-module/3-se.html index 2019ae71c..2505c67f6 100644 --- a/docs/index-module/3-se.html +++ b/docs/index-module/3-se.html @@ -191,7 +191,7 @@ function togglePopup(material_id) { }
    diff --git a/docs/index-module/3-spt.html b/docs/index-module/3-spt.html index 444ac27da..58e16e603 100644 --- a/docs/index-module/3-spt.html +++ b/docs/index-module/3-spt.html @@ -117,12 +117,12 @@ it already turns up under its owner. if (SPATIAL_DATA(I)->object_tree_child) Data::Objects::index(OUT, SPATIAL_DATA(I)->object_tree_child, NULL, depth+1, details); if ((Spatial::object_is_a_room(I)) && - (PL::Map::object_is_a_door(I) == FALSE)) { + (Map::instance_is_a_door(I) == FALSE)) { instance *I2; LOOP_OVER_INSTANCES(I2, K_object) { - if ((PL::Map::object_is_a_door(I2)) && (Spatial::progenitor(I2) != I)) { + if ((Map::instance_is_a_door(I2)) && (Spatial::progenitor(I2) != I)) { instance *A = NULL, *B = NULL; - PL::Map::get_door_data(I2, &A, &B); + Map::get_door_data(I2, &A, &B); if (A == I) Data::Objects::index(OUT, I2, NULL, depth+1, details); if (B == I) Data::Objects::index(OUT, I2, NULL, depth+1, details); } @@ -165,7 +165,7 @@ it already turns up under its owner. }
    diff --git a/docs/index-module/3-tm.html b/docs/index-module/3-tm.html new file mode 100644 index 000000000..7e1a32d56 --- /dev/null +++ b/docs/index-module/3-tm.html @@ -0,0 +1,105 @@ + + + + The Map + + + + + + + + + + + + + + + +
    + + +

    Indexing the player's initial position.

    + +

    §1.

    + +
    +int IXMap::add_to_World_index(OUTPUT_STREAM, instance *O) {
    +    if ((O) && (Instances::of_kind(O, K_room))) {
    +        PL::SpatialMap::index_room_connections(OUT, O);
    +    }
    +    return FALSE;
    +}
    +
    +int IXMap::annotate_in_World_index(OUTPUT_STREAM, instance *O) {
    +    if ((O) && (Instances::of_kind(O, K_door))) {
    +        instance *A = NULL, *B = NULL;
    +        Map::get_door_data(O, &A, &B);
    +        if ((A) && (B)) WRITE(" - <i>door to ");
    +        else WRITE(" - <i>one-sided door to ");
    +        instance *X = A;
    +        if (A == Data::Objects::room_being_indexed()) X = B;
    +        if (X == NULL) {
    +            parse_node *S = PropertyInferences::value_of(
    +                Instances::as_subject(O), P_other_side);
    +            X = Rvalues::to_object_instance(S);
    +        }
    +        if (X == NULL) WRITE("nowhere");
    +        else IXInstances::index_name(OUT, X);
    +        WRITE("</i>");
    +        return TRUE;
    +    }
    +    return FALSE;
    +}
    +
    + + +
    + + + diff --git a/docs/index-module/3-tp.html b/docs/index-module/3-tp.html index 1c17e0ab3..d2482fa24 100644 --- a/docs/index-module/3-tp.html +++ b/docs/index-module/3-tp.html @@ -93,7 +93,7 @@ usually appear anywhere. }
    diff --git a/docs/index-module/index.html b/docs/index-module/index.html index c9752abb3..3843716dd 100644 --- a/docs/index-module/index.html +++ b/docs/index-module/index.html @@ -184,6 +184,11 @@ Regions - Indexing the player's initial position.

    +
  • +

    + The Map - + Indexing the player's initial position.

    +
  • diff --git a/docs/runtime-module/2-emt.html b/docs/runtime-module/2-emt.html index f3c1f42eb..772b9aff9 100644 --- a/docs/runtime-module/2-emt.html +++ b/docs/runtime-module/2-emt.html @@ -84,7 +84,7 @@ function togglePopup(material_id) { inter_tree *I7_generation_tree = NULL; -inter_tree *Emit::tree(void) { +inter_tree *Emit::tree(void) { return I7_generation_tree; } @@ -349,7 +349,7 @@ insert them into the Inter stream close to the top. Packaging::exit(Emit::tree(), save); } -inter_name *Emit::named_numeric_constant(inter_name *name, inter_ti val) { +inter_name *Emit::named_numeric_constant(inter_name *name, inter_ti val) { packaging_state save = Packaging::enter_home_of(name); inter_symbol *con_name = Produce::define_symbol(name); Produce::guard(Inter::Constant::new_numerical(Packaging::at(Emit::tree()), Inter::SymbolsTables::id_from_IRS_and_symbol(Packaging::at(Emit::tree()), con_name), Inter::SymbolsTables::id_from_IRS_and_symbol(Packaging::at(Emit::tree()), int_interk), LITERAL_IVAL, val, Produce::baseline(Packaging::at(Emit::tree())), NULL)); @@ -502,7 +502,7 @@ insert them into the Inter stream close to the top. return save; } -packaging_state Emit::named_array_begin(inter_name *N, kind *K) { +packaging_state Emit::named_array_begin(inter_name *N, kind *K) { packaging_state save = Packaging::enter_home_of(N); inter_symbol *symb = Produce::define_symbol(N); Emit::push_array(); @@ -512,7 +512,7 @@ insert them into the Inter stream close to the top. return save; } -void Emit::array_iname_entry(inter_name *iname) { +void Emit::array_iname_entry(inter_name *iname) { if (current_A == NULL) internal_error("entry outside of inter array"); inter_symbol *alias; if (iname == NULL) alias = Site::veneer_symbol(Emit::tree(), NOTHING_VSYMB); @@ -568,12 +568,12 @@ insert them into the Inter stream close to the top. Emit::add_entry(v1, v2); } -void Emit::array_numeric_entry(inter_ti N) { +void Emit::array_numeric_entry(inter_ti N) { if (current_A == NULL) internal_error("entry outside of inter array"); Emit::add_entry(LITERAL_IVAL, N); } -void Emit::array_divider(text_stream *divider_text) { +void Emit::array_divider(text_stream *divider_text) { if (current_A == NULL) internal_error("entry outside of inter array"); inter_ti S = Inter::Warehouse::create_text(Inter::Tree::warehouse(Emit::tree()), Inter::Bookmarks::package(Packaging::at(Emit::tree()))); Str::copy(Inter::Warehouse::get_text(Inter::Tree::warehouse(Emit::tree()), S), divider_text); @@ -586,7 +586,7 @@ insert them into the Inter stream close to the top. return IBM; } -void Emit::array_end(packaging_state save) { +void Emit::array_end(packaging_state save) { if (current_A == NULL) internal_error("inter array not opened"); inter_symbol *con_name = current_A->array_name_symbol; inter_bookmark *IBM = Packaging::at(Emit::tree()); @@ -617,7 +617,7 @@ insert them into the Inter stream close to the top. Packaging::exit(Emit::tree(), save); } -inter_name *Emit::named_iname_constant(inter_name *name, kind *K, inter_name *iname) { +inter_name *Emit::named_iname_constant(inter_name *name, kind *K, inter_name *iname) { packaging_state save = Packaging::enter_home_of(name); inter_symbol *con_name = Produce::define_symbol(name); inter_symbol *val_kind = Produce::kind_to_symbol(K); @@ -633,7 +633,7 @@ insert them into the Inter stream close to the top. return name; } -inter_name *Emit::named_numeric_constant_hex(inter_name *name, inter_ti val) { +inter_name *Emit::named_numeric_constant_hex(inter_name *name, inter_ti val) { packaging_state save = Packaging::enter_home_of(name); inter_symbol *con_name = Produce::define_symbol(name); Produce::annotate_symbol_i(con_name, HEX_IANN, 0); @@ -642,7 +642,7 @@ insert them into the Inter stream close to the top. return name; } -inter_name *Emit::named_unchecked_constant_hex(inter_name *name, inter_ti val) { +inter_name *Emit::named_unchecked_constant_hex(inter_name *name, inter_ti val) { packaging_state save = Packaging::enter_home_of(name); inter_symbol *con_name = Produce::define_symbol(name); Produce::annotate_symbol_i(con_name, HEX_IANN, 0); @@ -651,7 +651,7 @@ insert them into the Inter stream close to the top. return name; } -inter_name *Emit::named_numeric_constant_signed(inter_name *name, int val) { +inter_name *Emit::named_numeric_constant_signed(inter_name *name, int val) { packaging_state save = Packaging::enter_home_of(name); inter_symbol *con_name = Produce::define_symbol(name); Produce::annotate_symbol_i(con_name, SIGNED_IANN, 0); @@ -667,7 +667,7 @@ insert them into the Inter stream close to the top. */ } -void Emit::code_comment(text_stream *text) { +void Emit::code_comment(text_stream *text) { inter_ti ID = Inter::Warehouse::create_text(Inter::Tree::warehouse(Emit::tree()), Inter::Bookmarks::package(Packaging::at(Emit::tree()))); Str::copy(Inter::Warehouse::get_text(Inter::Tree::warehouse(Emit::tree()), ID), text); Produce::guard(Inter::Comment::new(Produce::at(Emit::tree()), (inter_ti) Produce::level(Emit::tree()), NULL, ID)); @@ -675,7 +675,7 @@ insert them into the Inter stream close to the top. } -void Emit::routine(inter_name *rname, kind *rkind, inter_package *block) { +void Emit::routine(inter_name *rname, kind *rkind, inter_package *block) { if (Packaging::at(Emit::tree()) == NULL) internal_error("no inter repository"); inter_symbol *AB_symbol = Produce::kind_to_symbol(rkind); inter_symbol *rsymb = Produce::define_symbol(rname); @@ -686,7 +686,7 @@ insert them into the Inter stream close to the top. Produce::baseline(Packaging::at(Emit::tree())), NULL)); } -inter_symbol *Emit::local(kind *K, text_stream *lname, inter_ti annot, text_stream *comm) { +inter_symbol *Emit::local(kind *K, text_stream *lname, inter_ti annot, text_stream *comm) { if (Site::get_cir(Emit::tree()) == NULL) internal_error("not in an inter routine"); if (K == NULL) K = K_number; inter_symbol *loc_name = Produce::new_local_symbol(Site::get_cir(Emit::tree()), lname); @@ -702,13 +702,13 @@ insert them into the Inter stream close to the top. return loc_name; } -void Emit::cast(kind *F, kind *T) { +void Emit::cast(kind *F, kind *T) { inter_symbol *from_kind = Produce::kind_to_symbol(F); inter_symbol *to_kind = Produce::kind_to_symbol(T); Produce::guard(Inter::Cast::new(Produce::at(Emit::tree()), from_kind, to_kind, (inter_ti) Produce::level(Emit::tree()), NULL)); } -void Emit::intervention(int stage, text_stream *segment, text_stream *part, text_stream *i6, text_stream *seg) { +void Emit::intervention(int stage, text_stream *segment, text_stream *part, text_stream *i6, text_stream *seg) { inter_warehouse *warehouse = Inter::Tree::warehouse(Emit::tree()); inter_ti ID1 = Inter::Warehouse::create_text(warehouse, Inter::Bookmarks::package(Packaging::at(Emit::tree()))); Str::copy(Inter::Warehouse::get_text(Inter::Tree::warehouse(Emit::tree()), ID1), segment); @@ -736,12 +736,12 @@ insert them into the Inter stream close to the top.
     
     
    -text_stream *Emit::to_text(inter_name *iname) {
    +text_stream *Emit::to_text(inter_name *iname) {
         if (iname == NULL) return NULL;
         return InterNames::to_symbol(iname)->symbol_name;
     }
     
    -void Emit::holster(value_holster *VH, inter_name *iname) {
    +void Emit::holster(value_holster *VH, inter_name *iname) {
         if (Holsters::data_acceptable(VH)) {
             inter_ti v1 = 0, v2 = 0;
             Emit::to_ival(&v1, &v2, iname);
    @@ -749,20 +749,20 @@ insert them into the Inter stream close to the top.
         }
     }
     
    -void Emit::symbol_to_ival(inter_ti *val1, inter_ti *val2, inter_symbol *S) {
    +void Emit::symbol_to_ival(inter_ti *val1, inter_ti *val2, inter_symbol *S) {
         inter_bookmark *IBM = Packaging::at(Emit::tree());
         if (S) { Inter::Symbols::to_data(Inter::Bookmarks::tree(IBM), Inter::Bookmarks::package(IBM), S, val1, val2); return; }
         *val1 = LITERAL_IVAL; *val2 = 0;
     }
     
    -void Emit::to_ival(inter_ti *val1, inter_ti *val2, inter_name *iname) {
    +void Emit::to_ival(inter_ti *val1, inter_ti *val2, inter_name *iname) {
         inter_bookmark *IBM = Packaging::at(Emit::tree());
         inter_symbol *S = InterNames::to_symbol(iname);
         if (S) { Inter::Symbols::to_data(Inter::Bookmarks::tree(IBM), Inter::Bookmarks::package(IBM), S, val1, val2); return; }
         *val1 = LITERAL_IVAL; *val2 = 0;
     }
     
    -void Emit::to_ival_in_context(inter_name *context, inter_ti *val1, inter_ti *val2, inter_name *iname) {
    +void Emit::to_ival_in_context(inter_name *context, inter_ti *val1, inter_ti *val2, inter_name *iname) {
         package_request *PR = InterNames::location(context);
         inter_package *pack = Packaging::incarnate(PR);
         inter_symbol *S = InterNames::to_symbol(iname);
    @@ -770,7 +770,7 @@ insert them into the Inter stream close to the top.
         *val1 = LITERAL_IVAL; *val2 = 0;
     }
     
    -int Emit::defined(inter_name *iname) {
    +int Emit::defined(inter_name *iname) {
         if (iname == NULL) return FALSE;
         inter_symbol *S = InterNames::to_symbol(iname);
         if (Inter::Symbols::is_defined(S)) return TRUE;
    @@ -782,27 +782,27 @@ insert them into the Inter stream close to the top.
         struct packaging_state saved_PS;
     } ival_emission;
     
    -ival_emission Emit::begin_ival_emission(inter_name *iname) {
    +ival_emission Emit::begin_ival_emission(inter_name *iname) {
         ival_emission IE;
         IE.emission_VH = Holsters::new(INTER_DATA_VHMODE);
         IE.saved_PS = Packaging::enter_home_of(iname);
         return IE;
     }
     
    -value_holster *Emit::ival_holster(ival_emission *IE) {
    +value_holster *Emit::ival_holster(ival_emission *IE) {
         return &(IE->emission_VH);
     }
     
    -void Emit::end_ival_emission(ival_emission *IE, inter_ti *v1, inter_ti *v2) {
    +void Emit::end_ival_emission(ival_emission *IE, inter_ti *v1, inter_ti *v2) {
         Holsters::unholster_pair(&(IE->emission_VH), v1, v2);
         Packaging::exit(Emit::tree(), IE->saved_PS);
     }
     
    -package_request *Emit::current_enclosure(void) {
    +package_request *Emit::current_enclosure(void) {
         return Packaging::enclosure(Emit::tree());
     }
     
    -packaging_state Emit::unused_packaging_state(void) {
    +packaging_state Emit::unused_packaging_state(void) {
         return Packaging::stateless();
     }
     
    diff --git a/docs/runtime-module/2-hrr.html b/docs/runtime-module/2-hrr.html index 2ffefae58..a9f981e3d 100644 --- a/docs/runtime-module/2-hrr.html +++ b/docs/runtime-module/2-hrr.html @@ -1723,11 +1723,11 @@ function togglePopup(material_id) {

    §4.

    -inter_name *Hierarchy::find(int id) {
    +inter_name *Hierarchy::find(int id) {
         return HierarchyLocations::find(Emit::tree(), id);
     }
     
    -void Hierarchy::make_available(inter_tree *I, inter_name *iname) {
    +void Hierarchy::make_available(inter_tree *I, inter_name *iname) {
         text_stream *ma_as = Produce::get_translation(iname);
         if (Str::len(ma_as) == 0) ma_as = Emit::to_text(iname);
         PackageTypes::get(I, I"_linkage");
    @@ -1739,7 +1739,7 @@ function togglePopup(material_id) {
         return HierarchyLocations::attach_new_package(Emit::tree(), C, NULL, hap_id);
     }
     
    -package_request *Hierarchy::synoptic_package(int hap_id) {
    +package_request *Hierarchy::synoptic_package(int hap_id) {
         return HierarchyLocations::attach_new_package(Emit::tree(), NULL, NULL, hap_id);
     }
     
    @@ -1751,11 +1751,11 @@ function togglePopup(material_id) {
         return HierarchyLocations::attach_new_package(Emit::tree(), NULL, Packaging::enclosure(Emit::tree()), hap_id);
     }
     
    -package_request *Hierarchy::package_within(int hap_id, package_request *super) {
    +package_request *Hierarchy::package_within(int hap_id, package_request *super) {
         return HierarchyLocations::attach_new_package(Emit::tree(), NULL, super, hap_id);
     }
     
    -inter_name *Hierarchy::make_iname_in(int id, package_request *P) {
    +inter_name *Hierarchy::make_iname_in(int id, package_request *P) {
         return HierarchyLocations::find_in_package(Emit::tree(), id, P, EMPTY_WORDING, NULL, -1, NULL);
     }
     
    diff --git a/docs/runtime-module/4-ins.html b/docs/runtime-module/4-ins.html
    index ebdfbb961..1d5da44ec 100644
    --- a/docs/runtime-module/4-ins.html
    +++ b/docs/runtime-module/4-ins.html
    @@ -91,7 +91,7 @@ function togglePopup(material_id) {
         I->icd.instance_emitted = FALSE;
     }
     
    -inter_name *RTInstances::iname(instance *I) {
    +inter_name *RTInstances::iname(instance *I) {
         if (I == NULL) return NULL;
         return I->icd.instance_iname;
     }
    @@ -127,9 +127,7 @@ declarations) and finally return     LOOP_OVER(I, instance)
             if (Kinds::Behaviour::is_object(Instances::to_kind(I)) == FALSE)
                 RTInstances::emit_one(family, Instances::as_subject(I));
    -    #ifdef IF_MODULE
         RTNaming::compile_small_names();
    -    #endif
         return TRUE;
     }
     
    @@ -144,7 +142,7 @@ declarations) and finally return RTPropertyValues::emit_subject(infs); } -inter_name *RTInstances::emitted_iname(instance *I) { +inter_name *RTInstances::emitted_iname(instance *I) { if (I == NULL) return NULL; inter_name *iname = RTInstances::iname(I); if (I->icd.instance_emitted == FALSE) { @@ -154,7 +152,7 @@ declarations) and finally return return iname; } -package_request *RTInstances::package(instance *I) { +package_request *RTInstances::package(instance *I) { RTInstances::iname(I); Thus forcing this to exist... return I->icd.instance_package; } diff --git a/docs/runtime-module/4-rtn.html b/docs/runtime-module/4-rtn.html index 72c0a8df9..6539f14b2 100644 --- a/docs/runtime-module/4-rtn.html +++ b/docs/runtime-module/4-rtn.html @@ -81,7 +81,7 @@ already been set up, or not. Here's not:

    -packaging_state Routines::begin(inter_name *name) {
    +packaging_state Routines::begin(inter_name *name) {
         return Routines::begin_framed(name, NULL);
     }
     
    @@ -140,7 +140,7 @@ did not.

    -void Routines::end(packaging_state save) {
    +void Routines::end(packaging_state save) {
         kind *R_kind = LocalVariables::deduced_function_kind(currently_compiling_in_frame);
     
         inter_name *kernel_name = NULL, *public_name = currently_compiling_iname;
    diff --git a/docs/runtime-module/5-bck.html b/docs/runtime-module/5-bck.html
    index 8d191dc55..e49e261eb 100644
    --- a/docs/runtime-module/5-bck.html
    +++ b/docs/runtime-module/5-bck.html
    @@ -142,7 +142,7 @@
     
    • This code is used in §2.
    diff --git a/docs/runtime-module/5-bd.html b/docs/runtime-module/5-bd.html index e52b3db8c..d750a53cb 100644 --- a/docs/runtime-module/5-bd.html +++ b/docs/runtime-module/5-bd.html @@ -211,7 +211,7 @@ around it, in byte-accessible memory. }
    diff --git a/docs/runtime-module/5-ef.html b/docs/runtime-module/5-ef.html index 3c9600fc9..f47c9942f 100644 --- a/docs/runtime-module/5-ef.html +++ b/docs/runtime-module/5-ef.html @@ -129,7 +129,7 @@
    • The structure external_file_compilation_data is private to this section.
    diff --git a/docs/runtime-module/5-fgr.html b/docs/runtime-module/5-fgr.html index 5144230dc..ed14aabd8 100644 --- a/docs/runtime-module/5-fgr.html +++ b/docs/runtime-module/5-fgr.html @@ -77,7 +77,7 @@ }
    diff --git a/docs/runtime-module/5-nmn.html b/docs/runtime-module/5-nmn.html index 568400d18..cf9f87db5 100644 --- a/docs/runtime-module/5-nmn.html +++ b/docs/runtime-module/5-nmn.html @@ -186,7 +186,7 @@ function togglePopup(material_id) {
    • The structure short_name_notice is private to this section.
    diff --git a/docs/runtime-module/5-prs.html b/docs/runtime-module/5-prs.html index 248511a91..cbe0633ae 100644 --- a/docs/runtime-module/5-prs.html +++ b/docs/runtime-module/5-prs.html @@ -148,7 +148,7 @@ for the kinds we inherit from. }
    diff --git a/docs/runtime-module/5-rgn.html b/docs/runtime-module/5-rgn.html index 4db728449..a98defa03 100644 --- a/docs/runtime-module/5-rgn.html +++ b/docs/runtime-module/5-rgn.html @@ -108,7 +108,7 @@ function togglePopup(material_id) { }
    diff --git a/docs/runtime-module/5-se.html b/docs/runtime-module/5-se.html index 77c3a136d..75e28eb24 100644 --- a/docs/runtime-module/5-se.html +++ b/docs/runtime-module/5-se.html @@ -77,7 +77,7 @@ } diff --git a/docs/runtime-module/5-spt.html b/docs/runtime-module/5-spt.html index 4bd08d380..95fcddc5e 100644 --- a/docs/runtime-module/5-spt.html +++ b/docs/runtime-module/5-spt.html @@ -142,7 +142,7 @@ be compiled, so this code is never used. } diff --git a/docs/runtime-module/5-tm.html b/docs/runtime-module/5-tm.html new file mode 100644 index 000000000..392ab236a --- /dev/null +++ b/docs/runtime-module/5-tm.html @@ -0,0 +1,350 @@ + + + + The Map + + + + + + + + + + + + + + + +
    + + +
    + +

    §1.

    + +
    +inter_name *RTMap::new_direction_iname(void) {
    +    package_request *PR = Hierarchy::synoptic_package(DIRECTIONS_HAP);
    +    return Hierarchy::make_iname_in(DIRECTION_HL, PR);
    +}
    +
    +

    §2. One of the few early breaks with I6 practice was that I7 stores the +map differently at run-time compared to earlier I6 games. +

    + +
    +int RTMap::compile_model_tables(void) {
    +    Declare I6 constants for the directions2.1;
    +    Compile the I6 Map-Storage array2.2;
    +    return FALSE;
    +}
    +
    +

    §2.1. Declare I6 constants for the directions2.1 = +

    + +
    +    inter_name *ndi = Hierarchy::find(NO_DIRECTIONS_HL);
    +    Emit::named_numeric_constant(ndi, (inter_ti) Map::number_of_directions());
    +    Hierarchy::make_available(Emit::tree(), ndi);
    +
    +    instance *I;
    +    LOOP_OVER_INSTANCES(I, K_direction)
    +        Emit::named_iname_constant(MAP_DATA(I)->direction_iname, K_object,
    +            RTInstances::emitted_iname(I));
    +
    +
    • This code is used in §2.
    +

    §2.2. The Map_Storage array consists only of the exits arrays written out +one after another. It looks wasteful of memory, since it is almost always +going to be filled mostly with 0 entries (meaning: no exit that way). But +the memory needs to be there because map connections can be added dynamically +at run-time, so we can't know now how many we will need. +

    + +

    Compile the I6 Map-Storage array2.2 = +

    + +
    +    instance *I;
    +    LOOP_OVER_INSTANCES(I, K_object)
    +        RTInstances::emitted_iname(I);
    +    inter_name *iname = Hierarchy::find(MAP_STORAGE_HL);
    +    packaging_state save = Emit::named_array_begin(iname, K_object);
    +    int words_used = 0;
    +    if (Task::wraps_existing_storyfile()) {
    +        Emit::array_divider(I"minimal, as there are no rooms");
    +        Emit::array_iname_entry(NULL);
    +        Emit::array_iname_entry(NULL);
    +        Emit::array_iname_entry(NULL);
    +        Emit::array_iname_entry(NULL);
    +        words_used = 4;
    +    } else {
    +        Emit::array_divider(I"one row per room");
    +        instance *I;
    +        LOOP_OVER_INSTANCES(I, K_object)
    +            if (Spatial::object_is_a_room(I)) {
    +                int N = Map::number_of_directions();
    +                for (int i=0; i<N; i++) {
    +                    instance *to = MAP_EXIT(I, i);
    +                    if (to)
    +                        Emit::array_iname_entry(RTInstances::iname(to));
    +                    else
    +                        Emit::array_numeric_entry(0);
    +                }
    +                words_used++;
    +                TEMPORARY_TEXT(divider)
    +                WRITE_TO(divider, "Exits from: %~I", I);
    +                Emit::array_divider(divider);
    +                DISCARD_TEXT(divider)
    +            }
    +    }
    +    Emit::array_end(save);
    +    Hierarchy::make_available(Emit::tree(), iname);
    +
    +
    • This code is used in §2.
    +

    §3. Two-sided doors. The I6 implementation of two-way doors and of what, in I7, are called backdrops, +is quite complicated; and the Inter code we generate follows that traditional +form. See the Inform Designer's Manual, fourth edition (the "DM4") for explanations. +We are essentially trying to program all of that automatically, which is why these +awkward multi-purpose I6 properties (door_to, found_in, etc.) have no direct +I7 equivalents. +

    + +

    These little structures are needed to remember routines to compile later: +

    + +
    +typedef struct door_dir_notice {
    +    struct inter_name *ddn_iname;
    +    struct instance *door;
    +    struct instance *R1;
    +    struct instance *D1;
    +    struct instance *D2;
    +    CLASS_DEFINITION
    +} door_dir_notice;
    +
    +typedef struct door_to_notice {
    +    struct inter_name *dtn_iname;
    +    struct instance *door;
    +    struct instance *R1;
    +    struct instance *R2;
    +    CLASS_DEFINITION
    +} door_to_notice;
    +
    +parse_node *RTMap::door_dir_for_2_sided(instance *I, instance *R1, instance *D1,
    +    instance *D2) {
    +    door_dir_notice *notice = CREATE(door_dir_notice);
    +    notice->ddn_iname =
    +        Hierarchy::make_iname_in(TSD_DOOR_DIR_FN_HL, RTInstances::package(I));
    +    notice->door = I;
    +    notice->R1 = R1;
    +    notice->D1 = D1;
    +    notice->D2 = D2;
    +    return Rvalues::from_iname(notice->ddn_iname);
    +}
    +
    +parse_node *RTMap::door_to_for_2_sided(instance *I, instance *R1, instance *R2) {
    +    door_to_notice *notice = CREATE(door_to_notice);
    +    notice->dtn_iname =
    +        Hierarchy::make_iname_in(TSD_DOOR_TO_FN_HL, RTInstances::package(I));
    +    notice->door = I;
    +    notice->R1 = R1;
    +    notice->R2 = R2;
    +    return Rvalues::from_iname(notice->dtn_iname);
    +}
    +
    +parse_node *RTMap::found_in_for_2_sided(instance *I, instance *R1, instance *R2) {
    +    package_request *PR =
    +        Hierarchy::package_within(INLINE_PROPERTIES_HAP, RTInstances::package(I));
    +    inter_name *S = Hierarchy::make_iname_in(INLINE_PROPERTY_HL, PR);
    +    packaging_state save = Emit::named_array_begin(S, K_value);
    +    Emit::array_iname_entry(RTInstances::iname(R1));
    +    Emit::array_iname_entry(RTInstances::iname(R2));
    +    Emit::array_end(save);
    +    Produce::annotate_i(S, INLINE_ARRAY_IANN, 1);
    +    return Rvalues::from_iname(S);
    +}
    +
    +
    • The structure door_dir_notice is private to this section.
    • The structure door_to_notice is private to this section.
    +

    §4. Redeeming those notices: +

    + +
    +void RTMap::write_door_dir_routines(void) {
    +    door_dir_notice *notice;
    +    LOOP_OVER(notice, door_dir_notice) {
    +        packaging_state save = Routines::begin(notice->ddn_iname);
    +        local_variable *loc = LocalVariables::add_internal_local_c(I"loc", "room of actor");
    +        inter_symbol *loc_s = LocalVariables::declare_this(loc, FALSE, 8);
    +        Produce::inv_primitive(Emit::tree(), STORE_BIP);
    +        Produce::down(Emit::tree());
    +            Produce::ref_symbol(Emit::tree(), K_value, loc_s);
    +            Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(LOCATION_HL));
    +        Produce::up(Emit::tree());
    +
    +        Produce::inv_primitive(Emit::tree(), IF_BIP);
    +        Produce::down(Emit::tree());
    +            Produce::inv_primitive(Emit::tree(), EQ_BIP);
    +            Produce::down(Emit::tree());
    +                Produce::val_symbol(Emit::tree(), K_value, loc_s);
    +                Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(THEDARK_HL));
    +            Produce::up(Emit::tree());
    +            Produce::code(Emit::tree());
    +            Produce::down(Emit::tree());
    +                Produce::inv_primitive(Emit::tree(), STORE_BIP);
    +                Produce::down(Emit::tree());
    +                    Produce::ref_symbol(Emit::tree(), K_value, loc_s);
    +                    Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(REAL_LOCATION_HL));
    +                Produce::up(Emit::tree());
    +            Produce::up(Emit::tree());
    +        Produce::up(Emit::tree());
    +
    +        Produce::inv_primitive(Emit::tree(), IF_BIP);
    +        Produce::down(Emit::tree());
    +            Produce::inv_primitive(Emit::tree(), EQ_BIP);
    +            Produce::down(Emit::tree());
    +                Produce::val_symbol(Emit::tree(), K_value, loc_s);
    +                Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R1));
    +            Produce::up(Emit::tree());
    +            Produce::code(Emit::tree());
    +            Produce::down(Emit::tree());
    +                Produce::inv_primitive(Emit::tree(), RETURN_BIP);
    +                Produce::down(Emit::tree());
    +                    Produce::val_iname(Emit::tree(), K_value,
    +                        RTInstances::iname(Map::get_value_of_opposite_property(notice->D1)));
    +                Produce::up(Emit::tree());
    +            Produce::up(Emit::tree());
    +        Produce::up(Emit::tree());
    +
    +        Produce::inv_primitive(Emit::tree(), RETURN_BIP);
    +        Produce::down(Emit::tree());
    +            Produce::val_iname(Emit::tree(), K_value,
    +                RTInstances::iname(Map::get_value_of_opposite_property(notice->D2)));
    +        Produce::up(Emit::tree());
    +
    +        Routines::end(save);
    +    }
    +}
    +
    +void RTMap::write_door_to_routines(void) {
    +    door_to_notice *notice;
    +    LOOP_OVER(notice, door_to_notice) {
    +        packaging_state save = Routines::begin(notice->dtn_iname);
    +        local_variable *loc = LocalVariables::add_internal_local_c(I"loc", "room of actor");
    +        inter_symbol *loc_s = LocalVariables::declare_this(loc, FALSE, 8);
    +        Produce::inv_primitive(Emit::tree(), STORE_BIP);
    +        Produce::down(Emit::tree());
    +            Produce::ref_symbol(Emit::tree(), K_value, loc_s);
    +            Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(LOCATION_HL));
    +        Produce::up(Emit::tree());
    +
    +        Produce::inv_primitive(Emit::tree(), IF_BIP);
    +        Produce::down(Emit::tree());
    +            Produce::inv_primitive(Emit::tree(), EQ_BIP);
    +            Produce::down(Emit::tree());
    +                Produce::val_symbol(Emit::tree(), K_value, loc_s);
    +                Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(THEDARK_HL));
    +            Produce::up(Emit::tree());
    +            Produce::code(Emit::tree());
    +            Produce::down(Emit::tree());
    +                Produce::inv_primitive(Emit::tree(), STORE_BIP);
    +                Produce::down(Emit::tree());
    +                    Produce::ref_symbol(Emit::tree(), K_value, loc_s);
    +                    Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(REAL_LOCATION_HL));
    +                Produce::up(Emit::tree());
    +            Produce::up(Emit::tree());
    +        Produce::up(Emit::tree());
    +
    +        Produce::inv_primitive(Emit::tree(), IF_BIP);
    +        Produce::down(Emit::tree());
    +            Produce::inv_primitive(Emit::tree(), EQ_BIP);
    +            Produce::down(Emit::tree());
    +                Produce::val_symbol(Emit::tree(), K_value, loc_s);
    +                Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R1));
    +            Produce::up(Emit::tree());
    +            Produce::code(Emit::tree());
    +            Produce::down(Emit::tree());
    +                Produce::inv_primitive(Emit::tree(), RETURN_BIP);
    +                Produce::down(Emit::tree());
    +                    Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R2));
    +                Produce::up(Emit::tree());
    +            Produce::up(Emit::tree());
    +        Produce::up(Emit::tree());
    +
    +        Produce::inv_primitive(Emit::tree(), RETURN_BIP);
    +        Produce::down(Emit::tree());
    +            Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R1));
    +        Produce::up(Emit::tree());
    +
    +        Routines::end(save);
    +    }
    +}
    +
    +

    §5. ident is an identifier name for the direction instance. It seems redundant +here because surely if we know I, we know its runtime representation; but +that's not true — we need to call this function at a time when the final +identifier names for instance have not yet been settled. +

    + +
    +void RTMap::set_map_schemas(binary_predicate *bp, instance *I) {
    +    inter_name *ident = MAP_DATA(I)->direction_iname;
    +    bp->task_functions[TEST_ATOM_TASK] =
    +        Calculus::Schemas::new("(MapConnection(*2,%n) == *1)", ident);
    +    bp->task_functions[NOW_ATOM_TRUE_TASK] =
    +        Calculus::Schemas::new("AssertMapConnection(*2,%n,*1)", ident);
    +    bp->task_functions[NOW_ATOM_FALSE_TASK] =
    +        Calculus::Schemas::new("AssertMapUnconnection(*2,%n,*1)", ident);
    +}
    +
    + + +
    + + + diff --git a/docs/runtime-module/5-tp.html b/docs/runtime-module/5-tp.html index 4680cd41f..586b4b064 100644 --- a/docs/runtime-module/5-tp.html +++ b/docs/runtime-module/5-tp.html @@ -114,7 +114,7 @@ the function ChangePlayer} diff --git a/docs/runtime-module/index.html b/docs/runtime-module/index.html index 45080a3f7..b9324bb93 100644 --- a/docs/runtime-module/index.html +++ b/docs/runtime-module/index.html @@ -349,6 +349,11 @@ Regions -

    +
  • +

    + The Map - +

    +
  • diff --git a/inform7/Figures/memory-diagnostics.txt b/inform7/Figures/memory-diagnostics.txt index 3755f9377..cd16ca592 100644 --- a/inform7/Figures/memory-diagnostics.txt +++ b/inform7/Figures/memory-diagnostics.txt @@ -1,13 +1,13 @@ Total memory consumption was 258576K = 253 MB -62.4% was used for 1337985 objects, in 278606 frames in 202 x 800K = 161600K = 157 MB: +62.4% was used for 1337984 objects, in 278605 frames in 202 x 800K = 161600K = 157 MB: 9.8% inter_tree_node_array 36 x 8192 = 294912 objects, 25953408 bytes 5.5% text_stream_array 2595 x 100 = 259500 objects, 14615040 bytes 3.9% parse_node 129993 objects, 10399440 bytes 2.8% verb_conjugation 160 objects, 7425280 bytes 2.6% parse_node_annotation_array 431 x 500 = 215500 objects, 6909792 bytes - 2.4% linked_list 11779 objects, 6596240 bytes + 2.4% linked_list 11780 objects, 6596800 bytes 2.3% inter_symbol_array 70 x 1024 = 71680 objects, 6310080 bytes 1.2% pcalc_prop_array 24 x 1000 = 24000 objects, 3264768 bytes 1.2% map_data 670 objects, 3178480 bytes @@ -91,8 +91,8 @@ Total memory consumption was 258576K = 253 MB ---- parse_node_tree 20 objects, 17280 bytes ---- match_avinue_array 1 x 1000 objects, 16032 bytes ---- linked_list_item_array 1 x 1000 objects, 16032 bytes - ---- method 325 objects, 15600 bytes ---- to_phrase_request 59 objects, 15576 bytes + ---- method 323 objects, 15504 bytes ---- adjective 137 objects, 14248 bytes ---- literal_text 147 objects, 12936 bytes ---- adjective_iname_holder 320 objects, 12800 bytes @@ -124,23 +124,23 @@ Total memory consumption was 258576K = 253 MB ---- instance_usage_array 1 x 200 objects, 3232 bytes ---- kind_constructor_comparison_schema_array 1 x 100 objects, 3232 bytes ---- method_set 100 objects, 3200 bytes - ---- definition 44 objects, 3168 bytes ---- compatibility_specification 66 objects, 3168 bytes + ---- definition 44 objects, 3168 bytes ---- inform_extension 19 objects, 3040 bytes ---- either_or_property_data 62 objects, 2976 bytes ---- property_of_value_storage 93 objects, 2976 bytes ---- submodule_request 72 objects, 2880 bytes ---- inter_construct 32 objects, 2560 bytes - ---- part_of_inference_data 79 objects, 2528 bytes ---- parentage_inference_data 79 objects, 2528 bytes + ---- part_of_inference_data 79 objects, 2528 bytes ---- kind_constructor_instance_array 1 x 100 objects, 2432 bytes ---- kind_constructor_casting_rule_array 1 x 100 objects, 2432 bytes ---- equation_symbol 30 objects, 2400 bytes ---- semver_range 22 objects, 2288 bytes ---- use_option 29 objects, 1856 bytes ---- pronoun_usage 42 objects, 1680 bytes - ---- table_contribution_array 1 x 100 objects, 1632 bytes ---- activity_crossref_array 1 x 100 objects, 1632 bytes + ---- table_contribution_array 1 x 100 objects, 1632 bytes ---- kind_interaction 39 objects, 1560 bytes ---- inter_annotation_form 37 objects, 1480 bytes ---- plugin 23 objects, 1472 bytes @@ -148,52 +148,52 @@ Total memory consumption was 258576K = 253 MB ---- noun_filter_token 22 objects, 1408 bytes ---- scene 1 object, 1344 bytes ---- special_meaning_holder 33 objects, 1320 bytes - ---- constant_phrase 20 objects, 1280 bytes ---- build_script 40 objects, 1280 bytes + ---- constant_phrase 20 objects, 1280 bytes ---- invocation_options_array 1 x 100 objects, 1224 bytes ---- hierarchy_metadatum 15 objects, 1200 bytes ---- direction_inference_data 30 objects, 1200 bytes ---- quantifier 16 objects, 1024 bytes ---- table_column 16 objects, 896 bytes ---- inbuild_requirement 22 objects, 880 bytes - ---- code_generation 1 object, 864 bytes ---- control_structure_phrase 12 objects, 864 bytes + ---- code_generation 1 object, 864 bytes ---- cached_understanding 21 objects, 840 bytes ---- runtime_kind_structure 13 objects, 832 bytes ---- phrase_option_array 1 x 100 objects, 824 bytes - ---- pipeline_stage 17 objects, 816 bytes ---- target_vm 6 objects, 816 bytes + ---- pipeline_stage 17 objects, 816 bytes ---- generated_segment 25 objects, 800 bytes ---- inter_data_type 14 objects, 784 bytes ---- submodule_identity 23 objects, 736 bytes ---- rulebook_outcome 17 objects, 680 bytes ---- inform_language 6 objects, 672 bytes + ---- inter_warehouse_room 10 objects, 640 bytes ---- relation_guard 5 objects, 640 bytes ---- I6T_intervention 8 objects, 640 bytes - ---- inter_warehouse_room 10 objects, 640 bytes ---- nascent_array 7 objects, 616 bytes - ---- inbuild_search_result 15 objects, 600 bytes ---- named_rulebook_outcome 15 objects, 600 bytes + ---- inbuild_search_result 15 objects, 600 bytes ---- label_namespace 10 objects, 560 bytes ---- small_word_set 11 objects, 528 bytes - ---- implication 13 objects, 520 bytes ---- inform_kit 5 objects, 520 bytes + ---- implication 13 objects, 520 bytes ---- inference_family 11 objects, 440 bytes - ---- equation 4 objects, 416 bytes ---- i6_memory_setting 13 objects, 416 bytes - ---- module_package 10 objects, 400 bytes + ---- equation 4 objects, 416 bytes ---- dval_written 10 objects, 400 bytes - ---- article_usage 8 objects, 384 bytes + ---- module_package 10 objects, 400 bytes ---- bp_family 12 objects, 384 bytes + ---- article_usage 8 objects, 384 bytes ---- source_file 5 objects, 360 bytes ---- inbuild_genre 7 objects, 336 bytes - ---- grammatical_category 8 objects, 320 bytes - ---- pronoun 8 objects, 320 bytes ---- door_dir_notice 5 objects, 320 bytes + ---- pronoun 8 objects, 320 bytes + ---- grammatical_category 8 objects, 320 bytes ---- build_step 4 objects, 288 bytes ---- up_family 9 objects, 288 bytes - ---- door_to_notice 5 objects, 280 bytes ---- explicit_bp_data 5 objects, 280 bytes + ---- door_to_notice 5 objects, 280 bytes ---- inform_pipeline 4 objects, 256 bytes ---- verb_usage_tier 5 objects, 240 bytes ---- adjective_meaning_family 7 objects, 224 bytes @@ -201,34 +201,34 @@ Total memory consumption was 258576K = 253 MB ---- test_scenario 1 object, 208 bytes ---- build_skill 5 objects, 200 bytes ---- compilation_unit 5 objects, 200 bytes - ---- kit_dependency 4 objects, 192 bytes ---- plural_dictionary_entry 4 objects, 192 bytes + ---- kit_dependency 4 objects, 192 bytes ---- inform_project 1 object, 176 bytes - ---- pointer_allocation 2 objects, 160 bytes - ---- inter_architecture 4 objects, 160 bytes ---- link_instruction 4 objects, 160 bytes + ---- inter_architecture 4 objects, 160 bytes ---- inference_subject_family 5 objects, 160 bytes + ---- pointer_allocation 2 objects, 160 bytes ---- code_generation_target 4 objects, 160 bytes - ---- element_activation 4 objects, 128 bytes ---- codegen_pipeline 1 object, 128 bytes + ---- element_activation 4 objects, 128 bytes ---- inbuild_nest 3 objects, 120 bytes ---- inform_kit_ittt 2 objects, 96 bytes - ---- list_together_routine 2 objects, 80 bytes - ---- article 2 objects, 80 bytes ---- compile_task_data 1 object, 80 bytes + ---- article 2 objects, 80 bytes + ---- list_together_routine 2 objects, 80 bytes ---- build_methodology 1 object, 56 bytes ---- inter_warehouse 1 object, 56 bytes - ---- star_invention 1 object, 48 bytes ---- HTML_file_state 1 object, 48 bytes ---- figures_data 1 object, 48 bytes - ---- parse_name_notice 1 object, 40 bytes - ---- by_routine_bp_data 1 object, 40 bytes + ---- star_invention 1 object, 48 bytes ---- kind_template_definition 1 object, 40 bytes + ---- by_routine_bp_data 1 object, 40 bytes + ---- parse_name_notice 1 object, 40 bytes ---- loop_over_scope 1 object, 40 bytes 37.5% was used for memory not allocated for objects: - 15.9% text stream storage 42248372 bytes in 265816 claims + 15.9% text stream storage 42248420 bytes in 265816 claims 3.5% dictionary storage 9278976 bytes in 16372 claims ---- sorting 1064 bytes in 3 claims 2.7% source text 7200000 bytes in 3 claims @@ -244,5 +244,5 @@ Total memory consumption was 258576K = 253 MB ---- emitter array storage 12320 bytes in 8 claims ---- code generation workspace for objects 9200 bytes in 9 claims -19.9% was overhead - 52765592 bytes = 51528K = 50 MB +19.9% was overhead - 52765128 bytes = 51528K = 50 MB diff --git a/inform7/Figures/timings-diagnostics.txt b/inform7/Figures/timings-diagnostics.txt index afede8724..0db0b1950 100644 --- a/inform7/Figures/timings-diagnostics.txt +++ b/inform7/Figures/timings-diagnostics.txt @@ -1,15 +1,15 @@ 100.0% in inform7 run - 67.8% in compilation to Inter - 25.8% in //Phrases::Manager::compile_first_block// + 67.2% in compilation to Inter + 25.6% in //Phrases::Manager::compile_first_block// 8.9% in //Phrases::Manager::compile_as_needed// - 6.7% in //Strings::compile_responses// - 6.4% in //InferenceSubjects::emit_all// + 6.8% in //Strings::compile_responses// + 5.9% in //InferenceSubjects::emit_all// 4.4% in //MajorNodes::pre_pass// - 3.4% in //MajorNodes::pass_1// + 3.3% in //MajorNodes::pass_1// 2.0% in //Phrases::Manager::RulePrintingRule_routine// 1.8% in //Phrases::Manager::rulebooks_array// - 0.9% in //Phrases::Manager::traverse// 0.9% in //RTVerbs::ConjugateVerb// + 0.7% in //Phrases::Manager::traverse// 0.5% in //Phrases::Manager::parse_rule_parameters// 0.5% in //World::stage_V// 0.3% in //MajorNodes::pass_2// @@ -19,11 +19,11 @@ 0.1% in //RTKinds::compile_data_type_support_routines// 0.1% in //Task::make_built_in_kind_constructors// 0.1% in //World::stages_II_and_III// - 3.3% not specifically accounted for - 29.7% in running Inter pipeline - 9.7% in step preparation - 9.5% in inter step 2/12: link - 6.9% in inter step 12/12: generate inform6 -> auto.inf + 3.4% not specifically accounted for + 30.3% in running Inter pipeline + 10.0% in step preparation + 9.6% in inter step 2/12: link + 7.0% in inter step 12/12: generate inform6 -> auto.inf 0.3% in inter step 9/12: make-identifiers-unique 0.1% in inter step 10/12: reconcile-verbs 0.1% in inter step 11/12: eliminate-redundant-labels diff --git a/inform7/assertions-module/Chapter 2/Anaphoric References.w b/inform7/assertions-module/Chapter 2/Anaphoric References.w index 0d13b3b02..79656e60d 100644 --- a/inform7/assertions-module/Chapter 2/Anaphoric References.w +++ b/inform7/assertions-module/Chapter 2/Anaphoric References.w @@ -105,7 +105,7 @@ void Anaphora::change_discussion_topic(inference_subject *infsx, if (Annotations::node_has(current_sentence, implicit_in_creation_of_ANNOT)) return; #ifdef IF_MODULE - if ((PL::Map::is_a_direction(infsx)) && + if ((Map::subject_is_a_direction(infsx)) && ((InstanceSubjects::to_object_instance(infsx) == NULL) || (InstanceSubjects::to_object_instance(infsy_full)))) infsx = NULL; #endif diff --git a/inform7/assertions-module/Chapter 2/Classifying Sentences.w b/inform7/assertions-module/Chapter 2/Classifying Sentences.w index 827b8f457..0791b9c47 100644 --- a/inform7/assertions-module/Chapter 2/Classifying Sentences.w +++ b/inform7/assertions-module/Chapter 2/Classifying Sentences.w @@ -52,14 +52,13 @@ void Classifying::sentence(parse_node *p) { SyntaxTree::graft(Task::syntax_tree(), VP_PN, p); if (SyntaxTree::is_trace_set(Task::syntax_tree())) LOG("$T\n", p); @; - #ifdef IF_MODULE - PL::MapDirections::look_for_direction_creation(p); - #endif PropertySentences::look_for_property_creation(p); @; @; - if ((VP_PN->next) && (VP_PN->next->next) && (Diagrams::is_possessive_RELATIONSHIP(VP_PN->next->next))) + if ((VP_PN->next) && (VP_PN->next->next) && + (Diagrams::is_possessive_RELATIONSHIP(VP_PN->next->next))) @; + PluginCalls::new_assertion_notify(p); } else { LOG("$T\n", p); (W); diff --git a/inform7/assertions-module/Chapter 4/Assertions.w b/inform7/assertions-module/Chapter 4/Assertions.w index e27f7c0b9..d4580d387 100644 --- a/inform7/assertions-module/Chapter 4/Assertions.w +++ b/inform7/assertions-module/Chapter 4/Assertions.w @@ -379,7 +379,7 @@ at which point it becomes a |PROPER_NOUN_NT| node.) @ = #ifdef IF_MODULE if ((Node::get_type(px) == PROPER_NOUN_NT) && - (PL::Map::is_a_direction(Node::get_subject(px))) && + (Map::subject_is_a_direction(Node::get_subject(px))) && (Node::get_type(py->down) == PROPER_NOUN_NT)) { int np = problem_count; Assertions::make_coupling(px, py->down); /* A is a B */ @@ -1025,10 +1025,10 @@ in this case. #ifdef IF_MODULE if ((PL::MapDirections::get_mapping_relationship(px)) && (PL::MapDirections::get_mapping_relationship(py))) { - PL::Map::enter_one_way_mode(); + Map::enter_one_way_mode(); Assertions::make_coupling(px, py->down); Assertions::make_coupling(px->down, py); - PL::Map::exit_one_way_mode(); + Map::exit_one_way_mode(); return; } #endif @@ -1559,8 +1559,8 @@ There is also one case in which an object can be set equal to another object: } #ifdef IF_MODULE - if ((PL::Map::is_a_direction(Node::get_subject(px))) || - (PL::Map::is_a_direction(Node::get_subject(py)))) + if ((Map::subject_is_a_direction(Node::get_subject(px))) || + (Map::subject_is_a_direction(Node::get_subject(py)))) @ else #endif @@ -1592,7 +1592,7 @@ There is also one case in which an object can be set equal to another object: return; } inference_subject *target = Node::get_subject(py), *way = Node::get_subject(px); - if (PL::Map::is_a_direction(target)) { + if (Map::subject_is_a_direction(target)) { target = Node::get_subject(px); way = Node::get_subject(py); } if (global_pass_state.pass == 2) { @@ -1603,7 +1603,7 @@ There is also one case in which an object can be set equal to another object: "like saying '20 is north'. This is an odd thing " "to say, and makes me think that I've misunderstood you."); } else { - PL::Map::connect(Anaphora::get_current_subject(), target, way); + Map::connect(Anaphora::get_current_subject(), target, way); } } diff --git a/inform7/assertions-module/Chapter 4/Relation Knowledge.w b/inform7/assertions-module/Chapter 4/Relation Knowledge.w index 7e8ad60f6..9eb3d0585 100644 --- a/inform7/assertions-module/Chapter 4/Relation Knowledge.w +++ b/inform7/assertions-module/Chapter 4/Relation Knowledge.w @@ -76,9 +76,9 @@ void Assertions::Relational::assert_subtree_in_relationship(parse_node *value, p if ((iy == NULL) || (id == NULL)) internal_error("malformed directional subtree"); if (Rvalues::is_nothing_object_constant(value)) - PL::Map::connect(iy, NULL, id); + Map::connect(iy, NULL, id); else if (Rvalues::is_object(Node::get_evaluation(value))) - PL::Map::connect(iy, Node::get_subject(value), id); + Map::connect(iy, Node::get_subject(value), id); else { LOG("Val is $P\n", value); StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_MapToNonobject), diff --git a/inform7/core-module/Chapter 1/Class Predeclarations.w b/inform7/core-module/Chapter 1/Class Predeclarations.w index 8eb06241f..d7578e1ff 100644 --- a/inform7/core-module/Chapter 1/Class Predeclarations.w +++ b/inform7/core-module/Chapter 1/Class Predeclarations.w @@ -182,6 +182,8 @@ DECLARE_CLASS(use_as_event) @e backdrop_found_in_notice_CLASS @e bp_runtime_implementation_CLASS @e definition_CLASS +@e door_dir_notice_CLASS +@e door_to_notice_CLASS @e dval_written_CLASS @e i6_inclusion_matter_CLASS @e internal_test_case_CLASS @@ -199,6 +201,8 @@ DECLARE_CLASS(adjective_iname_holder) DECLARE_CLASS(backdrop_found_in_notice) DECLARE_CLASS(bp_runtime_implementation) DECLARE_CLASS(definition) +DECLARE_CLASS(door_dir_notice) +DECLARE_CLASS(door_to_notice) DECLARE_CLASS(dval_written) DECLARE_CLASS(i6_inclusion_matter) DECLARE_CLASS(internal_test_case) @@ -234,8 +238,6 @@ DECLARE_CLASS(index_lexicon_entry) @e command_index_entry_CLASS @e connected_submap_CLASS @e direction_inference_data_CLASS -@e door_dir_notice_CLASS -@e door_to_notice_CLASS @e EPS_map_level_CLASS @e found_in_inference_data_CLASS @e grammar_line_CLASS @@ -272,8 +274,6 @@ DECLARE_CLASS(cached_understanding) DECLARE_CLASS(command_index_entry) DECLARE_CLASS(connected_submap) DECLARE_CLASS(direction_inference_data) -DECLARE_CLASS(door_dir_notice) -DECLARE_CLASS(door_to_notice) DECLARE_CLASS(EPS_map_level) DECLARE_CLASS(found_in_inference_data) DECLARE_CLASS(grammar_line) diff --git a/inform7/core-module/Chapter 3/Plugin Calls.w b/inform7/core-module/Chapter 3/Plugin Calls.w index 35b03c61c..34b14915e 100644 --- a/inform7/core-module/Chapter 3/Plugin Calls.w +++ b/inform7/core-module/Chapter 3/Plugin Calls.w @@ -139,6 +139,17 @@ int PluginCalls::refine_implicit_noun(parse_node *p) { PLUGINS_CALL(REFINE_IMPLICIT_NOUN_PLUG, p); } +@ Called from //assertions: Classifying Sentences// to give plugins the chance +of an early look at a newly-read assertion. For example, the map plugin uses +this to spot that a sentence will create a new direction. + +@e NEW_ASSERTION_NOTIFY_PLUG + += +int PluginCalls::new_assertion_notify(parse_node *p) { + PLUGINS_CALL(NEW_ASSERTION_NOTIFY_PLUG, p); +} + @ Called from //assertions: The Equality Relation Revisited// when we have to decide if it's valid to ask or declare that two things are the same. Returning |TRUE| says that it is always valid; returning |FALSE| leaves diff --git a/inform7/if-module/Chapter 1/IF Module.w b/inform7/if-module/Chapter 1/IF Module.w index c7751f9d3..e2f00e48a 100644 --- a/inform7/if-module/Chapter 1/IF Module.w +++ b/inform7/if-module/Chapter 1/IF Module.w @@ -80,7 +80,7 @@ void IFModule::create_plugins(void) { bibliographic_plugin = PluginManager::new(&BibliographicData::start, I"bibliographic data", ifp); chronology_plugin = PluginManager::new(&Chronology::start_plugin, I"chronology", ifp); devices_plugin = PluginManager::new(&PL::Devices::start, I"devices", ifp); - map_plugin = PluginManager::new(&PL::Map::start, I"mapping", ifp); + map_plugin = PluginManager::new(&Map::start, I"mapping", ifp); persons_plugin = PluginManager::new(&PL::Persons::start, I"persons", ifp); player_plugin = PluginManager::new(&Player::start, I"player", ifp); regions_plugin = PluginManager::new(&Regions::start, I"regions", ifp); diff --git a/inform7/if-module/Chapter 2/Bibliographic Data.w b/inform7/if-module/Chapter 2/Bibliographic Data.w index 2f030bc65..6a49d9b34 100644 --- a/inform7/if-module/Chapter 2/Bibliographic Data.w +++ b/inform7/if-module/Chapter 2/Bibliographic Data.w @@ -408,10 +408,7 @@ just too short to care overmuch about this. @ = int i, pos = STREAM_EXTENT(OUT), whitespace_count=0, black_chars_written = 0; - int N = 100; - #ifdef IF_MODULE - N = BIBLIOGRAPHIC_TEXT_TRUNCATION; - #endif + int N = BIBLIOGRAPHIC_TEXT_TRUNCATION; if (p[0] == '"') p++; for (i=0; p[i]; i++) { if (STREAM_EXTENT(OUT) - pos >= N) break; diff --git a/inform7/if-module/Chapter 3/Backdrops.w b/inform7/if-module/Chapter 3/Backdrops.w index 42d13fc97..2e769656e 100644 --- a/inform7/if-module/Chapter 3/Backdrops.w +++ b/inform7/if-module/Chapter 3/Backdrops.w @@ -170,7 +170,7 @@ int Backdrops::complete_model(int stage) { @; if ((val_of_found_in == NULL) && (Instances::of_kind(I, K_backdrop))) @; - if (val_of_found_in) PL::Map::set_found_in(I, val_of_found_in); + if (val_of_found_in) Map::set_found_in(I, val_of_found_in); } } return FALSE; diff --git a/inform7/if-module/Chapter 3/Map Connection Relations.w b/inform7/if-module/Chapter 3/Map Connection Relations.w index 0cb213329..2454ee822 100644 --- a/inform7/if-module/Chapter 3/Map Connection Relations.w +++ b/inform7/if-module/Chapter 3/Map Connection Relations.w @@ -4,6 +4,12 @@ To define one binary predicate for each map direction, such as "mapped north of". @h Family. +This section creates a family of implicit relations (implemented as binary +predicates) corresponding to the different directions. + +For every direction created, a predicate is created for the possibility of +a map connection. For instance, "if Versailles is mapped north of the +Metro" tests the "mapped-north" BP. = bp_family *map_connecting_bp_family = NULL; @@ -12,42 +18,8 @@ void PL::MapDirections::start(void) { map_connecting_bp_family = BinaryPredicateFamilies::new(); METHOD_ADD(map_connecting_bp_family, TYPECHECK_BPF_MTID, PL::MapDirections::typecheck); METHOD_ADD(map_connecting_bp_family, ASSERT_BPF_MTID, PL::MapDirections::assert); - METHOD_ADD(map_connecting_bp_family, SCHEMA_BPF_MTID, PL::MapDirections::schema); - METHOD_ADD(map_connecting_bp_family, DESCRIBE_FOR_PROBLEMS_BPF_MTID, PL::MapDirections::describe_for_problems); - METHOD_ADD(map_connecting_bp_family, DESCRIBE_FOR_INDEX_BPF_MTID, PL::MapDirections::describe_for_index); -} - -@ This section creates a family of implicit relations (implemented as binary -predicates) corresponding to the different directions. - -For every direction created, a predicate is created for the possibility of -a map connection. For instance, "if Versailles is mapped north of the -Metro" tests the "mapped-north" BP. There is also one general relation -built in: - -= -binary_predicate *R_adjacency = NULL; - -@h The adjacency relation. -We may as well do this here: creating the relation "X is adjacent to Y". - -= -void PL::MapDirections::create_relations(void) { - R_adjacency = - BinaryPredicates::make_pair(spatial_bp_family, - BPTerms::new(infs_room), - BPTerms::new(infs_room), - I"adjacent-to", I"adjacent-from", - NULL, Calculus::Schemas::new("TestAdjacency(*1,*2)"), - PreformUtilities::wording(, ADJACENCY_RELATION_NAME)); - -} - -@ There is nothing special about asserting this, so we don't intervene: - -= -int PL::MapDirections::assert_relations(binary_predicate *relation, instance *I0, instance *I1) { - return FALSE; + METHOD_ADD(map_connecting_bp_family, DESCRIBE_FOR_INDEX_BPF_MTID, + PL::MapDirections::describe_for_index); } @h Subsequent creations. @@ -118,14 +90,6 @@ this to other languages.) is intentionally done very early on. @d MAX_DIRECTIONS 100 /* the Standard Rules define only 12, so this is plenty */ - -= -parse_node *directions_noticed[MAX_DIRECTIONS]; -binary_predicate *direction_relations_noticed[MAX_DIRECTIONS]; -int no_directions_noticed = 0; - -@ - @d MAX_MAPPING_RELATION_NAME_LENGTH MAX_WORDS_IN_DIRECTION*MAX_WORD_LENGTH+10 @ = @@ -169,22 +133,17 @@ int no_directions_noticed = 0; instance |I| for the direction, and given it the kind "direction". That makes it possible to complete the details of the BP. -|ident| can be any string of text which evaluates in I6 to the -object number of the direction object. It seems redundant here because -surely if we know |I|, we know its runtime representation; but that's not -true -- we need to call this routine at a time when the final identifier -names for I6 objects have not yet been settled. - = int mmp_call_counter = 0; -void PL::MapDirections::make_mapped_predicate(instance *I, inter_name *ident) { +void PL::MapDirections::make_mapped_predicate(instance *I) { wording W = Instances::get_name(I, FALSE); if ((Wordings::empty(W)) || (Wordings::length(W) > MAX_WORDS_IN_DIRECTION)) internal_error("bad direction name"); binary_predicate *bp = direction_relations_noticed[mmp_call_counter++]; if (bp == NULL) { LOG("Improper text: %W\n", W); - StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_ImproperlyMadeDirection), + StandardProblems::sentence_problem(Task::syntax_tree(), + _p_(PM_ImproperlyMadeDirection), "directions must be created by only the simplest possible sentences", "in the form 'North-north-west is a direction' only. Using adjectives, " "'called', 'which', and so on is not allowed. (In practice this is not " @@ -196,35 +155,10 @@ void PL::MapDirections::make_mapped_predicate(instance *I, inter_name *ident) { bp->term_details[0] = BPTerms::new(NULL); bp->term_details[1] = BPTerms::new(NULL); BinaryPredicates::set_index_details(bp, "room/door", "room/door"); - bp->task_functions[TEST_ATOM_TASK] = Calculus::Schemas::new("(MapConnection(*2,%n) == *1)", ident); - bp->task_functions[NOW_ATOM_TRUE_TASK] = Calculus::Schemas::new("AssertMapConnection(*2,%n,*1)", ident); - bp->task_functions[NOW_ATOM_FALSE_TASK] = Calculus::Schemas::new("AssertMapUnconnection(*2,%n,*1)", ident); + RTMap::set_map_schemas(bp, I); MAP_DATA(I)->direction_relation = bp; } -@ - -= -void PL::MapDirections::look_for_direction_creation(parse_node *pn) { - if (Node::get_type(pn) != SENTENCE_NT) return; - if ((pn->down == NULL) || (pn->down->next == NULL) || (pn->down->next->next == NULL)) return; - if (Node::get_type(pn->down) != VERB_NT) return; - if (Node::get_type(pn->down->next) != UNPARSED_NOUN_NT) return; - if (Node::get_type(pn->down->next->next) != UNPARSED_NOUN_NT) return; - current_sentence = pn; - pn = pn->down->next; - if (!(((Node::get_text(pn->next))) - && (<> == 0))) return; - if (no_directions_noticed >= MAX_DIRECTIONS) { - StandardProblems::limit_problem(Task::syntax_tree(), _p_(PM_TooManyDirections), - "different directions", MAX_DIRECTIONS); - return; - } - direction_relations_noticed[no_directions_noticed] = - PL::MapDirections::create_sketchy_mapping_direction(Node::get_text(pn)); - directions_noticed[no_directions_noticed++] = pn; -} - @h Typechecking. This won't catch everything, but it will do. Run-time checking will pick up remaining anomalies. @@ -237,7 +171,8 @@ int PL::MapDirections::typecheck(bp_family *self, binary_predicate *bp, if ((Kinds::compatible(kinds_of_terms[t], K_room) == NEVER_MATCH) && (Kinds::compatible(kinds_of_terms[t], K_door) == NEVER_MATCH)) { LOG("Term %d is %u but should be a room or door\n", t, kinds_of_terms[t]); - Propositions::Checker::issue_bp_typecheck_error(bp, kinds_of_terms[0], kinds_of_terms[1], tck); + Propositions::Checker::issue_bp_typecheck_error(bp, kinds_of_terms[0], + kinds_of_terms[1], tck); return NEVER_MATCH; } return ALWAYS_MATCH; @@ -261,30 +196,20 @@ int PL::MapDirections::assert(bp_family *self, binary_predicate *bp, SpatialInferences::infer_is_room(infs_from, prevailing_mood); if ((prevailing_mood >= 0) && (infs_to)) SpatialInferences::infer_is_room(infs_to, LIKELY_CE); - PL::Map::infer_direction(infs_from, infs_to, o_dir); + Map::infer_direction(infs_from, infs_to, o_dir); return TRUE; } -@h Compilation. -We need do nothing special: these relations can be compiled from their schemas. +@h Indexing. = -int PL::MapDirections::schema(bp_family *self, int task, binary_predicate *bp, annotated_i6_schema *asch) { - return FALSE; -} - -@h Problem message text. - -= -int PL::MapDirections::describe_for_problems(bp_family *self, OUTPUT_STREAM, binary_predicate *bp) { - return FALSE; -} -void PL::MapDirections::describe_for_index(bp_family *self, OUTPUT_STREAM, binary_predicate *bp) { +void PL::MapDirections::describe_for_index(bp_family *self, OUTPUT_STREAM, + binary_predicate *bp) { WRITE("map"); } @h The correspondence with directions. -(Speed really does not matter here.) +Speed really does not matter here. = binary_predicate *PL::MapDirections::get_mapping_relation(instance *dir) { @@ -311,3 +236,16 @@ instance *PL::MapDirections::get_mapping_relationship(parse_node *p) { } return NULL; } + +@h The adjacency relation. +There is also one general relation built in, though it belongs to the spatial family: + += +void PL::MapDirections::create_relations(void) { + BinaryPredicates::make_pair(spatial_bp_family, + BPTerms::new(infs_room), + BPTerms::new(infs_room), + I"adjacent-to", I"adjacent-from", + NULL, Calculus::Schemas::new("TestAdjacency(*1,*2)"), + PreformUtilities::wording(, ADJACENCY_RELATION_NAME)); +} diff --git a/inform7/if-module/Chapter 3/Spatial Map.w b/inform7/if-module/Chapter 3/Spatial Map.w index da1c0f412..2b844ee48 100644 --- a/inform7/if-module/Chapter 3/Spatial Map.w +++ b/inform7/if-module/Chapter 3/Spatial Map.w @@ -221,8 +221,8 @@ for any subsequent story directions to be unshown: int story_dir_to_page_dir[MAX_DIRECTIONS]; void PL::SpatialMap::initialise_page_directions(void) { - int i; - for (i=0; idirection_index >= 12)) { wording W = Instances::get_name(R, FALSE); - wording OW = Instances::get_name(PL::Map::get_value_of_opposite_property(R), FALSE); + wording OW = Instances::get_name(Map::get_value_of_opposite_property(R), FALSE); LOG("%+W is a direction. The opposite of %+W is %+W.\n", W, W, OW); } if (Instances::of_kind(R, K_region)) { @@ -2799,7 +2799,7 @@ void PL::SpatialMap::log_precis_of_map(void) { if (MAP_DATA(dir)->direction_index == i) { wording DW = Instances::get_name(dir, FALSE); LOG("%+W is %W of %+W.\n", OW, DW, RW); - instance *opp = PL::Map::get_value_of_opposite_property(dir); + instance *opp = Map::get_value_of_opposite_property(dir); int od = MAP_DATA(opp)->direction_index; if ((S) && (PL::SpatialMap::room_exit(S, od, NULL) == NULL)) { wording OPW = Instances::get_name(dir, FALSE); @@ -2830,7 +2830,7 @@ void PL::SpatialMap::index_room_connections(OUTPUT_STREAM, instance *R) { instance *dir; LOOP_OVER_INSTANCES(dir, K_direction) { int i = MAP_DATA(dir)->direction_index; - instance *opp = PL::Map::get_value_of_opposite_property(dir); + instance *opp = Map::get_value_of_opposite_property(dir); int od = opp?(MAP_DATA(opp)->direction_index):(-1); instance *D = NULL; instance *S = PL::SpatialMap::room_exit(R, i, &D); diff --git a/inform7/if-module/Chapter 3/Spatial Model.w b/inform7/if-module/Chapter 3/Spatial Model.w index eb77542a5..d1bbac679 100644 --- a/inform7/if-module/Chapter 3/Spatial Model.w +++ b/inform7/if-module/Chapter 3/Spatial Model.w @@ -784,7 +784,7 @@ when it finishes this will be set to the most recently mentioned. @ = inference *inf; POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), part_of_inf) { - if ((Spatial::object_is_a_room(I)) || (PL::Map::object_is_a_door(I))) { + if ((Spatial::object_is_a_room(I)) || (Map::instance_is_a_door(I))) { StandardProblems::object_problem(_p_(PM_RoomOrDoorAsPart), I, "was set up as being part of something else, which doors and rooms " diff --git a/inform7/if-module/Chapter 3/Spatial Relations.w b/inform7/if-module/Chapter 3/Spatial Relations.w index 2683b5f9e..cbed4b1c0 100644 --- a/inform7/if-module/Chapter 3/Spatial Relations.w +++ b/inform7/if-module/Chapter 3/Spatial Relations.w @@ -206,7 +206,6 @@ way which isn't symmetrical between the two, and this way round is cleanest. @ = if (Backdrops::assert_relations(bp, I0, I1)) return TRUE; - if (PL::MapDirections::assert_relations(bp, I0, I1)) return TRUE; if (Regions::assert_relations(bp, I0, I1)) return TRUE; @ This is the point at which non-assertable relations are thrown out. diff --git a/inform7/if-module/Chapter 3/The Map.w b/inform7/if-module/Chapter 3/The Map.w index 82278eee5..75bcea74f 100644 --- a/inform7/if-module/Chapter 3/The Map.w +++ b/inform7/if-module/Chapter 3/The Map.w @@ -1,19 +1,334 @@ -[PL::Map::] The Map. +[Map::] The Map. A plugin to provide a geographical model, linking rooms and doors together in oppositely-paired directions. -@ The map is a complicated data structure, both because it amounts to a +@h Introduction. +The map is a complicated data structure, both because it amounts to a ternary relation (though being implemented by many binary ones) and because of an ambiguity: a map connection from a room R can lead to another room S, to a door, or to nothing. Doors come in two sorts, one and two-sided, and checking the physical realism of all this means we need to produce many quite specific problem messages. -We will use quite a lot of temporary work-space to put all of this -together, but the details can be ignored. If we expected very large numbers -of objects then it would be worth economising here, but profiling suggests -that it really isn't. += +void Map::start(void) { + Map::create_inference(); + PluginManager::plug(MAKE_SPECIAL_MEANINGS_PLUG, Map::make_special_meanings); + PluginManager::plug(NEW_ASSERTION_NOTIFY_PLUG, Map::look_for_direction_creation); + PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, Map::new_base_kind_notify); + PluginManager::plug(NEW_SUBJECT_NOTIFY_PLUG, Map::new_subject_notify); + PluginManager::plug(SET_KIND_NOTIFY_PLUG, Map::set_kind_notify); + PluginManager::plug(SET_SUBKIND_NOTIFY_PLUG, Map::set_subkind_notify); + PluginManager::plug(ACT_ON_SPECIAL_NPS_PLUG, Map::act_on_special_NPs); + PluginManager::plug(CHECK_GOING_PLUG, Map::check_going); + PluginManager::plug(COMPLETE_MODEL_PLUG, Map::complete_model); + PluginManager::plug(NEW_PROPERTY_NOTIFY_PLUG, Map::new_property_notify); + PluginManager::plug(INFERENCE_DRAWN_NOTIFY_PLUG, Map::inference_drawn); + PluginManager::plug(INTERVENE_IN_ASSERTION_PLUG, Map::intervene_in_assertion); + PluginManager::plug(ADD_TO_WORLD_INDEX_PLUG, IXMap::add_to_World_index); + PluginManager::plug(ANNOTATE_IN_WORLD_INDEX_PLUG, IXMap::annotate_in_World_index); + PluginManager::plug(PRODUCTION_LINE_PLUG, Map::production_line); +} + +int Map::production_line(int stage, int debugging, stopwatch_timer *sequence_timer) { + if (stage == INTER1_CSEQ) { + BENCH(RTMap::compile_model_tables); + BENCH(RTMap::write_door_dir_routines); + BENCH(RTMap::write_door_to_routines); + } + return FALSE; +} + +@ This special sentence is used as a hint in making map documents; it has no +effect on the world model itself, and so is dealt with elsewhere, in //EPS Map//. + += +int Map::make_special_meanings(void) { + SpecialMeanings::declare(PL::EPSMap::index_map_with_SMF, I"index-map-with", 4); + return FALSE; +} + +@ Though it isn't implemented as a special meaning, we do look by hand early +in Inform's run for sentences in the form "X is a direction", so that they can +be "noticed". We need to do that in order to make sense of subsequent sentences +using directions to imply relations, as in "East of Eden is the Land of Nod." + += +parse_node *directions_noticed[MAX_DIRECTIONS]; +binary_predicate *direction_relations_noticed[MAX_DIRECTIONS]; +int no_directions_noticed = 0; + +int Map::look_for_direction_creation(parse_node *pn) { + if (Node::get_type(pn) != SENTENCE_NT) return FALSE; + if ((pn->down == NULL) || (pn->down->next == NULL) || (pn->down->next->next == NULL)) + return FALSE; + if (Node::get_type(pn->down) != VERB_NT) return FALSE; + if (Node::get_type(pn->down->next) != UNPARSED_NOUN_NT) return FALSE; + if (Node::get_type(pn->down->next->next) != UNPARSED_NOUN_NT) return FALSE; + current_sentence = pn; + pn = pn->down->next; + if (!(((Node::get_text(pn->next))) && (<> == 0))) return FALSE; + if (no_directions_noticed >= MAX_DIRECTIONS) { + StandardProblems::limit_problem(Task::syntax_tree(), _p_(PM_TooManyDirections), + "different directions", MAX_DIRECTIONS); + return FALSE; + } + direction_relations_noticed[no_directions_noticed] = + PL::MapDirections::create_sketchy_mapping_direction(Node::get_text(pn)); + directions_noticed[no_directions_noticed++] = pn; + return FALSE; +} + +@h The direction inference. +While we could probably represent map knowledge using relation inferences +in connection with the "mapped D of" relations, it's altogether easier and +makes for more legible code if we use a special inference family of our own: + += (early code) +inference_family *direction_inf = NULL; /* 100; where do map connections from O lead? */ + +@ = +void Map::create_inference(void) { + direction_inf = Inferences::new_family(I"direction_inf"); + METHOD_ADD(direction_inf, LOG_DETAILS_INF_MTID, Map::log_direction_inf); + METHOD_ADD(direction_inf, COMPARE_INF_MTID, Map::cmp_direction_inf); +} + +typedef struct direction_inference_data { + struct inference_subject *to; + struct inference_subject *dir; + CLASS_DEFINITION +} direction_inference_data; + +inference *Map::new_direction_inference(inference_subject *infs_from, + inference_subject *infs_to, instance *o_dir) { + PROTECTED_MODEL_PROCEDURE; + direction_inference_data *data = CREATE(direction_inference_data); + data->to = infs_to; + data->dir = (o_dir)?(Instances::as_subject(o_dir)):NULL; + return Inferences::create_inference(direction_inf, + STORE_POINTER_direction_inference_data(data), prevailing_mood); +} + +void Map::infer_direction(inference_subject *infs_from, inference_subject *infs_to, + instance *o_dir) { + inference *i = Map::new_direction_inference(infs_from, infs_to, o_dir); + Inferences::join_inference(i, infs_from); +} + +void Map::log_direction_inf(inference_family *f, inference *inf) { + direction_inference_data *data = RETRIEVE_POINTER_direction_inference_data(inf->data); + LOG("-to:$j -dir:$j", data->to, data->dir); +} + +@ Inferences about different directions from a location are different topics; +but different destinations in the same direction are different in content. + += +int Map::cmp_direction_inf(inference_family *f, inference *i1, inference *i2) { + direction_inference_data *data1 = RETRIEVE_POINTER_direction_inference_data(i1->data); + direction_inference_data *data2 = RETRIEVE_POINTER_direction_inference_data(i2->data); + + int c = Inferences::measure_infs(data1->dir) - Inferences::measure_infs(data2->dir); + if (c > 0) return CI_DIFFER_IN_TOPIC; if (c < 0) return -CI_DIFFER_IN_TOPIC; + c = Inferences::measure_infs(data1->to) - Inferences::measure_infs(data2->to); + if (c > 0) return CI_DIFFER_IN_CONTENT; if (c < 0) return -CI_DIFFER_IN_CONTENT; + + c = Inferences::measure_inf(i1) - Inferences::measure_inf(i2); + if (c > 0) return CI_DIFFER_IN_COPY_ONLY; if (c < 0) return -CI_DIFFER_IN_COPY_ONLY; + return CI_IDENTICAL; +} + +void Map::get_map_references(inference *i, + inference_subject **infs1, inference_subject **infs2) { + if ((i == NULL) || (i->family != direction_inf)) + internal_error("not a direction inf"); + direction_inference_data *data = RETRIEVE_POINTER_direction_inference_data(i->data); + if (infs1) *infs1 = data->to; if (infs2) *infs2 = data->dir; +} + +@h Special kinds. +It's obvious why the kinds direction and door are special. + += (early code) +kind *K_direction = NULL; +kind *K_door = NULL; + +@ These are recognised by the English name when defined by the Standard +Rules. (So there is no need to translate this to other languages.) + += + ::= + direction | + door + +@ = +int Map::new_base_kind_notify(kind *new_base, text_stream *name, wording W) { + if ((W)) { + switch (<>) { + case 0: K_direction = new_base; return TRUE; + case 1: K_door = new_base; return TRUE; + } + } + return FALSE; +} + +@ Direction needs to be an abstract object, not a thing or a room, so: + += +int Map::set_subkind_notify(kind *sub, kind *super) { + if ((sub == K_direction) && (super != K_object)) { + if (problem_count == 0) + StandardProblems::sentence_problem(Task::syntax_tree(), + _p_(PM_DirectionAdrift), + "'direction' is not allowed to be a kind of anything (other than " + "'object')", + "because it's too fundamental to the way Inform maps out the " + "geography of the physical world."); + return TRUE; + } + if (super == K_direction) { + if (problem_count == 0) + StandardProblems::sentence_problem(Task::syntax_tree(), + _p_(PM_DirectionSubkinded), + "'direction' is not allowed to have more specific kinds", + "because it's too fundamental to the way Inform maps out the " + "geography of the physical world."); + return TRUE; + } + if ((K_backdrop) && (sub == K_door) && + (Kinds::Behaviour::is_object_of_kind(super, K_backdrop))) { + StandardProblems::sentence_problem(Task::syntax_tree(), + _p_(PM_DoorAdrift), + "'door' is not allowed to be a kind of 'backdrop'", + "because it's too fundamental to the way Inform maps out the " + "geography of the physical world."); + return TRUE; + } + if ((K_backdrop) && (sub == K_backdrop) && + (Kinds::Behaviour::is_object_of_kind(super, K_door))) { + StandardProblems::sentence_problem(Task::syntax_tree(), + _p_(PM_BackdropAdrift), + "'backdrop' is not allowed to be a kind of 'door'", + "because it's too fundamental to the way Inform maps out the " + "geography of the physical world."); + return TRUE; + } + return FALSE; +} + +@h Spotting directions and doors. + += +int Map::subject_is_a_direction(inference_subject *infs) { + if (K_direction == NULL) return FALSE; /* in particular, if plugin inactive */ + return InferenceSubjects::is_within(infs, KindSubjects::from_kind(K_direction)); +} + +int Map::instance_is_a_direction(instance *I) { + if ((PluginManager::active(map_plugin)) && (K_direction) && (I) && + (Instances::of_kind(I, K_direction))) + return TRUE; + return FALSE; +} + +@ = +int Map::subject_is_a_door(inference_subject *infs) { + return Map::instance_is_a_door( + InstanceSubjects::to_object_instance(infs)); +} + +int Map::instance_is_a_door(instance *I) { + if ((PluginManager::active(map_plugin)) && (K_door) && (I) && + (Instances::of_kind(I, K_door))) + return TRUE; + return FALSE; +} + +@h Directions and their numbers. +Directions play a special role because sentences like "east of the treehouse +is the garden" are parsed differently from sentences like "the nearby place +property of the treehouse is the garden". + +For reasons to do with creating direction mapping relations, the lengths of +direction names are capped, though very, very few Inform users have ever +realised this: + +@d MAX_WORDS_IN_DIRECTION (MAX_WORDS_IN_ASSEMBLAGE - 4) + +@ When a new direction comes into existence (i.e., not when the underlying +instance |I| is created, but when its kind is realised to be "direction"), +we will assign it a number: + += +int registered_directions = 0; /* next direction number to be free */ + +int Map::number_of_directions(void) { + return registered_directions; +} + +@ "Up" and "down" are not really special among possible direction instances, but +they have linguistic features not shared by lateral directions. "Above the +garden is the treehouse", for instance, does not directly refer to either +direction, but implies both. + += +instance *I_up = NULL; +instance *I_down = NULL; + +@ These are recognised by their English names when defined by the Standard Rules. +(So there is no need to translate this to other languages.) + += + ::= + up | + down + +@ = +int Map::set_kind_notify(instance *I, kind *k) { + kind *kw = Instances::to_kind(I); + if ((!(Kinds::Behaviour::is_object_of_kind(kw, K_direction))) && + (Kinds::Behaviour::is_object_of_kind(k, K_direction))) { + wording IW = Instances::get_name(I, FALSE); + @; + if ((IW)) { + switch (<>) { + case 0: I_up = I; break; + case 1: I_down = I; break; + } + } + Naming::object_takes_definite_article(Instances::as_subject(I)); + @; + } + return FALSE; +} + +@ = + if (Wordings::empty(IW)) { + StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_NamelessDirection), + "nameless directions are not allowed", + "so writing something like 'There is a direction.' is forbidden."); + return TRUE; + } + if (Wordings::length(IW) > MAX_WORDS_IN_DIRECTION) { + StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_DirectionTooLong), + "although direction names can be really quite long in today's Inform", + "they can't be as long as that."); + return TRUE; + } + +@ = + registered_directions++; + inter_name *dname = RTMap::new_direction_iname(); + MAP_DATA(I)->direction_iname = dname; + PL::MapDirections::make_mapped_predicate(I); + +@h Map data on instances. +We will use quite a lot of temporary work-space to put all of this together, +but the details can be ignored. If we expected very large numbers of instances +then it would be worth economising here, but profiling suggests that it really +isn't. @d MAP_DATA(I) PLUGIN_DATA_ON_INSTANCE(map, I) @@ -49,327 +364,86 @@ typedef struct map_data { CLASS_DEFINITION } map_data; -@ It's obvious why the kinds direction and door are special. It's not so -obvious why "up" and "down" are: the answer is that there are linguistic -features of these which aren't shared by lateral directions. "Above the -garden is the treehouse", for instance, does not directly refer to either -direction, but implies both. - -= (early code) -kind *K_direction = NULL; -kind *K_door = NULL; -instance *I_up = NULL; -instance *I_down = NULL; - -@ Special properties. The I6 implementation of two-way doors and of what, in -I7, are called backdrops, is quite complicated. See the Inform Designer's Manual, -fourth edition (the "DM4") for explanations. We are essentially trying to -program all of that automatically, which is why these awkward multi-purpose -I6 properties (|door_to|, |found_in|, etc.) have no direct I7 equivalents. - -= (early code) -property *P_door = NULL; /* I6 only */ -property *P_door_dir = NULL; /* I6 only */ -property *P_door_to = NULL; /* I6 only */ -property *P_other_side = NULL; /* a value property for the other side of a door */ -property *P_opposite = NULL; /* a value property for the reverse of a direction */ -property *P_room_index = NULL; /* I6 only: workspace for path-finding through the map */ -property *P_found_in = NULL; /* I6 only: needed for multiply-present objects */ - -@ While we could probably represent map knowledge using relation inferences -in connection with the "mapped D of" relations, it's altogether easier and -makes for more legible code if we use a special inference type of our own: - -= (early code) -inference_family *DIRECTION_INF = NULL; /* 100; where do map connections from O lead? */ - -@ - -= -typedef struct direction_inference_data { - struct inference_subject *to; - struct inference_subject *dir; - CLASS_DEFINITION -} direction_inference_data; - -inference *PL::Map::new_direction_inference(inference_subject *infs_from, - inference_subject *infs_to, instance *o_dir) { - PROTECTED_MODEL_PROCEDURE; - direction_inference_data *data = CREATE(direction_inference_data); - data->to = infs_to; - data->dir = (o_dir)?(Instances::as_subject(o_dir)):NULL; - return Inferences::create_inference(DIRECTION_INF, - STORE_POINTER_direction_inference_data(data), prevailing_mood); -} - -void PL::Map::infer_direction(inference_subject *infs_from, inference_subject *infs_to, - instance *o_dir) { - inference *i = PL::Map::new_direction_inference(infs_from, infs_to, o_dir); - Inferences::join_inference(i, infs_from); -} - -void PL::Map::get_map_references(inference *i, - inference_subject **infs1, inference_subject **infs2) { - if ((i == NULL) || (i->family != DIRECTION_INF)) - internal_error("not a direction inf"); - direction_inference_data *data = RETRIEVE_POINTER_direction_inference_data(i->data); - if (infs1) *infs1 = data->to; if (infs2) *infs2 = data->dir; -} - -void PL::Map::log_direction_inf(inference_family *f, inference *inf) { - direction_inference_data *data = RETRIEVE_POINTER_direction_inference_data(inf->data); - LOG("-to:$j -dir:$j", data->to, data->dir); -} - -int PL::Map::cmp_direction_inf(inference_family *f, inference *i1, inference *i2) { - direction_inference_data *data1 = RETRIEVE_POINTER_direction_inference_data(i1->data); - direction_inference_data *data2 = RETRIEVE_POINTER_direction_inference_data(i2->data); - - int c = Inferences::measure_infs(data1->dir) - Inferences::measure_infs(data2->dir); - if (c > 0) return CI_DIFFER_IN_TOPIC; if (c < 0) return -CI_DIFFER_IN_TOPIC; - c = Inferences::measure_infs(data1->to) - Inferences::measure_infs(data2->to); - if (c > 0) return CI_DIFFER_IN_CONTENT; if (c < 0) return -CI_DIFFER_IN_CONTENT; - - c = Inferences::measure_inf(i1) - Inferences::measure_inf(i2); - if (c > 0) return CI_DIFFER_IN_COPY_ONLY; if (c < 0) return -CI_DIFFER_IN_COPY_ONLY; - return CI_IDENTICAL; -} - -@ One useful constant: - -@d MAX_WORDS_IN_DIRECTION (MAX_WORDS_IN_ASSEMBLAGE - 4) - -@ These little structures are needed to remember routines to compile later: - -= -typedef struct door_dir_notice { - struct inter_name *ddn_iname; - struct instance *door; - struct instance *R1; - struct instance *D1; - struct instance *D2; - CLASS_DEFINITION -} door_dir_notice; - -typedef struct door_to_notice { - struct inter_name *dtn_iname; - struct instance *door; - struct instance *R1; - struct instance *R2; - CLASS_DEFINITION -} door_to_notice; - -@h Initialisation. - -= -void PL::Map::start(void) { - DIRECTION_INF = Inferences::new_family(I"DIRECTION_INF"); - METHOD_ADD(DIRECTION_INF, LOG_DETAILS_INF_MTID, PL::Map::log_direction_inf); - METHOD_ADD(DIRECTION_INF, COMPARE_INF_MTID, PL::Map::cmp_direction_inf); - - PluginManager::plug(MAKE_SPECIAL_MEANINGS_PLUG, PL::Map::make_special_meanings); - PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, PL::Map::map_new_base_kind_notify); - PluginManager::plug(NEW_SUBJECT_NOTIFY_PLUG, PL::Map::map_new_subject_notify); - PluginManager::plug(SET_KIND_NOTIFY_PLUG, PL::Map::map_set_kind_notify); - PluginManager::plug(SET_SUBKIND_NOTIFY_PLUG, PL::Map::map_set_subkind_notify); - PluginManager::plug(ACT_ON_SPECIAL_NPS_PLUG, PL::Map::map_act_on_special_NPs); - PluginManager::plug(CHECK_GOING_PLUG, PL::Map::map_check_going); - PluginManager::plug(COMPLETE_MODEL_PLUG, PL::Map::map_complete_model); - PluginManager::plug(NEW_PROPERTY_NOTIFY_PLUG, PL::Map::map_new_property_notify); - PluginManager::plug(INFERENCE_DRAWN_NOTIFY_PLUG, PL::Map::map_inference_drawn); - PluginManager::plug(INTERVENE_IN_ASSERTION_PLUG, PL::Map::map_intervene_in_assertion); - PluginManager::plug(ADD_TO_WORLD_INDEX_PLUG, PL::Map::map_add_to_World_index); - PluginManager::plug(ANNOTATE_IN_WORLD_INDEX_PLUG, PL::Map::map_annotate_in_World_index); - PluginManager::plug(PRODUCTION_LINE_PLUG, PL::Map::production_line); -} - -int PL::Map::production_line(int stage, int debugging, stopwatch_timer *sequence_timer) { - if (stage == INTER1_CSEQ) { - BENCH(PL::Map::map_compile_model_tables); - BENCH(PL::Map::write_door_dir_routines); - BENCH(PL::Map::write_door_to_routines); - } - return FALSE; -} - -int PL::Map::make_special_meanings(void) { - SpecialMeanings::declare(PL::EPSMap::index_map_with_SMF, I"index-map-with", 4); - return FALSE; -} - @ = -map_data *PL::Map::new_data(inference_subject *subj) { +int Map::new_subject_notify(inference_subject *subj) { map_data *md = CREATE(map_data); - md->direction_index = -1; - md->direction_relation = NULL; - - int i; - for (i=0; iexits_set_at[i] = NULL; - md->exits[i] = NULL; - } md->map_connection_a = NULL; md->map_connection_b = NULL; md->map_direction_a = NULL; md->map_direction_b = NULL; + md->direction_index = -1; + md->direction_relation = NULL; + md->direction_iname = NULL; + + for (int i=0; iexits_set_at[i] = NULL; + md->exits[i] = NULL; + } + PL::SpatialMap::initialise_mapping_data(md); - return md; + ATTACH_PLUGIN_DATA_TO_SUBJECT(map, subj, md); + return FALSE; } -@h Kinds. -These are kind names to do with mapping which Inform provides special -support for; it recognises the English name when defined by the Standard -Rules. (So there is no need to translate this to other languages.) +@ Special properties. +These are property names to do with mapping which Inform provides special +support for. Two are visible to I7 authors, and the others are low-level +properties needed for the run-time implementation. + += (early code) +property *P_other_side = NULL; /* a value property for the other side of a door */ +property *P_opposite = NULL; /* a value property for the reverse of a direction */ + +property *P_door = NULL; /* Inter only */ +property *P_door_dir = NULL; /* Inter only */ +property *P_door_to = NULL; /* Inter only */ +property *P_room_index = NULL; /* Inter only: workspace for path-finding through the map */ +property *P_found_in = NULL; /* Inter only: needed for multiply-present objects */ + +@ We recognise these by their English names when they are defined by the +Standard Rules. (So there is no need to translate this to other languages.) = - ::= - direction | - door + ::= + opposite | + other side @ = -int PL::Map::map_new_base_kind_notify(kind *new_base, text_stream *name, wording W) { - if ((W)) { +int Map::new_property_notify(property *prn) { + if ((prn->name)) { switch (<>) { - case 0: K_direction = new_base; return TRUE; - case 1: K_door = new_base; return TRUE; + case 0: P_opposite = prn; break; + case 1: P_other_side = prn; break; } } return FALSE; } -@ Direction needs to be an abstract object, not a thing or a room, so: +@ The following is used also by //Backdrops//, since both plugins use a +shared Inter-level property at run-time. But this function will work even if +the map plugin is inactive; so you can still have backdrops without a map. = -int PL::Map::map_set_subkind_notify(kind *sub, kind *super) { - if ((sub == K_direction) && (super != K_object)) { - if (problem_count == 0) - StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_DirectionAdrift), - "'direction' is not allowed to be a kind of anything (other than " - "'object')", - "because it's too fundamental to the way Inform maps out the " - "geography of the physical world."); - return TRUE; - } - if (super == K_direction) { - if (problem_count == 0) - StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_DirectionSubkinded), - "'direction' is not allowed to have more specific kinds", - "because it's too fundamental to the way Inform maps out the " - "geography of the physical world."); - return TRUE; - } - if ((K_backdrop) && (sub == K_door) && (Kinds::Behaviour::is_object_of_kind(super, K_backdrop))) { - StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_DoorAdrift), - "'door' is not allowed to be a kind of 'backdrop'", - "because it's too fundamental to the way Inform maps out the " - "geography of the physical world."); - return TRUE; - } - if ((K_backdrop) && (sub == K_backdrop) && (Kinds::Behaviour::is_object_of_kind(super, K_door))) { - StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_BackdropAdrift), - "'backdrop' is not allowed to be a kind of 'door'", - "because it's too fundamental to the way Inform maps out the " - "geography of the physical world."); - return TRUE; - } - return FALSE; +void Map::set_found_in(instance *I, parse_node *val) { + if (P_found_in == NULL) + P_found_in = ValueProperties::new_nameless(I"found_in", + K_value); + if (PropertyInferences::value_of( + Instances::as_subject(I), P_found_in)) + internal_error("rival found_in interpretations"); + ValueProperties::assert(P_found_in, Instances::as_subject(I), val, CERTAIN_CE); } -@ = -int PL::Map::map_new_subject_notify(inference_subject *subj) { - ATTACH_PLUGIN_DATA_TO_SUBJECT(map, subj, PL::Map::new_data(subj)); - return FALSE; -} - -@ = -int PL::Map::object_is_a_direction(instance *I) { - if ((PluginManager::active(map_plugin)) && (K_direction) && (I) && - (Instances::of_kind(I, K_direction))) - return TRUE; - return FALSE; -} - -@ = -int PL::Map::object_is_a_door(instance *I) { - if ((PluginManager::active(map_plugin)) && (K_door) && (I) && - (Instances::of_kind(I, K_door))) - return TRUE; - return FALSE; -} - -int PL::Map::subject_is_a_door(inference_subject *infs) { - return PL::Map::object_is_a_door( - InstanceSubjects::to_object_instance(infs)); -} - -@h Directions and their numbers. -Directions play a special role because sentences like "east of the treehouse -is the garden" are parsed differently from sentences like "the nearby place -property of the treehouse is the garden"; they're also one domain of what -amounts to the ternary map relation, though we actually implement it as a -sheaf of binary relations, one for each direction. Anyway: +@ This utility returns the "opposite" property for a direction, which is +always another direction: for example, the opposite of northwest is southeast. = -int PL::Map::is_a_direction(inference_subject *infs) { - if (K_direction == NULL) return FALSE; /* in particular, if we aren't using the IF model */ - return InferenceSubjects::is_within(infs, KindSubjects::from_kind(K_direction)); +instance *Map::get_value_of_opposite_property(instance *I) { + parse_node *val = PropertyInferences::value_of( + Instances::as_subject(I), P_opposite); + if (val) return Rvalues::to_object_instance(val); + return NULL; } -@ When a new direction comes into existence (i.e., not when the underlying -object |I| is created, but when its kind is first realised to be "direction"), -we need to assign it a number: - -= -int registered_directions = 0; /* next direction number to be free */ - -@ These are direction names which Inform provides special support for; it -recognises the English names when defined by the Standard Rules. (So there is -no need to translate this to other languages.) - -= - ::= - up | - down - -@ = -int PL::Map::map_set_kind_notify(instance *I, kind *k) { - kind *kw = Instances::to_kind(I); - if ((!(Kinds::Behaviour::is_object_of_kind(kw, K_direction))) && - (Kinds::Behaviour::is_object_of_kind(k, K_direction))) { - wording IW = Instances::get_name(I, FALSE); - @; - if ((IW)) { - switch (<>) { - case 0: I_up = I; break; - case 1: I_down = I; break; - } - } - Naming::object_takes_definite_article(Instances::as_subject(I)); - @; - } - return FALSE; -} - -@ = - if (Wordings::empty(IW)) { - StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_NamelessDirection), - "nameless directions are not allowed", - "so writing something like 'There is a direction.' is forbidden."); - return TRUE; - } - if (Wordings::length(IW) > MAX_WORDS_IN_DIRECTION) { - StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_DirectionTooLong), - "although direction names can be really quite long in today's Inform", - "they can't be as long as that."); - return TRUE; - } - -@ = - registered_directions++; - package_request *PR = Hierarchy::synoptic_package(DIRECTIONS_HAP); - inter_name *dname = Hierarchy::make_iname_in(DIRECTION_HL, PR); - MAP_DATA(I)->direction_iname = dname; - PL::MapDirections::make_mapped_predicate(I, dname); - @h The exits array. The bulk of the map is stored in the arrays called |exits|, which hold the map connections fanning out from each room. The direction numbers carefully @@ -378,13 +452,13 @@ noted above are keys into these arrays. It might look a little wasteful of I7's memory to expand the direction inferences, a nicely compact representation, into large and sparse arrays. But it's convenient, and profiling suggests that the memory overhead is not -significant. It also means that the World Index mapping code, which contains +significant. It also means that the //Spatial Map// mapping code, which contains quite crunchy algorithms, has the fastest possible access to the layout. @d MAP_EXIT(X, Y) MAP_DATA(X)->exits[Y] = -void PL::Map::build_exits_array(void) { +void Map::build_exits_array(void) { instance *I; int d = 0; LOOP_OVER_INSTANCES(I, K_object) { @@ -394,9 +468,9 @@ void PL::Map::build_exits_array(void) { } LOOP_OVER_INSTANCES(I, K_object) { inference *inf; - POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), DIRECTION_INF) { + POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), direction_inf) { inference_subject *infs1, *infs2; - PL::Map::get_map_references(inf, &infs1, &infs2); + Map::get_map_references(inf, &infs1, &infs2); instance *to = NULL, *dir = NULL; if (infs1) to = InstanceSubjects::to_object_instance(infs1); if (infs2) dir = InstanceSubjects::to_object_instance(infs2); @@ -411,69 +485,6 @@ void PL::Map::build_exits_array(void) { } } -@ This is easy to translate into I6 (though that's partly because I7 doesn't -follow the traditional I6 library way to represent the map): - -= -int PL::Map::map_compile_model_tables(void) { - @; - @; - return FALSE; -} - -@ = - inter_name *ndi = Hierarchy::find(NO_DIRECTIONS_HL); - Emit::named_numeric_constant(ndi, (inter_ti) registered_directions); - Hierarchy::make_available(Emit::tree(), ndi); - - instance *I; - LOOP_OVER_INSTANCES(I, K_direction) { - Emit::named_iname_constant(MAP_DATA(I)->direction_iname, K_object, RTInstances::emitted_iname(I)); - } - -@ The |Map_Storage| array consists only of the |exits| arrays written out -one after another. It looks wasteful of memory, since it is almost always -going to be filled mostly with |0| entries (meaning: no exit that way). But -the memory needs to be there because map connections can be added dynamically -at run-time, so we can't know now how many we will need. - -@ = - instance *I; - LOOP_OVER_INSTANCES(I, K_object) - RTInstances::emitted_iname(I); - inter_name *iname = Hierarchy::find(MAP_STORAGE_HL); - packaging_state save = Emit::named_array_begin(iname, K_object); - int words_used = 0; - if (Task::wraps_existing_storyfile()) { - Emit::array_divider(I"minimal, as there are no rooms"); - Emit::array_iname_entry(NULL); - Emit::array_iname_entry(NULL); - Emit::array_iname_entry(NULL); - Emit::array_iname_entry(NULL); - words_used = 4; - } else { - Emit::array_divider(I"one row per room"); - instance *I; - LOOP_OVER_INSTANCES(I, K_object) - if (Spatial::object_is_a_room(I)) { - int i; - for (i=0; imap_connection_a; if (c2) *c2 = MAP_DATA(door)->map_connection_b; } -@h Properties. -These are property names to do with mapping which Inform provides special -support for; it recognises the English names when they are defined by the -Standard Rules. (So there is no need to translate this to other languages.) - -= - ::= - opposite | - other side - -@ = -int PL::Map::map_new_property_notify(property *prn) { - if ((prn->name)) { - switch (<>) { - case 0: P_opposite = prn; break; - case 1: P_other_side = prn; break; - } - } - return FALSE; -} - @ We would like to deduce from a sentence like >> The other side of the iron door is the Black Holding Area. that the "Black Holding Area" is a room; otherwise, if it has no map -connections, Inform may well think it's just an object. This is where that +connections, Inform may well think it's just a thing. This is where that deduction is made: = -int PL::Map::map_inference_drawn(inference *I, inference_subject *subj) { +int Map::inference_drawn(inference *I, inference_subject *subj) { property *prn = PropertyInferences::get_property(I); if ((prn) && (prn == P_other_side)) { parse_node *val = PropertyInferences::get_value(I); @@ -528,36 +518,6 @@ int PL::Map::map_inference_drawn(inference *I, inference_subject *subj) { return FALSE; } -@ The I6 |found_in| property is a general mechanism for multiply-present -objects. This causes great complications, and I7 simplifies the model world -by hiding it from the author, and using it internally to implement backdrops -and two-sided doors. Two different plugins therefore need access to it (this -one and Backdrops), and this is where they set it. - -= -void PL::Map::set_found_in(instance *I, parse_node *val) { - if (P_found_in == NULL) - P_found_in = ValueProperties::new_nameless(I"found_in", - K_value); - if (PropertyInferences::value_of( - Instances::as_subject(I), P_found_in)) - internal_error("rival found_in interpretations"); - ValueProperties::assert(P_found_in, Instances::as_subject(I), val, CERTAIN_CE); -} - -@ This utility routine which looks for the "opposite" -property in the linked list of inferences belonging to an object. -(This is a property of directions.) Crude, but not time-sensitive, -and there seems little point in writing this any better. - -= -instance *PL::Map::get_value_of_opposite_property(instance *I) { - parse_node *val = PropertyInferences::value_of( - Instances::as_subject(I), P_opposite); - if (val) return Rvalues::to_object_instance(val); - return NULL; -} - @h Linguistic extras. These NPs allow us to refer to the special directions "up" and "down": @@ -567,7 +527,7 @@ These NPs allow us to refer to the special directions "up" and "down": above @ = -int PL::Map::map_act_on_special_NPs(parse_node *p) { +int Map::act_on_special_NPs(parse_node *p) { if ((Node::get_text(p))) { switch (<>) { case 0: @@ -590,7 +550,7 @@ int PL::Map::map_act_on_special_NPs(parse_node *p) { @ We also add some optional clauses to the "going" action: = -int PL::Map::map_check_going(parse_node *from, parse_node *to, +int Map::check_going(parse_node *from, parse_node *to, parse_node *by, parse_node *through, parse_node *pushing) { if (PL::Actions::Patterns::check_going(from, "from", K_room, K_region) == FALSE) return FALSE; @@ -623,18 +583,19 @@ But we must be careful not to catch "East is a direction" in the same net because, of course, that does set its kind. = -int PL::Map::map_intervene_in_assertion(parse_node *px, parse_node *py) { +int Map::intervene_in_assertion(parse_node *px, parse_node *py) { if ((Node::get_type(px) == PROPER_NOUN_NT) && (Node::get_type(py) == COMMON_NOUN_NT)) { inference_subject *left_object = Node::get_subject(px); inference_subject *right_kind = Node::get_subject(py); - if ((PL::Map::is_a_direction(left_object)) && - (PL::Map::is_a_direction(right_kind) == FALSE)) { + if ((Map::subject_is_a_direction(left_object)) && + (Map::subject_is_a_direction(right_kind) == FALSE)) { Assertions::Creator::convert_instance_to_nounphrase(py, NULL); return FALSE; } if (Annotations::read_int(px, nowhere_ANNOT)) { - Problems::Using::assertion_problem(Task::syntax_tree(), _p_(PM_NowhereDescribed), + Problems::Using::assertion_problem(Task::syntax_tree(), + _p_(PM_NowhereDescribed), "'nowhere' cannot be made specific", "and so cannot have specific properties or be of any given kind."); return TRUE; @@ -654,8 +615,8 @@ make this guess; so we begin with switching in and out. = int oneway_map_connections_only = FALSE; -void PL::Map::enter_one_way_mode(void) { oneway_map_connections_only = TRUE; } -void PL::Map::exit_one_way_mode(void) { oneway_map_connections_only = FALSE; } +void Map::enter_one_way_mode(void) { oneway_map_connections_only = TRUE; } +void Map::exit_one_way_mode(void) { oneway_map_connections_only = FALSE; } @ Note that, in order to make the conjectural reverse map direction, we need to look up the "opposite" property of the forward one. This relies on all @@ -664,14 +625,14 @@ reason for Inform's insistence that directions are always created in matched pairs. = -void PL::Map::connect(inference_subject *i_from, inference_subject *i_to, +void Map::connect(inference_subject *i_from, inference_subject *i_to, inference_subject *i_dir) { instance *go_from = InstanceSubjects::to_object_instance(i_from); instance *go_to = InstanceSubjects::to_object_instance(i_to); instance *forwards_dir = InstanceSubjects::to_object_instance(i_dir); if (Instances::of_kind(forwards_dir, K_direction) == FALSE) internal_error("unknown direction"); - instance *reverse_dir = PL::Map::get_value_of_opposite_property(forwards_dir); + instance *reverse_dir = Map::get_value_of_opposite_property(forwards_dir); if (go_from == NULL) { Problems::quote_source(1, current_sentence); Problems::quote_object(2, forwards_dir); @@ -684,12 +645,13 @@ void PL::Map::connect(inference_subject *i_from, inference_subject *i_to, return; } - PL::Map::oneway_map_connection(go_from, go_to, forwards_dir, CERTAIN_CE); + Map::oneway_map_connection(go_from, go_to, forwards_dir, CERTAIN_CE); if ((reverse_dir) && (go_to) && (oneway_map_connections_only == FALSE)) { if (Instances::of_kind(reverse_dir, K_direction) == FALSE) { Problems::quote_object(1, forwards_dir); Problems::quote_object(2, reverse_dir); - StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_OppositeNotDirection)); + StandardProblems::handmade_problem(Task::syntax_tree(), + _p_(PM_OppositeNotDirection)); Problems::issue_problem_segment( "I'm trying to make a map connection in the %1 direction, " "which means there ought to be map connection back in the " @@ -697,11 +659,11 @@ void PL::Map::connect(inference_subject *i_from, inference_subject *i_to, "which doesn't make sense since %2 isn't a direction. (Maybe " "you forgot to say that it was?)"); Problems::issue_problem_end(); - } else PL::Map::oneway_map_connection(go_to, go_from, reverse_dir, LIKELY_CE); + } else Map::oneway_map_connection(go_to, go_from, reverse_dir, LIKELY_CE); } } -void PL::Map::oneway_map_connection(instance *go_from, instance *go_to, +void Map::oneway_map_connection(instance *go_from, instance *go_to, instance *forwards_dir, int certainty_level) { binary_predicate *bp = PL::MapDirections::get_mapping_relation(forwards_dir); if (bp == NULL) internal_error("map connection in non-direction"); @@ -718,7 +680,7 @@ And here begins the fun. It's not as easy to write down the requirements for the map as might be thought. = -int PL::Map::map_complete_model(int stage) { +int Map::complete_model(int stage) { switch (stage) { case 2: @; @@ -735,7 +697,7 @@ int PL::Map::map_complete_model(int stage) { @; @; break; - case 4: PL::Map::build_exits_array(); break; + case 4: Map::build_exits_array(); break; } return FALSE; } @@ -763,12 +725,12 @@ checks that various mapping impossibilities do not occur. instance *I; LOOP_OVER_INSTANCES(I, K_object) { inference *inf; - POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), DIRECTION_INF) { + POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), direction_inf) { inference_subject *infs1; - PL::Map::get_map_references(inf, &infs1, NULL); + Map::get_map_references(inf, &infs1, NULL); instance *to = InstanceSubjects::to_object_instance(infs1); if ((Spatial::object_is_a_room(I)) && (to) && - (PL::Map::object_is_a_door(to) == FALSE) && + (Map::instance_is_a_door(to) == FALSE) && (Spatial::object_is_a_room(to) == FALSE)) StandardProblems::contradiction_problem(_p_(PM_BadMapCell), Instances::get_creating_sentence(to), @@ -776,7 +738,7 @@ checks that various mapping impossibilities do not occur. "appears to be something which can be reached via a map " "connection, but it seems to be neither a room nor a door", "and these are the only possibilities allowed by Inform."); - if ((PL::Map::object_is_a_door(I)) && + if ((Map::instance_is_a_door(I)) && (Spatial::object_is_a_room(to) == FALSE)) StandardProblems::object_problem(_p_(PM_DoorToNonRoom), I, @@ -789,15 +751,15 @@ checks that various mapping impossibilities do not occur. @ = instance *I; LOOP_OVER_INSTANCES(I, K_object) - if (PL::Map::object_is_a_door(I)) { + if (Map::instance_is_a_door(I)) { int connections_in = 0; inference *inf; parse_node *where[3]; where[0] = NULL; where[1] = NULL; where[2] = NULL; /* to placate |gcc| */ inference *front_side_inf = NULL, *back_side_inf = NULL; - POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), DIRECTION_INF) { + POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), direction_inf) { inference_subject *infs1, *infs2; - PL::Map::get_map_references(inf, &infs1, &infs2); + Map::get_map_references(inf, &infs1, &infs2); instance *to = InstanceSubjects::to_object_instance(infs1); instance *dir = InstanceSubjects::to_object_instance(infs2); if (to) { @@ -867,18 +829,19 @@ from which there's no way back.) LOOP_OVER_INSTANCES(I, K_object) if (Spatial::object_is_a_room(I)) { inference *inf; - POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), DIRECTION_INF) { + POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), direction_inf) { inference_subject *infs1; - PL::Map::get_map_references(inf, &infs1, NULL); + Map::get_map_references(inf, &infs1, NULL); instance *to = InstanceSubjects::to_object_instance(infs1); - if (PL::Map::object_is_a_door(to)) { + if (Map::instance_is_a_door(to)) { instance *exit1 = MAP_DATA(to)->map_connection_a; instance *exit2 = MAP_DATA(to)->map_connection_b; if ((I != exit1) && (exit2 == NULL)) { Problems::quote_object(1, I); Problems::quote_object(2, to); Problems::quote_object(3, exit1); - StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_RoomTwistyDoor)); + StandardProblems::handmade_problem(Task::syntax_tree(), + _p_(PM_RoomTwistyDoor)); Problems::issue_problem_segment( "%1, a room, seems to have a map connection which goes " "through %2, a door: but that doesn't seem physically " @@ -890,7 +853,8 @@ from which there's no way back.) Problems::quote_object(2, to); Problems::quote_object(3, exit1); Problems::quote_object(4, exit2); - StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_RoomMissingDoor)); + StandardProblems::handmade_problem(Task::syntax_tree(), + _p_(PM_RoomMissingDoor)); Problems::issue_problem_segment( "%1, a room, seems to have a map connection which goes " "through %2, a door: but that doesn't seem physically " @@ -905,7 +869,7 @@ from which there's no way back.) @ = instance *I; LOOP_OVER_INSTANCES(I, K_object) - if ((PL::Map::object_is_a_door(I)) && + if ((Map::instance_is_a_door(I)) && (MAP_DATA(I)->map_connection_a) && (MAP_DATA(I)->map_connection_b) && (PropertyInferences::value_of( @@ -928,7 +892,7 @@ model at run-time.) This is where we apply the kill-joy rule in question: @ = instance *I; LOOP_OVER_INSTANCES(I, K_object) - if ((PL::Map::object_is_a_door(I)) && + if ((Map::instance_is_a_door(I)) && (Spatial::progenitor(I)) && (Spatial::progenitor(I) != MAP_DATA(I)->map_connection_a) && (Spatial::progenitor(I) != MAP_DATA(I)->map_connection_b)) @@ -944,7 +908,7 @@ to them. @ = instance *I; LOOP_OVER_INSTANCES(I, K_object) - if ((PL::Map::object_is_a_door(I)) && + if ((Map::instance_is_a_door(I)) && (MAP_DATA(I)->map_connection_b == NULL) && (Spatial::progenitor(I) == NULL)) Spatial::set_progenitor(I, MAP_DATA(I)->map_connection_a, NULL); @@ -962,7 +926,7 @@ trust that there is nothing surprising here. instance *I; LOOP_OVER_INSTANCES(I, K_object) - if (PL::Map::object_is_a_door(I)) { + if (Map::instance_is_a_door(I)) { EitherOrProperties::assert( P_door, Instances::as_subject(I), TRUE, CERTAIN_CE); instance *R1 = MAP_DATA(I)->map_connection_a; @@ -981,39 +945,22 @@ trust that there is nothing surprising here. @ Here |found_in| is a two-entry list. @ = - package_request *PR = Hierarchy::package_within(INLINE_PROPERTIES_HAP, RTInstances::package(I)); - inter_name *S = Hierarchy::make_iname_in(INLINE_PROPERTY_HL, PR); - packaging_state save = Emit::named_array_begin(S, K_value); - Emit::array_iname_entry(RTInstances::iname(R1)); - Emit::array_iname_entry(RTInstances::iname(R2)); - Emit::array_end(save); - Produce::annotate_i(S, INLINE_ARRAY_IANN, 1); - PL::Map::set_found_in(I, Rvalues::from_iname(S)); + parse_node *val = RTMap::found_in_for_2_sided(I, R1, R2); + Map::set_found_in(I, val); @ Here |door_dir| is a routine looking at the current location and returning always the way to the other room -- the one we are not in. @ = - door_dir_notice *notice = CREATE(door_dir_notice); - notice->ddn_iname = Hierarchy::make_iname_in(TSD_DOOR_DIR_FN_HL, RTInstances::package(I)); - notice->door = I; - notice->R1 = R1; - notice->D1 = D1; - notice->D2 = D2; - ValueProperties::assert(P_door_dir, Instances::as_subject(I), - Rvalues::from_iname(notice->ddn_iname), CERTAIN_CE); + parse_node *val = RTMap::door_dir_for_2_sided(I, R1, D1, D2); + ValueProperties::assert(P_door_dir, Instances::as_subject(I), val, CERTAIN_CE); @ Here |door_to| is a routine looking at the current location and returning always the other room -- the one we are not in. @ = - door_to_notice *notice = CREATE(door_to_notice); - notice->dtn_iname = Hierarchy::make_iname_in(TSD_DOOR_TO_FN_HL, RTInstances::package(I)); - notice->door = I; - notice->R1 = R1; - notice->R2 = R2; - ValueProperties::assert(P_door_to, Instances::as_subject(I), - Rvalues::from_iname(notice->dtn_iname), CERTAIN_CE); + parse_node *val = RTMap::door_to_for_2_sided(I, R1, R2); + ValueProperties::assert(P_door_to, Instances::as_subject(I), val, CERTAIN_CE); @ The reversal of direction here looks peculiar, but is correct. Suppose the Drainage Room contains a one-sided door called the iron grating, and @@ -1027,151 +974,7 @@ property for the door; "other side" is an alias for |door_to|, which is why we don't need to compile |door_to| here. @ = - instance *backwards = PL::Map::get_value_of_opposite_property(D1); + instance *backwards = Map::get_value_of_opposite_property(D1); if (backwards) ValueProperties::assert(P_door_dir, Instances::as_subject(I), Rvalues::from_iname(RTInstances::emitted_iname(backwards)), CERTAIN_CE); - -@h Redeeming those notices. - -= -void PL::Map::write_door_dir_routines(void) { - door_dir_notice *notice; - LOOP_OVER(notice, door_dir_notice) { - packaging_state save = Routines::begin(notice->ddn_iname); - local_variable *loc = LocalVariables::add_internal_local_c(I"loc", "room of actor"); - inter_symbol *loc_s = LocalVariables::declare_this(loc, FALSE, 8); - Produce::inv_primitive(Emit::tree(), STORE_BIP); - Produce::down(Emit::tree()); - Produce::ref_symbol(Emit::tree(), K_value, loc_s); - Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(LOCATION_HL)); - Produce::up(Emit::tree()); - - Produce::inv_primitive(Emit::tree(), IF_BIP); - Produce::down(Emit::tree()); - Produce::inv_primitive(Emit::tree(), EQ_BIP); - Produce::down(Emit::tree()); - Produce::val_symbol(Emit::tree(), K_value, loc_s); - Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(THEDARK_HL)); - Produce::up(Emit::tree()); - Produce::code(Emit::tree()); - Produce::down(Emit::tree()); - Produce::inv_primitive(Emit::tree(), STORE_BIP); - Produce::down(Emit::tree()); - Produce::ref_symbol(Emit::tree(), K_value, loc_s); - Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(REAL_LOCATION_HL)); - Produce::up(Emit::tree()); - Produce::up(Emit::tree()); - Produce::up(Emit::tree()); - - Produce::inv_primitive(Emit::tree(), IF_BIP); - Produce::down(Emit::tree()); - Produce::inv_primitive(Emit::tree(), EQ_BIP); - Produce::down(Emit::tree()); - Produce::val_symbol(Emit::tree(), K_value, loc_s); - Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R1)); - Produce::up(Emit::tree()); - Produce::code(Emit::tree()); - Produce::down(Emit::tree()); - Produce::inv_primitive(Emit::tree(), RETURN_BIP); - Produce::down(Emit::tree()); - Produce::val_iname(Emit::tree(), K_value, - RTInstances::iname(PL::Map::get_value_of_opposite_property(notice->D1))); - Produce::up(Emit::tree()); - Produce::up(Emit::tree()); - Produce::up(Emit::tree()); - - Produce::inv_primitive(Emit::tree(), RETURN_BIP); - Produce::down(Emit::tree()); - Produce::val_iname(Emit::tree(), K_value, - RTInstances::iname(PL::Map::get_value_of_opposite_property(notice->D2))); - Produce::up(Emit::tree()); - - Routines::end(save); - } -} - -void PL::Map::write_door_to_routines(void) { - door_to_notice *notice; - LOOP_OVER(notice, door_to_notice) { - packaging_state save = Routines::begin(notice->dtn_iname); - local_variable *loc = LocalVariables::add_internal_local_c(I"loc", "room of actor"); - inter_symbol *loc_s = LocalVariables::declare_this(loc, FALSE, 8); - Produce::inv_primitive(Emit::tree(), STORE_BIP); - Produce::down(Emit::tree()); - Produce::ref_symbol(Emit::tree(), K_value, loc_s); - Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(LOCATION_HL)); - Produce::up(Emit::tree()); - - Produce::inv_primitive(Emit::tree(), IF_BIP); - Produce::down(Emit::tree()); - Produce::inv_primitive(Emit::tree(), EQ_BIP); - Produce::down(Emit::tree()); - Produce::val_symbol(Emit::tree(), K_value, loc_s); - Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(THEDARK_HL)); - Produce::up(Emit::tree()); - Produce::code(Emit::tree()); - Produce::down(Emit::tree()); - Produce::inv_primitive(Emit::tree(), STORE_BIP); - Produce::down(Emit::tree()); - Produce::ref_symbol(Emit::tree(), K_value, loc_s); - Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(REAL_LOCATION_HL)); - Produce::up(Emit::tree()); - Produce::up(Emit::tree()); - Produce::up(Emit::tree()); - - Produce::inv_primitive(Emit::tree(), IF_BIP); - Produce::down(Emit::tree()); - Produce::inv_primitive(Emit::tree(), EQ_BIP); - Produce::down(Emit::tree()); - Produce::val_symbol(Emit::tree(), K_value, loc_s); - Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R1)); - Produce::up(Emit::tree()); - Produce::code(Emit::tree()); - Produce::down(Emit::tree()); - Produce::inv_primitive(Emit::tree(), RETURN_BIP); - Produce::down(Emit::tree()); - Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R2)); - Produce::up(Emit::tree()); - Produce::up(Emit::tree()); - Produce::up(Emit::tree()); - - Produce::inv_primitive(Emit::tree(), RETURN_BIP); - Produce::down(Emit::tree()); - Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R1)); - Produce::up(Emit::tree()); - - Routines::end(save); - } -} - -@h Indexing. - -= -int PL::Map::map_add_to_World_index(OUTPUT_STREAM, instance *O) { - if ((O) && (Instances::of_kind(O, K_room))) { - PL::SpatialMap::index_room_connections(OUT, O); - } - return FALSE; -} - -int PL::Map::map_annotate_in_World_index(OUTPUT_STREAM, instance *O) { - if ((O) && (Instances::of_kind(O, K_door))) { - instance *A = NULL, *B = NULL; - PL::Map::get_door_data(O, &A, &B); - if ((A) && (B)) WRITE(" - door to "); - else WRITE(" - one-sided door to "); - instance *X = A; - if (A == Data::Objects::room_being_indexed()) X = B; - if (X == NULL) { - parse_node *S = PropertyInferences::value_of( - Instances::as_subject(O), P_other_side); - X = Rvalues::to_object_instance(S); - } - if (X == NULL) WRITE("nowhere"); - else IXInstances::index_name(OUT, X); - WRITE(""); - return TRUE; - } - return FALSE; -} diff --git a/inform7/index-module/Chapter 2/Index Physical World.w b/inform7/index-module/Chapter 2/Index Physical World.w index e9b72d080..cd8f35f61 100644 --- a/inform7/index-module/Chapter 2/Index Physical World.w +++ b/inform7/index-module/Chapter 2/Index Physical World.w @@ -66,7 +66,7 @@ void Data::Objects::page_World(OUTPUT_STREAM) { instance *I; LOOP_OVER_INSTANCES(I, K_object) if ((IXSpatial::no_detail_index(I)) - || (PL::Map::object_is_a_direction(I))) + || (Map::instance_is_a_direction(I))) IXInstances::increment_indexing_count(I); @ = diff --git a/inform7/index-module/Chapter 3/Spatial.w b/inform7/index-module/Chapter 3/Spatial.w index 6d4de55d4..a75f8ca87 100644 --- a/inform7/index-module/Chapter 3/Spatial.w +++ b/inform7/index-module/Chapter 3/Spatial.w @@ -43,12 +43,12 @@ void IXSpatial::index_object_further(OUTPUT_STREAM, instance *I, int depth, int if (SPATIAL_DATA(I)->object_tree_child) Data::Objects::index(OUT, SPATIAL_DATA(I)->object_tree_child, NULL, depth+1, details); if ((Spatial::object_is_a_room(I)) && - (PL::Map::object_is_a_door(I) == FALSE)) { + (Map::instance_is_a_door(I) == FALSE)) { instance *I2; LOOP_OVER_INSTANCES(I2, K_object) { - if ((PL::Map::object_is_a_door(I2)) && (Spatial::progenitor(I2) != I)) { + if ((Map::instance_is_a_door(I2)) && (Spatial::progenitor(I2) != I)) { instance *A = NULL, *B = NULL; - PL::Map::get_door_data(I2, &A, &B); + Map::get_door_data(I2, &A, &B); if (A == I) Data::Objects::index(OUT, I2, NULL, depth+1, details); if (B == I) Data::Objects::index(OUT, I2, NULL, depth+1, details); } diff --git a/inform7/index-module/Chapter 3/The Map.w b/inform7/index-module/Chapter 3/The Map.w new file mode 100644 index 000000000..ac79af159 --- /dev/null +++ b/inform7/index-module/Chapter 3/The Map.w @@ -0,0 +1,32 @@ +[IXMap::] The Map. + +Indexing the player's initial position. + +@ = +int IXMap::add_to_World_index(OUTPUT_STREAM, instance *O) { + if ((O) && (Instances::of_kind(O, K_room))) { + PL::SpatialMap::index_room_connections(OUT, O); + } + return FALSE; +} + +int IXMap::annotate_in_World_index(OUTPUT_STREAM, instance *O) { + if ((O) && (Instances::of_kind(O, K_door))) { + instance *A = NULL, *B = NULL; + Map::get_door_data(O, &A, &B); + if ((A) && (B)) WRITE(" - door to "); + else WRITE(" - one-sided door to "); + instance *X = A; + if (A == Data::Objects::room_being_indexed()) X = B; + if (X == NULL) { + parse_node *S = PropertyInferences::value_of( + Instances::as_subject(O), P_other_side); + X = Rvalues::to_object_instance(S); + } + if (X == NULL) WRITE("nowhere"); + else IXInstances::index_name(OUT, X); + WRITE(""); + return TRUE; + } + return FALSE; +} diff --git a/inform7/index-module/Contents.w b/inform7/index-module/Contents.w index 409d23fa6..9dd9903c1 100644 --- a/inform7/index-module/Contents.w +++ b/inform7/index-module/Contents.w @@ -31,3 +31,4 @@ Chapter 3: Indexing for Plugins The Player Backdrops Regions + The Map diff --git a/inform7/runtime-module/Chapter 4/Instances.w b/inform7/runtime-module/Chapter 4/Instances.w index fd9f4078e..4b149f112 100644 --- a/inform7/runtime-module/Chapter 4/Instances.w +++ b/inform7/runtime-module/Chapter 4/Instances.w @@ -55,9 +55,7 @@ int RTInstances::emit_all(inference_subject_family *family, int ignored) { LOOP_OVER(I, instance) if (Kinds::Behaviour::is_object(Instances::to_kind(I)) == FALSE) RTInstances::emit_one(family, Instances::as_subject(I)); - #ifdef IF_MODULE RTNaming::compile_small_names(); - #endif return TRUE; } diff --git a/inform7/runtime-module/Chapter 5/The Map.w b/inform7/runtime-module/Chapter 5/The Map.w new file mode 100644 index 000000000..90b6be949 --- /dev/null +++ b/inform7/runtime-module/Chapter 5/The Map.w @@ -0,0 +1,263 @@ +[RTMap::] The Map. + +@ + += +inter_name *RTMap::new_direction_iname(void) { + package_request *PR = Hierarchy::synoptic_package(DIRECTIONS_HAP); + return Hierarchy::make_iname_in(DIRECTION_HL, PR); +} + +@ One of the few early breaks with I6 practice was that I7 stores the +map differently at run-time compared to earlier I6 games. + += +int RTMap::compile_model_tables(void) { + @; + @; + return FALSE; +} + +@ = + inter_name *ndi = Hierarchy::find(NO_DIRECTIONS_HL); + Emit::named_numeric_constant(ndi, (inter_ti) Map::number_of_directions()); + Hierarchy::make_available(Emit::tree(), ndi); + + instance *I; + LOOP_OVER_INSTANCES(I, K_direction) + Emit::named_iname_constant(MAP_DATA(I)->direction_iname, K_object, + RTInstances::emitted_iname(I)); + +@ The |Map_Storage| array consists only of the |exits| arrays written out +one after another. It looks wasteful of memory, since it is almost always +going to be filled mostly with |0| entries (meaning: no exit that way). But +the memory needs to be there because map connections can be added dynamically +at run-time, so we can't know now how many we will need. + +@ = + instance *I; + LOOP_OVER_INSTANCES(I, K_object) + RTInstances::emitted_iname(I); + inter_name *iname = Hierarchy::find(MAP_STORAGE_HL); + packaging_state save = Emit::named_array_begin(iname, K_object); + int words_used = 0; + if (Task::wraps_existing_storyfile()) { + Emit::array_divider(I"minimal, as there are no rooms"); + Emit::array_iname_entry(NULL); + Emit::array_iname_entry(NULL); + Emit::array_iname_entry(NULL); + Emit::array_iname_entry(NULL); + words_used = 4; + } else { + Emit::array_divider(I"one row per room"); + instance *I; + LOOP_OVER_INSTANCES(I, K_object) + if (Spatial::object_is_a_room(I)) { + int N = Map::number_of_directions(); + for (int i=0; iddn_iname = + Hierarchy::make_iname_in(TSD_DOOR_DIR_FN_HL, RTInstances::package(I)); + notice->door = I; + notice->R1 = R1; + notice->D1 = D1; + notice->D2 = D2; + return Rvalues::from_iname(notice->ddn_iname); +} + +parse_node *RTMap::door_to_for_2_sided(instance *I, instance *R1, instance *R2) { + door_to_notice *notice = CREATE(door_to_notice); + notice->dtn_iname = + Hierarchy::make_iname_in(TSD_DOOR_TO_FN_HL, RTInstances::package(I)); + notice->door = I; + notice->R1 = R1; + notice->R2 = R2; + return Rvalues::from_iname(notice->dtn_iname); +} + +parse_node *RTMap::found_in_for_2_sided(instance *I, instance *R1, instance *R2) { + package_request *PR = + Hierarchy::package_within(INLINE_PROPERTIES_HAP, RTInstances::package(I)); + inter_name *S = Hierarchy::make_iname_in(INLINE_PROPERTY_HL, PR); + packaging_state save = Emit::named_array_begin(S, K_value); + Emit::array_iname_entry(RTInstances::iname(R1)); + Emit::array_iname_entry(RTInstances::iname(R2)); + Emit::array_end(save); + Produce::annotate_i(S, INLINE_ARRAY_IANN, 1); + return Rvalues::from_iname(S); +} + +@ Redeeming those notices: + += +void RTMap::write_door_dir_routines(void) { + door_dir_notice *notice; + LOOP_OVER(notice, door_dir_notice) { + packaging_state save = Routines::begin(notice->ddn_iname); + local_variable *loc = LocalVariables::add_internal_local_c(I"loc", "room of actor"); + inter_symbol *loc_s = LocalVariables::declare_this(loc, FALSE, 8); + Produce::inv_primitive(Emit::tree(), STORE_BIP); + Produce::down(Emit::tree()); + Produce::ref_symbol(Emit::tree(), K_value, loc_s); + Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(LOCATION_HL)); + Produce::up(Emit::tree()); + + Produce::inv_primitive(Emit::tree(), IF_BIP); + Produce::down(Emit::tree()); + Produce::inv_primitive(Emit::tree(), EQ_BIP); + Produce::down(Emit::tree()); + Produce::val_symbol(Emit::tree(), K_value, loc_s); + Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(THEDARK_HL)); + Produce::up(Emit::tree()); + Produce::code(Emit::tree()); + Produce::down(Emit::tree()); + Produce::inv_primitive(Emit::tree(), STORE_BIP); + Produce::down(Emit::tree()); + Produce::ref_symbol(Emit::tree(), K_value, loc_s); + Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(REAL_LOCATION_HL)); + Produce::up(Emit::tree()); + Produce::up(Emit::tree()); + Produce::up(Emit::tree()); + + Produce::inv_primitive(Emit::tree(), IF_BIP); + Produce::down(Emit::tree()); + Produce::inv_primitive(Emit::tree(), EQ_BIP); + Produce::down(Emit::tree()); + Produce::val_symbol(Emit::tree(), K_value, loc_s); + Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R1)); + Produce::up(Emit::tree()); + Produce::code(Emit::tree()); + Produce::down(Emit::tree()); + Produce::inv_primitive(Emit::tree(), RETURN_BIP); + Produce::down(Emit::tree()); + Produce::val_iname(Emit::tree(), K_value, + RTInstances::iname(Map::get_value_of_opposite_property(notice->D1))); + Produce::up(Emit::tree()); + Produce::up(Emit::tree()); + Produce::up(Emit::tree()); + + Produce::inv_primitive(Emit::tree(), RETURN_BIP); + Produce::down(Emit::tree()); + Produce::val_iname(Emit::tree(), K_value, + RTInstances::iname(Map::get_value_of_opposite_property(notice->D2))); + Produce::up(Emit::tree()); + + Routines::end(save); + } +} + +void RTMap::write_door_to_routines(void) { + door_to_notice *notice; + LOOP_OVER(notice, door_to_notice) { + packaging_state save = Routines::begin(notice->dtn_iname); + local_variable *loc = LocalVariables::add_internal_local_c(I"loc", "room of actor"); + inter_symbol *loc_s = LocalVariables::declare_this(loc, FALSE, 8); + Produce::inv_primitive(Emit::tree(), STORE_BIP); + Produce::down(Emit::tree()); + Produce::ref_symbol(Emit::tree(), K_value, loc_s); + Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(LOCATION_HL)); + Produce::up(Emit::tree()); + + Produce::inv_primitive(Emit::tree(), IF_BIP); + Produce::down(Emit::tree()); + Produce::inv_primitive(Emit::tree(), EQ_BIP); + Produce::down(Emit::tree()); + Produce::val_symbol(Emit::tree(), K_value, loc_s); + Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(THEDARK_HL)); + Produce::up(Emit::tree()); + Produce::code(Emit::tree()); + Produce::down(Emit::tree()); + Produce::inv_primitive(Emit::tree(), STORE_BIP); + Produce::down(Emit::tree()); + Produce::ref_symbol(Emit::tree(), K_value, loc_s); + Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(REAL_LOCATION_HL)); + Produce::up(Emit::tree()); + Produce::up(Emit::tree()); + Produce::up(Emit::tree()); + + Produce::inv_primitive(Emit::tree(), IF_BIP); + Produce::down(Emit::tree()); + Produce::inv_primitive(Emit::tree(), EQ_BIP); + Produce::down(Emit::tree()); + Produce::val_symbol(Emit::tree(), K_value, loc_s); + Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R1)); + Produce::up(Emit::tree()); + Produce::code(Emit::tree()); + Produce::down(Emit::tree()); + Produce::inv_primitive(Emit::tree(), RETURN_BIP); + Produce::down(Emit::tree()); + Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R2)); + Produce::up(Emit::tree()); + Produce::up(Emit::tree()); + Produce::up(Emit::tree()); + + Produce::inv_primitive(Emit::tree(), RETURN_BIP); + Produce::down(Emit::tree()); + Produce::val_iname(Emit::tree(), K_value, RTInstances::iname(notice->R1)); + Produce::up(Emit::tree()); + + Routines::end(save); + } +} + +@ |ident| is an identifier name for the direction instance. It seems redundant +here because surely if we know |I|, we know its runtime representation; but +that's not true -- we need to call this function at a time when the final +identifier names for instance have not yet been settled. + += +void RTMap::set_map_schemas(binary_predicate *bp, instance *I) { + inter_name *ident = MAP_DATA(I)->direction_iname; + bp->task_functions[TEST_ATOM_TASK] = + Calculus::Schemas::new("(MapConnection(*2,%n) == *1)", ident); + bp->task_functions[NOW_ATOM_TRUE_TASK] = + Calculus::Schemas::new("AssertMapConnection(*2,%n,*1)", ident); + bp->task_functions[NOW_ATOM_FALSE_TASK] = + Calculus::Schemas::new("AssertMapUnconnection(*2,%n,*1)", ident); +} diff --git a/inform7/runtime-module/Contents.w b/inform7/runtime-module/Contents.w index 038289604..3b4005cff 100644 --- a/inform7/runtime-module/Contents.w +++ b/inform7/runtime-module/Contents.w @@ -69,3 +69,4 @@ Chapter 5: Plugin Support The Player Backdrops Regions + The Map