diff --git a/src/chat.rs b/src/chat.rs index c032d05..6cb3f0c 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -19,8 +19,10 @@ pub const TOKEN_IF: &str = "if"; pub const TOKEN_GOTO: &str = "goto"; pub const TOKEN_LABEL: &str = "label"; pub const TOKEN_SCRIPT: &str = "script"; +pub const TOKEN_GOTO_EXIT: &str = "EXIT"; pub const NAME_FALLBACK: &str = "Unknown"; +pub const MAX_BRANCH_DEPTH: usize = 64; pub const CHOICE_TIMER: f64 = 40.0 * settings::DEFAULT_CHAT_SPEED as f64; pub const LETTERS_PER_SECOND: f32 = 17.0; @@ -168,6 +170,48 @@ impl ChatDB { return None; } + fn search_label_recursively(&self, sequence: &Value, label: &String, mut pos: ChatPos) -> Option { + if pos.len() > MAX_BRANCH_DEPTH { + return None; + } + if let Some(vector) = sequence.as_sequence() { + for (index, item) in vector.iter().enumerate() { + match item { + Value::String(_) => {} + Value::Mapping(map) => { + for (key, value) in map { + if let Some(key) = key.as_str() { + if key == TOKEN_LABEL { + if value == label { + pos.push(index); + return Some(pos); + } + } + } + if value.is_sequence() { + pos.push(index); + if let Some(result) = self.search_label_recursively( + value, label, pos.clone()) { + return Some(result) + } + pos.pop(); + } + } + } + _ => {} + } + } + } + return None; + } + + fn search_label(&self, chat_id: usize, label: &String) -> Option { + if label == TOKEN_GOTO_EXIT { + return Some(vec![]); + } + return self.search_label_recursively(&self.0[chat_id], label, vec![]); + } + // returns true if we reached the end of a branch and possibly popped the position stack fn advance_pointer(&self, chat: &mut Chat) -> bool { let len = chat.position.len(); @@ -178,8 +222,6 @@ impl ChatDB { let mut popped = false; while chat.position.len() > 0 { - dbg!(&chat.position); - dbg!(self.at(chat.id, &chat.position)); match self.at(chat.id, &chat.position) { None => { chat.position.pop(); @@ -276,7 +318,16 @@ impl ChatDB { } (Some(TOKEN_SET), _) => {} (Some(TOKEN_IF), _) => {} - (Some(TOKEN_GOTO), _) => {} + (Some(TOKEN_GOTO), Value::String(label)) => { + match self.search_label(chat.id, &label) { + Some(pos) => { + chat.position = pos; + } + None => { + error!("Could not find goto label {label}!"); + } + } + } (Some(TOKEN_SCRIPT), Value::String(script)) => { event.send(ChatEvent::RunScript(script)); }