hiraku-engine 0.1.0

Hiraku visual-novel engine
use super::*;

#[allow(clippy::too_many_arguments)]
pub(super) fn dispatch_dialogue_command(
    command: DialogueCommand,
    commands: &mut Commands,
    dialogue_state: &mut DialogueState,
    dialogue_history: &mut DialogueHistoryState,
    shared_state: &mut SceneSharedState,
    animations: &mut AnimationState,
    dialogue_root: &mut Query<&mut Visibility, (With<DialogueRoot>, Without<HintText>)>,
    speaker_text: &mut Query<&mut Text, (With<SpeakerText>, Without<LineText>)>,
    line_text: &mut Query<&mut Text, (With<LineText>, Without<SpeakerText>)>,
    line_text_entity: &Query<Entity, (With<LineText>, Without<SpeakerText>)>,
    ui_fonts: &UiFonts,
    ui_style: &UiStyle,
) {
    match command {
        DialogueCommand::Say {
            speaker,
            text,
            animation_id,
        } => {
            if let Some(waiting) = dialogue_state.waiting.take() {
                complete_dialogue_wait(commands, animations, waiting);
            }
            if let Ok(mut visibility) = dialogue_root.single_mut() {
                *visibility = Visibility::Visible;
            }
            if let Ok(mut speaker_node) = speaker_text.single_mut() {
                **speaker_node = speaker.clone();
            }
            if let Ok(line_root) = line_text_entity.single() {
                set_dialogue_line_text(
                    commands,
                    dialogue_state,
                    line_root,
                    line_text,
                    ui_fonts,
                    ui_style,
                    &text,
                    0,
                    None,
                );
            } else {
                set_dialogue_model_reveal(dialogue_state, &text, 0, None);
            }
            dialogue_state.waiting = Some(PendingDialogueAdvance {
                animation_id,
                request: None,
            });
            shared_state.0.dialogue = Some(DialogueSnapshot { speaker, text });
            if let Some(dialogue) = shared_state.0.dialogue.clone() {
                dialogue_history.entries.push(dialogue);
            }
        }
        DialogueCommand::Continue { text, animation_id } => {
            if let Some(waiting) = dialogue_state.waiting.take() {
                complete_dialogue_wait(commands, animations, waiting);
            }
            if shared_state.0.dialogue.is_none() {
                warn!("dialogue continuation has no UI buffer; treating it as narration");
                if let Ok(mut visibility) = dialogue_root.single_mut() {
                    *visibility = Visibility::Visible;
                }
                if let Ok(mut speaker_node) = speaker_text.single_mut() {
                    **speaker_node = String::new();
                }
                if let Ok(line_root) = line_text_entity.single() {
                    set_dialogue_line_text(
                        commands,
                        dialogue_state,
                        line_root,
                        line_text,
                        ui_fonts,
                        ui_style,
                        &text,
                        0,
                        None,
                    );
                } else {
                    set_dialogue_model_reveal(dialogue_state, &text, 0, None);
                }
                shared_state.0.dialogue = Some(DialogueSnapshot {
                    speaker: String::new(),
                    text,
                });
            } else {
                let previous_chars = shared_state
                    .0
                    .dialogue
                    .as_ref()
                    .map(|dialogue| dialogue.text.chars().count())
                    .unwrap_or_default();
                if let Ok(line_root) = line_text_entity.single() {
                    append_dialogue_line_text(
                        commands,
                        dialogue_state,
                        line_root,
                        ui_fonts,
                        ui_style,
                        &text,
                        None,
                    );
                } else {
                    append_dialogue_model_reveal(
                        dialogue_state,
                        previous_chars,
                        text.chars().count(),
                        None,
                    );
                }
                if let Some(dialogue) = shared_state.0.dialogue.as_mut() {
                    dialogue.text.push_str(&text);
                }
                if let (Some(current), Some(last)) = (
                    shared_state.0.dialogue.as_ref(),
                    dialogue_history.entries.last_mut(),
                ) {
                    *last = current.clone();
                }
            }
            dialogue_state.waiting = Some(PendingDialogueAdvance {
                animation_id,
                request: None,
            });
        }
        DialogueCommand::AwaitAdvance { done } => {
            dialogue_state.waiting = Some(PendingDialogueAdvance {
                animation_id: None,
                request: Some(done),
            });
        }
        DialogueCommand::Clear => {
            if let Some(waiting) = dialogue_state.waiting.take() {
                complete_dialogue_wait(commands, animations, waiting);
            }
            clear_dialogue_spans(commands, dialogue_state);
            if let Ok(mut visibility) = dialogue_root.single_mut() {
                *visibility = Visibility::Hidden;
            }
            if let Ok(mut speaker_node) = speaker_text.single_mut() {
                **speaker_node = String::new();
            }
            if let Ok(mut line_node) = line_text.single_mut() {
                **line_node = String::new();
            }
            shared_state.0.dialogue = None;
        }
    }
}