1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-05 08:34:22 +03:00
inform7/docs/if-module/3-sm.html
2020-03-22 10:50:19 +00:00

2122 lines
235 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>3/tnt</title>
<meta name="viewport" content="width=device-width initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="../inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body>
<nav role="navigation">
<h1><a href="../webs.html">Sources</a></h1>
<ul>
<li><a href="../compiler.html"><b>compiler</b></a></li>
<li><a href="../other.html">other tools</a></li>
<li><a href="../extensions.html">extensions and kits</a></li>
<li><a href="../units.html">unit test tools</a></li>
</ul>
<h2>Compiler Webs</h2>
<ul>
<li><a href="../inbuild/index.html">inbuild</a></li>
<li><a href="../inform7/index.html">inform7</a></li>
<li><a href="../inter/index.html">inter</a></li>
</ul>
<h2>Inbuild Modules</h2>
<ul>
<li><a href="../inbuild-module/index.html">inbuild</a></li>
<li><a href="../arch-module/index.html">arch</a></li>
<li><a href="../words-module/index.html">words</a></li>
<li><a href="../syntax-module/index.html">syntax</a></li>
<li><a href="../html-module/index.html">html</a></li>
</ul>
<h2>Inform7 Modules</h2>
<ul>
<li><a href="../core-module/index.html">core</a></li>
<li><a href="../problems-module/index.html">problems</a></li>
<li><a href="../inflections-module/index.html">inflections</a></li>
<li><a href="../linguistics-module/index.html">linguistics</a></li>
<li><a href="../kinds-module/index.html">kinds</a></li>
<li><a href="../if-module/index.html">if</a></li>
<li><a href="../multimedia-module/index.html">multimedia</a></li>
<li><a href="../index-module/index.html">index</a></li>
</ul>
<h2>Inter Modules</h2>
<ul>
<li><a href="../inter-module/index.html">inter</a></li>
<li><a href="../building-module/index.html">building</a></li>
<li><a href="../codegen-module/index.html">codegen</a></li>
</ul>
<h2>Foundation</h2>
<ul>
<li><a href="../../../inweb/docs/foundation-module/index.html">foundation</a></li>
</ul>
</nav>
<main role="main">
<!--Weave of '3/sm' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">Source</a></li><li><a href="../compiler.html">Compiler Modules</a></li><li><a href="index.html">if</a></li><li><a href="index.html#3">Chapter 3: Space and Time</a></li><li><b>Spatial Model</b></li></ul><p class="purpose">A plugin which constructs the fundamental spatial model used by IF, to represent containment, support, carrying, wearing, and incorporation.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Definitions</a></li><li><a href="#SP7">&#167;7. Initialisation</a></li><li><a href="#SP10">&#167;10. Special inferences</a></li><li><a href="#SP11">&#167;11. Special kinds</a></li><li><a href="#SP17">&#167;17. Special properties</a></li><li><a href="#SP19">&#167;19. Default appearances</a></li><li><a href="#SP20">&#167;20. Composite noun-quantifiers</a></li><li><a href="#SP22">&#167;22. Nowhere</a></li><li><a href="#SP25">&#167;25. Here</a></li><li><a href="#SP28">&#167;28. Completing the model, stages I and II</a></li><li><a href="#SP34">&#167;34. Completing the model, stages III and IV</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. Definitions. </b></p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b>The "spatial model" is the aspect of the IF model world which represents
containment, support, carrying, wearing, and incorporation; say, a button
which is part of a shirt which is in a tumble-drier which is in a room
called the Laundry, where there's also a man carrying a box of washing
powder and wearing a dressing gown. That's quite a lot of concepts, but
note that it doesn't include the geographical model (directions, the map,
regions, and so on), which are formally separated from the spatial model
and are therefore managed by other plugins.
</p>
<p class="inwebparagraph">This is the largest and most complicated of the plugins. It has two basic
tasks: to infer the spatial structure from context and rather vague indications
of kinds and forms of containment; and then to compile an Inform 6
representation of the result, which is quite a messy business.
</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b>Every inference subject contains a pointer to its own unique copy of the
following structure, though it will only be relevant for instances of
"room" and "thing" &mdash; the raw materials of our model world. The
fundamental spatial data we will keep for each object is its "progenitor",
which may be <code class="display"><span class="extract">NULL</span></code>, representing the object which immediately contains,
carries, wears, supports or incorporates it.
</p>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">spatial_data</span><span class="plain"> {</span>
<span class="comment">fundamental spatial information about an object's location</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">progenitor</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">progenitor_set_at</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">part_flag</span><span class="plain">; </span> <span class="comment">is this a component part of something else?</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">here_flag</span><span class="plain">; </span> <span class="comment">was this declared simply as being "here"?</span>
<span class="comment">temporary storage needed when compiling spatial data to I6 code</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">object_tree_parent</span><span class="plain">; </span> <span class="comment">in/on/worn by/carried by tree structure</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">object_tree_child</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">object_tree_sibling</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">incorp_tree_parent</span><span class="plain">; </span> <span class="comment">part-of tree structure</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">incorp_tree_child</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">incorp_tree_sibling</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">I6_definition_depth</span><span class="plain">; </span> <span class="comment">i.e., how many arrows <code class="display"><span class="extract">-&gt;</span></code> appear in its I6 header</span>
<span class="identifier">MEMORY_MANAGEMENT</span>
<span class="plain">} </span><span class="reserved">spatial_data</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure spatial_data is private to this section.</p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. </b>Here, first, are the special kinds of inference needed to store these vague
indications of spatial structure:
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">IS_ROOM_INF</span><span class="plain"> 50 </span> <span class="comment">is O a room?</span>
<span class="definitionkeyword">define</span> <span class="constant">CONTAINS_THINGS_INF</span><span class="plain"> 51 </span> <span class="comment">does O contain things?</span>
<span class="definitionkeyword">define</span> <span class="constant">PARENTAGE_INF</span><span class="plain"> 52 </span> <span class="comment">where is O located?</span>
<span class="definitionkeyword">define</span> <span class="constant">PARENTAGE_HERE_INF</span><span class="plain"> 53 </span> <span class="comment">located vaguely as "here"?</span>
<span class="definitionkeyword">define</span> <span class="constant">PARENTAGE_NOWHERE_INF</span><span class="plain"> 54 </span> <span class="comment">located vaguely as "nowhere"?</span>
<span class="definitionkeyword">define</span> <span class="constant">PART_OF_INF</span><span class="plain"> 55 </span> <span class="comment">is O a part of another object?</span>
</pre>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. </b>The Spatial plugin also needs to know about a considerable number of special
kinds and properties:
</p>
<pre class="display">
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K_room</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K_thing</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K_container</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K_supporter</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K_person</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K_players_holdall</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">property</span><span class="plain"> *</span><span class="identifier">P_initial_appearance</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">property</span><span class="plain"> *</span><span class="identifier">P_wearable</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">property</span><span class="plain"> *</span><span class="identifier">P_fixed_in_place</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">property</span><span class="plain"> *</span><span class="identifier">P_component_parent</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">property</span><span class="plain"> *</span><span class="identifier">P_component_child</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">property</span><span class="plain"> *</span><span class="identifier">P_component_sibling</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">property</span><span class="plain"> *</span><span class="identifier">P_worn</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">property</span><span class="plain"> *</span><span class="identifier">P_mark_as_room</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">property</span><span class="plain"> *</span><span class="identifier">P_mark_as_thing</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">property</span><span class="plain"> *</span><span class="identifier">P_container</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">property</span><span class="plain"> *</span><span class="identifier">P_supporter</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">property</span><span class="plain"> *</span><span class="identifier">P_matching_key</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. </b>We will also need constants to talk about the inference subjects which
correspond to four of the special kinds &mdash; ordinarily that would be redundant,
since you can get the subject as a function of the kind, but there's a tricky
timing issue to get around (see below).
</p>
<pre class="display">
<span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">infs_room</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">infs_thing</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">infs_supporter</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">infs_person</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. Initialisation. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Spatial::start</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_NEW_BASE_KIND_NOTIFY</span><span class="plain">, </span><span class="functiontext">PL::Spatial::spatial_new_base_kind_notify</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_ACT_ON_SPECIAL_NPS</span><span class="plain">, </span><span class="functiontext">PL::Spatial::spatial_act_on_special_NPs</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_COMPLETE_MODEL</span><span class="plain">, </span><span class="functiontext">PL::Spatial::IF_complete_model</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_DEFAULT_APPEARANCE</span><span class="plain">, </span><span class="functiontext">PL::Spatial::spatial_default_appearance</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_INFERENCES_CONTRADICT</span><span class="plain">, </span><span class="functiontext">PL::Spatial::spatial_inferences_contradict</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_EXPLAIN_CONTRADICTION</span><span class="plain">, </span><span class="functiontext">PL::Spatial::spatial_explain_contradiction</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_LOG_INFERENCE_TYPE</span><span class="plain">, </span><span class="functiontext">PL::Spatial::spatial_log_inference_type</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_NAME_TO_EARLY_INFS</span><span class="plain">, </span><span class="functiontext">PL::Spatial::spatial_name_to_early_infs</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_NEW_SUBJECT_NOTIFY</span><span class="plain">, </span><span class="functiontext">PL::Spatial::spatial_new_subject_notify</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_NEW_PROPERTY_NOTIFY</span><span class="plain">, </span><span class="functiontext">PL::Spatial::spatial_new_property_notify</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_PARSE_COMPOSITE_NQS</span><span class="plain">, </span><span class="functiontext">PL::Spatial::spatial_parse_composite_NQs</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_SET_KIND_NOTIFY</span><span class="plain">, </span><span class="functiontext">PL::Spatial::spatial_set_kind_notify</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_SET_SUBKIND_NOTIFY</span><span class="plain">, </span><span class="functiontext">PL::Spatial::spatial_set_subkind_notify</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_ADD_TO_WORLD_INDEX</span><span class="plain">, </span><span class="functiontext">PL::Spatial::spatial_add_to_World_index</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_INTERVENE_IN_ASSERTION</span><span class="plain">, </span><span class="functiontext">PL::Spatial::spatial_intervene_in_assertion</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Create early inference subjects</span> <span class="cwebmacronumber">7.1</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::start appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP7_1"></a><b>&#167;7.1. </b>In talking about some of the fundamental spatial domains we potentially have
a vicious circle, because
</p>
<ul class="items"><li>(a) we need fundamental kinds like "thing" and "room" in order to
specify the domains for built-in relations like "containment",
</li><li>(b) we need built-in relations like "containment" in order to specify
the meanings of prepositional usages like "to be inside",
</li><li>(c) we need to have defined usages like "to be inside" in order to
break up sentences in the parse tree and identify their primary verbs and
noun phrases, but
</li><li>(d) we need a parse tree already in place before we can act on sentences
like "A room is a kind of object." which create the fundamental kinds.
</li></ul>
<p class="inwebparagraph">We break the deadlock at (a) by specifying the domains of the built-in
relations using inference subject structures created in advance of the
kinds they will one day infer about. These amount to promisory notes that
we will make them correspond to the actual kinds later on, at some point
after stage (d) when they exist.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Create early inference subjects</span> <span class="cwebmacronumber">7.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">infs_room</span><span class="plain"> = </span><span class="identifier">InferenceSubjects::new</span><span class="plain">(</span><span class="identifier">global_constants</span><span class="plain">,</span>
<span class="identifier">FUND_SUB</span><span class="plain">, </span><span class="identifier">NULL_GENERAL_POINTER</span><span class="plain">, </span><span class="identifier">LIKELY_CE</span><span class="plain">);</span>
<span class="identifier">infs_thing</span><span class="plain"> = </span><span class="identifier">InferenceSubjects::new</span><span class="plain">(</span><span class="identifier">global_constants</span><span class="plain">,</span>
<span class="identifier">FUND_SUB</span><span class="plain">, </span><span class="identifier">NULL_GENERAL_POINTER</span><span class="plain">, </span><span class="identifier">LIKELY_CE</span><span class="plain">);</span>
<span class="identifier">infs_supporter</span><span class="plain"> = </span><span class="identifier">InferenceSubjects::new</span><span class="plain">(</span><span class="identifier">global_constants</span><span class="plain">,</span>
<span class="identifier">FUND_SUB</span><span class="plain">, </span><span class="identifier">NULL_GENERAL_POINTER</span><span class="plain">, </span><span class="identifier">LIKELY_CE</span><span class="plain">);</span>
<span class="identifier">infs_person</span><span class="plain"> = </span><span class="identifier">InferenceSubjects::new</span><span class="plain">(</span><span class="identifier">global_constants</span><span class="plain">,</span>
<span class="identifier">FUND_SUB</span><span class="plain">, </span><span class="identifier">NULL_GENERAL_POINTER</span><span class="plain">, </span><span class="identifier">LIKELY_CE</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. </b>And this is where those IOUs are redeemed. What happens is that, ordinarily,
the machinery creating objects (and kinds) will allocate a new inference
structure for each object, but it first invites plugins to choose an existing
one instead. (The INFS structure is rewritten, but the important thing is that
pointers to it remain consistent and valid.)
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_name_to_early_infs</span><span class="plain">(</span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">inference_subject</span><span class="plain"> **</span><span class="identifier">infs</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (&lt;</span><span class="identifier">notable</span><span class="plain">-</span><span class="identifier">spatial</span><span class="plain">-</span><span class="identifier">kinds</span><span class="plain">&gt;(</span><span class="identifier">W</span><span class="plain">)) {</span>
<span class="reserved">switch</span><span class="plain"> (&lt;&lt;</span><span class="identifier">r</span><span class="plain">&gt;&gt;) {</span>
<span class="reserved">case</span><span class="plain"> 0: </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K_room</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) *</span><span class="identifier">infs</span><span class="plain"> = </span><span class="identifier">infs_room</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 1: </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K_thing</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) *</span><span class="identifier">infs</span><span class="plain"> = </span><span class="identifier">infs_thing</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="comment">container isn't an early case, surprisingly</span>
<span class="reserved">case</span><span class="plain"> 3: </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K_supporter</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) *</span><span class="identifier">infs</span><span class="plain"> = </span><span class="identifier">infs_supporter</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 4: </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K_person</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) *</span><span class="identifier">infs</span><span class="plain"> = </span><span class="identifier">infs_person</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_name_to_early_infs is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP9"></a><b>&#167;9. </b>Here we initialise the data used by Spatial for each object:
</p>
<pre class="display">
<span class="reserved">spatial_data</span><span class="plain"> *</span><span class="functiontext">PL::Spatial::new_data</span><span class="plain">(</span><span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">subj</span><span class="plain">) {</span>
<span class="reserved">spatial_data</span><span class="plain"> *</span><span class="identifier">sd</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">spatial_data</span><span class="plain">);</span>
<span class="identifier">sd</span><span class="plain">-</span><span class="element">&gt;progenitor</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span><span class="identifier">sd</span><span class="plain">-</span><span class="element">&gt;progenitor_set_at</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span><span class="identifier">sd</span><span class="plain">-</span><span class="element">&gt;part_flag</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="identifier">sd</span><span class="plain">-</span><span class="element">&gt;object_tree_parent</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span><span class="identifier">sd</span><span class="plain">-</span><span class="element">&gt;object_tree_child</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span><span class="identifier">sd</span><span class="plain">-</span><span class="element">&gt;object_tree_sibling</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">sd</span><span class="plain">-</span><span class="element">&gt;incorp_tree_child</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span><span class="identifier">sd</span><span class="plain">-</span><span class="element">&gt;incorp_tree_sibling</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span><span class="identifier">sd</span><span class="plain">-</span><span class="element">&gt;incorp_tree_parent</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">sd</span><span class="plain">-</span><span class="element">&gt;I6_definition_depth</span><span class="plain"> = 0;</span>
<span class="identifier">sd</span><span class="plain">-</span><span class="element">&gt;here_flag</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">sd</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::new_data is used in <a href="#SP12">&#167;12</a>.</p>
<p class="inwebparagraph"><a id="SP10"></a><b>&#167;10. Special inferences. </b>Four of these are quite simple inferences, but <code class="display"><span class="extract">PARENTAGE_INF</span></code> stores the
object to which a spatial relationship is being inferred; and this means that
multiple <code class="display"><span class="extract">PARENTAGE_INF</span></code>s can contradict each other.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_log_inference_type</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">it</span><span class="plain">) {</span>
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">it</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">CONTAINS_THINGS_INF</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"CONTAINS_THINGS_INF"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">IS_ROOM_INF</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"IS_ROOM_INF"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">PARENTAGE_HERE_INF</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"PARENTAGE_HERE_INF"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">PARENTAGE_NOWHERE_INF</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"PARENTAGE_NOWHERE_INF"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">PARENTAGE_INF</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"PARENTAGE_INF"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">PART_OF_INF</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"PART_OF_INF"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_inferences_contradict</span><span class="plain">(</span><span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">B</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">similarity</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">World::Inferences::get_inference_type</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">) == </span><span class="constant">PARENTAGE_INF</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">World::Inferences::get_reference_as_object</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">) !=</span>
<span class="identifier">World::Inferences::get_reference_as_object</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">)))</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_explain_contradiction</span><span class="plain">(</span><span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">B</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">similarity</span><span class="plain">,</span>
<span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">subj</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">World::Inferences::get_inference_type</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">) == </span><span class="constant">PARENTAGE_INF</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">World::Inferences::get_reference_as_object</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">) !=</span>
<span class="identifier">World::Inferences::get_reference_as_object</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">))) {</span>
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">World::Inferences::where_inferred</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">));</span>
<span class="identifier">Problems::quote_source</span><span class="plain">(2, </span><span class="identifier">World::Inferences::where_inferred</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">));</span>
<span class="identifier">Problems::quote_subject</span><span class="plain">(3, </span><span class="identifier">subj</span><span class="plain">);</span>
<span class="identifier">Problems::quote_object</span><span class="plain">(4, </span><span class="identifier">World::Inferences::get_reference_as_object</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">));</span>
<span class="identifier">Problems::quote_object</span><span class="plain">(5, </span><span class="identifier">World::Inferences::get_reference_as_object</span><span class="plain">(</span><span class="identifier">B</span><span class="plain">));</span>
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">Task::syntax_tree</span><span class="plain">(), </span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_SpatialContradiction</span><span class="plain">));</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
<span class="string">"You wrote %1, but also %2: that seems to be saying that the same "</span>
<span class="string">"object (%3) must be in two different places (%4 and %5). This "</span>
<span class="string">"looks like a contradiction. %P"</span>
<span class="string">"This sometimes happens as a result of a sentence like 'Every person "</span>
<span class="string">"carries a bag', when Inform doesn't know 'bag' as the name of any "</span>
<span class="string">"kind - so that it makes only a single thing called 'bag', and then "</span>
<span class="string">"the sentence looks as if it says everyone is carrying the same bag."</span><span class="plain">);</span>
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_log_inference_type is used in <a href="#SP7">&#167;7</a>.</p>
<p class="endnote">The function PL::Spatial::spatial_inferences_contradict is used in <a href="#SP7">&#167;7</a>.</p>
<p class="endnote">The function PL::Spatial::spatial_explain_contradiction is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP11"></a><b>&#167;11. Special kinds. </b>These are kind names to do with spatial layout which Inform provides special
support for; it recognises the Englishs name when defined by the Standard
Rules. (So there is no need to translate this to other languages.)
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">notable</span><span class="plain">-</span><span class="identifier">spatial</span><span class="plain">-</span><span class="identifier">kinds</span><span class="plain">&gt; ::=</span>
<span class="identifier">room</span><span class="plain"> |</span>
<span class="identifier">thing</span><span class="plain"> |</span>
<span class="identifier">container</span><span class="plain"> |</span>
<span class="identifier">supporter</span><span class="plain"> |</span>
<span class="identifier">person</span><span class="plain"> |</span>
<span class="identifier">player</span><span class="character">'s holdall</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP12"></a><b>&#167;12. </b></p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_new_base_kind_notify</span><span class="plain">(</span><span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">new_base</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">name</span><span class="plain">, </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">W</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (&lt;</span><span class="identifier">notable</span><span class="plain">-</span><span class="identifier">spatial</span><span class="plain">-</span><span class="identifier">kinds</span><span class="plain">&gt;(</span><span class="identifier">W</span><span class="plain">)) {</span>
<span class="reserved">switch</span><span class="plain"> (&lt;&lt;</span><span class="identifier">r</span><span class="plain">&gt;&gt;) {</span>
<span class="reserved">case</span><span class="plain"> 0: </span><span class="identifier">K_room</span><span class="plain"> = </span><span class="identifier">new_base</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 1: </span><span class="identifier">K_thing</span><span class="plain"> = </span><span class="identifier">new_base</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 2: </span><span class="identifier">K_container</span><span class="plain"> = </span><span class="identifier">new_base</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 3: </span><span class="identifier">K_supporter</span><span class="plain"> = </span><span class="identifier">new_base</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 4: </span><span class="identifier">K_person</span><span class="plain"> = </span><span class="identifier">new_base</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 5: </span><span class="identifier">K_players_holdall</span><span class="plain"> = </span><span class="identifier">new_base</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_new_subject_notify</span><span class="plain">(</span><span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">subj</span><span class="plain">) {</span>
<span class="identifier">CREATE_PF_DATA</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">subj</span><span class="plain">, </span><span class="functiontext">PL::Spatial::new_data</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_new_base_kind_notify is used in <a href="#SP7">&#167;7</a>.</p>
<p class="endnote">The function PL::Spatial::spatial_new_subject_notify is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP13"></a><b>&#167;13. </b>When the rest of Inform makes something a room, for instance in response to
an explicit sentence like "The Hall of Mirrors is a room.", we take notice;
if it turns out to be news, we infer <code class="display"><span class="extract">IS_ROOM_INF</span></code> with certainty.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_set_kind_notify</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">k</span><span class="plain">) {</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">kw</span><span class="plain"> = </span><span class="identifier">Instances::to_kind</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((!(</span><span class="identifier">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">kw</span><span class="plain">, </span><span class="identifier">K_room</span><span class="plain">))) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">k</span><span class="plain">, </span><span class="identifier">K_room</span><span class="plain">)))</span>
<span class="identifier">World::Inferences::draw</span><span class="plain">(</span><span class="constant">IS_ROOM_INF</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="identifier">CERTAIN_CE</span><span class="plain">,</span>
<span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_set_kind_notify is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP14"></a><b>&#167;14. </b>Nothing in the core Inform language prevents room from being made a kind
of vehicle, and so on, but this would cause mayhem in the model world. So:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_set_subkind_notify</span><span class="plain">(</span><span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">sub</span><span class="plain">, </span><span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">super</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">sub</span><span class="plain"> == </span><span class="identifier">K_thing</span><span class="plain">) &amp;&amp; (</span><span class="identifier">super</span><span class="plain"> != </span><span class="identifier">K_object</span><span class="plain">)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">problem_count</span><span class="plain"> == 0)</span>
<span class="identifier">Problems::Issue::sentence_problem</span><span class="plain">(</span><span class="identifier">Task::syntax_tree</span><span class="plain">(), </span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_ThingAdrift</span><span class="plain">),</span>
<span class="string">"'thing' is not allowed to be a kind of anything (other than "</span>
<span class="string">"'object')"</span><span class="plain">,</span>
<span class="string">"because it's too fundamental to the way Inform uses rooms "</span>
<span class="string">"and things to model the physical world."</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">sub</span><span class="plain"> == </span><span class="identifier">K_room</span><span class="plain">) &amp;&amp; (</span><span class="identifier">super</span><span class="plain"> != </span><span class="identifier">K_object</span><span class="plain">)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">problem_count</span><span class="plain"> == 0)</span>
<span class="identifier">Problems::Issue::sentence_problem</span><span class="plain">(</span><span class="identifier">Task::syntax_tree</span><span class="plain">(), </span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_RoomAdrift</span><span class="plain">),</span>
<span class="string">"'room' is not allowed to be a kind of anything (other than "</span>
<span class="string">"'object')"</span><span class="plain">,</span>
<span class="string">"because it's too fundamental to the way Inform uses rooms "</span>
<span class="string">"and things to model the physical world."</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (((</span><span class="identifier">sub</span><span class="plain"> == </span><span class="identifier">K_container</span><span class="plain">) &amp;&amp; (</span><span class="identifier">super</span><span class="plain"> == </span><span class="identifier">K_supporter</span><span class="plain">)) ||</span>
<span class="plain">((</span><span class="identifier">sub</span><span class="plain"> == </span><span class="identifier">K_supporter</span><span class="plain">) &amp;&amp; (</span><span class="identifier">super</span><span class="plain"> == </span><span class="identifier">K_container</span><span class="plain">))) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">problem_count</span><span class="plain"> == 0)</span>
<span class="identifier">Problems::Issue::sentence_problem</span><span class="plain">(</span><span class="identifier">Task::syntax_tree</span><span class="plain">(), </span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_ContainerAdrift</span><span class="plain">),</span>
<span class="string">"'container' and 'supporter' are not allowed to be kinds "</span>
<span class="string">"of each other"</span><span class="plain">,</span>
<span class="string">"because they're too fundamental to the way Inform models the "</span>
<span class="string">"physical world. Both are kinds of 'thing', but they are "</span>
<span class="string">"different, and no object is allowed to belong to both at once."</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_set_subkind_notify is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP15"></a><b>&#167;15. </b>This tests whether an object is an instance of "room":
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::object_is_a_room</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">Plugins::Manage::plugged_in</span><span class="plain">(</span><span class="identifier">spatial_plugin</span><span class="plain">)) &amp;&amp; (</span><span class="identifier">K_room</span><span class="plain">) &amp;&amp; (</span><span class="identifier">I</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Instances::of_kind</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">K_room</span><span class="plain">)))</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::object_is_a_room is used in <a href="#SP32_3_2">&#167;32.3.2</a>, <a href="#SP32_3_3">&#167;32.3.3</a>, <a href="#SP33">&#167;33</a>, <a href="#SP41">&#167;41</a>, <a href="#SP44">&#167;44</a>, 3/tnt (<a href="3-tnt.html#SP11_1">&#167;11.1</a>), 3/tp (<a href="3-tp.html#SP12_1">&#167;12.1</a>, <a href="3-tp.html#SP12_3">&#167;12.3</a>), 3/rgn (<a href="3-rgn.html#SP18">&#167;18</a>), 3/tm (<a href="3-tm.html#SP23_2">&#167;23.2</a>, <a href="3-tm.html#SP37_1">&#167;37.1</a>, <a href="3-tm.html#SP37_2">&#167;37.2</a>, <a href="3-tm.html#SP37_4">&#167;37.4</a>), 3/sm2 (<a href="3-sm2.html#SP6">&#167;6</a>, <a href="3-sm2.html#SP8_16">&#167;8.16</a>), 3/em (<a href="3-em.html#SP11">&#167;11</a>, <a href="3-em.html#SP22_2">&#167;22.2</a>, <a href="3-em.html#SP22_4_1">&#167;22.4.1</a>, <a href="3-em.html#SP25_6">&#167;25.6</a>).</p>
<p class="inwebparagraph"><a id="SP16"></a><b>&#167;16. </b>This is where we give Inform the numbers it needs to write the "a world
with 5 rooms and 27 things"-style text in a successful report on its run.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Spatial::get_world_size</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> *</span><span class="identifier">rooms</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> *</span><span class="identifier">things</span><span class="plain">) {</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">;</span>
<span class="plain">*</span><span class="identifier">rooms</span><span class="plain"> = 0; *</span><span class="identifier">things</span><span class="plain"> = 0;</span>
<span class="identifier">LOOP_OVER_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">K_room</span><span class="plain">) (*</span><span class="identifier">rooms</span><span class="plain">)++;</span>
<span class="identifier">LOOP_OVER_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">K_thing</span><span class="plain">) (*</span><span class="identifier">things</span><span class="plain">)++;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::get_world_size appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP17"></a><b>&#167;17. Special properties. </b>These are property names to do with spatial layout 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.)
</p>
<p class="inwebparagraph">"Matching key" has to appear in here because it both has a traditional I6
name and is used as relation storage. If we didn't care about it being
called <code class="display"><span class="extract">with_key</span></code> in the I6 source code, we wouldn't need to do anything
special with it at all.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">notable</span><span class="plain">-</span><span class="identifier">spatial</span><span class="plain">-</span><span class="identifier">properties</span><span class="plain">&gt; ::=</span>
<span class="identifier">initial</span><span class="plain"> </span><span class="identifier">appearance</span><span class="plain"> |</span>
<span class="identifier">wearable</span><span class="plain"> |</span>
<span class="identifier">fixed</span><span class="plain"> </span><span class="identifier">in</span><span class="plain"> </span><span class="identifier">place</span><span class="plain"> |</span>
<span class="identifier">matching</span><span class="plain"> </span><span class="identifier">key</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP18"></a><b>&#167;18. </b></p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_new_property_notify</span><span class="plain">(</span><span class="identifier">property</span><span class="plain"> *</span><span class="identifier">prn</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (&lt;</span><span class="identifier">notable</span><span class="plain">-</span><span class="identifier">spatial</span><span class="plain">-</span><span class="identifier">properties</span><span class="plain">&gt;(</span><span class="identifier">prn</span><span class="plain">-</span><span class="element">&gt;name</span><span class="plain">)) {</span>
<span class="reserved">switch</span><span class="plain"> (&lt;&lt;</span><span class="identifier">r</span><span class="plain">&gt;&gt;) {</span>
<span class="reserved">case</span><span class="plain"> 0: </span><span class="identifier">P_initial_appearance</span><span class="plain"> = </span><span class="identifier">prn</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 1: </span><span class="identifier">P_wearable</span><span class="plain"> = </span><span class="identifier">prn</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 2: </span><span class="identifier">P_fixed_in_place</span><span class="plain"> = </span><span class="identifier">prn</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 3: </span><span class="identifier">P_matching_key</span><span class="plain"> = </span><span class="identifier">prn</span><span class="plain">;</span>
<span class="identifier">Properties::set_translation</span><span class="plain">(</span><span class="identifier">P_matching_key</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"with_key"</span><span class="plain">);</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_new_property_notify is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP19"></a><b>&#167;19. Default appearances. </b>Spatial gets to decide here what raw text following a new object will be
taken to mean: for scenery it will be the "description" (i.e., the text
produced on examining), for any other thing it will be the "initial
appearance".
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_default_appearance</span><span class="plain">(</span><span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">infs</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">txt</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">InferenceSubjects::is_within</span><span class="plain">(</span><span class="identifier">infs</span><span class="plain">, </span><span class="identifier">Kinds::Knowledge::as_subject</span><span class="plain">(</span><span class="identifier">K_object</span><span class="plain">))) {</span>
<span class="identifier">property</span><span class="plain"> *</span><span class="identifier">set_prn</span><span class="plain"> = </span><span class="identifier">P_description</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">InferenceSubjects::is_within</span><span class="plain">(</span><span class="identifier">infs</span><span class="plain">, </span><span class="identifier">Kinds::Knowledge::as_subject</span><span class="plain">(</span><span class="identifier">K_thing</span><span class="plain">))) {</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain"> = </span><span class="identifier">InferenceSubjects::as_object_instance</span><span class="plain">(</span><span class="identifier">infs</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">I</span><span class="plain">) &amp;&amp; (</span><span class="functiontext">PL::Backdrops::object_is_scenery</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">))) {</span>
<span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">inf</span><span class="plain">;</span>
<span class="identifier">KNOWLEDGE_LOOP</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">, </span><span class="identifier">infs</span><span class="plain">, </span><span class="identifier">PROPERTY_INF</span><span class="plain">) {</span>
<span class="identifier">property</span><span class="plain"> *</span><span class="identifier">prn</span><span class="plain"> = </span><span class="identifier">World::Inferences::get_property</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (((</span><span class="identifier">prn</span><span class="plain">) &amp;&amp; (</span><span class="identifier">World::Inferences::get_certainty</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">) &gt; 0)) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">prn</span><span class="plain"> == </span><span class="identifier">P_description</span><span class="plain">)) {</span>
&lt;<span class="cwebmacro">Produce a problem for doubly described scenery</span> <span class="cwebmacronumber">19.1</span>&gt;<span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">set_prn</span><span class="plain"> = </span><span class="identifier">P_initial_appearance</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">Properties::Valued::assert</span><span class="plain">(</span><span class="identifier">set_prn</span><span class="plain">, </span><span class="identifier">infs</span><span class="plain">, </span><span class="identifier">txt</span><span class="plain">, </span><span class="identifier">CERTAIN_CE</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_default_appearance is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP19_1"></a><b>&#167;19.1. </b>A lone string as a sentence is a description for a room, but an initial
description for an object. Only now can we know which, since we have only
just decided whether <code class="display"><span class="extract">I</span></code> is a room or not. We therefore draw the necessary
inference.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Produce a problem for doubly described scenery</span> <span class="cwebmacronumber">19.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Problems::Issue::object_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_SceneryDoublyDescribed</span><span class="plain">),</span>
<span class="identifier">I</span><span class="plain">,</span>
<span class="string">"is scenery, which means that it cannot sensibly have any 'initial "</span>
<span class="string">"appearance' property - being scenery, it isn't announced when the "</span>
<span class="string">"player first sees it. That means the quoted text about it has to "</span>
<span class="string">"be read as its 'description' instead, seen when the player examines "</span>
<span class="string">"it. But the source text writes out its description, too"</span><span class="plain">,</span>
<span class="string">"which means we have a subtle little contradiction here."</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP19">&#167;19</a>.</p>
<p class="inwebparagraph"><a id="SP20"></a><b>&#167;20. Composite noun-quantifiers. </b>"Nothing" is conspicuously absent from the possibilities below. It gets
special treatment elsewhere since it can also double as a value (the "not
an object" pseudo-value).
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">spatial</span><span class="plain">-</span><span class="identifier">specifying</span><span class="plain">-</span><span class="identifier">nouns</span><span class="plain">&gt; ::=</span>
<span class="identifier">_something</span><span class="plain">/</span><span class="identifier">anything</span><span class="plain"> *** | ==&gt; 0; &lt;&lt;</span><span class="identifier">kind</span><span class="plain">:</span><span class="identifier">k</span><span class="plain">&gt;&gt; = </span><span class="identifier">K_thing</span>
<span class="identifier">_somewhere</span><span class="plain">/</span><span class="identifier">anywhere</span><span class="plain"> *** | ==&gt; 0; &lt;&lt;</span><span class="identifier">kind</span><span class="plain">:</span><span class="identifier">k</span><span class="plain">&gt;&gt; = </span><span class="identifier">K_room</span>
<span class="identifier">_someone</span><span class="plain">/</span><span class="identifier">anyone</span><span class="plain">/</span><span class="identifier">somebody</span><span class="plain">/</span><span class="identifier">anybody</span><span class="plain"> *** | ==&gt; 0; &lt;&lt;</span><span class="identifier">kind</span><span class="plain">:</span><span class="identifier">k</span><span class="plain">&gt;&gt; = </span><span class="identifier">K_person</span>
<span class="identifier">_everything</span><span class="plain"> *** | ==&gt; 0; &lt;&lt;</span><span class="identifier">kind</span><span class="plain">:</span><span class="identifier">k</span><span class="plain">&gt;&gt; = </span><span class="identifier">K_thing</span><span class="plain">; &lt;&lt;</span><span class="identifier">quantifier</span><span class="plain">:</span><span class="identifier">q</span><span class="plain">&gt;&gt; = </span><span class="identifier">for_all_quantifier</span>
<span class="identifier">_everywhere</span><span class="plain"> *** | ==&gt; 0; &lt;&lt;</span><span class="identifier">kind</span><span class="plain">:</span><span class="identifier">k</span><span class="plain">&gt;&gt; = </span><span class="identifier">K_room</span><span class="plain">; &lt;&lt;</span><span class="identifier">quantifier</span><span class="plain">:</span><span class="identifier">q</span><span class="plain">&gt;&gt; = </span><span class="identifier">for_all_quantifier</span>
<span class="identifier">_everyone</span><span class="plain">/</span><span class="identifier">everybody</span><span class="plain"> *** | ==&gt; 0; &lt;&lt;</span><span class="identifier">kind</span><span class="plain">:</span><span class="identifier">k</span><span class="plain">&gt;&gt; = </span><span class="identifier">K_person</span><span class="plain">; &lt;&lt;</span><span class="identifier">quantifier</span><span class="plain">:</span><span class="identifier">q</span><span class="plain">&gt;&gt; = </span><span class="identifier">for_all_quantifier</span>
<span class="identifier">_nowhere</span><span class="plain"> *** | ==&gt; 0; &lt;&lt;</span><span class="identifier">kind</span><span class="plain">:</span><span class="identifier">k</span><span class="plain">&gt;&gt; = </span><span class="identifier">K_room</span><span class="plain">; &lt;&lt;</span><span class="identifier">quantifier</span><span class="plain">:</span><span class="identifier">q</span><span class="plain">&gt;&gt; = </span><span class="identifier">not_exists_quantifier</span>
<span class="identifier">_nobody</span><span class="plain">/</span><span class="identifier">no</span><span class="plain">-</span><span class="identifier">one</span><span class="plain"> *** | ==&gt; 0; &lt;&lt;</span><span class="identifier">kind</span><span class="plain">:</span><span class="identifier">k</span><span class="plain">&gt;&gt; = </span><span class="identifier">K_person</span><span class="plain">; &lt;&lt;</span><span class="identifier">quantifier</span><span class="plain">:</span><span class="identifier">q</span><span class="plain">&gt;&gt; = </span><span class="identifier">not_exists_quantifier</span>
<span class="identifier">_no</span><span class="plain"> </span><span class="identifier">_one</span><span class="plain"> *** ==&gt; 0; &lt;&lt;</span><span class="identifier">kind</span><span class="plain">:</span><span class="identifier">k</span><span class="plain">&gt;&gt; = </span><span class="identifier">K_person</span><span class="plain">; &lt;&lt;</span><span class="identifier">quantifier</span><span class="plain">:</span><span class="identifier">q</span><span class="plain">&gt;&gt; = </span><span class="identifier">not_exists_quantifier</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP21"></a><b>&#167;21. </b>Words like "something" or "everywhere" combine a common noun &mdash; thing,
and implicitly room &mdash; with a determiner &mdash; one thing, all rooms. When we
detect them, we set both <code class="display"><span class="extract">quantifier_used</span></code> and <code class="display"><span class="extract">some_kind</span></code> appropriately.
None can be recognised if the basic kinds are not created yet, which we
check for by inspecting <code class="display"><span class="extract">K_thing</span></code>. (Note that the S-parser may indeed be
asked to parse "something" before this point, as when it scans the
domains of adjective definitions, but that it's okay that it produces a
null result.)
</p>
<p class="inwebparagraph">With the "some-" words, no quantifier is set because the meaning here is
the <code class="display"><span class="extract">exists_quantifier</span></code>. Since this is the default behaviour for
unquantified descriptions anyway &mdash; "a door is in the Great Hall" means
that such a door exists &mdash; we needn't set the variable.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_parse_composite_NQs</span><span class="plain">(</span><span class="identifier">wording</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">wording</span><span class="plain"> *</span><span class="identifier">DW</span><span class="plain">,</span>
<span class="identifier">quantifier</span><span class="plain"> **</span><span class="identifier">quant</span><span class="plain">, </span><span class="identifier">kind</span><span class="plain"> **</span><span class="identifier">some_kind</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K_thing</span><span class="plain">) {</span>
<span class="plain">&lt;&lt;</span><span class="identifier">quantifier</span><span class="plain">:</span><span class="identifier">q</span><span class="plain">&gt;&gt; = </span><span class="identifier">NULL</span><span class="plain">; &lt;&lt;</span><span class="identifier">kind</span><span class="plain">:</span><span class="identifier">k</span><span class="plain">&gt;&gt; = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (&lt;</span><span class="identifier">spatial</span><span class="plain">-</span><span class="identifier">specifying</span><span class="plain">-</span><span class="identifier">nouns</span><span class="plain">&gt;(*</span><span class="identifier">W</span><span class="plain">)) {</span>
<span class="plain">*</span><span class="identifier">W</span><span class="plain"> = </span><span class="identifier">Wordings::from</span><span class="plain">(*</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">GET_RW</span><span class="plain">(&lt;</span><span class="identifier">spatial</span><span class="plain">-</span><span class="identifier">specifying</span><span class="plain">-</span><span class="identifier">nouns</span><span class="plain">&gt;, 1)));</span>
<span class="plain">*</span><span class="identifier">quant</span><span class="plain"> = &lt;&lt;</span><span class="identifier">quantifier</span><span class="plain">:</span><span class="identifier">q</span><span class="plain">&gt;&gt;; *</span><span class="identifier">some_kind</span><span class="plain"> = &lt;&lt;</span><span class="identifier">kind</span><span class="plain">:</span><span class="identifier">k</span><span class="plain">&gt;&gt;;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_parse_composite_NQs is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP22"></a><b>&#167;22. Nowhere. </b>This means the same as "nothing", in a noun context, but we annotate a parse
node using this wording in order to produce better problem messages if need be.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">notable</span><span class="plain">-</span><span class="identifier">spatial</span><span class="plain">-</span><span class="identifier">noun</span><span class="plain">-</span><span class="identifier">phrases</span><span class="plain">&gt; ::=</span>
<span class="identifier">nowhere</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP23"></a><b>&#167;23. </b></p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_act_on_special_NPs</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((&lt;</span><span class="identifier">notable</span><span class="plain">-</span><span class="identifier">spatial</span><span class="plain">-</span><span class="identifier">noun</span><span class="plain">-</span><span class="identifier">phrases</span><span class="plain">&gt;(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">))) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Word::unexpectedly_upper_case</span><span class="plain">(</span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">))) == </span><span class="identifier">FALSE</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">K_room</span><span class="plain">)) {</span>
<span class="identifier">Assertions::Refiner::noun_from_value</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">Rvalues::new_nothing_object_constant</span><span class="plain">());</span>
<span class="identifier">ParseTree::annotate_int</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">nowhere_ANNOT</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_act_on_special_NPs is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP24"></a><b>&#167;24. </b>Now in fact this often does get picked up:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_intervene_in_assertion</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">px</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">py</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::int_annotation</span><span class="plain">(</span><span class="identifier">py</span><span class="plain">, </span><span class="identifier">nowhere_ANNOT</span><span class="plain">)) {</span>
<span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">left_subject</span><span class="plain"> = </span><span class="identifier">ParseTree::get_subject</span><span class="plain">(</span><span class="identifier">px</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">left_subject</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">InferenceSubjects::domain</span><span class="plain">(</span><span class="identifier">left_subject</span><span class="plain">))</span>
<span class="identifier">Problems::Issue::subject_problem_at_sentence</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_KindNowhere</span><span class="plain">),</span>
<span class="identifier">left_subject</span><span class="plain">,</span>
<span class="string">"seems to be said to be 'nowhere' in some way"</span><span class="plain">,</span>
<span class="string">"which doesn't make sense. An individual thing can be 'nowhere', "</span>
<span class="string">"but here we're talking about a whole kind, and it's not allowed "</span>
<span class="string">"to talk about general locations of a whole kind of things at once."</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">Calculus::Propositions::Assert::assert_true_about</span><span class="plain">(</span>
<span class="identifier">Calculus::Propositions::Abstract::to_put_nowhere</span><span class="plain">(), </span><span class="identifier">left_subject</span><span class="plain">, </span><span class="identifier">prevailing_mood</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_intervene_in_assertion is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP25"></a><b>&#167;25. Here. </b>A sentence like "The sonic screwdriver is here." is not copular, but instead
expresses a relationship &mdash; "here" is not a value but a relation to an
unstated object. That object is the room we're currently talking about, which
sounds easy to work out, but isn't: we don't yet know which of the objects
being talked about will eventually turn out to be rooms. As a result, "here"
needs delicate handling, and its own inference type.
</p>
<p class="inwebparagraph">The fact that rooms cannot be "here" is useful, because it means Inform can
with certainty read
</p>
<blockquote>
<p>The washing machine is here. The shirt is in the machine.</p>
</blockquote>
<p class="inwebparagraph">as creating a container called "washing machine", not a room.
</p>
<p class="inwebparagraph"><a id="SP26"></a><b>&#167;26. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Spatial::infer_presence_here</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">infs</span><span class="plain"> = </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">);</span>
<span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">inf</span><span class="plain">;</span>
<span class="identifier">POSITIVE_KNOWLEDGE_LOOP</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">, </span><span class="identifier">infs</span><span class="plain">, </span><span class="constant">PARENTAGE_HERE_INF</span><span class="plain">) {</span>
<span class="identifier">Problems::Issue::contradiction_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_DuplicateHere</span><span class="plain">),</span>
<span class="identifier">World::Inferences::where_inferred</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">),</span>
<span class="identifier">current_sentence</span><span class="plain">,</span>
<span class="identifier">I</span><span class="plain">,</span>
<span class="string">"can only be said to be 'here' once"</span><span class="plain">,</span>
<span class="string">"in a single assertion sentence. This avoids potential confusion, "</span>
<span class="string">"since 'here' can mean different things in different sentences."</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">World::Inferences::draw</span><span class="plain">(</span><span class="constant">PARENTAGE_HERE_INF</span><span class="plain">, </span><span class="identifier">infs</span><span class="plain">, </span><span class="identifier">CERTAIN_CE</span><span class="plain">,</span>
<span class="identifier">Assertions::Traverse::get_current_subject</span><span class="plain">(), </span><span class="identifier">NULL</span><span class="plain">);</span>
<span class="identifier">World::Inferences::draw</span><span class="plain">(</span><span class="constant">IS_ROOM_INF</span><span class="plain">, </span><span class="identifier">infs</span><span class="plain">, </span><span class="identifier">IMPOSSIBLE_CE</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::infer_presence_here appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP27"></a><b>&#167;27. </b>Similarly:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Spatial::infer_presence_nowhere</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="identifier">World::Inferences::draw</span><span class="plain">(</span><span class="constant">PARENTAGE_NOWHERE_INF</span><span class="plain">,</span>
<span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="identifier">CERTAIN_CE</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">);</span>
<span class="identifier">World::Inferences::draw</span><span class="plain">(</span><span class="constant">IS_ROOM_INF</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="identifier">IMPOSSIBLE_CE</span><span class="plain">,</span>
<span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::infer_presence_nowhere appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP28"></a><b>&#167;28. Completing the model, stages I and II. </b>That's enough preliminaries; time to get on with adding a sense of space
to the model world.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::IF_complete_model</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">stage</span><span class="plain">) {</span>
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">stage</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> 1: </span><span class="functiontext">PL::Spatial::spatial_stage_I</span><span class="plain">(); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 2: </span><span class="functiontext">PL::Spatial::spatial_stage_II</span><span class="plain">(); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 3: </span><span class="functiontext">PL::Spatial::spatial_stage_III</span><span class="plain">(); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> 4: </span><span class="functiontext">PL::Spatial::spatial_stage_IV</span><span class="plain">(); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::IF_complete_model is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP29"></a><b>&#167;29. </b>Recall that as we begin stage I of model creation, all objects are, of
course, created, and they have kinds associated with them if the source
text has said explicitly what kind they have: but that is not good enough.
It often happens that the source implicitly specifies a kind, and we need
to take note. If X is in Y, then Y might be a room, or a region, or a
container, and we might need to look at other sentences &mdash; say, establishing
that Y is the destination of a map connection &mdash; to see which.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_stage_I</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">)</span>
&lt;<span class="cwebmacro">Perform kind determination for this object</span> <span class="cwebmacronumber">29.1</span>&gt;<span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_stage_I is used in <a href="#SP28">&#167;28</a>.</p>
<p class="inwebparagraph"><a id="SP29_1"></a><b>&#167;29.1. </b>Our main problem in what follows is caused by "in" being so ambiguous,
or perhaps it might be said that the real problem is that we choose to
distinguish between rooms and containers on a world-modelling level &mdash; when it
could well be argued that they are linguistically the same thing.
</p>
<p class="inwebparagraph">It means that Inform is often reading code such as:
</p>
<blockquote>
<p>The croquet ball is in the Boxed Set.</p>
</blockquote>
<p class="inwebparagraph">and not being sure whether "Boxed Set" is a container or a room.
</p>
<p class="inwebparagraph">In the following determination, we use two sources of information. One is explicit
data given by the source text or unambiguously implied in it, like so &mdash;
</p>
<blockquote>
<p>The Boxed Set is a container. The spoon is on the low table.</p>
</blockquote>
<p class="inwebparagraph">which tell us the Boxed Set is certainly a container and the table certainly
a supporter. This information about an object is the "designer choice" about
its kind.
</p>
<p class="inwebparagraph">The other source of information comes from less definite sentences using words
like "in", and from the spatial context in which the object appears. This
is the "geography choice" for its kind.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Perform kind determination for this object</span> <span class="cwebmacronumber">29.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">current_sentence</span><span class="plain"> = </span><span class="identifier">Instances::get_creating_sentence</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">);</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">designers_choice</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Determine the designer choice</span> <span class="cwebmacronumber">29.1.1</span>&gt;<span class="plain">;</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">geography_choice</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">geography_inference</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">geography_certainty</span><span class="plain"> = </span><span class="identifier">UNKNOWN_CE</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Determine the geography choice</span> <span class="cwebmacronumber">29.1.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">geography_choice</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">geography_choice</span><span class="plain">, </span><span class="identifier">designers_choice</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">))</span>
&lt;<span class="cwebmacro">Attempt to reconcile the two choices</span> <span class="cwebmacronumber">29.1.3</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">Instances::to_kind</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="identifier">K_object</span><span class="plain">))</span>
<span class="identifier">Calculus::Propositions::Abstract::assert_kind_of_object</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">K_thing</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP29">&#167;29</a>.</p>
<p class="inwebparagraph"><a id="SP29_1_1"></a><b>&#167;29.1.1. </b>By this point, any explicit information is reflected in the hierarchy of
kinds. We look out for four specialised kinds of thing, but failing that,
we simply take its broadest kind &mdash; usually "thing", "room", "direction"
or "region".
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Determine the designer choice</span> <span class="cwebmacronumber">29.1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">f</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">infs</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">infs</span><span class="plain"> = </span><span class="identifier">Kinds::Knowledge::as_subject</span><span class="plain">(</span><span class="identifier">Instances::to_kind</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">));</span>
<span class="identifier">infs</span><span class="plain">; </span><span class="identifier">infs</span><span class="plain"> = </span><span class="identifier">InferenceSubjects::narrowest_broader_subject</span><span class="plain">(</span><span class="identifier">infs</span><span class="plain">)) {</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain"> = </span><span class="identifier">InferenceSubjects::as_kind</span><span class="plain">(</span><span class="identifier">infs</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::Compare::lt</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">, </span><span class="identifier">K_object</span><span class="plain">)) {</span>
<span class="identifier">f</span><span class="plain"> = </span><span class="identifier">K</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">f</span><span class="plain">, </span><span class="identifier">K_container</span><span class="plain">)) ||</span>
<span class="plain">(</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">f</span><span class="plain">, </span><span class="identifier">K_supporter</span><span class="plain">)) ||</span>
<span class="plain">(</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">f</span><span class="plain">, </span><span class="identifier">K_door</span><span class="plain">)) ||</span>
<span class="plain">(</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">f</span><span class="plain">, </span><span class="identifier">K_person</span><span class="plain">)))</span>
<span class="identifier">designers_choice</span><span class="plain"> = </span><span class="identifier">f</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">designers_choice</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">designers_choice</span><span class="plain"> = </span><span class="identifier">f</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP29_1">&#167;29.1</a>.</p>
<p class="inwebparagraph"><a id="SP29_1_2"></a><b>&#167;29.1.2. </b>If there is any positive information that this is a room, that's the
geography choice; otherwise it's whichever of room or container is more
probably suggested by inferences.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Determine the geography choice</span> <span class="cwebmacronumber">29.1.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">inf</span><span class="plain">;</span>
<span class="identifier">KNOWLEDGE_LOOP</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="constant">CONTAINS_THINGS_INF</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">World::Inferences::get_certainty</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">) &gt; </span><span class="identifier">geography_certainty</span><span class="plain">) {</span>
<span class="identifier">geography_choice</span><span class="plain"> = </span><span class="identifier">K_container</span><span class="plain">;</span>
<span class="identifier">geography_certainty</span><span class="plain"> = </span><span class="identifier">World::Inferences::get_certainty</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">);</span>
<span class="identifier">geography_inference</span><span class="plain"> = </span><span class="identifier">inf</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">KNOWLEDGE_LOOP</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="constant">IS_ROOM_INF</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">World::Inferences::get_certainty</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">) &gt; </span><span class="identifier">UNKNOWN_CE</span><span class="plain">) ||</span>
<span class="plain">(</span><span class="identifier">World::Inferences::get_certainty</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">) &gt; </span><span class="identifier">geography_certainty</span><span class="plain">)) {</span>
<span class="identifier">geography_choice</span><span class="plain"> = </span><span class="identifier">K_room</span><span class="plain">;</span>
<span class="identifier">geography_certainty</span><span class="plain"> = </span><span class="identifier">World::Inferences::get_certainty</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">);</span>
<span class="identifier">geography_inference</span><span class="plain"> = </span><span class="identifier">inf</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP29_1">&#167;29.1</a>.</p>
<p class="inwebparagraph"><a id="SP29_1_3"></a><b>&#167;29.1.3. </b>Since the designer choice is the one currently in force, we have basically
three choices here: impose the geography choice instead; do nothing; or issue
a problem message. The case where we do nothing is if geography suggests
something is a room, when it's actually a door: this is because sentences
like "East is the Marble Portal" can suggest the "Marble Portal" is a room
when it's legitimately a door.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Attempt to reconcile the two choices</span> <span class="cwebmacronumber">29.1.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">sentence_setting_kind</span><span class="plain"> = </span><span class="identifier">Instances::get_kind_set_sentence</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">designers_choice</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) ||</span>
<span class="plain">((</span><span class="identifier">geography_certainty</span><span class="plain"> == </span><span class="identifier">CERTAIN_CE</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Kinds::Compare::le</span><span class="plain">(</span><span class="identifier">geography_choice</span><span class="plain">, </span><span class="identifier">designers_choice</span><span class="plain">))))</span>
&lt;<span class="cwebmacro">Accept the geography choice, since it only refines what we already know</span> <span class="cwebmacronumber">29.1.3.1</span>&gt;
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">geography_certainty</span><span class="plain"> == </span><span class="identifier">CERTAIN_CE</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(!((</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">designers_choice</span><span class="plain">, </span><span class="identifier">K_door</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">geography_choice</span><span class="plain">, </span><span class="identifier">K_room</span><span class="plain">)))))</span>
&lt;<span class="cwebmacro">Issue a problem message, since the choices are irreconcilable</span> <span class="cwebmacronumber">29.1.3.2</span>&gt;<span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP29_1">&#167;29.1</a>.</p>
<p class="inwebparagraph"><a id="SP29_1_3_1"></a><b>&#167;29.1.3.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Accept the geography choice, since it only refines what we already know</span> <span class="cwebmacronumber">29.1.3.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">KIND_CHANGES</span><span class="plain">, </span><span class="string">"Accepting geography choice of kind of $O as $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">,</span>
<span class="identifier">I</span><span class="plain">, </span><span class="identifier">geography_choice</span><span class="plain">);</span>
<span class="identifier">Calculus::Propositions::Abstract::assert_kind_of_object</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">geography_choice</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP29_1_3">&#167;29.1.3</a>.</p>
<p class="inwebparagraph"><a id="SP29_1_3_2"></a><b>&#167;29.1.3.2. </b><code class="display">
&lt;<span class="cwebmacrodefn">Issue a problem message, since the choices are irreconcilable</span> <span class="cwebmacronumber">29.1.3.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Choices: designer $u, geography $u.\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">designers_choice</span><span class="plain">, </span><span class="identifier">geography_choice</span><span class="plain">);</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">decider</span><span class="plain"> = </span><span class="identifier">Instances::get_creating_sentence</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">sentence_setting_kind</span><span class="plain">) </span><span class="identifier">decider</span><span class="plain"> = </span><span class="identifier">sentence_setting_kind</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">designers_choice</span><span class="plain">, </span><span class="identifier">K_person</span><span class="plain">))</span>
&lt;<span class="cwebmacro">Issue a problem message for implied containment by a person</span> <span class="cwebmacronumber">29.1.3.2.1</span>&gt;
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">designers_choice</span><span class="plain">, </span><span class="identifier">K_supporter</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">geography_choice</span><span class="plain">, </span><span class="identifier">K_container</span><span class="plain">)))</span>
&lt;<span class="cwebmacro">Issue a problem message for simultaneous containment and support</span> <span class="cwebmacronumber">29.1.3.2.2</span>&gt;
<span class="reserved">else</span>
&lt;<span class="cwebmacro">Issue a more generic problem message for irreconcilable kinds</span> <span class="cwebmacronumber">29.1.3.2.3</span>&gt;<span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP29_1_3">&#167;29.1.3</a>.</p>
<p class="inwebparagraph"><a id="SP29_1_3_2_1"></a><b>&#167;29.1.3.2.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Issue a problem message for implied containment by a person</span> <span class="cwebmacronumber">29.1.3.2.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Problems::Issue::contradiction_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_PersonContaining</span><span class="plain">),</span>
<span class="identifier">sentence_setting_kind</span><span class="plain">,</span>
<span class="identifier">World::Inferences::where_inferred</span><span class="plain">(</span><span class="identifier">geography_inference</span><span class="plain">), </span><span class="identifier">I</span><span class="plain">,</span>
<span class="string">"cannot contain or support things like something inanimate"</span><span class="plain">,</span>
<span class="string">"which is what you are implying. Instead, people must carry or wear them: "</span>
<span class="string">"so 'The briefcase is in Daphne.' is disallowed, but 'The briefcase is "</span>
<span class="string">"carried by Daphne.' is fine, or indeed 'Daphne carries the briefcase.'"</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP29_1_3_2">&#167;29.1.3.2</a>.</p>
<p class="inwebparagraph"><a id="SP29_1_3_2_2"></a><b>&#167;29.1.3.2.2. </b>A notorious problem message for a notorious limitation of the traditional
Inform spatial model:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Issue a problem message for simultaneous containment and support</span> <span class="cwebmacronumber">29.1.3.2.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Problems::Issue::contradiction_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_CantContainAndSupport</span><span class="plain">),</span>
<span class="identifier">decider</span><span class="plain">, </span><span class="identifier">World::Inferences::where_inferred</span><span class="plain">(</span><span class="identifier">geography_inference</span><span class="plain">), </span><span class="identifier">I</span><span class="plain">,</span>
<span class="string">"cannot both contain things and support things"</span><span class="plain">,</span>
<span class="string">"which is what you're implying here. If you need both, the easiest way is "</span>
<span class="string">"to make it either a supporter with a container attached or vice versa. "</span>
<span class="string">"For instance: 'A desk is here. On the desk is a newspaper. An openable "</span>
<span class="string">"container called the drawer is part of the desk. In the drawer is a "</span>
<span class="string">"stapler.'"</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP29_1_3_2">&#167;29.1.3.2</a>.</p>
<p class="inwebparagraph"><a id="SP29_1_3_2_3"></a><b>&#167;29.1.3.2.3. </b><code class="display">
&lt;<span class="cwebmacrodefn">Issue a more generic problem message for irreconcilable kinds</span> <span class="cwebmacronumber">29.1.3.2.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Problems::Issue::contradiction_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_BothRoomAndSupporter</span><span class="plain">),</span>
<span class="identifier">decider</span><span class="plain">,</span>
<span class="identifier">World::Inferences::where_inferred</span><span class="plain">(</span><span class="identifier">geography_inference</span><span class="plain">), </span><span class="identifier">I</span><span class="plain">,</span>
<span class="string">"would need to have two different and incompatible kinds to make both "</span>
<span class="string">"sentences true"</span><span class="plain">,</span>
<span class="string">"and this is a contradiction."</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP29_1_3_2">&#167;29.1.3.2</a>.</p>
<p class="inwebparagraph"><a id="SP30"></a><b>&#167;30. </b>Stage II at last. Now the kinds are all known, and it's time to work out
the spatial arrangements. Inform's spatial model assigns every instance object
a unique "progenitor", which may be <code class="display"><span class="extract">NULL</span></code>, representing the object which
immediately contains, carries, wears, supports or incorporates it.
</p>
<p class="inwebparagraph">Clearly if we know every object's progenitor, then we know the whole spatial
layout &mdash; it's all just elaboration from there. (See Stage III below.) But
since other plugins can decide on this, not just Spatial, we had better
provide access routines to read and write:
</p>
<pre class="display">
<span class="identifier">instance</span><span class="plain"> *</span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">I</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Plugins::Manage::plugged_in</span><span class="plain">(</span><span class="identifier">spatial_plugin</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;progenitor</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Spatial::set_progenitor</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">of</span><span class="plain">, </span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">to</span><span class="plain">, </span><span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">reason</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Plugins::Manage::plugged_in</span><span class="plain">(</span><span class="identifier">spatial_plugin</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"spatial plugin inactive"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">to</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"set progenitor of nothing"</span><span class="plain">);</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">of</span><span class="plain">)-</span><span class="element">&gt;progenitor</span><span class="plain"> = </span><span class="identifier">to</span><span class="plain">;</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">of</span><span class="plain">)-</span><span class="element">&gt;progenitor_set_at</span><span class="plain"> =</span>
<span class="plain">(</span><span class="identifier">reason</span><span class="plain">)?</span><span class="identifier">World::Inferences::where_inferred</span><span class="plain">(</span><span class="identifier">reason</span><span class="plain">):</span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::progenitor is used in <a href="#SP32_2">&#167;32.2</a>, <a href="#SP37">&#167;37</a>, <a href="#SP38_2">&#167;38.2</a>, <a href="#SP38_2_1">&#167;38.2.1</a>, <a href="#SP38_3">&#167;38.3</a>, <a href="#SP38_4">&#167;38.4</a>, <a href="#SP42">&#167;42</a>, <a href="#SP44">&#167;44</a>, <a href="#SP45">&#167;45</a>, 3/tp (<a href="3-tp.html#SP12_3">&#167;12.3</a>), 3/rgn (<a href="3-rgn.html#SP18">&#167;18</a>), 3/tm (<a href="3-tm.html#SP37_6">&#167;37.6</a>, <a href="3-tm.html#SP37_7">&#167;37.7</a>).</p>
<p class="endnote">The function PL::Spatial::set_progenitor is used in <a href="#SP32_3">&#167;32.3</a>, 3/tm (<a href="3-tm.html#SP37_7">&#167;37.7</a>).</p>
<p class="inwebparagraph"><a id="SP31"></a><b>&#167;31. </b>This is used for error recovery only.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Spatial::void_progenitor</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">of</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Plugins::Manage::plugged_in</span><span class="plain">(</span><span class="identifier">spatial_plugin</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"spatial plugin inactive"</span><span class="plain">);</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">of</span><span class="plain">)-</span><span class="element">&gt;progenitor</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">of</span><span class="plain">)-</span><span class="element">&gt;progenitor_set_at</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::void_progenitor is used in <a href="#SP38_2">&#167;38.2</a>.</p>
<p class="inwebparagraph"><a id="SP32"></a><b>&#167;32. </b>We need to establish what the rooms are before we worry about objects which
are "here"; rooms are never "here", so there's no circularity in that,
and we solve this problem by determining the kind of non-here objects before
the kind of here-objects.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_stage_II</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Set the here flag for all those objects whose parentage is only thus known</span> <span class="cwebmacronumber">32.1</span>&gt;<span class="plain">;</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;here_flag</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">)</span>
&lt;<span class="cwebmacro">Position this object spatially</span> <span class="cwebmacronumber">32.3</span>&gt;<span class="plain">;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;here_flag</span><span class="plain">)</span>
&lt;<span class="cwebmacro">Position this object spatially</span> <span class="cwebmacronumber">32.3</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Issue problem messages if non-physical objects are spatially enclosed</span> <span class="cwebmacronumber">32.2</span>&gt;<span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_stage_II is used in <a href="#SP28">&#167;28</a>.</p>
<p class="inwebparagraph"><a id="SP32_1"></a><b>&#167;32.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Set the here flag for all those objects whose parentage is only thus known</span> <span class="cwebmacronumber">32.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;here_flag</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">inf</span><span class="plain">;</span>
<span class="identifier">POSITIVE_KNOWLEDGE_LOOP</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="constant">PARENTAGE_HERE_INF</span><span class="plain">)</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;here_flag</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP32">&#167;32</a>.</p>
<p class="inwebparagraph"><a id="SP32_2"></a><b>&#167;32.2. </b><code class="display">
&lt;<span class="cwebmacrodefn">Issue problem messages if non-physical objects are spatially enclosed</span> <span class="cwebmacronumber">32.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Instances::of_kind</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">K_thing</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Instances::of_kind</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">K_room</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">PL::Regions::object_is_a_region</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)) {</span>
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">Instances::get_creating_sentence</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">));</span>
<span class="identifier">Problems::quote_object</span><span class="plain">(2, </span><span class="identifier">I</span><span class="plain">);</span>
<span class="identifier">Problems::quote_object</span><span class="plain">(3, </span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">));</span>
<span class="identifier">Problems::quote_kind</span><span class="plain">(4, </span><span class="identifier">Instances::to_kind</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">));</span>
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">Task::syntax_tree</span><span class="plain">(), </span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_NonThingInModel</span><span class="plain">));</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
<span class="string">"In the sentence %1, you create an object '%2' which you then seem "</span>
<span class="string">"to place in or on or as part of '%3', but the kind of '%2' is %4. "</span>
<span class="string">"Since %4 is not a kind of thing, it follows that %2 is not a thing, "</span>
<span class="string">"so it doesn't represent something physical and can't be put in spatial "</span>
<span class="string">"relationships like this. (For the same reason that you can't put "</span>
<span class="string">"'southeast', the direction, inside a kitchen cupboard.)"</span><span class="plain">);</span>
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP32">&#167;32</a>.</p>
<p class="inwebparagraph"><a id="SP32_3"></a><b>&#167;32.3. </b>At last we come to it: determining the progenitor, and part-flag, for the
object under investigation.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Position this object spatially</span> <span class="cwebmacronumber">32.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">parent_setting_inference</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Find the inference which will decide the progenitor</span> <span class="cwebmacronumber">32.3.1</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">parent_setting_inference</span><span class="plain">) {</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">whereabouts</span><span class="plain"> =</span>
<span class="identifier">World::Inferences::get_reference_as_object</span><span class="plain">(</span><span class="identifier">parent_setting_inference</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;here_flag</span><span class="plain">) </span>&lt;<span class="cwebmacro">Find the whereabouts of something here</span> <span class="cwebmacronumber">32.3.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">whereabouts</span><span class="plain">) {</span>
<span class="functiontext">PL::Spatial::set_progenitor</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">whereabouts</span><span class="plain">, </span><span class="identifier">parent_setting_inference</span><span class="plain">);</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">OBJECT_TREE</span><span class="plain">, </span><span class="string">"Progenitor of $O is $O\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">whereabouts</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
&lt;<span class="cwebmacro">Determine whether the object in question is a component part</span> <span class="cwebmacronumber">32.3.3</span>&gt;<span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP32">&#167;32</a> (twice).</p>
<p class="inwebparagraph"><a id="SP32_3_1"></a><b>&#167;32.3.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Find the inference which will decide the progenitor</span> <span class="cwebmacronumber">32.3.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">inf</span><span class="plain">;</span>
<span class="identifier">POSITIVE_KNOWLEDGE_LOOP</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="constant">PARENTAGE_NOWHERE_INF</span><span class="plain">)</span>
&lt;<span class="cwebmacro">Make this the determining inference</span> <span class="cwebmacronumber">32.3.1.1</span>&gt;<span class="plain">;</span>
<span class="identifier">POSITIVE_KNOWLEDGE_LOOP</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="constant">PARENTAGE_HERE_INF</span><span class="plain">)</span>
&lt;<span class="cwebmacro">Make this the determining inference</span> <span class="cwebmacronumber">32.3.1.1</span>&gt;<span class="plain">;</span>
<span class="identifier">POSITIVE_KNOWLEDGE_LOOP</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="constant">PARENTAGE_INF</span><span class="plain">)</span>
&lt;<span class="cwebmacro">Make this the determining inference</span> <span class="cwebmacronumber">32.3.1.1</span>&gt;<span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP32_3">&#167;32.3</a>.</p>
<p class="inwebparagraph"><a id="SP32_3_1_1"></a><b>&#167;32.3.1.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Make this the determining inference</span> <span class="cwebmacronumber">32.3.1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">parent_setting_inference</span><span class="plain">) {</span>
<span class="identifier">Problems::Issue::contradiction_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_DuplicateParentage</span><span class="plain">),</span>
<span class="identifier">World::Inferences::where_inferred</span><span class="plain">(</span><span class="identifier">parent_setting_inference</span><span class="plain">),</span>
<span class="identifier">World::Inferences::where_inferred</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">),</span>
<span class="identifier">I</span><span class="plain">,</span>
<span class="string">"can only be given its position once"</span><span class="plain">,</span>
<span class="string">"in a single assertion sentence."</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">parent_setting_inference</span><span class="plain"> = </span><span class="identifier">inf</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP32_3_1">&#167;32.3.1</a> (three times).</p>
<p class="inwebparagraph"><a id="SP32_3_2"></a><b>&#167;32.3.2. </b><code class="display">
&lt;<span class="cwebmacrodefn">Find the whereabouts of something here</span> <span class="cwebmacronumber">32.3.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">PL::Spatial::object_is_a_room</span><span class="plain">(</span><span class="identifier">whereabouts</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="identifier">whereabouts</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">whereabouts</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">here_sentence</span><span class="plain"> =</span>
<span class="identifier">World::Inferences::where_inferred</span><span class="plain">(</span><span class="identifier">parent_setting_inference</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Set the whereabouts to the last discussed room prior to this inference being drawn</span> <span class="cwebmacronumber">32.3.2.1</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">whereabouts</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
<span class="identifier">current_sentence</span><span class="plain"> = </span><span class="identifier">here_sentence</span><span class="plain">;</span>
<span class="identifier">Problems::Issue::object_problem_at_sentence</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_NoHere</span><span class="plain">),</span>
<span class="identifier">I</span><span class="plain">,</span>
<span class="string">"was described as being 'here', and there doesn't seem to be any "</span>
<span class="string">"location being talked about at this point in the source text"</span><span class="plain">,</span>
<span class="string">"so there's nowhere you can call 'here'."</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP32_3">&#167;32.3</a>.</p>
<p class="inwebparagraph"><a id="SP32_3_2_1"></a><b>&#167;32.3.2.1. </b>This runs through the source text from the beginning up to the "here"
sentence, setting <code class="display"><span class="extract">whereabouts</span></code> to any rooms it finds along the way, so that
when it finishes this will be set to the most recently mentioned.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Set the whereabouts to the last discussed room prior to this inference being drawn</span> <span class="cwebmacronumber">32.3.2.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">ParseTree::traverse_up_to_ip</span><span class="plain">(</span><span class="identifier">Task::syntax_tree</span><span class="plain">(), </span><span class="identifier">here_sentence</span><span class="plain">, </span><span class="functiontext">PL::Spatial::seek_room</span><span class="plain">, &amp;</span><span class="identifier">whereabouts</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP32_3_2">&#167;32.3.2</a>.</p>
<p class="inwebparagraph"><a id="SP32_3_3"></a><b>&#167;32.3.3. </b><code class="display">
&lt;<span class="cwebmacrodefn">Determine whether the object in question is a component part</span> <span class="cwebmacronumber">32.3.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">inf</span><span class="plain">;</span>
<span class="identifier">POSITIVE_KNOWLEDGE_LOOP</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="constant">PART_OF_INF</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">PL::Spatial::object_is_a_room</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">)) || (</span><span class="functiontext">PL::Map::object_is_a_door</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">))) {</span>
<span class="identifier">Problems::Issue::object_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_RoomOrDoorAsPart</span><span class="plain">),</span>
<span class="identifier">I</span><span class="plain">,</span>
<span class="string">"was set up as being part of something else, which doors and rooms "</span>
<span class="string">"are not allowed to be"</span><span class="plain">,</span>
<span class="string">"because they are part of the fixed map of the world - if they were "</span>
<span class="string">"parts of something else, they might move around. (Of course, it's "</span>
<span class="string">"easy to make a door look as if it's part of something to the player - "</span>
<span class="string">"describing it as part of a wall, or bulkhead, or cottage, say - "</span>
<span class="string">"and if there really is an entrance that needs to move around - say, "</span>
<span class="string">"the hatchway on a tank - it's probably best to make it an enterable "</span>
<span class="string">"container.)"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;part_flag</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP32_3">&#167;32.3</a>.</p>
<p class="inwebparagraph"><a id="SP33"></a><b>&#167;33. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Spatial::seek_room</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">sent</span><span class="plain">, </span><span class="identifier">instance</span><span class="plain"> **</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">isub</span><span class="plain"> = </span><span class="identifier">ParseTree::get_interpretation_of_subject</span><span class="plain">(</span><span class="identifier">sent</span><span class="plain">);</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">sub</span><span class="plain"> = </span><span class="identifier">InferenceSubjects::as_object_instance</span><span class="plain">(</span><span class="identifier">isub</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">PL::Spatial::object_is_a_room</span><span class="plain">(</span><span class="identifier">sub</span><span class="plain">)) *</span><span class="identifier">I</span><span class="plain"> = </span><span class="identifier">sub</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::seek_room is used in <a href="#SP32_3_2_1">&#167;32.3.2.1</a>.</p>
<p class="inwebparagraph"><a id="SP34"></a><b>&#167;34. Completing the model, stages III and IV. </b>By the beginning of Stage III, the progenitor of every object is known, and
so is whether it is a part. It's time to start work on compiling the I6
representation of all this, but unfortunately that will need to be quite a
bit more complicated. So we're going to do this in two stages, the first
of which is to construct a pair of object trees as an intermediate state.
</p>
<p class="inwebparagraph">We have a main object tree, in fact a forest (i.e., it's probably disconnected),
to represent containment, support, carrying and wearing; and a secondary tree
for incorporation only. In this source code, we'll use the language of family
trees (parent, children, siblings) rather than horticulture (branches, leaves,
grafting). Both trees must be well-founded, and must be such that each object
is the parent of all its children. But the trees aren't independent of each
other: an object is not allowed to have a parent in both trees at once.
If it has a parent in either one, then that parent is required to be its progenitor.
</p>
<p class="inwebparagraph"><a id="SP35"></a><b>&#167;35. </b>The following logs the more interesting tree:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Spatial::log_object_tree</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;object_tree_parent</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)</span>
<span class="functiontext">PL::Spatial::log_object_tree_recursively</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, 0);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Spatial::log_object_tree_recursively</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">depth</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain"> = </span><span class="identifier">depth</span><span class="plain">;</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">&gt;0) { </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">" "</span><span class="plain">); </span><span class="identifier">i</span><span class="plain">--; }</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"$O\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;object_tree_child</span><span class="plain">)</span>
<span class="functiontext">PL::Spatial::log_object_tree_recursively</span><span class="plain">(</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;object_tree_child</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">+1);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain">)</span>
<span class="functiontext">PL::Spatial::log_object_tree_recursively</span><span class="plain">(</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::log_object_tree is used in <a href="#SP38">&#167;38</a>.</p>
<p class="endnote">The function PL::Spatial::log_object_tree_recursively appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP36"></a><b>&#167;36. </b>The initial state of both trees is total disconnection. They are then produced
using only two operations, which we'll call "adoption" and "parting".
</p>
<p class="inwebparagraph">The adoption routine is the equivalent of the Inform 6 statement "move
X to Y", and moves X and its children to become the youngest child of Y.
The tree is grown entirely from its root by repeated use of this one operation.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Spatial::adopt_object</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">orphan</span><span class="plain">, </span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">foster</span><span class="plain">) {</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">OBJECT_TREE</span><span class="plain">, </span><span class="string">"Grafting $O to be child of $O\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">orphan</span><span class="plain">, </span><span class="identifier">foster</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">orphan</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"orphan is null in adoption"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">foster</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"foster is null in adoption"</span><span class="plain">);</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">former_parent</span><span class="plain"> = </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">orphan</span><span class="plain">)-</span><span class="element">&gt;object_tree_parent</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">former_parent</span><span class="plain">) </span>&lt;<span class="cwebmacro">Remove the object from the main object tree</span> <span class="cwebmacronumber">36.2</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Adopt the object into the main object tree</span> <span class="cwebmacronumber">36.3</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::adopt_object is used in <a href="#SP38_3">&#167;38.3</a>.</p>
<p class="inwebparagraph"><a id="SP36_1"></a><b>&#167;36.1. </b>"Parting" is the operation of being removed from the main tree and placed
in the incorporation tree instead, but with the same parent.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Spatial::part_object</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">orphan</span><span class="plain">) {</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">OBJECT_TREE</span><span class="plain">, </span><span class="string">"Parting $O\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">orphan</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">orphan</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"new part is null in parting"</span><span class="plain">);</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">former_parent</span><span class="plain"> = </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">orphan</span><span class="plain">)-</span><span class="element">&gt;object_tree_parent</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">former_parent</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"new part is without parent"</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Remove the object from the main object tree</span> <span class="cwebmacronumber">36.2</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Adopt the object into the incorporation tree</span> <span class="cwebmacronumber">36.1.1</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::part_object is used in <a href="#SP38_3">&#167;38.3</a>.</p>
<p class="inwebparagraph"><a id="SP36_2"></a><b>&#167;36.2. </b><code class="display">
&lt;<span class="cwebmacrodefn">Remove the object from the main object tree</span> <span class="cwebmacronumber">36.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">former_parent</span><span class="plain">)-</span><span class="element">&gt;object_tree_child</span><span class="plain"> == </span><span class="identifier">orphan</span><span class="plain">) {</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">former_parent</span><span class="plain">)-</span><span class="element">&gt;object_tree_child</span><span class="plain"> =</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">orphan</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">elder</span><span class="plain"> = </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">former_parent</span><span class="plain">)-</span><span class="element">&gt;object_tree_child</span><span class="plain">;</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">elder</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">elder</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain"> == </span><span class="identifier">orphan</span><span class="plain">)</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">elder</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain"> =</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">orphan</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain">;</span>
<span class="identifier">elder</span><span class="plain"> = </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">elder</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">orphan</span><span class="plain">)-</span><span class="element">&gt;object_tree_parent</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">orphan</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP36">&#167;36</a>, <a href="#SP36_1">&#167;36.1</a>.</p>
<p class="inwebparagraph"><a id="SP36_3"></a><b>&#167;36.3. </b><code class="display">
&lt;<span class="cwebmacrodefn">Adopt the object into the main object tree</span> <span class="cwebmacronumber">36.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">foster</span><span class="plain">)-</span><span class="element">&gt;object_tree_child</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">foster</span><span class="plain">)-</span><span class="element">&gt;object_tree_child</span><span class="plain"> = </span><span class="identifier">orphan</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">elder</span><span class="plain"> = </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">foster</span><span class="plain">)-</span><span class="element">&gt;object_tree_child</span><span class="plain">;</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">elder</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain">)</span>
<span class="identifier">elder</span><span class="plain"> = </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">elder</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain">;</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">elder</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain"> = </span><span class="identifier">orphan</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">orphan</span><span class="plain">)-</span><span class="element">&gt;object_tree_parent</span><span class="plain"> = </span><span class="identifier">foster</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP36">&#167;36</a>.</p>
<p class="inwebparagraph"><a id="SP36_1_1"></a><b>&#167;36.1.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Adopt the object into the incorporation tree</span> <span class="cwebmacronumber">36.1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">former_parent</span><span class="plain">)-</span><span class="element">&gt;incorp_tree_child</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">former_parent</span><span class="plain">)-</span><span class="element">&gt;incorp_tree_child</span><span class="plain"> = </span><span class="identifier">orphan</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">existing_part</span><span class="plain"> = </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">former_parent</span><span class="plain">)-</span><span class="element">&gt;incorp_tree_child</span><span class="plain">;</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">existing_part</span><span class="plain">)-</span><span class="element">&gt;incorp_tree_sibling</span><span class="plain">)</span>
<span class="identifier">existing_part</span><span class="plain"> = </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">existing_part</span><span class="plain">)-</span><span class="element">&gt;incorp_tree_sibling</span><span class="plain">;</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">existing_part</span><span class="plain">)-</span><span class="element">&gt;incorp_tree_sibling</span><span class="plain"> = </span><span class="identifier">orphan</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">orphan</span><span class="plain">)-</span><span class="element">&gt;incorp_tree_parent</span><span class="plain"> = </span><span class="identifier">former_parent</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP36_1">&#167;36.1</a>.</p>
<p class="inwebparagraph"><a id="SP37"></a><b>&#167;37. </b>What will we use the trees for? Well, one use is to tell other plugins
which depend on Spatial whether or not one object spatially contains another:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::encloses</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I1</span><span class="plain">, </span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I2</span><span class="plain">) {</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">I1</span><span class="plain">) {</span>
<span class="identifier">I1</span><span class="plain"> = </span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">I1</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">I1</span><span class="plain"> == </span><span class="identifier">I2</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::encloses is used in 3/rgn (<a href="3-rgn.html#SP10">&#167;10</a>).</p>
<p class="inwebparagraph"><a id="SP38"></a><b>&#167;38. </b>But the main use for the trees is, as noted above, to form a convenient
intermediate state between the mass of progenitor data and the messy Inform 6
code it turns into. Here goes:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_stage_III</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">well_founded</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Define the Rucksack Class constant</span> <span class="cwebmacronumber">38.1</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Check the well-foundedness of the hierarchy of the set of progenitors</span> <span class="cwebmacronumber">38.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">well_founded</span><span class="plain">) </span>&lt;<span class="cwebmacro">Expand the progenitor data into the two object trees</span> <span class="cwebmacronumber">38.3</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Assert the portability of any item carried or supported by a person</span> <span class="cwebmacronumber">38.4</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Assert I6-level properties to express the spatial structure</span> <span class="cwebmacronumber">38.5</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Set up the compilation sequence so that it traverses the main object tree</span> <span class="cwebmacronumber">38.6</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Log::aspect_switched_on</span><span class="plain">(</span><span class="identifier">OBJECT_TREE_DA</span><span class="plain">)) </span><span class="functiontext">PL::Spatial::log_object_tree</span><span class="plain">();</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_stage_III is used in <a href="#SP28">&#167;28</a>.</p>
<p class="inwebparagraph"><a id="SP38_1"></a><b>&#167;38.1. </b>To enable the use of player's holdalls, we must declare a constant
<code class="display"><span class="extract">RUCKSACK_CLASS</span></code> to tell some code in the template layer to use possessions
with this I6 class as the rucksack pro tem. This is all a bit of a hack, to retrofit
a degree of generality onto the original I6 library feature, and even then
it isn't really fully general: only the player has the benefit of a "player's
holdall" (hence the name), with other actors oblivious.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Define the Rucksack Class constant</span> <span class="cwebmacronumber">38.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K_players_holdall</span><span class="plain">) {</span>
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">iname</span><span class="plain"> = </span><span class="identifier">Hierarchy::find</span><span class="plain">(</span><span class="identifier">RUCKSACK_CLASS_HL</span><span class="plain">);</span>
<span class="identifier">Hierarchy::make_available</span><span class="plain">(</span><span class="identifier">Emit::tree</span><span class="plain">(), </span><span class="identifier">iname</span><span class="plain">);</span>
<span class="identifier">Emit::named_iname_constant</span><span class="plain">(</span><span class="identifier">iname</span><span class="plain">, </span><span class="identifier">K_value</span><span class="plain">, </span><span class="identifier">Kinds::RunTime::I6_classname</span><span class="plain">(</span><span class="identifier">K_players_holdall</span><span class="plain">));</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP38">&#167;38</a>.</p>
<p class="inwebparagraph"><a id="SP38_2"></a><b>&#167;38.2. </b>The following verifies, in a brute-force way, that there are no cycles in
the directed graph formed by the objects and progeniture. (We're doing this
now, rather than at Stage II above, because other plugins may also have
changed progenitors at Stage II.)
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Check the well-foundedness of the hierarchy of the set of progenitors</span> <span class="cwebmacronumber">38.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">max_loop</span><span class="plain"> = </span><span class="identifier">NUMBER_CREATED</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain">) + 1;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">k</span><span class="plain">;</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I2</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">I2</span><span class="plain"> = </span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="identifier">k</span><span class="plain">=0; (</span><span class="identifier">I2</span><span class="plain">) &amp;&amp; (</span><span class="identifier">k</span><span class="plain">&lt;</span><span class="identifier">max_loop</span><span class="plain">);</span>
<span class="identifier">I2</span><span class="plain"> = </span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">I2</span><span class="plain">), </span><span class="identifier">k</span><span class="plain">++) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">I2</span><span class="plain"> == </span><span class="identifier">I</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Diagnose the ill-foundedness with a problem message</span> <span class="cwebmacronumber">38.2.1</span>&gt;<span class="plain">;</span>
<span class="functiontext">PL::Spatial::void_progenitor</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">); </span> <span class="comment">thus cutting the cycle</span>
<span class="identifier">well_founded</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP38">&#167;38</a>.</p>
<p class="inwebparagraph"><a id="SP38_2_1"></a><b>&#167;38.2.1. </b>The cutest of all the object problem messages, really:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Diagnose the ill-foundedness with a problem message</span> <span class="cwebmacronumber">38.2.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Problems::quote_object</span><span class="plain">(1, </span><span class="identifier">I</span><span class="plain">);</span>
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">Task::syntax_tree</span><span class="plain">(), </span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_IllFounded</span><span class="plain">));</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span><span class="string">"The %1 seems to be containing itself: "</span><span class="plain">);</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I3</span><span class="plain"> = </span><span class="identifier">I</span><span class="plain">;</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">TRUE</span><span class="plain">) {</span>
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">IW</span><span class="plain"> = </span><span class="identifier">Instances::get_name</span><span class="plain">(</span><span class="identifier">I3</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">);</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">creator</span><span class="plain"> = </span><span class="identifier">NounPhrases::new_raw</span><span class="plain">(</span><span class="identifier">IW</span><span class="plain">);</span>
<span class="identifier">Problems::quote_object</span><span class="plain">(2, </span><span class="identifier">I3</span><span class="plain">);</span>
<span class="identifier">Problems::quote_source</span><span class="plain">(3, </span><span class="identifier">creator</span><span class="plain">);</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span><span class="string">"%2 (created by %3) "</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I3</span><span class="plain">)-</span><span class="element">&gt;part_flag</span><span class="plain">) </span><span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span><span class="string">"part of "</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span><span class="string">"in "</span><span class="plain">);</span>
<span class="identifier">I3</span><span class="plain"> = </span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">I3</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">I3</span><span class="plain"> == </span><span class="identifier">I</span><span class="plain">) </span><span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span><span class="string">"%1... and so on. This is forbidden."</span><span class="plain">);</span>
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP38_2">&#167;38.2</a>.</p>
<p class="inwebparagraph"><a id="SP38_3"></a><b>&#167;38.3. </b>Intermediate states are always suspect in program design, and we might
ask what's wrong with simply making the trees as we go along, rather than
storing all of those progenitors and then converting them into the trees.
We don't do that because (for reasons to do with "here" and with how work
is shared among the plugins) the progenitors are determined in an undefined
order; if we made the object tree as we went along, the spatial model would
be perfectly correct, but siblings &mdash; say, the three things on the grass in
the Croquet Lawn &mdash; would be compiled in the I6 code in some undefined
order. This order matters because it affects the text produced by typical
room descriptions: "You can also see a box, a ball and a peg here." might
become "You can also see a ball, a box and a peg here."
</p>
<p class="inwebparagraph">Inform therefore needs a definite rule of ordering, and this rule is that
siblings appear in their order of creation in the I7 source text, with the
first created being the eldest child. Looping over the objects to add them
to the trees in creation order achieves this nicely:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Expand the progenitor data into the two object trees</span> <span class="cwebmacronumber">38.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">))</span>
<span class="functiontext">PL::Spatial::adopt_object</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, </span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">));</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;part_flag</span><span class="plain">)</span>
<span class="functiontext">PL::Spatial::part_object</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP38">&#167;38</a>.</p>
<p class="inwebparagraph"><a id="SP38_4"></a><b>&#167;38.4. </b>As a brief aside: if something is carried by a living person, we can
reasonably assume it's portable. (This is needed in particular to ensure that
supporters which are initially carried don't pick up "fixed in place" in
the absence of other information.)
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Assert the portability of any item carried or supported by a person</span> <span class="cwebmacronumber">38.4</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">portable</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">J</span><span class="plain"> = </span><span class="identifier">I</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;part_flag</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">J</span><span class="plain"> = </span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">); </span><span class="identifier">J</span><span class="plain">; </span><span class="identifier">J</span><span class="plain"> = </span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">J</span><span class="plain">)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">J</span><span class="plain">)-</span><span class="element">&gt;part_flag</span><span class="plain">) </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Instances::of_kind</span><span class="plain">(</span><span class="identifier">J</span><span class="plain">, </span><span class="identifier">K_person</span><span class="plain">)) {</span>
<span class="identifier">portable</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">portable</span><span class="plain">)</span>
<span class="identifier">Properties::EitherOr::assert</span><span class="plain">(</span>
<span class="identifier">P_fixed_in_place</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="identifier">FALSE</span><span class="plain">, </span><span class="identifier">CERTAIN_CE</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP38">&#167;38</a>.</p>
<p class="inwebparagraph"><a id="SP38_5"></a><b>&#167;38.5. </b><code class="display">
&lt;<span class="cwebmacrodefn">Assert I6-level properties to express the spatial structure</span> <span class="cwebmacronumber">38.5</span>&gt; =
</code></p>
<pre class="displaydefn">
&lt;<span class="cwebmacro">Assert an explicit default description value for the room kind</span> <span class="cwebmacronumber">38.5.1</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Assert room and thing indicator properties</span> <span class="cwebmacronumber">38.5.2</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Assert container and supporter indicator properties</span> <span class="cwebmacronumber">38.5.3</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Assert incorporation tree properties</span> <span class="cwebmacronumber">38.5.4</span>&gt;<span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP38">&#167;38</a>.</p>
<p class="inwebparagraph"><a id="SP38_5_1"></a><b>&#167;38.5.1. </b>We need to make sure that every room does have an I6 <code class="display"><span class="extract">description</span></code> value
which can be written to (i.e., we need to avoid accidental use of the Z-machine's
readable-only default properties feature); hence the following, which ensures
that any room with no explicit description will inherit <code class="display"><span class="extract">EMPTY_TEXT_VALUE</span></code>
as a value for <code class="display"><span class="extract">description</span></code> from the room class.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Assert an explicit default description value for the room kind</span> <span class="cwebmacronumber">38.5.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K_room</span><span class="plain">) {</span>
<span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">inf</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">desc_seen</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="identifier">POSITIVE_KNOWLEDGE_LOOP</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">, </span><span class="identifier">Kinds::Knowledge::as_subject</span><span class="plain">(</span><span class="identifier">K_room</span><span class="plain">), </span><span class="identifier">PROPERTY_INF</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">World::Inferences::get_property</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">) == </span><span class="identifier">P_description</span><span class="plain">)</span>
<span class="identifier">desc_seen</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">desc_seen</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) {</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">val</span><span class="plain">);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">val</span><span class="plain">, </span><span class="string">"\</span><span class="plain">"</span><span class="string">\</span><span class="plain">"</span><span class="string">"</span><span class="plain">);</span>
<span class="identifier">Properties::Valued::assert</span><span class="plain">(</span><span class="identifier">P_description</span><span class="plain">, </span><span class="identifier">Kinds::Knowledge::as_subject</span><span class="plain">(</span><span class="identifier">K_room</span><span class="plain">),</span>
<span class="identifier">Rvalues::from_unescaped_wording</span><span class="plain">(</span><span class="identifier">Feeds::feed_stream</span><span class="plain">(</span><span class="identifier">val</span><span class="plain">)), </span><span class="identifier">LIKELY_CE</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">val</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP38_5">&#167;38.5</a>.</p>
<p class="inwebparagraph"><a id="SP38_5_2"></a><b>&#167;38.5.2. </b>These I6-only properties exist for speed. They're implemented in I6 as
attributes, which means that testing them is very fast and there is no memory
overhead for their storage. That shaves a little time off route-finding in
extensive maps.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Assert room and thing indicator properties</span> <span class="cwebmacronumber">38.5.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">P_mark_as_room</span><span class="plain"> = </span><span class="identifier">Properties::EitherOr::new_nameless</span><span class="plain">(</span><span class="identifier">L</span><span class="string">"mark_as_room"</span><span class="plain">);</span>
<span class="identifier">Properties::EitherOr::implement_as_attribute</span><span class="plain">(</span><span class="identifier">P_mark_as_room</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">);</span>
<span class="identifier">P_mark_as_thing</span><span class="plain"> = </span><span class="identifier">Properties::EitherOr::new_nameless</span><span class="plain">(</span><span class="identifier">L</span><span class="string">"mark_as_thing"</span><span class="plain">);</span>
<span class="identifier">Properties::EitherOr::implement_as_attribute</span><span class="plain">(</span><span class="identifier">P_mark_as_thing</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">);</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Instances::of_kind</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">K_room</span><span class="plain">))</span>
<span class="identifier">Properties::EitherOr::assert</span><span class="plain">(</span>
<span class="identifier">P_mark_as_room</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="identifier">TRUE</span><span class="plain">, </span><span class="identifier">CERTAIN_CE</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Instances::of_kind</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">K_thing</span><span class="plain">))</span>
<span class="identifier">Properties::EitherOr::assert</span><span class="plain">(</span>
<span class="identifier">P_mark_as_thing</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="identifier">TRUE</span><span class="plain">, </span><span class="identifier">CERTAIN_CE</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP38_5">&#167;38.5</a>.</p>
<p class="inwebparagraph"><a id="SP38_5_3"></a><b>&#167;38.5.3. </b><code class="display">
&lt;<span class="cwebmacrodefn">Assert container and supporter indicator properties</span> <span class="cwebmacronumber">38.5.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">P_container</span><span class="plain"> = </span><span class="identifier">Properties::EitherOr::new_nameless</span><span class="plain">(</span><span class="identifier">L</span><span class="string">"container"</span><span class="plain">);</span>
<span class="identifier">Properties::EitherOr::implement_as_attribute</span><span class="plain">(</span><span class="identifier">P_container</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">);</span>
<span class="identifier">P_supporter</span><span class="plain"> = </span><span class="identifier">Properties::EitherOr::new_nameless</span><span class="plain">(</span><span class="identifier">L</span><span class="string">"supporter"</span><span class="plain">);</span>
<span class="identifier">Properties::EitherOr::implement_as_attribute</span><span class="plain">(</span><span class="identifier">P_supporter</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">);</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Instances::of_kind</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">K_container</span><span class="plain">))</span>
<span class="identifier">Properties::EitherOr::assert</span><span class="plain">(</span>
<span class="identifier">P_container</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="identifier">TRUE</span><span class="plain">, </span><span class="identifier">CERTAIN_CE</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Instances::of_kind</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">K_supporter</span><span class="plain">))</span>
<span class="identifier">Properties::EitherOr::assert</span><span class="plain">(</span>
<span class="identifier">P_supporter</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="identifier">TRUE</span><span class="plain">, </span><span class="identifier">CERTAIN_CE</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP38_5">&#167;38.5</a>.</p>
<p class="inwebparagraph"><a id="SP38_5_4"></a><b>&#167;38.5.4. </b>The main spatial tree is expressed in the compiled I6 code in an implicit
way, using the I6 object tree, but the incorporation tree is expressed using
a triplet of I6-only properties:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Assert incorporation tree properties</span> <span class="cwebmacronumber">38.5.4</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">P_component_parent</span><span class="plain"> =</span>
<span class="identifier">Properties::Valued::new_nameless</span><span class="plain">(</span><span class="identifier">I</span><span class="string">"component_parent"</span><span class="plain">, </span><span class="identifier">K_object</span><span class="plain">);</span>
<span class="identifier">P_component_child</span><span class="plain"> =</span>
<span class="identifier">Properties::Valued::new_nameless</span><span class="plain">(</span><span class="identifier">I</span><span class="string">"component_child"</span><span class="plain">, </span><span class="identifier">K_object</span><span class="plain">);</span>
<span class="identifier">P_component_sibling</span><span class="plain"> =</span>
<span class="identifier">Properties::Valued::new_nameless</span><span class="plain">(</span><span class="identifier">I</span><span class="string">"component_sibling"</span><span class="plain">, </span><span class="identifier">K_object</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K_thing</span><span class="plain">) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">nothing_constant</span><span class="plain"> = </span><span class="identifier">Rvalues::new_nothing_object_constant</span><span class="plain">();</span>
<span class="identifier">Properties::Valued::assert</span><span class="plain">(</span><span class="identifier">P_component_parent</span><span class="plain">, </span><span class="identifier">Kinds::Knowledge::as_subject</span><span class="plain">(</span><span class="identifier">K_thing</span><span class="plain">),</span>
<span class="identifier">nothing_constant</span><span class="plain">, </span><span class="identifier">CERTAIN_CE</span><span class="plain">);</span>
<span class="identifier">Properties::Valued::assert</span><span class="plain">(</span><span class="identifier">P_component_child</span><span class="plain">, </span><span class="identifier">Kinds::Knowledge::as_subject</span><span class="plain">(</span><span class="identifier">K_thing</span><span class="plain">),</span>
<span class="identifier">nothing_constant</span><span class="plain">, </span><span class="identifier">CERTAIN_CE</span><span class="plain">);</span>
<span class="identifier">Properties::Valued::assert</span><span class="plain">(</span><span class="identifier">P_component_sibling</span><span class="plain">, </span><span class="identifier">Kinds::Knowledge::as_subject</span><span class="plain">(</span><span class="identifier">K_thing</span><span class="plain">),</span>
<span class="identifier">nothing_constant</span><span class="plain">, </span><span class="identifier">CERTAIN_CE</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">cp</span><span class="plain"> = </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;incorp_tree_parent</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">cp</span><span class="plain">) </span><span class="identifier">Properties::Valued::assert</span><span class="plain">(</span><span class="identifier">P_component_parent</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">),</span>
<span class="identifier">Rvalues::from_instance</span><span class="plain">(</span><span class="identifier">cp</span><span class="plain">), </span><span class="identifier">CERTAIN_CE</span><span class="plain">);</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">cc</span><span class="plain"> = </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;incorp_tree_child</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">cc</span><span class="plain">) </span><span class="identifier">Properties::Valued::assert</span><span class="plain">(</span><span class="identifier">P_component_child</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">),</span>
<span class="identifier">Rvalues::from_instance</span><span class="plain">(</span><span class="identifier">cc</span><span class="plain">), </span><span class="identifier">CERTAIN_CE</span><span class="plain">);</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">cs</span><span class="plain"> = </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;incorp_tree_sibling</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">cs</span><span class="plain">) </span><span class="identifier">Properties::Valued::assert</span><span class="plain">(</span><span class="identifier">P_component_sibling</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">),</span>
<span class="identifier">Rvalues::from_instance</span><span class="plain">(</span><span class="identifier">cs</span><span class="plain">), </span><span class="identifier">CERTAIN_CE</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP38_5">&#167;38.5</a>.</p>
<p class="inwebparagraph"><a id="SP38_6"></a><b>&#167;38.6. </b>Because Inform 6 requires objects to be defined in a traversal order for
the main spatial tree (only the main one because I6 has no concept of
incorporation), we use the main tree to determine the compilation sequence
for objects:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Set up the compilation sequence so that it traverses the main object tree</span> <span class="cwebmacronumber">38.6</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Instances::begin_sequencing_objects</span><span class="plain">();</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;object_tree_parent</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)</span>
<span class="functiontext">PL::Spatial::add_to_object_sequence</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">, 0);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP38">&#167;38</a>.</p>
<p class="inwebparagraph"><a id="SP39"></a><b>&#167;39. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Spatial::add_to_object_sequence</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">depth</span><span class="plain">) {</span>
<span class="identifier">Instances::place_this_object_next</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">);</span>
<span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;I6_definition_depth</span><span class="plain"> = </span><span class="identifier">depth</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;object_tree_child</span><span class="plain">)</span>
<span class="functiontext">PL::Spatial::add_to_object_sequence</span><span class="plain">(</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;object_tree_child</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">+1);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain">)</span>
<span class="functiontext">PL::Spatial::add_to_object_sequence</span><span class="plain">(</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::add_to_object_sequence is used in <a href="#SP38_6">&#167;38.6</a>.</p>
<p class="inwebparagraph"><a id="SP40"></a><b>&#167;40. </b>The "definition depth" is the same thing as the depth in the main tree;
0 for a room, 1 for a player standing in that room, 2 for his hat, and so on.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::get_definition_depth</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Plugins::Manage::plugged_in</span><span class="plain">(</span><span class="identifier">spatial_plugin</span><span class="plain">))</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;I6_definition_depth</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> 0;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::get_definition_depth appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP41"></a><b>&#167;41. </b>At last, Stage IV. We're all done except for a little checking of the
degenerate case where Inform is just binding up an existing story file, so
that there's really no spatial model at all &mdash; the world is, or should be,
empty.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_stage_IV</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Task::wraps_existing_storyfile</span><span class="plain">()) {</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">PL::Spatial::object_is_a_room</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">)) {</span>
<span class="identifier">Problems::Issue::unlocated_problem</span><span class="plain">(</span><span class="identifier">Task::syntax_tree</span><span class="plain">(), </span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_RoomInIgnoredSource</span><span class="plain">),</span>
<span class="string">"This is supposed to be a source text which only contains "</span>
<span class="string">"release instructions to bind up an existing story file "</span>
<span class="string">"(for instance, one produced using Inform 6). That's because "</span>
<span class="string">"the instruction 'Release along with an existing story file' "</span>
<span class="string">"is present. So the source text must not contain rooms or "</span>
<span class="string">"other game design - these would be ignored."</span><span class="plain">);</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_stage_IV is used in <a href="#SP28">&#167;28</a>.</p>
<p class="inwebparagraph"><a id="SP42"></a><b>&#167;42. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Spatial::index_spatial_relationship</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">rel</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">P</span><span class="plain"> = </span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">P</span><span class="plain">) {</span>
<span class="comment">we could set <code class="display"><span class="extract">rel</span></code> to "in" here, but the index omits that for clarity</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Instances::of_kind</span><span class="plain">(</span><span class="identifier">P</span><span class="plain">, </span><span class="identifier">K_supporter</span><span class="plain">)) </span><span class="identifier">rel</span><span class="plain"> = </span><span class="string">"on"</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Instances::of_kind</span><span class="plain">(</span><span class="identifier">P</span><span class="plain">, </span><span class="identifier">K_person</span><span class="plain">)) </span><span class="identifier">rel</span><span class="plain"> = </span><span class="string">"carried"</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;part_flag</span><span class="plain">) </span><span class="identifier">rel</span><span class="plain"> = </span><span class="string">"part"</span><span class="plain">;</span>
<span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">inf</span><span class="plain">;</span>
<span class="identifier">POSITIVE_KNOWLEDGE_LOOP</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">), </span><span class="identifier">PROPERTY_INF</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">World::Inferences::get_property</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">) == </span><span class="identifier">P_worn</span><span class="plain">)</span>
<span class="identifier">rel</span><span class="plain"> = </span><span class="string">"worn"</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">rel</span><span class="plain">) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;i&gt;%s&lt;/i&gt; "</span><span class="plain">, </span><span class="identifier">rel</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::index_spatial_relationship appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP43"></a><b>&#167;43. </b>If something is a part, we don't detail it on the World index page, since
it already turns up under its owner.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::no_detail_index</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;incorp_tree_parent</span><span class="plain"> != </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::no_detail_index appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP44"></a><b>&#167;44. </b>In the World index, we recurse to show the contents and parts:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Spatial::index_object_further</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">depth</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">details</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">depth</span><span class="plain"> &gt; </span><span class="identifier">NUMBER_CREATED</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain">) + 1) </span><span class="reserved">return</span><span class="plain">; </span> <span class="comment">to recover from errors</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;incorp_tree_child</span><span class="plain"> != </span><span class="identifier">NULL</span><span class="plain">) {</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I2</span><span class="plain"> = </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;incorp_tree_child</span><span class="plain">;</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">I2</span><span class="plain"> != </span><span class="identifier">NULL</span><span class="plain">) {</span>
<span class="identifier">Data::Objects::index</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I2</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">+1, </span><span class="identifier">details</span><span class="plain">);</span>
<span class="identifier">I2</span><span class="plain"> = </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I2</span><span class="plain">)-</span><span class="element">&gt;incorp_tree_sibling</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;object_tree_child</span><span class="plain">)</span>
<span class="identifier">Data::Objects::index</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;object_tree_child</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">+1, </span><span class="identifier">details</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">PL::Spatial::object_is_a_room</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">PL::Map::object_is_a_door</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)) {</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I2</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_OBJECT_INSTANCES</span><span class="plain">(</span><span class="identifier">I2</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">PL::Map::object_is_a_door</span><span class="plain">(</span><span class="identifier">I2</span><span class="plain">)) &amp;&amp; (</span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">I2</span><span class="plain">) != </span><span class="identifier">I</span><span class="plain">)) {</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">A</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">, *</span><span class="identifier">B</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="functiontext">PL::Map::get_door_data</span><span class="plain">(</span><span class="identifier">I2</span><span class="plain">, &amp;</span><span class="identifier">A</span><span class="plain">, &amp;</span><span class="identifier">B</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">A</span><span class="plain"> == </span><span class="identifier">I</span><span class="plain">) </span><span class="identifier">Data::Objects::index</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I2</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">+1, </span><span class="identifier">details</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">B</span><span class="plain"> == </span><span class="identifier">I</span><span class="plain">) </span><span class="identifier">Data::Objects::index</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I2</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">+1, </span><span class="identifier">details</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="functiontext">PL::Player::index_object_further</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">, </span><span class="identifier">details</span><span class="plain">);</span>
<span class="functiontext">PL::Backdrops::index_object_further</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">, </span><span class="identifier">details</span><span class="plain">, 0);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain">)</span>
<span class="identifier">Data::Objects::index</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">)-</span><span class="element">&gt;object_tree_sibling</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">, </span><span class="identifier">details</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::index_object_further appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP45"></a><b>&#167;45. </b>And also:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Spatial::spatial_add_to_World_index</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">O</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">O</span><span class="plain">) &amp;&amp; (</span><span class="identifier">Instances::of_kind</span><span class="plain">(</span><span class="identifier">O</span><span class="plain">, </span><span class="identifier">K_thing</span><span class="plain">))) {</span>
<span class="identifier">HTMLFiles::open_para</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, 1, </span><span class="string">"tight"</span><span class="plain">);</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">P</span><span class="plain"> = </span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">O</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">P</span><span class="plain">) {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;i&gt;initial location:&lt;/i&gt; "</span><span class="plain">);</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">rel</span><span class="plain"> = </span><span class="string">"in"</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Instances::of_kind</span><span class="plain">(</span><span class="identifier">P</span><span class="plain">, </span><span class="identifier">K_supporter</span><span class="plain">)) </span><span class="identifier">rel</span><span class="plain"> = </span><span class="string">"on"</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Instances::of_kind</span><span class="plain">(</span><span class="identifier">P</span><span class="plain">, </span><span class="identifier">K_person</span><span class="plain">)) </span><span class="identifier">rel</span><span class="plain"> = </span><span class="string">"carried by"</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">O</span><span class="plain">)-</span><span class="element">&gt;part_flag</span><span class="plain">) </span><span class="identifier">rel</span><span class="plain"> = </span><span class="string">"part of"</span><span class="plain">;</span>
<span class="identifier">inference</span><span class="plain"> *</span><span class="identifier">inf</span><span class="plain">;</span>
<span class="identifier">POSITIVE_KNOWLEDGE_LOOP</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">O</span><span class="plain">), </span><span class="identifier">PROPERTY_INF</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">World::Inferences::get_property</span><span class="plain">(</span><span class="identifier">inf</span><span class="plain">) == </span><span class="identifier">P_worn</span><span class="plain">)</span>
<span class="identifier">rel</span><span class="plain"> = </span><span class="string">"worn by"</span><span class="plain">;</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%s "</span><span class="plain">, </span><span class="identifier">rel</span><span class="plain">);</span>
<span class="identifier">Instances::index_name</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">P</span><span class="plain">);</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">at</span><span class="plain"> = </span><span class="identifier">PF_I</span><span class="plain">(</span><span class="identifier">spatial</span><span class="plain">, </span><span class="identifier">O</span><span class="plain">)-</span><span class="element">&gt;progenitor_set_at</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">at</span><span class="plain">) </span><span class="identifier">Index::link</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">at</span><span class="plain">)));</span>
<span class="plain">}</span>
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Spatial::spatial_add_to_World_index is used in <a href="#SP7">&#167;7</a>.</p>
<hr class="tocbar">
<ul class="toc"><li><a href="3-tnt.html">Back to 'The Naming Thicket'</a></li><li><a href="3-sr.html">Continue with 'Spatial Relations'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</main>
</body>
</html>