summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortroido <troido@protonmail.com>2020-04-02 14:13:18 +0200
committertroido <troido@protonmail.com>2020-04-02 14:13:18 +0200
commit4f9932074a8f0390d5cb6072b4e419c7ab08ffed (patch)
treed83da5cd8b35af25aa6e0b2c9105182920c49bd0
parentec007f34c4cd984640a235660803b81a739742b3 (diff)
added flags component, and conditions for building
-rw-r--r--content/encyclopediae/default_encyclopedia.json26
-rw-r--r--src/assemblage.rs2
-rw-r--r--src/components/flags.rs32
-rw-r--r--src/components/item.rs22
-rw-r--r--src/components/mod.rs13
-rw-r--r--src/componentwrapper.rs32
-rw-r--r--src/parameter.rs7
-rw-r--r--src/resources/ground.rs14
-rw-r--r--src/room.rs2
-rw-r--r--src/systems/moving.rs23
-rw-r--r--src/systems/useitem.rs23
-rw-r--r--src/world.rs2
-rw-r--r--todo.md1
13 files changed, 126 insertions, 73 deletions
diff --git a/content/encyclopediae/default_encyclopedia.json b/content/encyclopediae/default_encyclopedia.json
index 28d834d..46bb64e 100644
--- a/content/encyclopediae/default_encyclopedia.json
+++ b/content/encyclopediae/default_encyclopedia.json
@@ -1,22 +1,22 @@
{
"assemblages": {
"wall": {
- "components": ["Blocking"],
+ "components": [["Flags", {"flags": ["strings", ["Blocking"]]}]],
"sprite": "wall",
"height": 2
},
"rock": {
- "components": ["Blocking"],
+ "components": [["Flags", {"flags": ["strings", ["Blocking"]]}]],
"sprite": "rock",
"height": 10
},
"tree": {
- "components": ["Blocking"],
+ "components": [["Flags", {"flags": ["strings", ["Blocking"]]}]],
"sprite": "tree",
"height": 3
},
"fence": {
- "components": ["Blocking"],
+ "components": [["Flags", {"flags": ["strings", ["Blocking"]]}]],
"sprite": "fence",
"height": 1
},
@@ -35,7 +35,7 @@
"height": ["float", 0.1],
"name": ["string", "grass"]
}],
- "Floor"
+ ["Flags", {"flags": ["strings", ["Floor", "Soil"]]}]
]
},
"greengrass": {
@@ -49,22 +49,22 @@
"height": ["float", 0.1],
"name": ["string", "grass"]
}],
- "Floor"
+ ["Flags", {"flags": ["strings", ["Floor", "Soil"]]}]
]
},
"ground": {
- "components": ["Floor"],
+ "components": [["Flags", {"flags": ["strings", ["Floor", "Soil"]]}]],
"sprite": "ground",
"height": 0.1
},
"floor": {
- "components": ["Floor"],
+ "components": [["Flags", {"flags": ["strings", ["Floor"]]}]],
"sprite": "floor",
"height": 0.1
},
"bridge": {
"components": [
- "Floor"
+ ["Flags", {"flags": ["strings", ["Floor"]]}]
],
"sprite": "bridge",
"height": 0.1
@@ -86,7 +86,7 @@
"height": 0.3
},
"stone": {
- "item": ["build", "builtwall"],
+ "item": ["build", ["builtwall", ["Floor"], ["Blocking"]]],
"sprite": "stone",
"height": 0.4
},
@@ -109,13 +109,13 @@
"arguments": [["destination", "string"], ["dest_pos", "string", ""]],
"components": [
["RoomExit", {"destination": ["arg", "destination"], "dest_pos": ["arg", "dest_pos"]}],
- "Floor"
+ ["Flags", {"flags": ["strings", ["Floor"]]}]
]
},
"builtwall": {
"arguments": [["health", "int", 100]],
"components": [
- "Blocking",
+ ["Flags", {"flags": ["strings", ["Blocking"]]}],
["Health", {"health": ["arg", "health"], "maxhealth": ["int", 100]}],
"Mortal"
],
@@ -193,7 +193,7 @@
"sprite": "seed",
"height": 0.2,
"name": "radishseed",
- "item": ["build", "plantedradishseed"]
+ "item": ["build", ["plantedradishseed", ["Floor", "Soil"], ["Occupied"]]]
},
"plantedradishseed": {
"arguments": [["target_time", "int", 0]],
diff --git a/src/assemblage.rs b/src/assemblage.rs
index 55c52f4..ffb1420 100644
--- a/src/assemblage.rs
+++ b/src/assemblage.rs
@@ -188,7 +188,7 @@ impl Assemblage {
for (name, param) in compparams {
compargs.insert(name.as_str(), param.evaluate(&arguments, template).ok_or(aerr!("argument not found"))?);
}
- components.push(ComponentWrapper::load_component(*comptype, compargs).ok_or(aerr!("failed to load component"))?);
+ components.push(ComponentWrapper::load_component(*comptype, compargs)?);
}
if template.save && self.save {
components.push(ComponentWrapper::Serialise(Serialise{template: template.clone(), extract: self.extract.clone() }));
diff --git a/src/components/flags.rs b/src/components/flags.rs
new file mode 100644
index 0000000..d985bf2
--- /dev/null
+++ b/src/components/flags.rs
@@ -0,0 +1,32 @@
+
+use std::collections::HashSet;
+use specs::{
+ Component,
+ VecStorage,
+};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum Flag {
+ Blocking,
+ Floor,
+ Occupied,
+ Soil
+}
+
+use Flag::*;
+impl Flag {
+ pub fn from_str(s: &str) -> Option<Flag> {
+ Some(match s {
+ "Blocking" => Blocking,
+ "Floor" => Floor,
+ "Occupied" => Occupied,
+ "Soil" => Soil,
+ _ => None?
+ })
+ }
+}
+
+
+#[derive(Component, Debug, Clone, PartialEq, Eq)]
+#[storage(VecStorage)]
+pub struct Flags(pub HashSet<Flag>);
diff --git a/src/components/item.rs b/src/components/item.rs
index 3b931bb..9793061 100644
--- a/src/components/item.rs
+++ b/src/components/item.rs
@@ -1,6 +1,10 @@
+use std::collections::HashSet;
use specs::{Component, DenseVecStorage};
-use crate::{Template};
+use crate::{
+ Template,
+ components::Flag
+};
use super::equipment::Equippable;
@@ -18,7 +22,7 @@ use serde_json::{json, Value};
#[derive(Debug, Clone, PartialEq)]
pub enum ItemAction {
Eat(i64),
- Build(Template),
+ Build(Template, HashSet<Flag>, HashSet<Flag>),
Equip(Equippable),
None
}
@@ -26,21 +30,17 @@ pub enum ItemAction {
use ItemAction::{Eat, Build, Equip, None};
impl ItemAction {
- pub fn to_json(&self) -> Value {
- match self {
- Eat(health) => json!(["eat", health]),
- Build(template) => json!(["build", template.to_json()]),
- Equip(equippable) => json!(["equip", equippable.to_json()]),
- None => json!(["none", null])
- }
- }
pub fn from_json(val: &Value) -> Option<Self> {
let typ = val.get(0)?;
let arg = val.get(1)?;
Some(match typ.as_str()? {
"eat" => Eat(arg.as_i64()?),
- "build" => Build(Template::from_json(arg).ok()?),
+ "build" => Build(
+ Template::from_json(arg.get(0)?).ok()?,
+ arg.get(1)?.as_array()?.into_iter().map(|v| Flag::from_str(v.as_str()?)).collect::<Option<HashSet<Flag>>>()?,
+ arg.get(2)?.as_array()?.into_iter().map(|v| Flag::from_str(v.as_str()?)).collect::<Option<HashSet<Flag>>>()?
+ ),
"none" => None,
"equip" => Equip(Equippable::from_json(arg)?),
_ => {return Option::None}
diff --git a/src/components/mod.rs b/src/components/mod.rs
index 071b5e0..efdf8f7 100644
--- a/src/components/mod.rs
+++ b/src/components/mod.rs
@@ -6,6 +6,7 @@ pub mod interactable;
pub mod equipment;
pub mod inventory;
pub mod serialise;
+pub mod flags;
pub use item::Item;
pub use messages::{
@@ -18,6 +19,10 @@ pub use interactable::Interactable;
pub use equipment::Equipment;
pub use inventory::Inventory;
pub use serialise::Serialise;
+pub use flags::{
+ Flag,
+ Flags
+};
use specs::{
DenseVecStorage,
@@ -76,14 +81,6 @@ pub struct Movable {
#[derive(Default, Component, Debug, Clone)]
#[storage(NullStorage)]
-pub struct Blocking;
-
-#[derive(Default, Component, Debug, Clone)]
-#[storage(NullStorage)]
-pub struct Floor;
-
-#[derive(Default, Component, Debug, Clone)]
-#[storage(NullStorage)]
pub struct New;
#[derive(Default, Component, Debug, Clone)]
diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs
index 42eccff..c4b70a5 100644
--- a/src/componentwrapper.rs
+++ b/src/componentwrapper.rs
@@ -1,5 +1,5 @@
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
use specs::Builder;
use rand::Rng;
@@ -10,10 +10,13 @@ use crate::{
playerstate::RoomPos,
components::{
AttackType,
- Clan
+ Clan,
+ Flag
},
parameter::{Parameter, ParameterType},
- Timestamp
+ Timestamp,
+ Result,
+ aerr
};
@@ -33,16 +36,17 @@ macro_rules! components {
)*
}
}
- pub fn load_component(comptype: ComponentType, mut parameters: HashMap<&str, Parameter>) -> Option<Self> {
+ pub fn load_component(comptype: ComponentType, mut parameters: HashMap<&str, Parameter>) -> Result<Self> {
#[allow(unused_imports, unreachable_code)]
match comptype {
$(
- ComponentType::$comp => Some(Self::$comp({
+ ComponentType::$comp => Ok(Self::$comp({
use crate::components::$comp;
$(
- let $paramname = match parameters.remove(stringify!($paramname))? {
+ let $paramname = match parameters.remove(stringify!($paramname))
+ .ok_or(aerr!(&format!("required parameter '{}'not found", stringify!($paramname))))? {
Parameter::$paramtype(p) => p,
- _ => {return None}
+ x => Err(aerr!(&format!("parameter type mismatch for parameter {}: {} {:?}", stringify!($paramname), stringify!($paramtype), x)))?
};
)*
$creation
@@ -137,8 +141,6 @@ components!(
}
};
Movable (cooldown: Int);
- Blocking;
- Floor;
Player (name: String) {Player::new(PlayerId{name})};
Item (ent: Template, name: String, action: Action);
Inventory () {panic!("inventory from parameters not implemented")};
@@ -178,8 +180,8 @@ components!(
};
Clan (name: String);
Home (home: Pos);
- Faction (faction: String) {Faction::from_str(faction.as_str())?};
- Interactable (action: String) {Interactable::from_str(action.as_str())?};
+ 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"))?};
Loot (loot: LootList);
Grow (
into: Template (Grow.into.clone()),
@@ -200,6 +202,14 @@ components!(
};
Equipment () {panic!("equipment from parameters not implemented")};
CreationTime (time: Int) {CreationTime{time: Timestamp(time)}};
+ Flags (flags: Strings) {
+ Flags(
+ flags
+ .iter()
+ .map(|f| Flag::from_str(f))
+ .collect::<Option<HashSet<Flag>>>().ok_or(aerr!("invalid flag name"))?
+ )
+ };
);
diff --git a/src/parameter.rs b/src/parameter.rs
index 829c5cf..2ac9be1 100644
--- a/src/parameter.rs
+++ b/src/parameter.rs
@@ -68,13 +68,18 @@ 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)?) (v.to_json());
+ Action (ItemAction) action, v (ItemAction::from_json(v)?) (panic!("item actions 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|
Some((Template::from_json(item.get(0)?).ok()?, item.get(1)?.as_f64()?))
).collect::<Option<Vec<(Template, f64)>>>()?)
({json!(v.iter().map(|(t, c)| (t.to_json(), *c)).collect::<Vec<(Value, f64)>>())});
+ Strings (Vec<String>) strings, v
+ (v.as_array()?.iter().map(|item|
+ Some(item.as_str()?.to_string())
+ ).collect::<Option<Vec<String>>>()?)
+ ({json!(v)});
);
diff --git a/src/resources/ground.rs b/src/resources/ground.rs
index a5f4c00..8194a44 100644
--- a/src/resources/ground.rs
+++ b/src/resources/ground.rs
@@ -8,7 +8,7 @@ use specs::{
};
use crate::{
- components::{Visible, Removed},
+ components::{Visible, Removed, Flags, Flag},
Pos
};
@@ -28,6 +28,15 @@ impl Ground {
.collect()
}
+ pub fn all_components_on<'a, C: Component>(&self, pos: Pos, component_type: &'a ReadStorage<C>) -> Vec<&'a C> {
+ self.cells
+ .get(&pos)
+ .unwrap_or(&HashSet::new())
+ .iter()
+ .filter_map(|e| component_type.get(*e))
+ .collect()
+ }
+
pub fn by_height(&self, pos: &Pos, visibles: &ReadStorage<Visible>, ignore: &Entity) -> Vec<Entity> {
let mut entities: Vec<Entity> = self.cells
.get(&pos).unwrap_or(&HashSet::new())
@@ -41,4 +50,7 @@ impl Ground {
entities
}
+ pub fn flags_on<'a>(&self, pos: Pos, flags: &'a ReadStorage<Flags>) -> HashSet<Flag> {
+ self.all_components_on::<Flags>(pos, flags).into_iter().fold(HashSet::new(), |a, b| &a | &b.0)
+ }
}
diff --git a/src/room.rs b/src/room.rs
index 805f94e..6c92e8c 100644
--- a/src/room.rs
+++ b/src/room.rs
@@ -122,7 +122,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, Loot, Grow, Equipment, CreationTime),
+ (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, Grow, Equipment, CreationTime, Flags),
(Ground, Input, Output, Size, Spawn, Players, Emigration, Time)
);
diff --git a/src/systems/moving.rs b/src/systems/moving.rs
index 5232076..6ecf040 100644
--- a/src/systems/moving.rs
+++ b/src/systems/moving.rs
@@ -15,9 +15,9 @@ use crate::{
Pos,
components::{
Controller,
- Blocking,
Position,
- Floor,
+ Flags,
+ Flag,
Moved,
Entered,
Movable,
@@ -40,34 +40,23 @@ impl <'a> System<'a> for Move {
ReadStorage<'a, Controller>,
WriteStorage<'a, Position>,
Read<'a, Size>,
- ReadStorage<'a, Blocking>,
+ ReadStorage<'a, Flags>,
Write<'a, Ground>,
- ReadStorage<'a, Floor>,
WriteStorage<'a, Moved>,
WriteStorage<'a, Entered>,
ReadStorage<'a, Movable>,
WriteStorage<'a, ControlCooldown>
);
- fn run(&mut self, (entities, controllers, mut positions, size, blocking, mut ground, floor, mut moved, mut entered, movables, mut cooldowns): Self::SystemData) {
+ fn run(&mut self, (entities, controllers, mut positions, size, flags, mut ground, mut moved, mut entered, movables, mut cooldowns): Self::SystemData) {
moved.clear();
entered.clear();
for (ent, controller, mut pos, movable) in (&entities, &controllers, &mut positions.restrict_mut(), &movables).join(){
match &controller.control {
Control::Move(direction) => {
let newpos = (pos.get_unchecked().pos + direction.to_position()).clamp(Pos::new(0, 0), Pos::new(size.width - 1, size.height - 1));
- let mut blocked = false;
- let mut on_floor = false;
- for ent in ground.cells.get(&newpos).unwrap_or(&HashSet::new()) {
- if blocking.get(*ent).is_some(){
- blocked = true;
- break;
- }
- if floor.get(*ent).is_some(){
- on_floor = true;
- }
- }
- if !blocked && on_floor {
+ let ground_flags = ground.flags_on(newpos, &flags);
+ if !ground_flags.contains(&Flag::Blocking) && ground_flags.contains(&Flag::Floor) {
let mut pos_mut = pos.get_mut_unchecked();
moved.insert(ent, Moved{from: pos_mut.pos}).expect("can't insert Moved");
ground.cells.get_mut(&pos_mut.pos).unwrap().remove(&ent);
diff --git a/src/systems/useitem.rs b/src/systems/useitem.rs
index de9ed29..d96f6ef 100644
--- a/src/systems/useitem.rs
+++ b/src/systems/useitem.rs
@@ -6,7 +6,8 @@ use specs::{
WriteStorage,
System,
Join,
- Write
+ Write,
+ Read
};
use crate::{
@@ -16,9 +17,10 @@ use crate::{
Inventory,
AttackInbox,
AttackMessage,
- AttackType
+ AttackType,
+ Flags
},
- resources::{NewEntities},
+ resources::{NewEntities, Ground},
components::item::ItemAction::{None, Build, Eat, Equip},
controls::Control,
};
@@ -32,18 +34,23 @@ impl <'a> System<'a> for Use {
ReadStorage<'a, Position>,
WriteStorage<'a, Inventory>,
Write<'a, NewEntities>,
- WriteStorage<'a, AttackInbox>
+ WriteStorage<'a, AttackInbox>,
+ Read<'a, Ground>,
+ ReadStorage<'a, Flags>
);
- fn run(&mut self, (entities, controllers, positions, mut inventories, mut new, mut attacked): Self::SystemData) {
+ fn run(&mut self, (entities, controllers, positions, mut inventories, mut new, mut attacked, ground, flags): Self::SystemData) {
for (ent, controller, position, inventory) in (&entities, &controllers, &positions, &mut inventories).join(){
match &controller.control {
Control::Use(rank) => {
if let Some(entry) = inventory.items.get_mut(*rank) {
match &entry.0.action {
- Build(template) => {
- new.create(position.pos, template.clone()).unwrap();
- inventory.items.remove(*rank);
+ 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();
+ inventory.items.remove(*rank);
+ }
}
Eat(health_diff) => {
AttackInbox::add_message(&mut attacked, ent, AttackMessage{typ: AttackType::Heal(*health_diff), attacker: Option::None});
diff --git a/src/world.rs b/src/world.rs
index 50a3a4b..cdcbff1 100644
--- a/src/world.rs
+++ b/src/world.rs
@@ -180,7 +180,7 @@ impl <'a, 'b>World<'a, 'b> {
} else {
let age = *self.room_age.get(&roomid).unwrap_or(&0) + 1;
self.room_age.insert(roomid.clone(), age);
- if age > 2 {
+ if age > 10 {
to_remove.push(roomid.clone());
}
}
diff --git a/todo.md b/todo.md
index ec698be..ee36f49 100644
--- a/todo.md
+++ b/todo.md
@@ -2,6 +2,7 @@
# TODO
- make readme
+- more tests
- timer resource?
- log world events to player
- draw new entities