implement conditions on choices
This commit is contained in:
parent
d21f8b4b09
commit
2e57f911ed
103
src/chat.rs
103
src/chat.rs
|
@ -117,13 +117,29 @@ pub enum ChatEvent {
|
||||||
DespawnAllChoices,
|
DespawnAllChoices,
|
||||||
DespawnAllChats,
|
DespawnAllChats,
|
||||||
SpawnMessage(String, hud::LogLevel, String),
|
SpawnMessage(String, hud::LogLevel, String),
|
||||||
SpawnChoice(String, usize, ChatPos, bool),
|
SpawnChoice(String, usize, ChatPos, bool, Option<String>),
|
||||||
RunScript(String),
|
RunScript(String),
|
||||||
SleepSeconds(f64),
|
SleepSeconds(f64),
|
||||||
SetVariable(String),
|
SetVariable(String),
|
||||||
GotoIf(String, ChatPos),
|
GotoIf(String, ChatPos),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Extracted {
|
||||||
|
choice_text: Option<String>,
|
||||||
|
nowait: bool,
|
||||||
|
condition: Option<String>,
|
||||||
|
}
|
||||||
|
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.
|
// This is the only place where any YAML interaction should be happening.
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct ChatDB(Vec<Value>);
|
pub struct ChatDB(Vec<Value>);
|
||||||
|
@ -229,28 +245,38 @@ impl ChatDB {
|
||||||
// Not acceptable:
|
// Not acceptable:
|
||||||
// - `"What's up?"`
|
// - `"What's up?"`
|
||||||
// - `{"goto": "foo"}`
|
// - `{"goto": "foo"}`
|
||||||
// Returns (choice text, sub-conversation branch, nowait flag)
|
fn is_choice(&self, yaml: Option<&Value>) -> bool {
|
||||||
fn search_choice(&self, yaml: Option<&Value>) -> Option<(String, Value, bool)> {
|
if let Some(data) = self.extract(yaml) {
|
||||||
|
return data.choice_text.is_some();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract(&self, yaml: Option<&Value>) -> Option<Extracted> {
|
||||||
let non_choice_tokens = NON_CHOICE_TOKENS.to_vec();
|
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 {
|
if let Some(Value::Mapping(map)) = yaml {
|
||||||
|
let mut result: Extracted = Extracted::default();
|
||||||
for (key, value) in map {
|
for (key, value) in map {
|
||||||
if let Value::String(key) = key {
|
if let Value::String(key) = key {
|
||||||
if key == TOKEN_NOWAIT && value.as_bool() == Some(true) {
|
if key == TOKEN_NOWAIT && value.as_bool() == Some(true) {
|
||||||
nowait = true;
|
result.nowait = true;
|
||||||
}
|
}
|
||||||
if non_choice_tokens.contains(&key.as_str()) {
|
else if key == TOKEN_IF {
|
||||||
continue;
|
if let Some(condition) = value.as_str() {
|
||||||
|
result.condition = Some(condition.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if key.as_str().starts_with(TOKEN_IF_INLINE) {
|
else if non_choice_tokens.contains(&key.as_str()) {
|
||||||
continue;
|
// 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<ChatPos> {
|
fn search_label_recursively(&self, sequence: &Value, label: &String, mut pos: ChatPos) -> Option<ChatPos> {
|
||||||
|
@ -317,7 +343,7 @@ impl ChatDB {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(Value::Mapping(map)) => {
|
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
|
// we just dropped out of a branch and ended up in a dialog
|
||||||
// choice. let's seek past all the choices until we find
|
// choice. let's seek past all the choices until we find
|
||||||
// the next non-dialog-choice item.
|
// the next non-dialog-choice item.
|
||||||
|
@ -426,7 +452,7 @@ impl ChatDB {
|
||||||
let mut sound = DEFAULT_SOUND.to_string();
|
let mut sound = DEFAULT_SOUND.to_string();
|
||||||
|
|
||||||
// Is this a dialog choice?
|
// 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;
|
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
|
// Spawn choices until we reach a non-choice item or the end of the branch
|
||||||
let mut key: usize = 0;
|
let mut key: usize = 0;
|
||||||
let mut reached_end_of_branch = false;
|
let mut reached_end_of_branch = false;
|
||||||
while let Some((choice, _, nowait)) =
|
while let Some(data) = self.extract(self.at(chat.internal_id, &chat.position).as_ref()) {
|
||||||
self.search_choice(self.at(chat.internal_id, &chat.position).as_ref()) {
|
if let Some(choice_text) = data.choice_text {
|
||||||
if reached_end_of_branch {
|
if reached_end_of_branch {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut goto: Vec<usize> = 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;
|
break;
|
||||||
}
|
}
|
||||||
let mut goto: Vec<usize> = 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);
|
let sfx = audio::str2sfx(sound);
|
||||||
ew_sfx.send(audio::PlaySfxEvent(sfx));
|
ew_sfx.send(audio::PlaySfxEvent(sfx));
|
||||||
}
|
}
|
||||||
ChatEvent::SpawnChoice(replytext, key, goto, nowait) => {
|
ChatEvent::SpawnChoice(replytext, key, goto, nowait, condition) => {
|
||||||
commands.spawn((
|
'out: {
|
||||||
world::DespawnOnPlayerDeath,
|
dbg!(condition);
|
||||||
Choice {
|
if let Some(condition) = condition {
|
||||||
text: replytext.into(),
|
if !vars.evaluate_condition(condition, &chat.talker.actor_id) {
|
||||||
key: *key,
|
break 'out;
|
||||||
goto: goto.clone(),
|
}
|
||||||
|
}
|
||||||
|
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) => {
|
ChatEvent::RunScript(script) => {
|
||||||
|
|
Loading…
Reference in a new issue