diff options
| -rw-r--r-- | content/encyclopediae/npcs.json | 36 | ||||
| -rw-r--r-- | src/assemblage.rs | 38 | ||||
| -rw-r--r-- | src/components/mod.rs | 1 | ||||
| -rw-r--r-- | src/componentwrapper.rs | 2 | ||||
| -rw-r--r-- | src/parameterexpression.rs | 8 | ||||
| -rw-r--r-- | src/systems/spawn.rs | 4 |
6 files changed, 68 insertions, 21 deletions
diff --git a/content/encyclopediae/npcs.json b/content/encyclopediae/npcs.json index f4642b4..63f5b13 100644 --- a/content/encyclopediae/npcs.json +++ b/content/encyclopediae/npcs.json @@ -1,13 +1,15 @@ { "assemblages": { "rat": { + "arguments": {"home": []}, "sprite": "rat", "height": 1.0, "components": [ ["MonsterAI", { "view_distance": 3, "move_chance": 0.08, - "homesickness": 0.1 + "homesickness": 0.1, + "home": {"$arg": "home"} }], ["Health", {"health": 8, "maxhealth": 8}], ["Fighter", {"damage": 2, "cooldown": 6}], @@ -19,13 +21,15 @@ ] }, "goblin": { + "arguments": {"home": []}, "sprite": "goblin", "height": 1.0, "components": [ ["MonsterAI", { "view_distance": 8, "move_chance": 0.02, - "homesickness": 0.1 + "homesickness": 0.1, + "home": {"$arg": "home"} }], ["Health", {"health": 15, "maxhealth": 15}], ["Fighter", {"damage": 5, "cooldown": 8}], @@ -39,13 +43,15 @@ ] }, "troll": { + "arguments": {"home": []}, "sprite": "troll", "height": 1.0, "components": [ ["MonsterAI", { "view_distance": 8, "move_chance": 0.01, - "homesickness": 0.1 + "homesickness": 0.1, + "home": {"$arg": "home"} }], ["Health", {"health": 75, "maxhealth": 75}], ["Fighter", {"damage": 15, "cooldown": 10}], @@ -62,19 +68,22 @@ ] }, "rabbit": { + "arguments": {"home": []}, "sprite": "rabbit", "height": 1.0, "components": [ ["MonsterAI", { "view_distance": 3, "move_chance": 0.08, - "homesickness": 0.01 + "homesickness": 0.01, + "home": {"$arg": "home"} }], ["Movable", {"cooldown": 3}], ["Faction", {"faction": "neutral"}] ] }, "dude": { + "arguments": {"home": []}, "sprite": "human", "height": 1.5, "flags": ["Occupied"], @@ -83,11 +92,13 @@ ["MonsterAI", { "view_distance": 1, "move_chance": 0.01, - "homesickness": 0.3 + "homesickness": 0.3, + "home": {"$arg": "home"} }] ] }, "trader": { + "arguments": {"home": []}, "sprite": "human", "height": 1.5, "name": "crop trader", @@ -101,12 +112,14 @@ ["MonsterAI", { "view_distance": 1, "move_chance": 0.01, - "homesickness": 0.3 + "homesickness": 0.3, + "home": {"$arg": "home"} }], ["Movable", {"cooldown": 3}] ] }, "dyetrader": { + "arguments": {"home": []}, "sprite": "human", "height": 1.5, "name": "dye trader", @@ -119,12 +132,14 @@ ["MonsterAI", { "view_distance": 1, "move_chance": 0.01, - "homesickness": 0.3 + "homesickness": 0.3, + "home": {"$arg": "home"} }], ["Movable", {"cooldown": 3}] ] }, "toolsmith": { + "arguments": {"home": []}, "sprite": "human", "height": 1.5, "name": "toolsmith", @@ -135,12 +150,14 @@ ["MonsterAI", { "view_distance": 1, "move_chance": 0.01, - "homesickness": 0.3 + "homesickness": 0.3, + "home": {"$arg": "home"} }], ["Movable", {"cooldown": 3}] ] }, "villager": { + "arguments": {"home": []}, "sprite": "human", "height": 1.5, "name": "villager", @@ -148,7 +165,8 @@ ["MonsterAI", { "view_distance": 1, "move_chance": 0.01, - "homesickness": 0.3 + "homesickness": 0.3, + "home": {"$arg": "home"} }], ["Movable", {"cooldown": 3}], ["Interactable", {"typ": "say", "arg": "Hello"}] diff --git a/src/assemblage.rs b/src/assemblage.rs index 773ebf0..24d4539 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -24,13 +24,12 @@ impl Assemblage { pub fn validate(&self) -> AnyResult<()> { - let arguments = self.arguments.iter().filter_map(|(k, v)|Some((k.clone(), v.clone()?))).collect::<HashMap<String, Parameter>>(); for (comptype, parameters) in &self.components { let mut is_complete = true; let mut compargs = HashMap::new(); for paramname in comptype.parameters() { let param = parameters.get(paramname).ok_or(aerr!("missing parameter {} for component {:?}", paramname, comptype))?; - match param.evaluate(&arguments, &Template::empty("")) { + match param.evaluate(&self.arguments, &Template::empty("")) { Err(EvaluationError::MissingArgument(_)) => {is_complete = false;} Err(EvaluationError::Other(msg)) => {return Err(aerr!("invalid value for {}: {}", paramname, msg))} Ok(p) => {compargs.insert(paramname, p);} @@ -45,18 +44,16 @@ impl Assemblage { pub fn instantiate(&self, template: &Template) -> AnyResult<Vec<ComponentWrapper>>{ - let mut args = self.arguments.clone(); + let mut arguments = self.arguments.clone(); for (key, param) in template.kwargs.clone() { - // todo: warn about unknown keys - args.insert(key, Some(param)); + arguments.insert(key, Some(param)); } - let arguments = args.into_iter().map(|(k, v)|Ok((k.clone(), v.ok_or(aerr!("missing argument value for {}", k))?))).collect::<AnyResult<HashMap<String, Parameter>>>()?; let mut components: Vec<ComponentWrapper> = Vec::new(); for (comptype, compparams) in &self.components { let mut compargs: HashMap<&str, Parameter> = HashMap::new(); for (name, param) in compparams { compargs.insert(name.as_str(), param.evaluate(&arguments, template).map_err(|e| match e { - EvaluationError::MissingArgument(arg) => aerr!("argument {} not found", arg), + EvaluationError::MissingArgument(arg) => aerr!("argument {} has no value", arg), EvaluationError::Other(msg) => aerr!("{}", msg) })?); } @@ -245,6 +242,33 @@ mod tests { #[test] + fn unknown_argument(){ + Assemblage::deserialize(&json!({ + "arguments": {"name": "me"}, + "components": [ + ["Visible", { + "sprite": {"$arg": "sprite"}, + "height": 0.1, + "name": "grass" + }] + ] + })).unwrap().validate().unwrap_err(); + } + + #[test] + fn missing_component_parameter(){ + Assemblage::deserialize(&json!({ + "arguments": {}, + "components": [ + ["Visible", { + "height": 0.1, + "name": "grass" + }] + ] + })).unwrap().validate().unwrap_err(); + } + + #[test] fn null_argument(){ let result = Assemblage::deserialize(&json!({ "arguments": {"sprite": null}, diff --git a/src/components/mod.rs b/src/components/mod.rs index 34630e4..f3a91d5 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -170,6 +170,7 @@ pub struct MonsterAI { pub move_chance: f64, pub view_distance: i64, pub homesickness: f64, + pub home: Option<Pos> } #[derive(Component, Debug, Clone, Default)] diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index 75a0bca..2f12a42 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -159,7 +159,7 @@ components!(all: Fighter (damage: i64, cooldown: i64) {Fighter{attack: AttackType::Attack(damage), cooldown, range: 1}}; Healing (delay: i64, health: i64) {Healing{delay, health, next_heal: None}}; Autofight () {Autofight::default()}; - MonsterAI (move_chance: f64, view_distance: i64, homesickness: f64); + MonsterAI (move_chance: f64, view_distance: i64, homesickness: f64, home: Option<Pos>); Spawner (amount: i64, clan: String, template: Template, radius: i64) { Spawner{ amount: amount as usize, diff --git a/src/parameterexpression.rs b/src/parameterexpression.rs index dfba562..0208fb9 100644 --- a/src/parameterexpression.rs +++ b/src/parameterexpression.rs @@ -32,11 +32,11 @@ pub enum EvaluationError { impl ParameterExpression { - pub fn evaluate(&self, arguments: &HashMap<String, Parameter>, template: &Template) -> Result<Parameter, EvaluationError> { + pub fn evaluate(&self, arguments: &HashMap<String, Option<Parameter>>, template: &Template) -> Result<Parameter, EvaluationError> { self.evaluate_(arguments, template, 0) } - fn evaluate_(&self, arguments: &HashMap<String, Parameter>, template: &Template, nesting: usize) -> Result<Parameter, EvaluationError> { + fn evaluate_(&self, arguments: &HashMap<String, Option<Parameter>>, template: &Template, nesting: usize) -> Result<Parameter, EvaluationError> { if nesting > MAX_NESTING { return Err(EvaluationError::Other("Maximum nesting reached in parameter evaluation".to_string())); } @@ -61,7 +61,9 @@ impl ParameterExpression { })) } Self::Argument(argname) => { - Ok(arguments.get(argname.as_str()).ok_or(EvaluationError::MissingArgument(argname.to_string()))?.clone()) + arguments.get(argname.as_str()) + .ok_or(EvaluationError::Other(format!("unknown argument {}", argname)))?.clone() + .ok_or(EvaluationError::MissingArgument(argname.to_string())) } Self::Random(options) => { let r = rand::thread_rng().gen_range(0, options.len()); diff --git a/src/systems/spawn.rs b/src/systems/spawn.rs index 284c2ab..da0735d 100644 --- a/src/systems/spawn.rs +++ b/src/systems/spawn.rs @@ -24,7 +24,8 @@ use crate::{ }, resources::{NewEntities}, componentwrapper::ComponentWrapper, - Pos + Pos, + fromtoparameter::FromToParameter }; @@ -52,6 +53,7 @@ impl <'a> System<'a> for Spawn { if spawner.clan.name == "" { spawner.clan.name = format!("$random({},{},{})", position.pos.x, position.pos.y, spawner.template.name.0); } + spawner.template.kwargs.insert("home".to_string(), Some(position.pos).to_parameter()); if triggerbox.has_message(&[Trigger::Spawn]) { if *clan_nums.get(&spawner.clan).unwrap_or(&0) < spawner.amount { if spawner.saturated { |
