use std::collections::HashMap;
use bevy::prelude::*;
use crate::data::{DialogueDatabase, FieldValue};
#[derive(Resource, Debug, Default)]
pub struct Variables(pub HashMap<String, FieldValue>);
impl Variables {
pub fn get(&self, name: &str) -> Option<&FieldValue> {
self.0.get(name)
}
pub fn set(&mut self, name: impl Into<String>, value: impl Into<FieldValue>) {
self.0.insert(name.into(), value.into());
}
pub fn truthy(&self, name: &str) -> bool {
matches!(self.get(name), Some(FieldValue::Boolean(true)))
}
pub fn number(&self, name: &str) -> f32 {
match self.get(name) {
Some(FieldValue::Number(n)) => *n,
_ => 0.0,
}
}
pub fn text(&self, name: &str) -> &str {
match self.get(name) {
Some(FieldValue::Text(s)) => s,
_ => "",
}
}
pub fn seed(&mut self, db: &DialogueDatabase) {
for variable in &db.variables {
self.0
.entry(variable.name.clone())
.or_insert_with(|| variable.initial.clone());
}
}
}
pub fn seed_variables(
mut events: MessageReader<AssetEvent<DialogueDatabase>>,
databases: Res<Assets<DialogueDatabase>>,
mut variables: ResMut<Variables>,
) {
for event in events.read() {
let (AssetEvent::Added { id } | AssetEvent::Modified { id }) = event else {
continue;
};
if let Some(db) = databases.get(*id) {
variables.seed(db);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::data::Variable;
use rstest::{fixture, rstest};
#[fixture]
fn db() -> DialogueDatabase {
DialogueDatabase {
variables: vec![
Variable {
name: "AcceptedJob".to_owned(),
initial: FieldValue::Boolean(false),
fields: vec![],
},
Variable {
name: "Gold".to_owned(),
initial: FieldValue::Number(10.0),
fields: vec![],
},
],
..Default::default()
}
}
#[rstest]
fn seed_fills_missing_variables(db: DialogueDatabase) {
let mut vars = Variables::default();
vars.seed(&db);
assert!(!vars.truthy("AcceptedJob"));
assert_eq!(vars.number("Gold"), 10.0);
}
#[rstest]
fn seed_keeps_existing_values(db: DialogueDatabase) {
let mut vars = Variables::default();
vars.set("Gold", 99.0);
vars.seed(&db);
assert_eq!(vars.number("Gold"), 99.0);
assert!(!vars.truthy("AcceptedJob"));
}
#[test]
fn typed_accessors_default_on_missing_or_mismatch() {
let mut vars = Variables::default();
vars.set("Name", "Feri");
assert_eq!(vars.text("Name"), "Feri");
assert_eq!(vars.text("Missing"), "");
assert_eq!(vars.number("Name"), 0.0);
assert!(!vars.truthy("Name"));
}
#[rstest]
fn loading_a_database_seeds_the_store(db: DialogueDatabase) {
let mut app = App::new();
app.add_plugins((MinimalPlugins, AssetPlugin::default(), crate::TalksPlugin));
let _handle = app
.world_mut()
.resource_mut::<Assets<DialogueDatabase>>()
.add(db);
app.update();
app.update();
let vars = app.world().resource::<Variables>();
assert_eq!(vars.number("Gold"), 10.0);
}
}