diff --git a/src/chat.rs b/src/chat.rs index c1b8a82..fb69f97 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -113,7 +113,14 @@ impl ChatDB { return Err(format!("No chat with the conversation ID `{id}` was found.")); } - fn search_choice(&self, yaml: Option<&Value>) -> Option { + // For a given Value, check whether it's a Value::Mapping and whether it + // contains a choice. Mappings that will be detected as choices: + // - `{"What's up?": [...]}` + // - `{"What's up?": [...], "if": "value > 3"}` + // Not acceptable: + // - `"What's up?"` + // - `{"goto": "foo"}` + fn search_choice(&self, yaml: Option<&Value>) -> Option<(String, Value)> { let non_choice_tokens = NON_CHOICE_TOKENS.to_vec(); if let Some(Value::Mapping(hash)) = yaml { for key in hash.keys() { @@ -121,7 +128,7 @@ impl ChatDB { if non_choice_tokens.contains(&key.as_str()) { continue; } - return Some(key.into()); + return Some((key.into(), hash[key].clone())); } } } @@ -130,23 +137,33 @@ impl ChatDB { // returns false if the advanced pointer is out of bounds fn advance_pointer(&self, chat: &mut Chat) -> bool { - let index = chat.position.len() - 1; - chat.position[index] += 1; + let len = chat.position.len(); + if len == 0 { + return false; + } + chat.position[len - 1] += 1; while chat.position.len() > 0 { + dbg!(&chat.position); dbg!(self.at(chat.id, &chat.position)); match self.at(chat.id, &chat.position) { None => { dbg!("Pop."); chat.position.pop(); - let index = chat.position.len() - 1; - chat.position[index] += 1; + if chat.position.len() > 0 { + let index = chat.position.len() - 1; + chat.position[index] += 1; + } }, Some(_) => { break; } } } + if chat.position.len() == 0 { + // out of bounds, return false. + return false; + } return true; } @@ -156,22 +173,47 @@ impl ChatDB { position[index] += 1; } - fn at(&self, id: usize, position: &Vec) -> Option<&Value> { + // Returns the Value at the given ID/position, as-is. + // If it's a choice, it returns the entire {"choice text": [...]} mapping. + fn at(&self, id: usize, position: &Vec) -> Option { if position.len() == 0 { return None; } - let mut pointer: Option<&Value> = Some(&self.0[id]); + let mut result: Option = None; + let mut pointer: Option = Some(self.0[id].clone()); + let mut next_pointer: Option = None; for index in position { - if let Some(Value::Sequence(seq)) = self.0.get(id) { - // TODO: handle mappings - if let Some(value) = seq.get(*index) { - pointer = Some(value); + if let Some(Value::Sequence(seq)) = &pointer { + let value = seq.get(*index); + match value { + Some(Value::String(value_string)) => { + result = Some(Value::String(value_string.into())); + } + Some(Value::Mapping(mapping)) => { + if let Some((_choicetext, subconversation)) = self.search_choice(value) { + result = Some(Value::Mapping(mapping.clone())); + next_pointer = Some(subconversation); + } + else { + result = Some(Value::Mapping(mapping.clone())); + } + } + None => { + // Out of bounds. + return None; + } + _ => { + error!("Could not handle YAML value {value:?}"); + return None; + } } + pointer = next_pointer; + next_pointer = None; } else { return None; } } - return pointer; + return result; } pub fn advance_chat(&self, chat: &mut Chat, event: &mut EventWriter) { @@ -188,7 +230,7 @@ impl ChatDB { event.send(ChatEvent::DespawnAllChats); return; } - else if let Some(_) = self.search_choice(self.at(chat.id, &chat.position)) { + else if let Some(_) = self.search_choice(self.at(chat.id, &chat.position).as_ref()) { is_skipping_through = true; } else if let Some(Value::String(message)) = self.at(chat.id, &chat.position) { @@ -203,7 +245,11 @@ impl ChatDB { if is_skipping_through /*|| pos[0] >= conv.len()*/ { // TODO: out of bounds checking break; } - if let Some(choice) = self.search_choice(self.at(chat.id, &pos)) { + dbg!(&pos); + dbg!(self.at(chat.id, &pos)); + let choice = self.search_choice(self.at(chat.id, &pos).as_ref()); + dbg!(&choice); + if let Some((choice, _)) = choice { let mut goto: Vec = pos.clone(); goto.push(0); event.send(ChatEvent::SpawnChoice(choice, key, goto)); @@ -246,6 +292,21 @@ pub fn load_chats(mut chatdb: ResMut) { error!("Could not load chat definitions. Validate files in `src/chats/` path."); } } +// let mut chat = Chat { +// id: 2, +// position: vec![0], +// timer: 0.0, +// talker: Talker { +// conv_id: "Icarus".to_string(), +// name: None, +// pronoun: None, +// talking_speed: 1.0, +// } +// }; + dbg!(chatdb.at(2, &vec![0])); + dbg!(chatdb.at(2, &vec![1])); + dbg!(chatdb.at(2, &vec![2])); + dbg!(chatdb.at(2, &vec![3])); } pub fn handle_new_conversations(