Some additions to an _instance package for instances of the kind "backdrop".
§1. Compilation. We add a found_in function to test whether the given backdrop is found in the current location or not.
void RTScenes::compile_extra(instance *I) { if ((K_scene) && (Instances::of_kind(I, K_scene))) { scene *sc = Scenes::from_named_constant(I); package_request *pack = RTInstances::package(I); Hierarchy::apply_metadata_from_number(pack, INSTANCE_IS_SCENE_MD_HL, 1); if (Scenes::is_entire_game(I)) Hierarchy::apply_metadata_from_number(pack, INSTANCE_IS_ENTIRE_GAME_MD_HL, 1); if (sc->start_of_play) Hierarchy::apply_metadata_from_number(pack, INSTANCE_SCENE_STARTS_MD_HL, 1); else if (sc->ends[0].anchor_condition) Hierarchy::apply_metadata_from_number(pack, INSTANCE_SCENE_STARTS_ON_CONDITION_MD_HL, 1); if (sc->ends[0].as_beat) Hierarchy::apply_metadata_from_iname(pack, INSTANCE_SCENE_STARTS_ON_BEAT_MD_HL, RTDialogueBeats::iname(sc->ends[0].as_beat)); if (sc->ends[1].as_beat) Hierarchy::apply_metadata_from_iname(pack, INSTANCE_SCENE_ENDS_ON_BEAT_MD_HL, RTDialogueBeats::iname(sc->ends[1].as_beat)); inference_subject *subj = Instances::as_subject(sc->as_instance); if (PropertyInferences::either_or_state(subj, P_recurring) > UNKNOWN_CE) Hierarchy::apply_metadata_from_number(pack, INSTANCE_SCENE_RECURS_MD_HL, 1); int ways_to_end = 0; for (int e=1; e<sc->no_ends; e++) { if (sc->ends[e].as_beat) ways_to_end++; if (sc->ends[e].anchor_connectors) ways_to_end++; if (sc->ends[e].anchor_condition) ways_to_end++; } if (ways_to_end == 0) Hierarchy::apply_metadata_from_number(pack, INSTANCE_SCENE_NEVER_ENDS_MD_HL, 1); text_stream *desc = Str::new(); WRITE_TO(desc, "scene change fn for "); Instances::write(desc, I); Sequence::queue(&RTScenes::change_compilation_agent, STORE_POINTER_scene(sc), desc); text_stream *desc2 = Str::new(); WRITE_TO(desc2, "scene status fn for "); Instances::write(desc, I); Sequence::queue(&RTScenes::status_compilation_agent, STORE_POINTER_scene(sc), desc2); for (int e=0; e<sc->no_ends; e++) { package_request *EP = Hierarchy::package_within(SCENE_ENDS_HAP, pack); Hierarchy::apply_metadata_from_raw_wording(EP, SCENE_END_NAME_MD_HL, sc->ends[e].end_names); Hierarchy::apply_metadata_from_number(EP, SCENE_END_AT_MD_HL, (inter_ti) Wordings::first_wn(Node::get_text(sc->ends[e].anchor_condition_set))); Hierarchy::apply_metadata_from_raw_wording(EP, SCENE_END_CONDITION_MD_HL, Node::get_text(sc->ends[e].anchor_condition)); Hierarchy::apply_metadata_from_iname(EP, SCENE_END_RULEBOOK_MD_HL, RTRulebooks::id_iname(sc->ends[e].end_rulebook)); for (scene_connector *scon = sc->ends[e].anchor_connectors; scon; scon=scon->next) { package_request *CP = Hierarchy::package_within(SCENE_CONNECTORS_HAP, EP); Hierarchy::apply_metadata_from_iname(CP, SCENE_CONNECTOR_TO_MD_HL, RTInstances::value_iname(scon->connect_to->as_instance)); Hierarchy::apply_metadata_from_number(CP, SCENE_CONNECTOR_END_MD_HL, (inter_ti) scon->end); Hierarchy::apply_metadata_from_number(CP, SCENE_CONNECTOR_AT_MD_HL, (inter_ti) Wordings::first_wn(Node::get_text(scon->where_said))); } } } }
§2. Runtime data. Each scene has an associated function which runs once per turn to decide whether or not a scene change has happened, and to take action if so.
At runtime, 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 arrays which are indexed by scene ID number, a number at runtime which agrees with the allocation ID at compile-time for the scene structure: i.e, it counts upwards from 0 in creation order.
The arrays are:
- ● 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).
§3. Scene change functions. 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.
void RTScenes::change_compilation_agent(compilation_subtask *t) { scene *sc = (scene *) RETRIEVE_POINTER_scene(t->data); package_request *pack = RTInstances::package(sc->as_instance); inter_name *iname = Hierarchy::make_iname_in(SCENE_CHANGE_FN_HL, pack); packaging_state save = Functions::begin(iname); inter_symbol *ch_s = LocalVariables::new_internal_commented_as_symbol(I"ch", I"flag: change made"); Compile code detecting the ends of a specific scene3.1; EmitCode::rfalse(); Functions::end(save); inter_name *md_iname = Hierarchy::make_iname_in(INSTANCE_SCF_MD_HL, pack); Emit::iname_constant(md_iname, K_value, iname); }
§3.1. 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 scene3.1 =
EmitCode::inv(IF_BIP); EmitCode::down(); EmitCode::inv(EQ_BIP); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_object, Hierarchy::find(SCENE_STATUS_HL)); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::val_number(1); EmitCode::up(); EmitCode::code(); EmitCode::down(); for (int end=sc->no_ends-1; end>=1; end--) RTScenes::test_scene_end(sc, end, ch_s); EmitCode::up(); EmitCode::up(); EmitCode::inv(IF_BIP); EmitCode::down(); EmitCode::inv(EQ_BIP); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_object, Hierarchy::find(SCENE_STATUS_HL)); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::val_number(0); EmitCode::up(); EmitCode::code(); EmitCode::down(); RTScenes::test_scene_end(sc, 0, ch_s); EmitCode::up(); EmitCode::up();
- This code is used in §3.
§4. 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.
void RTScenes::test_scene_end(scene *sc, int end, inter_symbol *ch_s) { if ((end == 0) && (sc->start_of_play)) { EmitCode::inv(IF_BIP); EmitCode::down(); EmitCode::inv(EQ_BIP); EmitCode::down(); EmitCode::inv(BITWISEAND_BIP); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_object, Hierarchy::find(SCENE_ENDINGS_HL)); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::val_number(1); EmitCode::up(); EmitCode::val_number(0); EmitCode::up(); EmitCode::code(); EmitCode::down(); RTScenes::compile_scene_end(sc, 0); EmitCode::up(); EmitCode::up(); } parse_node *S = sc->ends[end].anchor_condition; if (S) { Reparse the scene end condition in this new context4.1; Compile code to test the scene end condition4.2; } dialogue_beat *db = sc->ends[end].as_beat; if (db) { Compile code to test the beat end condition4.3; } }
§4.1. Reparse the scene end condition in this new context4.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;
- This code is used in §4.
§4.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 condition4.2 =
EmitCode::inv(IF_BIP); EmitCode::down(); current_sentence = sc->ends[end].anchor_condition_set; CompileValues::to_code_val_of_kind(S, K_truth_state); EmitCode::code(); EmitCode::down(); EmitCode::inv(STORE_BIP); EmitCode::down(); EmitCode::ref_symbol(K_value, ch_s); EmitCode::val_number(1); EmitCode::up(); RTScenes::compile_scene_end(sc, end); EmitCode::rtrue(); EmitCode::up(); EmitCode::up();
- This code is used in §4.
§4.3. 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 beat end condition4.3 =
EmitCode::inv(IF_BIP); EmitCode::down(); if (end == 0) { EmitCode::call(Hierarchy::find(DIRECTOR_BEAT_BEING_PERFORMED_HL)); EmitCode::down(); EmitCode::val_iname(K_value, RTDialogueBeats::iname(sc->ends[end].as_beat)); EmitCode::up(); } else if (end == 1) { EmitCode::inv(EQ_BIP); EmitCode::down(); EmitCode::call(Hierarchy::find(DIRECTOR_BEAT_BEING_PERFORMED_HL)); EmitCode::down(); EmitCode::val_iname(K_value, RTDialogueBeats::iname(sc->ends[end].as_beat)); EmitCode::up(); EmitCode::val_number(0); EmitCode::up(); } else internal_error("only ends 0 and 1 can be tied to a beat"); EmitCode::code(); EmitCode::down(); EmitCode::inv(STORE_BIP); EmitCode::down(); EmitCode::ref_symbol(K_value, ch_s); EmitCode::val_number(1); EmitCode::up(); RTScenes::compile_scene_end(sc, end); EmitCode::rtrue(); EmitCode::up(); EmitCode::up();
- This code is used in §4.
§5. 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.
void RTScenes::compile_scene_end(scene *sc, int end) { scene *sc2; LOOP_OVER(sc2, scene) sc2->marker = 0; RTScenes::compile_scene_end_r(sc, end); }
§6. 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.
void RTScenes::compile_scene_end_r(scene *sc, int end) { int ix = sc->allocation_id; sc->marker++; if (end >= 2) { int e = end; end = 1; Compile code to print text in response to the SCENES command6.4; Compile code to update the scene status6.1; Compile code to update the arrays recording most recent scene ending6.3; end = e; } Compile code to print text in response to the SCENES command6.4; Compile code to update the scene status6.1; Compile code to run the scene end rulebooks6.2; Compile code to update the arrays recording most recent scene ending6.3; Compile code to cause consequent scene ends6.5; if (end >= 2) { int e = end; end = 1; Compile code to run the scene end rulebooks6.2; Compile code to cause consequent scene ends6.5; end = e; } }
§6.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.)
Compile code to update the scene status6.1 =
if (end == 0) { EmitCode::inv(STORE_BIP); EmitCode::down(); EmitCode::reference(); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_value, Hierarchy::find(SCENE_STATUS_HL)); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::up(); EmitCode::val_number(1); EmitCode::up(); } else { EmitCode::inv(IFELSE_BIP); EmitCode::down(); inter_name *iname = Hierarchy::find(GPROPERTY_HL); EmitCode::call(iname); EmitCode::down(); RTKindIDs::emit_weak_ID_as_val(K_scene); EmitCode::val_number((inter_ti) ix+1); EmitCode::val_iname(K_value, RTProperties::iname(P_recurring)); EmitCode::up(); EmitCode::code(); EmitCode::down(); EmitCode::inv(STORE_BIP); EmitCode::down(); EmitCode::reference(); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_value, Hierarchy::find(SCENE_STATUS_HL)); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::up(); EmitCode::val_number(0); EmitCode::up(); EmitCode::up(); EmitCode::code(); EmitCode::down(); EmitCode::inv(STORE_BIP); EmitCode::down(); EmitCode::reference(); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_value, Hierarchy::find(SCENE_STATUS_HL)); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::up(); EmitCode::val_number(2); EmitCode::up(); EmitCode::up(); EmitCode::up(); }
- This code is used in §6 (twice).
§6.2. Compile code to run the scene end rulebooks6.2 =
if (end == 0) { EmitCode::call(Hierarchy::find(FOLLOWRULEBOOK_HL)); EmitCode::down(); EmitCode::val_iname(K_value, Hierarchy::find(WHEN_SCENE_BEGINS_HL)); EmitCode::val_number((inter_ti) (sc->allocation_id + 1)); EmitCode::up(); } EmitCode::call(Hierarchy::find(FOLLOWRULEBOOK_HL)); EmitCode::down(); EmitCode::val_iname(K_value, RTRulebooks::id_iname(sc->ends[end].end_rulebook)); EmitCode::up(); if (end == 1) { EmitCode::call(Hierarchy::find(FOLLOWRULEBOOK_HL)); EmitCode::down(); EmitCode::val_iname(K_value, Hierarchy::find(WHEN_SCENE_ENDS_HL)); EmitCode::val_number((inter_ti) (sc->allocation_id + 1)); EmitCode::up(); } if ((end == 0) && (sc->ends[0].as_beat)) { EmitCode::call(Hierarchy::find(DIRECTOR_PERFORM_TIED_BEAT_HL)); EmitCode::down(); EmitCode::val_iname(K_value, RTDialogueBeats::iname(sc->ends[0].as_beat)); EmitCode::up(); }
- This code is used in §6 (twice).
§6.3. Compile code to update the arrays recording most recent scene ending6.3 =
inter_name *sarr = Hierarchy::find(SCENE_ENDED_HL); if (end == 0) sarr = Hierarchy::find(SCENE_STARTED_HL); EmitCode::inv(STORE_BIP); EmitCode::down(); EmitCode::reference(); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_value, sarr); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::up(); EmitCode::val_iname(K_number, Hierarchy::find(THE_TIME_HL)); EmitCode::up(); EmitCode::inv(STORE_BIP); EmitCode::down(); EmitCode::reference(); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_value, Hierarchy::find(SCENE_ENDINGS_HL)); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::up(); EmitCode::inv(BITWISEOR_BIP); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_value, Hierarchy::find(SCENE_ENDINGS_HL)); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::val_number((inter_ti) (1 << end)); EmitCode::up(); EmitCode::up(); EmitCode::inv(STORE_BIP); EmitCode::down(); EmitCode::reference(); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_value, Hierarchy::find(SCENE_LATEST_ENDING_HL)); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::up(); EmitCode::val_number((inter_ti) end); EmitCode::up();
- This code is used in §6 (twice).
§6.4. Compile code to print text in response to the SCENES command6.4 =
EmitCode::inv(IF_BIP); EmitCode::down(); EmitCode::val_iname(K_value, Hierarchy::find(DEBUG_SCENES_HL)); EmitCode::code(); EmitCode::down(); TEMPORARY_TEXT(OUT) WRITE("[Scene '"); if (sc->as_instance) WRITE("%+W", Instances::get_name(sc->as_instance, FALSE)); WRITE("' "); if (end == 0) WRITE("begins"); else WRITE("ends"); if (end >= 2) WRITE(" %+W", sc->ends[end].end_names); WRITE("]\n"); EmitCode::inv(PRINT_BIP); EmitCode::down(); EmitCode::val_text(OUT); EmitCode::up(); DISCARD_TEXT(OUT) EmitCode::up(); EmitCode::up();
- This code is used in §6 (twice).
§6.5. In general, the marker count is used to ensure that RTScenes::compile_scene_end_r 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 ends6.5 =
scene *other_scene; LOOP_OVER(other_scene, scene) { int tolerance = 1; if (sc == other_scene) tolerance = sc->no_ends; if (other_scene->marker < tolerance) { int other_end; for (other_end = 0; other_end < other_scene->no_ends; other_end++) { scene_connector *scon; for (scon = other_scene->ends[other_end].anchor_connectors; scon; scon = scon->next) { if ((scon->connect_to == sc) && (scon->end == end)) { EmitCode::inv(IF_BIP); EmitCode::down(); EmitCode::inv(EQ_BIP); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_value, Hierarchy::find(SCENE_STATUS_HL)); EmitCode::val_number((inter_ti) other_scene->allocation_id); EmitCode::up(); if (other_end >= 1) EmitCode::val_number(1); else EmitCode::val_number(0); EmitCode::up(); EmitCode::code(); EmitCode::down(); RTScenes::compile_scene_end_r(other_scene, other_end); EmitCode::up(); EmitCode::up(); } } } } }
- This code is used in §6 (twice).
§7. 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 for the scene in question.
void RTScenes::status_compilation_agent(compilation_subtask *t) { scene *sc = (scene *) RETRIEVE_POINTER_scene(t->data); inter_name *iname = Hierarchy::make_iname_in(SCENE_STATUS_FN_HL, RTInstances::package(sc->as_instance)); packaging_state save = Functions::begin(iname); EmitCode::inv(IFDEBUG_BIP); EmitCode::down(); EmitCode::code(); EmitCode::down(); wording NW = Instances::get_name(sc->as_instance, FALSE); EmitCode::inv(IFELSE_BIP); EmitCode::down(); EmitCode::inv(EQ_BIP); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_object, Hierarchy::find(SCENE_STATUS_HL)); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::val_number(1); EmitCode::up(); EmitCode::code(); EmitCode::down(); Show status of this running scene7.1; EmitCode::up(); EmitCode::code(); EmitCode::down(); Show status of this non-running scene7.2; EmitCode::up(); EmitCode::up(); EmitCode::up(); EmitCode::up(); Functions::end(save); inter_name *md_iname = Hierarchy::make_iname_in(INSTANCE_SSF_MD_HL, RTInstances::package(sc->as_instance)); Emit::iname_constant(md_iname, K_value, iname); }
§7.1. Show status of this running scene7.1 =
TEMPORARY_TEXT(T) WRITE_TO(T, "Scene '%+W' playing (for ", NW); EmitCode::inv(PRINT_BIP); EmitCode::down(); EmitCode::val_text(T); EmitCode::up(); DISCARD_TEXT(T) EmitCode::inv(PRINTNUMBER_BIP); EmitCode::down(); EmitCode::inv(MINUS_BIP); EmitCode::down(); EmitCode::val_iname(K_number, Hierarchy::find(THE_TIME_HL)); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_object, Hierarchy::find(SCENE_STARTED_HL)); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::up(); EmitCode::up(); EmitCode::inv(PRINT_BIP); EmitCode::down(); EmitCode::val_text(I" mins now)\n"); EmitCode::up();
- This code is used in §7.
§7.2. Show status of this non-running scene7.2 =
EmitCode::inv(IF_BIP); EmitCode::down(); EmitCode::inv(GT_BIP); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_object, Hierarchy::find(SCENE_LATEST_ENDING_HL)); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::val_number(0); EmitCode::up(); EmitCode::code(); EmitCode::down(); Show status of this recently ended scene7.2.1; EmitCode::up(); EmitCode::up();
- This code is used in §7.
§7.2.1. Show status of this recently ended scene7.2.1 =
TEMPORARY_TEXT(T) WRITE_TO(T, "Scene '%+W' ended", NW); EmitCode::inv(PRINT_BIP); EmitCode::down(); EmitCode::val_text(T); EmitCode::up(); DISCARD_TEXT(T) if (sc->no_ends > 2) { EmitCode::inv(SWITCH_BIP); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_object, Hierarchy::find(SCENE_LATEST_ENDING_HL)); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::code(); EmitCode::down(); for (int end=2; end<sc->no_ends; end++) { EmitCode::inv(CASE_BIP); EmitCode::down(); EmitCode::val_number((inter_ti) end); EmitCode::code(); EmitCode::down(); TEMPORARY_TEXT(T) WRITE_TO(T, " %+W", sc->ends[end].end_names); EmitCode::inv(PRINT_BIP); EmitCode::down(); EmitCode::val_text(T); EmitCode::up(); DISCARD_TEXT(T) EmitCode::up(); EmitCode::up(); } EmitCode::up(); EmitCode::up(); } EmitCode::inv(PRINT_BIP); EmitCode::down(); EmitCode::val_text(I"\n"); EmitCode::up();
- This code is used in §7.2.
§8. 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:
void RTScenes::compile_during_clause(parse_node *spec) { int stuck = TRUE; if (K_scene == NULL) { EmitCode::val_true(); 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); EmitCode::inv(EQ_BIP); EmitCode::down(); EmitCode::inv(LOOKUP_BIP); EmitCode::down(); EmitCode::val_iname(K_value, Hierarchy::find(SCENE_STATUS_HL)); EmitCode::val_number((inter_ti) sc->allocation_id); EmitCode::up(); EmitCode::val_number(1); EmitCode::up(); 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) { EmitCode::call(Hierarchy::find(DURINGSCENEMATCHING_HL)); EmitCode::down(); CompileValues::to_code_val(desc); EmitCode::up(); stuck = FALSE; } } } if (stuck) { EmitCode::val_true(); 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; } }