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; #ifdefIF_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;
- #ifdefIF_MODULE
-PL::MapDirections::look_for_direction_creation(p);
- #endifPropertySentences::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
#ifdefIF_MODULEif ((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)) {intnp = problem_count;Assertions::make_coupling(px, py->down); A is a B
@@ -1391,10 +1391,10 @@ in this case.
#ifdefIF_MODULEif ((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.
} #ifdefIF_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.1else #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);elseif (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.
enumbackdrop_found_in_notice_CLASSenumbp_runtime_implementation_CLASSenumdefinition_CLASS
+enumdoor_dir_notice_CLASS
+enumdoor_to_notice_CLASSenumdval_written_CLASSenumi6_inclusion_matter_CLASSenuminternal_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.
enumcommand_index_entry_CLASSenumconnected_submap_CLASSenumdirection_inference_data_CLASS
-enumdoor_dir_notice_CLASS
-enumdoor_to_notice_CLASSenumEPS_map_level_CLASSenumfound_in_inference_data_CLASSenumgrammar_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) {
§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 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.
+
§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);}
-
§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);}
-
§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 I1PLUGINS_CALL(MORE_SPECIFIC_PLUG, I1, I2);}
-
§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);}
-
§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);}
-
§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);}
-
§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);}
-
§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);}
-
§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);}
-
§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);}
-
§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);}
-
§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);}
-
§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);}
-
§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);}
-
§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);}
-
§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);}
-
§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);}
-
§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);}
-
§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.
inti, pos = STREAM_EXTENT(OUT), whitespace_count=0, black_chars_written = 0;
-intN = 100;
- #ifdefIF_MODULE
-N = BIBLIOGRAPHIC_TEXT_TRUNCATION;
- #endif
+intN = 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); } }returnFALSE;
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.
§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.
+
§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".
-
§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:
§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.
defineMAX_DIRECTIONS100 the Standard Rules define only 12, so this is plenty
+defineMAX_MAPPING_RELATION_NAME_LENGTHMAX_WORDS_IN_DIRECTION*MAX_WORD_LENGTH+10
§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.
-
-
intmmp_call_counter = 0;
-voidPL::MapDirections::make_mapped_predicate(instance *I, inter_name *ident) {
+voidPL::MapDirections::make_mapped_predicate(instance *I) {wordingW = 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;}
§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.
-intPL::MapDirections::typecheck(bp_family *self, binary_predicate *bp,
+intPL::MapDirections::typecheck(bp_family *self, binary_predicate *bp,kind **kinds_of_terms, kind **kinds_required, tc_problem_kit *tck) {intt;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);returnNEVER_MATCH; }returnALWAYS_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.
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.
definescenes_datascene
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:
-voidSpatialInferences::infer_is_room(inference_subject *R, intcertitude) {
+voidSpatialInferences::infer_is_room(inference_subject *R, intcertitude) {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:
-intSpatial::object_is_a_room(instance *I) {
+intSpatial::object_is_a_room(instance *I) {if ((K_room) && (I) && (Instances::of_kind(I, K_room))) returnTRUE;returnFALSE;}
@@ -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.
-voidPL::SpatialMap::initialise_mapping_data(map_data *md) {
+voidPL::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:
intstory_dir_to_page_dir[MAX_DIRECTIONS];voidPL::SpatialMap::initialise_page_directions(void) {
-inti;
-for (i=0; i<registered_directions; i++)
+intN = Map::number_of_directions();
+for (inti=0; i<N; i++)story_dir_to_page_dir[i] = i;}
@@ -469,7 +469,7 @@ we use these hard-wired macros instead.
defineLOOP_OVER_DIRECTIONS(i)for (i=0; i<12; i++)defineLOOP_OVER_STORY_DIRECTIONS(i)
-for (i=0; i<registered_directions; i++)
+for (i=0; i<Map::number_of_directions(); i++)defineLOOP_OVER_LATTICE_DIRECTIONS(i)for (i=0; i<10; i++)defineLOOP_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)) {wordingW = Instances::get_name(R, FALSE);
-wordingOW = Instances::get_name(PL::Map::get_value_of_opposite_property(R), FALSE);
+wordingOW = 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) {wordingDW = 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);intod = MAP_DATA(opp)->direction_index;if ((S) && (PL::SpatialMap::room_exit(S, od, NULL) == NULL)) {wordingOPW = Instances::get_name(dir, FALSE);
@@ -3239,12 +3239,12 @@ can make use of the following:
§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.
+
§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.
+
§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."
+
§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?
+
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.
+
§10. Direction needs to be an abstract object, not a thing or a room, so:
+
+
+
+intMap::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.");
+returnTRUE;
+ }
+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.");
+returnTRUE;
+ }
+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.");
+returnTRUE;
+ }
+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.");
+returnTRUE;
+ }
+returnFALSE;
+}
+
§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:
+
§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:
+
+
+
+intregistered_directions = 0; next direction number to be free
+
+intMap::number_of_directions(void) {
+returnregistered_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.
+
+intMap::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))) {
+wordingIW = Instances::get_name(I, FALSE);
+Vet the direction name for acceptability17.1;
+if (<notable-map-directions>(IW)) {
+switch (<<r>>) {
+case0: I_up = I; break;
+case1: 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;
+ }
+returnFALSE;
+}
+
+
§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.");
+returnTRUE;
+ }
+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.");
+returnTRUE;
+ }
+
§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.
defineMAP_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.
-
§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?
-
§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.)
-
§12. Direction needs to be an abstract object, not a thing or a room, so:
-
-
-
-intPL::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.");
-returnTRUE;
- }
-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.");
-returnTRUE;
- }
-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.");
-returnTRUE;
- }
-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.");
-returnTRUE;
- }
-returnFALSE;
-}
-
§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:
-
-
-
-intPL::Map::is_a_direction(inference_subject *infs) {
-if (K_direction == NULL) returnFALSE; in particular, if we aren't using the IF model
-returnInferenceSubjects::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:
-
-
-
-intregistered_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.)
-
§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.)
+
+intMap::new_property_notify(property *prn) {
+if (<notable-map-properties>(prn->name)) {
+switch (<<r>>) {
+case0: P_opposite = prn; break;
+case1: 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; }returnFALSE;}
-
§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.");
-returnTRUE;
- }
-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.");
-returnTRUE;
- }
+voidMap::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);
+}
§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.
§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.
defineMAP_EXIT(X, Y) MAP_DATA(X)->exits[Y]
-voidPL::Map::build_exits_array(void) {
+voidMap::build_exits_array(void) {instance *I;intd = 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):
-
§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.
-
§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:
§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.)
-
§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:
§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.
-
§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.
-
§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.
-intPL::Map::map_act_on_special_NPs(parse_node *p) {
+intMap::act_on_special_NPs(parse_node *p) {if (<notable-map-noun-phrases>(Node::get_text(p))) {switch (<<r>>) {case0:
@@ -735,7 +683,7 @@ and there seems little point in writing this any better.
-intPL::Map::map_check_going(parse_node *from, parse_node *to,
+intMap::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) returnFALSE;
@@ -777,18 +725,19 @@ because, of course, that does set its kind.
-intPL::Map::map_intervene_in_assertion(parse_node *px, parse_node *py) {
+intMap::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);returnFALSE; }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.");returnTRUE;
@@ -809,8 +758,8 @@ make this guess; so we begin with switching in and out.
§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.
-voidPL::Map::connect(inference_subject *i_from, inference_subject *i_to,
+voidMap::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();
- } elsePL::Map::oneway_map_connection(go_to, go_from, reverse_dir, LIKELY_CE);
+ } elseMap::oneway_map_connection(go_to, go_from, reverse_dir, LIKELY_CE); }}
-voidPL::Map::oneway_map_connection(instance *go_from, instance *go_to,
+voidMap::oneway_map_connection(instance *go_from, instance *go_to,instance *forwards_dir, intcertainty_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");intx = prevailing_mood;prevailing_mood = certainty_level;
@@ -874,7 +824,7 @@ the map as might be thought.
instance *I;LOOP_OVER_INSTANCES(I, K_object)
-if (PL::Map::object_is_a_door(I)) {
+if (Map::instance_is_a_door(I)) {intconnections_in = 0;inference *inf;parse_node *where[3];where[0] = NULL; where[1] = NULL; where[2] = NULL; to placate gccinference *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:
§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.
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 = {
intdelete_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) {
structunderstanding_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) {
+
+
+
+
+
+
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) {returnI7_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_tival) {
+inter_name *Emit::named_numeric_constant(inter_name *name, inter_tival) {packaging_statesave = 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.
returnsave;}
-packaging_stateEmit::named_array_begin(inter_name *N, kind *K) {
+packaging_stateEmit::named_array_begin(inter_name *N, kind *K) {packaging_statesave = 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.
returnsave;}
-voidEmit::array_iname_entry(inter_name *iname) {
+voidEmit::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);}
-voidEmit::array_numeric_entry(inter_tiN) {
+voidEmit::array_numeric_entry(inter_tiN) {if (current_A == NULL) internal_error("entry outside of inter array");Emit::add_entry(LITERAL_IVAL, N);}
-voidEmit::array_divider(text_stream *divider_text) {
+voidEmit::array_divider(text_stream *divider_text) {if (current_A == NULL) internal_error("entry outside of inter array");inter_tiS = 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.
returnIBM;}
-voidEmit::array_end(packaging_statesave) {
+voidEmit::array_end(packaging_statesave) {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_statesave = 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.
returnname;}
-inter_name *Emit::named_numeric_constant_hex(inter_name *name, inter_tival) {
+inter_name *Emit::named_numeric_constant_hex(inter_name *name, inter_tival) {packaging_statesave = 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.
returnname;}
-inter_name *Emit::named_unchecked_constant_hex(inter_name *name, inter_tival) {
+inter_name *Emit::named_unchecked_constant_hex(inter_name *name, inter_tival) {packaging_statesave = 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.
returnname;}
-inter_name *Emit::named_numeric_constant_signed(inter_name *name, intval) {
+inter_name *Emit::named_numeric_constant_signed(inter_name *name, intval) {packaging_statesave = 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.
*/}
-voidEmit::code_comment(text_stream *text) {
+voidEmit::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.
}
-voidEmit::routine(inter_name *rname, kind *rkind, inter_package *block) {
+voidEmit::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_tiannot, text_stream *comm) {
+inter_symbol *Emit::local(kind *K, text_stream *lname, inter_tiannot, 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.
returnloc_name;}
-voidEmit::cast(kind *F, kind *T) {
+voidEmit::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));}
-voidEmit::intervention(intstage, text_stream *segment, text_stream *part, text_stream *i6, text_stream *seg) {
+voidEmit::intervention(intstage, text_stream *segment, text_stream *part, text_stream *i6, text_stream *seg) {inter_warehouse *warehouse = Inter::Tree::warehouse(Emit::tree());inter_tiID1 = 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.
§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.
+
§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:
+
§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.
+
-
+
+
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