1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-06-17 07:40:47 +03:00

Runtime representation of dialogue beats

This commit is contained in:
Graham Nelson 2022-09-17 19:49:46 +01:00
parent 3d53a40960
commit 0736bf435f
34 changed files with 863 additions and 183 deletions

View file

@ -1,6 +1,6 @@
# Inform 7
[Version](notes/versioning.md): 10.2.0-beta+6V62 'Krypton' (16 September 2022)
[Version](notes/versioning.md): 10.2.0-beta+6V63 'Krypton' (17 September 2022)
## About Inform

View file

@ -1,3 +1,3 @@
Prerelease: beta
Build Date: 16 September 2022
Build Number: 6V62
Build Date: 17 September 2022
Build Number: 6V63

View file

@ -3,8 +3,7 @@
Behaviour specific to copies of either the projectbundle or projectfile genres.
@h Scanning metadata.
Metadata for pipelines -- or rather, the complete lack of same -- is stored
in the following structure.
Metadata for projects is stored in the following structure.
=
typedef struct inform_project {
@ -563,7 +562,8 @@ because of the following sort:
kit_dependency *kd;
LOOP_OVER_LINKED_LIST(kd, kit_dependency, project->kits_to_include)
if ((Str::eq(kd->kit->as_copy->edition->work->title, I"CommandParserKit")) ||
(Str::eq(kd->kit->as_copy->edition->work->title, I"WorldModelKit")))
(Str::eq(kd->kit->as_copy->edition->work->title, I"WorldModelKit")) ||
(Str::eq(kd->kit->as_copy->edition->work->title, I"DialogueKit")))
basic = FALSE;
if (basic == FALSE) {
TEMPORARY_TEXT(err)
@ -699,6 +699,25 @@ filename *Projects::get_primary_output(inform_project *proj) {
}
}
@h Detecting dialogue.
There's an awkward timing issue with detecting dialogue in the source text.
The rule is that an Inform project should depend on DialogueKit if it contains
content under a dialogue section, but not otherwise. That in turn activates
the "dialogue" compiler feature. On the other hand, the source text also has
material placed under headings which are for use with dialogue only. So we
can't read the entire source text first and then decide: we have to switch
on the dialogue feature the moment any dialogue matter is found. This is
done by having the //syntax// module call the following:
=
inform_project *project_being_scanned = NULL;
void Projects::dialogue_present(void) {
if (project_being_scanned) {
Projects::add_kit_dependency(project_being_scanned, I"DialogueKit", NULL, NULL, NULL);
Projects::activate_elements(project_being_scanned);
}
}
@h The full graph.
This can be quite grandiose even though most of it will never come to anything,
rather like a family tree for a minor European royal family.
@ -708,11 +727,9 @@ void Projects::construct_graph(inform_project *proj) {
if (proj == NULL) return;
if (proj->chosen_build_target == NULL) {
Projects::finalise_kit_dependencies(proj);
project_being_scanned = proj;
Copies::get_source_text(proj->as_copy);
if (proj->syntax_tree->contains_dialogue) {
Projects::add_kit_dependency(proj, I"DialogueKit", NULL, NULL, NULL);
Projects::activate_elements(proj);
}
project_being_scanned = NULL;
build_vertex *V = proj->as_copy->vertex;
@<Construct the graph upstream of V@>;
@<Construct the graph downstream of V@>;

View file

@ -290,6 +290,11 @@ void SourceText::new_beginend(parse_node *pn, inbuild_copy *C) {
if (Node::get_type(pn) == ENDHERE_NT) Inclusions::check_ends_here(pn, E);
}
@ This callback is called by //syntax// when it first reaches a dialogue line
or beat.
@d DIALOGUE_WARNING_SYNTAX_CALLBACK Projects::dialogue_present
@ Lastly, this callback is called by //syntax// when it hits a sentence like:
>> Use interactive fiction language element.

View file

@ -2,7 +2,7 @@
"is": {
"type": "kit",
"title": "BasicInformExtrasKit",
"version": "10.2.0-beta+6V62"
"version": "10.2.0-beta+6V63"
},
"kit-details": {
"has-priority": 1

View file

@ -2,7 +2,7 @@
"is": {
"type": "kit",
"title": "BasicInformKit",
"version": "10.2.0-beta+6V62"
"version": "10.2.0-beta+6V63"
},
"needs": [ {
"unless": {

View file

@ -2,7 +2,7 @@
"is": {
"type": "kit",
"title": "CommandParserKit",
"version": "10.2.0-beta+6V62"
"version": "10.2.0-beta+6V63"
},
"needs": [ {
"need": {

View file

@ -5,6 +5,108 @@ Run-time support for dialogue.
@h Placeholder.
=
Global latest_performed_beat = 0;
Array DialogueTopicPool --> 20;
[ DirectorEmptyDialogueTopicPool;
DialogueTopicPool-->0 = 0;
];
[ DirectorAddLiveSubjectList obj i;
for (i=18:i>0:i--) DialogueTopicPool-->i = DialogueTopicPool-->(i-1);
DialogueTopicPool-->0 = obj;
DialogueTopicPool-->19 = 0;
];
[ DirectorRemoveLiveSubjectList obj i j;
for (i=0:i<20:i++) {
if (DialogueTopicPool-->i == 0) return;
if (DialogueTopicPool-->i == obj) {
for (j=i:j<19:j++) DialogueTopicPool-->j = DialogueTopicPool-->(j+1);
}
}
DialogueTopicPool-->19 = 0;
];
[ DirectorLiveSubjectList list len i;
if ((list==0) || (BlkValueWeakKind(list) ~= LIST_OF_TY)) return 0;
len = 0;
while (DialogueTopicPool-->len) len++;
LIST_OF_TY_SetLength(list, len);
for (i=0: i<len: i++)
LIST_OF_TY_PutItem(list, i+1, DialogueTopicPool-->i);
return list;
];
[ DirectorAlterLiveSubjectList list len i;
if ((list==0) || (BlkValueWeakKind(list) ~= LIST_OF_TY)) return 0;
len = BlkValueRead(list, LIST_LENGTH_F);
if (len > 19) len = 19;
for (i=0: i<len: i++)
DialogueTopicPool-->i = BlkValueRead(list, LIST_ITEM_BASE+i);
DialogueTopicPool-->len = 0;
DialogueTopicPool-->19 = 0;
];
[ DirectorBegin;
DirectorEmptyDialogueTopicPool();
latest_performed_beat = 0;
rfalse;
];
[ DirectorPerform db;
print "Performing beat ", (PrintDialogueBeatName) db, "^";
latest_performed_beat = db;
];
[ DirectorListLiveTopics i t;
for (i=0: i<20: i++) {
t = DialogueTopicPool-->i;
if (t == 0) return;
print (name) t, "^";
}
];
[ DirectorBeatAvailable db fn;
if ((db == 0) || (db > TableOfDialogueBeats-->0)) rfalse;
fn = TableOfDialogueBeats-->(3*db - 2);
if (fn) {
return (fn)(latest_performed_beat);
}
rtrue;
];
[ DirectorBeatRelevant db fn;
if ((db == 0) || (db > TableOfDialogueBeats-->0)) rfalse;
fn = TableOfDialogueBeats-->(3*db - 1);
if (fn) {
return (fn)(DialogueTopicPool);
}
rfalse;
];
[ DirectorBeatPrintStructure db tab pc which depth i;
if ((db == 0) || (db > TableOfDialogueBeats-->0)) return;
print (PrintDialogueBeatName) db;
print " (";
if (DirectorBeatAvailable(db)) print "available"; else print "unavailable";
print ", ";
if (DirectorBeatRelevant(db)) print "relevant"; else print "irrelevant";
print "):^";
tab = TableOfDialogueBeats-->(3*db);
if (tab) {
pc = 0;
while (tab-->pc) {
which = (tab-->pc)/100;
depth = (tab-->pc)%100;
for (i=0: i<depth: i++) print " ";
switch (which) {
1: print "Line ", (PrintDialogueLineName) tab-->(pc+1), "^";
2: print "Choice ", (PrintDialogueChoiceName) tab-->(pc+1), "^";
3: print "Decision of type ", tab-->(pc+1), "^";
default: print "*** Unimplemented ***^";
}
pc = pc + 2;
}
}
];

View file

@ -2,7 +2,7 @@
"is": {
"type": "kit",
"title": "EnglishLanguageKit",
"version": "10.2.0-beta+6V62"
"version": "10.2.0-beta+6V63"
},
"needs": [ {
"need": {

View file

@ -2,7 +2,7 @@
"is": {
"type": "kit",
"title": "WorldModelKit",
"version": "10.2.0-beta+6V62"
"version": "10.2.0-beta+6V63"
},
"needs": [ {
"need": {

View file

@ -0,0 +1,96 @@
The Cricket History Museum is a room. The bat, the ball and the pads are here. Daphne is a woman in the Museum. The trophy case is in the Museum. The urn and the scoring pencil are in the case.
Daphne can be honest or disingenuous.
A dialogue beat can be dramatic, quiet or subdued.
Spoken rapidly is a performance style.
When play begins:
say "== The stock...";
showme the list of dialogue beats;
showme the list of dialogue lines;
showme the list of dialogue choices;
say "== Dual scene and beat naming...";
showme the alpha scene;
showme the alpha beat;
say "== Properties...";
showme the list of dramatic dialogue beats;
showme the list of subdued dialogue beats;
say "== Performance...";
showme the list of unperformed dialogue beats;
perform the alpha beat;
showme the list of unperformed dialogue beats;
say "== The live conversational subject list...";
showme the live conversational subject list;
make the bat a live conversational subject;
make the ball a live conversational subject;
showme the live conversational subject list;
make the bat a dead conversational subject;
showme the live conversational subject list;
make the ball a dead conversational subject;
showme the live conversational subject list;
make the ball a dead conversational subject;
showme the live conversational subject list;
alter the live conversational subject list to { Daphne, the pads };
showme the live conversational subject list;
say "== Relevance...";
alter the live conversational subject list to { the bat };
showme the live conversational subject list;
showme the list of relevant dialogue beats;
alter the live conversational subject list to { the ball };
showme the live conversational subject list;
showme the list of relevant dialogue beats;
alter the live conversational subject list to { the bat, the scoring pencil };
showme the live conversational subject list;
showme the list of relevant dialogue beats;
say "== Availability...";
now every dialogue beat is unperformed;
showme the list of available dialogue beats;
perform the gamma beat;
showme the list of available dialogue beats;
perform the nu beat;
showme the list of available dialogue beats;
now Daphne is honest;
showme the list of available dialogue beats;
say "== Structure...";
repeat with B running through dialogue beats:
showme the beat structure of B;
Section 1 - Meeting (dialogue)
(This is the alpha scene.)
Daphne: "Welcome to the Museum of Cricket."
(This is the beta beat. About the bat.)
Daphne: "Made of willow, the cricket bat is sprung to provide a good drive."
(This is the gamma beat. About the ball and everything in the case.)
Daphne: "A cricket ball is made with a core of cork, which is layered with tightly wound string, and covered by a leather case with a slightly raised sewn seam."
(This is the delta beat. Immediately after the gamma beat. Quiet.)
Daphne: "I forgot to mention, British Standard BS 5993 specifies the construction details, dimensions, quality and performance of cricket balls."
(This is the epsilon beat. After the gamma beat. Subdued.)
Daphne: "Dukes balls have a prouder seam and will tend to swing more than Kookaburra balls."
(This is the nu beat.)
Daphne: "Cricket's kind of dull, when you think about it."
Ball (this is the disgruntled ball line): "I disagree!"
Bat: "I especially enjoy it."
(This is the mu beat. If Daphne is honest.)
Daphne: "I prefer softball, honestly."
(This is the eta beat. Before the nu beat.)
Daphne: "This is the foremost museum in New South Wales."

View file

@ -0,0 +1,65 @@
Cricket History Museum
== The stock...
"list of dialogue beats" = list of dialogue beats: {alpha beat, beta beat, gamma beat, delta beat, epsilon beat, nu beat, mu beat, eta beat}
"list of dialogue lines" = list of dialogue lines: {line-1, line-2, line-3, line-4, line-5, line-6, disgruntled ball line, line-8, line-9, line-10}
"list of dialogue choices" = list of dialogue choices: {}
== Dual scene and beat naming...
scene: alpha scene
dialogue beat: alpha beat
== Properties...
"list of dramatic dialogue beats" = list of dialogue beats: {alpha beat, beta beat, gamma beat, nu beat, mu beat, eta beat}
"list of subdued dialogue beats" = list of dialogue beats: {epsilon beat}
== Performance...
"list of unperformed dialogue beats" = list of dialogue beats: {alpha beat, beta beat, gamma beat, delta beat, epsilon beat, nu beat, mu beat, eta beat}
Performing beat alpha beat
"list of unperformed dialogue beats" = list of dialogue beats: {beta beat, gamma beat, delta beat, epsilon beat, nu beat, mu beat, eta beat}
== The live conversational subject list...
"live conversational subject list" = list of objects: {}
"live conversational subject list" = list of objects: {ball, bat}
"live conversational subject list" = list of objects: {ball}
"live conversational subject list" = list of objects: {}
"live conversational subject list" = list of objects: {}
"live conversational subject list" = list of objects: {Daphne, pads}
== Relevance...
"live conversational subject list" = list of objects: {bat}
"list of relevant dialogue beats" = list of dialogue beats: {beta beat, gamma beat}
"live conversational subject list" = list of objects: {ball}
"list of relevant dialogue beats" = list of dialogue beats: {gamma beat}
"live conversational subject list" = list of objects: {bat, scoring pencil}
"list of relevant dialogue beats" = list of dialogue beats: {beta beat, gamma beat}
== Availability...
"list of available dialogue beats" = list of dialogue beats: {alpha beat, beta beat, gamma beat, nu beat, eta beat}
Performing beat gamma beat
"list of available dialogue beats" = list of dialogue beats: {alpha beat, beta beat, gamma beat, epsilon beat, nu beat, eta beat}
Performing beat nu beat
"list of available dialogue beats" = list of dialogue beats: {alpha beat, beta beat, gamma beat, epsilon beat, nu beat}
"list of available dialogue beats" = list of dialogue beats: {alpha beat, beta beat, gamma beat, epsilon beat, nu beat, mu beat}
== Structure...
alpha beat (available, irrelevant):
Line line-1
beta beat (available, relevant):
Line line-2
gamma beat (available, relevant):
Line line-3
delta beat (unavailable, irrelevant):
Line line-4
epsilon beat (available, irrelevant):
Line line-5
nu beat (available, irrelevant):
Line line-6
Line disgruntled ball line
Line line-8
mu beat (available, irrelevant):
Line line-9
eta beat (unavailable, irrelevant):
Line line-10
Welcome
An Interactive Fiction
Release 1 / Serial number 160428 / Inform 7 v10.2.0 / D
Cricket History Museum
You can see a bat, a ball, a pads, Daphne and a trophy case (in which are an urn and a scoring pencil) here.
> > Cricket History Museum
> Are you sure you want to quit?

View file

@ -211,7 +211,9 @@ here, which only happens when special runs are made for compiler testing.
BENCH(RTTableColumns::compile)
BENCH(RTEquations::compile)
BENCH(ImperativeDefinitions::compile_first_block)
BENCH(RTDialogue::compile)
BENCH(RTDialogueBeats::compile)
BENCH(RTDialogueLines::compile)
BENCH(RTDialogueChoices::compile)
BENCH(RTRules::compile)
BENCH(RTRulebooks::compile)
BENCH(RTRulebooks::compile_nros)

View file

@ -1269,6 +1269,36 @@ The print protagonist internal rule translates into Inter as
@h Dialogue support.
=
Section 10 - Performance Styles (for dialogue language element only)
Section 10 - Dialogue (for dialogue language element only)
There is a performance style called spoken normally.
A dialogue beat can be performed or unperformed. A dialogue beat is usually
unperformed.
A dialogue beat can be recurring or non-recurring. A dialogue beat is usually
non-recurring.
To make (T - an object) a live conversational subject:
(- DirectorAddLiveSubjectList({T}); -).
To make (T - an object) a dead conversational subject:
(- DirectorRemoveLiveSubjectList({T}); -).
To decide what list of objects is the live conversational subject list:
(- DirectorLiveSubjectList({-new:list of objects}) -).
To alter the live conversational subject list to (L - list of objects):
(- DirectorAlterLiveSubjectList({-by-reference:L}); -).
To perform (B - a dialogue beat):
ask DialogueKit to perform B;
now B is performed.
To ask DialogueKit to perform (B - a dialogue beat):
(- DirectorPerform({B}); -).
To showme the beat structure of (B - dialogue beat): (- DirectorBeatPrintStructure({B}); -).
Definition: A dialogue beat is available rather than unavailable if Inter routine
"DirectorBeatAvailable" says so (it meets all its after or before, if and unless conditions).
Definition: A dialogue beat is relevant rather than irrelevant if Inter routine
"DirectorBeatRelevant" says so (one of the topics it is about is currently live).

View file

@ -106,7 +106,7 @@ typedef struct dialogue_beat {
db->some_time_before = NEW_LINKED_LIST(parse_node);
db->about_list = NEW_LINKED_LIST(parse_node);
db->root = NULL;
db->compilation_data = RTDialogue::new_beat(PN, db);
db->compilation_data = RTDialogueBeats::new_beat(PN, db);
@ Each clause can be one of about 10 possibilities, as follows, and the
wording tells us immediately which possibility it is, even early in the run.

View file

@ -50,7 +50,7 @@ typedef struct dialogue_choice {
dc->selection_parameter = EMPTY_WORDING;
dc->to_perform = NULL;
dc->selection_type = BLANK_DSEL;
dc->compilation_data = RTDialogue::new_choice(PN, dc);
dc->compilation_data = RTDialogueChoices::new(PN, dc);
@ Each choice produces an instance of the kind |dialogue choice|, using the name
given in its clauses if one was.

View file

@ -56,7 +56,7 @@ typedef struct dialogue_line {
dl->speaker_text = EMPTY_WORDING;
dl->speaker_description = NULL;
dl->without_speaking = FALSE;
dl->compilation_data = RTDialogue::new_line(PN, dl);
dl->compilation_data = RTDialogueLines::new(PN, dl);
dl->speech_text = EMPTY_WORDING;
dl->mentioning = NEW_LINKED_LIST(parse_node);
dl->how_performed = PerformanceStyles::default();

View file

@ -11,6 +11,7 @@ handles that kind, so it won't be dealt with in the code for this feature.
=
void Dialogue::start(void) {
Dialogue::declare_annotations();
PluginCalls::plug(NEW_PROPERTY_NOTIFY_PLUG, Dialogue::new_property_notify);
PluginCalls::plug(NEW_BASE_KIND_NOTIFY_PLUG, Dialogue::new_base_kind_notify);
PluginCalls::plug(COMPARE_CONSTANT_PLUG, Dialogue::compare_CONSTANT);
}
@ -37,6 +38,27 @@ int Dialogue::new_base_kind_notify(kind *new_base, text_stream *name, wording W)
return FALSE;
}
@ The following either/or property needs some compiler support:
= (early code)
property *P_performed = NULL;
@ We will need to compile code using this.
=
<notable-dialogue-properties> ::=
performed
@ =
int Dialogue::new_property_notify(property *prn) {
if (<notable-dialogue-properties>(prn->name)) {
switch (<<r>>) {
case 0: P_performed = prn; break;
}
}
return FALSE;
}
@ The rest of this section is to some extent boiler-plate code: it provides for
specific beats and lines to be represented as rvalues, both inside the compiler
(and when typechecking) and at runtime.

View file

@ -959,7 +959,15 @@ void Hierarchy::establish(void) {
@e INLINE_PROPERTIES_HAP
@e INLINE_PROPERTY_HL
@e DIRECTION_HL
@e BEAT_FILTER_FN_HL
@e INSTANCE_IS_DB_MD_HL
@e INSTANCE_IS_DL_MD_HL
@e INSTANCE_IS_DC_MD_HL
@e BEAT_AVAILABLE_MD_HL
@e BEAT_AVAILABLE_FN_HL
@e BEAT_RELEVANT_MD_HL
@e BEAT_RELEVANT_FN_HL
@e BEAT_STRUCTURE_MD_HL
@e BEAT_STRUCTURE_HL
@<Establish instances@> =
submodule_identity *instances = LargeScale::register_submodule_identity(I"instances");
@ -1052,7 +1060,15 @@ void Hierarchy::establish(void) {
H_F_G(REGION_FOUND_IN_FN_HL, I"region_found_in_fn", I"RFI_for_I")
H_F_G(TSD_DOOR_DIR_FN_HL, I"tsd_door_dir_fn", I"TSD_door_dir_value")
H_F_G(TSD_DOOR_TO_FN_HL, I"tsd_door_to_fn", I"TSD_door_to_value")
H_F_G(BEAT_FILTER_FN_HL, I"beat_filter_fn", I"DB_filter")
H_C_U(INSTANCE_IS_DB_MD_HL, I"^is_dialogue_beat")
H_C_U(INSTANCE_IS_DL_MD_HL, I"^is_dialogue_line")
H_C_U(INSTANCE_IS_DC_MD_HL, I"^is_dialogue_choice")
H_C_U(BEAT_AVAILABLE_MD_HL, I"^available")
H_F_U(BEAT_AVAILABLE_FN_HL, I"available_fn")
H_C_U(BEAT_RELEVANT_MD_HL, I"^relevant")
H_F_U(BEAT_RELEVANT_FN_HL, I"relevant_fn")
H_C_U(BEAT_STRUCTURE_MD_HL, I"^structure")
H_C_U(BEAT_STRUCTURE_HL, I"structure")
H_F_U(INST_SHOWME_FN_HL, I"showme_fn")
H_BEGIN_AP(INLINE_PROPERTIES_HAP, I"inline_property", I"_inline_property")
H_C_U(INLINE_PROPERTY_HL, I"inline")

View file

@ -0,0 +1,340 @@
[RTDialogueBeats::] Dialogue Beat Instances.
To compile any dialogue details in the instances submodule.
@h Compilation data for dialogue beats.
Each |dialogue_beat| object contains this data:
=
typedef struct dialogue_beat_compilation_data {
struct parse_node *where_created;
struct inter_name *available_function;
struct inter_name *relevant_function;
struct inter_name *structure_array;
} dialogue_beat_compilation_data;
dialogue_beat_compilation_data RTDialogueBeats::new_beat(parse_node *PN, dialogue_beat *db) {
dialogue_beat_compilation_data dbcd;
dbcd.where_created = PN;
dbcd.available_function = NULL;
dbcd.relevant_function = NULL;
dbcd.structure_array = NULL;
return dbcd;
}
package_request *RTDialogueBeats::package(dialogue_beat *db) {
if (db->as_instance == NULL) internal_error("not available yet");
return RTInstances::package(db->as_instance);
}
inter_name *RTDialogueBeats::available_fn_iname(dialogue_beat *db) {
if (db->compilation_data.available_function == NULL)
db->compilation_data.available_function =
Hierarchy::make_iname_in(BEAT_AVAILABLE_FN_HL, RTDialogueBeats::package(db));
return db->compilation_data.available_function;
}
inter_name *RTDialogueBeats::relevant_fn_iname(dialogue_beat *db) {
if (db->compilation_data.relevant_function == NULL)
db->compilation_data.relevant_function =
Hierarchy::make_iname_in(BEAT_RELEVANT_FN_HL, RTDialogueBeats::package(db));
return db->compilation_data.relevant_function;
}
inter_name *RTDialogueBeats::structure_fn_iname(dialogue_beat *db) {
if (db->compilation_data.structure_array == NULL)
db->compilation_data.structure_array =
Hierarchy::make_iname_in(BEAT_STRUCTURE_HL, RTDialogueBeats::package(db));
return db->compilation_data.structure_array;
}
@h Compilation of dialogue.
=
void RTDialogueBeats::compile(void) {
dialogue_beat *db;
LOOP_OVER(db, dialogue_beat) {
text_stream *desc = Str::new();
WRITE_TO(desc, "dialogue beat %d", db->allocation_id);
Sequence::queue(&RTDialogueBeats::beat_compilation_agent, STORE_POINTER_dialogue_beat(db), desc);
}
}
void RTDialogueBeats::beat_compilation_agent(compilation_subtask *ct) {
dialogue_beat *db = RETRIEVE_POINTER_dialogue_beat(ct->data);
current_sentence = db->compilation_data.where_created;
package_request *PR = RTDialogueBeats::package(db);
@<Deal with the availability of the beat@>;
@<Deal with the relevance of the beat@>;
@<Compile the structure array@>;
}
@<Deal with the availability of the beat@> =
int conditions = 0;
for (parse_node *clause = db->cue_at->down; clause; clause = clause->next) {
int c = Annotations::read_int(clause, dialogue_beat_clause_ANNOT);
if ((c == IF_DBC) || (c == UNLESS_DBC)) conditions++;
}
if ((db->immediately_after) ||
(LinkedLists::len(db->some_time_after) > 0) ||
(LinkedLists::len(db->some_time_before) > 0) ||
(conditions > 0)) {
Hierarchy::apply_metadata_from_iname(PR,
BEAT_AVAILABLE_MD_HL, RTDialogueBeats::available_fn_iname(db));
@<Compile the available function@>;
}
@<Compile the available function@> =
packaging_state save = Functions::begin(RTDialogueBeats::available_fn_iname(db));
local_variable *latest = LocalVariables::new_internal_commented(I"latest", I"most recently performed beat");
LocalVariables::set_kind(latest, K_dialogue_beat);
inter_symbol *latest_s = LocalVariables::declare(latest);
if (db->immediately_after) @<Check the immediately after condition@>;
@<Check the after and before conditions@>;
@<Check the if and unless conditions@>;
EmitCode::rtrue();
Functions::end(save);
@<Check the immediately after condition@> =
EmitCode::inv(IF_BIP);
EmitCode::down();
EmitCode::inv(NE_BIP);
EmitCode::down();
EmitCode::val_symbol(K_value, latest_s);
EmitCode::val_number(0);
EmitCode::up();
EmitCode::code();
EmitCode::down();
@<Return false if latest does not match the immediately after description@>;
EmitCode::rfalse();
EmitCode::up();
EmitCode::up();
@<Return false if latest does not match the immediately after description@> =
EmitCode::inv(IF_BIP);
EmitCode::down();
instance *I = Rvalues::to_instance(db->immediately_after);
if (I) {
EmitCode::inv(NE_BIP);
EmitCode::down();
EmitCode::val_symbol(K_value, latest_s);
EmitCode::val_iname(K_dialogue_beat, RTInstances::value_iname(I));
EmitCode::up();
} else {
pcalc_prop *prop = Propositions::negate(Descriptions::to_proposition(db->immediately_after));
if (prop) {
TypecheckPropositions::type_check(prop,
TypecheckPropositions::tc_no_problem_reporting());
CompilePropositions::to_test_as_condition(Lvalues::new_LOCAL_VARIABLE(EMPTY_WORDING, latest), prop);
} else {
internal_error("cannot test");
}
}
EmitCode::code();
EmitCode::down();
EmitCode::rfalse();
EmitCode::up();
EmitCode::up();
@<Check the after and before conditions@> =
parse_node *desc;
LOOP_OVER_LINKED_LIST(desc, parse_node, db->some_time_after) {
int negate_me = FALSE;
@<Work out proposition@>;
}
LOOP_OVER_LINKED_LIST(desc, parse_node, db->some_time_before) {
int negate_me = TRUE;
@<Work out proposition@>;
}
@<Work out proposition@> =
instance *I = Rvalues::to_instance(desc);
pcalc_prop *prop = NULL;
adjective *adj = EitherOrProperties::as_adjective(P_performed);
if (I) {
prop = AdjectivalPredicates::new_atom(adj, negate_me, Terms::new_constant(desc));
} else {
pcalc_prop *exists = Atoms::QUANTIFIER_new(exists_quantifier, 0, 0);
pcalc_prop *domain = KindPredicates::new_atom(K_dialogue_beat, Terms::new_variable(0));
pcalc_prop *performed = AdjectivalPredicates::new_atom(adj, negate_me, Terms::new_variable(0));
pcalc_prop *desc_prop = Descriptions::to_proposition(desc);
prop = Propositions::concatenate(exists,
Propositions::concatenate(domain,
Propositions::concatenate(performed,
desc_prop)));
}
prop = Propositions::negate(prop);
EmitCode::inv(IF_BIP);
EmitCode::down();
TypecheckPropositions::type_check(prop,
TypecheckPropositions::tc_no_problem_reporting());
CompilePropositions::to_test_as_condition(NULL, prop);
EmitCode::code();
EmitCode::down();
EmitCode::rfalse();
EmitCode::up();
EmitCode::up();
@<Check the if and unless conditions@> =
current_sentence = db->cue_at;
for (parse_node *clause = db->cue_at->down; clause; clause = clause->next) {
wording CW = Node::get_text(clause);
int c = Annotations::read_int(clause, dialogue_beat_clause_ANNOT);
switch (c) {
case IF_DBC:
case UNLESS_DBC: {
<dialogue-beat-clause>(CW);
wording A = GET_RW(<dialogue-beat-clause>, 1);
if (<s-condition>(A)) {
parse_node *cond = <<rp>>;
if (Dash::validate_conditional_clause(cond)) {
EmitCode::inv(IF_BIP);
EmitCode::down();
if (c == IF_DBC) {
EmitCode::inv(NOT_BIP);
EmitCode::down();
}
CompileValues::to_code_val_of_kind(cond, K_truth_state);
if (c == IF_DBC) {
EmitCode::up();
}
EmitCode::code();
EmitCode::down();
EmitCode::rfalse();
EmitCode::up();
EmitCode::up();
}
}
break;
}
}
}
@<Deal with the relevance of the beat@> =
if (LinkedLists::len(db->about_list) > 0) {
Hierarchy::apply_metadata_from_iname(PR,
BEAT_RELEVANT_MD_HL, RTDialogueBeats::relevant_fn_iname(db));
@<Compile the relevant function@>;
}
@<Compile the relevant function@> =
packaging_state save = Functions::begin(RTDialogueBeats::relevant_fn_iname(db));
local_variable *pool = LocalVariables::new_internal_commented(I"pool", I"pool of live topics");
local_variable *iv = LocalVariables::new_internal_commented(I"iv", I"index variable");
local_variable *topic = LocalVariables::new_internal_commented(I"topic", I"live topic");
inter_symbol *pool_s = LocalVariables::declare(pool);
inter_symbol *iv_s = LocalVariables::declare(iv);
inter_symbol *topic_s = LocalVariables::declare(topic);
@<Check the about list against the subject pool@>;
EmitCode::rfalse();
Functions::end(save);
@<Check the about list against the subject pool@> =
inter_symbol *loop_label = EmitCode::reserve_label(I"about_loop");
EmitCode::place_label(loop_label);
EmitCode::inv(STORE_BIP);
EmitCode::down();
EmitCode::ref_symbol(K_value, topic_s);
EmitCode::inv(LOOKUP_BIP);
EmitCode::down();
EmitCode::val_symbol(K_value, pool_s);
EmitCode::val_symbol(K_value, iv_s);
EmitCode::up();
EmitCode::up();
EmitCode::inv(IF_BIP);
EmitCode::down();
EmitCode::inv(NE_BIP);
EmitCode::down();
EmitCode::val_symbol(K_value, topic_s);
EmitCode::val_number(0);
EmitCode::up();
EmitCode::code();
EmitCode::down();
parse_node *desc;
LOOP_OVER_LINKED_LIST(desc, parse_node, db->about_list) {
instance *I = Rvalues::to_instance(desc);
EmitCode::inv(IF_BIP);
EmitCode::down();
if (I) {
EmitCode::inv(EQ_BIP);
EmitCode::down();
EmitCode::val_symbol(K_value, topic_s);
EmitCode::val_iname(K_value, RTInstances::value_iname(I));
EmitCode::up();
} else {
pcalc_prop *prop = Descriptions::to_proposition(desc);
if (prop) {
TypecheckPropositions::type_check(prop,
TypecheckPropositions::tc_no_problem_reporting());
CompilePropositions::to_test_as_condition(
Lvalues::new_LOCAL_VARIABLE(EMPTY_WORDING, topic), prop);
} else {
internal_error("cannot test");
}
}
EmitCode::code();
EmitCode::down();
EmitCode::rtrue();
EmitCode::up();
EmitCode::up();
}
EmitCode::inv(POSTINCREMENT_BIP);
EmitCode::down();
EmitCode::ref_symbol(K_value, iv_s);
EmitCode::up();
EmitCode::inv(JUMP_BIP);
EmitCode::down();
EmitCode::lab(loop_label);
EmitCode::up();
EmitCode::up();
EmitCode::up();
EmitCode::rfalse();
@ And this is always present.
@<Compile the structure array@> =
Hierarchy::apply_metadata_from_iname(PR,
BEAT_STRUCTURE_MD_HL, RTDialogueBeats::structure_fn_iname(db));
packaging_state save =
EmitArrays::begin_word(RTDialogueBeats::structure_fn_iname(db), K_value);
RTDialogueBeats::compile_structure_r(db->root, 1);
EmitArrays::numeric_entry(0);
EmitArrays::end(save);
@ =
void RTDialogueBeats::compile_structure_r(dialogue_node *dn, inter_ti depth) {
while (dn) {
if (dn->if_line) {
EmitArrays::numeric_entry(depth + 100);
EmitArrays::iname_entry(RTInstances::value_iname(dn->if_line->as_instance));
} else if (dn->if_choice) {
EmitArrays::numeric_entry(depth + 200);
EmitArrays::iname_entry(RTInstances::value_iname(dn->if_choice->as_instance));
} else if (dn->if_decision) {
EmitArrays::numeric_entry(depth + 300);
EmitArrays::numeric_entry((inter_ti) (dn->if_decision->decision_type));
} else internal_error("unimplemented dialogue node compilation");
if (dn->child_node)
RTDialogueBeats::compile_structure_r(dn->child_node, depth+1);
dn = dn->next_node;
}
}
@ =
void RTDialogueBeats::log_r(dialogue_node *dn) {
while (dn) {
if (dn->if_line)
LOG("Line %d = %W\n",
dn->if_line->allocation_id, Node::get_text(dn->if_line->compilation_data.where_created));
if (dn->if_choice)
LOG("Choice %d = %W\n",
dn->if_choice->allocation_id, Node::get_text(dn->if_choice->compilation_data.where_created));
if (dn->child_node) {
if (dn->child_node->parent_node != dn) LOG("*** Broken parentage ***\n");
LOG_INDENT;
RTDialogueBeats::log_r(dn->child_node);
LOG_OUTDENT;
}
dn = dn->next_node;
}
}

View file

@ -0,0 +1,36 @@
[RTDialogueChoices::] Dialogue Choice Instances.
To compile any dialogue details in the instances submodule.
@h Compilation data for dialogue choices.
Each |dialogue_choice| object contains this data:
=
typedef struct dialogue_choice_compilation_data {
struct parse_node *where_created;
} dialogue_choice_compilation_data;
dialogue_choice_compilation_data RTDialogueChoices::new(parse_node *PN, dialogue_choice *dc) {
dialogue_choice_compilation_data dlcd;
dlcd.where_created = PN;
return dlcd;
}
@h Compilation of dialogue.
=
void RTDialogueChoices::compile(void) {
dialogue_choice *dc;
LOOP_OVER(dc, dialogue_choice) {
text_stream *desc = Str::new();
WRITE_TO(desc, "dialogue choice %d", dc->allocation_id);
Sequence::queue(&RTDialogueChoices::choice_compilation_agent,
STORE_POINTER_dialogue_choice(dc), desc);
}
}
@ =
void RTDialogueChoices::choice_compilation_agent(compilation_subtask *ct) {
dialogue_choice *dc = RETRIEVE_POINTER_dialogue_choice(ct->data);
current_sentence = dc->compilation_data.where_created;
}

View file

@ -0,0 +1,35 @@
[RTDialogueLines::] Dialogue.
To compile any dialogue details in the instances submodule.
@h Compilation data for dialogue lines.
Each |dialogue_line| object contains this data:
=
typedef struct dialogue_line_compilation_data {
struct parse_node *where_created;
} dialogue_line_compilation_data;
dialogue_line_compilation_data RTDialogueLines::new(parse_node *PN, dialogue_line *dl) {
dialogue_line_compilation_data dlcd;
dlcd.where_created = PN;
return dlcd;
}
@h Compilation of dialogue.
=
void RTDialogueLines::compile(void) {
dialogue_line *dl;
LOOP_OVER(dl, dialogue_line) {
text_stream *desc = Str::new();
WRITE_TO(desc, "dialogue line %d", dl->allocation_id);
Sequence::queue(&RTDialogueLines::line_compilation_agent, STORE_POINTER_dialogue_line(dl), desc);
}
}
@ =
void RTDialogueLines::line_compilation_agent(compilation_subtask *ct) {
dialogue_line *dl = RETRIEVE_POINTER_dialogue_line(ct->data);
current_sentence = dl->compilation_data.where_created;
}

View file

@ -1,160 +0,0 @@
[RTDialogue::] Dialogue.
To compile the dialogue submodule for a compilation unit, which contains
something to be worked out.
@h Compilation data for dialogue beats.
Each |dialogue_beat| object contains this data:
=
typedef struct dialogue_beat_compilation_data {
struct parse_node *where_created;
struct inter_name *usage_filter_function;
} dialogue_beat_compilation_data;
dialogue_beat_compilation_data RTDialogue::new_beat(parse_node *PN, dialogue_beat *db) {
dialogue_beat_compilation_data dbcd;
dbcd.where_created = PN;
dbcd.usage_filter_function = NULL;
return dbcd;
}
inter_name *RTDialogue::beat_filter(dialogue_beat *db) {
if (db->compilation_data.usage_filter_function == NULL)
db->compilation_data.usage_filter_function =
Hierarchy::make_iname_in(BEAT_FILTER_FN_HL, RTInstances::package(db->as_instance));
return db->compilation_data.usage_filter_function;
}
@h Compilation data for dialogue lines.
Each |dialogue_line| object contains this data:
=
typedef struct dialogue_line_compilation_data {
struct parse_node *where_created;
} dialogue_line_compilation_data;
dialogue_line_compilation_data RTDialogue::new_line(parse_node *PN, dialogue_line *dl) {
dialogue_line_compilation_data dlcd;
dlcd.where_created = PN;
return dlcd;
}
@h Compilation data for dialogue choices.
Each |dialogue_choice| object contains this data:
=
typedef struct dialogue_choice_compilation_data {
struct parse_node *where_created;
} dialogue_choice_compilation_data;
dialogue_choice_compilation_data RTDialogue::new_choice(parse_node *PN, dialogue_choice *dc) {
dialogue_choice_compilation_data dlcd;
dlcd.where_created = PN;
return dlcd;
}
@h Compilation of dialogue.
=
void RTDialogue::compile(void) {
dialogue_beat *db;
LOOP_OVER(db, dialogue_beat) {
text_stream *desc = Str::new();
WRITE_TO(desc, "dialogue beat %d", db->allocation_id);
Sequence::queue(&RTDialogue::beat_compilation_agent, STORE_POINTER_dialogue_beat(db), desc);
}
dialogue_line *dl;
LOOP_OVER(dl, dialogue_line) {
text_stream *desc = Str::new();
WRITE_TO(desc, "dialogue line %d", dl->allocation_id);
Sequence::queue(&RTDialogue::line_compilation_agent, STORE_POINTER_dialogue_line(dl), desc);
}
}
void RTDialogue::beat_compilation_agent(compilation_subtask *ct) {
dialogue_beat *db = RETRIEVE_POINTER_dialogue_beat(ct->data);
current_sentence = db->compilation_data.where_created;
LOG("Beat %d = %W name '%W' scene '%W'\n",
db->allocation_id, Node::get_text(current_sentence), db->beat_name, db->scene_name);
RTDialogue::log_r(db->root);
packaging_state save = Functions::begin(RTDialogue::beat_filter(db));
local_variable *latest = LocalVariables::new_internal_commented(I"latest", I"most recently performed beat");
LocalVariables::set_kind(latest, K_dialogue_beat);
local_variable *pool = LocalVariables::new_internal_commented(I"pool", I"pool of live topics");
inter_symbol *latest_s = LocalVariables::declare(latest);
inter_symbol *pool_s = LocalVariables::declare(pool);
if (db->immediately_after) {
EmitCode::inv(IF_BIP);
EmitCode::down();
EmitCode::inv(NE_BIP);
EmitCode::down();
EmitCode::val_symbol(K_value, latest_s);
EmitCode::val_number(0);
EmitCode::up();
EmitCode::code();
EmitCode::down();
@<Return true if latest matches the immediately after description@>;
EmitCode::rfalse();
EmitCode::up();
EmitCode::up();
}
EmitCode::inv(STORE_BIP);
EmitCode::down();
EmitCode::ref_symbol(K_value, pool_s);
EmitCode::val_number(0);
EmitCode::up();
EmitCode::rfalse();
Functions::end(save);
}
@<Return true if latest matches the immediately after description@> =
EmitCode::inv(IF_BIP);
EmitCode::down();
LOG("IA cond is $T\n", db->immediately_after);
instance *I = Rvalues::to_instance(db->immediately_after);
if (I) {
EmitCode::inv(EQ_BIP);
EmitCode::down();
EmitCode::val_symbol(K_value, latest_s);
EmitCode::val_iname(K_dialogue_beat, RTInstances::value_iname(I));
EmitCode::up();
} else {
pcalc_prop *prop = Descriptions::to_proposition(db->immediately_after);
if (prop) {
CompilePropositions::to_test_as_condition(Lvalues::new_LOCAL_VARIABLE(EMPTY_WORDING, latest), prop);
} else {
internal_error("cannot test");
}
}
EmitCode::code();
EmitCode::down();
EmitCode::rtrue();
EmitCode::up();
EmitCode::up();
@ =
void RTDialogue::line_compilation_agent(compilation_subtask *ct) {
dialogue_line *dl = RETRIEVE_POINTER_dialogue_line(ct->data);
current_sentence = dl->compilation_data.where_created;
LOG("Line %d = %W name '%W'\n", dl->allocation_id, Node::get_text(current_sentence), dl->line_name);
}
void RTDialogue::log_r(dialogue_node *dn) {
while (dn) {
if (dn->if_line)
LOG("Line %d = %W\n",
dn->if_line->allocation_id, Node::get_text(dn->if_line->compilation_data.where_created));
if (dn->if_choice)
LOG("Choice %d = %W\n",
dn->if_choice->allocation_id, Node::get_text(dn->if_choice->compilation_data.where_created));
if (dn->child_node) {
if (dn->child_node->parent_node != dn) LOG("*** Broken parentage ***\n");
LOG_INDENT;
RTDialogue::log_r(dn->child_node);
LOG_OUTDENT;
}
dn = dn->next_node;
}
}

View file

@ -157,6 +157,15 @@ void RTInstances::compilation_agent(compilation_subtask *t) {
if ((K_sound_name) && (Kinds::eq(K, K_sound_name)))
Hierarchy::apply_metadata_from_number(pack,
INSTANCE_IS_SOUND_MD_HL, 1);
if ((K_dialogue_beat) && (Kinds::eq(K, K_dialogue_beat)))
Hierarchy::apply_metadata_from_number(pack,
INSTANCE_IS_DB_MD_HL, 1);
if ((K_dialogue_line) && (Kinds::eq(K, K_dialogue_line)))
Hierarchy::apply_metadata_from_number(pack,
INSTANCE_IS_DL_MD_HL, 1);
if ((K_dialogue_choice) && (Kinds::eq(K, K_dialogue_choice)))
Hierarchy::apply_metadata_from_number(pack,
INSTANCE_IS_DC_MD_HL, 1);
if ((K_figure_name) && (Kinds::eq(K, K_figure_name)))
Hierarchy::apply_metadata_from_number(pack,
INSTANCE_IS_FIGURE_MD_HL, 1);

View file

@ -61,7 +61,9 @@ Chapter 5: Provision Submodules
Multimedia
Tables
Table Columns
Dialogue
Dialogue Beat Instances
Dialogue Line Instances
Dialogue Choice Instances
Rules
Rulebooks
Variables

View file

@ -0,0 +1,46 @@
[SynopticDialogue::] Dialogue.
To compile the main/synoptic/dialogue submodule.
@ Our inventory |inv| already contains a list |inv->instance_nodes| of all packages
in the tree with type |_instance|.
For the moment, at least, it seems too ambitious to dynamically renumber instances
in the linking stage. Until then, this section is something of a placeholder,
making only a debugging function.
=
void SynopticDialogue::compile(inter_tree *I, pipeline_step *step, tree_inventory *inv) {
if (InterNodeList::array_len(inv->instance_nodes) > 0)
InterNodeList::array_sort(inv->instance_nodes, MakeSynopticModuleStage::module_order);
@<Define DIALOGUEBEATS array@>;
}
@<Define DIALOGUEBEATS array@> =
inter_ti count = 0;
for (int i=0; i<InterNodeList::array_len(inv->instance_nodes); i++) {
inter_package *pack =
PackageInstruction::at_this_head(inv->instance_nodes->list[i].node);
if (Metadata::read_optional_numeric(pack, I"^is_dialogue_beat")) count++;
}
inter_name *iname = HierarchyLocations::iname(I, DIALOGUEBEATS_HL);
Synoptic::begin_array(I, step, iname);
Synoptic::numeric_entry(count);
if (count == 0) Synoptic::numeric_entry(0);
for (int i=0; i<InterNodeList::array_len(inv->instance_nodes); i++) {
inter_package *pack =
PackageInstruction::at_this_head(inv->instance_nodes->list[i].node);
if (Metadata::read_optional_numeric(pack, I"^is_dialogue_beat")) {
inter_symbol *filter = Metadata::optional_symbol(pack, I"^available");
if (filter) Synoptic::symbol_entry(filter);
else Synoptic::numeric_entry(0);
inter_symbol *rel = Metadata::optional_symbol(pack, I"^relevant");
if (rel) Synoptic::symbol_entry(rel);
else Synoptic::numeric_entry(0);
inter_symbol *str = Metadata::optional_symbol(pack, I"^structure");
if (str) Synoptic::symbol_entry(str);
else Synoptic::numeric_entry(0);
}
}
Synoptic::end_array(I);

View file

@ -28,6 +28,7 @@ int MakeSynopticModuleStage::run(pipeline_step *step) {
SynopticChronology::compile(I, step, inv);
SynopticExtensions::compile(I, step, inv);
SynopticInstances::compile(I, step, inv);
SynopticDialogue::compile(I, step, inv);
SynopticKinds::compile(I, step, inv);
SynopticMultimedia::compile(I, step, inv);
SynopticProperties::compile(I, step, inv);

View file

@ -21,6 +21,7 @@ void SynopticHierarchy::establish(inter_tree *I) {
@<Resources for activities@>;
@<Resources for chronology@>;
@<Resources for conjugations@>;
@<Resources for dialogue@>;
@<Resources for extensions@>;
@<Resources for instances@>;
@<Resources for kinds@>;
@ -117,6 +118,15 @@ The |/main/synoptic/conjugations| submodule.
SYN_SUBMD(I"conjugations")
SYN_CONST(TABLEOFVERBS_HL, I"TableOfVerbs")
@h Dialogue.
The |/main/synoptic/dialogue| submodule.
@e DIALOGUEBEATS_HL
@<Resources for dialogue@> =
SYN_SUBMD(I"dialogue")
SYN_CONST(DIALOGUEBEATS_HL, I"TableOfDialogueBeats")
@h Extensions.
The |/main/synoptic/extensions| submodule.

View file

@ -41,6 +41,7 @@ Chapter 5: Synoptic Module
Activities
Actions
Instances
Dialogue
Kinds
Properties
Relations

View file

@ -706,6 +706,11 @@ here. This hand-tooled parser is annoyingly long to write out, but only in
order to catch improbable unmatched-bracket errors with tidy error messages.
@<Make a DIALOGUE node@> =
#ifdef DIALOGUE_WARNING_SYNTAX_CALLBACK
if (T->contains_dialogue == FALSE) {
DIALOGUE_WARNING_SYNTAX_CALLBACK();
}
#endif
T->contains_dialogue = TRUE;
if ((Lexer::word(Wordings::first_wn(W)) == OPENBRACKET_V) &&
(Lexer::word(Wordings::last_wn(W)) == CLOSEBRACKET_V))