diff --git a/docs/assertions-module/4-ass.html b/docs/assertions-module/4-ass.html
index f2dc05e9f..2baf3fe4f 100644
--- a/docs/assertions-module/4-ass.html
+++ b/docs/assertions-module/4-ass.html
@@ -1389,8 +1389,8 @@ in this case.
#ifdefIF_MODULE
-if ((PL::MapDirections::get_mapping_relationship(px)) &&
- (PL::MapDirections::get_mapping_relationship(py))) {
+if ((MapRelations::get_mapping_relationship(px)) &&
+ (MapRelations::get_mapping_relationship(py))) {Map::enter_one_way_mode();Assertions::make_coupling(px, py->down);Assertions::make_coupling(px->down, py);
diff --git a/docs/assertions-module/4-rk.html b/docs/assertions-module/4-rk.html
index 601bea3e0..cc6ba5ad3 100644
--- a/docs/assertions-module/4-rk.html
+++ b/docs/assertions-module/4-rk.html
@@ -107,7 +107,7 @@ objects or values, but there are two exceptional cases to take care of.
return; } #ifdefIF_MODULE
-if (PL::MapDirections::get_mapping_relationship(relationship_subtree))
+if (MapRelations::get_mapping_relationship(relationship_subtree))Exceptional relationship nodes for map connections1.3;pronoun_usage *pro = Node::get_pronoun(relationship_subtree->down);if ((pro) && (pro->pronoun_used == here_pronoun))
diff --git a/docs/assertions-module/4-rpt.html b/docs/assertions-module/4-rpt.html
index 1594673c7..aa1cc90a3 100644
--- a/docs/assertions-module/4-rpt.html
+++ b/docs/assertions-module/4-rpt.html
@@ -498,7 +498,7 @@ has the marble and the box as its children, the relationship being containment.
if (p->down) {Refiner::refine(p->down, creation_rule); #ifdefIF_MODULE
-instance *dir = PL::MapDirections::get_mapping_relationship(p);
+instance *dir = MapRelations::get_mapping_relationship(p);if (dir) Make the relation one which refers to a map direction11.5.1; #endifif (p->down->next) Refiner::refine(p->down->next, creation_rule);
diff --git a/docs/core-module/1-cp.html b/docs/core-module/1-cp.html
index 70262bb75..00971d3da 100644
--- a/docs/core-module/1-cp.html
+++ b/docs/core-module/1-cp.html
@@ -287,18 +287,24 @@ We begin with core itself.
@@ -307,9 +313,7 @@ We begin with core itself.
enumauxiliary_file_CLASSenumcached_understanding_CLASSenumcommand_index_entry_CLASS
-enumconnected_submap_CLASSenumdirection_inference_data_CLASS
-enumEPS_map_level_CLASSenumfound_in_inference_data_CLASSenumgrammar_line_CLASSenumgrammar_verb_CLASS
@@ -326,7 +330,6 @@ We begin with core itself.
enumregions_data_CLASSenumrelease_instructions_CLASSenumreserved_command_verb_CLASS
-enumrubric_holder_CLASSenumscene_CLASSenumslash_gpr_CLASSenumspatial_data_CLASS
@@ -342,9 +345,7 @@ We begin with core itself.
DECLARE_CLASS(auxiliary_file)DECLARE_CLASS(cached_understanding)DECLARE_CLASS(command_index_entry)
-DECLARE_CLASS(connected_submap)DECLARE_CLASS(direction_inference_data)
-DECLARE_CLASS(EPS_map_level)DECLARE_CLASS(found_in_inference_data)DECLARE_CLASS(grammar_line)DECLARE_CLASS(grammar_verb)
@@ -361,7 +362,6 @@ We begin with core itself.
DECLARE_CLASS(regions_data)DECLARE_CLASS(release_instructions)DECLARE_CLASS(reserved_command_verb)
-DECLARE_CLASS(rubric_holder)DECLARE_CLASS(scene)DECLARE_CLASS(slash_gpr)DECLARE_CLASS(spatial_data)
diff --git a/docs/if-module/1-im.html b/docs/if-module/1-im.html
index 1c26bbd04..1403b084d 100644
--- a/docs/if-module/1-im.html
+++ b/docs/if-module/1-im.html
@@ -96,7 +96,7 @@ function togglePopup(material_id) {
ReleaseInstructions::start();WherePredicates::start();SpatialRelations::start();
-PL::MapDirections::start();
+MapRelations::start();}
diff --git a/docs/if-module/3-dvc.html b/docs/if-module/3-dvc.html
index 7150168e9..6ce846a51 100644
--- a/docs/if-module/3-dvc.html
+++ b/docs/if-module/3-dvc.html
@@ -79,15 +79,13 @@ Rules in a clumsy sort of way (with a direct I6 code injection), but in the
age of Inter we want to avoid that sort of tomfoolery.
-
diff --git a/docs/if-module/3-enah.html b/docs/if-module/3-enah.html
index 5686fc309..872e9668b 100644
--- a/docs/if-module/3-enah.html
+++ b/docs/if-module/3-enah.html
@@ -304,7 +304,7 @@ and put the issue aside for now.
}
§2. Subsequent creations. Every direction created has a relation associated with it: for instance,
@@ -103,7 +103,7 @@ at an earlier stage in Inform's run, so another two-step is needed:
-binary_predicate *PL::MapDirections::create_sketchy_mapping_direction(wordingW) {
+binary_predicate *MapRelations::create_sketchy_mapping_direction(wordingW) {binary_predicate *bp;Create the mapping BP for the new direction2.3;returnbp;
@@ -122,7 +122,7 @@ is done to avoid ambiguities with the already-existing meanings of inside
and outside to do with spatial containment.
-
The use of the word "mapped" may seem itself off. Why define "to be mapped
+
The use of the word "mapped" may seem itself odd. Why define "to be mapped
east of" rather than "to be east of"? After all, that seems to be what is
used in assertions like:
@@ -131,8 +131,8 @@ used in assertions like:
The Bakery is east of Pudding Lane.
-
In fact, the A-parser reads sentences like that by looking out specially for
-direction names plus "of" — so this is parsed without using the mapping
+
In fact, the assertion parser reads sentences like that by looking out specially
+for direction names plus "of" — so this is parsed without using the mapping
predicate for "east". But it cannot read:
@@ -144,14 +144,6 @@ predicate for "east". But it cannot read:
"down", and anyway there is no "of".
-
We do not allow direction names with unexpected capital letters because we
-want to allow room names to contain direction names on occasion:
-
-
-
-
The fire hydrant is in West from 47th Street.
-
-
<mapping-relation-construction>::=mapping...
@@ -229,7 +221,7 @@ makes it possible to complete the details of the BP.
diff --git a/docs/if-module/3-rgn.html b/docs/if-module/3-rgn.html
index 8c39b9b6d..c0b0839c5 100644
--- a/docs/if-module/3-rgn.html
+++ b/docs/if-module/3-rgn.html
@@ -165,7 +165,7 @@ region is either the next broadest region containing it, or else
-instance *Regions::enclosing(instance *reg) {
+instance *Regions::enclosing(instance *reg) {instance *P = NULL;if (Spatial::object_is_a_room(reg)) P = REGIONS_DATA(reg)->in_region;if (Regions::object_is_a_region(reg)) P = Spatial::progenitor(reg);
@@ -180,7 +180,7 @@ domains.)
-intRegions::object_is_a_region(instance *I) {
+intRegions::object_is_a_region(instance *I) {if ((K_region) && (I) && (Instances::of_kind(I, K_region))) returnTRUE;returnFALSE;}
@@ -219,7 +219,7 @@ following minimal structure, though it will only be relevant for instances of
CLASS_DEFINITION} regions_data;
-intRegions::new_subject_notify(inference_subject *subj) {
+intRegions::new_subject_notify(inference_subject *subj) {regions_data *rd = CREATE(regions_data);rd->in_region = NULL;rd->in_region_set_at = NULL;
@@ -243,7 +243,7 @@ Standard Rules. (So there is no need to translate this to other languages.)
property *P_map_region = NULL; a value property giving the region of a room
-intRegions::new_property_notify(property *prn) {
+intRegions::new_property_notify(property *prn) {if (<notable-regions-properties>(prn->name))P_map_region = prn;returnFALSE;
@@ -254,7 +254,7 @@ messages which would have been less helpful if core Inform had produced them.
-intRegions::intervene_in_assertion(parse_node *px, parse_node *py) {
+intRegions::intervene_in_assertion(parse_node *px, parse_node *py) {if ((Node::get_type(px) == PROPER_NOUN_NT) && (Node::get_type(py) == COMMON_NOUN_NT)) {inference_subject *left_subject = Node::get_subject(px);
@@ -296,7 +296,7 @@ messages which would have been less helpful if core Inform had produced them.
Scenes are periods of time during play: at any given moment, several may be going on, or none. They are started and stopped when certain conditions are met, or by virtue of having been anchored together.
+
A plugin to support named periods of time during an interactive story.
§1. Scenes are gated intervals of time, but there are more than two gates: for
-while there is only one past, there are many possible futures. These gates
-are called "ends" in the code below, and are numbered end 0 (the beginning),
-end 1 (the usual end), and then any named ends ("ends badly" or "ends
-triumphantly", for instance, might be ends 2 and 3). Each end has a condition
-which can cause it, or can be "anchored" to any number of ends of other
-scenes — to express which, the scene_connector structure is used.
-
-
-
defineMAX_SCENE_ENDS32 this must exceed 31
-
-
-typedefstructscene_connector {
-structscene *connect_to; scene connected to
-intend; end number: see above
-structscene_connector *next; next in list of connectors for a scene end
-structparse_node *where_said; where this linkage was specified in source
-} scene_connector;
-
-typedefstructscene {
-structinstance *as_instance; the constant for the name of the scene
-intonce_only; cannot repeat during play
-intstart_of_play; if begins when play begins
-intmarker; used to detect potentially infinite recursion when scene changes occur
-intno_ends; how many ends the scene has
-structwordingend_names[MAX_SCENE_ENDS]; for ends 2, 3, ...: e.g. "badly"
-structrulebook *end_rulebook[MAX_SCENE_ENDS]; rules to apply then
-structparse_node *anchor_condition[MAX_SCENE_ENDS];
-structscene_connector *anchor_scene[MAX_SCENE_ENDS]; linked list
-intindexed; temporary storage during Scenes index creation
-structparse_node *scene_declared_at; where defined
-structparse_node *anchor_condition_set[MAX_SCENE_ENDS]; where set
-CLASS_DEFINITION
-} scene;
-
-
The structure scene_connector is accessed in 2/ri, 3/tm, 3/em, 3/tm2, 3/ts, 4/act, 4/anl, 4/ap2, 4/nap, 5/tfg, 5/gl and here.
The structure scene is accessed in 3/tm2 and here.
§3. The following either/or property needs some compiler support:
+
§1. Introduction. Scenes are periods of time during play: at any given moment, several may be
+going on, or none. They are started and stopped when certain conditions are
+met, or by virtue of having been anchored together. All of this takes compiler
+support: unlike most of the plugins in the if module, this one code-generates
+to non-trivial functions as well as tables of data.
§5. Scenes are similarly numbered and stored in their own kind:
-actually, they are for practical purposes a built-in enumeration kind.
-
-
-
-kind *K_scene = NULL;
-
-
§6. At run-time, we need to store information about the current state of each
-scene: whether it is currently playing or not, when the last change occurred,
-and so on. This data is stored in I6 arrays as follows:
-
-
-
First, each scene has a unique ID number, used as an index X to these arrays.
-This ID number is what is stored as an I6 value for the kind of value scene,
-and it agrees with the allocation ID for the I7 scene structure.
-
-
-
scene_status-->X is 0 if the scene is not playing, but may do so in future;
-1 if the scene is playing; or 2 if the scene is not playing and will never
-play again.
-
-
-
scene_started-->X is the value of the_time when the scene last started,
-or 0 if it has never started.
-
-
-
scene_ended-->X is the value of the_time when the scene last ended,
-or 0 if it has never ended. (The "starting" end does not count as ending
-for this purpose.)
-
-
-
scene_endings-->X is a bitmap recording which ends have been used,
-including bit 1 which records whether the scene has started.
-
-
-
scene_latest_ending-->X holds the end number of the most recent ending
-(or 0 if the scene has never ended).
-
§4. Scenes are the instances of a built-in enumeration kind, created by a
+Neptune file belonging to WorldModelKit, and this is recognised by its
+Inter identifier SCENE_TY.
§7. The following either/or property needs some compiler support:
+
+
+
+property *P_recurring = NULL;
+
+
§8. This is a property name to do with scenes which Inform provides special
support for; it recognises the English name when it is defined by the
Standard Rules. (So there is no need to translate this to other languages.)
@@ -245,10 +170,10 @@ Standard Rules. (So there is no need to translate this to other languages.)
recurring
-intPL::Scenes::scenes_new_property_notify(property *prn) {
+intScenes::new_property_notify(property *prn) {if (<notable-scene-properties>(prn->name)) {switch (<<r>>) {case0: P_recurring = prn; break;
@@ -257,34 +182,75 @@ Standard Rules. (So there is no need to translate this to other languages.)
returnFALSE;}
-
§14. Scene structures are automatically created whenever a new instance of the
-kind "scene" is created, and this is where that happens.
+
§10. Conceptual model of scenes. Scenes are gated intervals of time, but there are more than two gates: for
+while there is only one past, there are many possible futures. These gates
+are called "ends" in the code below, and are numbered end 0 (the beginning),
+end 1 (the usual end), and then any named ends ("ends badly" or "ends
+triumphantly", for instance, might be ends 2 and 3). Each end has a condition
+which can cause it, or can be "anchored" to any number of ends of other
+scenes — to express which, the scene_connector structure is used.
+
defineMAX_SCENE_ENDS32 this must exceed 31
+
-intPL::Scenes::scenes_new_named_instance_notify(instance *I) {
-if ((K_scene) && (Kinds::eq(Instances::to_kind(I), K_scene))) {
-PL::Scenes::new_scene(I);
-returnTRUE;
- }
-returnFALSE;
+typedefstructscene {
+structinstance *as_instance; the constant for the name of the scene
+intonce_only; cannot repeat during play
+intstart_of_play; if begins when play begins
+intmarker; used to detect potentially infinite recursion when scene changes occur
+intno_ends; how many ends the scene has
+structscene_endends[MAX_SCENE_ENDS];
+intindexed; temporary storage during Scenes index creation
+CLASS_DEFINITION
+} scene;
+
+typedefstructscene_end {
+structwordingend_names; for ends 2, 3, ...: e.g. "badly"
+structrulebook *end_rulebook; rules to apply then
+structparse_node *anchor_condition;
+structscene_connector *anchor_connectors; linked list
+structparse_node *anchor_condition_set; where set
+CLASS_DEFINITION
+} scene_end;
+
+typedefstructscene_connector {
+structscene *connect_to; scene connected to
+intend; end number: see above
+structscene_connector *next; next in list of connectors for a scene end
+structparse_node *where_said; where this linkage was specified in source
+} scene_connector;
+
+scene *SC_entire_game = NULL;
+
+wordingScenes::get_name(scene *sc) {
+returnInstances::get_name(sc->as_instance, FALSE);}
-
§15. Scene structures. As we've seen, the following is called whenever a new instance of "scene"
+
The structure scene is private to this section.
The structure scene_end is private to this section.
The structure scene_connector is accessed in 2/ri, 3/tm, 3/ts, 4/act, 4/anl, 4/ap2, 4/nap, 5/tfg, 5/gl and here.
+
§11. A plugin called xyzzy generally has a hunk of subject data called xyzzy_data,
+so we would normally have a structure called scenes_data, but in fact that
+structure is just going to be scene. So:
+
§12.2. This is a scene name which Inform provides special support for; it recognises
the English name when it is defined by the Standard Rules. (So there is no need
to translate this to other languages.)
@@ -311,7 +275,7 @@ to translate this to other languages.)
entiregame
§17.1. Issue a too-many-ends problem message17.1 =
+
§14.1. Issue a too-many-ends problem message14.1 =
@@ -370,28 +329,28 @@ to translate this to other languages.)
"count as two of those, so you can only name up to 13 or 29 more specific ""ways for the scene to end.)");
§18.1. For example, if a scene is called "Banquet Entertainment" and it ends
+
§15.1. For example, if a scene is called "Banquet Entertainment" and it ends
"merrily", then the rulebook has two names: "when Banquet Entertainment
ends merrily" and "when the Banquet Entertainment ends merrily".
-
Compose a name and alternate name for the new scene end rulebook18.1 =
+
Compose a name and alternate name for the new scene end rulebook15.1 =
@@ -401,7 +360,7 @@ ends merrily" and "when the Banquet Entertainment ends merrily".
Feeds::feed_C_string_expanding_strings(L"when");Feeds::feed_wording(NW);Feeds::feed_C_string_expanding_strings((end==0)?L"begins":L"ends");
-if (end >= 2) Feeds::feed_wording(sc->end_names[end]);
+if (end >= 2) Feeds::feed_wording(sc->ends[end].end_names);RW = Feeds::end(id);id = Feeds::begin();
@@ -409,11 +368,11 @@ ends merrily" and "when the Banquet Entertainment ends merrily".
NW = Instances::get_name(sc->as_instance, FALSE);Feeds::feed_wording(NW);Feeds::feed_C_string_expanding_strings((end==0)?L"begins":L"ends");
-if (end >= 2) Feeds::feed_wording(sc->end_names[end]);
+if (end >= 2) Feeds::feed_wording(sc->ends[end].end_names);AW = Feeds::end(id);
§15.2. Define phrases detecting whether or not the scene has ended this way15.2 =
@@ -424,7 +383,7 @@ ends merrily" and "when the Banquet Entertainment ends merrily".
Feeds::feed_C_string_expanding_strings(L"To decide if (S - ");Feeds::feed_wording(NW);Feeds::feed_C_string_expanding_strings(L") ended ");
-Feeds::feed_wording(sc->end_names[end]);
+Feeds::feed_wording(sc->ends[end].end_names);Sentences::make_node(Task::syntax_tree(), Feeds::end(id), ':');id = Feeds::begin();
@@ -438,7 +397,7 @@ ends merrily" and "when the Banquet Entertainment ends merrily".
Feeds::feed_C_string_expanding_strings(L"To decide if (S - ");Feeds::feed_wording(NW);Feeds::feed_C_string_expanding_strings(L") did not end ");
-Feeds::feed_wording(sc->end_names[end]);
+Feeds::feed_wording(sc->ends[end].end_names);Sentences::make_node(Task::syntax_tree(), Feeds::end(id), ':');id = Feeds::begin();
@@ -450,14 +409,23 @@ ends merrily" and "when the Banquet Entertainment ends merrily".
RuleSubtrees::register_recently_lexed_phrases();DISCARD_TEXT(i6_code)
§19. Anchors. These are joins between the endings of different scenes, and there are two
-assertion sentences to create them. This handles the special meaning "X
-begins when...".
+
§24. The following is elementary enough, but we want to be careful because
+
§22. The following is elementary enough, but we want to be careful because
there are possible ambiguities: the condition might contain the word "ends"
in a different context, for instance, and could still be valid in that case.
@@ -615,8 +585,8 @@ in a different context, for instance, and could still be valid in that case.
"when...' or 'Confrontation ends tragically when...'."); ==> { -1, - };
§24. Lastly, scene end names are parsed by these internals. They are identical
except that the creating case will create a new end if need be so that it
never fails.
§25.2. Make this an external scene end condition25.2 =
-if (this_scene->anchor_condition[end])
-StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_ScenesOversetEnd),
+if (this_scene->ends[end].anchor_condition)
+StandardProblems::sentence_problem(Task::syntax_tree(),
+_p_(PM_ScenesOversetEnd),"you have already told me a condition for when that happens","and although a scene can be linked to the beginning or ending ""of any number of other scenes, it can only have a single ""condition such as 'when the player is in the Dining Car' ""to trigger it from outside the scene machinery.");
-this_scene->anchor_condition[end] = external_condition;
-this_scene->anchor_condition_set[end] = current_sentence;
+this_scene->ends[end].anchor_condition = external_condition;
+this_scene->ends[end].anchor_condition_set = current_sentence;
§28. Scene-changing machinery at run-time. So what are scenes for? Well, they have two uses. One is that the end rulebooks
-are run when ends occur, which is a convenient way to time events. The
-following generates the necessary code to (a) detect when a scene end occurs,
-and (b) act upon it. This is all handled by the following I6 routine.
-
-
-
There is one argument, chs: the number of iterations so far. Iterations occur
-because each set of scene changes could change the circumstances in such a
-way that other scene changes are now required (through external conditions,
-not through anchors); we don't want this to lock up, so we will cap recursion.
-Within the routine, a second local variable, ch, is a flag indicating
-whether any change in status has or has not occurred.
-
-
-
There is no significance to the return value.
-
-
-
defineMAX_SCENE_CHANGE_ITERATION20
-
-
-voidPL::Scenes::DetectSceneChange_routine(void) {
-inter_name *iname = Hierarchy::find(DETECTSCENECHANGE_HL);
-packaging_statesave = Routines::begin(iname);
-inter_symbol *chs_s = LocalVariables::add_internal_local_c_as_symbol(I"chs", "count of changes made");
-inter_symbol *ch_s = LocalVariables::add_internal_local_c_as_symbol(I"ch", "flag: change made");
-inter_symbol *CScene_l = Produce::reserve_label(Emit::tree(), I".CScene");
-
-scene *sc;
-LOOP_OVER(sc, scene) Compile code detecting the ends of a specific scene28.2;
-
-Produce::place_label(Emit::tree(), CScene_l);
-Add the scene-change tail28.1;
-
-Routines::end(save);
-Hierarchy::make_available(Emit::tree(), iname);
-}
-
§28.2. Recall that ends numbered 1, 2, 3, ... are all ways for the scene to end,
-so they are only checked if its status is currently running; end 0 is the
-beginning, checked only if it isn't. We give priority to the higher end
-numbers so that more abstruse ways to end take precedence over less.
-
-
-
Compile code detecting the ends of a specific scene28.2 =
-
§29. Individual ends are tested here. There are actually three ways an end can
-occur: at start of play (for end 0 only), when an I7 condition holds, or when
-another end to which it is anchored also ends. But we only check the first
-two, because the third way will be taken care of by the consequences code
-below.
-
-
-
-voidPL::Scenes::test_scene_end(scene *sc, intend, inter_symbol *ch_s, inter_symbol *CScene_l) {
-if ((end == 0) && (sc->start_of_play)) {
-Produce::inv_primitive(Emit::tree(), IF_BIP);
-Produce::down(Emit::tree());
-Produce::inv_primitive(Emit::tree(), EQ_BIP);
-Produce::down(Emit::tree());
-Produce::inv_primitive(Emit::tree(), BITWISEAND_BIP);
-Produce::down(Emit::tree());
-Produce::inv_primitive(Emit::tree(), LOOKUP_BIP);
-Produce::down(Emit::tree());
-Produce::val_iname(Emit::tree(), K_object, Hierarchy::find(SCENE_ENDINGS_HL));
-Produce::val(Emit::tree(), K_number, LITERAL_IVAL, (inter_ti) sc->allocation_id);
-Produce::up(Emit::tree());
-Produce::val(Emit::tree(), K_number, LITERAL_IVAL, 1);
-Produce::up(Emit::tree());
-Produce::val(Emit::tree(), K_number, LITERAL_IVAL, 0);
-Produce::up(Emit::tree());
-Produce::code(Emit::tree());
-Produce::down(Emit::tree());
-PL::Scenes::compile_scene_end(sc, 0);
-Produce::up(Emit::tree());
-Produce::up(Emit::tree());
- }
-parse_node *S = sc->anchor_condition[end];
-if (S) {
-Reparse the scene end condition in this new context29.1;
-Compile code to test the scene end condition29.2;
- }
-}
-
-
§29.1. Reparse the scene end condition in this new context29.1 =
-
-
-
-current_sentence = sc->anchor_condition_set[end];
-if (Node::is(S, UNKNOWN_NT)) {
-if (<s-condition>(Node::get_text(S))) S = <<rp>>;
-sc->anchor_condition[end] = S;
- }
-if (Node::is(S, UNKNOWN_NT)) {
-LOG("Condition: $P\n", S);
-StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_ScenesBadCondition),
-"'begins when' and 'ends when' must be followed by a condition",
-"which this does not seem to be, or else 'when play begins', "
-"'when play ends', 'when S begins', or 'when S ends', where "
-"S is the name of any scene.");
-return;
- }
-
-if (Dash::check_condition(S) == FALSE) return;
-
§29.2. If the condition holds, we set the change flag ch and abort the search
-through scenes by jumping past the run of tests. (We can't compile a break
-instruction because we're not compiling a loop.)
-
-
-
Compile code to test the scene end condition29.2 =
-
§30. That's everything except for the consequences of a scene end occurring.
-Code for that is generated here.
-
-
-
Because one end can cause another, given anchoring, we must guard against
-compiler hangs when the source text calls for infinite recursion (since
-this would cause us to generate infinitely long code). So the marker flags
-are used to mark which scenes have already been ended in code generated
-for this purpose.
-
§31. The semantics of scene ending are trickier than they look, because of the
-fact that "Ballroom Dance ends merrily" (say, end number 3) is in some
-sense a specialisation of "Ballroom Dance ends" (1). The doctrine is that
-end 3 causes end 1 to happen first, because a special ending is also a
-general ending; but rules taking effect on end 3 come earlier than
-those for end 1, because they're more specialised, so they have a right to
-take effect first.
-
§31.1. If the scene has the "recurring" either/or property, then any of the
-"ends" endings will fail to reset its status. (This doesn't mean that no
-end actually occurred.)
-
§31.5. In general, the marker count is used to ensure that PL::Scenes::compile_scene_end_dash
-never calls itself for a scene it has been called with before on this round.
-This prevents Inform locking up generating infinite amounts of code. However,
-one exception is allowed, in very limited circumstances. Suppose we want to
-make a scene recur, but only if it ends in a particular way. Then we might
-type:
-
-
-
-
Brisk Quadrille begins when Brisk Quadrille ends untidily.
-
-
-
This is allowed; it's a case where the "tolerance" below is raised.
-
-
-
Compile code to cause consequent scene ends31.5 =
-
§32. More SCENES output. As we've seen, when the SCENES command has been typed, Inform prints a notice
-out at run-time when any scene end occurs. It also prints a run-down of the
-scene status at the moment the command is typed, and the following code is
-what handles this.
-
§33. During clauses. We've now seen one use of scenes: they kick off rulebooks when they begin or
-end. The other use for them is to predicate rules on whether they are currently
-playing or not, using a "during" clause.
-
-
-
We allow these either to name a specific scene, or to describe a collection
-of them:
+
§26. One use of scenes is to kick off rulebooks when they begin or end. The other
+use for them is to predicate rules on whether they are currently playing or
+not, using a "during" clause, and this is used when parsing those in rule
+headers. Note that a match here can name a specific scene, or describe a
+collection of them:
diff --git a/docs/if-module/3-sm.html b/docs/if-module/3-sm.html
index d36d35529..6b9eab104 100644
--- a/docs/if-module/3-sm.html
+++ b/docs/if-module/3-sm.html
@@ -209,7 +209,7 @@ of vehicle, and so on, but this would cause mayhem in the model world. So:
diff --git a/docs/if-module/3-tm.html b/docs/if-module/3-tm.html
index 282fa1988..39f02947e 100644
--- a/docs/if-module/3-tm.html
+++ b/docs/if-module/3-tm.html
@@ -127,12 +127,12 @@ quite specific problem messages.
}
§2. This special sentence is used as a hint in making map documents; it has no
-effect on the world model itself, and so is dealt with elsewhere, in EPS Map.
+effect on the world model itself, and so is dealt with elsewhere, in EPS Map (in index).
@@ -163,7 +163,7 @@ using directions to imply relations, as in "East of Eden is the Land of Nod."
returnFALSE; }direction_relations_noticed[no_directions_noticed] =
-PL::MapDirections::create_sketchy_mapping_direction(Node::get_text(pn));
+MapRelations::create_sketchy_mapping_direction(Node::get_text(pn));directions_noticed[no_directions_noticed++] = pn;returnFALSE;}
@@ -174,7 +174,7 @@ makes for more legible code if we use a special inference family of our own:
-inference_family *direction_inf = NULL; 100; where do map connections from O lead?
+inference_family *direction_inf = NULL; where do map connections from O lead?
§5.
@@ -338,7 +338,7 @@ Rules. (So there is no need to translate this to other languages.)
InstanceSubjects::to_object_instance(infs));}
-intMap::instance_is_a_door(instance *I) {
+intMap::instance_is_a_door(instance *I) {if ((PluginManager::active(map_plugin)) && (K_door) && (I) && (Instances::of_kind(I, K_door)))returnTRUE;
@@ -365,7 +365,7 @@ we will assign it a number:
intregistered_directions = 0; next direction number to be free
-intMap::number_of_directions(void) {
+intMap::number_of_directions(void) {returnregistered_directions;}
§18. Map data on instances. We will use quite a lot of temporary work-space to put all of this together,
@@ -465,24 +465,24 @@ isn't.
structinstance *spatial_relationship[12];intexit_lengths[MAX_DIRECTIONS];structinstance *lock_exits[MAX_DIRECTIONS];
-structvectorposition;
-structvectorsaved_gridpos;
+structvectorposition;
+structvectorsaved_gridpos;intcooled, shifted, zone;
-structconnected_submap *submap;
+structconnected_submap *submap;structinstance *next_room_in_submap;wchar_t *world_index_colour; an HTML colour for the room square (rooms only)wchar_t *world_index_text_colour; an HTML colour for the room text (rooms only)
-structmap_parameter_scopelocal_map_parameters; temporary: used in EPS mapping
+structmap_parameter_scopelocal_map_parameters; temporary: used in EPS mappinginteps_x, eps_y;CLASS_DEFINITION} map_data;
-
The structure map_data is accessed in 3/mcr, 3/sm2, 3/hm, 3/em and here.
+
The structure map_data is accessed in 3/mcr and here.
§19.
-intMap::new_subject_notify(inference_subject *subj) {
+intMap::new_subject_notify(inference_subject *subj) {map_data *md = CREATE(map_data);md->map_connection_a = NULL; md->map_connection_b = NULL;md->map_direction_a = NULL; md->map_direction_b = NULL;
@@ -496,7 +496,7 @@ isn't.
md->exits[i] = NULL; }
-PL::SpatialMap::initialise_mapping_data(md);
+PL::SpatialMap::initialise_mapping_data(md);ATTACH_PLUGIN_DATA_TO_SUBJECT(map, subj, md);returnFALSE;}
@@ -530,7 +530,7 @@ Standard Rules. (So there is no need to translate this to other languages.)
§22.
-intMap::new_property_notify(property *prn) {
+intMap::new_property_notify(property *prn) {if (<notable-map-properties>(prn->name)) {switch (<<r>>) {case0: P_opposite = prn; break;
@@ -546,7 +546,7 @@ the map plugin is inactive; so you can still have backdrops without a map.
-voidMap::set_found_in(instance *I, parse_node *val) {
+voidMap::set_found_in(instance *I, parse_node *val) {if (P_found_in == NULL)P_found_in = ValueProperties::new_nameless(I"found_in",K_value);
@@ -561,7 +561,7 @@ always another direction: for example, the opposite of northwest is southeast.
-instance *Map::get_value_of_opposite_property(instance *I) {
+instance *Map::get_value_of_opposite_property(instance *I) {parse_node *val = PropertyInferences::value_of(Instances::as_subject(I), P_opposite);if (val) returnRvalues::to_object_instance(val);
@@ -576,14 +576,14 @@ noted above are keys into these arrays.
It might look a little wasteful of I7's memory to expand the direction
inferences, a nicely compact representation, into large and sparse arrays.
But it's convenient, and profiling suggests that the memory overhead is not
-significant. It also means that the Spatial Map mapping code, which contains
-quite crunchy algorithms, has the fastest possible access to the layout.
+significant. It also means that the Spatial Map (in index) mapping code, which
+contains quite crunchy algorithms, has the fastest possible access to the layout.
defineMAP_EXIT(X, Y) MAP_DATA(X)->exits[Y]
-voidMap::build_exits_array(void) {
+voidMap::build_exits_array(void) {instance *I;intd = 0;LOOP_OVER_INSTANCES(I, K_object) {
@@ -619,7 +619,7 @@ object has four pieces of data attached:
diff --git a/docs/if-module/3-tp.html b/docs/if-module/3-tp.html
index b7bbb8540..4ebd8cd68 100644
--- a/docs/if-module/3-tp.html
+++ b/docs/if-module/3-tp.html
@@ -180,7 +180,7 @@ is created in English.)
returnFALSE;}
-instance *Player::get_start_room(void) {
+instance *Player::get_start_room(void) {returnstart_room;}
@@ -236,7 +236,7 @@ aliasing.
-intPlayer::variable_set_warning(nonlocal_variable *nlv, parse_node *val) {
+intPlayer::variable_set_warning(nonlocal_variable *nlv, parse_node *val) {if (nlv == player_VAR) {instance *npc = Rvalues::to_object_instance(val);if (npc) {
@@ -276,7 +276,7 @@ that is, when the source text explicitly sets a value for "player".
-intPlayer::detect_bodysnatching(inference_subject *body, int *snatcher,
+intPlayer::detect_bodysnatching(inference_subject *body, int *snatcher,inference_subject **counterpart) {if ((player_character_object == I_yourself) || (player_character_object == NULL) || (I_yourself == NULL)) returnFALSE;
@@ -316,7 +316,7 @@ ensure that assemblies such as "A nose is part of every person" produces
-intPlayer::irregular_genitive(inference_subject *owner, text_stream *genitive,
+intPlayer::irregular_genitive(inference_subject *owner, text_stream *genitive,int *propriety) {if (owner == Instances::as_subject(I_yourself)) {WRITE_TO(genitive, "your ");
@@ -351,7 +351,7 @@ and people still sometimes type it.
§9.
-intPlayer::refine_implicit_noun(parse_node *p) {
+intPlayer::refine_implicit_noun(parse_node *p) {if (<implicit-player-relationship>(Node::get_text(p))) {Refiner::give_subject_to_noun(p, Instances::as_subject(player_character_object));returnTRUE;
@@ -374,7 +374,7 @@ we assume he is freestanding in the earliest defined room.
§1. At one time, all interactive fiction had a scoring system, because that's
+what computers did for our entertainment: they rewarded us with points. Having
+its distant roots in that period, Inform handles a numerical score with just
+a little compiler support, and this is where.
+
§2. For many years this was a defined I6 constant, but then people sent in bug
-reports asking why it wouldn't change in play.
+
§2. For many years "maximum score" was compiled to a constant, but then people sent
+in bug reports asking why it wouldn't change in play. "Score", of course, is
+more evidently variable.
@@ -106,10 +109,14 @@ reports asking why it wouldn't change in play.
maximumscore
§4. These are marked "initialisable" because of the way they are implemented at
+run-time, using special variables in WorldModelKit rather than being
+storage allocated by I7. Variables stored that way would not ordinarily be
+possible to give values to in I7 assertions; but these are.
+
§5. The maximum score and rankings table. A special rule is that if a table is called "Rankings" and contains a column
+
§5. A special rule is that if a table is called "Rankings" and contains a column
of numbers followed by a column of text, then it is used by the run-time
scoring system. In retrospect, Inform really shouldn't support this at the
-compiler level (not that it does much), and in any case it's a very old-school
-idea of IF. Still, it does little harm.
+compiler level (not that it does much), but it does little harm.
@@ -137,53 +143,37 @@ idea of IF. Still, it does little harm.
rankings
§6. This can only happen if we declare it somehow in I6 code, which
-we do with the constant RANKING_TABLE. We also set the MAX_SCORE variable
-equal to the number in the bottom row of the table, which is assumed to be the
-score corresponding to successful completion and the highest rank.
+
§6. Nothing will happen unless a table has both this magic name, and also the
+right shape: two columns, number then text. If so, the maximum score is
+initialised to the number in the final row of the table, which is assumed to
+be the score corresponding to successful completion and the highest rank.
+
+
+
The test case Cooking, an example from the documentation, tests this.
diff --git a/docs/if-module/4-act.html b/docs/if-module/4-act.html
index 14867d1fe..5b717421d 100644
--- a/docs/if-module/4-act.html
+++ b/docs/if-module/4-act.html
@@ -138,7 +138,7 @@ and maximum below are always equal.
CLASS_DEFINITION} action_name;
-
The structure action_name is accessed in 2/bd, 3/sm, 3/tp, 3/bck, 3/rgn, 3/tm, 3/em, 3/sc, 3/scn, 3/ts, 4/anaa, 4/anl, 4/nap, 4/ai, 5/pp, 5/gv, 5/gl, 5/gpr and here.
+
The structure action_name is accessed in 2/bd, 3/sm, 3/tp, 3/bck, 3/rgn, 3/tm, 3/scn, 3/ts, 4/anaa, 4/anl, 4/nap, 4/ai, 5/pp, 5/gv, 5/gl, 5/gpr and here.
§3.
diff --git a/docs/if-module/4-anl.html b/docs/if-module/4-anl.html
index 8be7cebb5..4e7097e8b 100644
--- a/docs/if-module/4-anl.html
+++ b/docs/if-module/4-anl.html
@@ -107,7 +107,7 @@ MathJax = {
intdelete_this_link; used temporarily during parsing} action_name_list;
-
The structure action_name_list is accessed in 2/ri, 3/tm, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/ap2, 4/nap, 5/tfg, 5/gl and here.
+
The structure action_name_list is accessed in 2/ri, 3/tm, 3/scn, 3/ts, 4/act, 4/ap2, 4/nap, 5/tfg, 5/gl and here.
§2. The action name list is the part of an action pattern identifying
which actions are allowed: "taking, dropping or examining" for
example. The following routine extracts this from a potentially longer
diff --git a/docs/if-module/4-ap2.html b/docs/if-module/4-ap2.html
index ce95fcb04..bf7c64ab4 100644
--- a/docs/if-module/4-ap2.html
+++ b/docs/if-module/4-ap2.html
@@ -151,7 +151,7 @@ not-really-action APs are used in no other context, and employ the
CLASS_DEFINITION} ap_optional_clause;
-
The structure action_pattern is accessed in 2/ri, 3/tm, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/anl, 4/nap, 5/tfg, 5/gl and here.
The structure ap_optional_clause is accessed in 2/ri, 3/tm, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/anl, 4/nap, 5/tfg, 5/gl and here.
+
The structure action_pattern is accessed in 2/ri, 3/tm, 3/scn, 3/ts, 4/act, 4/anl, 4/nap, 5/tfg, 5/gl and here.
The structure ap_optional_clause is accessed in 2/ri, 3/tm, 3/scn, 3/ts, 4/act, 4/anl, 4/nap, 5/tfg, 5/gl and here.
§2. When we parse action patterns, we record why they fail, in order to make
it easier to produce helpful error messages. (We can't simply fire off
errors at the time they occur, because text is often parsed in several
diff --git a/docs/if-module/4-nap.html b/docs/if-module/4-nap.html
index cda0f8368..9d0fea9cf 100644
--- a/docs/if-module/4-nap.html
+++ b/docs/if-module/4-nap.html
@@ -85,7 +85,7 @@ function togglePopup(material_id) {
CLASS_DEFINITION} named_action_pattern;
-
The structure named_action_pattern is accessed in 2/bd, 3/sm, 3/tp, 3/bck, 3/rgn, 3/tm, 3/em, 3/sc, 3/scn, 3/ts, 4/anaa, 4/act, 4/anl, 5/pp, 5/gv, 5/gpr and here.
+
The structure named_action_pattern is accessed in 2/bd, 3/sm, 3/tp, 3/bck, 3/rgn, 3/tm, 3/scn, 3/ts, 4/anaa, 4/act, 4/anl, 5/pp, 5/gv, 5/gpr and here.
§2.
diff --git a/docs/if-module/5-gv.html b/docs/if-module/5-gv.html
index 90ef57454..d4a68c95a 100644
--- a/docs/if-module/5-gv.html
+++ b/docs/if-module/5-gv.html
@@ -126,7 +126,7 @@ of these is associated with a genuine typed-by-the-player command verb:
CLASS_DEFINITION} grammar_verb;
-
The structure grammar_verb is accessed in 2/bd, 3/sm, 3/tp, 3/bck, 3/rgn, 3/tm, 3/em, 3/sc, 3/scn, 3/ts, 4/anaa, 4/act, 4/anl, 4/nap, 5/pp, 5/gpr and here.
+
The structure grammar_verb is accessed in 2/bd, 3/sm, 3/tp, 3/bck, 3/rgn, 3/tm, 3/scn, 3/ts, 4/anaa, 4/act, 4/anl, 4/nap, 5/pp, 5/gpr and here.
§3. A few imperative verbs are reserved for Inform testing, such as SHOWME.
We record those as instances of the following:
The structure understanding_item is accessed in 2/ri, 3/tm, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/anl, 4/ap2, 4/nap, 5/gl and here.
The structure understanding_reference is accessed in 2/ri, 3/tm, 3/em, 3/scn, 3/tm2, 3/ts, 4/act, 4/anl, 4/ap2, 4/nap, 5/gl and here.
+
The structure understanding_item is accessed in 2/ri, 3/tm, 3/scn, 3/ts, 4/act, 4/anl, 4/ap2, 4/nap, 5/gl and here.
The structure understanding_reference is accessed in 2/ri, 3/tm, 3/scn, 3/ts, 4/act, 4/anl, 4/ap2, 4/nap, 5/gl and here.
§3. New grammar arrives in the system in two ways: primarily by means of explicit
Understand sentences in the source text, but also secondarily in the form
of table entries or other values used to match against snippets. For example:
diff --git a/docs/if-module/index.html b/docs/if-module/index.html
index f064c43ae..ffa925653 100644
--- a/docs/if-module/index.html
+++ b/docs/if-module/index.html
@@ -171,45 +171,15 @@
Map Connection Relations -
To define one binary predicate for each map direction, such as "mapped north of".
-
-
- Spatial Geometry -
- To deal with vectors and cuboids in a three-dimensional integer lattice.
-
-
-
- Spatial Map -
- To fit the map of the rooms in the game into a cubical grid, preserving distances and angles where possible, and so to give each room approximate coordinate locations.
-
-
-
- HTML Map -
- To render the spatial map of rooms as HTML.
-
-
-
- EPS Map -
- To render the spatial map of rooms as an EPS (Encapsulated PostScript) file.
-
-
-
- Showme Command -
- A plugin to provide some support for the SHOWME testing command.
-
Scenes -
- Scenes are periods of time during play: at any given moment, several may be going on, or none. They are started and stopped when certain conditions are met, or by virtue of having been anchored together.
-
-
-
- Temporal Map -
- Parallel to the World index of space is the Scenes index of time, and in this section we render it as HTML.
+ A plugin to support named periods of time during an interactive story.
The Score -
- A plugin to support the maximum score variable.
+ A plugin to support the score variables.
diff --git a/docs/imperative-module/2-rls.html b/docs/imperative-module/2-rls.html
index 54c5955f3..c74500b0d 100644
--- a/docs/imperative-module/2-rls.html
+++ b/docs/imperative-module/2-rls.html
@@ -907,7 +907,7 @@ as the definition of the rule in future.
#ifdefIF_MODULEif (rc.scene_context) {WRITE(" during ");
-wordingSW = PL::Scenes::get_name(rc.scene_context);
+wordingSW = Scenes::get_name(rc.scene_context);WRITE("%+W", SW); } #endif
diff --git a/docs/imperative-module/3-prcd.html b/docs/imperative-module/3-prcd.html
index 94b8916d9..503706ece 100644
--- a/docs/imperative-module/3-prcd.html
+++ b/docs/imperative-module/3-prcd.html
@@ -234,7 +234,7 @@ extracts a single specified scene if there is one:
if (phrcd == NULL) returnNULL;if (Rvalues::is_rvalue(phrcd->during_scene)) {instance *q = Rvalues::to_instance(phrcd->during_scene);
-if (q) returnPL::Scenes::from_named_constant(q);
+if (q) returnScenes::from_named_constant(q); }returnNULL;}
@@ -510,7 +510,7 @@ with the default outcome return (see above).
Produce::inv_primitive(Emit::tree(), IFELSE_BIP);Produce::down(Emit::tree());
-PL::Scenes::emit_during_clause(phrcd->during_scene);
+RTScenes::emit_during_clause(phrcd->during_scene);Produce::code(Emit::tree());Produce::down(Emit::tree());
diff --git a/docs/index-module/1-im.html b/docs/index-module/1-im.html
index a2cfa1f32..e1c3f86f8 100644
--- a/docs/index-module/1-im.html
+++ b/docs/index-module/1-im.html
@@ -95,7 +95,7 @@ which use this module:
}
diff --git a/docs/index-module/2-adj.html b/docs/index-module/2-adj.html
index d258a0308..ff1a2bcd5 100644
--- a/docs/index-module/2-adj.html
+++ b/docs/index-module/2-adj.html
@@ -104,7 +104,7 @@ prefaced "(of a rulebook)", "(of an activity)", and so on.
diff --git a/docs/index-module/2-dr.html b/docs/index-module/2-dr.html
index fcff6169f..1ab893dc7 100644
--- a/docs/index-module/2-dr.html
+++ b/docs/index-module/2-dr.html
@@ -472,7 +472,7 @@ and we need to search fairly seldom:
diff --git a/docs/index-module/2-ih.html b/docs/index-module/2-ih.html
index 6d11e3503..fab87286a 100644
--- a/docs/index-module/2-ih.html
+++ b/docs/index-module/2-ih.html
@@ -169,7 +169,7 @@ surreptitiously check that it is correctly formed at the same time.
}}
-
The structure contents_entry is accessed in 2/ins and here.
+
The structure contents_entry is accessed in 2/ins, 3/scn, 4/em and here.
§3.1. Index this entry in the contents3.1 =
@@ -350,7 +350,7 @@ but should this arise then the best recourse is to ignore the heading.
diff --git a/docs/index-module/2-inf.html b/docs/index-module/2-inf.html
index 6af7ad059..ff23c002f 100644
--- a/docs/index-module/2-inf.html
+++ b/docs/index-module/2-inf.html
@@ -128,13 +128,13 @@ state of being boolean, and the given certainty levels:
if (f) { WRITE("<i>%s</i> ", cert); f = FALSE; }elseWRITE(", ");
-WRITE("%+W", prn->name);
+WRITE("%+W", prn->name);IXProperties::set_indexed_already_flag(prn, TRUE);if (Properties::is_either_or(prn)) {property *prnbar = EitherOrProperties::get_negation(prn);if (prnbar) {
-WRITE(" <i>not</i> %+W", prnbar->name);
+WRITE(" <i>not</i> %+W", prnbar->name);IXProperties::set_indexed_already_flag(prnbar, TRUE); } } else {
@@ -169,7 +169,7 @@ state of being boolean, and the given certainty levels:
if (k == 1) HTML::open_indented_p(OUT, 1, "hanging");elseWRITE("; ");if (S < 0) WRITE("not ");
-WRITE("%+W", prn->name);
+WRITE("%+W", prn->name);if (P) Index::link(OUT, Wordings::first_wn(Node::get_text(P))); } }
@@ -183,7 +183,7 @@ state of being boolean, and the given certainty levels:
parse_node *S = PropertyInferences::value_and_where_without_inheritance(infs, prn, &P);if ((S) && (Wordings::nonempty(Node::get_text(S)))) {HTML::open_indented_p(OUT, 1, "hanging");
-WRITE("%+W: ", prn->name);
+WRITE("%+W: ", prn->name);HTML::begin_colour(OUT, I"000080");WRITE("%+W", Node::get_text(S));HTML::end_colour(OUT);
@@ -194,7 +194,7 @@ state of being boolean, and the given certainty levels:
}
diff --git a/docs/index-module/2-li.html b/docs/index-module/2-li.html
index 854d34d98..41edec251 100644
--- a/docs/index-module/2-li.html
+++ b/docs/index-module/2-li.html
@@ -654,7 +654,7 @@ be able to print out a table of just those verbs created in that extension.
}
§1. The mapping of time is on the one hand simpler than the mapping of space
since there is only one dimension, but on the other hand more complex since
@@ -83,21 +83,21 @@ seems natural enough to learn in practice.
§1.2. The sorted ordering is used as-is later on, when we get to the details, but
for the tabulation it's refined further. First we have the start-of-play
scenes, in sorted order; then scenes with a condition for their beginning
@@ -126,53 +126,52 @@ about and created but never made use of.)
HTML_OPEN("p");
-Index::anchor(OUT, I"SRULES");
+Index::anchor(OUT, I"SRULES");WRITE("<b>General rules applying to scene changes</b>");HTML_CLOSE("p");Rulebooks::index_rules_box(OUT, "When a scene begins", EMPTY_WORDING, NULL,
@@ -180,20 +179,19 @@ about and created but never made use of.)
Rulebooks::index_rules_box(OUT, "When a scene ends", EMPTY_WORDING, NULL,built_in_rulebooks[WHEN_SCENE_ENDS_RB], NULL, NULL, 1, FALSE);
§1.5.1. The curious condition about end 1 here is to avoid printing "Ends: Never"
in cases where fancier ends for the scene exist, so that the scene can, in
fact, end.
@@ -203,34 +201,33 @@ fact, end.
§2. Table of Scenes. We finally return to the table of scenes. The following is recursive, and
is called at the top level for each scene in turn which starts at the start
of play (see above).
@@ -355,19 +351,19 @@ on the initial call when dept
defineNEVER_HAPPENS_END -2
§2.5. And this is where the routine recurses, so that consequent scenes are
tabulated underneath the present one, indented one step further in (since
indentation is coupled to depth). First we recurse to scenes which end when
@@ -431,40 +427,39 @@ this one does; then to scenes which begin when this one ends.
diff --git a/docs/index-module/3-spt.html b/docs/index-module/3-spt.html
index 58e16e603..2d2cb52e1 100644
--- a/docs/index-module/3-spt.html
+++ b/docs/index-module/3-spt.html
@@ -165,7 +165,7 @@ it already turns up under its owner.
}
§1. EPS-format files are vector art, rather than raster art, and are produced
with the intention that authors can tidy them up afterwards using programs
@@ -127,7 +127,7 @@ values inherited by sub-objects.
intnumeric_value; or numeric value, if appropriate to this type} plotting_parameter;
-
The structure plotting_parameter is accessed in 2/bd, 3/sm, 3/tp, 3/bck, 3/rgn, 3/tm, 3/sc, 3/scn, 3/ts, 4/anaa, 4/act, 4/anl, 4/nap, 5/pp, 5/gv, 5/gpr and here.
+
The structure plotting_parameter is accessed in 2/ie, 2/ins, 2/vrb, 2/prp, 2/inf, 3/fgr, 3/se, 3/ef and here.
§3. A set of variables associated with any map object is called a "scope".
As implied above, the global scope is special: it contains the default
settings passed down to all lower scopes.
@@ -221,7 +221,7 @@ hold the applicable mapping parameters.
CLASS_DEFINITION} EPS_map_level;
-
The structure EPS_map_level is accessed in 2/ri, 2/tir and here.
+
The structure EPS_map_level is private to this section.
§6. The following are the directions at which arrows for UP, DOWN, IN and OUT
are drawn on EPS maps.
-voidPL::EPSMap::prepare_map_parameter_scope(map_parameter_scope *scope) {
+voidPL::EPSMap::prepare_map_parameter_scope(map_parameter_scope *scope) {ints;scope->wider_scope = &global_map_scope;for (s=0; s<NO_MAP_PARAMETERS; s++) {
@@ -285,71 +285,71 @@ If all are null, then the global scope is used.
§19. The value of map settings is as follows. In retrospect, the "booleans"
perhaps should just have been "true" and "false", not "on" and "off".
Never mind.
@@ -629,7 +629,7 @@ offset or else the ER
§23. Offset notation. The offset parameter \((x, y)\) is stored as the integer \(10000y + x\). Except
for the error value, we are required to have \(-9999 \leq x, y \leq 9999\), and
the syntax to specify this is two literal numbers divided by an ampersand.
@@ -968,7 +968,7 @@ For instance, 28&-125defineERRONEOUS_OFFSET_VALUE100000000
§28. EPS header. EPS files are identified and version-numbered by a header, as follows.
-voidPL::EPSMap::EPS_compile_header(OUTPUT_STREAM, intbounding_box_width, intbounding_box_height,
+voidPL::EPSMap::EPS_compile_header(OUTPUT_STREAM, intbounding_box_width, intbounding_box_height,wchar_t *default_font, intdefault_point_size) {WRITE("%%!PS-Adobe EPSF-3.0\n");WRITE("%%%%BoundingBox: 0 0 %d %d\n", bounding_box_width, bounding_box_height);
@@ -1481,14 +1481,14 @@ closed (joined up back to the start position) with a
-voidPL::EPSMap::EPS_compile_circular_path(OUTPUT_STREAM, intx0, inty0, intradius) {
+voidPL::EPSMap::EPS_compile_circular_path(OUTPUT_STREAM, intx0, inty0, intradius) {WRITE("%d %d moveto %% rightmost point\n", x0+radius, y0);WRITE("%d %d %d %d %d arc %% full circle traced anticlockwise\n",x0, y0, radius, 0, 360);WRITE("closepath\n");}
-voidPL::EPSMap::EPS_compile_rectangular_path(OUTPUT_STREAM, intx0, inty0, intx1, inty1) {
+voidPL::EPSMap::EPS_compile_rectangular_path(OUTPUT_STREAM, intx0, inty0, intx1, inty1) {WRITE("%d %d moveto %% bottom left corner\n", x0, y0);WRITE("%d %d lineto %% bottom side\n", x1, y0);WRITE("%d %d lineto %% right side\n", x1, y1);
@@ -1500,21 +1500,21 @@ closed (joined up back to the start position) with a
§1. Building the grids. Three three-dimensional arrays called "grids" are used to store a rasterised
version of the map before we render this on screen.
@@ -109,40 +109,40 @@ i_2\leq 4\() associated with the room cell at \)(x, y, z)$.
this icon position, and has the same indexing as the icon grid.
@@ -151,7 +151,7 @@ this icon position, and has the same indexing as the icon grid.
LOOP_OVER_ROOMS(R)room_grid[ROOM_GRID_POS(Room_position(R))] = R;
-
§1.3.1. We next define constants needed for the icon bitmap. The information
we extract from the map exits is recorded in the low four bits as
follows:
@@ -212,7 +212,7 @@ stage can even begin.
§1.3.4.1. Suppose we are looking east from the Ballroom to the Kitchens. If the Kitchens
will indeed be plotted at the position directly east of the Ballroom, we award
the "adjacent" bit; if they will be plotted due east, but further away than
@@ -241,15 +241,15 @@ a single square distant, then we get the "aligned" bit as a consolation prize.
§1.3.4.2. If a different room altogether — say, the Tack Room — is being plotted one
square east of the Ballroom, even though the map connection leads to the
Kitchens, then we get the "fading" bit. (At one time connections like this
@@ -264,13 +264,13 @@ is east from B to K. If so, we get both the fading and aligned bits.
§2. A process called "pair correction" fills in the nuance bits for all
adjacent icons representing the same exit. Thus the east side icon of
one room may need to be married up with the west side icon of the
@@ -309,19 +309,19 @@ vector to one of its eight neighbouring cell positions on the map. If
§2.2. That leaves just three bits left to set: meet, crossdoor and crossdot.
The meet bit is used to show that the door on a connection should be plotted
symmetrically between the two rooms it connects. This is easy for the
@@ -375,7 +375,7 @@ directions N, S, E and W:
icon_grid[ICON_GRID_POS(Q, to_i1, to_i2)] |= MEET_MAPBIT; }
-
§2.3. But the case of a diagonal direction is much harder, because we may need
to add cornice-pieces. There are four possible diagonal directions (NE, NW,
SE and SW), and in each case the origin \(P\) and the neighbour cell \(P+D\)
@@ -391,10 +391,10 @@ we were originally looking at, or might be one of the other two).
vectorN = P;if (D.x < 0) N.x--;if (D.y < 0) N.y--;
-PL::HTMLMap::correct_diagonal(N, TRUE);
-PL::HTMLMap::correct_diagonal(N, FALSE);
+PL::HTMLMap::correct_diagonal(N, TRUE);
+PL::HTMLMap::correct_diagonal(N, FALSE);
-
§3. So now the vector \(BL\) represents the bottom left cell (i.e., the southwestern
corner of the box). We can obtain the other three cells of the \(2\times 2\) box
by offsetting to N, E and NE. Two of these cells form the diagonal of the
@@ -402,24 +402,24 @@ map connection (are "used"), and two are off-diagonal (are "unused").
§3.1.1. If the off-diagonal cells happen to be free, we can use them to draw a nice
large door which is exactly halfway between the two rooms it connects, and
is perpendicular to the direction of the map connection.
@@ -451,7 +451,7 @@ is perpendicular to the direction of the map connection.
icon_grid[pos_01] = CROSSDOOR_MAPBIT;icon_grid[pos_10] = CROSSDOOR_MAPBIT;
-
§3.1.2. But if the off-diagonal cells aren't free, we have no room for that, and
must draw a much smaller door on one end or the other (not both) of the
connection.
@@ -464,7 +464,7 @@ connection.
icon_grid[pos_00] = DOOR2_MAPBIT; mark the door on the BL half of the exiticon_grid[pos_11] = EXIT_MAPBIT; with no door on the other half of the exit
-
§3.2. If the off-diagonal cells happen to be free, we can put little single-pixel
icons into them to repair the notches which would otherwise show when the
map connection stripe (3 pixels wide) passes through a cell corner.
@@ -481,7 +481,7 @@ map connection stripe (3 pixels wide) passes through a cell corner.
icon_grid[pos_10] = CROSSDOT_MAPBIT; }
-
§4. Nested HTML Tables. In 2010 it is considered something of a heresy to be still doing web page
layout using nested tables - supposedly, CSS is now strong enough for all
our needs - but the map is unusually well suited to a table approach since
@@ -493,20 +493,20 @@ it consists, in the end, of tessalations of rectangles.
-voidPL::HTMLMap::end_map_table(OUTPUT_STREAM) {
+voidPL::HTMLMap::end_map_table(OUTPUT_STREAM) {map_tables_begun--;
-Include some indentation for a new map table4.2;
+Include some indentation for a new map table4.2;HTML::end_html_table(OUT);WRITE("\n");}
@@ -529,18 +529,18 @@ it consists, in the end, of tessalations of rectangles.
WRITE("\n");for (inti=0; i<map_tables_begun; i++) WRITE(" ");
§5. Icon images. The icons we use will all be PNGs, and all stored in the map_icons
directory. A "tool tip" is the text which appears over the mouse arrow
when it hovers for long enough over the icon.
-voidPL::HTMLMap::devise_level_rubric(intz, char **level_rubric, int *par) {
+voidPL::HTMLMap::devise_level_rubric(intz, char **level_rubric, int *par) { *level_rubric = "Map"; *par = 0;switch(Universe.corner1.z - Universe.corner0.z) {case0:
@@ -740,20 +740,20 @@ that the grids are calculated, the region colours decided, and so on.
§9.3.2.1.1. The centre of a cell might be a room, or it might be an icon showing the
continuation of one or more long connections running through this cell.
There are 15 possibilities, and their icons are named as the following shows:
@@ -993,7 +993,7 @@ There are 15 possibilities, and their icons are named as the following shows:
HTML_OPEN("td");intbits = (icon_grid[ICON_GRID_POS(P, 2, 2)]) & LONGS_BITMAP;if (bits == 0)
-PL::HTMLMap::index_room_square(OUT, room_grid[ROOM_GRID_POS(P)], pass);
+PL::HTMLMap::index_room_square(OUT, room_grid[ROOM_GRID_POS(P)], pass);else {TEMPORARY_TEXT(icon_name)WRITE_TO(icon_name, "long");
@@ -1001,36 +1001,36 @@ There are 15 possibilities, and their icons are named as the following shows:
if (bits & LONGNS_MAPBIT) WRITE_TO(icon_name, "_ns");if (bits & LONGSWNE_MAPBIT) WRITE_TO(icon_name, "_swne");if (bits & LONGNWSE_MAPBIT) WRITE_TO(icon_name, "_nwse");
-PL::HTMLMap::plot_map_icon(OUT, icon_name);
+PL::HTMLMap::plot_map_icon(OUT, icon_name);DISCARD_TEXT(icon_name) }HTML_CLOSE("td");
-
§9.3.1.2. Numbering cells. If we're displaying a numbering in the map, that means there are two
columns — the first and last — which don't contain rooms or exits, but
are simply blank except for an italic row number.
@@ -1041,15 +1041,15 @@ are simply blank except for an italic row number.
This code is used in §9.3.1 (twice), §9.3.3 (twice).
+
This code is used in §9.3.1 (twice), §9.3.3 (twice).
§9.3.2.2. Note that the row number is with respect to the entire Universe, not to
the current rectangle being rendered. The two aren't the same, because the
rectangle may be for a level in which we've omitted blank rows at the north
@@ -1061,7 +1061,7 @@ and south ends.
§10. Plotting the eight exterior icons. That leaves just the low-level routines to handle the nine individual pieces
of the cell. First, the eight cells around the outside:
§11. Plotting the single central square. The following routine renders the square icons for the rooms themselves,
which are bordered and coloured single-cell tables.
@@ -1184,7 +1184,7 @@ which are bordered and coloured single-cell tables.
defineROOM_TEXT_COLOUR"000000"
-voidPL::HTMLMap::index_room_square(OUTPUT_STREAM, instance *I, intpass) {
+voidPL::HTMLMap::index_room_square(OUTPUT_STREAM, instance *I, intpass) {if (I) {intb = ROOM_BORDER_SIZE;if ((I == benchmark_room) && (pass == 1)) b = B_ROOM_BORDER_SIZE;
@@ -1195,14 +1195,14 @@ which are bordered and coloured single-cell tables.
b, ROOM_BORDER_COLOUR, MAP_CELL_INNER_SIZE, MAP_CELL_INNER_SIZE, I);HTML_OPEN("tr");HTML_OPEN_WITH("td", "valign=\"middle\" align=\"center\" bgcolor=\"#%w\"",
-MAP_DATA(I)->world_index_colour);
+MAP_DATA(I)->world_index_colour);TEMPORARY_TEXT(col)
-if (MAP_DATA(I)->world_index_text_colour)
-WRITE_TO(col, "%w", MAP_DATA(I)->world_index_text_colour);
+if (MAP_DATA(I)->world_index_text_colour)
+WRITE_TO(col, "%w", MAP_DATA(I)->world_index_text_colour);elseWRITE_TO(col, "%s", ROOM_TEXT_COLOUR);HTML::begin_colour(OUT, col);
-Write the text of the abbreviated name of the room11.1;
+Write the text of the abbreviated name of the room11.1;HTML::end_colour(OUT);HTML_CLOSE("td");HTML_CLOSE("tr");
@@ -1227,7 +1227,7 @@ which are bordered and coloured single-cell tables.
}if ((pass == 1) && (I == benchmark_room)) HTML_OPEN("b");TEMPORARY_TEXT(abbrev)
-Work out the abbreviation for this room's name11.1.2;
+Work out the abbreviation for this room's name11.1.2; #ifdefHTML_MAP_FONT_SIZEHTML_OPEN_WITH("span", "style=\"font-size:%dpx;\"", HTML_MAP_FONT_SIZE); #endif
@@ -1240,7 +1240,7 @@ which are bordered and coloured single-cell tables.
if (pass == 1) { HTML::end_colour(OUT); HTML_CLOSE("a"); }DISCARD_TEXT(abbrev)
§11.1.1. When names are abbreviated for use on the World Index map (for instance,
"Marble Hallway" becomes "MH") each word is tested against the following
nonterminal; those which match are omitted. So, for instance, "Queen Of The
@@ -1278,23 +1278,23 @@ South" comes out as "QS".
} }
-
§12. The colour chip. The first of two extras, which aren't strictly speaking part of the HTML map.
This is the chip shown on the "details" box for a room in the World Index.
-voidPL::HTMLMap::colour_chip(OUTPUT_STREAM, instance *I, instance *Reg, parse_node *at) {
+voidPL::HTMLMap::colour_chip(OUTPUT_STREAM, instance *I, instance *Reg, parse_node *at) {HTML_OPEN_WITH("table","border=\"%d\" cellpadding=\"0\" cellspacing=\"0\" ""bordercolor=\"#%s\" height=\"%d\"",ROOM_BORDER_SIZE, ROOM_BORDER_COLOUR, MAP_CELL_INNER_SIZE);HTML_OPEN("tr");HTML_OPEN_WITH("td", "valign=\"middle\" align=\"center\" bgcolor=\"#%w\"",
-MAP_DATA(Reg)->world_index_colour);
+MAP_DATA(Reg)->world_index_colour);WRITE(" ");
-IXInstances::index_name(OUT, Reg); WRITE(" region");
-if (at) Index::link(OUT, Wordings::first_wn(Node::get_text(at)));
+IXInstances::index_name(OUT, Reg); WRITE(" region");
+if (at) Index::link(OUT, Wordings::first_wn(Node::get_text(at)));WRITE(" ");HTML_CLOSE("td");HTML_CLOSE("tr");
@@ -1307,11 +1307,11 @@ that nothing is shown if all of the rooms are outside of regions.
@@ -1340,7 +1340,7 @@ that nothing is shown if all of the rooms are outside of regions.
HTML::begin_plain_html_table(OUT);HTML_OPEN("tr"); WRITE("\n");HTML_OPEN_WITH("td", "width=\"40\" valign=\"middle\" align=\"left\"");
-PL::HTMLMap::index_room_square(OUT, R, 1);
+PL::HTMLMap::index_room_square(OUT, R, 1);HTML_CLOSE("td"); WRITE("\n");HTML_OPEN_WITH("td", "valign=\"middle\" align=\"left\"");WRITE("<b>");
@@ -1349,7 +1349,7 @@ that nothing is shown if all of the rooms are outside of regions.
elseWRITE("<i>Not in any region</i>");WRITE("</b>: ");
The structure vector is accessed in 3/sm2, 3/hm, 3/em and here.
+
The structure vector is accessed in 4/sm, 4/hm, 4/em and here.
§2. Some useful constant vectors, including those pointing in each direction.
Note that these are not of unit length — rather, they are the ideal grid
offsets on the map we will eventually draw.
@@ -129,11 +129,11 @@ corners are meaningless and are by convention at the origin.
structvectorcorner1;} cuboid;
-
The structure cuboid is accessed in 3/sm2, 3/hm, 3/em and here.
+
The structure cuboid is accessed in 4/sm, 4/hm, 4/em and here.
§4. Vectors.
-vectorGeometry::vec(intx, inty, intz) {
+vectorGeometry::vec(intx, inty, intz) {vectorR;R.x = x; R.y = y; R.z = z;returnR;
@@ -143,12 +143,12 @@ corners are meaningless and are by convention at the origin.
-intGeometry::vec_eq(vectorU, vectorV) {
+intGeometry::vec_eq(vectorU, vectorV) {if ((U.x == V.x) && (U.y == V.y) && (U.z == V.z)) returnTRUE;returnFALSE;}
-intGeometry::vec_lateral(vectorV) {
+intGeometry::vec_lateral(vectorV) {if ((V.x == 0) && (V.y == 0)) returnFALSE;returnTRUE;}
@@ -157,25 +157,25 @@ corners are meaningless and are by convention at the origin.
To fit the map of the rooms in the game into a cubical grid, preserving distances and angles where possible, and so to give each room approximate coordinate locations.
§1. We assign \((x, y, z)\) coordinates to each room, aiming to make the
descriptive map connections ("The Ballroom is east of the Old Kitchens")
@@ -190,9 +190,9 @@ than the number of rooms in the submap; this is why we keep the linked list.
§7.3. Locking is a way to influence the algorithm in this section by forcing a
@@ -291,15 +291,15 @@ given exit to be locked in place, forbidding it to be distorted.
§7.4. Page directions. These are any of the 12 standard IF directions (N, NE, NW, S, SE, SW, E, W,
@@ -319,10 +319,10 @@ for any subsequent story directions to be unshown:
§7.17.1. We first find a spread of nearly opposite directions: for instance, if i
is northeast, then back is SW, cw is W, cwcw is NW, ccw is S, ccwccw
is SE. We also find the backstep, the room you get to if trying to go back
@@ -646,20 +646,20 @@ position the rooms.)
§7.17.1.3. Now perhaps A runs east to B, B runs south to A, but these are both 1-way
connections. We'll regard this as being a single passageway running on average
northeast from A to B:
@@ -721,23 +721,23 @@ northeast from A to B:
§7.17.1.4. Most of the time, a 1-way connection is fine for mapping purposes; it
establishes as good a spatial relationship as a 2-way one. But we suppress
this if either (a) there are already 2-way connections between the rooms
@@ -751,21 +751,21 @@ room (the case where backstep
§9. The spatial relationships arrays are read only by the following. Note
@@ -781,20 +781,20 @@ boundaries, and will be needed when we place submaps on the global grid.
§13. Here is how we read from the incidence cache. Its purpose is to provide
@@ -866,8 +866,8 @@ resized as the rooms in the submap move around, which complicates things.
-intPL::SpatialMap::occupied_in_submap(connected_submap *sub, vectorP) {
-inti = Geometry::cuboid_index(P, sub->incidence_cache_bounds);
+intPL::SpatialMap::occupied_in_submap(connected_submap *sub, vectorP) {
+inti = Geometry::cuboid_index(P, sub->incidence_cache_bounds);if (i < 0) return0;returnsub->incidence_cache[i];}
@@ -877,9 +877,9 @@ routine must be notified of any such:
§7.25. The following grows a component outwards from at, so that it also includes
all rooms locked to at or with a SR to it. If at is currently not in a
component, we start a new submap to hold it.
@@ -1072,20 +1072,20 @@ each room, so phase (2) has running time \(O(R)\).
§7.27. Synchronising movements of locked rooms. The next preliminary we need is the implementation of locking. As we've seen,
@@ -1115,24 +1115,24 @@ corresponding positions.
§7.29. Positioning within components. This is much more difficult. It's going to be a matter of minimising the
@@ -1172,9 +1172,9 @@ the loop over submaps doesn't therefore add to the running time.
inttotal_accuracy = 0;LOOP_OVER(sub, connected_submap) {LOGIF(SPATIAL_MAP, "Laying out component %d\n", sub->allocation_id);
-PL::SpatialMap::lock_positions_in_submap(sub); \(O(R)\) running time
-PL::SpatialMap::establish_natural_lengths(sub); \(O(R)\) running time
-PL::SpatialMap::position_submap(sub);
+PL::SpatialMap::lock_positions_in_submap(sub); \(O(R)\) running time
+PL::SpatialMap::establish_natural_lengths(sub); \(O(R)\) running time
+PL::SpatialMap::position_submap(sub);total_accuracy += sub->heat;LOGIF(SPATIAL_MAP, "Component %d has final heat %d\n", sub->allocation_id, sub->heat); }
@@ -1189,7 +1189,7 @@ the loop over submaps doesn't therefore add to the running time.
LOGIF(SPATIAL_MAP, "Cost: radiation %d drognas\n", radiation_spending);LOGIF(SPATIAL_MAP, "Cost: explosion %d drognas\n\n", explosion_spending);
§16. Every spatial relationship has a "length", which is a positive integer.
This is our preferred amount of stretch when laying out the rooms; a
length of 1 means one grid increment, and that's our preference if we
@@ -1197,15 +1197,15 @@ can have it. Initially, all SRs have length 1.
§22.1.2. Supposing we can divide, though, we need to set zone numbers throughout
the submap, and the procedure is different depending on whether we're
dividing at one relationship F1-to-T1 or at two, F1-to-T1 and F2-to-T2.
@@ -1469,50 +1469,50 @@ dividing at one relationship F1-to-T1 or at two, F1-to-T1 and F2-to-T2.
intZ1_count = 0, Z2_count = 0;if (div_F2) {intpredivision_spending = drognas_spent;
-PL::SpatialMap::divide_into_zones_twocut(div_F1, div_T1, div_F2, div_T2, Z1_number, Z2_number);
+PL::SpatialMap::divide_into_zones_twocut(div_F1, div_T1, div_F2, div_T2, Z1_number, Z2_number);instance *R;LOOP_OVER_SUBMAP(R, sub) {if (MAP_DATA(R)->zone == Z1_number) Z1_count++;if (MAP_DATA(R)->zone == Z2_number) Z2_count++; }LOGIF(SPATIAL_MAP, "Making a double cut: $O %s to $O and $O %s to $O at cost %d\n",
-div_F1, PL::SpatialMap::usual_Inform_direction_name(div_dir1), div_T1,
-div_F2, PL::SpatialMap::usual_Inform_direction_name(div_dir2), div_T2,
+div_F1, PL::SpatialMap::usual_Inform_direction_name(div_dir1), div_T1,
+div_F2, PL::SpatialMap::usual_Inform_direction_name(div_dir2), div_T2,drognas_spent - predivision_spending);division_spending += drognas_spent - predivision_spending; } else {intpredivision_spending = drognas_spent;
-PL::SpatialMap::divide_into_zones_onecut(sub, div_F1, div_T1,
+PL::SpatialMap::divide_into_zones_onecut(sub, div_F1, div_T1, &Z1_count, &Z2_count, Z1_number, Z2_number);LOGIF(SPATIAL_MAP, "Making a single cut: $O %s to $O at cost %d\n",
-div_F1, PL::SpatialMap::usual_Inform_direction_name(div_dir1), div_T1,
+div_F1, PL::SpatialMap::usual_Inform_direction_name(div_dir1), div_T1,drognas_spent - predivision_spending);division_spending += drognas_spent - predivision_spending; }LOGIF(SPATIAL_MAP, "This produces two zones of sizes %d and %d\n",Z1_count, Z2_count);
§22.1.4. The zone-1 rooms are now correctly placed with respect to each other, and
vice versa, but we might have a horrendous breakage where the two sets of
rooms meet. We need to rejoin them, and we do this by stretching the
@@ -1550,7 +1550,7 @@ sliding taking up about 80 percent of our time, which is unacceptable.
§22.1.4.1. Here we slide rooms which came from Zone 2 so that they retain their
positions with respect to each other, and therefore to T1, and so that T1
is placed correctly aligned along the axis from F1 with length L.
@@ -1591,16 +1591,16 @@ can't break a lock between two rooms.
§23. Finding how to divide. That completes the logic for how we divide and conquer the submaps, except,
of course, that some of the critical steps weren't spelled out. We do that
now. First, the code to find good cutpoint(s): map connection(s) which, if
@@ -1650,12 +1650,12 @@ run slowly; it's his own fault.
defineCLIPBOARD_SIZE3 a term to be explained below
§23.3. Suppose the larger and smaller zones have sizes \(X\) and \(Y\). Then clearly
\(X+Y = T\), where \(T\) is the total number of rooms (called size below). The
spread is by definition \(S = X-Y\). Therefore the size of the smaller zone
@@ -1749,7 +1749,7 @@ the time it takes.
returnTRUE; }
-
§24. The return value of PL::SpatialMap::assign_generation_count is the number of rooms which
it, and its recursive incarnations, visit in total. But as noted above, it
also records data in the arrays it is passed pointers to; that's what the
@@ -1759,7 +1759,7 @@ call; size is t
§24.2. At this point, it's as if we have been sent out to explore a labyrinth.
One problem we have is that we can't see what lies beyond here, with our
own eyes. "The underground rooms I can speak of only from report, because
@@ -1848,21 +1848,21 @@ there, maybe just a broom cupboard.
§24.2.1. Each fresh team of explorers gets a fresh clipboard on which to record what
they see — hence the new set of inner_contact_* arrays. (They don't get
individual copies of the best_* arrays, though — that's the point of these;
@@ -1879,7 +1879,7 @@ they're shared in common among all of the explorers.)
inner_contact_from[j] = NULL; inner_contact_to[j] = NULL; inner_contact_dir[j] = -1; }
-
§24.2.2. When the explorers get back, tired but happy, we look at their clipboard,
and see if those contacts excite us too — which they may not, because what
seemed to them a rediscovery might not seem that way to us; they've seen
@@ -1898,11 +1898,11 @@ clipboard only if they are contacts to places we know about, too.
instance *observed_from = inner_contact_from[j];instance *observed_to = inner_contact_to[j];intobserved_dir = inner_contact_dir[j];
-Contact hasss been made24.1.1;
+Contact hasss been made24.1.1; } }
-
§24.2.3.1. If exploration outward from here never resulted in a contact with known
territory, then cutting this link strands the far side as a disconnected zone.
@@ -1943,7 +1943,7 @@ territory, then cutting this link strands the far side as a disconnected zone.
best_dir1[BEST_ONECUT_ER] = i; }
-
§24.2.3.2. If exploration found just one contact, then that link, plus this one, would
if both removed cut off the far side. We have to be careful that we never
cut along locks, only along map connections; we know that the at to T
@@ -1961,9 +1961,9 @@ we can get it.
§24.1.1. This is a piece of code used twice in the above routine: it puts the
contact observed_from to observed_to onto our clipboard, provided that
there's room and/or it is interesting enough. We use an insertion-sort to
@@ -2001,7 +2001,7 @@ contact arrays were large, but break; }
-
§25. Zones 1 and 2 for a single cut. Suppose we have decided to cut the submap between rooms R1 and R2, in the
belief that this will disconnect the submap into two components. If that in
fact proves to be the case (as it always should) then we set the zone field
@@ -2018,7 +2018,7 @@ from R1, or vice versa, then we're in the
-intPL::SpatialMap::divide_into_zones_onecut(connected_submap *sub, instance *R1, instance *R2,
+intPL::SpatialMap::divide_into_zones_onecut(connected_submap *sub, instance *R1, instance *R2,int *Z1_count, int *Z2_count, intZ1, intZ2) {if (R1 == R2) internal_error("can't divide");instance *R;
@@ -2026,9 +2026,9 @@ from R1, or vice versa, then we're in the MAP_DATA(R1)->zone = Z1; MAP_DATA(R2)->zone = Z2; *Z1_count = 0; *Z2_count = 0;intcontacts = 0;
- *Z1_count = PL::SpatialMap::divide_into_zones_onecut_r(R1, NULL, R1, R2, &contacts);
+ *Z1_count = PL::SpatialMap::divide_into_zones_onecut_r(R1, NULL, R1, R2, &contacts);if (contacts > 0) returnFALSE;
- *Z2_count = PL::SpatialMap::divide_into_zones_onecut_r(R2, NULL, R2, R1, &contacts);
+ *Z2_count = PL::SpatialMap::divide_into_zones_onecut_r(R2, NULL, R2, R1, &contacts);LOOP_OVER_SUBMAP(R, sub)if (MAP_DATA(R)->zone == 0)MAP_DATA(R)->zone = Z1;
@@ -2048,17 +2048,17 @@ our original component into two disjoint connected zones.
§27. Zones 1 and 2 for a double cut. This is more or less the same, but simpler, since it can't determine whether
we've chosen the cuts correctly, so doesn't even try.
§29. Tactics. At long last we can forget about dividing submaps, and concentrate on the
four tactics for improving the layout of a given submap. We're going to do
all kinds of heuristic things here, some of them with iffy running times,
@@ -2138,16 +2138,16 @@ time.
§31.2. An important point here is that we don't re-measure the heat of the exits
after cooling. If we did, we might find that cooling is having no effect, and
then lock up. We're simply trying to deal with the heat as it looked at the
@@ -2289,9 +2289,9 @@ all three in an afternoon stroll.)
exit_heats[i] = 0; exits_cooled++; }if (exit_heats[i] > 0) {
-PL::SpatialMap::cool_exit(R, i);
+PL::SpatialMap::cool_exit(R, i);exit_heats[i] = 0; exits_cooled++;
-PL::SpatialMap::cool_component_from(sub, exit_rooms[i]);
+PL::SpatialMap::cool_component_from(sub, exit_rooms[i]);LOOP_OVER_LATTICE_DIRECTIONS(j)if ((exit_heats[j] > 0) && (exit_rooms[i] == exit_rooms[j])) {exit_heats[j] = 0; exits_cooled++;
@@ -2301,7 +2301,7 @@ all three in an afternoon stroll.)
if (exits_cooled == 0) break; }
-
§32. To cool an exit is to move the destination room into the perfect grid
position so that the exit's heat is 0. Note that we must always maintain
locking, and that we provide a convenient "undo" mechanism in case the
@@ -2312,25 +2312,25 @@ neighbours.)
§33. The quenching tactic. After the age of cooling, we can expect the universe to be mostly cold, but
@@ -2348,8 +2348,8 @@ on large connected submaps.
-voidPL::SpatialMap::quench_submap(connected_submap *sub, instance *avoid1, instance *avoid2) {
-intinitial_heat = PL::SpatialMap::find_submap_heat(sub), initial_spending = drognas_spent;
+voidPL::SpatialMap::quench_submap(connected_submap *sub, instance *avoid1, instance *avoid2) {
+intinitial_heat = PL::SpatialMap::find_submap_heat(sub), initial_spending = drognas_spent;LOGIF(SPATIAL_MAP, "\nTACTIC: Quenching submap %d: initial heat %d\n",sub->allocation_id, sub->heat);instance *R;
@@ -2362,8 +2362,8 @@ on large connected submaps.
LOOP_OVER_SUBMAP(R, sub) {inti;LOOP_OVER_LATTICE_DIRECTIONS(i)
-if (PL::SpatialMap::find_exit_heat(R, i) > 0)
-Attempt to quench this heated link33.1;
+if (PL::SpatialMap::find_exit_heat(R, i) > 0)
+Attempt to quench this heated link33.1; }LOG_OUTDENT;LOGIF(SPATIAL_MAP, "Quenching round %d had %d success(es).\n", rounds, successes);
@@ -2377,15 +2377,15 @@ on large connected submaps.
§34. The diffusion tactic. Where quenching fails to help much, this is usually because rooms are packed
too tightly together, and need to be eased apart. This makes space for
more interesting configurations and makes it easier to get rid of the very
@@ -2406,8 +2406,8 @@ neighbourhood as the rooms shimmy apart.
-voidPL::SpatialMap::diffuse_submap(connected_submap *sub) {
-intinitial_heat = PL::SpatialMap::find_submap_heat(sub), initial_spending = drognas_spent;
+voidPL::SpatialMap::diffuse_submap(connected_submap *sub) {
+intinitial_heat = PL::SpatialMap::find_submap_heat(sub), initial_spending = drognas_spent;LOGIF(SPATIAL_MAP, "\nTACTIC: Diffusing submap %d: initial heat %d\n",sub->allocation_id, sub->heat);instance *R;
@@ -2419,9 +2419,9 @@ neighbourhood as the rooms shimmy apart.
LOOP_OVER_SUBMAP(R, sub) {inti;LOOP_OVER_LATTICE_DIRECTIONS(i) {
-instance *T = PL::SpatialMap::read_smap(R, i);
+instance *T = PL::SpatialMap::read_smap(R, i);if (T)
-Try diffusion along this link34.1;
+Try diffusion along this link34.1; } }LOG_OUTDENT;
@@ -2444,29 +2444,29 @@ rooms whose exits are cold (or which are locked to each other).
§35. This recursively expands zone 2 to include rooms connected by cold links,
except that it's forbidden to including avoiding (the room we are trying
to lengthen away from).
§7.30. This is the clever part of radiation, and the reason why we only allow R
to radiate outward on cardinal points of the compass. Once again we will
move a whole clump of R's neighbours along with it, preserving their positions
@@ -2626,19 +2626,19 @@ become aligned.)
§7.32.1.1. Here we simply place the component immediately to the right of its
predecessor, with the same baseline, and on the level of the benchmark room.
@@ -2765,11 +2765,11 @@ predecessor, with the same baseline, and on the level of the benchmark room.
LOGIF(SPATIAL_MAP, "Component %d (size %d): side by side strategy\n",sub->allocation_id, sub->bounds.population);
-PL::SpatialMap::move_component(sub,
-Geometry::vec(x_max, box.corner0.y - sub->bounds.corner0.y,
+PL::SpatialMap::move_component(sub,
+Geometry::vec(x_max, box.corner0.y - sub->bounds.corner0.y,Room_position(benchmark_room).z - sub->bounds.corner0.z));
§7.32.1.2. The drill square is a way to place large numbers of single-room components,
such as exist in IF works where rooms are being plaited together live during
play and have no initial map. Side-by-side placement would be horrible for
@@ -2787,24 +2787,24 @@ one big component.
sub->allocation_id, sub->bounds.population);if (drill_square_side == 0) {Drill_square_O =
-Geometry::vec(box.corner1.x + 1, box.corner0.y, Room_position(benchmark_room).z);
+Geometry::vec(box.corner1.x + 1, box.corner0.y, Room_position(benchmark_room).z);Drill_square_At = Drill_square_O;connected_submap *sing;intN = 0;LOOP_OVER(sing, connected_submap)
-if ((sing->bounds.population == 1) && (PL::SpatialMap::component_is_isolated(sing)))
+if ((sing->bounds.population == 1) && (PL::SpatialMap::component_is_isolated(sing)))N++;while (drill_square_side*drill_square_side < N) drill_square_side++;if (drill_square_side*drill_square_side > N) drill_square_side--;LOGIF(SPATIAL_MAP, "Drill square: side %d\n", drill_square_side); }
-PL::SpatialMap::move_component(sub, Geometry::vec_minus(Drill_square_At, sub->bounds.corner0));
-Drill_square_At = Geometry::vec_plus(Drill_square_At, Geometry::vec(0, 1, 0));
+PL::SpatialMap::move_component(sub, Geometry::vec_minus(Drill_square_At, sub->bounds.corner0));
+Drill_square_At = Geometry::vec_plus(Drill_square_At, Geometry::vec(0, 1, 0));if (Drill_square_At.y - Drill_square_O.y == drill_square_side)
-Drill_square_At = Geometry::vec_plus(Drill_square_At,
-Geometry::vec(1, -drill_square_side, 0));
+Drill_square_At = Geometry::vec_plus(Drill_square_At,
+Geometry::vec(1, -drill_square_side, 0));
-
§37. The following means the components are sorted in descending size order,
but in order of creation within each size; when we get down to the
singletons, we sort by order of creation of the single rooms they
@@ -2871,7 +2871,7 @@ contain.
-intPL::SpatialMap::compare_components(constvoid *ent1, constvoid *ent2) {
+intPL::SpatialMap::compare_components(constvoid *ent1, constvoid *ent2) {constconnected_submap *mc1 = *((constconnected_submap **) ent1);constconnected_submap *mc2 = *((constconnected_submap **) ent2);intd = mc2->bounds.population - mc1->bounds.population;
@@ -2880,8 +2880,8 @@ contain.
instance *R1 = mc1->first_room_in_submap;instance *R2 = mc2->first_room_in_submap;if ((R1) && (R2)) { which should always happen, but just in case of an error
-instance *reg1 = Regions::enclosing(R1);
-instance *reg2 = Regions::enclosing(R2);
+instance *reg1 = Regions::enclosing(R1);
+instance *reg2 = Regions::enclosing(R2);if ((reg1) && (reg2 == NULL)) return -1;if ((reg1 == NULL) && (reg2)) return1;if (reg1) {
@@ -2901,13 +2901,13 @@ component; the second means it has no link at all to any other component.
§41. So, now we have to define our Swiss-army-knife routine to cope with all
@@ -2964,7 +2964,7 @@ rooms connected that way are by definition in the same component.
§7.33. "How bad they are" uses another heat-like measure. This one gives an
enormous penalty for being wrong vertically; people just don't like
reading maps where an inside room is displayed on the floor above or below.
@@ -3045,13 +3045,13 @@ insets — this makes the map line up elegantly.
-intPL::SpatialMap::find_cross_link_heat(instance *R, instance *S, intdir) {
+intPL::SpatialMap::find_cross_link_heat(instance *R, instance *S, intdir) {if ((R == NULL) || (S == NULL)) internal_error("bad room distance");
-returnPL::SpatialMap::component_metric(Room_position(R), Room_position(S), dir);
+returnPL::SpatialMap::component_metric(Room_position(R), Room_position(S), dir);}intPL::SpatialMap::component_metric(vectorP1, vectorP2, intdir) {
-vectorD = Geometry::vec_minus(P1, P2);
+vectorD = Geometry::vec_minus(P1, P2);intb = 0;if ((dir == 10) || (dir == 11)) { IN and OUT respectivelyif (D.x > 0) b++;
@@ -3076,12 +3076,12 @@ insets — this makes the map line up elegantly.
§7.35. Stage 6, removing blank planes. We need to avoid what might be an infinite loop in awkward cases where
locking means that blank planes are inevitable.
§42. Precis. It turns out to be useful to test the above algorithm on maps of actual IF
works. But they tend to have large source texts full of irrelevancies to
the spatial layout, so in order to extract the arrangement cleanly, we
@@ -3119,17 +3119,17 @@ can make use of the following:
@@ -3138,9 +3138,9 @@ can make use of the following:
if ((Instances::of_kind(R, K_direction)) &&
- (MAP_DATA(R)->direction_index >= 12)) {
+ (MAP_DATA(R)->direction_index >= 12)) {wordingW = Instances::get_name(R, FALSE);
-wordingOW = Instances::get_name(Map::get_value_of_opposite_property(R), FALSE);
+wordingOW = Instances::get_name(Map::get_value_of_opposite_property(R), FALSE);LOG("%+W is a direction. The opposite of %+W is %+W.\n", W, W, OW); }if (Instances::of_kind(R, K_region)) {
@@ -3159,7 +3159,7 @@ can make use of the following:
} }
§42.2. Declare the rooms in the precis, starting with the start room42.2 =
@@ -3167,7 +3167,7 @@ can make use of the following:
if (Instances::of_kind(R, K_room)) {wordingRW = Instances::get_name(R, FALSE);LOG("%+W is a room.\n", RW);
-instance *reg = Regions::enclosing(R);
+instance *reg = Regions::enclosing(R);if (reg) {wordingRGW = Instances::get_name(reg, FALSE);if (MAP_DATA(reg)->zone == 1) {
@@ -3176,13 +3176,13 @@ can make use of the following:
}LOG("%+W is in %+W.\n", RW, RGW); }
-instance *start = Player::get_start_room();
+instance *start = Player::get_start_room();if (R == start) {LOG("The player is in %+W.\n", RW); } }
-
-voidPL::SpatialMap::visit_to_transcribe(parse_node *p) {
+voidPL::SpatialMap::visit_to_transcribe(parse_node *p) {if ((Node::get_type(p) == SENTENCE_NT) && (p->down)) {MajorNodes::try_special_meaning(TRAVERSE_FOR_MAP_INDEX_SMFT, p->down); }
@@ -3239,15 +3239,15 @@ can make use of the following:
-voidPL::SpatialMap::index_room_connections(OUTPUT_STREAM, instance *R) {
+voidPL::SpatialMap::index_room_connections(OUTPUT_STREAM, instance *R) {wordingRW = Instances::get_name(R, FALSE); name of the origin roominstance *dir;LOOP_OVER_INSTANCES(dir, K_direction) {
-inti = MAP_DATA(dir)->direction_index;
-instance *opp = Map::get_value_of_opposite_property(dir);
-intod = opp?(MAP_DATA(opp)->direction_index):(-1);
+inti = MAP_DATA(dir)->direction_index;
+instance *opp = Map::get_value_of_opposite_property(dir);
+intod = opp?(MAP_DATA(opp)->direction_index):(-1);instance *D = NULL;
-instance *S = PL::SpatialMap::room_exit(R, i, &D);
+instance *S = PL::SpatialMap::room_exit(R, i, &D);if ((S) || (D)) {HTML::open_indented_p(OUT, 1, "tight");char *icon = "e_arrow";
@@ -3255,45 +3255,45 @@ can make use of the following:
elseif (D) icon = "e_arrow_door_blocked";HTML_TAG_WITH("img", "border=0 src=inform:/map_icons/%s.png", icon);WRITE(" ");
-IXInstances::index_name(OUT, dir);
+IXInstances::index_name(OUT, dir);WRITE(" to ");if (S) {
-IXInstances::index_name(OUT, S);
+IXInstances::index_name(OUT, S);if (D) {WRITE(" via ");
-IXInstances::index_name(OUT, D);
+IXInstances::index_name(OUT, D); } } else {
-IXInstances::index_name(OUT, D);
+IXInstances::index_name(OUT, D);WRITE(" (a door)"); }if (S) {
-instance *B = opp?(PL::SpatialMap::room_exit(S, od, NULL)):NULL;
+instance *B = opp?(PL::SpatialMap::room_exit(S, od, NULL)):NULL;if (B == NULL) {WRITE(" (but ");
-IXInstances::index_name(OUT, opp);
+IXInstances::index_name(OUT, opp);WRITE(" from ");
-IXInstances::index_name(OUT, S);
+IXInstances::index_name(OUT, S);WRITE(" is nowhere)"); } elseif (B != R) {WRITE(" (but ");
-IXInstances::index_name(OUT, opp);
+IXInstances::index_name(OUT, opp);WRITE(" from ");
-IXInstances::index_name(OUT, S);
+IXInstances::index_name(OUT, S);WRITE(" is ");
-IXInstances::index_name(OUT, B);
+IXInstances::index_name(OUT, B);WRITE(")"); } }
-parse_node *at = MAP_DATA(R)->exits_set_at[i];
-if (at) Index::link(OUT, Wordings::first_wn(Node::get_text(at)));
+parse_node *at = MAP_DATA(R)->exits_set_at[i];
+if (at) Index::link(OUT, Wordings::first_wn(Node::get_text(at)));HTML_CLOSE("p"); } }intk = 0;LOOP_OVER_INSTANCES(dir, K_direction) {
-inti = MAP_DATA(dir)->direction_index;
-if (PL::SpatialMap::room_exit(R, i, NULL)) continue;
+inti = MAP_DATA(dir)->direction_index;
+if (PL::SpatialMap::room_exit(R, i, NULL)) continue;wordingDW = Instances::get_name(dir, FALSE); name of the directionk++;if (k == 1) {
@@ -3327,9 +3327,9 @@ rooms:
diff --git a/docs/index-module/index.html b/docs/index-module/index.html
index 3843716dd..0bc631575 100644
--- a/docs/index-module/index.html
+++ b/docs/index-module/index.html
@@ -189,6 +189,37 @@
The Map -
Indexing the player's initial position.
+
+
+ Scenes -
+ Parallel to the World index of space is the Scenes index of time, and in this section we render it as HTML.
+
+
+
+
+
+ Chapter 4: Visualising Space
+
+
+
+ Spatial Geometry -
+ To deal with vectors and cuboids in a three-dimensional integer lattice.
+
+
+
+ Spatial Map -
+ To fit the map of the rooms in the game into a cubical grid, preserving distances and angles where possible, and so to give each room approximate coordinate locations.
+
+
+
+ HTML Map -
+ To render the spatial map of rooms as HTML.
+
+
+
+ EPS Map -
+ To render the spatial map of rooms as an EPS (Encapsulated PostScript) file.
+
diff --git a/docs/runtime-module/2-emt.html b/docs/runtime-module/2-emt.html
index 772b9aff9..451df76ff 100644
--- a/docs/runtime-module/2-emt.html
+++ b/docs/runtime-module/2-emt.html
@@ -84,7 +84,7 @@ function togglePopup(material_id) {
inter_tree *I7_generation_tree = NULL;
-inter_tree *Emit::tree(void) {
+inter_tree *Emit::tree(void) {returnI7_generation_tree;}
@@ -342,14 +342,14 @@ insert them into the Inter stream close to the top.
Emit::named_generic_constant(name, v1, v2);}
-voidEmit::named_generic_constant(inter_name *name, inter_tival1, inter_tival2) {
+voidEmit::named_generic_constant(inter_name *name, inter_tival1, inter_tival2) {packaging_statesave = Packaging::enter_home_of(name);inter_symbol *con_name = Produce::define_symbol(name);Produce::guard(Inter::Constant::new_numerical(Packaging::at(Emit::tree()), Inter::SymbolsTables::id_from_IRS_and_symbol(Packaging::at(Emit::tree()), con_name), Inter::SymbolsTables::id_from_IRS_and_symbol(Packaging::at(Emit::tree()), unchecked_interk), val1, val2, Produce::baseline(Packaging::at(Emit::tree())), NULL));Packaging::exit(Emit::tree(), save);}
-inter_name *Emit::named_numeric_constant(inter_name *name, inter_tival) {
+inter_name *Emit::named_numeric_constant(inter_name *name, inter_tival) {packaging_statesave = Packaging::enter_home_of(name);inter_symbol *con_name = Produce::define_symbol(name);Produce::guard(Inter::Constant::new_numerical(Packaging::at(Emit::tree()), Inter::SymbolsTables::id_from_IRS_and_symbol(Packaging::at(Emit::tree()), con_name), Inter::SymbolsTables::id_from_IRS_and_symbol(Packaging::at(Emit::tree()), int_interk), LITERAL_IVAL, val, Produce::baseline(Packaging::at(Emit::tree())), NULL));
@@ -617,7 +617,7 @@ insert them into the Inter stream close to the top.
Packaging::exit(Emit::tree(), save);}
-inter_name *Emit::named_iname_constant(inter_name *name, kind *K, inter_name *iname) {
+inter_name *Emit::named_iname_constant(inter_name *name, kind *K, inter_name *iname) {packaging_statesave = Packaging::enter_home_of(name);inter_symbol *con_name = Produce::define_symbol(name);inter_symbol *val_kind = Produce::kind_to_symbol(K);
diff --git a/docs/runtime-module/2-hrr.html b/docs/runtime-module/2-hrr.html
index a9f981e3d..9ac99b7e4 100644
--- a/docs/runtime-module/2-hrr.html
+++ b/docs/runtime-module/2-hrr.html
@@ -1723,11 +1723,11 @@ function togglePopup(material_id) {
§2.2. In the code running at this point, na holds the number of either/or
properties listed since the last time it was zeroed. If it's positive, we
need either a semicolon or a line break. If we're about to work on another
@@ -181,28 +181,28 @@ second of just one from "person".
-intPL::Showme::SHOWME_primitive(inference_subject *subj, property *prn, intcomp, inter_symbol *t_0_s, inter_symbol *na_s) {
+intRTShowmeCommand::SHOWME_primitive(inference_subject *subj, property *prn, intcomp, inter_symbol *t_0_s, inter_symbol *na_s) {if (IXProperties::is_shown_in_index(prn) == FALSE) returnFALSE;
-if (RTProperties::can_be_compiled(prn) == FALSE) returnFALSE;
+if (RTProperties::can_be_compiled(prn) == FALSE) returnFALSE;inference_subject *parent = InferenceSubjects::narrowest_broader_subject(subj);
@@ -239,9 +239,9 @@ second of just one from "person".
(PropertyPermissions::find(parent, prn, TRUE) == FALSE)) {if (comp) {if (Properties::is_value_property(prn))
-Compile the SHOWME printing code for a value property4.1
+Compile the SHOWME printing code for a value property4.1else
-Compile the SHOWME printing code for an either/or property4.2;
+Compile the SHOWME printing code for an either/or property4.2; }returnTRUE; }
@@ -274,105 +274,105 @@ routine for colours; and the best thing is to print nothing at all.
kind *K = ValueProperties::kind(prn);if (K) {intrequire_nonzero = FALSE;
-if ((RTProperties::uses_non_typesafe_0(prn)) ||
+if ((RTProperties::uses_non_typesafe_0(prn)) || (Kinds::Behaviour::is_object(K)))require_nonzero = TRUE;if (require_nonzero) {
-Produce::inv_primitive(Emit::tree(), IF_BIP);
-Produce::down(Emit::tree());
-inter_name *iname = Hierarchy::find(GPROPERTY_HL);
-Produce::inv_call_iname(Emit::tree(), iname);
-Produce::down(Emit::tree());
-RTKinds::emit_weak_id_as_val(K_object);
-Produce::val_symbol(Emit::tree(), K_value, t_0_s);
-Produce::val_iname(Emit::tree(), K_value, RTProperties::iname(prn));
-Produce::up(Emit::tree());
-Produce::code(Emit::tree());
-Produce::down(Emit::tree());
+Produce::inv_primitive(Emit::tree(), IF_BIP);
+Produce::down(Emit::tree());
+inter_name *iname = Hierarchy::find(GPROPERTY_HL);
+Produce::inv_call_iname(Emit::tree(), iname);
+Produce::down(Emit::tree());
+RTKinds::emit_weak_id_as_val(K_object);
+Produce::val_symbol(Emit::tree(), K_value, t_0_s);
+Produce::val_iname(Emit::tree(), K_value, RTProperties::iname(prn));
+Produce::up(Emit::tree());
+Produce::code(Emit::tree());
+Produce::down(Emit::tree()); }
-Compile the SHOWME printing of the value of a value property4.1.1;
+Compile the SHOWME printing of the value of a value property4.1.1;if (require_nonzero) {
-Produce::up(Emit::tree());
-Produce::up(Emit::tree());
+Produce::up(Emit::tree());
+Produce::up(Emit::tree()); } }
§4.2. The I6 template code is allowed to bar certain either/or properties using
AllowInShowme; it typically uses this to block distracting temporary-workspace
properties like "marked for listing" whose values have no significance
@@ -384,63 +384,63 @@ turn by turn.
§1. At run-time, we need to store information about the current state of each
+scene: whether it is currently playing or not, when the last change occurred,
+and so on. This data is stored in I6 arrays as follows:
+
+
+
First, each scene has a unique ID number, used as an index X to these arrays.
+This ID number is what is stored as an I6 value for the kind of value scene,
+and it agrees with the allocation ID for the I7 scene structure.
+
+
+
scene_status-->X is 0 if the scene is not playing, but may do so in future;
+1 if the scene is playing; or 2 if the scene is not playing and will never
+play again.
+
+
+
scene_started-->X is the value of the_time when the scene last started,
+or 0 if it has never started.
+
+
+
scene_ended-->X is the value of the_time when the scene last ended,
+or 0 if it has never ended. (The "starting" end does not count as ending
+for this purpose.)
+
+
+
scene_endings-->X is a bitmap recording which ends have been used,
+including bit 1 which records whether the scene has started.
+
+
+
scene_latest_ending-->X holds the end number of the most recent ending
+(or 0 if the scene has never ended).
+
+
+
§2. Scene-changing machinery at run-time. So what are scenes for? Well, they have two uses. One is that the end
+rulebooks are run when ends occur, which is a convenient way to time events.
+The following generates the necessary code to (a) detect when a scene end
+occurs, and (b) act upon it. This is all handled by the following Inter
+function.
+
+
+
There is one argument, chs: the number of iterations so far. Iterations
+occur because each set of scene changes could change the circumstances in such
+a way that other scene changes are now required (through external conditions,
+not through anchors); we don't want this to lock up, so we will cap recursion.
+Within the routine, a second local variable, ch, is a flag indicating
+whether any change in status has or has not occurred.
+
§2.2. Recall that ends numbered 1, 2, 3, ... are all ways for the scene to end,
+so they are only checked if its status is currently running; end 0 is the
+beginning, checked only if it isn't. We give priority to the higher end
+numbers so that more abstruse ways to end take precedence over less.
+
+
+
Compile code detecting the ends of a specific scene2.2 =
+
§3. Individual ends are tested here. There are actually three ways an end can
+occur: at start of play (for end 0 only), when an I7 condition holds, or when
+another end to which it is anchored also ends. But we only check the first
+two, because the third way will be taken care of by the consequences code
+below.
+
§3.1. Reparse the scene end condition in this new context3.1 =
+
+
+
+current_sentence = sc->ends[end].anchor_condition_set;
+if (Node::is(S, UNKNOWN_NT)) {
+if (<s-condition>(Node::get_text(S))) S = <<rp>>;
+sc->ends[end].anchor_condition = S;
+ }
+if (Node::is(S, UNKNOWN_NT)) {
+LOG("Condition: $P\n", S);
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_ScenesBadCondition),
+"'begins when' and 'ends when' must be followed by a condition",
+"which this does not seem to be, or else 'when play begins', "
+"'when play ends', 'when S begins', or 'when S ends', where "
+"S is the name of any scene.");
+return;
+ }
+
+if (Dash::check_condition(S) == FALSE) return;
+
§3.2. If the condition holds, we set the change flag ch and abort the search
+through scenes by jumping past the run of tests. (We can't compile a break
+instruction because we're not compiling a loop.)
+
+
+
Compile code to test the scene end condition3.2 =
+
§4. That's everything except for the consequences of a scene end occurring.
+Code for that is generated here.
+
+
+
Because one end can cause another, given anchoring, we must guard against
+compiler hangs when the source text calls for infinite recursion (since
+this would cause us to generate infinitely long code). So the marker flags
+are used to mark which scenes have already been ended in code generated
+for this purpose.
+
§5. The semantics of scene ending are trickier than they look, because of the
+fact that "Ballroom Dance ends merrily" (say, end number 3) is in some
+sense a specialisation of "Ballroom Dance ends" (1). The doctrine is that
+end 3 causes end 1 to happen first, because a special ending is also a
+general ending; but rules taking effect on end 3 come earlier than
+those for end 1, because they're more specialised, so they have a right to
+take effect first.
+
§5.1. If the scene has the "recurring" either/or property, then any of the
+"ends" endings will fail to reset its status. (This doesn't mean that no
+end actually occurred.)
+
§5.5. In general, the marker count is used to ensure that RTScenes::compile_scene_end_dash
+never calls itself for a scene it has been called with before on this round.
+This prevents Inform locking up generating infinite amounts of code. However,
+one exception is allowed, in very limited circumstances. Suppose we want to
+make a scene recur, but only if it ends in a particular way. Then we might
+type:
+
+
+
+
Brisk Quadrille begins when Brisk Quadrille ends untidily.
+
+
+
This is allowed; it's a case where the "tolerance" below is raised.
+
+
+
Compile code to cause consequent scene ends5.5 =
+
§6. More SCENES output. As we've seen, when the SCENES command has been typed, Inform prints a notice
+out at run-time when any scene end occurs. It also prints a run-down of the
+scene status at the moment the command is typed, and the following code is
+what handles this.
+
§7. During clauses. We've now seen one use of scenes: they kick off rulebooks when they begin or
+end. The other use for them is to predicate rules on whether they are currently
+playing or not, using a "during" clause.
+
+
+
This is where we compile Inter code to test that a scene matching this is
+actually running:
+
+
+
+voidRTScenes::emit_during_clause(parse_node *spec) {
+intstuck = TRUE;
+if (K_scene == NULL) { Produce::val(Emit::tree(), K_truth_state, LITERAL_IVAL, 1); return; }
+if (Rvalues::is_rvalue(spec)) {
+Dash::check_value(spec, K_scene);
+instance *I = Rvalues::to_instance(spec);
+if (Instances::of_kind(I, K_scene)) {
+scene *sc = Scenes::from_named_constant(I);
+Produce::inv_primitive(Emit::tree(), EQ_BIP);
+Produce::down(Emit::tree());
+Produce::inv_primitive(Emit::tree(), LOOKUP_BIP);
+Produce::down(Emit::tree());
+Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(SCENE_STATUS_HL));
+Produce::val(Emit::tree(), K_number, LITERAL_IVAL, (inter_ti) sc->allocation_id);
+Produce::up(Emit::tree());
+Produce::val(Emit::tree(), K_number, LITERAL_IVAL, 1);
+Produce::up(Emit::tree());
+stuck = FALSE;
+ }
+ } else {
+if (Dash::check_value(spec, Kinds::unary_con(CON_description, K_scene)) == ALWAYS_MATCH) {
+parse_node *desc = Descriptions::to_rvalue(spec);
+if (desc) {
+Produce::inv_call_iname(Emit::tree(), Hierarchy::find(DURINGSCENEMATCHING_HL));
+Produce::down(Emit::tree());
+Specifications::Compiler::emit_as_val(K_value, desc);
+Produce::up(Emit::tree());
+stuck = FALSE;
+ }
+ }
+ }
+if (stuck) {
+Produce::val(Emit::tree(), K_truth_state, LITERAL_IVAL, 1);
+StandardProblems::sentence_problem(Task::syntax_tree(),
+_p_(PM_ScenesBadDuring),
+"'during' must be followed by the name of a scene or of a "
+"description which applies to a single scene",
+"such as 'during Station Arrival' or 'during a recurring scene'.");
+return;
+ }
+}
+
diff --git a/docs/runtime-module/5-spt.html b/docs/runtime-module/5-spt.html
index 95fcddc5e..fa177caba 100644
--- a/docs/runtime-module/5-spt.html
+++ b/docs/runtime-module/5-spt.html
@@ -142,7 +142,7 @@ be compiled, so this code is never used.
}
diff --git a/docs/runtime-module/5-tm.html b/docs/runtime-module/5-tm.html
index 392ab236a..6e2ecde9f 100644
--- a/docs/runtime-module/5-tm.html
+++ b/docs/runtime-module/5-tm.html
@@ -341,7 +341,7 @@ identifier names for instance have not yet been settled.
}