A nascent system for managing conversation.

§1. This feature, dialogue, is technically not part of if, but it clearly belongs in this module.

Note that a child feature called performance styles — see Performance Styles — 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_ACTIVITY_NOTIFY_PLUG, Dialogue::new_activity_notify);
    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);
}

§2. These two kinds are both created by a Neptune file belonging to DialogueKit, and are recognised by their Inter identifiers:

kind *K_dialogue_beat = NULL;
kind *K_dialogue_line = NULL;
kind *K_dialogue_choice = NULL;

§3.

int Dialogue::new_base_kind_notify(kind *new_base, text_stream *name, wording W) {
    if (Str::eq_wide_string(name, U"DIALOGUE_BEAT_TY")) {
        K_dialogue_beat = new_base; return TRUE;
    }
    if (Str::eq_wide_string(name, U"DIALOGUE_LINE_TY")) {
        K_dialogue_line = new_base; return TRUE;
    }
    if (Str::eq_wide_string(name, U"DIALOGUE_CHOICE_TY")) {
        K_dialogue_choice = new_base; return TRUE;
    }
    return FALSE;
}

§4. The following need some compiler support:

property *P_elaborated = NULL;
property *P_performed = NULL;

activity *AV_offering_a_dialogue_choice = NULL;
activity *AV_performing_dialogue = NULL;

§5. We will need to compile code using this.

<notable-dialogue-properties> ::=
    elaborated |
    performed

<notable-dialogue-activities> ::=
    offering |
    performing

§6.

int Dialogue::new_property_notify(property *prn) {
    if (<notable-dialogue-properties>(prn->name)) {
        switch (<<r>>) {
            case 0: P_elaborated = prn; break;
            case 1: P_performed = prn; break;
        }
    }
    return FALSE;
}

int Dialogue::new_activity_notify(activity *av) {
    if (<notable-dialogue-activities>(av->name)) {
        switch (<<r>>) {
            case 0: AV_offering_a_dialogue_choice = av; break;
            case 1: AV_performing_dialogue = av; break;
        }
    }
    return FALSE;
}

§7. 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.

parse_node *Dialogue::rvalue_from_dialogue_beat(dialogue_beat *val) {
    CONV_FROM(dialogue_beat, K_dialogue_beat) }
dialogue_beat *Dialogue::rvalue_to_dialogue_beat(parse_node *spec) { CONV_TO(dialogue_beat) }
parse_node *Dialogue::rvalue_from_dialogue_line(dialogue_line *val) {
    CONV_FROM(dialogue_line, K_dialogue_line) }
dialogue_line *Dialogue::rvalue_to_dialogue_line(parse_node *spec) { CONV_TO(dialogue_line) }
parse_node *Dialogue::rvalue_from_dialogue_choice(dialogue_choice *val) {
    CONV_FROM(dialogue_choice, K_dialogue_choice) }
dialogue_choice *Dialogue::rvalue_to_dialogue_choice(parse_node *spec) { CONV_TO(dialogue_choice) }

§8. These can be compared at compile time, which means that type-checking can be used to select phrases or rules depending on specific beats or lines.

int Dialogue::compare_CONSTANT(parse_node *spec1, parse_node *spec2, int *rv) {
    kind *K = Node::get_kind_of_value(spec1);
    if (Kinds::eq(K, K_dialogue_beat)) {
        if (Dialogue::rvalue_to_dialogue_beat(spec1) ==
            Dialogue::rvalue_to_dialogue_beat(spec2)) {
            *rv = TRUE;
        }
        *rv = FALSE;
        return TRUE;
    }
    if (Kinds::eq(K, K_dialogue_line)) {
        if (Dialogue::rvalue_to_dialogue_line(spec1) ==
            Dialogue::rvalue_to_dialogue_line(spec2)) {
            *rv = TRUE;
        }
        *rv = FALSE;
        return TRUE;
    }
    if (Kinds::eq(K, K_dialogue_choice)) {
        if (Dialogue::rvalue_to_dialogue_choice(spec1) ==
            Dialogue::rvalue_to_dialogue_choice(spec2)) {
            *rv = TRUE;
        }
        *rv = FALSE;
        return TRUE;
    }
    return FALSE;
}

§9. The following syntax tree annotations are used for the constant rvalues:

enum constant_dialogue_beat_ANNOT  dialogue_beat: for constant values
enum constant_dialogue_line_ANNOT  dialogue_line: for constant values
enum constant_dialogue_choice_ANNOT  dialogue_choice: for constant values
DECLARE_ANNOTATION_FUNCTIONS(constant_dialogue_beat, dialogue_beat)
DECLARE_ANNOTATION_FUNCTIONS(constant_dialogue_line, dialogue_line)
DECLARE_ANNOTATION_FUNCTIONS(constant_dialogue_choice, dialogue_choice)

§10.

MAKE_ANNOTATION_FUNCTIONS(constant_dialogue_beat, dialogue_beat)
MAKE_ANNOTATION_FUNCTIONS(constant_dialogue_line, dialogue_line)
MAKE_ANNOTATION_FUNCTIONS(constant_dialogue_choice, dialogue_choice)

void Dialogue::declare_annotations(void) {
    Annotations::declare_type(constant_dialogue_beat_ANNOT,
        Dialogue::write_constant_dialogue_beat_ANNOT);
    Annotations::allow(CONSTANT_NT, constant_dialogue_beat_ANNOT);
    Annotations::declare_type(constant_dialogue_line_ANNOT,
        Dialogue::write_constant_dialogue_line_ANNOT);
    Annotations::allow(CONSTANT_NT, constant_dialogue_line_ANNOT);
    Annotations::declare_type(constant_dialogue_choice_ANNOT,
        Dialogue::write_constant_dialogue_choice_ANNOT);
    Annotations::allow(CONSTANT_NT, constant_dialogue_choice_ANNOT);
}
void Dialogue::write_constant_dialogue_beat_ANNOT(text_stream *OUT, parse_node *p) {
    if (Node::get_constant_dialogue_beat(p))
        WRITE(" {dialogue beat: %I}", Node::get_constant_dialogue_beat(p)->as_instance);
}
void Dialogue::write_constant_dialogue_line_ANNOT(text_stream *OUT, parse_node *p) {
    if (Node::get_constant_dialogue_line(p))
        WRITE(" {dialogue line: %I}", Node::get_constant_dialogue_line(p)->as_instance);
}
void Dialogue::write_constant_dialogue_choice_ANNOT(text_stream *OUT, parse_node *p) {
    if (Node::get_constant_dialogue_choice(p))
        WRITE(" {dialogue choice: %I}", Node::get_constant_dialogue_choice(p)->as_instance);
}

§11.

void Dialogue::after_pass_1(void) {
    DialogueBeats::decide_cue_sequencing();
    DialogueLines::decide_line_mentions();
    DialogueChoices::decide_choice_performs();
}