sevenx_engine 0.2.11

Engine de jogos 2D/3D completa com suporte Android, física, áudio, partículas, tilemap, UI, eventos e sistema 3D avançado com PBR.
Documentation
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Sistema de diálogos para NPCs e narrativa.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DialogueSystem {
    pub dialogues: HashMap<String, Dialogue>,
    pub current_dialogue: Option<String>,
    pub current_node: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Dialogue {
    pub id: String,
    pub speaker: String,
    pub nodes: Vec<DialogueNode>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DialogueNode {
    pub text: String,
    pub choices: Vec<DialogueChoice>,
    pub next_node: Option<usize>,
    pub triggers: Vec<String>, // Eventos que este nó dispara
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DialogueChoice {
    pub text: String,
    pub next_node: usize,
    pub condition: Option<String>, // Condição para mostrar esta escolha
}

impl DialogueSystem {
    pub fn new() -> Self {
        Self {
            dialogues: HashMap::new(),
            current_dialogue: None,
            current_node: 0,
        }
    }

    /// Adiciona um diálogo ao sistema.
    pub fn add_dialogue(&mut self, dialogue: Dialogue) {
        self.dialogues.insert(dialogue.id.clone(), dialogue);
    }

    /// Inicia um diálogo.
    pub fn start_dialogue(&mut self, dialogue_id: &str) -> bool {
        if self.dialogues.contains_key(dialogue_id) {
            self.current_dialogue = Some(dialogue_id.to_string());
            self.current_node = 0;
            true
        } else {
            false
        }
    }

    /// Obtém o nó atual do diálogo.
    pub fn get_current_node(&self) -> Option<&DialogueNode> {
        if let Some(dialogue_id) = &self.current_dialogue {
            if let Some(dialogue) = self.dialogues.get(dialogue_id) {
                return dialogue.nodes.get(self.current_node);
            }
        }
        None
    }

    /// Avança para o próximo nó.
    pub fn advance(&mut self) -> bool {
        if let Some(node) = self.get_current_node() {
            if let Some(next) = node.next_node {
                self.current_node = next;
                return true;
            }
        }
        self.end_dialogue();
        false
    }

    /// Escolhe uma opção de diálogo.
    pub fn choose(&mut self, choice_index: usize) -> bool {
        if let Some(node) = self.get_current_node() {
            if let Some(choice) = node.choices.get(choice_index) {
                self.current_node = choice.next_node;
                return true;
            }
        }
        false
    }

    /// Termina o diálogo atual.
    pub fn end_dialogue(&mut self) {
        self.current_dialogue = None;
        self.current_node = 0;
    }

    /// Verifica se há um diálogo ativo.
    pub fn is_active(&self) -> bool {
        self.current_dialogue.is_some()
    }

    /// Obtém o nome do falante atual.
    pub fn get_current_speaker(&self) -> Option<String> {
        if let Some(dialogue_id) = &self.current_dialogue {
            if let Some(dialogue) = self.dialogues.get(dialogue_id) {
                return Some(dialogue.speaker.clone());
            }
        }
        None
    }
}

impl Default for DialogueSystem {
    fn default() -> Self {
        Self::new()
    }
}

/// Builder para criar diálogos facilmente.
pub struct DialogueBuilder {
    dialogue: Dialogue,
}

impl DialogueBuilder {
    pub fn new(id: &str, speaker: &str) -> Self {
        Self {
            dialogue: Dialogue {
                id: id.to_string(),
                speaker: speaker.to_string(),
                nodes: Vec::new(),
            },
        }
    }

    pub fn add_node(mut self, text: &str) -> Self {
        self.dialogue.nodes.push(DialogueNode {
            text: text.to_string(),
            choices: Vec::new(),
            next_node: None,
            triggers: Vec::new(),
        });
        self
    }

    pub fn add_node_with_choices(mut self, text: &str, choices: Vec<(&str, usize)>) -> Self {
        let choices: Vec<DialogueChoice> = choices
            .into_iter()
            .map(|(text, next)| DialogueChoice {
                text: text.to_string(),
                next_node: next,
                condition: None,
            })
            .collect();

        self.dialogue.nodes.push(DialogueNode {
            text: text.to_string(),
            choices,
            next_node: None,
            triggers: Vec::new(),
        });
        self
    }

    pub fn build(self) -> Dialogue {
        self.dialogue
    }
}