From 1b380b31f50035f10f651e220effe8a2970c0fd5 Mon Sep 17 00:00:00 2001 From: troido Date: Tue, 12 May 2020 21:51:37 +0200 Subject: removed 'substitute' part of encyclopedia --- content/encyclopediae/default_encyclopedia.json | 7 +-- content/maps/room.json | 17 +++--- src/assemblage.rs | 5 +- src/components/mod.rs | 12 +++++ src/componentwrapper.rs | 6 +++ src/encyclopedia.rs | 70 ++----------------------- src/parameter.rs | 2 +- src/playerstate.rs | 5 +- src/room.rs | 10 ++-- src/systems/mod.rs | 6 ++- src/systems/replace.rs | 46 ++++++++++++++++ src/systems/spawntrigger.rs | 34 ++++++++++++ src/template.rs | 14 ++++- todo.md | 2 +- 14 files changed, 148 insertions(+), 88 deletions(-) create mode 100644 src/systems/replace.rs create mode 100644 src/systems/spawntrigger.rs diff --git a/content/encyclopediae/default_encyclopedia.json b/content/encyclopediae/default_encyclopedia.json index 204b104..2571997 100644 --- a/content/encyclopediae/default_encyclopedia.json +++ b/content/encyclopediae/default_encyclopedia.json @@ -424,6 +424,9 @@ ["list", [{"type": "stone"}, 1.0]] ]]}] ] + }, + "radishes": { + "substitute": "radish" } }, "items": { @@ -431,6 +434,7 @@ "stone": {"action": ["build", ["builtwall", ["Floor"], ["Blocking"]]]}, "radishseed": {"sprite": "seed", "action": ["build", ["plantedradishseed", ["Floor", "Soil"], ["Occupied", "Blocking"]]]}, "radish": {"sprite": "food", "action": ["eat", 3]}, + "radishes": {"sprite": "food", "name": "radish", "entity": "radish", "action": ["eat", 3]}, "eldritch_radish": {"sprite": "food", "name": "eldritch_radish", "action": ["eat", 20]}, "carrotseed": {"sprite": "seed", "action": ["build", ["plantedcarrotseed", ["Floor", "Soil"], ["Occupied", "Blocking"]]]}, "carrot": {"sprite": "food", "action": ["eat", 5]}, @@ -466,8 +470,5 @@ "plantedcarrotseed": ["plantedseed", {"delay": 60, "next": "carrotseedling"}], "carrotseedling": ["seedling", {"delay": 60, "next": "youngcarrotplant"}], "youngcarrotplant": ["youngplant", {"crop": "carrot", "delay": 60, "next": "carrotplant"}] - }, - "substitute": { - "radishes": "radish" } } diff --git a/content/maps/room.json b/content/maps/room.json index 853e7a3..f89b46a 100644 --- a/content/maps/room.json +++ b/content/maps/room.json @@ -16,14 +16,14 @@ " X,^,,,.,,,,,,,,,,,,~~~,,,,,T,,,,######,,,X", " X,^,,,.,,,,,,,,,,,,bbb,,,,,,,,,,#++++#,,,X", " X,,,t..............bbb..........D++++#,,,X", - " X,**,,.,,,,,,,,,,,,bbb,,,,,,,,,,#++++#,,,X", - " X,*,*,.,u,,,V,,V,,,~~~,,,T,,,T,,#++++#,,,X", - " X,,*,,.,,,,,,,,,,,,~~~,,,,,,,,,,######,,,X", - " X,oo,,.,s,d,,,,,,,~~~~,,,,,,,,,,f,,,,f,,,X", - " X,,*,,.,,,,,,,,,,,~~~''''''''''''''''f'''X", - " X*,,,,.,,,d,VVV,,,~~~'''''''''''f''''f'''X", - "1.......,,,,,VVV,,,~~~'''''''''''ffffff'''X", - " X/,,,,.,P,Q,VVV,,,~~~''''''''''''''''''''X", + " X,,,,,.,,,,,,,,,,,,bbb,,,,,,,,,,#++++#,,,X", + " X,,,,,.,,,,,,,,,,,,~~~,,,T,,,T,,#++++#,,,X", + " X,,,,,.,,,,,,,,,,,,~~~,,,,,,,,,,######,,,X", + " X,,,,,.,s,d,,,,,,,~~~~,,,,,,,,,,f,,,,f,,,X", + " X,,,,,.,,,,,,,,,,,~~~''''''''''''''''f'''X", + " X,,,,,.,,,d,,,,,,,~~~'''''''''''f''''f'''X", + "1.......,,,,,,,,,,,~~~'''''''''''ffffff'''X", + " X,,,,,.,,,Q,,,,,,,~~~''''''''''''''''''''X", " XXXXX,.,XXXXXXXXXX~~~XXXXXXXXXXXXXXXXXXXXX", " %%% " ], @@ -52,6 +52,7 @@ "u": ["ground", "dude"], "t": ["ground", "trader"], "P": ["ground", "pickaxe"], + "u": ["ground", "radishes"], "Q": "quarry", " ": [] } diff --git a/src/assemblage.rs b/src/assemblage.rs index 2ef62f0..96e44e9 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -58,7 +58,7 @@ impl Assemblage { .as_str().ok_or(perr!("component name not a string"))?; let comptype = ComponentType::from_str(name).ok_or(perr!("{} not a valid componenttype", name))?; let mut parameters: HashMap = HashMap::new(); - for (key, value) in tup.get(1).ok_or(perr!("index 1 not in component"))?.as_object().ok_or(perr!("component parameters not a json object"))? { + for (key, value) in tup.get(1).ok_or(perr!("index 1 not in component"))?.as_object().ok_or(perr!("component parameters not a json object: {:?}", tup.get(1)))? { let param = ComponentParameter::from_json(value)?; parameters.insert(key.clone(), param); } @@ -100,6 +100,9 @@ impl Assemblage { }])); } + if let Some(substitute) = val.get("substitute") { + components.push(json!(["Substitute", {"into": ["template", substitute]}])); + } Ok(components) } diff --git a/src/components/mod.rs b/src/components/mod.rs index 394284a..ee5176e 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -253,3 +253,15 @@ pub struct Minable { pub total: i64, pub trigger: Trigger } + +#[derive(Component, Debug, Clone)] +pub struct OnSpawn { + pub trigger: Trigger +} + + +#[derive(Component, Debug, Clone)] +pub struct Substitute { + pub into: Template +} + diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index 392c0dc..ee2f22f 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -293,6 +293,12 @@ components!(all: }; Removed; LootHolder () {panic!("LootHolder from parameters not implemented")}; + OnSpawn (trigger: String) { + OnSpawn { + trigger: Trigger::from_str(&trigger).ok_or(aerr!("invalid trigger name {}", trigger))? + } + }; + Substitute (into: Template); ); diff --git a/src/encyclopedia.rs b/src/encyclopedia.rs index ba9ad94..54fa82b 100644 --- a/src/encyclopedia.rs +++ b/src/encyclopedia.rs @@ -19,9 +19,7 @@ use crate::{ #[derive(Default, Clone)] pub struct Encyclopedia { assemblages: HashMap, - items: HashMap, - assemblage_substitute: HashMap, - item_substitute: HashMap, + items: HashMap } impl Encyclopedia { @@ -93,7 +91,7 @@ impl Encyclopedia { .as_str().ok_or(perr!("subtitution origin name not a string"))? .to_string()); let values = v.get(1).ok_or(perr!("index 0 not in subtitution template"))?; - let mut assemblage = assemblages.get(&enttype).ok_or(perr!("template name '{:?}' points not an assemblage", enttype))?.clone(); + let mut assemblage = assemblages.get(&enttype).ok_or(perr!("template name '{:?}' does not point to not an assemblage", enttype))?.clone(); for arg in assemblage.arguments.iter_mut() { if let Some(x) = values.get(&arg.0) { let param = Parameter::from_typed_json(arg.1, x).ok_or(perr!("subtitution parameter has wrong type"))?; @@ -103,51 +101,11 @@ impl Encyclopedia { assemblages.insert(EntityType(name.to_string()), assemblage); } - let assemblage_substitute = val - .get("assemblage_substitute") - .unwrap_or(&json!({})) - .as_object().ok_or(perr!("assemblage_subtitute not a json dict"))? - .iter() - .chain( - val - .get("substitute") - .unwrap_or(&json!({})) - .as_object().ok_or(perr!("substitute not a json dict"))? - .iter() - ) - .map(|(from, into)| { - Ok(( - EntityType(from.to_string()), - EntityType(into.as_str().ok_or(perr!("substitution value not a string: {:?}", into))?.to_string()) - )) - }) - .collect::>>()?; - - let item_substitute = val - .get("item_substitute") - .unwrap_or(&json!({})) - .as_object().ok_or(perr!("item_subtitute not a json dict"))? - .iter() - .chain( - val - .get("substitute") - .unwrap_or(&json!({})) - .as_object().ok_or(perr!("substitute not a json dict"))? - .iter() - ) - .map(|(from, into)| { - Ok(( - ItemId(from.to_string()), - ItemId(into.as_str().ok_or(perr!("substitution value not a string: {:?}", into))?.to_string()) - )) - }) - .collect::>>()?; Ok(Encyclopedia{ assemblages, - items, - assemblage_substitute, - item_substitute + items }) + } pub fn validate(&self) -> Result<()> { @@ -158,11 +116,6 @@ impl Encyclopedia { } pub fn construct(&self, template: &Template) -> Result { - if let Some(new_name) = self.assemblage_substitute.get(&template.name){ - let mut into = template.clone(); - into.name = new_name.clone(); - return self.construct(&into); - } let assemblage = self.assemblages .get(&template.name) .ok_or(aerr!("unknown assemblage name: '{:?}' in {:?}", template.name, template))?; @@ -170,20 +123,7 @@ impl Encyclopedia { } pub fn get_item(&self, id: &ItemId) -> Option { - let actual_id = if let Some(into) = self.item_substitute.get(id) { - into - } else { - id - }; - self.items.get(actual_id).map(|item| item.clone()) - } - - pub fn substitute_item(&self, id: &ItemId) -> ItemId { - if let Some(into) = self.item_substitute.get(id) { - into.clone() - } else { - id.clone() - } + self.items.get(id).map(|item| item.clone()) } } diff --git a/src/parameter.rs b/src/parameter.rs index 196f5fe..01a7f40 100644 --- a/src/parameter.rs +++ b/src/parameter.rs @@ -67,7 +67,7 @@ parameters!( Int (i64) int, v (v.as_i64()?) (json!(v)); 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()); + Template (Template) template, v (Template::from_json(v).ok()?) (json!(["template", v.to_json()])); 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) list, v diff --git a/src/playerstate.rs b/src/playerstate.rs index 778fc7f..f9f6a4e 100644 --- a/src/playerstate.rs +++ b/src/playerstate.rs @@ -164,9 +164,8 @@ impl PlayerState { ComponentWrapper::Player(Player::new(self.id.clone())), ComponentWrapper::Inventory(Inventory{ items: self.inventory.iter().map( |(itemid, is_equipped)| { - let id = encyclopedia.substitute_item(itemid); - let item = encyclopedia.get_item(&id).ok_or(aerr!("failed to load item '{:?} in inventory of player {:?}", itemid, self))?; - Ok(InventoryEntry{itemid: id, item, is_equipped: *is_equipped}) + let item = encyclopedia.get_item(&itemid).ok_or(aerr!("failed to load item '{:?} in inventory of player {:?}", itemid, self))?; + Ok(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 9583a93..d0f22df 100644 --- a/src/room.rs +++ b/src/room.rs @@ -67,13 +67,16 @@ use crate::{ Timeout, Clear, Building, - Deduplicate + Deduplicate, + SpawnTrigger, + Replace } }; pub fn default_dispatcher<'a, 'b>() -> Dispatcher<'a, 'b> { DispatcherBuilder::new() .with(Deduplicate, "deduplicate", &[]) + .with(Replace, "replace", &[]) .with(Timeout, "timeout", &[]) .with(UpdateCooldowns, "cool_down", &[]) .with(Spawn, "spawn", &[]) @@ -82,11 +85,12 @@ pub fn default_dispatcher<'a, 'b>() -> Dispatcher<'a, 'b> { .with(Take, "take", &["controlinput", "controlai"]) .with(Use, "use", &["controlinput", "controlai"]) .with(Interact, "interact", &["controlinput", "controlai"]) + .with(SpawnTrigger, "spawntrigger", &["spawn", "deduplicate", "replace"]) .with(Move, "move", &["controlinput", "controlai"]) .with(Trapping, "trapping", &["move"]) .with(Fight, "fight", &["move"]) .with(Heal, "heal", &[]) - .with(Attacking, "attacking", &["use", "trapping", "fight", "heal", "interact"]) + .with(Attacking, "attacking", &["use", "trapping", "fight", "heal", "interact", "spawntrigger"]) .with(Die, "die", &["attacking"]) .with(DropLoot, "droploot", &["attacking"]) .with(Building, "building", &["attacking"]) @@ -120,7 +124,7 @@ impl <'a, 'b>Room<'a, 'b> { world.insert(NewEntities::new(encyclopedia)); register_insert!( world, - (Position, Visible, Controller, Movable, New, Removed, Moved, Player, Inventory, Health, Serialise, RoomExit, Entered, TriggerBox, Trap, Fighter, Healing, ControlCooldown, Autofight, MonsterAI, Home, AttackInbox, Item, Spawner, Clan, Faction, Interactable, Loot, Timer, Equipment, TimeOffset, Flags, Ear, Build, Whitelist, Dedup, Minable, LootHolder), + (Position, Visible, Controller, Movable, New, Removed, Moved, Player, Inventory, Health, Serialise, RoomExit, Entered, TriggerBox, Trap, Fighter, Healing, ControlCooldown, Autofight, MonsterAI, Home, AttackInbox, Item, Spawner, Clan, Faction, Interactable, Loot, Timer, Equipment, TimeOffset, Flags, Ear, Build, Whitelist, Dedup, Minable, LootHolder, OnSpawn, Substitute), (Ground, Input, Output, Size, Spawn, Players, Emigration, Time) ); diff --git a/src/systems/mod.rs b/src/systems/mod.rs index 024f54f..7323dee 100644 --- a/src/systems/mod.rs +++ b/src/systems/mod.rs @@ -22,6 +22,8 @@ mod timeout; mod clear; mod building; mod deduplicate; +mod spawntrigger; +mod replace; pub use self::{ controlinput::ControlInput, @@ -46,5 +48,7 @@ pub use self::{ timeout::Timeout, clear::Clear, building::Building, - deduplicate::Deduplicate + deduplicate::Deduplicate, + spawntrigger::SpawnTrigger, + replace::Replace }; diff --git a/src/systems/replace.rs b/src/systems/replace.rs new file mode 100644 index 0000000..4ed516b --- /dev/null +++ b/src/systems/replace.rs @@ -0,0 +1,46 @@ + +use specs::{ + ReadStorage, + System, + Join, + Write, + WriteStorage, + Entities +}; + +use crate::{ + components::{ + Position, + Substitute, + Removed, + Serialise + }, + resources::{NewEntities} +}; + + +pub struct Replace; +impl <'a> System<'a> for Replace { + type SystemData = ( + Entities<'a>, + ReadStorage<'a, Position>, + Write<'a, NewEntities>, + ReadStorage<'a, Substitute>, + WriteStorage<'a, Removed>, + ReadStorage<'a, Serialise> + ); + + fn run(&mut self, (entities, positions, mut new, substitutes, mut removeds, serialisations): Self::SystemData) { + for (entity, position, substitute, serialisation) in (&entities, &positions, &substitutes, (&serialisations).maybe()).join(){ + // todo: better error handling + let mut template = substitute.into.clone(); + if let Some(serialise) = serialisation { + // todo: extraction? + template = template.merge(serialise.template.clone()); + } + let preent = new.encyclopedia.construct(&template).unwrap(); + new.to_build.push((position.pos, preent)); + removeds.insert(entity, Removed).unwrap(); + } + } +} diff --git a/src/systems/spawntrigger.rs b/src/systems/spawntrigger.rs new file mode 100644 index 0000000..95e95a8 --- /dev/null +++ b/src/systems/spawntrigger.rs @@ -0,0 +1,34 @@ + + +use specs::{ + WriteStorage, + ReadStorage, + Entities, + System, + Join +}; + +use crate::{ + components::{ + TriggerBox, + OnSpawn, + New + } +}; + + +pub struct SpawnTrigger; +impl <'a> System<'a> for SpawnTrigger { + type SystemData = ( + Entities<'a>, + WriteStorage<'a, TriggerBox>, + ReadStorage<'a, OnSpawn>, + ReadStorage<'a, New> + ); + + fn run(&mut self, (entities, mut triggerboxes, onspawns, news): Self::SystemData) { + for (entity, onspawn, _new) in (&entities, &onspawns, &news).join(){ + TriggerBox::add_message(&mut triggerboxes, entity, onspawn.trigger); + } + } +} diff --git a/src/template.rs b/src/template.rs index 6b2dec3..0ac03cd 100644 --- a/src/template.rs +++ b/src/template.rs @@ -12,7 +12,7 @@ use crate::{ pub struct EntityType(pub String); #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] -enum SaveOption { +pub enum SaveOption { Default, False, Always @@ -23,7 +23,7 @@ pub struct Template { pub name: EntityType, pub args: Vec, pub kwargs: HashMap, - save: SaveOption, + pub save: SaveOption, } @@ -65,6 +65,16 @@ impl Template { self } + pub fn merge(mut self, other: Template) -> Self { + if self.save == SaveOption::Default { + self.save = other.save; + } + for (key, value) in other.kwargs { + self.kwargs.entry(key).or_insert(value); + } + self + } + pub fn from_json(v: &Value) -> PResult