extern crate yaml_rust; use bevy::prelude::*; use yaml_rust::{Yaml, YamlLoader}; use crate::{audio, hud, world}; pub const CHATS: &[&str] = &[ include_str!("chats/serenity.yaml"), include_str!("chats/startrans.yaml"), ]; pub const TOKEN_CHAT: &str = "chat"; pub const TALKER_SPEED_FACTOR: f32 = 1.0 / 17.0; pub const CHAT_SPEED_MIN_LEN: f32 = 40.0; pub struct ChatPlugin; impl Plugin for ChatPlugin { fn build(&self, app: &mut App) { app.add_systems(Startup, load_chats); app.add_systems(Update, ( handle_new_conversations.before(handle_chat_events), handle_chat_events, handle_chat_timer.before(handle_chat_events), )); app.add_event::(); app.add_event::(); app.insert_resource(ChatDB(Vec::new())); } } #[derive(Component)] pub struct Chat { pub id: usize, pub position: usize, pub timer: f64, pub talker: Talker, } #[derive(Component)] pub struct Choice; // This is the only place where any YAML interaction should be happening. #[derive(Resource)] pub struct ChatDB(Vec); impl ChatDB { pub fn load_from_str(&mut self, yaml_string: &str) -> Result<(), ()> { if let Ok(mut yaml_data) = YamlLoader::load_from_str(yaml_string) { self.0.append(&mut yaml_data); return Ok(()); } return Err(()); } pub fn get_chat_by_id(&self, id: &String) -> Result { let mut found: Option = None; for (index, object_yaml) in self.0.iter().enumerate() { if let Some(chat_id) = object_yaml[0][TOKEN_CHAT].as_str() { if chat_id == id { if found.is_some() { return Err("Found multiple chats with the same id!".to_string()); } found = Some(index); } } } if let Some(result) = found { return Ok(result); } return Err(format!("No chat with the conversation ID `{id}` was found.")); } pub fn advance_chat(&self, chat: &mut Chat, event: &mut EventWriter) { event.send(ChatEvent::DespawnAllChoices); let conv = &self.0[chat.id].as_vec(); if conv.is_none() { return; } let conv = conv.unwrap(); chat.position += 1; if chat.position >= conv.len() { event.send(ChatEvent::DisplayMessage("Disconnected.".to_string())); event.send(ChatEvent::DespawnAllChats); return; } if let Some(message) = conv[chat.position].as_str() { event.send(ChatEvent::DisplayMessage(message.to_string())); } } } #[derive(Component)] #[derive(Clone)] pub struct Talker { pub conv_id: String, pub name: Option, pub pronoun: Option, pub talking_speed: f32, } #[derive(Event)] pub struct StartConversationEvent { pub talker: Talker, } #[derive(Event)] pub enum ChatEvent { DespawnAllChoices, DespawnAllChats, DisplayMessage(String), //SpawnChoice(String), //Script(String, String, String), } pub fn load_chats(mut chatdb: ResMut) { for chat_yaml in CHATS { if chatdb.load_from_str(chat_yaml).is_err() { error!("Could not load chat definitions. Validate files in `src/chats/` path."); } } } pub fn handle_new_conversations( mut commands: Commands, mut er_conv: EventReader, mut ew_sfx: EventWriter, mut ew_chatevent: EventWriter, chatdb: Res, q_chats: Query<&Chat>, time: Res