From 07c703f2a45e02217691af3447d87774256482fe Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Wed, 3 Nov 2021 09:55:17 -0400 Subject: [PATCH] Refactor entity spawning into its own module --- src/gui.rs | 8 +++- src/main.rs | 78 +++---------------------------- src/map.rs | 8 ++-- src/spawner.rs | 121 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 77 deletions(-) create mode 100644 src/spawner.rs diff --git a/src/gui.rs b/src/gui.rs index 5124b01..8506c43 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -88,7 +88,13 @@ fn draw_tooltips(ecs: &World, ctx: &mut Rltk) { let mut y = mouse_pos.1; for s in tooltip.iter() { - ctx.print_color(left_x, y, RGB::named(rltk::WHITE), RGB::named(rltk::GREY), s); + ctx.print_color( + left_x, + y, + RGB::named(rltk::WHITE), + RGB::named(rltk::GREY), + s, + ); let padding = (width - s.len() as i32) - 1; for i in 0..padding { ctx.print_color( diff --git a/src/main.rs b/src/main.rs index 48b3bd3..034611a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use rltk::{GameState, Point, Rltk, RGB}; +use rltk::{GameState, Point, Rltk}; use specs::prelude::*; mod components; @@ -22,6 +22,7 @@ use damage_system::DamageSystem; mod gamelog; mod gui; pub use gamelog::GameLog; +mod spawner; pub const MAP_SIZE: usize = 80 * 50; @@ -133,78 +134,11 @@ fn main() -> rltk::BError { let map: Map = Map::new_map_rooms_and_corridors(); let (player_x, player_y) = map.rooms[0].center(); - let player_entity = gs - .ecs - .create_entity() - .with(Position { - x: player_x, - y: player_y, - }) - .with(Renderable { - glyph: rltk::to_cp437('@'), - fg: RGB::named(rltk::YELLOW), - bg: RGB::named(rltk::BLACK), - }) - .with(Player {}) - .with(Viewshed { - visible_tiles: Vec::new(), - range: 8, - dirty: true, - }) - .with(Name { - name: "Player".to_string(), - }) - .with(CombatStats { - max_hp: 30, - hp: 30, - defense: 2, - power: 5, - }) - .build(); + let player_entity = spawner::player(&mut gs.ecs, player_x, player_y); - let mut rng = rltk::RandomNumberGenerator::new(); - for (i, room) in map.rooms.iter().skip(1).enumerate() { - let (x, y) = room.center(); - - let glyph: rltk::FontCharType; - let name: String; - let roll = rng.roll_dice(1, 2); - match roll { - 1 => { - glyph = rltk::to_cp437('g'); - name = "Goblin".to_string(); - } - _ => { - glyph = rltk::to_cp437('o'); - name = "Orc".to_string(); - } - } - - gs.ecs - .create_entity() - .with(Position { x, y }) - .with(Renderable { - glyph, - fg: RGB::named(rltk::RED), - bg: RGB::named(rltk::BLACK), - }) - .with(Viewshed { - visible_tiles: Vec::new(), - range: 8, - dirty: true, - }) - .with(Monster {}) - .with(Name { - name: format!("{} #{}", &name, i), - }) - .with(BlocksTile {}) - .with(CombatStats { - max_hp: 16, - hp: 16, - defense: 1, - power: 4, - }) - .build(); + gs.ecs.insert(rltk::RandomNumberGenerator::new()); + for room in map.rooms.iter().skip(1) { + spawner::spawn_room(&mut gs.ecs, room); } gs.ecs.insert(map); diff --git a/src/map.rs b/src/map.rs index c311294..fc180ab 100644 --- a/src/map.rs +++ b/src/map.rs @@ -3,9 +3,9 @@ use rltk::{Algorithm2D, BaseMap, Point, RandomNumberGenerator, Rltk, SmallVec, R use specs::prelude::*; use std::cmp::{max, min}; -const MAP_WIDTH: usize = 80; -const MAP_HEIGHT: usize = 43; -const MAP_COUNT: usize = MAP_HEIGHT * MAP_WIDTH; +pub const MAP_WIDTH: usize = 80; +pub const MAP_HEIGHT: usize = 43; +pub const MAP_COUNT: usize = MAP_HEIGHT * MAP_WIDTH; #[derive(PartialEq, Copy, Clone)] pub enum TileType { @@ -228,7 +228,7 @@ pub fn draw_map(ecs: &World, ctx: &mut Rltk) { // Move to the next set of coordinates x += 1; - if x > MAP_WIDTH as i32 -1 { + if x > MAP_WIDTH as i32 - 1 { x = 0; y += 1; } diff --git a/src/spawner.rs b/src/spawner.rs new file mode 100644 index 0000000..fd49a47 --- /dev/null +++ b/src/spawner.rs @@ -0,0 +1,121 @@ +use crate::{ + BlocksTile, CombatStats, Monster, Name, Player, Position, Rect, Renderable, Viewshed, MAP_WIDTH, +}; +use rltk::{RandomNumberGenerator, RGB}; +use specs::prelude::*; + +const MAX_MONSTERS: i32 = 4; +const MAX_ITEMS: i32 = 2; + +/// Spawns the player and returns their entity object +pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity { + ecs.create_entity() + .with(Position { + x: player_x, + y: player_y, + }) + .with(Renderable { + glyph: rltk::to_cp437('@'), + fg: RGB::named(rltk::YELLOW), + bg: RGB::named(rltk::BLACK), + }) + .with(Player {}) + .with(Viewshed { + visible_tiles: Vec::new(), + range: 8, + dirty: true, + }) + .with(Name { + name: "Player".to_string(), + }) + .with(CombatStats { + max_hp: 30, + hp: 30, + defense: 2, + power: 5, + }) + .build() +} + +/// Spawns a random monster at a given location +pub fn random_monster(ecs: &mut World, x: i32, y: i32) { + let roll: i32; + + { + let mut rng = ecs.write_resource::(); + roll = rng.roll_dice(1, 2); + } + + match roll { + 1 => orc(ecs, x, y), + _ => goblin(ecs, x, y), + } +} + +fn orc(ecs: &mut World, x: i32, y: i32) { + monster(ecs, x, y, rltk::to_cp437('o'), "Orc"); +} + +fn goblin(ecs: &mut World, x: i32, y: i32) { + monster(ecs, x, y, rltk::to_cp437('g'), "Goblin"); +} + +fn monster(ecs: &mut World, x: i32, y: i32, glyph: rltk::FontCharType, name: S) { + ecs.create_entity() + .with(Position { x, y }) + .with(Renderable { + glyph, + fg: RGB::named(rltk::RED), + bg: RGB::named(rltk::BLACK), + }) + .with(Viewshed { + visible_tiles: Vec::new(), + range: 8, + dirty: true, + }) + .with(Monster {}) + .with(Name { + name: name.to_string(), + }) + .with(BlocksTile {}) + .with(CombatStats { + max_hp: 16, + hp: 16, + defense: 1, + power: 4, + }) + .build(); +} + +/// fills a room with stuff! +pub fn spawn_room(ecs: &mut World, room: &Rect) { + let mut monster_spawn_points: Vec = Vec::new(); + + // Scope to keep the borrow checker happy + { + let mut rng = ecs.write_resource::(); + let num_monsters = rng.roll_dice(1, MAX_MONSTERS + 2) - 3; + + for _i in 0..num_monsters { + let mut added = false; + while !added { + let x = (room.x1 + rng.roll_dice(1, i32::abs(room.x2 - room.x1))) as usize; + let y = (room.y1 + rng.roll_dice(1, i32::abs(room.y2 - room.y1))) as usize; + let idx = (y * MAP_WIDTH) + x; + + if !monster_spawn_points.contains(&idx) { + monster_spawn_points.push(idx); + added = true; + } + } + } + } + + // Actually spawn the monsters + for idx in monster_spawn_points.iter() { + let x = *idx % MAP_WIDTH; + let y = *idx / MAP_WIDTH; + + random_monster(ecs, x as i32, y as i32); + } +}