diff --git a/src/chat.rs b/src/chat.rs index 822beee..7b0915f 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -117,13 +117,29 @@ pub enum ChatEvent { DespawnAllChoices, DespawnAllChats, SpawnMessage(String, hud::LogLevel, String), - SpawnChoice(String, usize, ChatPos, bool), + SpawnChoice(String, usize, ChatPos, bool, Option), RunScript(String), SleepSeconds(f64), SetVariable(String), GotoIf(String, ChatPos), } +pub struct Extracted { + choice_text: Option, + nowait: bool, + condition: Option, +} +impl Default for Extracted { + fn default() -> Self { + Self { + choice_text: None, + nowait: false, + condition: None, + } + } +} + + // This is the only place where any YAML interaction should be happening. #[derive(Resource)] pub struct ChatDB(Vec); @@ -229,28 +245,38 @@ impl ChatDB { // Not acceptable: // - `"What's up?"` // - `{"goto": "foo"}` - // Returns (choice text, sub-conversation branch, nowait flag) - fn search_choice(&self, yaml: Option<&Value>) -> Option<(String, Value, bool)> { + fn is_choice(&self, yaml: Option<&Value>) -> bool { + if let Some(data) = self.extract(yaml) { + return data.choice_text.is_some(); + } + return false; + } + + fn extract(&self, yaml: Option<&Value>) -> Option { let non_choice_tokens = NON_CHOICE_TOKENS.to_vec(); - let mut result: Option<(String, Value, bool)> = None; - let mut nowait = false; if let Some(Value::Mapping(map)) = yaml { + let mut result: Extracted = Extracted::default(); for (key, value) in map { if let Value::String(key) = key { if key == TOKEN_NOWAIT && value.as_bool() == Some(true) { - nowait = true; + result.nowait = true; } - if non_choice_tokens.contains(&key.as_str()) { - continue; + else if key == TOKEN_IF { + if let Some(condition) = value.as_str() { + result.condition = Some(condition.to_string()); + } } - if key.as_str().starts_with(TOKEN_IF_INLINE) { - continue; + else if non_choice_tokens.contains(&key.as_str()) { + // skip over the other non-choice tokens + } + else { + result.choice_text = Some(key.to_string()); } - result = Some((key.into(), map[key].clone(), nowait)); } } + return Some(result); } - return result; + return None; } fn search_label_recursively(&self, sequence: &Value, label: &String, mut pos: ChatPos) -> Option { @@ -317,7 +343,7 @@ impl ChatDB { } }, Some(Value::Mapping(map)) => { - if seek_past_dialog_choices && self.search_choice(Some(&Value::Mapping(map))).is_some() { + if seek_past_dialog_choices && self.is_choice(Some(&Value::Mapping(map))) { // we just dropped out of a branch and ended up in a dialog // choice. let's seek past all the choices until we find // the next non-dialog-choice item. @@ -426,7 +452,7 @@ impl ChatDB { let mut sound = DEFAULT_SOUND.to_string(); // Is this a dialog choice? - if let Some(_) = self.search_choice(Some(&Value::Mapping(map.clone()))) { + if self.is_choice(Some(&Value::Mapping(map.clone()))) { processed_a_choice = true; } @@ -542,16 +568,21 @@ impl ChatDB { // Spawn choices until we reach a non-choice item or the end of the branch let mut key: usize = 0; let mut reached_end_of_branch = false; - while let Some((choice, _, nowait)) = - self.search_choice(self.at(chat.internal_id, &chat.position).as_ref()) { - if reached_end_of_branch { + while let Some(data) = self.extract(self.at(chat.internal_id, &chat.position).as_ref()) { + if let Some(choice_text) = data.choice_text { + if reached_end_of_branch { + break; + } + let mut goto: Vec = chat.position.clone(); + goto.push(0); + event.send(ChatEvent::SpawnChoice(choice_text, + key, goto, data.nowait, data.condition)); + key += 1; + reached_end_of_branch = self.advance_pointer(chat); + } + else { break; } - let mut goto: Vec = chat.position.clone(); - goto.push(0); - event.send(ChatEvent::SpawnChoice(choice, key, goto, nowait)); - key += 1; - reached_end_of_branch = self.advance_pointer(chat); } } } @@ -661,17 +692,25 @@ pub fn handle_chat_events( let sfx = audio::str2sfx(sound); ew_sfx.send(audio::PlaySfxEvent(sfx)); } - ChatEvent::SpawnChoice(replytext, key, goto, nowait) => { - commands.spawn(( - world::DespawnOnPlayerDeath, - Choice { - text: replytext.into(), - key: *key, - goto: goto.clone(), + ChatEvent::SpawnChoice(replytext, key, goto, nowait, condition) => { + 'out: { + dbg!(condition); + if let Some(condition) = condition { + if !vars.evaluate_condition(condition, &chat.talker.actor_id) { + break 'out; + } + } + commands.spawn(( + world::DespawnOnPlayerDeath, + Choice { + text: replytext.into(), + key: *key, + goto: goto.clone(), + } + )); + if !nowait { + chat.timer = now + CHOICE_TIMER / settings.chat_speed as f64; } - )); - if !nowait { - chat.timer = now + CHOICE_TIMER / settings.chat_speed as f64; } } ChatEvent::RunScript(script) => {