A feature to provide support for backdrop objects, which are present as scenery in multiple rooms at once.
§1. While we normally assume that nothing can be in more than one place at
once, backdrops are an exception. These are intended to represent widely
spread, probably background, things, such as the sky, and then placing one
inside something generates found_in_inf rather than parentage_inf
inferences to avoid piling up bogus inconsistencies.
void Backdrops::start(void) { Backdrops::create_inference_families(); #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wincompatible-function-pointer-types-strict" PluginCalls::plug(NEW_BASE_KIND_NOTIFY_PLUG, Backdrops::new_base_kind_notify); PluginCalls::plug(NEW_SUBJECT_NOTIFY_PLUG, Backdrops::new_subject_notify); PluginCalls::plug(NEW_PROPERTY_NOTIFY_PLUG, Backdrops::new_property_notify); PluginCalls::plug(COMPLETE_MODEL_PLUG, Backdrops::complete_model); PluginCalls::plug(INTERVENE_IN_ASSERTION_PLUG, Backdrops::intervene_in_assertion); #pragma clang diagnostic pop }
§2. Instances. Every inference subject contains a pointer to its own unique copy of the following minimal structure, though it will only be relevant for instances of "backdrop":
define BACKDROPS_DATA(I) FEATURE_DATA_ON_INSTANCE(backdrops, I)
typedef struct backdrops_data { struct inter_name *found_in_fn_iname; int many_places; CLASS_DEFINITION } backdrops_data; int Backdrops::new_subject_notify(inference_subject *subj) { backdrops_data *bd = CREATE(backdrops_data); bd->found_in_fn_iname = NULL; bd->many_places = FALSE; ATTACH_FEATURE_DATA_TO_SUBJECT(backdrops, subj, bd); return FALSE; }
- The structure backdrops_data is private to this section.
§3. Kinds. This a kind name to do with backdrops which Inform provides special support for; it recognises the English name when defined by the Standard Rules. (So there is no need to translate this to other languages.)
kind *K_backdrop = NULL;
<notable-backdrops-kinds> ::= backdrop
- This is Preform grammar, not regular C code.
int Backdrops::new_base_kind_notify(kind *new_base, text_stream *name, wording W) { if (<notable-backdrops-kinds>(W)) { K_backdrop = new_base; return TRUE; } return FALSE; } int Backdrops::object_is_a_backdrop(instance *I) { if ((K_backdrop) && (I) && (Instances::of_kind(I, K_backdrop))) return TRUE; return FALSE; }
§6. Properties. This is a property name to do with backdrops 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.)
<notable-backdrops-properties> ::= scenery
- This is Preform grammar, not regular C code.
property *P_scenery = NULL; /* an I7 either/or property marking something as scenery */ int Backdrops::new_property_notify(property *prn) { if (<notable-backdrops-properties>(prn->name)) P_scenery = prn; return FALSE; } int Backdrops::object_is_scenery(instance *I) { if (PropertyInferences::either_or_state(Instances::as_subject(I), P_scenery) > 0) return TRUE; return FALSE; }
§8. Here we look at "in" and "part of" relationships to see if they concern
backdrops; if they do, then they need to become found_in_inf inferences.
Without this intervention, they'd be subject to the usual spatial rules
and text like
The sky is in the Grand Balcony. The sky is in the Vizier's Lawn.
would lead to contradiction problem messages.
int Backdrops::assert_relations(binary_predicate *relation, instance *I0, instance *I1) { if ((Instances::of_kind(I1, K_backdrop)) && ((relation == R_incorporation) || (relation == R_containment) || (relation == R_regional_containment))) { inference_subject *bd = Instances::as_subject(I1); inference_subject *loc = Instances::as_subject(I0); SpatialInferences::infer_part_of(bd, IMPOSSIBLE_CE, loc); SpatialInferences::infer_is_room(bd, IMPOSSIBLE_CE); inference *i = Backdrops::new_found_in_inference(loc, CERTAIN_CE); Inferences::join_inference(i, bd); return TRUE; } return FALSE; }
§9. Everywhere. Here we defines a form of noun phrase special to Backdrops (because a backdrop can be said to be "everywhere", which nothing else can).
<notable-backdrops-noun-phrases> ::= everywhere
- This is Preform grammar, not regular C code.
int Backdrops::intervene_in_assertion(parse_node *px, parse_node *py) { if ((Node::get_type(py) == EVERY_NT) && (<notable-backdrops-noun-phrases>(Node::get_text(py)))) { inference_subject *left_subject = Node::get_subject(px); if (left_subject == NULL) UsingProblems::assertion_problem(Task::syntax_tree(), _p_(PM_ValueEverywhere), "'everywhere' can only be used to place individual backdrops", "so although 'The mist is a backdrop. The mist is everywhere.' " "would be fine, 'Corruption is everywhere.' would not."); else if (KindSubjects::to_kind(left_subject)) StandardProblems::subject_problem_at_sentence(_p_(PM_KindOfBackdropEverywhere), left_subject, "seems to be said to be 'everywhere' in some way", "which doesn't make sense. An individual backdrop can be 'everywhere', " "but here we're talking about a whole kind, and it's not allowed " "to talk about general locations of a whole kind of things at once."); else Assert::true_about( Propositions::Abstract::to_put_everywhere(), left_subject, prevailing_mood); return TRUE; } return FALSE; }
property *P_absent = NULL; /* an I6-only property for backdrops out of play */ int Backdrops::complete_model(int stage) { if (stage == WORLD_STAGE_II) { P_absent = EitherOrProperties::new_nameless(I"absent"); // RTProperties::recommend_storing_as_attribute(P_absent, TRUE); instance *I; LOOP_OVER_INSTANCES(I, K_object) { parse_node *val_of_found_in = NULL; If the object is found everywhere, make a found-in property accordingly11.1; int room_count = 0, region_count = 0; Find how many rooms or regions the object is found inside11.2; if ((val_of_found_in == NULL) && (room_count > 0) && (room_count < 16) && (region_count == 0)) The object is found only in a few rooms, and no regions, so make it a list11.3; if ((val_of_found_in == NULL) && (room_count + region_count > 0)) The object is found in many rooms or in whole regions, so make it a routine11.4; if ((val_of_found_in == NULL) && (Instances::of_kind(I, K_backdrop))) The object is found nowhere, so give it a stub found-in property and mark it absent11.5; if (val_of_found_in) Map::set_found_in(I, val_of_found_in); } } return FALSE; }
§11.1. If the object is found everywhere, make a found-in property accordingly11.1 =
inference *inf; POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), found_everywhere_inf) { val_of_found_in = Rvalues::from_iname(Hierarchy::find(FOUND_EVERYWHERE_HL)); break; }
- This code is used in §11.
§11.2. Find how many rooms or regions the object is found inside11.2 =
inference *inf; POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), found_in_inf) { instance *loc = Backdrops::get_inferred_location(inf); if ((K_region) && (Instances::of_kind(loc, K_region))) region_count++; else room_count++; }
- This code is used in §11.
§11.3. The object is found only in a few rooms, and no regions, so make it a list11.3 =
package_request *PR = Hierarchy::package_within(INLINE_PROPERTIES_HAP, RTInstances::package(I)); inter_name *iname = Hierarchy::make_iname_in(INLINE_PROPERTY_HL, PR); packaging_state save = EmitArrays::begin_inline(iname, K_value); inference *inf; POSITIVE_KNOWLEDGE_LOOP(inf, Instances::as_subject(I), found_in_inf) EmitArrays::iname_entry(RTInstances::value_iname(Backdrops::get_inferred_location(inf))); EmitArrays::end(save); val_of_found_in = Rvalues::from_iname(iname);
- This code is used in §11.
§11.4. The object is found in many rooms or in whole regions, so make it a routine11.4 =
val_of_found_in = Rvalues::from_iname(RTBackdropInstances::found_in_val(I, TRUE));
- This code is used in §11.
§11.5. absent is an I6-only attribute which marks a backdrop has having been removed
from the world model. It's not sufficient for an object's found_in always to
say no to the question "are you in the current location?"; the I6 template
code, derived from the old I6 library, requires absent to be set. So:
The object is found nowhere, so give it a stub found-in property and mark it absent11.5 =
val_of_found_in = Rvalues::from_iname(RTBackdropInstances::found_in_val(I, FALSE)); EitherOrProperties::assert( P_absent, Instances::as_subject(I), TRUE, CERTAIN_CE);
- This code is used in §11.
inference_family *found_in_inf = NULL; /* for backdrop things in many places */ inference_family *found_everywhere_inf = NULL; /* ditto */
void Backdrops::create_inference_families(void) { found_in_inf = Inferences::new_family(I"found_in_inf"); METHOD_ADD(found_in_inf, LOG_DETAILS_INF_MTID, Backdrops::log); METHOD_ADD(found_in_inf, COMPARE_INF_MTID, Backdrops::cmp); found_everywhere_inf = Inferences::new_family(I"found_everywhere_inf"); }
typedef struct found_in_inference_data { struct inference_subject *location; CLASS_DEFINITION } found_in_inference_data; inference *Backdrops::new_found_in_inference(inference_subject *loc, int certitude) { PROTECTED_MODEL_PROCEDURE; found_in_inference_data *data = CREATE(found_in_inference_data); data->location = InferenceSubjects::divert(loc); return Inferences::create_inference(found_in_inf, STORE_POINTER_found_in_inference_data(data), certitude); } void Backdrops::log(inference_family *f, inference *inf) { found_in_inference_data *data = RETRIEVE_POINTER_found_in_inference_data(inf->data); if (data->location) LOG(" in:$j", data->location); } int Backdrops::cmp(inference_family *f, inference *i1, inference *i2) { found_in_inference_data *data1 = RETRIEVE_POINTER_found_in_inference_data(i1->data); found_in_inference_data *data2 = RETRIEVE_POINTER_found_in_inference_data(i2->data); int c = Inferences::measure_infs(data1->location) - Inferences::measure_infs(data2->location); if (c > 0) return CI_DIFFER_IN_TOPIC; if (c < 0) return -CI_DIFFER_IN_TOPIC; c = Inferences::measure_inf(i1) - Inferences::measure_inf(i2); if (c > 0) return CI_DIFFER_IN_COPY_ONLY; if (c < 0) return -CI_DIFFER_IN_COPY_ONLY; return CI_IDENTICAL; } instance *Backdrops::get_inferred_location(inference *i) { if ((i == NULL) || (i->family != found_in_inf)) internal_error("not a found_in_inf inf"); found_in_inference_data *data = RETRIEVE_POINTER_found_in_inference_data(i->data); return InstanceSubjects::to_instance(data->location); }
- The structure found_in_inference_data is private to this section.
void Backdrops::infer_presence_everywhere(instance *I) { if ((I == NULL) || (Instances::of_kind(I, K_backdrop) == FALSE)) { StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_EverywhereNonBackdrop), "only a backdrop can be everywhere", "and no other kind of object will do. For instance, 'The sky is " "a backdrop which is everywhere.' is allowed, but 'The travelator " "is a vehicle which is everywhere.' is not."); return; } Inferences::join_inference(Inferences::create_inference(found_everywhere_inf, NULL_GENERAL_POINTER, prevailing_mood), Instances::as_subject(I)); }