summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--content/encyclopediae/npcs.json36
-rw-r--r--src/assemblage.rs38
-rw-r--r--src/components/mod.rs1
-rw-r--r--src/componentwrapper.rs2
-rw-r--r--src/parameterexpression.rs8
-rw-r--r--src/systems/spawn.rs4
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 {