multiple levels

This commit is contained in:
Tyrel Souza 2021-08-31 15:56:51 -04:00
parent c17b62985b
commit da36acbade
8 changed files with 103 additions and 14 deletions

View File

@ -8,7 +8,9 @@ pub struct Render {
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct Player; pub struct Player {
pub map_level: u32,
}
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct Enemy; pub struct Enemy;

View File

@ -11,8 +11,8 @@ mod prelude {
pub use legion::systems::CommandBuffer; pub use legion::systems::CommandBuffer;
pub use legion::world::SubWorld; pub use legion::world::SubWorld;
pub use legion::*; pub use legion::*;
pub const SCREEN_WIDTH: i32 = 80; pub const SCREEN_WIDTH: i32 = 60;
pub const SCREEN_HEIGHT: i32 = 50; pub const SCREEN_HEIGHT: i32 = 40;
pub const DISPLAY_WIDTH: i32 = SCREEN_WIDTH / 2; pub const DISPLAY_WIDTH: i32 = SCREEN_WIDTH / 2;
pub const DISPLAY_HEIGHT: i32 = SCREEN_HEIGHT / 2; pub const DISPLAY_HEIGHT: i32 = SCREEN_HEIGHT / 2;
pub use crate::camera::*; pub use crate::camera::*;
@ -33,21 +33,80 @@ struct State {
monster_systems: Schedule, monster_systems: Schedule,
} }
impl State { impl State {
fn advance_level(&mut self) {
let player_entity = *<Entity>::query()
.filter(component::<Player>())
.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 { fn new() -> Self {
let mut ecs = World::default(); let mut ecs = World::default();
let mut resources = Resources::default(); let mut resources = Resources::default();
let mut rng = RandomNumberGenerator::new(); 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_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 map_builder
.monster_spawns .monster_spawns
.iter() .iter()
.for_each(|pos| spawn_entity(&mut ecs, &mut rng, *pos)); .for_each(|pos| spawn_entity(&mut ecs, &mut rng, *pos));
resources.insert(map_builder.map); resources.insert(map_builder.map);
resources.insert(Camera::new(map_builder.player_start)); resources.insert(Camera::new(map_builder.player_start));
resources.insert(TurnState::AwaitingInput); resources.insert(TurnState::AwaitingInput);
resources.insert(map_builder.theme); resources.insert(map_builder.theme);
State { State {
@ -89,9 +148,11 @@ impl State {
self.ecs = World::default(); self.ecs = World::default();
self.resources = Resources::default(); self.resources = Resources::default();
let mut rng = RandomNumberGenerator::new(); 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_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 map_builder
.monster_spawns .monster_spawns
.iter() .iter()
@ -148,6 +209,7 @@ impl GameState for State {
.execute(&mut self.ecs, &mut self.resources), .execute(&mut self.ecs, &mut self.resources),
TurnState::GameOver => self.game_over(ctx), TurnState::GameOver => self.game_over(ctx),
TurnState::Victory => self.victory(ctx), TurnState::Victory => self.victory(ctx),
TurnState::NextLevel => self.advance_level(),
} }
render_draw_buffer(ctx).expect("Render error"); render_draw_buffer(ctx).expect("Render error");
} }

View File

@ -5,6 +5,7 @@ const NUM_TILES: usize = (SCREEN_WIDTH * SCREEN_HEIGHT) as usize;
pub enum TileType { pub enum TileType {
Wall, Wall,
Floor, Floor,
Exit,
} }
pub struct Map { pub struct Map {
@ -29,7 +30,9 @@ impl Map {
} }
pub fn can_enter_tile(&self, point: Point) -> bool { 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<usize> { pub fn try_idx(&self, point: Point) -> Option<usize> {

View File

@ -13,6 +13,7 @@ impl MapTheme for DungeonTheme {
match tile_type { match tile_type {
TileType::Floor => to_cp437('.'), TileType::Floor => to_cp437('.'),
TileType::Wall => to_cp437('#'), TileType::Wall => to_cp437('#'),
TileType::Exit => to_cp437('>'),
} }
} }
} }
@ -28,6 +29,7 @@ impl MapTheme for ForestTheme {
match tile_type { match tile_type {
TileType::Floor => to_cp437(';'), TileType::Floor => to_cp437(';'),
TileType::Wall => to_cp437('"'), TileType::Wall => to_cp437('"'),
TileType::Exit => to_cp437('>'),
} }
} }
} }

View File

@ -2,7 +2,7 @@ pub use crate::prelude::*;
pub fn spawn_player(ecs: &mut World, pos: Point) { pub fn spawn_player(ecs: &mut World, pos: Point) {
ecs.push(( ecs.push((
Player, Player { map_level: 0 },
pos, pos,
Render { Render {
color: ColorPair::new(WHITE, BLACK), color: ColorPair::new(WHITE, BLACK),

View File

@ -5,10 +5,11 @@ use crate::prelude::*;
#[read_component(Point)] #[read_component(Point)]
#[read_component(Player)] #[read_component(Player)]
#[read_component(AmuletOfYala)] #[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::<Player>()); let mut player_hp = <(&Health, &Point)>::query().filter(component::<Player>());
let mut amulet = <&Point>::query().filter(component::<AmuletOfYala>()); let mut amulet = <&Point>::query().filter(component::<AmuletOfYala>());
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 current_state = turn_state.clone();
let mut new_state = match turn_state { 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 { if pos == amulet_pos {
new_state = TurnState::Victory; 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; *turn_state = new_state;
} }

View File

@ -12,7 +12,10 @@ pub fn hud(ecs: &SubWorld) {
let mut draw_batch = DrawBatch::new(); let mut draw_batch = DrawBatch::new();
draw_batch.target(2); 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( draw_batch.bar_horizontal(
Point::zero(), Point::zero(),
SCREEN_WIDTH * 2, SCREEN_WIDTH * 2,
@ -26,6 +29,17 @@ pub fn hud(ecs: &SubWorld) {
ColorPair::new(WHITE, RED), 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() let player = <(Entity, &Player)>::query()
.iter(ecs) .iter(ecs)
.find_map(|(entity, _player)| Some(*entity)) .find_map(|(entity, _player)| Some(*entity))

View File

@ -5,4 +5,5 @@ pub enum TurnState {
MonsterTurn, MonsterTurn,
GameOver, GameOver,
Victory, Victory,
NextLevel,
} }