implement choice selection

This commit is contained in:
yuni 2024-04-13 20:23:38 +02:00
parent 8df6914dba
commit e7df698225

View file

@ -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<String> {
// 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<usize>) -> 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<usize>) -> Option<Value> {
if position.len() == 0 {
return None;
}
let mut pointer: Option<&Value> = Some(&self.0[id]);
let mut result: Option<Value> = None;
let mut pointer: Option<Value> = Some(self.0[id].clone());
let mut next_pointer: Option<Value> = 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<ChatEvent>) {
@ -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<usize> = pos.clone();
goto.push(0);
event.send(ChatEvent::SpawnChoice(choice, key, goto));
@ -246,6 +292,21 @@ pub fn load_chats(mut chatdb: ResMut<ChatDB>) {
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(