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:
parent
3d53a40960
commit
0736bf435f
|
@ -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
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
Prerelease: beta
|
||||
Build Date: 16 September 2022
|
||||
Build Number: 6V62
|
||||
Build Date: 17 September 2022
|
||||
Build Number: 6V63
|
||||
|
|
|
@ -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@>;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"is": {
|
||||
"type": "kit",
|
||||
"title": "BasicInformKit",
|
||||
"version": "10.2.0-beta+6V62"
|
||||
"version": "10.2.0-beta+6V63"
|
||||
},
|
||||
"needs": [ {
|
||||
"unless": {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"is": {
|
||||
"type": "kit",
|
||||
"title": "CommandParserKit",
|
||||
"version": "10.2.0-beta+6V62"
|
||||
"version": "10.2.0-beta+6V63"
|
||||
},
|
||||
"needs": [ {
|
||||
"need": {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -2,7 +2,7 @@
|
|||
"is": {
|
||||
"type": "kit",
|
||||
"title": "EnglishLanguageKit",
|
||||
"version": "10.2.0-beta+6V62"
|
||||
"version": "10.2.0-beta+6V63"
|
||||
},
|
||||
"needs": [ {
|
||||
"need": {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"is": {
|
||||
"type": "kit",
|
||||
"title": "WorldModelKit",
|
||||
"version": "10.2.0-beta+6V62"
|
||||
"version": "10.2.0-beta+6V63"
|
||||
},
|
||||
"needs": [ {
|
||||
"need": {
|
||||
|
|
96
inform7/Tests/Test Cases/DialogueBeats.txt
Normal file
96
inform7/Tests/Test Cases/DialogueBeats.txt
Normal 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."
|
65
inform7/Tests/Test Cases/_Results_Ideal/DialogueBeats.txt
Normal file
65
inform7/Tests/Test Cases/_Results_Ideal/DialogueBeats.txt
Normal 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?
|
|
@ -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)
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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")
|
||||
|
|
340
inform7/runtime-module/Chapter 5/Dialogue Beat Instances.w
Normal file
340
inform7/runtime-module/Chapter 5/Dialogue Beat Instances.w
Normal 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;
|
||||
}
|
||||
}
|
36
inform7/runtime-module/Chapter 5/Dialogue Choice Instances.w
Normal file
36
inform7/runtime-module/Chapter 5/Dialogue Choice Instances.w
Normal 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;
|
||||
}
|
35
inform7/runtime-module/Chapter 5/Dialogue Line Instances.w
Normal file
35
inform7/runtime-module/Chapter 5/Dialogue Line Instances.w
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
46
inter/pipeline-module/Chapter 5/Dialogue.w
Normal file
46
inter/pipeline-module/Chapter 5/Dialogue.w
Normal 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);
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ Chapter 5: Synoptic Module
|
|||
Activities
|
||||
Actions
|
||||
Instances
|
||||
Dialogue
|
||||
Kinds
|
||||
Properties
|
||||
Relations
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in a new issue