diff options
| -rw-r--r-- | content/encyclopediae/default_encyclopedia.json | 137 | ||||
| -rw-r--r-- | src/assemblage.rs | 2 | ||||
| -rw-r--r-- | src/componentparameter.rs | 5 | ||||
| -rw-r--r-- | src/componentwrapper.rs | 10 | ||||
| -rw-r--r-- | src/encyclopedia.rs | 23 | ||||
| -rw-r--r-- | src/parameter.rs | 7 | ||||
| -rw-r--r-- | src/savestate.rs | 2 | ||||
| -rw-r--r-- | src/template.rs | 15 |
8 files changed, 152 insertions, 49 deletions
diff --git a/content/encyclopediae/default_encyclopedia.json b/content/encyclopediae/default_encyclopedia.json index b7364d5..760779d 100644 --- a/content/encyclopediae/default_encyclopedia.json +++ b/content/encyclopediae/default_encyclopedia.json @@ -24,16 +24,16 @@ "components": [ ["Visible", { "sprite": ["random", [ - ["string", "grass1"], - ["string", "grass2"], - ["string", "grass3"], - ["string", "grass1"], - ["string", "grass2"], - ["string", "grass3"], - ["string", "ground"] + "grass1", + "grass2", + "grass3", + "grass1", + "grass2", + "grass3", + "ground" ]], - "height": ["float", 0.1], - "name": ["string", "grass"] + "height": 0.1, + "name": "grass" }] ], "flags": ["Floor", "Soil"] @@ -42,12 +42,12 @@ "components": [ ["Visible", { "sprite": ["random", [ - ["string", "grass1"], - ["string", "grass2"], - ["string", "grass3"] + "grass1", + "grass2", + "grass3" ]], - "height": ["float", 0.1], - "name": ["string", "grass"] + "height": 0.1, + "name": "grass" }] ], "flags": ["Floor", "Soil"] @@ -82,7 +82,7 @@ "builtwall": { "arguments": [["health", "int", 100]], "components": [ - ["Health", {"health": ["arg", "health"], "maxhealth": ["int", 100]}], + ["Health", {"health": ["arg", "health"], "maxhealth": 100}], "Mortal" ], "sprite": "wall", @@ -91,7 +91,7 @@ "flags": ["Blocking"] }, "spiketrap": { - "components": [["Trap", {"damage": ["int", 8]}]], + "components": [["Trap", {"damage": 8}]], "sprite": "spikes", "height": 0.8 }, @@ -100,14 +100,14 @@ "sprite": "dummy", "height": 1, "components": [ - ["Health", {"health": ["arg", "health"], "maxhealth": ["int", 20]}], + ["Health", {"health": ["arg", "health"], "maxhealth": 20}], "Mortal" ] }, "wound": { "sprite": "wound", "height": 0.25, - "components": [["Volatile", {"delay": ["int", 4]}]], + "components": [["Volatile", {"delay": 3}]], "save": false }, "rat": { @@ -115,15 +115,15 @@ "height": 1, "components": [ ["MonsterAI", { - "view_distance": ["int", 3], - "move_chance": ["float", 0.08], - "homesickness": ["float", 0.1] + "view_distance": 3, + "move_chance": 0.08, + "homesickness": 0.1 }], - ["Health", {"health": ["int", 8], "maxhealth": ["int", 8]}], - ["Fighter", {"damage": ["int", 2], "cooldown": ["int", 6]}], - ["Movable", {"cooldown": ["int", 3]}], + ["Health", {"health": 8, "maxhealth": 8}], + ["Fighter", {"damage": 2, "cooldown": 6}], + ["Movable", {"cooldown": 3}], "Mortal", - ["Faction", {"faction": ["string", "evil"]}] + ["Faction", {"faction": "evil"}] ] }, "spawner": { @@ -141,9 +141,9 @@ "letter": { "arguments": [["char", "string"]], "components": [["Visible", { - "name": ["concat", [["string", "letter_"], ["arg", "char"]]], - "sprite": ["concat", [["string", "emptyletter-"], ["arg", "char"]]], - "height": ["float", 1.0] + "name": ["concat", ["letter_", ["arg", "char"]]], + "sprite": ["concat", ["emptyletter-", ["arg", "char"]]], + "height": 1.0 }]] }, "radishplant": { @@ -169,7 +169,7 @@ "name": "seed", "components": [ ["Grow", { - "delay": ["int", 600], + "delay": 600, "target_time": ["arg", "target_time"], "into": ["template", "radishseedling"] }] @@ -186,7 +186,7 @@ "name": "seedling", "components": [ ["Grow", { - "delay": ["int", 600], + "delay": 600, "target_time": ["arg", "target_time"], "into": ["template", "radishplant"] }] @@ -234,9 +234,77 @@ "components": [ ["Interactable", {"action": ["interaction", ["exchange", ["buy ", { "pebble": [["radish", "radish"], ["pebble"]], - "radishseed": [["radish"], ["radishseed", "radishseed"]] + "radishseed": [["radish"], ["radishseed", "radishseed"]], + "carrotseed": [["radish"], ["carrotseed"]] }]]]}] ] + }, + "plantedseed": { + "arguments": [["target_time", "int", 0], ["next", "template"], ["delay", "int"]], + "sprite": "seed", + "height": 0.05, + "name": "plantedseed", + "components": [ + ["Grow", { + "delay": ["arg", "delay"], + "target_time": ["arg", "target_time"], + "into": ["arg", "next"] + }] + ], + "extract": { + "target_time": ["Grow", "target_time"] + }, + "flags": ["Occupied"] + }, + "seedling": { + "arguments": [["target_time", "int", 0], ["next", "template"], ["delay", "int"]], + "sprite": "seed", + "height": 0.09, + "name": "seedling", + "components": [ + ["Grow", { + "delay": ["arg", "delay"], + "target_time": ["arg", "target_time"], + "into": ["arg", "next"] + }] + ], + "extract": { + "target_time": ["Grow", "target_time"] + }, + "flags": ["Occupied"] + }, + "youngplant": { + "arguments": [["target_time", "int", 0], ["next", "template"], ["crop", "string"], ["delay", "int"]], + "components": [ + ["Grow", { + "delay": ["arg", "delay"], + "target_time": ["arg", "target_time"], + "into": ["arg", "next"] + }], + ["Visible", { + "name": ["concat", [["string", "young"], ["arg", "crop"], ["string", "plant"]]], + "sprite": "youngplant", + "height": 0.8 + }] + ], + "extract": { + "target_time": ["Grow", "target_time"] + }, + "flags": ["Occupied"] + }, + "carrotplant": { + "sprite": "smallplant", + "name": "carrotplant", + "height": 1.0, + "components": [ + ["Interactable", {"action": ["interaction", "harvest"]}], + "Mortal", + ["Loot", {"loot": ["list", [ + ["list", [{"type": "carrotseed"}, 1.0]], + ["list", [{"type": "carrot"}, 1.0]] + ]]}] + ], + "flags": ["Occupied"] } }, "items": { @@ -244,9 +312,16 @@ "stone": {"action": ["build", ["builtwall", ["Floor"], ["Blocking"]]]}, "radishseed": {"sprite": "seed", "action": ["build", ["plantedradishseed", ["Floor", "Soil"], ["Occupied", "Blocking"]]]}, "radish": {"sprite": "food", "action": ["eat", 3]}, + "carrotseed": {"sprite": "seed", "action": ["build", ["plantedcarrotseed", ["Floor", "Soil"], ["Occupied", "Blocking"]]]}, + "carrot": {"sprite": "food", "action": ["eat", 5]}, "sword": {"action": ["equip", { "slot": "hand", "stats": {"strength": 50} }]} + }, + "templates":{ + "plantedcarrotseed": ["plantedseed", {"delay": 60, "next": "carrotseedling"}], + "carrotseedling": ["seedling", {"delay": 60, "next": "youngcarrotplant"}], + "youngcarrotplant": ["youngplant", {"crop": "carrot", "delay": 60, "next": "carrotplant"}] } } diff --git a/src/assemblage.rs b/src/assemblage.rs index 8f36556..e453471 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -142,7 +142,7 @@ impl Assemblage { pub fn validate(&self) -> Result<()> { for (comptype, parameters) in &self.components { for (paramname, paramtype) in comptype.parameters() { - let param = parameters.get(paramname).ok_or(aerr!("missing parameter"))?; + let param = parameters.get(paramname).ok_or(aerr!("missing parameter {} in {:?}", paramname, self))?; let actualtype = param.get_type(&self.arguments)?; if actualtype != paramtype { return Err(aerr!("parameter type incorrect")); diff --git a/src/componentparameter.rs b/src/componentparameter.rs index 73c7b30..47c9a26 100644 --- a/src/componentparameter.rs +++ b/src/componentparameter.rs @@ -63,6 +63,9 @@ impl ComponentParameter { } pub fn from_json(value: &Value) -> PResult<Self> { + if !value.is_array() { + return Ok(Self::Constant(Parameter::guess_from_json(value).ok_or(perr!("invalid component parameter {:?}", value))?)); + } let paramvalue = value.get(1).ok_or(perr!("index 1 not in component parameter"))?; let typename = value.get(0).ok_or(perr!("index 0 not in component parameter"))?.as_str().ok_or(perr!("compparam type not a string"))?; if let Some(paramtype) = ParameterType::from_str(typename) { @@ -101,7 +104,7 @@ impl ComponentParameter { pub fn get_type(&self, arguments: &[(String, ParameterType, Option<Parameter>)]) -> Result<ParameterType>{ Ok(match self { Self::Constant(param) => param.paramtype(), - Self::Argument(argname) => arguments.iter().find(|(n, _t, _d)| n == argname).ok_or(aerr!("unknown argument name"))?.1, + Self::Argument(argname) => arguments.iter().find(|(n, _t, _d)| n == argname).ok_or(aerr!("unknown argument name {} in {:?}", argname, arguments))?.1, Self::Random(options) => { let typ: ParameterType = options.get(0).ok_or(aerr!("random has no options"))?.get_type(arguments)?; for param in options { diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index d00b592..4b9401a 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -189,18 +189,18 @@ components!( loot .iter() .map(|param| {match param { - Parameter::Template(template) => Some((template.clone(), 1.0)), + Parameter::Template(template) => Ok((template.clone(), 1.0)), Parameter::List(l) => { if l.len() == 2 { if let (Parameter::Template(template), Parameter::Float(chance)) = (l[0].clone(), l[1].clone()) { - return Some((template.clone(), chance)) + return Ok((template.clone(), chance)) } } - None? + Err(aerr!("loot list elements as list must only contain a template and a float: {:?}", l))? }, - _ => None? + _ => Err(aerr!("loot list elements must be a template or a list: {:?}", param))? }}) - .collect::<Option<Vec<(Template, f64)>>>().ok_or(aerr!("invalid loot definition"))? + .collect::<Result<Vec<(Template, f64)>>>()? } }; Grow ( diff --git a/src/encyclopedia.rs b/src/encyclopedia.rs index c378b84..d396e0f 100644 --- a/src/encyclopedia.rs +++ b/src/encyclopedia.rs @@ -12,7 +12,8 @@ use crate::{ item::Item, item::ItemAction, PResult, - perr + perr, + parameter::Parameter }; #[derive(Default, Clone)] @@ -79,6 +80,26 @@ impl Encyclopedia { Ok((id, item)) }) .collect::<PResult<HashMap<ItemId, Item>>>()?; + for (name, v) in + val + .get("templates") + .unwrap_or(&json!({})) + .as_object().ok_or(perr!("templates not a json dict: {:?}", val.get("templates")))? + .iter() { + let enttype = EntityType(v + .get(0).ok_or(perr!("index 0 not in subtitution template"))? + .as_str().ok_or(perr!("subtitution origin name not a string"))? + .to_string()); + let values = v.get(1).ok_or(perr!("index 0 not in subtitution template"))?; + let mut assemblage = assemblages.get(&enttype).ok_or(perr!("template name '{:?}' points not an assemblage", enttype))?.clone(); + for arg in assemblage.arguments.iter_mut() { + if let Some(x) = values.get(&arg.0) { + let param = Parameter::from_typed_json(arg.1, x).ok_or(perr!("subtitution parameter has wrong type"))?; + arg.2 = Some(param); + } + } + assemblages.insert(EntityType(name.to_string()), assemblage); + } Ok(Encyclopedia{ assemblages, diff --git a/src/parameter.rs b/src/parameter.rs index a7419ed..196f5fe 100644 --- a/src/parameter.rs +++ b/src/parameter.rs @@ -70,15 +70,15 @@ parameters!( Template (Template) template, v (Template::from_json(v).ok()?) (v.to_json()); Interaction (Interactable) interaction, _v (Interactable::from_json(_v)?) (panic!("interactions can't be serialized")); Bool (bool) bool, v (v.as_bool()?) (json!(v)); - List (Vec<Parameter>) list, _v + List (Vec<Parameter>) list, v ({ - _v + v .as_array()? .iter() .map(|item| Parameter::guess_from_json(item)) .collect::<Option<Vec<Parameter>>>()? }) - (panic!("can not serialise parameter list")); + (json!(["list", v.iter().map(Parameter::to_json).collect::<Vec<Value>>()])); ); @@ -108,7 +108,6 @@ impl Parameter { } else if val.is_object(){ ParameterType::Template } else { - println!("{:?}", val); return None }; Self::from_typed_json(typ, val) diff --git a/src/savestate.rs b/src/savestate.rs index 4482fca..c3b79cb 100644 --- a/src/savestate.rs +++ b/src/savestate.rs @@ -4,8 +4,6 @@ use serde_json::{json, Value}; use crate::{ Pos, Template, - Result, - aerr, PResult, perr }; diff --git a/src/template.rs b/src/template.rs index c2f905f..850a323 100644 --- a/src/template.rs +++ b/src/template.rs @@ -49,10 +49,17 @@ impl Template { self } - pub fn from_json(val: &Value) -> PResult<Template> { - if val.is_string(){ - return Ok(Self::empty(val.as_str().unwrap())); - } + pub fn from_json(v: &Value) -> PResult<Template> { + let val = match v { + Value::String(s) => json!({"type": s}), + Value::Array(_) => json!({ + "type": v.get(0).ok_or(perr!("index 0 not in template array {:?}", v))?, + "kwargs": v.get(1).ok_or(perr!("index 1 not in template array {:?}", v))? + }), + Value::Object(_) => v.clone(), + _ => Err(perr!("invalid template {:?}", v))? + }; + let name = EntityType(val.get("type").ok_or(perr!("template doesn't have 'type'"))?.as_str().ok_or(perr!("template type not a string"))?.to_string()); let mut args = Vec::new(); for arg in val.get("args").unwrap_or(&json!([])).as_array().ok_or(perr!("template args not an array"))? { |
