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-tp.html

548 lines
52 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>3/sr</title>
<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>
<!--Weave of '3/tp' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">&#9733;</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>The Player</b></li></ul><p class="purpose">A plugin to give a special role to the player object.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Definitions</a></li><li><a href="#SP4">&#167;4. Initialisation</a></li><li><a href="#SP5">&#167;5. Special objects</a></li><li><a href="#SP6_1">&#167;6.1. Special variables</a></li><li><a href="#SP6_3">&#167;6.3. Aliasing and bodysnatching</a></li><li><a href="#SP9">&#167;9. Linguistic variations</a></li><li><a href="#SP12">&#167;12. Model completion</a></li><li><a href="#SP13">&#167;13. Initial time and place</a></li><li><a href="#SP14">&#167;14. World Index details</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>Altogether we keep track of four objects, though the first pair often coincide,
and so do the second pair. (<code class="display"><span class="extract">I_yourself</span></code> is constant once set, like <code class="display"><span class="extract">K_room</span></code> and
other such "constants" in the Inform source code.)
</p>
<pre class="display">
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">start_room</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">room in which play begins: e.g., Barber's Shop</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">start_object</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">object in which play begins: e.g., a barber's chair</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">player_character_object</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">the player character object used in this run</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">I_yourself</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">the default player character object, <code class="display"><span class="extract">selfobj</span></code> in I6</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b>Two variables are also special. The time of day might not look as if it belongs
to this plugin, but the idea is to position the player in both space and time.
</p>
<pre class="display">
<span class="identifier">nonlocal_variable</span><span class="plain"> *</span><span class="identifier">player_VAR</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">initially <code class="display"><span class="extract">player_character_object</span></code> and often always <code class="display"><span class="extract">I_yourself</span></code></span>
<span class="identifier">nonlocal_variable</span><span class="plain"> *</span><span class="identifier">time_of_day_VAR</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">nonlocal_variable</span><span class="plain"> *</span><span class="identifier">score_VAR</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. Initialisation. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Player::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_VARIABLE_NOTIFY</span><span class="plain">, </span><span class="functiontext">PL::Player::player_new_quantity_notify</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_VARIABLE_SET_WARNING</span><span class="plain">, </span><span class="functiontext">PL::Player::player_variable_set_warning</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_NEW_INSTANCE_NOTIFY</span><span class="plain">, </span><span class="functiontext">PL::Player::player_new_instance_notify</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_IRREGULAR_GENITIVE</span><span class="plain">, </span><span class="functiontext">PL::Player::player_irregular_genitive</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::Player::player_complete_model</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_REFINE_IMPLICIT_NOUN</span><span class="plain">, </span><span class="functiontext">PL::Player::player_refine_implicit_noun</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_DETECT_BODYSNATCHING</span><span class="plain">, </span><span class="functiontext">PL::Player::player_detect_bodysnatching</span><span class="plain">);</span>
<span class="identifier">PLUGIN_REGISTER</span><span class="plain">(</span><span class="identifier">PLUGIN_ANNOTATE_IN_WORLD_INDEX</span><span class="plain">, </span><span class="functiontext">PL::Player::player_annotate_in_World_index</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Player::start appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. Special objects. </b>The "yourself" object is special in being tied, or "aliased", to the
"player" variable, so Inform needs to recognise it. (No need to translate; it
is created in English.)
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">notable</span><span class="plain">-</span><span class="identifier">player</span><span class="plain">-</span><span class="identifier">instances</span><span class="plain">&gt; ::=</span>
<span class="identifier">yourself</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. </b></p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Player::player_new_instance_notify</span><span class="plain">(</span><span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">inst</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">inst</span><span class="plain">, </span><span class="identifier">FALSE</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">player</span><span class="plain">-</span><span class="identifier">instances</span><span class="plain">&gt;(</span><span class="identifier">IW</span><span class="plain">)) {</span>
<span class="identifier">I_yourself</span><span class="plain"> = </span><span class="identifier">inst</span><span class="plain">; </span><span class="identifier">player_character_object</span><span class="plain"> = </span><span class="identifier">I_yourself</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">player_VAR</span><span class="plain">) </span>&lt;<span class="cwebmacro">Alias the player variable to the yourself object</span> <span class="cwebmacronumber">6.3</span>&gt;<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="identifier">instance</span><span class="plain"> *</span><span class="functiontext">PL::Player::get_start_room</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">start_room</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Player::player_new_instance_notify is used in <a href="#SP4">&#167;4</a>.</p>
<p class="endnote">The function PL::Player::get_start_room is used in <a href="#SP14">&#167;14</a>, 3/sm2 (<a href="3-sm2.html#SP8_15">&#167;8.15</a>, <a href="3-sm2.html#SP43_2">&#167;43.2</a>).</p>
<p class="inwebparagraph"><a id="SP6_1"></a><b>&#167;6.1. Special variables. </b>"Time of day" is a perfectly normal variable and we only note down its
identity in order to find out the initial time of day intended by the
source text.
</p>
<p class="inwebparagraph">"Player", on the other hand, is unusual in two respects. First, it's aliased
to an object; second, it's set in an unusual way. That is, Inform does not
compile
</p>
<blockquote>
<p>now the player is Mr Chasuble;</p>
</blockquote>
<p class="inwebparagraph">to something like <code class="display"><span class="extract">player = O31_mr_chasuble</span></code>, as it would do for a typical
variable. It's very important that code compiled by Inform 7 doesn't do
this, because if executed it would break the invariants for the various I6
variables about the current situation. The correct thing is always to call
the template routine <code class="display"><span class="extract">ChangePlayer</span></code>. We ensure that by supplying an I6
schema which overrides the standard one for setting global variables:
</p>
<p class="inwebparagraph">As usual, no need to translate these; they are created in English.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">notable</span><span class="plain">-</span><span class="identifier">player</span><span class="plain">-</span><span class="identifier">variables</span><span class="plain">&gt; ::=</span>
<span class="identifier">player</span><span class="plain"> |</span>
<span class="identifier">score</span><span class="plain"> |</span>
<span class="identifier">time</span><span class="plain"> </span><span class="identifier">of</span><span class="plain"> </span><span class="identifier">day</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP6_2"></a><b>&#167;6.2. </b></p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Player::player_new_quantity_notify</span><span class="plain">(</span><span class="identifier">nonlocal_variable</span><span class="plain"> *</span><span class="identifier">nlv</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">player</span><span class="plain">-</span><span class="identifier">variables</span><span class="plain">&gt;(</span><span class="identifier">nlv</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">player_VAR</span><span class="plain"> = </span><span class="identifier">nlv</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">I_yourself</span><span class="plain">) </span>&lt;<span class="cwebmacro">Alias the player variable to the yourself object</span> <span class="cwebmacronumber">6.3</span>&gt;<span class="plain">;</span>
<span class="identifier">NonlocalVariables::set_write_schema</span><span class="plain">(</span><span class="identifier">nlv</span><span class="plain">, </span><span class="string">"ChangePlayer(*2)"</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">score_VAR</span><span class="plain"> = </span><span class="identifier">nlv</span><span class="plain">;</span>
<span class="identifier">NonlocalVariables::make_initalisable</span><span class="plain">(</span><span class="identifier">score_VAR</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">time_of_day_VAR</span><span class="plain"> = </span><span class="identifier">nlv</span><span class="plain">;</span>
<span class="identifier">NonlocalVariables::make_initalisable</span><span class="plain">(</span><span class="identifier">time_of_day_VAR</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::Player::player_new_quantity_notify is used in <a href="#SP4">&#167;4</a>.</p>
<p class="inwebparagraph"><a id="SP6_3"></a><b>&#167;6.3. Aliasing and bodysnatching. </b>As can be seen, as soon as both "yourself" (object) and "player" (variable)
have been created, they are aliased together. This is a form of tacit pointer
dereferencing, though authors probably don't think of it that way. A normal
object variable is like a pointer to an object, rather than an object itself,
and so the following doesn't make sense:
</p>
<blockquote>
<p>The top prize is an object that varies. The top prize is in the desk drawer.</p>
</blockquote>
<p class="inwebparagraph">Clearly something goes in the desk drawer, but it's quite ambiguous what: the
problem is that "top prize" describes some object, but it's not clear which.
(Inform generally disallows this even if the source text explicitly gives a
value for top prize.) But "player" is unusual because Inform authors are
encouraged always to describe the player object that way, and often don't
realise that it's a variable at all &mdash; and most of the time it never changes
its value, of course, but simply remains equal to "yourself" throughout play.
So we want to allow this sort of thing:
</p>
<blockquote>
<p>The player is in the Cage.</p>
</blockquote>
<p class="inwebparagraph">even though it has exactly the same problem as the top prize. We get around
this by treating "player", in assertions, as if it were its own initial
value ("yourself") &mdash; in effect, we silently dereference it. This is
aliasing.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Alias the player variable to the yourself object</span> <span class="cwebmacronumber">6.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">subj</span><span class="plain"> = </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I_yourself</span><span class="plain">);</span>
<span class="identifier">InferenceSubjects::alias_to_nonlocal_variable</span><span class="plain">(</span><span class="identifier">subj</span><span class="plain">, </span><span class="identifier">player_VAR</span><span class="plain">);</span>
<span class="identifier">NonlocalVariables::set_alias</span><span class="plain">(</span><span class="identifier">player_VAR</span><span class="plain">, </span><span class="identifier">subj</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP6">&#167;6</a>, <a href="#SP6_2">&#167;6.2</a>.</p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. </b>We also, though, want to look out for this sort of thing:
</p>
<blockquote>
<p>The player is Lord Collingwood.</p>
</blockquote>
<p class="inwebparagraph">because an assertion like this causes <code class="display"><span class="extract">player_character_object</span></code> to diverge from <code class="display"><span class="extract">I_yourself</span></code>;
here of course it becomes the Lord Collingwood object.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Player::player_variable_set_warning</span><span class="plain">(</span><span class="identifier">nonlocal_variable</span><span class="plain"> *</span><span class="identifier">nlv</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">val</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">nlv</span><span class="plain"> == </span><span class="identifier">player_VAR</span><span class="plain">) {</span>
<span class="identifier">instance</span><span class="plain"> *</span><span class="identifier">npc</span><span class="plain"> = </span><span class="identifier">Rvalues::to_object_instance</span><span class="plain">(</span><span class="identifier">val</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">npc</span><span class="plain">) {</span>
<span class="identifier">player_character_object</span><span class="plain"> = </span><span class="identifier">npc</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::Player::player_variable_set_warning is used in <a href="#SP4">&#167;4</a>.</p>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. </b>But it gets worse: as well as aliasing, there is bodysnatching. Our problem
is that once the author has written "The player is Lord Collingwood.", it's
clear that the "yourself" object shouldn't appear anywhere. But there are
two problems with that: one, the I6 template code needs it to exist, even if
it isn't in the model world; and two, we've just aliased "player" to it.
</p>
<p class="inwebparagraph">Bodysnatching allows one object (the "snatcher") to take over the life of
another (the "victim"), so that inferences made about the victim are diverted
to the snatcher. Thus if the source text reads:
</p>
<blockquote>
<p>The player is Lord Collingwood. The player carries a spyglass.</p>
</blockquote>
<p class="inwebparagraph">the second sentence goes through two transformations: first, because of
aliasing, Inform decides to draw an inference about "yourself", rather
than complaining that "player" is indefinite; and second, because of
bodysnatching, the Collingwood object (snatcher) takes over the inference
from the yourself object (victim). So Collingwood gets the spyglass, as
the source text clearly intended.
</p>
<p class="inwebparagraph">Bodysnatching is used only when <code class="display"><span class="extract">player_character_object</span></code> differs from <code class="display"><span class="extract">I_yourself</span></code>,
that is, when the source text explicitly sets a value for "player".
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Player::player_detect_bodysnatching</span><span class="plain">(</span><span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">body</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> *</span><span class="identifier">snatcher</span><span class="plain">,</span>
<span class="identifier">inference_subject</span><span class="plain"> **</span><span class="identifier">counterpart</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">player_character_object</span><span class="plain"> == </span><span class="identifier">I_yourself</span><span class="plain">) ||</span>
<span class="plain">(</span><span class="identifier">player_character_object</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) || (</span><span class="identifier">I_yourself</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="identifier">kind</span><span class="plain"> *</span><span class="identifier">KP</span><span class="plain"> = </span><span class="identifier">Instances::to_kind</span><span class="plain">(</span><span class="identifier">player_character_object</span><span class="plain">);</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">KY</span><span class="plain"> = </span><span class="identifier">Instances::to_kind</span><span class="plain">(</span><span class="identifier">I_yourself</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">KP</span><span class="plain">, </span><span class="identifier">KY</span><span class="plain">)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">body</span><span class="plain"> == </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">player_character_object</span><span class="plain">)) {</span>
<span class="plain">*</span><span class="identifier">snatcher</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">; *</span><span class="identifier">counterpart</span><span class="plain"> = </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I_yourself</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">if</span><span class="plain"> (</span><span class="identifier">body</span><span class="plain"> == </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I_yourself</span><span class="plain">)) {</span>
<span class="plain">*</span><span class="identifier">snatcher</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">; *</span><span class="identifier">counterpart</span><span class="plain"> = </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">player_character_object</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">else</span><span class="plain"> {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">body</span><span class="plain"> == </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">player_character_object</span><span class="plain">)) {</span>
<span class="plain">*</span><span class="identifier">snatcher</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">; *</span><span class="identifier">counterpart</span><span class="plain"> = </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I_yourself</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">if</span><span class="plain"> (</span><span class="identifier">body</span><span class="plain"> == </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I_yourself</span><span class="plain">)) {</span>
<span class="plain">*</span><span class="identifier">snatcher</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">; *</span><span class="identifier">counterpart</span><span class="plain"> = </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">player_character_object</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::Player::player_detect_bodysnatching is used in <a href="#SP4">&#167;4</a>.</p>
<p class="inwebparagraph"><a id="SP9"></a><b>&#167;9. Linguistic variations. </b>Thankfully everything else is straightforward. The following is used to
ensure that assemblies such as "A nose is part of every person" produces
"your nose" rather than "yourself's nose":
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Player::player_irregular_genitive</span><span class="plain">(</span><span class="identifier">inference_subject</span><span class="plain"> *</span><span class="identifier">owner</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">genitive</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> *</span><span class="identifier">propriety</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">owner</span><span class="plain"> == </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">I_yourself</span><span class="plain">)) {</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">genitive</span><span class="plain">, </span><span class="string">"your "</span><span class="plain">);</span>
<span class="plain">*</span><span class="identifier">propriety</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">if</span><span class="plain"> ((</span><span class="identifier">player_character_object</span><span class="plain">) &amp;&amp; (</span><span class="identifier">I_yourself</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">player_character_object</span><span class="plain"> != </span><span class="identifier">I_yourself</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">owner</span><span class="plain"> == </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">player_character_object</span><span class="plain">))) {</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">genitive</span><span class="plain">, </span><span class="string">"your "</span><span class="plain">);</span>
<span class="plain">*</span><span class="identifier">propriety</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::Player::player_irregular_genitive is used in <a href="#SP4">&#167;4</a>.</p>
<p class="inwebparagraph"><a id="SP10"></a><b>&#167;10. </b>The adjectives "worn" and "carried" &mdash; as in, "The nautical chart is
carried." &mdash; implicitly refer to the player as the unstated term in the
relationship; that makes them our business here. "Initially carried" is
now deprecated, but is provided as synonymous with "carried" because it
was once an either/or property in the clumsier early stages of Inform 7,
and people still sometimes type it.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">implicit</span><span class="plain">-</span><span class="identifier">player</span><span class="plain">-</span><span class="identifier">relationship</span><span class="plain">&gt; ::=</span>
<span class="identifier">worn</span><span class="plain"> |</span>
<span class="identifier">carried</span><span class="plain"> |</span>
<span class="identifier">initially</span><span class="plain"> </span><span class="identifier">carried</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP11"></a><b>&#167;11. </b></p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Player::player_refine_implicit_noun</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">implicit</span><span class="plain">-</span><span class="identifier">player</span><span class="plain">-</span><span class="identifier">relationship</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">))) {</span>
<span class="identifier">Assertions::Refiner::noun_from_infs</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">Instances::as_subject</span><span class="plain">(</span><span class="identifier">player_character_object</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::Player::player_refine_implicit_noun is used in <a href="#SP4">&#167;4</a>.</p>
<p class="inwebparagraph"><a id="SP12"></a><b>&#167;12. Model completion. </b>We take no interest until stage IV, a point at which kinds of objects and the
spatial model for them are both completely worked out. We won't change
anything: all we will do is calculate the start object and the start room
by looking at where the player sits in the spatial model.
</p>
<p class="inwebparagraph">Very often, the source text doesn't specify where the player is, and then
we assume he is freestanding in the earliest defined room.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Player::player_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">if</span><span class="plain"> (</span><span class="identifier">stage</span><span class="plain"> == 4) {</span>
&lt;<span class="cwebmacro">Set the start room to the earliest room defined in the source text</span> <span class="cwebmacronumber">12.1</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">If the start room is still null, there's no room, so issue a problem</span> <span class="cwebmacronumber">12.2</span>&gt;<span class="character">;</span>
&lt;<span class="cwebmacro">Otherwise see if the player has explicitly been placed in the model world</span> <span class="cwebmacronumber">12.3</span>&gt;<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::Player::player_complete_model is used in <a href="#SP4">&#167;4</a>.</p>
<p class="inwebparagraph"><a id="SP12_1"></a><b>&#167;12.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Set the start room to the earliest room defined in the source text</span> <span class="cwebmacronumber">12.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="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="identifier">start_room</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)</span>
<span class="plain">&amp;&amp; (</span><span class="identifier">Instances::get_creating_file</span><span class="plain">(</span><span class="identifier">I</span><span class="plain">) == </span><span class="identifier">primary_source_file</span><span class="plain">))</span>
<span class="identifier">start_room</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">)) &amp;&amp; (</span><span class="identifier">start_room</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">))</span>
<span class="identifier">start_room</span><span class="plain"> = </span><span class="identifier">I</span><span class="plain">;</span>
<span class="identifier">start_object</span><span class="plain"> = </span><span class="identifier">start_room</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP12">&#167;12</a>.</p>
<p class="inwebparagraph"><a id="SP12_2"></a><b>&#167;12.2. </b><code class="display">
&lt;<span class="cwebmacrodefn">If the start room is still null, there's no room, so issue a problem</span> <span class="cwebmacronumber">12.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">start_room</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) &amp;&amp; (</span><span class="identifier">existing_story_file</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">)) {</span>
<span class="identifier">Problems::Issue::unlocated_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_NoStartRoom</span><span class="plain">),</span>
<span class="string">"There doesn't seem to be any location in this story, so there's "</span>
<span class="string">"nowhere for the player to begin. This may be because I have "</span>
<span class="string">"misunderstood what was meant to be a room and what wasn't: I "</span>
<span class="string">"only know something is a room if you tell me explicitly ('The "</span>
<span class="string">"Observatory is a room') or if you imply it by giving map "</span>
<span class="string">"directions ('East of the Observatory is the Planetarium')."</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">This code is used in <a href="#SP12">&#167;12</a>.</p>
<p class="inwebparagraph"><a id="SP12_3"></a><b>&#167;12.3. </b>If the source text said nothing about the player's location, then the
player object will be a disconnected node in the containment tree: it will,
in fact, have no progenitor. In that event, the start room already calculated
will do. But otherwise:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Otherwise see if the player has explicitly been placed in the model world</span> <span class="cwebmacronumber">12.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">player_character_object</span><span class="plain">) {</span>
<span class="identifier">start_object</span><span class="plain"> = </span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">player_character_object</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">start_object</span><span class="plain">) {</span>
<span class="identifier">start_room</span><span class="plain"> = </span><span class="identifier">start_object</span><span class="plain">;</span>
<span class="reserved">while</span><span class="plain"> ((</span><span class="identifier">start_room</span><span class="plain">) &amp;&amp; (</span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">start_room</span><span class="plain">)))</span>
<span class="identifier">start_room</span><span class="plain"> = </span><span class="functiontext">PL::Spatial::progenitor</span><span class="plain">(</span><span class="identifier">start_room</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">start_room</span><span class="plain">) &amp;&amp; (</span><span class="functiontext">PL::Spatial::object_is_a_room</span><span class="plain">(</span><span class="identifier">start_room</span><span class="plain">) == </span><span class="identifier">FALSE</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_StartsOutsideRooms</span><span class="plain">),</span>
<span class="identifier">start_object</span><span class="plain">,</span>
<span class="string">"seems to be where the player is supposed to begin"</span><span class="plain">,</span>
<span class="string">"but (so far as I know) it is not a room, nor is it ultimately "</span>
<span class="string">"contained inside a room."</span><span class="plain">);</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">player_character_object</span><span class="plain">), </span><span class="constant">PART_OF_INF</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_PlayerIsPart</span><span class="plain">),</span>
<span class="identifier">start_object</span><span class="plain">,</span>
<span class="string">"seems to have the player attached as a component part"</span><span class="plain">,</span>
<span class="string">"which is not allowed. The player can be in a room, or "</span>
<span class="string">"inside a container, or on a supporter, but can't be part "</span>
<span class="string">"of something."</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="#SP12">&#167;12</a>.</p>
<p class="inwebparagraph"><a id="SP13"></a><b>&#167;13. Initial time and place. </b>Well: the point of tracking all of those variables was solely to be able to
compile this little array, which provides enough details for the I6 template
code to set things up correctly at run-time.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Player::InitialSituation</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">Plugins::Manage::plugged_in</span><span class="plain">(</span><span class="identifier">player_plugin</span><span class="plain">)) {</span>
<span class="identifier">Emit::named_numeric_constant</span><span class="plain">(</span><span class="identifier">InterNames::iname</span><span class="plain">(</span><span class="identifier">PLAYER_OBJECT_INIS_INAME</span><span class="plain">), (</span><span class="identifier">inter_t</span><span class="plain">) 0);</span>
<span class="identifier">Emit::named_numeric_constant</span><span class="plain">(</span><span class="identifier">InterNames::iname</span><span class="plain">(</span><span class="identifier">START_OBJECT_INIS_INAME</span><span class="plain">), (</span><span class="identifier">inter_t</span><span class="plain">) 1);</span>
<span class="identifier">Emit::named_numeric_constant</span><span class="plain">(</span><span class="identifier">InterNames::iname</span><span class="plain">(</span><span class="identifier">START_ROOM_INIS_INAME</span><span class="plain">), (</span><span class="identifier">inter_t</span><span class="plain">) 2);</span>
<span class="identifier">Emit::named_numeric_constant</span><span class="plain">(</span><span class="identifier">InterNames::iname</span><span class="plain">(</span><span class="identifier">START_TIME_INIS_INAME</span><span class="plain">), (</span><span class="identifier">inter_t</span><span class="plain">) 3);</span>
<span class="identifier">Emit::named_numeric_constant</span><span class="plain">(</span><span class="identifier">InterNames::iname</span><span class="plain">(</span><span class="identifier">DONE_INIS_INAME</span><span class="plain">), (</span><span class="identifier">inter_t</span><span class="plain">) 4);</span>
<span class="identifier">Emit::named_array_begin</span><span class="plain">(</span><span class="identifier">InterNames::iname</span><span class="plain">(</span><span class="identifier">InitialSituation_INAME</span><span class="plain">), </span><span class="identifier">K_value</span><span class="plain">);</span>
<span class="identifier">NonlocalVariables::emit_initial_value</span><span class="plain">(</span><span class="identifier">player_VAR</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">start_object</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">Emit::array_numeric_entry</span><span class="plain">(0);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">Emit::array_iname_entry</span><span class="plain">(</span><span class="identifier">Instances::iname</span><span class="plain">(</span><span class="identifier">start_object</span><span class="plain">));</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">start_room</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">Emit::array_numeric_entry</span><span class="plain">(0);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">Emit::array_iname_entry</span><span class="plain">(</span><span class="identifier">Instances::iname</span><span class="plain">(</span><span class="identifier">start_room</span><span class="plain">));</span>
<span class="identifier">NonlocalVariables::emit_initial_value</span><span class="plain">(</span><span class="identifier">time_of_day_VAR</span><span class="plain">);</span>
<span class="identifier">Emit::array_numeric_entry</span><span class="plain">(0);</span>
<span class="identifier">Emit::array_end</span><span class="plain">();</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function PL::Player::InitialSituation appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP14"></a><b>&#167;14. World Index details. </b>We explicitly mention the player in the World index, since otherwise it won't
usually appear anywhere.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">PL::Player::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">I</span><span class="plain"> == </span><span class="identifier">start_room</span><span class="plain">) &amp;&amp; (</span><span class="identifier">I_yourself</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Instances::indexed_yet</span><span class="plain">(</span><span class="identifier">I_yourself</span><span class="plain">) == </span><span class="identifier">FALSE</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">I_yourself</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="reserved">int</span><span class="plain"> </span><span class="functiontext">PL::Player::player_annotate_in_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">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="functiontext">PL::Player::get_start_room</span><span class="plain">()) {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" - &lt;i&gt;room where play begins&lt;/i&gt;"</span><span class="plain">);</span>
<span class="identifier">Index::DocReferences::link</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"ROOMPLAYBEGINS"</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::Player::index_object_further is used in 3/sm (<a href="3-sm.html#SP44">&#167;44</a>).</p>
<p class="endnote">The function PL::Player::player_annotate_in_World_index is used in <a href="#SP4">&#167;4</a>.</p>
<hr class="tocbar">
<ul class="toc"><li><a href="3-sr.html">Back to 'Spatial Relations'</a></li><li><a href="3-bck.html">Continue with 'Backdrops'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</body>
</html>