diff --git a/src/map_builders/mod.rs b/src/map_builders/mod.rs index e1597d8..561f7e1 100644 --- a/src/map_builders/mod.rs +++ b/src/map_builders/mod.rs @@ -18,6 +18,7 @@ use common::*; use dla::DLABuilder; use drunkard::DrunkardsWalkBuilder; use maze::MazeBuilder; +use prefab_builder::PrefabBuilder; use simple_map::SimpleMapBuilder; use specs::prelude::*; use voronoi::VoronoiCellBuilder; diff --git a/src/map_builders/prefab_builder.rs b/src/map_builders/prefab_builder.rs deleted file mode 100644 index 1355fdf..0000000 --- a/src/map_builders/prefab_builder.rs +++ /dev/null @@ -1,65 +0,0 @@ -use super::{remove_unreachable_areas_returning_most_distant, MapBuilder}; -use crate::{spawner, Map, Position, TileType, SHOW_MAPGEN_VISUALIZER}; -use rltk::RandomNumberGenerator; -use specs::prelude::*; - -#[derive(PartialEq, Clone)] -#[allow(dead_code)] -pub enum PrefabMode { - RexLevel { template: &'static str }, -} - -pub struct PrefabBuilder { - map: Map, - starting_position: Position, - depth: i32, - history: Vec, - mode: PrefabMode, -} - -impl MapBuilder for PrefabBuilder { - fn get_map(&self) -> Map { - self.map.clone() - } - - fn get_starting_position(&self) -> Position { - self.starting_position - } - - fn get_snapshot_history(&self) -> Vec { - self.history.clone() - } - - fn build_map(&mut self) { - self.build(); - } - - fn spawn_entities(&mut self, ecs: &mut World) {} - - fn take_snapshot(&mut self) { - if SHOW_MAPGEN_VISUALIZER { - let mut snapshot = self.map.clone(); - for v in snapshot.revealed_tiles.iter_mut() { - *v = true; - } - self.history.push(snapshot); - } - } -} - -impl PrefabBuilder { - #[allow(dead_code)] - pub fn new(new_depth: i32) -> PrefabBuilder { - PrefabBuilder { - map: Map::new(new_depth), - starting_position: Position { x: 0, y: 0 }, - depth: new_depth, - history: Vec::new(), - mode: PrefabMode::RexLevel { - template: "../resources/wfc-demo1.xp", - }, - } - } - - fn build(&mut self) {} -} diff --git a/src/map_builders/prefab_builder/mod.rs b/src/map_builders/prefab_builder/mod.rs new file mode 100644 index 0000000..149ca8b --- /dev/null +++ b/src/map_builders/prefab_builder/mod.rs @@ -0,0 +1,160 @@ +mod prefab_levels; + +use super::{remove_unreachable_areas_returning_most_distant, MapBuilder}; +use crate::{spawner, Map, Position, TileType, SHOW_MAPGEN_VISUALIZER}; +use rltk::RandomNumberGenerator; +use specs::prelude::*; + +#[derive(PartialEq, Clone)] +#[allow(dead_code)] +pub enum PrefabMode { + RexLevel { template: &'static str }, +} + +pub struct PrefabBuilder { + map: Map, + starting_position: Position, + depth: i32, + history: Vec, + mode: PrefabMode, + spawns: Vec<(usize, String)>, +} + +impl MapBuilder for PrefabBuilder { + fn get_map(&self) -> Map { + self.map.clone() + } + + fn get_starting_position(&self) -> Position { + self.starting_position + } + + fn get_snapshot_history(&self) -> Vec { + self.history.clone() + } + + fn build_map(&mut self) { + self.build(); + } + + fn spawn_entities(&mut self, ecs: &mut World) { + for entity in self.spawns.iter() { + spawner::spawn_entity(ecs, &(&entity.0, &entity.1)); + } + } + + fn take_snapshot(&mut self) { + if SHOW_MAPGEN_VISUALIZER { + let mut snapshot = self.map.clone(); + for v in snapshot.revealed_tiles.iter_mut() { + *v = true; + } + self.history.push(snapshot); + } + } +} + +impl PrefabBuilder { + #[allow(dead_code)] + pub fn new(new_depth: i32) -> PrefabBuilder { + PrefabBuilder { + map: Map::new(new_depth), + starting_position: Position { x: 0, y: 0 }, + depth: new_depth, + history: Vec::new(), + mode: PrefabMode::RexLevel { + template: "../resources/wfc-demo1.xp", + }, + spawns: Vec::new(), + } + } + + #[allow(dead_code)] + fn load_rex_map(&mut self, path: &str) { + let xp_file = rltk::rex::XpFile::from_resource(path).unwrap(); + + for layer in &xp_file.layers { + for y in 0..layer.height { + for x in 0..layer.width { + let cell = layer.get(x, y).unwrap(); + if x < self.map.width as usize && y < self.map.height as usize { + let idx = self.map.xy_idx(x as i32, y as i32); + // We're doing some nasty casting to make it easier to type things like '#' in the match + match (cell.ch as u8) as char { + ' ' => self.map.tiles[idx] = TileType::Floor, // space + '#' => self.map.tiles[idx] = TileType::Wall, // # + '@' => { + self.map.tiles[idx] = TileType::Floor; + self.starting_position = Position { + x: x as i32, + y: y as i32, + }; + } + '>' => self.map.tiles[idx] = TileType::DownStairs, + 'g' => { + self.map.tiles[idx] = TileType::Floor; + self.spawns.push((idx, "Goblin".to_string())); + } + 'o' => { + self.map.tiles[idx] = TileType::Floor; + self.spawns.push((idx, "Orc".to_string())); + } + '^' => { + self.map.tiles[idx] = TileType::Floor; + self.spawns.push((idx, "Bear Trap".to_string())); + } + '%' => { + self.map.tiles[idx] = TileType::Floor; + self.spawns.push((idx, "Rations".to_string())); + } + '!' => { + self.map.tiles[idx] = TileType::Floor; + self.spawns.push((idx, "Health Potion".to_string())); + } + _ => { + rltk::console::log(format!( + "Unknown glyph loading map: {}", + (cell.ch as u8) as char + )); + } + } + } + } + } + } + } + + fn build(&mut self) { + match self.mode { + PrefabMode::RexLevel { template } => self.load_rex_map(&template), + } + self.take_snapshot(); + + // Find a starting point; start at the middle and walk left until we find an open tile + if self.starting_position.x == 0 { + self.starting_position = Position { + x: self.map.width / 2, + y: self.map.height / 2, + }; + let mut start_idx = self + .map + .xy_idx(self.starting_position.x, self.starting_position.y); + while self.map.tiles[start_idx] != TileType::Floor { + self.starting_position.x -= 1; + start_idx = self + .map + .xy_idx(self.starting_position.x, self.starting_position.y); + } + self.take_snapshot(); + + // Find all tiles we can reach from the starting point + let exit_tile = + remove_unreachable_areas_returning_most_distant(&mut self.map, start_idx); + self.take_snapshot(); + + // Place the stairs + self.map.tiles[exit_tile] = TileType::DownStairs; + self.take_snapshot(); + } + } +} diff --git a/src/map_builders/prefab_builder/prefab_levels.rs b/src/map_builders/prefab_builder/prefab_levels.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/rex_assets.rs b/src/rex_assets.rs index b76b12c..7bdfb95 100644 --- a/src/rex_assets.rs +++ b/src/rex_assets.rs @@ -2,6 +2,7 @@ use rltk::rex::XpFile; rltk::embedded_resource!(SMALL_DUNGEON, "../resources/SmallDungeon_80x50.xp"); rltk::embedded_resource!(WFC_DEMO_IMAGE1, "../resources/wfc-demo1.xp"); +rltk::embedded_resource!(WFC_POPULATED, "../resources/wfc-populated.xp"); pub struct RexAssets { pub menu: XpFile, @@ -11,6 +12,7 @@ impl RexAssets { pub fn new() -> RexAssets { rltk::link_resource!(SMALL_DUNGEON, "../resources/SmallDungeon_80x50.xp"); rltk::link_resource!(WFC_DEMO_IMAGE1, "../resources/wfc-demo1.xp"); + rltk::link_resource!(WFC_POPULATED, "../resources/wfc-populated.xp"); RexAssets { menu: XpFile::from_resource("../resources/SmallDungeon_80x50.xp").unwrap(), diff --git a/src/spawner.rs b/src/spawner.rs index e8555dc..34dd491 100644 --- a/src/spawner.rs +++ b/src/spawner.rs @@ -111,7 +111,7 @@ pub fn spawn_region(ecs: &mut World, area: &[usize], map_depth: i32) { } /// Spawns a named entity (name in tuple.1) at the location in (tuple.0) -fn spawn_entity(ecs: &mut World, spawn: &(&usize, &String)) { +pub fn spawn_entity(ecs: &mut World, spawn: &(&usize, &String)) { let x = (*spawn.0 % MAP_WIDTH) as i32; let y = (*spawn.0 / MAP_WIDTH) as i32;