From f8364fb636a8e9276939ae8523966b038388e4ff Mon Sep 17 00:00:00 2001 From: troido Date: Wed, 4 Mar 2020 16:10:32 +0100 Subject: added loot/harvest --- content/encyclopediae/default_encyclopedia.json | 13 +++++++- src/assemblage.rs | 2 +- src/components/mod.rs | 10 ++++++ src/componentwrapper.rs | 5 +-- src/parameter.rs | 14 ++++++++- src/playerstate.rs | 4 +-- src/room.rs | 10 +++--- src/systems/droploot.rs | 41 +++++++++++++++++++++++++ src/systems/mod.rs | 4 ++- 9 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 src/systems/droploot.rs diff --git a/content/encyclopediae/default_encyclopedia.json b/content/encyclopediae/default_encyclopedia.json index c1b8c1e..56a0998 100644 --- a/content/encyclopediae/default_encyclopedia.json +++ b/content/encyclopediae/default_encyclopedia.json @@ -185,7 +185,18 @@ "height": 0.5, "components": [ ["Interactable", {"action": ["string", "harvest"]}], - "Mortal" + "Mortal", + ["Loot", {"loot": ["lootlist", [["radishseed", 0.92], ["radishseed", 0.20], ["radishes", 0.8], ["radishes", 0.4]]]}] ] + }, + "radishseed": { + "sprite": "seed", + "height": 0.2, + "name": "radishseed" + }, + "radishes": { + "sprite": "food", + "height": 0.3, + "name": "radishes" } } diff --git a/src/assemblage.rs b/src/assemblage.rs index 60ead29..4c9dd82 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -75,7 +75,7 @@ impl Assemblage { 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").ok_or("property 'components' not found")?)?, + 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")? }; // visible component is so common that shortcuts are very helpful diff --git a/src/components/mod.rs b/src/components/mod.rs index 66ac724..efaeb68 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -231,4 +231,14 @@ impl Interactable { } } +#[derive(Component, Debug, Clone)] +#[storage(HashMapStorage)] +pub struct Loot { + pub loot: Vec<(Template, f64)> +} + + + + + diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index 638531b..e1389c4 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -134,8 +134,9 @@ components!( }; Clan (name: String) Clan{name}; Home (home: Pos) Home{home}; - Faction (faction: String) {Faction::from_str(faction.as_str()).unwrap()}; - Interactable (action: String) {Interactable::from_str(action.as_str()).unwrap()}; + Faction (faction: String) {Faction::from_str(faction.as_str())?}; + Interactable (action: String) {Interactable::from_str(action.as_str())?}; + Loot (loot: LootList) {Loot{loot}}; ); diff --git a/src/parameter.rs b/src/parameter.rs index 9c72d69..d761331 100644 --- a/src/parameter.rs +++ b/src/parameter.rs @@ -9,7 +9,7 @@ use crate::{ macro_rules! parameters { - ($($name: ident ($typ: ident) $stringname: ident, $v: ident ($fromjson: expr) ($tojson: expr));*;) => { + ($($name: ident ($typ: ty) $stringname: ident, $v: ident ($fromjson: expr) ($tojson: expr));*;) => { #[derive(Debug, PartialEq, Clone)] pub enum Parameter { $( @@ -70,6 +70,11 @@ parameters!( Template (Template) template, v (Template::from_json(v).ok()?) (v.to_json()); Action (ItemAction) action, v (ItemAction::from_json(v)?) (v.to_json()); Bool (bool) bool, v (v.as_bool()?) (json!(v)); + LootList (Vec<(Template, f64)>) lootlist, v + (v.as_array()?.iter().map(|item| + Some((Template::from_json(item.get(0)?).ok()?, item.get(1)?.as_f64()?)) + ).collect::>>()?) + ({json!(v.iter().map(|(t, c)| (t.to_json(), *c)).collect::>())}); ); @@ -80,6 +85,13 @@ impl Parameter { } pub fn guess_from_json(val: &Value) -> Option { + if let Some(arr) = val.as_array() { + if arr.len() == 2 && arr[0].is_string() { + let typestr = arr[0].as_str().unwrap(); + let typ = ParameterType::from_str(typestr)?; + return Self::from_typed_json(typ, &arr[1]); + } + } let typ = if val.is_string() { ParameterType::String diff --git a/src/playerstate.rs b/src/playerstate.rs index c7b5f8c..9d84e5c 100644 --- a/src/playerstate.rs +++ b/src/playerstate.rs @@ -105,14 +105,14 @@ impl PlayerState { inventory: items, health: val.get("health").ok_or(aerr!("player json does not have health"))?.as_i64().ok_or(aerr!("player health not a number"))?, inventory_capacity: inventory.get("capacity").ok_or(aerr!("inventory does no have capacity"))?.as_i64().ok_or(aerr!("inventory capacity not a number"))? as usize, - maximum_health: val.get("maxhealth").ok_or(aerr!("player json does not have maxhealth"))?.as_i64().ok_or(aerr!("maxhealh not a number"))? + maximum_health: val.get("maxhealth").ok_or(aerr!("player json does not have maxhealth"))?.as_i64().ok_or(aerr!("maxhealth not a number"))? }) } pub fn respawn(&mut self) { self.room = None; self.pos = RoomPos::Unknown; - self.health = self.maximum_health; + self.health = self.maximum_health / 2; } pub fn construct(&self, encyclopedia: &Encyclopedia) -> PreEntity { diff --git a/src/room.rs b/src/room.rs index 02a3b75..e7153b7 100644 --- a/src/room.rs +++ b/src/room.rs @@ -63,7 +63,8 @@ use crate::{ ControlAI, Die, Spawn, - Interact + Interact, + DropLoot } }; @@ -84,10 +85,11 @@ pub fn default_dispatcher<'a, 'b>() -> Dispatcher<'a, 'b> { .with(Heal, "heal", &["registernew"]) .with(Attacking, "attacking", &["use", "trapping", "fight", "heal", "interact"]) .with(Die, "die", &["attacking"]) + .with(DropLoot, "droploot", &["attacking"]) .with(View::default(), "view", &["move", "attacking", "volate", "die"]) .with(Migrate, "migrate", &["view"]) - .with(Create, "create", &["view", "spawn"]) - .with(Remove, "remove", &["view", "move"]) + .with(Create, "create", &["view", "spawn", "droploot"]) + .with(Remove, "remove", &["view", "move", "droploot"]) .build() } @@ -117,7 +119,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, Spawner, Clan, Faction, Interactable), + (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) ); diff --git a/src/systems/droploot.rs b/src/systems/droploot.rs new file mode 100644 index 0000000..616d38d --- /dev/null +++ b/src/systems/droploot.rs @@ -0,0 +1,41 @@ + +use rand::Rng; + +use specs::{ + ReadStorage, + WriteStorage, + System, + Join, + Write +}; + +use crate::{ + components::{ + Position, + Loot, + Dead + }, + resources::{NewEntities} +}; + + +pub struct DropLoot; +impl <'a> System<'a> for DropLoot{ + type SystemData = ( + WriteStorage<'a, Position>, + Write<'a, NewEntities>, + ReadStorage<'a, Dead>, + ReadStorage<'a, Loot> + ); + + fn run(&mut self, (positions, mut new, deads, loots): Self::SystemData) { + for (position, _, loot) in (&positions, &deads, &loots).join(){ + 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(); + } + } + } + } +} diff --git a/src/systems/mod.rs b/src/systems/mod.rs index 887a1f9..1735df9 100644 --- a/src/systems/mod.rs +++ b/src/systems/mod.rs @@ -18,6 +18,7 @@ mod controlai; mod die; mod spawn; mod interact; +mod droploot; pub use self::{ controlinput::ControlInput, @@ -38,5 +39,6 @@ pub use self::{ controlai::ControlAI, die::Die, spawn::Spawn, - interact::Interact + interact::Interact, + droploot::DropLoot }; -- cgit