summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortroido <troido@protonmail.com>2020-04-05 20:04:33 +0200
committertroido <troido@protonmail.com>2020-04-05 20:04:33 +0200
commit48c24ec8b011d081550dc78329cbe61de67b30e9 (patch)
treed2d700897dc5ba3d0f52e8a1cd57c0f4880272fd
parent84c70cee089b72720a85d285ee0437b65be298b9 (diff)
items are now mostly replaced by itemids, with a mapping to the item in the encyclopedia
-rw-r--r--content/encyclopediae/default_encyclopedia.json65
-rw-r--r--src/assemblage.rs10
-rw-r--r--src/components/inventory.rs20
-rw-r--r--src/components/mod.rs10
-rw-r--r--src/componentwrapper.rs3
-rw-r--r--src/encyclopedia.rs82
-rw-r--r--src/item.rs (renamed from src/components/item.rs)18
-rw-r--r--src/main.rs2
-rw-r--r--src/parameter.rs2
-rw-r--r--src/playerstate.rs55
-rw-r--r--src/room.rs2
-rw-r--r--src/systems/take.rs11
-rw-r--r--src/systems/useitem.rs10
-rw-r--r--src/systems/view.rs2
-rw-r--r--src/template.rs17
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()));