diff --git a/src/components.rs b/src/components.rs index d8143db..7bcce85 100644 --- a/src/components.rs +++ b/src/components.rs @@ -23,6 +23,13 @@ pub struct Position { pub y: i32, } +#[derive(Component, Serialize, Deserialize, Clone)] +pub struct OtherLevelPosition { + pub x: i32, + pub y: i32, + pub id: i32, +} + #[derive(Component, ConvertSaveload, Clone)] pub struct Renderable { pub glyph: rltk::FontCharType, diff --git a/src/main.rs b/src/main.rs index 36924af..b6c3df0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -85,6 +85,8 @@ impl State { let map_building_info = map::level_transition(&mut self.ecs, new_id, offset); if let Some(history) = map_building_info { self.mapgen_history = history; + } else { + map::dungeon::thaw_entities(&mut self.ecs); } } @@ -133,58 +135,9 @@ impl State { mapindex.run_now(&self.ecs); } - fn entities_to_remove_on_level_change(&mut self) -> Vec { - let entities = self.ecs.entities(); - let player = self.ecs.read_storage::(); - let clock = self.ecs.read_storage::(); - let backpack = self.ecs.read_storage::(); - let player_entity = self.ecs.fetch::(); - let equipped = self.ecs.read_storage::(); - - let mut to_delete: Vec = Vec::new(); - for entity in entities.join() { - let mut should_delete = true; - - // Don't delete the turn clock - let c = clock.get(entity); - if let Some(_c) = c { - should_delete = false; - } - - // Don't delete player - let p = player.get(entity); - if let Some(_p) = p { - should_delete = false; - } - - // Don't delete player's equipment - let bp = backpack.get(entity); - if let Some(bp) = bp { - if bp.owner == *player_entity { - should_delete = false; - } - } - let eq = equipped.get(entity); - if let Some(eq) = eq { - if eq.owner == *player_entity { - should_delete = false; - } - } - - if should_delete { - to_delete.push(entity); - } - } - - return to_delete; - } - fn goto_level(&mut self, offset: i32) { - // Delete entities that aren't player/player's equipment - let to_delete = self.entities_to_remove_on_level_change(); - for target in to_delete { - self.ecs.delete_entity(target).expect("Unable to delete entity"); - } + // Freeze the current level + map::dungeon::freeze_entities(&mut self.ecs); // Build new map + place player let current_id; @@ -511,6 +464,7 @@ fn main() -> rltk::BError { }; gs.ecs.register::(); + gs.ecs.register::(); gs.ecs.register::(); gs.ecs.register::(); gs.ecs.register::(); diff --git a/src/map/dungeon.rs b/src/map/dungeon.rs index fd3e6d5..8f2395c 100644 --- a/src/map/dungeon.rs +++ b/src/map/dungeon.rs @@ -1,5 +1,5 @@ use super::{Map, TileType}; -use crate::{gamelog, map_builders, Position, Telepath, Viewshed}; +use crate::{gamelog, map_builders, OtherLevelPosition, Position, Telepath, Viewshed}; use rltk::prelude::*; use serde::{Deserialize, Serialize}; use specs::prelude::*; @@ -131,3 +131,49 @@ fn transition_to_new_map(ecs: &mut World, new_id: i32) -> Vec { dungeon_master.store_map(&builder.build_data.map); return mapgen_history; } + +/// Iterate through entities on the current level, save the current position and floor +/// of each entity-to-be-frozen, and then delete their current position. +pub fn freeze_entities(ecs: &mut World) { + // Obtain reqs from ECS + let entities = ecs.entities(); + let mut positions = ecs.write_storage::(); + let mut other_positions = ecs.write_storage::(); + let player_entity = ecs.fetch::(); + let map_id = ecs.fetch::().id; + // Save Positions and mark for deletion + let mut pos_to_delete: Vec = Vec::new(); + for (entity, pos) in (&entities, &positions).join() { + if entity != *player_entity { + other_positions + .insert(entity, OtherLevelPosition { x: pos.x, y: pos.y, id: map_id }) + .expect("Failed to insert OtherLevelPosition"); + pos_to_delete.push(entity); + } + } + for p in pos_to_delete.iter() { + positions.remove(*p); + } +} + +/// Iterate through entities, and insert a Position component if the +/// entity has an OtherLevelPosition for the new map id. +pub fn thaw_entities(ecs: &mut World) { + // Obtain reqs from ECS + let entities = ecs.entities(); + let mut positions = ecs.write_storage::(); + let mut other_positions = ecs.write_storage::(); + let player_entity = ecs.fetch::(); + let map_id = ecs.fetch::().id; + // Save Positions and mark for deletion + let mut pos_to_delete: Vec = Vec::new(); + for (entity, pos) in (&entities, &other_positions).join() { + if entity != *player_entity && pos.id == map_id { + positions.insert(entity, Position { x: pos.x, y: pos.y }).expect("Failed to insert OtherLevelPosition"); + pos_to_delete.push(entity); + } + } + for p in pos_to_delete.iter() { + other_positions.remove(*p); + } +} diff --git a/src/saveload_system.rs b/src/saveload_system.rs index 672eb72..97b9aaf 100644 --- a/src/saveload_system.rs +++ b/src/saveload_system.rs @@ -79,6 +79,7 @@ pub fn save_game(ecs: &mut World) { MultiAttack, NaturalAttacks, Name, + OtherLevelPosition, ParticleLifetime, Player, Pools, @@ -186,6 +187,7 @@ pub fn load_game(ecs: &mut World) { MultiAttack, NaturalAttacks, Name, + OtherLevelPosition, ParticleLifetime, Player, Pools,