1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-06-28 21:14:57 +03:00

Starting beats and required speaker lists

This commit is contained in:
Graham Nelson 2022-09-23 21:34:33 +01:00
parent c78c8a5322
commit 54d9e0404a
21 changed files with 146 additions and 16 deletions

View file

@ -1,6 +1,6 @@
# Inform 7
[Version](notes/versioning.md): 10.2.0-beta+6V68 'Krypton' (22 September 2022)
[Version](notes/versioning.md): 10.2.0-beta+6V69 'Krypton' (23 September 2022)
## About Inform

View file

@ -1,3 +1,3 @@
Prerelease: beta
Build Date: 22 September 2022
Build Number: 6V68
Build Date: 23 September 2022
Build Number: 6V69

View file

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

View file

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

View file

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

View file

@ -113,6 +113,12 @@ Array DirectorStackStart --> MAX_BEAT_PERFORMANCE_NESTING;
}
];
[ PERFORM_OPENING_BEAT_R db;
db = InitialSituation-->START_BEAT_INIS;
if (db) DirectorPerform(db);
rfalse;
];
[ DirectorTraceInst structure pc instruction depth;
];
@ -609,7 +615,7 @@ Global director_is_active = false;
if ((GProperty(DIALOGUE_BEAT_TY, db, performed) == 0) ||
(GProperty(DIALOGUE_BEAT_TY, db, recurring))) {
tab = TableOfDialogueBeats-->db;
i = 3;
i = 4;
while (true) {
speaker = tab-->i;
if (speaker == nothing) rtrue;
@ -620,6 +626,23 @@ Global director_is_active = false;
rfalse;
];
[ DirectorLiveRequiredList list db len i tab speaker;
if ((list==0) || (BlkValueWeakKind(list) ~= LIST_OF_TY)) return 0;
len = 0;
tab = TableOfDialogueBeats-->db;
i = 4;
while (true) {
speaker = tab-->i;
if (speaker == nothing) break;
len++;
i++;
}
LIST_OF_TY_SetLength(list, len);
for (i=0: i<len: i++)
LIST_OF_TY_PutItem(list, i+1, tab-->(i+4));
return list;
];
[ DIALOGUE_DIRECTION_R db i topic fn tab;
if (director_is_active == false) rfalse;
! If nothing much has happened this turn...

View file

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

View file

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

View file

@ -35,5 +35,6 @@ PM_ChoiceDashDashExpected
PM_ChoiceLeftArrowExpected
PM_ChoiceRightArrowExpected
PM_InstancesExplicit
PM_NotASpeaker
DialogueBeats
LBW

View file

@ -0,0 +1,7 @@
The Cricket History Museum is a room.
Section 1 - Arrival (dialogue)
(This is the starting beat. Requiring Felicity Dumplings and Mike Atherton.)
Narration: "There is a sinister chime, as if this museum is in fact run by Spectre."

View file

@ -0,0 +1,17 @@
Inform 7 v10.2.0 has started.
I've now read your source text, which is 39 words long.
I've also read Basic Inform by Graham Nelson, which is 7691 words long.
I've also read English Language by Graham Nelson, which is 2328 words long.
I've also read Standard Rules by Graham Nelson, which is 32643 words long.
Problem__ PM_NotASpeaker
In Section 1 - Arrival:
>--> The dialogue beat '(This is the starting beat . Requiring Felicity
Dumplings and Mike Atherton .)' (source text, line 5) apparently requires a
speaker (other than the player) called 'Felicity Dumplings' to be present
in order for it to be performed, but there's nobody of that name.
Problem__ PM_NotASpeaker
>--> The dialogue beat '(This is the starting beat . Requiring Felicity
Dumplings and Mike Atherton .)' (source text, line 5) apparently requires a
speaker (other than the player) called 'Mike Atherton' to be present in
order for it to be performed, but there's nobody of that name.
Inform 7 has finished.

View file

@ -1305,6 +1305,8 @@ 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 decide what list of objects is the list of speakers required by (B - dialogue beat):
(- DirectorLiveRequiredList({-new:list of objects}, {B}) -).
To perform (B - a dialogue beat):
ask DialogueKit to perform B;
@ -1345,6 +1347,9 @@ To make the dialogue/dialog director passive/inactive:
The dialogue direction rule is listed in the turn sequence rulebook.
The dialogue direction rule translates into Inter as "DIALOGUE_DIRECTION_R".
The performing opening dialogue beat rule is listed in the startup rulebook.
The performing opening dialogue beat rule translates into Inter as "PERFORM_OPENING_BEAT_R".
Section 10 - Dialogue Fallback (not for dialogue language element)
To abide by dialogue before action choices:

View file

@ -145,6 +145,10 @@ wording Scenes::get_name(scene *sc) {
return Instances::get_name(sc->as_instance, FALSE);
}
instance *Scenes::get_instance(scene *sc) {
return sc->as_instance;
}
@ A feature called |xyzzy| generally has a hunk of subject data called |xyzzy_data|,
so we would normally have a structure called |scenes_data|, but in fact that
structure is just going to be //scene//. So:

View file

@ -83,7 +83,9 @@ typedef struct dialogue_beat {
struct heading *under_heading;
struct instance *as_instance;
struct scene *as_scene;
struct linked_list *required; /* of |instance| */
int starting_beat;
struct parse_node *immediately_after;
struct linked_list *some_time_after; /* of |parse_node| */
struct linked_list *some_time_before; /* of |parse_node| */
@ -101,6 +103,8 @@ typedef struct dialogue_beat {
db->under_heading = dialogue_section_being_scanned;
db->as_instance = NULL;
db->as_scene = NULL;
db->required = NEW_LINKED_LIST(instance);
db->starting_beat = FALSE;
db->immediately_after = NULL;
db->some_time_after = NEW_LINKED_LIST(parse_node);
db->some_time_before = NEW_LINKED_LIST(parse_node);
@ -125,6 +129,7 @@ We annotate each clause with the answer. Thus we might have:
@e AFTER_DBC
@e IMMEDIATELY_AFTER_DBC
@e BEFORE_DBC
@e REQUIRING_DBC
@e LATER_DBC
@e NEXT_DBC
@e PROPERTY_DBC
@ -150,10 +155,14 @@ We annotate each clause with the answer. Thus we might have:
after ... | ==> { AFTER_DBC, - }
immediately after ... | ==> { IMMEDIATELY_AFTER_DBC, - }
before ... | ==> { BEFORE_DBC, - }
requiring ... | ==> { REQUIRING_DBC, - }
later | ==> { LATER_DBC, - }
next | ==> { NEXT_DBC, - }
... ==> { PROPERTY_DBC, - }
<dialogue-beat-starting-name> ::=
starting beat
@ It's convenient to be able to read this back in the debugging log, so:
=
@ -167,6 +176,7 @@ void DialogueBeats::write_dbc(OUTPUT_STREAM, int c) {
case AFTER_DBC: WRITE("AFTER"); break;
case IMMEDIATELY_AFTER_DBC: WRITE("IMMEDIATELY_AFTER"); break;
case BEFORE_DBC: WRITE("BEFORE"); break;
case REQUIRING_DBC: WRITE("REQUIRING"); break;
case LATER_DBC: WRITE("LATER"); break;
case NEXT_DBC: WRITE("NEXT"); break;
case PROPERTY_DBC: WRITE("PROPERTY"); break;
@ -191,6 +201,8 @@ but not of course both. If the latter, we construct the beat name itself as
DialogueBeats::non_unique_instance_problem(I, K_dialogue_beat);
} else {
current_dialogue_beat->beat_name = NW;
if (<dialogue-beat-starting-name>(NW))
current_dialogue_beat->starting_beat = TRUE;
}
dialogue_beat_name_count++;
break;
@ -325,6 +337,14 @@ performed only after or before other beats.
DialogueBeats::parse_beat_list(c, db, AL, &iac);
break;
}
case REQUIRING_DBC: {
<dialogue-beat-clause>(CW);
wording A = GET_RW(<dialogue-beat-clause>, 1);
<np-articled-list>(A);
parse_node *AL = <<rp>>;
DialogueBeats::parse_required_speaker_list(db, AL);
break;
}
}
}
if (iac > 1)
@ -353,7 +373,7 @@ void DialogueBeats::parse_beat_list(int c, dialogue_beat *db, parse_node *AL, in
} else if (Node::is(AL, UNPARSED_NOUN_NT)) {
switch(c) {
case IMMEDIATELY_AFTER_DBC: {
wording B = GET_RW(<dialogue-beat-clause>, 1);
wording B = Node::get_text(AL);
parse_node *desc = DialogueBeats::parse_beat_name(B);
if (desc) {
(*iac)++;
@ -362,13 +382,13 @@ void DialogueBeats::parse_beat_list(int c, dialogue_beat *db, parse_node *AL, in
break;
}
case AFTER_DBC: {
wording B = GET_RW(<dialogue-beat-clause>, 1);
wording B = Node::get_text(AL);
parse_node *desc = DialogueBeats::parse_beat_name(B);
if (desc) ADD_TO_LINKED_LIST(desc, parse_node, db->some_time_after);
break;
}
case BEFORE_DBC: {
wording B = GET_RW(<dialogue-beat-clause>, 1);
wording B = Node::get_text(AL);
parse_node *desc = DialogueBeats::parse_beat_name(B);
if (desc) ADD_TO_LINKED_LIST(desc, parse_node, db->some_time_before);
break;
@ -377,6 +397,34 @@ void DialogueBeats::parse_beat_list(int c, dialogue_beat *db, parse_node *AL, in
}
}
void DialogueBeats::parse_required_speaker_list(dialogue_beat *db, parse_node *AL) {
if (Node::is(AL, AND_NT)) {
DialogueBeats::parse_required_speaker_list(db, AL->down);
DialogueBeats::parse_required_speaker_list(db, AL->down->next);
} else if (Node::is(AL, UNPARSED_NOUN_NT)) {
wording B = Node::get_text(AL);
if (<s-type-expression-uncached>(B)) {
parse_node *desc = <<rp>>;
instance *I = Rvalues::to_instance(desc);
if (I) {
kind *K = Instances::to_kind(I);
if (Kinds::Behaviour::is_object(K)) {
ADD_TO_LINKED_LIST(I, instance, db->required);
return;
}
}
}
Problems::quote_source(1, current_sentence);
Problems::quote_wording(2, B);
StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_NotASpeaker));
Problems::issue_problem_segment(
"The dialogue beat %1 apparently requires a speaker (other than the player) "
"called '%2' to be present in order for it to be performed, but there's "
"nobody of that name.");
Problems::issue_problem_end();
}
}
parse_node *DialogueBeats::parse_beat_name(wording CW) {
if (<s-type-expression-uncached>(CW)) {
parse_node *desc = <<rp>>;

View file

@ -1111,6 +1111,7 @@ void Hierarchy::establish(void) {
@e START_OBJECT_INIS_HL
@e START_ROOM_INIS_HL
@e START_TIME_INIS_HL
@e START_BEAT_INIS_HL
@e DONE_INIS_HL
@e NO_DIRECTIONS_HL
@ -1125,6 +1126,7 @@ void Hierarchy::establish(void) {
H_C_T(START_OBJECT_INIS_HL, I"START_OBJECT_INIS")
H_C_T(START_ROOM_INIS_HL, I"START_ROOM_INIS")
H_C_T(START_TIME_INIS_HL, I"START_TIME_INIS")
H_C_T(START_BEAT_INIS_HL, I"START_BEAT_INIS")
H_C_T(DONE_INIS_HL, I"DONE_INIS")
H_END

View file

@ -93,6 +93,17 @@ void RTDialogueBeats::compile(void) {
}
}
void RTDialogueBeats::compile_starting_beat_entry(void) {
dialogue_beat *db, *starting_db = NULL;
LOOP_OVER(db, dialogue_beat) {
if (db->starting_beat) starting_db = db;
}
if (starting_db)
EmitArrays::iname_entry(RTInstances::value_iname(starting_db->as_instance));
else
EmitArrays::numeric_entry(0);
}
void RTDialogueBeats::beat_compilation_agent(compilation_subtask *ct) {
dialogue_beat *db = RETRIEVE_POINTER_dialogue_beat(ct->data);
current_sentence = db->compilation_data.where_created;
@ -105,6 +116,7 @@ void RTDialogueBeats::beat_compilation_agent(compilation_subtask *ct) {
@<Write the availability entry@>;
@<Write the relevance entry@>;
@<Write the structure entry@>;
@<Write the scene entry@>;
@<Write the speaker list@>;
EmitArrays::end(save);
@ -140,9 +152,18 @@ void RTDialogueBeats::beat_compilation_agent(compilation_subtask *ct) {
@<Write the structure entry@> =
EmitArrays::iname_entry(RTDialogueBeats::structure_array_iname(db));
@<Write the scene entry@> =
if (db->as_scene)
EmitArrays::iname_entry(RTInstances::value_iname(Scenes::get_instance(db->as_scene)));
else
EmitArrays::numeric_entry(0);
@<Write the speaker list@> =
linked_list *L = NEW_LINKED_LIST(instance);
RTDialogueBeats::find_speakers_r(L, db->root);
linked_list *L = db->required;
if (LinkedLists::len(L) == 0) {
L = NEW_LINKED_LIST(instance);
RTDialogueBeats::find_speakers_r(L, db->root);
}
instance *I;
LOOP_OVER_LINKED_LIST(I, instance, L)
EmitArrays::iname_entry(RTInstances::value_iname(I));

View file

@ -8,7 +8,8 @@ void RTPlayer::compile_generic_constants(void) {
RTPlayer::InitialSituation_define(START_OBJECT_INIS_HL, 1);
RTPlayer::InitialSituation_define(START_ROOM_INIS_HL, 2);
RTPlayer::InitialSituation_define(START_TIME_INIS_HL, 3);
RTPlayer::InitialSituation_define(DONE_INIS_HL, 4);
RTPlayer::InitialSituation_define(START_BEAT_INIS_HL, 4);
RTPlayer::InitialSituation_define(DONE_INIS_HL, 5);
}
void RTPlayer::InitialSituation(void) {
@ -20,6 +21,7 @@ void RTPlayer::InitialSituation(void) {
if (start_room == NULL) EmitArrays::numeric_entry(0);
else EmitArrays::iname_entry(RTInstances::value_iname(start_room));
RTVariables::initial_value_as_array_entry(time_of_day_VAR);
RTDialogueBeats::compile_starting_beat_entry();
EmitArrays::numeric_entry(0);
EmitArrays::end(save);
Hierarchy::make_available(iname);