summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortroido <troido@protonmail.com>2020-03-03 13:36:44 +0100
committertroido <troido@protonmail.com>2020-03-03 13:36:44 +0100
commitb2157791dfcaab18ec7f8ebb958341fe325cf419 (patch)
treef94e638573878599b0ee108a0b06fbe1c8f69ef9 /src
parenta8d0e075613cc973b66c37510103108362fe7d3d (diff)
added spawners an not-saved assemblages/templates
Diffstat (limited to 'src')
-rw-r--r--src/assemblage.rs14
-rw-r--r--src/components/mod.rs15
-rw-r--r--src/componentwrapper.rs43
-rw-r--r--src/defaultencyclopedia.rs14
-rw-r--r--src/room.rs18
-rw-r--r--src/systems/mod.rs4
-rw-r--r--src/systems/spawn.rs50
-rw-r--r--src/template.rs3
-rw-r--r--src/worldloader.rs1
9 files changed, 125 insertions, 37 deletions
diff --git a/src/assemblage.rs b/src/assemblage.rs
index 71142f1..65c9bfa 100644
--- a/src/assemblage.rs
+++ b/src/assemblage.rs
@@ -15,7 +15,8 @@ type ArgumentDef = (String, ParameterType, Option<Parameter>);
#[derive(Debug, PartialEq, Clone)]
pub struct Assemblage {
pub arguments: Vec<ArgumentDef>,
- pub components: Vec<(ComponentType, HashMap<String, ComponentParameter>)>
+ pub components: Vec<(ComponentType, HashMap<String, ComponentParameter>)>,
+ pub save: bool
}
impl Assemblage {
@@ -74,7 +75,8 @@ impl Assemblage {
pub fn from_json(val: &Value) -> Result<Self, &'static str>{
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").ok_or("property 'components' not found")?)?,
+ 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
if let Some(spritename) = val.get("sprite") {
@@ -134,7 +136,7 @@ impl Assemblage {
}
components.push(ComponentWrapper::load_component(*comptype, compargs).ok_or("failed to load component")?);
}
- if template.save {
+ if template.save && self.save {
components.push(ComponentWrapper::Serialise(Serialise{template: template.clone()}));
}
Ok(components)
@@ -184,7 +186,8 @@ mod tests {
"sprite".to_string() => ComponentParameter::Argument("sprite".to_string()),
"height".to_string() => ComponentParameter::Constant(Parameter::Float(0.1))
))
- ]
+ ],
+ save: true
};
assert_eq!(result, constructed);
}
@@ -294,7 +297,8 @@ mod tests {
"sprite".to_string() => ComponentParameter::Argument("sprite".to_string()),
"height".to_string() => ComponentParameter::Constant(Parameter::Float(0.1))
))
- ]
+ ],
+ save: true
};
assert_eq!(result, constructed);
}
diff --git a/src/components/mod.rs b/src/components/mod.rs
index 8c0e6c6..8777d37 100644
--- a/src/components/mod.rs
+++ b/src/components/mod.rs
@@ -197,5 +197,20 @@ pub struct Home {
#[derive(Component, Debug, Clone, Default)]
pub struct Mortal;
+#[derive(Component, Debug, Clone)]
+#[storage(HashMapStorage)]
+pub struct Spawner {
+ pub amount: usize,
+ pub delay: i64,
+ pub clan: Clan,
+ pub template: Template,
+ pub last_spawn: Timestamp
+}
+
+#[derive(Component, Debug, Clone, PartialEq, Eq, Hash)]
+#[storage(HashMapStorage)]
+pub struct Clan {
+ pub name: String,
+}
diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs
index c553f61..a03ab17 100644
--- a/src/componentwrapper.rs
+++ b/src/componentwrapper.rs
@@ -1,6 +1,7 @@
use std::collections::HashMap;
use specs::Builder;
+use rand::Rng;
use crate::{
PlayerId,
@@ -8,37 +9,22 @@ use crate::{
Sprite,
playerstate::RoomPos,
components::{
- Visible,
- Movable,
- Blocking,
- Player,
- Floor,
- Item,
- Inventory,
- Health,
- Serialise,
- RoomExit,
- Trap,
- Fighter,
- Healing,
- Volatile,
AttackMessage,
- Autofight,
- MonsterAI,
- Mortal
+ Clan
},
- parameter::{Parameter, ParameterType}
+ parameter::{Parameter, ParameterType},
+ Timestamp
};
macro_rules! components {
- ($($comp: ident ($($paramname: ident : $paramtype: ident),*) {$creation: expr});*;) => {
+ ($($comp: ident ($($paramname: ident : $paramtype: ident),*) $creation: expr);*;) => {
#[derive(Clone)]
pub enum ComponentWrapper{
$(
- $comp($comp),
+ $comp(crate::components::$comp),
)*
}
@@ -58,6 +44,7 @@ macro_rules! components {
$(
ComponentType::$comp => Some(Self::$comp({
+ use crate::components::$comp;
$(
let $paramname = match parameters.remove(stringify!($paramname))? {
Parameter::$paramtype(p) => p,
@@ -140,6 +127,22 @@ components!(
Autofight () {Autofight::default()};
MonsterAI (move_chance: Float, homesickness: Float, view_distance: Int) {MonsterAI{move_chance, homesickness, view_distance}};
Mortal () {Mortal};
+ Spawner (amount: Int, delay: Int, clan: String, template: Template) {
+ Spawner{
+ amount: amount as usize,
+ delay,
+ clan: Clan{name:
+ if clan == "" {
+ format!("$random({})", rand::thread_rng().gen::<u32>())
+ } else {
+ clan
+ }
+ },
+ template,
+ last_spawn: Timestamp(0)
+ }
+ };
+ Clan (name: String) Clan{name};
);
diff --git a/src/defaultencyclopedia.rs b/src/defaultencyclopedia.rs
index 252174d..b6ab6cc 100644
--- a/src/defaultencyclopedia.rs
+++ b/src/defaultencyclopedia.rs
@@ -145,7 +145,8 @@ pub fn default_encyclopedia() -> Encyclopedia {
"wound": {
"sprite": "wound",
"height": 0.25,
- "components": [["Volatile", {"delay": ["int", 4]}]]
+ "components": [["Volatile", {"delay": ["int", 4]}]],
+ "save": false
},
"rat": {
"sprite": "rat",
@@ -161,6 +162,17 @@ pub fn default_encyclopedia() -> Encyclopedia {
["Movable", {"cooldown": ["int", 3]}],
"Mortal"
]
+ },
+ "spawner": {
+ "arguments": [["template", "template", null], ["amount", "int", 1], ["delay", "int", 0], ["clan", "string", ""]],
+ "components": [
+ ["Spawner", {
+ "template": ["arg", "template"],
+ "amount": ["arg", "amount"],
+ "delay": ["arg", "delay"],
+ "clan": ["arg", "clan"]
+ }]
+ ]
}
})).unwrap()
}
diff --git a/src/room.rs b/src/room.rs
index 52621ac..f3cdbf8 100644
--- a/src/room.rs
+++ b/src/room.rs
@@ -19,7 +19,7 @@ use crate::{
Output,
Input,
NewEntities,
- Spawn,
+ Spawn as SpawnPosition,
Players,
Emigration,
TimeStamp
@@ -61,7 +61,8 @@ use crate::{
Volate,
UpdateCooldowns,
ControlAI,
- Die
+ Die,
+ Spawn
}
};
@@ -70,6 +71,7 @@ pub fn default_dispatcher<'a, 'b>() -> Dispatcher<'a, 'b> {
.with(Volate, "volate", &[])
.with(RegisterNew::default(), "registernew", &[])
.with(UpdateCooldowns, "cool_down", &["registernew"])
+ .with(Spawn, "spawn", &["registernew"])
.with(ControlInput, "controlinput", &["cool_down"])
.with(ControlAI, "controlai", &["cool_down"])
.with(Take, "take", &["controlinput", "controlai"])
@@ -82,7 +84,7 @@ pub fn default_dispatcher<'a, 'b>() -> Dispatcher<'a, 'b> {
.with(Die, "die", &["attacking"])
.with(View::default(), "view", &["move", "attacking", "volate", "die"])
.with(Migrate, "migrate", &["view"])
- .with(Create, "create", &["view"])
+ .with(Create, "create", &["view", "spawn"])
.with(Remove, "remove", &["view", "move"])
.build()
}
@@ -113,7 +115,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),
+ (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),
(Ground, Input, Output, Size, Spawn, Players, Emigration, TimeStamp)
);
@@ -131,14 +133,14 @@ impl <'a, 'b>Room<'a, 'b> {
self.world.fetch_mut::<Size>().width = width;
self.world.fetch_mut::<Size>().height = height;
- self.world.fetch_mut::<Spawn>().pos = template.spawn;
+ self.world.fetch_mut::<SpawnPosition>().pos = template.spawn;
for (idx, templates) in template.field.iter().enumerate() {
let x = (idx as i64) % width;
let y = (idx as i64) / width;
for template in templates {
- let _ = self.create_entity(template.clone().unsaved(), Pos{x, y});
+ self.create_entity(template.clone().unsaved(), Pos{x, y}).unwrap();
}
}
for (name, place) in &template.places {
@@ -171,7 +173,7 @@ impl <'a, 'b>Room<'a, 'b> {
pub fn add_player(&mut self, state: &PlayerState){
let pre_player = state.construct(&self.world.fetch::<NewEntities>().encyclopedia);
let spawn = match &state.pos {
- RoomPos::Unknown => self.world.fetch::<Spawn>().pos,
+ RoomPos::Unknown => self.world.fetch::<SpawnPosition>().pos,
RoomPos::Pos(pos) => *pos,
RoomPos::Name(name) => *self.places.get(name).unwrap()
};
@@ -205,7 +207,7 @@ impl <'a, 'b>Room<'a, 'b> {
pub fn load_saved(&mut self, state: &SaveState) {
for (pos, templates) in state.changes.iter() {
for template in templates {
- let _ = self.create_entity(template.clone(), *pos);
+ self.create_entity(template.clone(), *pos).unwrap();
}
}
}
diff --git a/src/systems/mod.rs b/src/systems/mod.rs
index f4b3edb..37afcd0 100644
--- a/src/systems/mod.rs
+++ b/src/systems/mod.rs
@@ -16,6 +16,7 @@ mod volate;
mod updatecooldowns;
mod controlai;
mod die;
+mod spawn;
pub use self::{
controlinput::ControlInput,
@@ -34,5 +35,6 @@ pub use self::{
volate::Volate,
updatecooldowns::UpdateCooldowns,
controlai::ControlAI,
- die::Die
+ die::Die,
+ spawn::Spawn
};
diff --git a/src/systems/spawn.rs b/src/systems/spawn.rs
new file mode 100644
index 0000000..6bb4912
--- /dev/null
+++ b/src/systems/spawn.rs
@@ -0,0 +1,50 @@
+
+use std::collections::HashMap;
+
+use specs::{
+ WriteStorage,
+ ReadStorage,
+ Write,
+ Read,
+ System,
+ Join
+};
+
+use crate::{
+ components::{
+ Position,
+ Spawner,
+ Clan
+ },
+ resources::{NewEntities, TimeStamp},
+ componentwrapper::ComponentWrapper
+};
+
+
+
+pub struct Spawn;
+impl <'a> System<'a> for Spawn {
+ type SystemData = (
+ ReadStorage<'a, Position>,
+ Write<'a, NewEntities>,
+ WriteStorage<'a, Spawner>,
+ ReadStorage<'a, Clan>,
+ Read<'a, TimeStamp>
+ );
+
+ fn run(&mut self, (positions, mut new, mut spawners, clans, time): Self::SystemData) {
+ let mut clan_nums: HashMap<&Clan, usize> = HashMap::new();
+ for clan in (&clans).join() {
+ let n: usize = *clan_nums.entry(clan).or_insert(0);
+ clan_nums.insert(clan, n+1);
+ }
+ for (spawner, position) in (&mut spawners, &positions).join() {
+ if time.time > spawner.last_spawn + spawner.delay && *clan_nums.get(&spawner.clan).unwrap_or(&0) < spawner.amount {
+ spawner.last_spawn = time.time;
+ let mut preent = new.encyclopedia.construct(&spawner.template).expect("unable to spawn entity from spawner");
+ preent.push(ComponentWrapper::Clan(spawner.clan.clone()));
+ new.to_build.push((position.pos, preent));
+ }
+ }
+ }
+}
diff --git a/src/template.rs b/src/template.rs
index 5539f94..cf0fee2 100644
--- a/src/template.rs
+++ b/src/template.rs
@@ -53,7 +53,8 @@ impl Template {
for (key, arg) in val.get("kwargs").unwrap_or(&json!({})).as_object().ok_or(aerr!("template kwargs not a json object"))? {
kwargs.insert(key.to_string(), Parameter::guess_from_json(arg).ok_or(aerr!("template arg not a parameter"))?);
}
- Ok(Template {name, args, kwargs, save: true})
+ let save = val.get("save").unwrap_or(&json!(true)).as_bool().ok_or(aerr!("save not a bool"))?;
+ Ok(Template {name, args, kwargs, save})
}
pub fn to_json(&self) -> Value {
diff --git a/src/worldloader.rs b/src/worldloader.rs
index afaabb7..d8a7c0f 100644
--- a/src/worldloader.rs
+++ b/src/worldloader.rs
@@ -25,7 +25,6 @@ impl WorldLoader {
let mut path = self.directory.clone();
let fname = id.to_string() + ".json";
path.push(fname);
- println!("PATH: {:?}", path);
let text = fs::read_to_string(path)?;
let json: Value = serde_json::from_str(&text)?;
let template = RoomTemplate::from_json(&json)?;