diff options
| author | troido <troido@protonmail.com> | 2020-04-05 20:04:33 +0200 |
|---|---|---|
| committer | troido <troido@protonmail.com> | 2020-04-05 20:04:33 +0200 |
| commit | 48c24ec8b011d081550dc78329cbe61de67b30e9 (patch) | |
| tree | d2d700897dc5ba3d0f52e8a1cd57c0f4880272fd | |
| parent | 84c70cee089b72720a85d285ee0437b65be298b9 (diff) | |
items are now mostly replaced by itemids, with a mapping to the item in the encyclopedia
| -rw-r--r-- | content/encyclopediae/default_encyclopedia.json | 65 | ||||
| -rw-r--r-- | src/assemblage.rs | 10 | ||||
| -rw-r--r-- | src/components/inventory.rs | 20 | ||||
| -rw-r--r-- | src/components/mod.rs | 10 | ||||
| -rw-r--r-- | src/componentwrapper.rs | 3 | ||||
| -rw-r--r-- | src/encyclopedia.rs | 82 | ||||
| -rw-r--r-- | src/item.rs (renamed from src/components/item.rs) | 18 | ||||
| -rw-r--r-- | src/main.rs | 2 | ||||
| -rw-r--r-- | src/parameter.rs | 2 | ||||
| -rw-r--r-- | src/playerstate.rs | 55 | ||||
| -rw-r--r-- | src/room.rs | 2 | ||||
| -rw-r--r-- | src/systems/take.rs | 11 | ||||
| -rw-r--r-- | src/systems/useitem.rs | 10 | ||||
| -rw-r--r-- | src/systems/view.rs | 2 | ||||
| -rw-r--r-- | src/template.rs | 17 |
15 files changed, 184 insertions, 125 deletions
diff --git a/content/encyclopediae/default_encyclopedia.json b/content/encyclopediae/default_encyclopedia.json index a7196d8..1c48a6b 100644 --- a/content/encyclopediae/default_encyclopedia.json +++ b/content/encyclopediae/default_encyclopedia.json @@ -72,37 +72,6 @@ "sprite": "water", "height": 0.1 }, - "pebble": { - "components": [ - ["Item", { - "ent": ["self", null], - "name": ["string", "pebble"], - "action": ["action", ["none", null]] - }] - ], - "sprite": "pebble", - "height": 0.3 - }, - "stone": { - "item": ["build", ["builtwall", ["Floor"], ["Blocking"]]], - "sprite": "stone", - "height": 0.4 - }, - "player": { - "arguments": [["name", "string"]], - "components": [ - ["Visible", { - "sprite": ["string", "player"], - "height": ["float", 1.0], - "name": ["arg", "name"] - }], - ["Player", { - "name": ["arg", "name"] - }], - ["Inventory", {"capacity": ["int", 3]}], - ["Health", {"health": ["int", 9], "maxhealth": ["int", 10]}] - ] - }, "portal": { "arguments": [["destination", "string"], ["dest_pos", "string", ""]], "components": [ @@ -187,18 +156,12 @@ ["Loot", {"loot": ["list", [ ["list", [{"type": "radishseed"}, 0.92]], ["list", [{"type": "radishseed"}, 0.20]], - ["list", [{"type": "radishes"}, 0.8]], - ["list", [{"type": "radishes"}, 0.4]] + ["list", [{"type": "radish"}, 0.8]], + ["list", [{"type": "radish"}, 0.4]] ]]}] ], "flags": ["Occupied"] }, - "radishseed": { - "sprite": "seed", - "height": 0.2, - "name": "radishseed", - "item": ["build", ["plantedradishseed", ["Floor", "Soil"], ["Occupied", "Blocking"]]] - }, "plantedradishseed": { "arguments": [["target_time", "int", 0]], "sprite": "seed", @@ -233,20 +196,6 @@ }, "flags": ["Occupied"] }, - "radishes": { - "sprite": "food", - "height": 0.3, - "name": "radishes", - "item": ["eat", 3] - }, - "sword": { - "sprite": "sword", - "height": 0.5, - "item": ["equip", { - "slot": "hand", - "stats": {"strength": 50} - }] - }, "closeddoor": { "sprite": "closeddoor", "height": 2, @@ -279,5 +228,15 @@ ["Interactable", {"action": ["interaction", ["reply", "did you say '{}'?"]]}] ] } + }, + "items": { + "pebble": {}, + "stone": {"action": ["build", ["builtwall", ["Floor"], ["Blocking"]]]}, + "radishseed": {"action": ["build", ["plantedradishseed", ["Floor", "Soil"], ["Occupied", "Blocking"]]]}, + "radish": {"action": ["eat", 3]}, + "sword": {"action": ["equip", { + "slot": "hand", + "stats": {"strength": 50} + }]} } } diff --git a/src/assemblage.rs b/src/assemblage.rs index 6856151..aa3154f 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -98,15 +98,9 @@ impl Assemblage { }])); } // item component is common too - if let Some(action) = val.get("item") { + if let Some(item) = val.get("item") { components.push(json!(["Item", { - "ent": ["self", null], - "name": if let Some(n) = name { - json!(["string", n]) - } else { - json!(["name", Value::Null]) - }, - "action": ["action", action] + "item": ["string", item] }])); } // and so is flags diff --git a/src/components/inventory.rs b/src/components/inventory.rs index 81064d8..c3282e9 100644 --- a/src/components/inventory.rs +++ b/src/components/inventory.rs @@ -1,14 +1,22 @@ use std::collections::HashMap; use specs::{Component, FlaggedStorage, HashMapStorage}; -use super::{ +use crate::{ + ItemId, item::{Item, ItemAction}, - equipment::{Stat, Equippable}, + components::equipment::{Stat, Equippable}, }; +#[derive(Debug, Clone)] +pub struct InventoryEntry { + pub itemid: ItemId, + pub item: Item, + pub is_equipped: bool +} + #[derive(Debug, Clone, Default)] pub struct Inventory { - pub items: Vec<(Item, bool)>, + pub items: Vec<InventoryEntry>, pub capacity: usize } impl Component for Inventory { @@ -19,9 +27,9 @@ impl Inventory { fn equipped(&self) -> Vec<Equippable> { let mut equippables = Vec::new(); - for (item, is_equipped) in self.items.iter() { - if *is_equipped { - if let ItemAction::Equip(equippable) = &item.action { + for entry in self.items.iter() { + if entry.is_equipped { + if let ItemAction::Equip(equippable) = &entry.item.action { equippables.push(equippable.clone()); } else { panic!("unequippable item equipped!"); diff --git a/src/components/mod.rs b/src/components/mod.rs index 1a590b2..4065cc2 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,5 +1,4 @@ -pub mod item; pub mod messages; pub mod faction; pub mod interactable; @@ -9,7 +8,6 @@ pub mod serialise; pub mod flags; pub mod ear; -pub use item::Item; pub use messages::{ AttackMessage, AttackInbox, @@ -46,7 +44,8 @@ use crate::{ controls::Control, Template, playerstate::RoomPos, - Timestamp + Timestamp, + ItemId, }; #[derive(Component, Debug, Clone)] @@ -229,3 +228,8 @@ pub struct CreationTime { } +#[derive(Component, Debug, Clone)] +pub struct Item(pub ItemId); + + + diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index 360a546..d00b592 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -6,6 +6,7 @@ use rand::Rng; use crate::{ PlayerId, RoomId, + ItemId, Sprite, playerstate::RoomPos, components::{ @@ -143,7 +144,7 @@ components!( }; Movable (cooldown: Int); Player (name: String) {Player::new(PlayerId{name})}; - Item (ent: Template, name: String, action: Action); + Item (item: String) {Item(ItemId(item))}; Inventory () {panic!("inventory from parameters not implemented")}; Health (health: Int, maxhealth: Int); Serialise () {panic!("serialise from parameters not implemented")}; diff --git a/src/encyclopedia.rs b/src/encyclopedia.rs index 4e09f22..fe9a9d3 100644 --- a/src/encyclopedia.rs +++ b/src/encyclopedia.rs @@ -1,34 +1,98 @@ use std::collections::HashMap; -use serde_json::Value; +use serde_json::{Value, json}; use crate::{ assemblage::Assemblage, componentwrapper::PreEntity, Template, template::EntityType, Result, - aerr + aerr, + ItemId, + item::Item, + item::ItemAction }; #[derive(Default, Clone)] pub struct Encyclopedia { - items: HashMap<EntityType, Assemblage> + assemblages: HashMap<EntityType, Assemblage>, + items: HashMap<ItemId, Item> } impl Encyclopedia { pub fn from_json(val: Value) -> Result<Encyclopedia> { - let mut items = HashMap::new(); - for (k, v) in val.get("assemblages").ok_or(aerr!("no assemblages in encyclopedia json"))?.as_object().ok_or(aerr!("encyclopedia not a json object"))?.into_iter() { - items.insert(EntityType(k.clone()), Assemblage::from_json(v)?); - } - Ok(Encyclopedia{items}) + let mut assemblages = + val + .get("assemblages") + .ok_or(aerr!("no assemblages in encyclopedia json"))? + .as_object() + .ok_or(aerr!("encyclopedia assemblages not a json object"))? + .into_iter() + .map(|(k, v)| Ok((EntityType(k.clone()), Assemblage::from_json(v)?))) + .collect::<Result<HashMap<EntityType, Assemblage>>>()?; + let items = + val + .get("items") + .ok_or(aerr!("no items in encyclopedia json"))? + .as_object() + .ok_or(aerr!("encyclopedia items not a json object"))? + .into_iter() + .map(|(k, v)| { + let id = ItemId(k.clone()); + let sprite = + if let Some(sprite) = v.get("sprite") { + sprite.as_str().ok_or(aerr!("item sprite not a string: {:?}", v))? + } else { + k + }; + let name = + if let Some(name) = v.get("name") { + name.as_str().ok_or(aerr!("item name not a string: {:?}", v))?.to_string() + } else { + k.to_string() + }; + let item = Item { + name: name.clone(), + ent: + if let Some(ent) = v.get("entity") { + Template::from_json(ent)? + } else { + let enttyp = EntityType(k.clone()); + assemblages.insert(enttyp.clone(), Assemblage::from_json(&json!({ + "height": 0.3, + "sprite": sprite, + "name": name, + "item": k + }))?); + Template::from_entity_type(enttyp) + }, + action: + if let Some(action) = v.get("action") { + ItemAction::from_json(action).ok_or(aerr!("failed to parse ItemAction: {:?}", v))? + } else { + ItemAction::None + } + }; + Ok((id, item)) + }) + .collect::<Result<HashMap<ItemId, Item>>>()?; + + Ok(Encyclopedia{ + assemblages, + items + }) } pub fn construct(&self, template: &Template) -> Result<PreEntity> { - let assemblage = self.items.get(&template.name).ok_or(aerr!("unknown assemblage name: '{:?}' in {:?}", template.name, template))?; + let assemblage = self.assemblages + .get(&template.name) + .ok_or(aerr!("unknown assemblage name: '{:?}' in {:?}", template.name, template))?; assemblage.instantiate(template) } + pub fn get_item(&self, id: &ItemId) -> Option<Item> { + self.items.get(id).map(|item| item.clone()) + } } diff --git a/src/components/item.rs b/src/item.rs index 0cb2589..d5ffaa1 100644 --- a/src/components/item.rs +++ b/src/item.rs @@ -1,24 +1,28 @@ + use std::collections::HashSet; use serde_json::{Value}; use specs::{Component, DenseVecStorage}; use crate::{ Template, - components::Flag + components::{ + Flag, + equipment::Equippable + } }; -use super::equipment::Equippable; -#[derive(Component, Debug, Clone)] + +#[derive(Debug, Default, PartialEq, Eq, Clone, Hash)] +pub struct ItemId(pub String); + +#[derive(Debug, Clone)] pub struct Item { pub ent: Template, pub name: String, pub action: ItemAction } - - - #[derive(Debug, Clone, PartialEq)] pub enum ItemAction { Eat(i64), @@ -52,7 +56,7 @@ impl ItemAction { mod tests { use super::*; use crate::hashmap; - use super::super::equipment::*; + use crate::components::equipment::*; use serde_json::json; #[test] diff --git a/src/main.rs b/src/main.rs index 2f42ac3..34819e3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,11 +35,13 @@ mod sprite; mod timestamp; mod purgatory; mod config; +mod item; use self::{ pos::Pos, playerid::PlayerId, roomid::RoomId, + item::ItemId, util::Result, sprite::Sprite, template::Template, diff --git a/src/parameter.rs b/src/parameter.rs index ed445b3..a7419ed 100644 --- a/src/parameter.rs +++ b/src/parameter.rs @@ -2,7 +2,6 @@ use serde_json::{Value, json}; use crate::{ Template, - components::item::ItemAction, components::interactable::Interactable, Pos }; @@ -69,7 +68,6 @@ parameters!( Pos (Pos) pos, v (Pos::from_json(v)?) (json!(v)); 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)); List (Vec<Parameter>) list, _v diff --git a/src/playerstate.rs b/src/playerstate.rs index f05332b..852c04f 100644 --- a/src/playerstate.rs +++ b/src/playerstate.rs @@ -6,10 +6,12 @@ use crate::{ componentwrapper::{ComponentWrapper, PreEntity}, PlayerId, RoomId, + ItemId, components::{ Visible, Player, Inventory, + inventory::InventoryEntry, Health, Fighter, Healing, @@ -43,7 +45,7 @@ pub struct PlayerState { pub room: Option<RoomId>, pub pos: RoomPos, pub inventory_capacity: usize, - pub inventory: Vec<(Template, bool)>, + pub inventory: Vec<(ItemId, bool)>, pub health: i64, pub maximum_health: i64, pub equipment: HashMap<Slot, Option<Template>> @@ -64,7 +66,7 @@ impl PlayerState { } } - pub fn create(id: PlayerId, room: RoomId, inventory: Vec<(Template, bool)>, inventory_capacity: usize, health: i64, maximum_health: i64, equipment: HashMap<Slot, Option<Template>>) -> Self { + pub fn create(id: PlayerId, room: RoomId, inventory: Vec<(ItemId, bool)>, inventory_capacity: usize, health: i64, maximum_health: i64, equipment: HashMap<Slot, Option<Template>>) -> Self { Self { id, room: Some(room), @@ -86,7 +88,7 @@ impl PlayerState { }, "inventory": { "capacity": self.inventory_capacity, - "items": self.inventory.iter().map(|(item, e)| (Template::to_json(item), *e)).collect::<Vec<(Value, bool)>>() + "items": self.inventory.iter().map(|(item, e)| (json!(item.0), *e)).collect::<Vec<(Value, bool)>>() }, "equipment": { "hand": null, @@ -99,17 +101,31 @@ impl PlayerState { pub fn from_json(val: &Value) -> Result<Self> { let inventory = val.get("inventory").ok_or(aerr!("player json does not have inventory"))?; - let mut items = vec![]; - for item in inventory.get("items").ok_or(aerr!("inventory does not have items"))?.as_array().ok_or(aerr!("inventory items not an array"))? { - if item.is_array() { - items.push(( - Template::from_json(item.get(0).ok_or(aerr!("invalid item"))?)?, - item.get(1).ok_or(aerr!("invalid item"))?.as_bool().ok_or(aerr!("invalid item"))? - )); - } else { - items.push((Template::from_json(item)?, false)); - } - } + let items = + inventory + .get("items") + .ok_or(aerr!("inventory does not have items"))? + .as_array() + .ok_or(aerr!("inventory items not an array"))? + .into_iter() + .map(|entry| { + let itemid = ItemId( + entry + .get(0) + .ok_or(aerr!("item does not have name"))? + .as_str() + .ok_or(aerr!("item name not a string"))? + .to_string() + ); + let is_equipped = + entry + .get(1) + .ok_or(aerr!("item does not have equipped flag"))? + .as_bool() + .ok_or(aerr!("item is_equipped not a bool"))?; + Ok((itemid, is_equipped)) + }) + .collect::<Result<Vec<(ItemId, bool)>>>()?; Ok(Self { id: PlayerId{name: val.get("name").ok_or(aerr!("player json does not have name"))?.as_str().ok_or(aerr!("player name not a string"))?.to_string()}, room: match val.get("roomname").ok_or(aerr!("player json does not have room name"))? { @@ -136,14 +152,9 @@ impl PlayerState { ComponentWrapper::Visible(Visible{sprite: Sprite{name: "player".to_string()}, height: 1.2, name: self.id.name.clone()}), ComponentWrapper::Player(Player::new(self.id.clone())), ComponentWrapper::Inventory(Inventory{ - items: self.inventory.iter().map( |(template, equippable)| { - let item_ent = encyclopedia.construct(template).unwrap(); - for component in item_ent { - if let ComponentWrapper::Item(item) = component { - return (item, *equippable); - } - } - panic!("Item in inventory does not have item component") + items: self.inventory.iter().map( |(itemid, is_equipped)| { + let item = encyclopedia.get_item(itemid).unwrap(); + InventoryEntry{itemid: itemid.clone(), item, is_equipped: *is_equipped} }).collect(), capacity: self.inventory_capacity }), diff --git a/src/room.rs b/src/room.rs index 2b4fb7e..46948cb 100644 --- a/src/room.rs +++ b/src/room.rs @@ -250,7 +250,7 @@ impl <'a, 'b>Room<'a, 'b> { Some(PlayerState::create( player.id.clone(), self.id.clone(), - inventory.items.iter().map(|(item, e)| (item.ent.clone(), *e)).collect(), + inventory.items.iter().map(|entry| (entry.itemid.clone(), entry.is_equipped)).collect(), inventory.capacity, health.health, health.maxhealth, diff --git a/src/systems/take.rs b/src/systems/take.rs index 9eb76e7..5a86269 100644 --- a/src/systems/take.rs +++ b/src/systems/take.rs @@ -14,6 +14,7 @@ use crate::components::{ Position, Removed, Inventory, + inventory::InventoryEntry, Item, Visible }; @@ -50,7 +51,11 @@ impl <'a> System<'a> for Take { } for ent in ents { if let Some(item) = items.get(ent) { - inventory.items.insert(0, (item.clone(), false)); + inventory.items.insert(0, InventoryEntry{ + itemid: item.0.clone(), + item: new.encyclopedia.get_item(&item.0).unwrap(), + is_equipped: false + }); if let Err(msg) = removed.insert(ent, Removed) { println!("{:?}", msg); } @@ -62,8 +67,8 @@ impl <'a> System<'a> for Take { if *rank >= inventory.items.len() { return } - let (item, _is_equipped) = inventory.items.remove(*rank); - let _ = new.create(position.pos, &item.ent); + let entry = inventory.items.remove(*rank); + let _ = new.create(position.pos, &entry.item.ent); } _ => {} } diff --git a/src/systems/useitem.rs b/src/systems/useitem.rs index 8763843..605f083 100644 --- a/src/systems/useitem.rs +++ b/src/systems/useitem.rs @@ -21,7 +21,7 @@ use crate::{ Flags }, resources::{NewEntities, Ground}, - components::item::ItemAction::{None, Build, Eat, Equip}, + item::ItemAction::{None, Build, Eat, Equip}, controls::Control, }; @@ -44,7 +44,7 @@ impl <'a> System<'a> for Use { match &controller.control { Control::Use(rank) => { if let Some(entry) = inventory.items.get_mut(*rank) { - match &entry.0.action { + match &entry.item.action { 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){ @@ -59,13 +59,13 @@ impl <'a> System<'a> for Use { Equip(equippable) => { let slot = equippable.slot; for otherentry in inventory.items.iter_mut() { - if let Equip(other) = &otherentry.0.action { + if let Equip(other) = &otherentry.item.action { if other.slot == slot { - otherentry.1 = false; + otherentry.is_equipped = false; } } } - inventory.items[*rank].1 = true; + inventory.items[*rank].is_equipped = true; } None => {} } diff --git a/src/systems/view.rs b/src/systems/view.rs index 4419203..f1641bd 100644 --- a/src/systems/view.rs +++ b/src/systems/view.rs @@ -59,7 +59,7 @@ impl <'a> System<'a> for View { updates.change = Some(changes.clone()); } if let Some(inventory) = inventories.get(ent){ - updates.inventory = Some(inventory.items.iter().map(|(item, _equipped)| item.name.clone()).collect()); + updates.inventory = Some(inventory.items.iter().map(|entry| entry.item.name.clone()).collect()); } if let Some(health) = healths.get(ent){ updates.health = Some((health.health, health.maxhealth)); diff --git a/src/template.rs b/src/template.rs index 496d08e..0f62754 100644 --- a/src/template.rs +++ b/src/template.rs @@ -31,15 +31,24 @@ impl Template { } } + pub fn empty(name: &str) -> Self { + Self::new(name, HashMap::new()) + } + + pub fn from_entity_type(typ: EntityType) -> Self { + Self { + name: typ, + args: Vec::new(), + kwargs: HashMap::new(), + save: true + } + } + pub fn unsaved(mut self) -> Self { self.save = false; self } - pub fn empty(name: &str) -> Self { - Self::new(name, HashMap::new()) - } - pub fn from_json(val: &Value) -> Result<Template> { if val.is_string(){ return Ok(Self::empty(val.as_str().unwrap())); |
