From da36acbade6dd33e74e8b2f01ae3ae8435a84388 Mon Sep 17 00:00:00 2001 From: Tyrel Souza <923113+tyrelsouza@users.noreply.github.com> Date: Tue, 31 Aug 2021 15:56:51 -0400 Subject: [PATCH] multiple levels --- src/components.rs | 4 +- src/main.rs | 78 +++++++++++++++++++++++++++++++++++---- src/map.rs | 5 ++- src/map_builder/themes.rs | 2 + src/spawners.rs | 2 +- src/systems/end_turn.rs | 9 ++++- src/systems/hud.rs | 16 +++++++- src/turn_state.rs | 1 + 8 files changed, 103 insertions(+), 14 deletions(-) diff --git a/src/components.rs b/src/components.rs index 2d39775..f060405 100644 --- a/src/components.rs +++ b/src/components.rs @@ -8,7 +8,9 @@ pub struct Render { } #[derive(Clone, Copy, Debug, PartialEq)] -pub struct Player; +pub struct Player { + pub map_level: u32, +} #[derive(Clone, Copy, Debug, PartialEq)] pub struct Enemy; diff --git a/src/main.rs b/src/main.rs index 53eac14..c9c9d25 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,8 +11,8 @@ mod prelude { pub use legion::systems::CommandBuffer; pub use legion::world::SubWorld; pub use legion::*; - pub const SCREEN_WIDTH: i32 = 80; - pub const SCREEN_HEIGHT: i32 = 50; + pub const SCREEN_WIDTH: i32 = 60; + pub const SCREEN_HEIGHT: i32 = 40; pub const DISPLAY_WIDTH: i32 = SCREEN_WIDTH / 2; pub const DISPLAY_HEIGHT: i32 = SCREEN_HEIGHT / 2; pub use crate::camera::*; @@ -33,21 +33,80 @@ struct State { monster_systems: Schedule, } impl State { + fn advance_level(&mut self) { + let player_entity = *::query() + .filter(component::()) + .iter(&mut self.ecs) + .nth(0) + .unwrap(); + use std::collections::HashSet; + let mut entities_to_keep = HashSet::new(); + entities_to_keep.insert(player_entity); + + <(Entity, &Carried)>::query() + .iter(&self.ecs) + .filter(|(_e, carry)| carry.0 == player_entity) + .map(|(e, _carry)| *e) + .for_each(|e| { + entities_to_keep.insert(e); + }); + let mut cb = CommandBuffer::new(&mut self.ecs); + for e in Entity::query().iter(&self.ecs) { + if !entities_to_keep.contains(e) { + cb.remove(*e); + } + } + cb.flush(&mut self.ecs); + + <&mut FieldOfView>::query() + .iter_mut(&mut self.ecs) + .for_each(|fov| fov.is_dirty = true); + + let mut rng = RandomNumberGenerator::new(); + let mut map_builder = MapBuilder::new(&mut rng); + let mut map_level = 0; + <(&mut Player, &mut Point)>::query() + .iter_mut(&mut self.ecs) + .for_each(|(player, pos)| { + player.map_level += 1; + map_level = player.map_level; + pos.x = map_builder.player_start.x; + pos.y = map_builder.player_start.y; + }); + if map_level == 2 { + spawn_amulet_of_yala(&mut self.ecs, map_builder.amulet_start); + } else { + let exit_idx = map_builder.map.point2d_to_index(map_builder.amulet_start); + map_builder.map.tiles[exit_idx] = TileType::Exit; + } + + map_builder + .monster_spawns + .iter() + .for_each(|pos| spawn_entity(&mut self.ecs, &mut rng, *pos)); + + self.resources.insert(map_builder.map); + self.resources.insert(Camera::new(map_builder.player_start)); + self.resources.insert(TurnState::AwaitingInput); + self.resources.insert(map_builder.theme); + } + fn new() -> Self { let mut ecs = World::default(); let mut resources = Resources::default(); let mut rng = RandomNumberGenerator::new(); - let map_builder = MapBuilder::new(&mut rng); - + let mut map_builder = MapBuilder::new(&mut rng); spawn_player(&mut ecs, map_builder.player_start); - spawn_amulet_of_yala(&mut ecs, map_builder.amulet_start); + //spawn_amulet_of_yala(&mut ecs, map_builder.amulet_start); + let exit_idx = map_builder.map.point2d_to_index(map_builder.amulet_start); + map_builder.map.tiles[exit_idx] = TileType::Exit; + map_builder .monster_spawns .iter() .for_each(|pos| spawn_entity(&mut ecs, &mut rng, *pos)); resources.insert(map_builder.map); resources.insert(Camera::new(map_builder.player_start)); - resources.insert(TurnState::AwaitingInput); resources.insert(map_builder.theme); State { @@ -89,9 +148,11 @@ impl State { self.ecs = World::default(); self.resources = Resources::default(); let mut rng = RandomNumberGenerator::new(); - let map_builder = MapBuilder::new(&mut rng); + let mut map_builder = MapBuilder::new(&mut rng); spawn_player(&mut self.ecs, map_builder.player_start); - spawn_amulet_of_yala(&mut self.ecs, map_builder.amulet_start); + //spawn_amulet_of_yala(&mut self.ecs, map_builder.amulet_start); + let exit_idx = map_builder.map.point2d_to_index(map_builder.amulet_start); + map_builder.map.tiles[exit_idx] = TileType::Exit; map_builder .monster_spawns .iter() @@ -148,6 +209,7 @@ impl GameState for State { .execute(&mut self.ecs, &mut self.resources), TurnState::GameOver => self.game_over(ctx), TurnState::Victory => self.victory(ctx), + TurnState::NextLevel => self.advance_level(), } render_draw_buffer(ctx).expect("Render error"); } diff --git a/src/map.rs b/src/map.rs index 704a938..6095efc 100644 --- a/src/map.rs +++ b/src/map.rs @@ -5,6 +5,7 @@ const NUM_TILES: usize = (SCREEN_WIDTH * SCREEN_HEIGHT) as usize; pub enum TileType { Wall, Floor, + Exit, } pub struct Map { @@ -29,7 +30,9 @@ impl Map { } pub fn can_enter_tile(&self, point: Point) -> bool { - self.in_bounds(point) && self.tiles[map_idx(point.x, point.y)] == TileType::Floor + self.in_bounds(point) + && (self.tiles[map_idx(point.x, point.y)] == TileType::Floor + || self.tiles[map_idx(point.x, point.y)] == TileType::Exit) } pub fn try_idx(&self, point: Point) -> Option { diff --git a/src/map_builder/themes.rs b/src/map_builder/themes.rs index 47f2f95..0edaac0 100644 --- a/src/map_builder/themes.rs +++ b/src/map_builder/themes.rs @@ -13,6 +13,7 @@ impl MapTheme for DungeonTheme { match tile_type { TileType::Floor => to_cp437('.'), TileType::Wall => to_cp437('#'), + TileType::Exit => to_cp437('>'), } } } @@ -28,6 +29,7 @@ impl MapTheme for ForestTheme { match tile_type { TileType::Floor => to_cp437(';'), TileType::Wall => to_cp437('"'), + TileType::Exit => to_cp437('>'), } } } diff --git a/src/spawners.rs b/src/spawners.rs index 65fec49..b7cbf34 100644 --- a/src/spawners.rs +++ b/src/spawners.rs @@ -2,7 +2,7 @@ pub use crate::prelude::*; pub fn spawn_player(ecs: &mut World, pos: Point) { ecs.push(( - Player, + Player { map_level: 0 }, pos, Render { color: ColorPair::new(WHITE, BLACK), diff --git a/src/systems/end_turn.rs b/src/systems/end_turn.rs index 04ac91a..2012388 100644 --- a/src/systems/end_turn.rs +++ b/src/systems/end_turn.rs @@ -5,10 +5,11 @@ use crate::prelude::*; #[read_component(Point)] #[read_component(Player)] #[read_component(AmuletOfYala)] -pub fn end_turn(ecs: &SubWorld, #[resource] turn_state: &mut TurnState) { +pub fn end_turn(ecs: &SubWorld, #[resource] turn_state: &mut TurnState, #[resource] map: &Map) { let mut player_hp = <(&Health, &Point)>::query().filter(component::()); let mut amulet = <&Point>::query().filter(component::()); - let amulet_pos = amulet.iter(ecs).nth(0).unwrap(); + let amulet_default = Point::new(-1, -1); + let amulet_pos = amulet.iter(ecs).nth(0).unwrap_or(&amulet_default); let current_state = turn_state.clone(); let mut new_state = match turn_state { @@ -24,6 +25,10 @@ pub fn end_turn(ecs: &SubWorld, #[resource] turn_state: &mut TurnState) { if pos == amulet_pos { new_state = TurnState::Victory; } + let idx = map.point2d_to_index(*pos); + if map.tiles[idx] == TileType::Exit { + new_state = TurnState::NextLevel; + } }); *turn_state = new_state; } diff --git a/src/systems/hud.rs b/src/systems/hud.rs index 710de75..576dab9 100644 --- a/src/systems/hud.rs +++ b/src/systems/hud.rs @@ -12,7 +12,10 @@ pub fn hud(ecs: &SubWorld) { let mut draw_batch = DrawBatch::new(); draw_batch.target(2); - draw_batch.print_centered(1, "Explore the Dungeon. Cursor keys to move."); + draw_batch.print_centered( + 1, + "Explore the Dungeon. Arrow keys to move and attack. G to get item. 1-9 to use item.", + ); draw_batch.bar_horizontal( Point::zero(), SCREEN_WIDTH * 2, @@ -26,6 +29,17 @@ pub fn hud(ecs: &SubWorld) { ColorPair::new(WHITE, RED), ); + let (player, map_level) = <(Entity, &Player)>::query() + .iter(ecs) + .find_map(|(entity, player)| Some((*entity, player.map_level))) + .unwrap(); + draw_batch.print_color_right( + Point::new(SCREEN_WIDTH * 2, 1), + format!("DUNGEON LEVEL: {}", map_level + 1), + ColorPair::new(YELLOW, BLACK), + ); + + // Inventory let player = <(Entity, &Player)>::query() .iter(ecs) .find_map(|(entity, _player)| Some(*entity)) diff --git a/src/turn_state.rs b/src/turn_state.rs index e552be4..fe7ac0f 100644 --- a/src/turn_state.rs +++ b/src/turn_state.rs @@ -5,4 +5,5 @@ pub enum TurnState { MonsterTurn, GameOver, Victory, + NextLevel, }