From 022e439a6677b9865b7a3287dbd197d86266f8ef Mon Sep 17 00:00:00 2001 From: troido Date: Wed, 4 Mar 2020 19:47:00 +0100 Subject: implemented growth --- src/assemblage.rs | 58 ++++++++++++++++++++++++----------------------- src/componentparameter.rs | 32 +++++++++++++++----------- src/components/mod.rs | 8 +++++++ src/componentwrapper.rs | 1 + src/encyclopedia.rs | 12 ++++++---- src/resources/mod.rs | 2 +- src/room.rs | 16 +++++++------ src/systems/droploot.rs | 3 +-- src/systems/growth.rs | 48 +++++++++++++++++++++++++++++++++++++++ src/systems/heal.rs | 10 ++++---- src/systems/mod.rs | 4 +++- src/systems/spawn.rs | 4 ++-- src/systems/useitem.rs | 4 ++-- src/systems/volate.rs | 4 ++-- 14 files changed, 138 insertions(+), 68 deletions(-) create mode 100644 src/systems/growth.rs (limited to 'src') diff --git a/src/assemblage.rs b/src/assemblage.rs index 4c9dd82..730b34d 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -7,7 +7,9 @@ use crate::{ componentwrapper::{ComponentWrapper, ComponentType}, components::Serialise, hashmap, - Template + Template, + Result, + aerr }; type ArgumentDef = (String, ParameterType, Option); @@ -22,34 +24,34 @@ pub struct Assemblage { impl Assemblage { - fn parse_definition_arguments(args: &Value) -> Result, &'static str> { + fn parse_definition_arguments(args: &Value) -> Result> { let mut arguments: Vec = Vec::new(); - for arg in args.as_array().ok_or("arguments is not an array")? { - let tup = arg.as_array().ok_or("argument is not an array")?; - let key = tup.get(0).ok_or("argument has no name")?.as_str().ok_or("argument name is not a string")?.to_string(); - let typ = ParameterType::from_str(tup.get(1).ok_or("argument has no type")?.as_str().ok_or("argument type not a string")?).ok_or("failed to parse argument type")?; + for arg in args.as_array().ok_or(aerr!("arguments is not an array"))? { + let tup = arg.as_array().ok_or(aerr!("argument is not an array"))?; + let key = tup.get(0).ok_or(aerr!("argument has no name"))?.as_str().ok_or(aerr!("argument name is not a string"))?.to_string(); + let typ = ParameterType::from_str(tup.get(1).ok_or(aerr!("argument has no type"))?.as_str().ok_or(aerr!("argument type not a string"))?).ok_or(aerr!("failed to parse argument type"))?; let def = tup.get(2).ok_or("argument has no default")?; if def.is_null() { arguments.push((key.clone(), typ, None)); } else { - arguments.push((key.clone(), typ, Some(Parameter::from_typed_json(typ, def).ok_or("invalid argument default")?))); + arguments.push((key.clone(), typ, Some(Parameter::from_typed_json(typ, def).ok_or(aerr!("invalid argument default"))?))); } } Ok(arguments) } - fn parse_definition_components(comps: &Value) -> Result)>, &'static str> { + fn parse_definition_components(comps: &Value) -> Result)>> { let mut components = Vec::new(); - for tup in comps.as_array().ok_or("components is not a json array")? { + for tup in comps.as_array().ok_or(aerr!("components is not a json array"))? { if let Some(name) = tup.as_str() { - components.push((ComponentType::from_str(name).ok_or("not a valid componenttype")?, HashMap::new())); + components.push((ComponentType::from_str(name).ok_or(aerr!("not a valid componenttype"))?, HashMap::new())); } else { let comptype = ComponentType::from_str(tup - .get(0).ok_or("index 0 not in component")? - .as_str().ok_or("component name not a string")? + .get(0).ok_or(aerr!("index 0 not in component"))? + .as_str().ok_or(aerr!("component name not a string"))? ).ok_or("not a valid componenttype")?; let mut parameters: HashMap = HashMap::new(); - for (key, value) in tup.get(1).ok_or("index 1 not in component")?.as_object().ok_or("component parameters not a json object")? { + for (key, value) in tup.get(1).ok_or(aerr!("index 1 not in component"))?.as_object().ok_or(aerr!("component parameters not a json object"))? { let param = ComponentParameter::from_json(value)?; parameters.insert(key.clone(), param); } @@ -59,40 +61,40 @@ impl Assemblage { Ok(components) } - fn validate(&self) -> Result<(), &'static str> { + fn validate(&self) -> Result<()> { for (comptype, parameters) in &self.components { for (paramname, paramtype) in comptype.parameters() { - let param = parameters.get(paramname).ok_or("missing parameter")?; + let param = parameters.get(paramname).ok_or(aerr!("missing parameter"))?; let actualtype = param.get_type(&self.arguments)?; if actualtype != paramtype { - return Err("parameter type incorrect"); + return Err(aerr!("parameter type incorrect")); } } } Ok(()) } - pub fn from_json(val: &Value) -> Result{ + pub fn from_json(val: &Value) -> Result{ let mut assemblage = Self { arguments: Self::parse_definition_arguments(val.get("arguments").unwrap_or(&json!([])))?, components: Self::parse_definition_components(val.get("components").unwrap_or(&json!([])))?, - save: val.get("save").unwrap_or(&json!(true)).as_bool().ok_or("assemblage save not a bool")? + save: val.get("save").unwrap_or(&json!(true)).as_bool().ok_or(aerr!("assemblage save not a bool"))? }; // visible component is so common that shortcuts are very helpful if let Some(spritename) = val.get("sprite") { - let height = val.get("height").ok_or("defining a sprite requires also defining a height")?; + let height = val.get("height").ok_or(aerr!("defining a sprite requires also defining a height"))?; let name = val.get("name").unwrap_or(spritename); assemblage.components.push(( ComponentType::Visible, hashmap!( "sprite".to_string() => ComponentParameter::Constant( - Parameter::String(spritename.as_str().ok_or("sprite not a string")?.to_string()) + Parameter::String(spritename.as_str().ok_or(aerr!("sprite not a string"))?.to_string()) ), "height".to_string() => ComponentParameter::Constant( - Parameter::Float(height.as_f64().ok_or("height not a float")?) + Parameter::Float(height.as_f64().ok_or(aerr!("height not a float"))?) ), "name".to_string() => ComponentParameter::Constant( - Parameter::String(name.as_str().ok_or("name not a string")?.to_string()) + Parameter::String(name.as_str().ok_or(aerr!("name not a string"))?.to_string()) ) ) )); @@ -101,7 +103,7 @@ impl Assemblage { Ok(assemblage) } - fn prepare_arguments(&self, args: &[Parameter], kwargs: &HashMap) -> Result, &'static str> { + fn prepare_arguments(&self, args: &[Parameter], kwargs: &HashMap) -> Result> { let mut arguments: HashMap<&str, Parameter> = HashMap::new(); for (idx, (name, typ, def)) in self.arguments.iter().enumerate() { let value: Option = { @@ -115,16 +117,16 @@ impl Assemblage { None } }; - let param = value.ok_or("argument has no value")?; + let param = value.ok_or(aerr!("argument has no value"))?; if param.paramtype() != *typ { - return Err("argument has incorrect type"); + return Err(aerr!("argument has incorrect type")); } arguments.insert(name, param); } Ok(arguments) } - pub fn instantiate(&self, template: &Template) -> Result, &'static str>{ + pub fn instantiate(&self, template: &Template) -> Result>{ let args = &template.args; let kwargs = &template.kwargs; let mut components: Vec = Vec::new(); @@ -132,9 +134,9 @@ impl Assemblage { 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).ok_or("argument not found")?); + compargs.insert(name.as_str(), param.evaluate(&arguments).ok_or(aerr!("argument not found"))?); } - components.push(ComponentWrapper::load_component(*comptype, compargs).ok_or("failed to load component")?); + components.push(ComponentWrapper::load_component(*comptype, compargs).ok_or(aerr!("failed to load component"))?); } if template.save && self.save { components.push(ComponentWrapper::Serialise(Serialise{template: template.clone()})); diff --git a/src/componentparameter.rs b/src/componentparameter.rs index 2b76849..fdbfc71 100644 --- a/src/componentparameter.rs +++ b/src/componentparameter.rs @@ -2,7 +2,11 @@ use std::collections::HashMap; use rand::Rng; use serde_json::Value; -use crate::parameter::{Parameter, ParameterType}; +use crate::{ + parameter::{Parameter, ParameterType}, + Result, + aerr +}; const MAX_NESTING: usize = 5; @@ -50,19 +54,21 @@ impl ComponentParameter { } } - pub fn from_json(value: &Value) -> Result { - let paramvalue = value.get(1).ok_or("index 1 not in component parameter")?; - let typename = value.get(0).ok_or("index 0 not in component parameter")?.as_str().ok_or("compparam type not a string")?; + pub fn from_json(value: &Value) -> Result { + let paramvalue = value.get(1).ok_or(aerr!("index 1 not in component parameter"))?; + let typename = value.get(0).ok_or(aerr!("index 0 not in component parameter"))?.as_str().ok_or(aerr!("compparam type not a string"))?; if let Some(paramtype) = ParameterType::from_str(typename) { - Ok(Self::Constant(Parameter::from_typed_json(paramtype, paramvalue).ok_or("failed to parse parameter constant")?)) + Ok(Self::Constant(Parameter::from_typed_json(paramtype, paramvalue).ok_or_else(|| + aerr!(& format!("failed to parse parameter constant: {:?} {:?}", paramtype, paramvalue)) + )?)) } else { match typename { "A" | "arg" => { - let argname = paramvalue.as_str().ok_or("argument parameter not a string")?.to_string(); + let argname = paramvalue.as_str().ok_or(aerr!("argument parameter not a string"))?.to_string(); Ok(Self::Argument(argname)) }, "random" => { - let optionvalues = paramvalue.as_array().ok_or("random argument not an array")?; + let optionvalues = paramvalue.as_array().ok_or(aerr!("random argument not an array"))?; let mut options = Vec::new(); for option in optionvalues { options.push(Self::from_json(option)?) @@ -70,27 +76,27 @@ impl ComponentParameter { Ok(Self::Random(options)) }, "concat" => { - let values = paramvalue.as_array().ok_or("concat argument not an array")?; + let values = paramvalue.as_array().ok_or(aerr!("concat argument not an array"))?; let mut options = Vec::new(); for option in values { options.push(Self::from_json(option)?) } Ok(Self::Concat(options)) }, - _ => Err("unknown compparam type") + _ => Err(aerr!("unknown compparam type")) } } } - pub fn get_type(&self, arguments: &[(String, ParameterType, Option)]) -> Result{ + pub fn get_type(&self, arguments: &[(String, ParameterType, Option)]) -> Result{ Ok(match self { Self::Constant(param) => param.paramtype(), - Self::Argument(argname) => arguments.iter().find(|(n, _t, _d)| n == argname).ok_or("unknown argument name")?.1, + Self::Argument(argname) => arguments.iter().find(|(n, _t, _d)| n == argname).ok_or(aerr!("unknown argument name"))?.1, Self::Random(options) => { - let typ: ParameterType = options.get(0).ok_or("random has no options")?.get_type(arguments)?; + let typ: ParameterType = options.get(0).ok_or(aerr!("random has no options"))?.get_type(arguments)?; for param in options { if param.get_type(arguments)? != typ { - return Err("inconsistent parameter types"); + return Err(aerr!("inconsistent parameter types")); } } typ diff --git a/src/components/mod.rs b/src/components/mod.rs index efaeb68..ac6c9e6 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -238,6 +238,14 @@ pub struct Loot { } +#[derive(Component, Debug, Clone)] +#[storage(HashMapStorage)] +pub struct Grow { + pub delay: i64, + pub target_time: Option, + pub into: Template +} + diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index e1389c4..7a3d946 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -137,6 +137,7 @@ components!( Faction (faction: String) {Faction::from_str(faction.as_str())?}; Interactable (action: String) {Interactable::from_str(action.as_str())?}; Loot (loot: LootList) {Loot{loot}}; + Grow (delay: Int, into: Template) {Grow{delay, into, target_time: None}}; ); diff --git a/src/encyclopedia.rs b/src/encyclopedia.rs index 7b40373..8de5424 100644 --- a/src/encyclopedia.rs +++ b/src/encyclopedia.rs @@ -5,7 +5,9 @@ use crate::{ assemblage::Assemblage, componentwrapper::PreEntity, Template, - template::EntityType + template::EntityType, + Result, + aerr }; #[derive(Default, Clone)] @@ -15,16 +17,16 @@ pub struct Encyclopedia { impl Encyclopedia { - pub fn from_json(val: Value) -> Result { + pub fn from_json(val: Value) -> Result { let mut items = HashMap::new(); - for (k, v) in val.as_object().ok_or("encyclopedia not a json object")?.into_iter() { + for (k, v) in val.as_object().ok_or(aerr!("encyclopedia not a json object"))?.into_iter() { items.insert(EntityType(k.clone()), Assemblage::from_json(v)?); } Ok(Encyclopedia{items}) } - pub fn construct(&self, template: &Template) -> Result { - let assemblage = self.items.get(&template.name).ok_or("unknown assemblage name")?; + pub fn construct(&self, template: &Template) -> Result { + let assemblage = self.items.get(&template.name).ok_or(aerr!("unknown assemblage name"))?; assemblage.instantiate(template) } diff --git a/src/resources/mod.rs b/src/resources/mod.rs index 4ce0e59..ae3f4e2 100644 --- a/src/resources/mod.rs +++ b/src/resources/mod.rs @@ -52,6 +52,6 @@ pub struct Emigration { } #[derive(Default)] -pub struct TimeStamp { +pub struct Time { pub time: Timestamp } diff --git a/src/room.rs b/src/room.rs index e7153b7..f41350a 100644 --- a/src/room.rs +++ b/src/room.rs @@ -22,7 +22,7 @@ use crate::{ Spawn as SpawnPosition, Players, Emigration, - TimeStamp + Time }, components::{ Position, @@ -64,7 +64,8 @@ use crate::{ Die, Spawn, Interact, - DropLoot + DropLoot, + Growth } }; @@ -72,6 +73,7 @@ pub fn default_dispatcher<'a, 'b>() -> Dispatcher<'a, 'b> { DispatcherBuilder::new() .with(Volate, "volate", &[]) .with(RegisterNew::default(), "registernew", &[]) + .with(Growth, "growth", &["registernew"]) .with(UpdateCooldowns, "cool_down", &["registernew"]) .with(Spawn, "spawn", &["registernew"]) .with(ControlInput, "controlinput", &["cool_down"]) @@ -88,7 +90,7 @@ pub fn default_dispatcher<'a, 'b>() -> Dispatcher<'a, 'b> { .with(DropLoot, "droploot", &["attacking"]) .with(View::default(), "view", &["move", "attacking", "volate", "die"]) .with(Migrate, "migrate", &["view"]) - .with(Create, "create", &["view", "spawn", "droploot"]) + .with(Create, "create", &["view", "spawn", "droploot", "growth"]) .with(Remove, "remove", &["view", "move", "droploot"]) .build() } @@ -119,8 +121,8 @@ impl <'a, 'b>Room<'a, 'b> { world.insert(NewEntities::new(encyclopedia)); register_insert!( world, - (Position, Visible, Controller, Movable, Blocking, Floor, New, Removed, Moved, Player, Inventory, Health, Serialise, RoomExit, Entered, Dead, Trap, Fighter, Healing, Volatile, ControlCooldown, Autofight, MonsterAI, Home, Mortal, AttackInbox, Item, Spawner, Clan, Faction, Interactable, Loot), - (Ground, Input, Output, Size, Spawn, Players, Emigration, TimeStamp) + (Position, Visible, Controller, Movable, Blocking, Floor, New, Removed, Moved, Player, Inventory, Health, Serialise, RoomExit, Entered, Dead, Trap, Fighter, Healing, Volatile, ControlCooldown, Autofight, MonsterAI, Home, Mortal, AttackInbox, Item, Spawner, Clan, Faction, Interactable, Loot, Grow), + (Ground, Input, Output, Size, Spawn, Players, Emigration, Time) ); Room { @@ -164,7 +166,7 @@ impl <'a, 'b>Room<'a, 'b> { } pub fn update(&mut self, timestamp: Timestamp) { - self.world.fetch_mut::().time = timestamp; + self.world.fetch_mut::