diff options
| author | troido <troido@protonmail.com> | 2020-03-03 13:36:44 +0100 |
|---|---|---|
| committer | troido <troido@protonmail.com> | 2020-03-03 13:36:44 +0100 |
| commit | b2157791dfcaab18ec7f8ebb958341fe325cf419 (patch) | |
| tree | f94e638573878599b0ee108a0b06fbe1c8f69ef9 /src | |
| parent | a8d0e075613cc973b66c37510103108362fe7d3d (diff) | |
added spawners an not-saved assemblages/templates
Diffstat (limited to 'src')
| -rw-r--r-- | src/assemblage.rs | 14 | ||||
| -rw-r--r-- | src/components/mod.rs | 15 | ||||
| -rw-r--r-- | src/componentwrapper.rs | 43 | ||||
| -rw-r--r-- | src/defaultencyclopedia.rs | 14 | ||||
| -rw-r--r-- | src/room.rs | 18 | ||||
| -rw-r--r-- | src/systems/mod.rs | 4 | ||||
| -rw-r--r-- | src/systems/spawn.rs | 50 | ||||
| -rw-r--r-- | src/template.rs | 3 | ||||
| -rw-r--r-- | src/worldloader.rs | 1 |
9 files changed, 125 insertions, 37 deletions
diff --git a/src/assemblage.rs b/src/assemblage.rs index 71142f1..65c9bfa 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -15,7 +15,8 @@ type ArgumentDef = (String, ParameterType, Option<Parameter>); #[derive(Debug, PartialEq, Clone)] pub struct Assemblage { pub arguments: Vec<ArgumentDef>, - pub components: Vec<(ComponentType, HashMap<String, ComponentParameter>)> + pub components: Vec<(ComponentType, HashMap<String, ComponentParameter>)>, + pub save: bool } impl Assemblage { @@ -74,7 +75,8 @@ impl Assemblage { pub fn from_json(val: &Value) -> Result<Self, &'static str>{ let mut assemblage = Self { arguments: Self::parse_definition_arguments(val.get("arguments").unwrap_or(&json!([])))?, - components: Self::parse_definition_components(val.get("components").ok_or("property 'components' not found")?)? + components: Self::parse_definition_components(val.get("components").ok_or("property 'components' not found")?)?, + save: val.get("save").unwrap_or(&json!(true)).as_bool().ok_or("assemblage save not a bool")? }; // visible component is so common that shortcuts are very helpful if let Some(spritename) = val.get("sprite") { @@ -134,7 +136,7 @@ impl Assemblage { } components.push(ComponentWrapper::load_component(*comptype, compargs).ok_or("failed to load component")?); } - if template.save { + if template.save && self.save { components.push(ComponentWrapper::Serialise(Serialise{template: template.clone()})); } Ok(components) @@ -184,7 +186,8 @@ mod tests { "sprite".to_string() => ComponentParameter::Argument("sprite".to_string()), "height".to_string() => ComponentParameter::Constant(Parameter::Float(0.1)) )) - ] + ], + save: true }; assert_eq!(result, constructed); } @@ -294,7 +297,8 @@ mod tests { "sprite".to_string() => ComponentParameter::Argument("sprite".to_string()), "height".to_string() => ComponentParameter::Constant(Parameter::Float(0.1)) )) - ] + ], + save: true }; assert_eq!(result, constructed); } diff --git a/src/components/mod.rs b/src/components/mod.rs index 8c0e6c6..8777d37 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -197,5 +197,20 @@ pub struct Home { #[derive(Component, Debug, Clone, Default)] pub struct Mortal; +#[derive(Component, Debug, Clone)] +#[storage(HashMapStorage)] +pub struct Spawner { + pub amount: usize, + pub delay: i64, + pub clan: Clan, + pub template: Template, + pub last_spawn: Timestamp +} + +#[derive(Component, Debug, Clone, PartialEq, Eq, Hash)] +#[storage(HashMapStorage)] +pub struct Clan { + pub name: String, +} diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index c553f61..a03ab17 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use specs::Builder; +use rand::Rng; use crate::{ PlayerId, @@ -8,37 +9,22 @@ use crate::{ Sprite, playerstate::RoomPos, components::{ - Visible, - Movable, - Blocking, - Player, - Floor, - Item, - Inventory, - Health, - Serialise, - RoomExit, - Trap, - Fighter, - Healing, - Volatile, AttackMessage, - Autofight, - MonsterAI, - Mortal + Clan }, - parameter::{Parameter, ParameterType} + parameter::{Parameter, ParameterType}, + Timestamp }; macro_rules! components { - ($($comp: ident ($($paramname: ident : $paramtype: ident),*) {$creation: expr});*;) => { + ($($comp: ident ($($paramname: ident : $paramtype: ident),*) $creation: expr);*;) => { #[derive(Clone)] pub enum ComponentWrapper{ $( - $comp($comp), + $comp(crate::components::$comp), )* } @@ -58,6 +44,7 @@ macro_rules! components { $( ComponentType::$comp => Some(Self::$comp({ + use crate::components::$comp; $( let $paramname = match parameters.remove(stringify!($paramname))? { Parameter::$paramtype(p) => p, @@ -140,6 +127,22 @@ components!( Autofight () {Autofight::default()}; MonsterAI (move_chance: Float, homesickness: Float, view_distance: Int) {MonsterAI{move_chance, homesickness, view_distance}}; Mortal () {Mortal}; + Spawner (amount: Int, delay: Int, clan: String, template: Template) { + Spawner{ + amount: amount as usize, + delay, + clan: Clan{name: + if clan == "" { + format!("$random({})", rand::thread_rng().gen::<u32>()) + } else { + clan + } + }, + template, + last_spawn: Timestamp(0) + } + }; + Clan (name: String) Clan{name}; ); diff --git a/src/defaultencyclopedia.rs b/src/defaultencyclopedia.rs index 252174d..b6ab6cc 100644 --- a/src/defaultencyclopedia.rs +++ b/src/defaultencyclopedia.rs @@ -145,7 +145,8 @@ pub fn default_encyclopedia() -> Encyclopedia { "wound": { "sprite": "wound", "height": 0.25, - "components": [["Volatile", {"delay": ["int", 4]}]] + "components": [["Volatile", {"delay": ["int", 4]}]], + "save": false }, "rat": { "sprite": "rat", @@ -161,6 +162,17 @@ pub fn default_encyclopedia() -> Encyclopedia { ["Movable", {"cooldown": ["int", 3]}], "Mortal" ] + }, + "spawner": { + "arguments": [["template", "template", null], ["amount", "int", 1], ["delay", "int", 0], ["clan", "string", ""]], + "components": [ + ["Spawner", { + "template": ["arg", "template"], + "amount": ["arg", "amount"], + "delay": ["arg", "delay"], + "clan": ["arg", "clan"] + }] + ] } })).unwrap() } diff --git a/src/room.rs b/src/room.rs index 52621ac..f3cdbf8 100644 --- a/src/room.rs +++ b/src/room.rs @@ -19,7 +19,7 @@ use crate::{ Output, Input, NewEntities, - Spawn, + Spawn as SpawnPosition, Players, Emigration, TimeStamp @@ -61,7 +61,8 @@ use crate::{ Volate, UpdateCooldowns, ControlAI, - Die + Die, + Spawn } }; @@ -70,6 +71,7 @@ pub fn default_dispatcher<'a, 'b>() -> Dispatcher<'a, 'b> { .with(Volate, "volate", &[]) .with(RegisterNew::default(), "registernew", &[]) .with(UpdateCooldowns, "cool_down", &["registernew"]) + .with(Spawn, "spawn", &["registernew"]) .with(ControlInput, "controlinput", &["cool_down"]) .with(ControlAI, "controlai", &["cool_down"]) .with(Take, "take", &["controlinput", "controlai"]) @@ -82,7 +84,7 @@ pub fn default_dispatcher<'a, 'b>() -> Dispatcher<'a, 'b> { .with(Die, "die", &["attacking"]) .with(View::default(), "view", &["move", "attacking", "volate", "die"]) .with(Migrate, "migrate", &["view"]) - .with(Create, "create", &["view"]) + .with(Create, "create", &["view", "spawn"]) .with(Remove, "remove", &["view", "move"]) .build() } @@ -113,7 +115,7 @@ 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), + (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), (Ground, Input, Output, Size, Spawn, Players, Emigration, TimeStamp) ); @@ -131,14 +133,14 @@ impl <'a, 'b>Room<'a, 'b> { self.world.fetch_mut::<Size>().width = width; self.world.fetch_mut::<Size>().height = height; - self.world.fetch_mut::<Spawn>().pos = template.spawn; + self.world.fetch_mut::<SpawnPosition>().pos = template.spawn; for (idx, templates) in template.field.iter().enumerate() { let x = (idx as i64) % width; let y = (idx as i64) / width; for template in templates { - let _ = self.create_entity(template.clone().unsaved(), Pos{x, y}); + self.create_entity(template.clone().unsaved(), Pos{x, y}).unwrap(); } } for (name, place) in &template.places { @@ -171,7 +173,7 @@ impl <'a, 'b>Room<'a, 'b> { pub fn add_player(&mut self, state: &PlayerState){ let pre_player = state.construct(&self.world.fetch::<NewEntities>().encyclopedia); let spawn = match &state.pos { - RoomPos::Unknown => self.world.fetch::<Spawn>().pos, + RoomPos::Unknown => self.world.fetch::<SpawnPosition>().pos, RoomPos::Pos(pos) => *pos, RoomPos::Name(name) => *self.places.get(name).unwrap() }; @@ -205,7 +207,7 @@ impl <'a, 'b>Room<'a, 'b> { pub fn load_saved(&mut self, state: &SaveState) { for (pos, templates) in state.changes.iter() { for template in templates { - let _ = self.create_entity(template.clone(), *pos); + self.create_entity(template.clone(), *pos).unwrap(); } } } diff --git a/src/systems/mod.rs b/src/systems/mod.rs index f4b3edb..37afcd0 100644 --- a/src/systems/mod.rs +++ b/src/systems/mod.rs @@ -16,6 +16,7 @@ mod volate; mod updatecooldowns; mod controlai; mod die; +mod spawn; pub use self::{ controlinput::ControlInput, @@ -34,5 +35,6 @@ pub use self::{ volate::Volate, updatecooldowns::UpdateCooldowns, controlai::ControlAI, - die::Die + die::Die, + spawn::Spawn }; diff --git a/src/systems/spawn.rs b/src/systems/spawn.rs new file mode 100644 index 0000000..6bb4912 --- /dev/null +++ b/src/systems/spawn.rs @@ -0,0 +1,50 @@ + +use std::collections::HashMap; + +use specs::{ + WriteStorage, + ReadStorage, + Write, + Read, + System, + Join +}; + +use crate::{ + components::{ + Position, + Spawner, + Clan + }, + resources::{NewEntities, TimeStamp}, + componentwrapper::ComponentWrapper +}; + + + +pub struct Spawn; +impl <'a> System<'a> for Spawn { + type SystemData = ( + ReadStorage<'a, Position>, + Write<'a, NewEntities>, + WriteStorage<'a, Spawner>, + ReadStorage<'a, Clan>, + Read<'a, TimeStamp> + ); + + fn run(&mut self, (positions, mut new, mut spawners, clans, time): Self::SystemData) { + let mut clan_nums: HashMap<&Clan, usize> = HashMap::new(); + for clan in (&clans).join() { + let n: usize = *clan_nums.entry(clan).or_insert(0); + clan_nums.insert(clan, n+1); + } + for (spawner, position) in (&mut spawners, &positions).join() { + if time.time > spawner.last_spawn + spawner.delay && *clan_nums.get(&spawner.clan).unwrap_or(&0) < spawner.amount { + spawner.last_spawn = time.time; + let mut preent = new.encyclopedia.construct(&spawner.template).expect("unable to spawn entity from spawner"); + preent.push(ComponentWrapper::Clan(spawner.clan.clone())); + new.to_build.push((position.pos, preent)); + } + } + } +} diff --git a/src/template.rs b/src/template.rs index 5539f94..cf0fee2 100644 --- a/src/template.rs +++ b/src/template.rs @@ -53,7 +53,8 @@ impl Template { for (key, arg) in val.get("kwargs").unwrap_or(&json!({})).as_object().ok_or(aerr!("template kwargs not a json object"))? { kwargs.insert(key.to_string(), Parameter::guess_from_json(arg).ok_or(aerr!("template arg not a parameter"))?); } - Ok(Template {name, args, kwargs, save: true}) + let save = val.get("save").unwrap_or(&json!(true)).as_bool().ok_or(aerr!("save not a bool"))?; + Ok(Template {name, args, kwargs, save}) } pub fn to_json(&self) -> Value { diff --git a/src/worldloader.rs b/src/worldloader.rs index afaabb7..d8a7c0f 100644 --- a/src/worldloader.rs +++ b/src/worldloader.rs @@ -25,7 +25,6 @@ impl WorldLoader { let mut path = self.directory.clone(); let fname = id.to_string() + ".json"; path.push(fname); - println!("PATH: {:?}", path); let text = fs::read_to_string(path)?; let json: Value = serde_json::from_str(&text)?; let template = RoomTemplate::from_json(&json)?; |
