From b597d2279db7beb0d619fac472481b7f707609c8 Mon Sep 17 00:00:00 2001 From: troido Date: Thu, 2 Apr 2020 16:07:32 +0200 Subject: built doors --- content/encyclopediae/default_encyclopedia.json | 18 +++++++++++++++++- content/maps/room.json | 3 ++- src/components/interactable.rs | 16 ++++++++++++---- src/components/item.rs | 2 +- src/componentwrapper.rs | 2 +- src/parameter.rs | 2 ++ src/resources/newentities.rs | 4 ++-- src/room.rs | 2 +- src/systems/attacking.rs | 2 +- src/systems/droploot.rs | 2 +- src/systems/interact.rs | 25 +++++++++++++++++-------- src/systems/take.rs | 2 +- src/systems/useitem.rs | 2 +- todo.md | 2 +- 14 files changed, 60 insertions(+), 24 deletions(-) diff --git a/content/encyclopediae/default_encyclopedia.json b/content/encyclopediae/default_encyclopedia.json index 9b625b9..b3dc5d0 100644 --- a/content/encyclopediae/default_encyclopedia.json +++ b/content/encyclopediae/default_encyclopedia.json @@ -182,7 +182,7 @@ "name": "radishplant", "height": 0.5, "components": [ - ["Interactable", {"action": ["string", "harvest"]}], + ["Interactable", {"action": ["interaction", "harvest"]}], "Mortal", ["Loot", {"loot": ["lootlist", [["radishseed", 0.92], ["radishseed", 0.20], ["radishes", 0.8], ["radishes", 0.4]]]}] ], @@ -241,6 +241,22 @@ "slot": "hand", "stats": {"strength": 50} }] + }, + "closeddoor": { + "sprite": "closeddoor", + "height": 2, + "flags": ["Blocking"], + "components": [ + ["Interactable", {"action": ["interaction", ["change", {"type": "opendoor", "save": false}]]}] + ] + }, + "opendoor": { + "sprite": "opendoor", + "height": 0.8, + "flags": ["Occupied"], + "components": [ + ["Interactable", {"action": ["interaction", ["change", {"type": "closeddoor", "save": false}]]}] + ] } } } diff --git a/content/maps/room.json b/content/maps/room.json index 39d504e..cbf7bdc 100644 --- a/content/maps/room.json +++ b/content/maps/room.json @@ -15,7 +15,7 @@ "X,,,,,.,,,,,,,,,,,,~~~,,,,,,,,,,,,,,,,,,,X", "X,^,,,.,,,,,,,,,,,,~~~,,,,,T,,,,######,,,X", "X,^,,,.,,,,,,,,,,,,bbb,,,,,,,,,,#++++#,,,X", - "X,,,,,.............bbb...........++++#,,,X", + "X,,,,,.............bbb..........D++++#,,,X", "X,**,,.,,,,,,,,,,,,bbb,,,,,,,,,,#++++#,,,X", "X,*,*,.,,,,,V,,V,,,~~~,,,T,,,T,,#++++#,,,X", "X,,*,,.,,,,,,,,,,,,~~~,,,,,,,,,,######,,,X", @@ -46,6 +46,7 @@ "r": ["grass", {"type": "spawner", "kwargs": {"template": {"type": "rat"}, "amount": 3, "clan": "rats", "delay": 200}}], "V": ["grass", "radishplant"], "/": ["grass", "sword"], + "D": ["ground", "closeddoor"], " ": [] } } diff --git a/src/components/interactable.rs b/src/components/interactable.rs index f6ce8c4..2dca6ea 100644 --- a/src/components/interactable.rs +++ b/src/components/interactable.rs @@ -1,19 +1,27 @@ +use serde_json::{Value}; use specs::{ Component, HashMapStorage }; +use crate::{ + Template +}; -#[derive(Component, Debug, Clone, PartialEq, Eq)] +#[derive(Component, Debug, Clone, PartialEq)] #[storage(HashMapStorage)] pub enum Interactable { - Harvest + Harvest, + Change(Template) } impl Interactable { - pub fn from_str(txt: &str) -> Option { - match txt { + pub fn from_json(val: &Value) -> Option { + let typ = if val.is_string() {val} else {val.get(0)?}; + let arg = if val.is_string() {&Value::Null} else {val.get(1)?}; + match typ.as_str()? { "harvest" => Some(Interactable::Harvest), + "change" => Some(Interactable::Change(Template::from_json(arg).ok()?)), _ => None } } diff --git a/src/components/item.rs b/src/components/item.rs index 9793061..40be7f1 100644 --- a/src/components/item.rs +++ b/src/components/item.rs @@ -1,5 +1,6 @@ use std::collections::HashSet; +use serde_json::{Value}; use specs::{Component, DenseVecStorage}; use crate::{ Template, @@ -17,7 +18,6 @@ pub struct Item { -use serde_json::{json, Value}; #[derive(Debug, Clone, PartialEq)] pub enum ItemAction { diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index c4b70a5..898ab1b 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -181,7 +181,7 @@ components!( Clan (name: String); Home (home: Pos); Faction (faction: String) {Faction::from_str(faction.as_str()).ok_or(aerr!("invalid faction name"))?}; - Interactable (action: String) {Interactable::from_str(action.as_str()).ok_or(aerr!("invalid interactable name"))?}; + Interactable (action: Interaction) {action}; Loot (loot: LootList); Grow ( into: Template (Grow.into.clone()), diff --git a/src/parameter.rs b/src/parameter.rs index 2ac9be1..a9ef898 100644 --- a/src/parameter.rs +++ b/src/parameter.rs @@ -3,6 +3,7 @@ use serde_json::{Value, json}; use crate::{ Template, components::item::ItemAction, + components::interactable::Interactable, Pos }; @@ -69,6 +70,7 @@ parameters!( Float (f64) float, v (v.as_f64()?) (json!(v)); Template (Template) template, v (Template::from_json(v).ok()?) (v.to_json()); Action (ItemAction) action, v (ItemAction::from_json(v)?) (panic!("item actions can't be serialized")); + Interaction (Interactable) interaction, v (Interactable::from_json(v)?) (panic!("interactions can't be serialized")); Bool (bool) bool, v (v.as_bool()?) (json!(v)); LootList (Vec<(Template, f64)>) lootlist, v (v.as_array()?.iter().map(|item| diff --git a/src/resources/newentities.rs b/src/resources/newentities.rs index a9c4ddc..f03fbbb 100644 --- a/src/resources/newentities.rs +++ b/src/resources/newentities.rs @@ -20,8 +20,8 @@ impl NewEntities { encyclopedia } } - pub fn create(&mut self, pos: Pos, template: Template) -> Result<()> { - let components = self.encyclopedia.construct(&template)?; + pub fn create(&mut self, pos: Pos, template: &Template) -> Result<()> { + let components = self.encyclopedia.construct(template)?; self.to_build.push((pos, components)); Ok(()) } diff --git a/src/room.rs b/src/room.rs index 6c92e8c..5b125c4 100644 --- a/src/room.rs +++ b/src/room.rs @@ -261,7 +261,7 @@ impl <'a, 'b>Room<'a, 'b> { } fn create_entity(&mut self, template: Template, pos: Pos) -> Result<()>{ - self.world.fetch_mut::().create(pos, template)?; + self.world.fetch_mut::().create(pos, &template)?; Ok(()) } diff --git a/src/systems/attacking.rs b/src/systems/attacking.rs index 4318695..e4001c9 100644 --- a/src/systems/attacking.rs +++ b/src/systems/attacking.rs @@ -64,7 +64,7 @@ impl <'a> System<'a> for Attacking { } if let Some(position) = positions.get(ent){ if wounded { - new.create(position.pos, Template::empty("wound")).unwrap(); + new.create(position.pos, &Template::empty("wound")).unwrap(); } } } diff --git a/src/systems/droploot.rs b/src/systems/droploot.rs index 1b8f824..5eff7f7 100644 --- a/src/systems/droploot.rs +++ b/src/systems/droploot.rs @@ -32,7 +32,7 @@ impl <'a> System<'a> for DropLoot{ for (template, chance) in &loot.loot { if *chance > rand::thread_rng().gen_range(0.0, 1.0) { // todo: better error handling - new.create(position.pos, template.clone()).unwrap(); + new.create(position.pos, &template).unwrap(); } } } diff --git a/src/systems/interact.rs b/src/systems/interact.rs index 4c0245d..e3b8358 100644 --- a/src/systems/interact.rs +++ b/src/systems/interact.rs @@ -6,7 +6,8 @@ use specs::{ WriteStorage, System, Join, - Read + Read, + Write }; use crate::components::{ @@ -14,11 +15,12 @@ use crate::components::{ Position, ControlCooldown, Interactable, - Dead + Dead, + Removed }; use crate::controls::{Control}; -use crate::resources::{Ground}; +use crate::resources::{Ground, NewEntities}; @@ -31,18 +33,21 @@ impl <'a> System<'a> for Interact { Read<'a, Ground>, WriteStorage<'a, ControlCooldown>, ReadStorage<'a, Interactable>, - WriteStorage<'a, Dead> + WriteStorage<'a, Dead>, + WriteStorage<'a, Removed>, + Write<'a, NewEntities> ); - fn run(&mut self, (entities, controllers, positions, ground, mut cooldowns, interactables, mut deads): Self::SystemData) { + fn run(&mut self, (entities, controllers, positions, ground, mut cooldowns, interactables, mut deads, mut removeds, mut new): Self::SystemData) { for (entity, controller, position) in (&entities, &controllers, &positions).join(){ let mut target = None; match &controller.control { Control::Interact(directions) => { 'targets: for direction in directions { - for ent in ground.cells.get(&(position.pos + direction.to_position())).unwrap_or(&HashSet::new()) { + let pos = position.pos + direction.to_position(); + for ent in ground.cells.get(&pos).unwrap_or(&HashSet::new()) { if let Some(interactable) = interactables.get(*ent) { - target = Some((*ent, interactable)); + target = Some((*ent, interactable, pos)); break 'targets; } } @@ -50,11 +55,15 @@ impl <'a> System<'a> for Interact { } _ => {} } - if let Some((ent, interactable)) = target { + if let Some((ent, interactable, pos)) = target { match interactable { Interactable::Harvest => { deads.insert(ent, Dead).unwrap(); } + Interactable::Change(into) => { + new.create(pos, into).unwrap(); + removeds.insert(ent, Removed).unwrap(); + } } cooldowns.insert(entity, ControlCooldown{amount: 2}).unwrap(); } diff --git a/src/systems/take.rs b/src/systems/take.rs index 0652fdb..9eb76e7 100644 --- a/src/systems/take.rs +++ b/src/systems/take.rs @@ -63,7 +63,7 @@ impl <'a> System<'a> for Take { return } let (item, _is_equipped) = inventory.items.remove(*rank); - let _ = new.create(position.pos, item.ent); + let _ = new.create(position.pos, &item.ent); } _ => {} } diff --git a/src/systems/useitem.rs b/src/systems/useitem.rs index d96f6ef..8763843 100644 --- a/src/systems/useitem.rs +++ b/src/systems/useitem.rs @@ -48,7 +48,7 @@ impl <'a> System<'a> for Use { Build(template, required_flags, blocking_flags) => { let ground_flags = ground.flags_on(position.pos, &flags); if required_flags.is_subset(&ground_flags) && blocking_flags.is_disjoint(&ground_flags){ - new.create(position.pos, template.clone()).unwrap(); + new.create(position.pos, &template).unwrap(); inventory.items.remove(*rank); } } diff --git a/todo.md b/todo.md index ee36f49..8b4fc2c 100644 --- a/todo.md +++ b/todo.md @@ -3,10 +3,10 @@ - make readme - more tests +- command line options - timer resource? - log world events to player - draw new entities - relative room locations? - improve error handling -- doors -- cgit