dlg 0.1.0

A library for parsing .dlg files
Documentation
mod cursor;

use std::fmt::{write, Display};

pub use cursor::Cursor;

use crate::{parser::Menu, prelude::*};

pub trait Player {
    fn play(dialog: Dialog);
    fn process_line(state: &mut DialogState, line: &Line);
    fn end();
}

#[derive(Default, Debug)]
pub struct Animation {
    pub current: usize,
    pub target: usize,
    pub waited: usize,
}

impl Display for Animation {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}..{}", self.current, self.target)
    }
}

#[derive(Default, Debug)]
pub struct DialogState {
    pub cursor: Cursor,
    pub animation: Animation,
}

pub struct ConsoleDialogPlayer;

impl ConsoleDialogPlayer {
    fn clear_terminal() {}

    fn wait_for_enter(message: &str) {
        use std::io::{self, BufRead};

        println!();
        println!("{}", message);

        let stdin = io::stdin();
        let mut input = String::new();
        stdin.lock().read_line(&mut input).expect("Why?");
    }
}

impl Player for ConsoleDialogPlayer {
    fn play(dialog: Dialog) {
        let mut state = DialogState {
            cursor: Cursor::default(),
            animation: Animation::default(),
        };

        while let Some(line) = dialog.get_line_by_cursor(&state.cursor) {
            Self::process_line(&mut state, line);
        }

        Self::end();
    }

    fn process_line(state: &mut DialogState, line: &Line) {
        Self::clear_terminal();

        match line {
            Line::Phrase { speaker, lines } => {
                if let Some(line) = lines.get(state.cursor.phrase_index()) {
                    println!("{:?}: {:?}", speaker, line);
                    state.cursor.next_phrase_index();
                } else {
                    state.cursor.next_line_index();
                    return;
                }
            }
            Line::Menu(menu) => {
                let Menu { title, options } = menu;
                println!("{:?}", title);
                println!();
                for (index, opt) in options.iter().enumerate() {
                    println!("{}. {:?}", index + 1, opt.title);
                }
            }
        }

        Self::wait_for_enter("Нажмите [Enter] для продолжения");
    }

    fn end() {
        println!("End");
    }
}