diff --git a/src/camera.rs b/src/camera.rs index 1897b39..c71e12c 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -7,13 +7,24 @@ const SHOW_BOUNDARIES: bool = false; pub fn get_screen_bounds(ecs: &World, _ctx: &mut Rltk) -> (i32, i32, i32, i32, i32, i32) { let player_pos = ecs.fetch::(); - let (x_chars, y_chars, x_offset, y_offset) = (69, 41, 1, 10); + let map = ecs.fetch::(); + let (x_chars, y_chars, mut x_offset, mut y_offset) = (69, 41, 1, 10); let centre_x = (x_chars / 2) as i32; let centre_y = (y_chars / 2) as i32; - let min_x = player_pos.x - centre_x; - let min_y = player_pos.y - centre_y; + let min_x = if map.width < (x_chars as i32) { + x_offset += ((x_chars as i32) - map.width) / 2; + 0 + } else { + (player_pos.x - centre_x).clamp(0, map.width - (x_chars as i32)) + }; + let min_y = if map.height < (y_chars as i32) { + y_offset += ((y_chars as i32) - map.height) / 2; + 0 + } else { + (player_pos.y - centre_y).clamp(0, map.height - (y_chars as i32)) + }; let max_x = min_x + (x_chars as i32); let max_y = min_y + (y_chars as i32); diff --git a/src/data/visuals.rs b/src/data/visuals.rs index 1afd15d..f9402be 100644 --- a/src/data/visuals.rs +++ b/src/data/visuals.rs @@ -3,7 +3,7 @@ pub const WITH_SCANLINES: bool = false; // Adds scanlines to the screen. pub const WITH_SCREEN_BURN: bool = false; // Requires WITH_SCANLINES. pub const WITH_DARKEN_BY_DISTANCE: bool = true; // If further away tiles should get darkened, instead of a harsh transition to non-visible. -pub const MAX_COLOUR_OFFSET_PERCENT: i32 = 30; +pub const MAX_COLOUR_OFFSET: i32 = 30; pub const WITH_SCANLINES_BRIGHTEN_AMOUNT: f32 = 0.1; // 0.0 = no brightening, 1.0 = full brightening. pub const NON_VISIBLE_MULTIPLIER: f32 = 0.3; // 0.0 = black, 1.0 = full colour. pub const NON_VISIBLE_MULTIPLIER_IF_SCANLINES: f32 = 0.8; // as above, but when using scanlines. should be higher. @@ -35,6 +35,8 @@ pub const SAND_COLOUR: (u8, u8, u8) = (70, 70, 21); pub const SHALLOW_WATER_COLOUR: (u8, u8, u8) = (24, 47, 99); pub const DEEP_WATER_COLOUR: (u8, u8, u8) = (18, 33, 63); pub const BARS_COLOUR: (u8, u8, u8) = (100, 100, 100); +pub const IMPASSABLE_MOUNTAIN_COLOUR: (u8, u8, u8) = (35, 38, 36); +pub const IMPASSABLE_MOUNTAIN_FG_COLOUR: (u8, u8, u8) = (0, 0, 0); // FOREST THEME pub const FOREST_WALL_COLOUR: (u8, u8, u8) = (0, 153, 0); @@ -56,6 +58,7 @@ pub const SAND_GLYPH: char = '.'; pub const SHALLOW_WATER_GLYPH: char = '~'; pub const DEEP_WATER_GLYPH: char = '≈'; pub const BARS_GLYPH: char = '#'; +pub const IMPASSABLE_MOUNTAIN_GLYPH: char = '▲'; // FOREST THEME pub const FOREST_WALL_GLYPH: char = '♣'; diff --git a/src/main.rs b/src/main.rs index 14a41a3..da5e63d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -723,7 +723,7 @@ fn main() -> rltk::BError { // Insert calls gs.ecs.insert(rltk::RandomNumberGenerator::new()); gs.ecs.insert(map::MasterDungeonMap::new()); // Master map list - gs.ecs.insert(Map::new(1, 64, 64, 0, "New Map")); // Map + gs.ecs.insert(Map::new(true, 1, 64, 64, 0, "New Map")); // Map gs.ecs.insert(Point::new(0, 0)); // Player pos gs.ecs.insert(gui::Ancestry::Dwarf); // ancestry let player_entity = spawner::player(&mut gs.ecs, 0, 0); diff --git a/src/map/mod.rs b/src/map/mod.rs index 7ea2b95..f236122 100644 --- a/src/map/mod.rs +++ b/src/map/mod.rs @@ -8,7 +8,7 @@ pub use interval_spawning_system::try_spawn_interval; pub mod dungeon; pub use dungeon::{ level_transition, MasterDungeonMap }; pub mod themes; -use crate::data::visuals::MAX_COLOUR_OFFSET_PERCENT; +use crate::data::visuals::MAX_COLOUR_OFFSET; // FIXME: If the map size gets too small, entities stop being rendered starting from the right. // i.e. on a map size of 40*40, only entities to the left of the player are rendered. @@ -16,6 +16,7 @@ use crate::data::visuals::MAX_COLOUR_OFFSET_PERCENT; #[derive(Default, Serialize, Deserialize, Clone)] pub struct Map { + pub overmap: bool, pub tiles: Vec, pub width: i32, pub height: i32, @@ -23,7 +24,7 @@ pub struct Map { pub visible_tiles: Vec, pub lit_tiles: Vec, pub telepath_tiles: Vec, - pub colour_offset: Vec<(f32, f32, f32)>, + pub colour_offset: Vec<(i32, i32, i32)>, pub additional_fg_offset: rltk::RGB, pub id: i32, pub name: String, @@ -37,10 +38,11 @@ impl Map { (y as usize) * (self.width as usize) + (x as usize) } - pub fn new(new_id: i32, width: i32, height: i32, difficulty: i32, name: S) -> Map { + pub fn new(overmap: bool, new_id: i32, width: i32, height: i32, difficulty: i32, name: S) -> Map { let map_tile_count = (width * height) as usize; crate::spatial::set_size(map_tile_count); let mut map = Map { + overmap: overmap, tiles: vec![TileType::Wall; map_tile_count], width: width, height: height, @@ -48,11 +50,11 @@ impl Map { visible_tiles: vec![false; map_tile_count], lit_tiles: vec![true; map_tile_count], // NYI: Light sources. Once those exist, we can set this to false. telepath_tiles: vec![false; map_tile_count], - colour_offset: vec![(1.0, 1.0, 1.0); map_tile_count], + colour_offset: vec![(0, 0, 0); map_tile_count], additional_fg_offset: rltk::RGB::from_u8( - MAX_COLOUR_OFFSET_PERCENT as u8, - MAX_COLOUR_OFFSET_PERCENT as u8, - MAX_COLOUR_OFFSET_PERCENT as u8 + MAX_COLOUR_OFFSET as u8, + MAX_COLOUR_OFFSET as u8, + MAX_COLOUR_OFFSET as u8 ), id: new_id, name: name.to_string(), @@ -61,16 +63,13 @@ impl Map { view_blocked: HashSet::new(), }; - const TWICE_OFFSET: i32 = MAX_COLOUR_OFFSET_PERCENT * 2; + const TWICE_OFFSET: i32 = MAX_COLOUR_OFFSET * 2; let mut rng = rltk::RandomNumberGenerator::new(); for idx in 0..map.colour_offset.len() { - let red_roll: f32 = - ((rng.roll_dice(1, TWICE_OFFSET - 1) + 1 - MAX_COLOUR_OFFSET_PERCENT) as f32) / 100f32 + 1.0; - let green_roll: f32 = - ((rng.roll_dice(1, TWICE_OFFSET - 1) + 1 - MAX_COLOUR_OFFSET_PERCENT) as f32) / 100f32 + 1.0; - let blue_roll: f32 = - ((rng.roll_dice(1, TWICE_OFFSET - 1) + 1 - MAX_COLOUR_OFFSET_PERCENT) as f32) / 100f32 + 1.0; + let red_roll: i32 = rng.roll_dice(1, TWICE_OFFSET) - MAX_COLOUR_OFFSET; + let blue_roll: i32 = rng.roll_dice(1, TWICE_OFFSET) - MAX_COLOUR_OFFSET; + let green_roll: i32 = rng.roll_dice(1, TWICE_OFFSET) - MAX_COLOUR_OFFSET; map.colour_offset[idx] = (red_roll, green_roll, blue_roll); } diff --git a/src/map/themes.rs b/src/map/themes.rs index 5cc5966..0f872f3 100644 --- a/src/map/themes.rs +++ b/src/map/themes.rs @@ -11,8 +11,8 @@ pub fn get_tile_renderables_for_id( other_pos: Option, debug: Option ) -> (rltk::FontCharType, RGB, RGB) { - let (glyph, mut fg, mut bg) = match map.id { - 2 => get_forest_theme_renderables(idx, map, debug), + let (glyph, mut fg, mut bg, offset_mod) = match map.id { + 3 => get_forest_theme_renderables(idx, map, debug), _ => get_default_theme_renderables(idx, map, debug), }; @@ -24,7 +24,7 @@ pub fn get_tile_renderables_for_id( } fg = fg.add(map.additional_fg_offset); - (fg, bg) = apply_colour_offset(fg, bg, map, idx); + (fg, bg) = apply_colour_offset(fg, bg, map, idx, offset_mod); if CONFIG.visuals.with_scanlines && WITH_SCANLINES_BRIGHTEN_AMOUNT > 0.0 { (fg, bg) = brighten_by(fg, bg, WITH_SCANLINES_BRIGHTEN_AMOUNT); } @@ -60,12 +60,13 @@ pub fn get_tile_renderables_for_id( } #[rustfmt::skip] -pub fn get_default_theme_renderables(idx: usize, map: &Map, debug: Option) -> (rltk::FontCharType, RGB, RGB) { +pub fn get_default_theme_renderables(idx: usize, map: &Map, debug: Option) -> (rltk::FontCharType, RGB, RGB, (f32, f32, f32)) { let glyph: rltk::FontCharType; #[allow(unused_assignments)] let mut fg: RGB = RGB::new(); #[allow(unused_assignments)] let mut bg: RGB = RGB::new(); + let mut offset_mod: (f32, f32, f32) = (0.5, 0.2, 0.0); match map.tiles[idx] { TileType::Floor => { glyph = rltk::to_cp437(FLOOR_GLYPH); fg = RGB::named(FLOOR_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); } @@ -84,26 +85,28 @@ pub fn get_default_theme_renderables(idx: usize, map: &Map, debug: Option) TileType::ShallowWater => { glyph = rltk::to_cp437(SHALLOW_WATER_GLYPH); bg = RGB::named(SHALLOW_WATER_COLOUR); } TileType::DeepWater => { glyph = rltk::to_cp437(DEEP_WATER_GLYPH); bg = RGB::named(DEEP_WATER_COLOUR); } TileType::Bars => { glyph = rltk::to_cp437(BARS_GLYPH); fg = RGB::named(BARS_COLOUR); bg = RGB::named(FLOOR_COLOUR); } + TileType::ImpassableMountain => { glyph = rltk::to_cp437(IMPASSABLE_MOUNTAIN_GLYPH); bg = RGB::named(IMPASSABLE_MOUNTAIN_COLOUR); fg = RGB::named((20, 20, 20)) } } - return (glyph, fg, bg); + return (glyph, fg, bg, offset_mod); } #[rustfmt::skip] -fn get_forest_theme_renderables(idx:usize, map: &Map, debug: Option) -> (rltk::FontCharType, RGB, RGB) { +fn get_forest_theme_renderables(idx:usize, map: &Map, debug: Option) -> (rltk::FontCharType, RGB, RGB, (f32, f32, f32)) { let glyph; #[allow(unused_assignments)] let mut fg = RGB::new(); #[allow(unused_assignments)] let mut bg = RGB::new(); + let mut offset_mod: (f32, f32, f32) = (1.0, 1.0, 1.0); match map.tiles[idx] { TileType::Wall => { glyph = rltk::to_cp437(FOREST_WALL_GLYPH); fg = RGB::named(FOREST_WALL_COLOUR); bg = RGB::named(GRASS_COLOUR) } TileType::Road => { glyph = rltk::to_cp437(ROAD_GLYPH); bg = RGB::named(ROAD_COLOUR); } TileType::ShallowWater => { glyph = rltk::to_cp437(SHALLOW_WATER_GLYPH); bg = RGB::named(SHALLOW_WATER_COLOUR); } - _ => { (glyph, fg, _) = get_default_theme_renderables(idx, map, debug); bg = RGB::named(GRASS_COLOUR) } + _ => { (glyph, fg, _, offset_mod) = get_default_theme_renderables(idx, map, debug); bg = RGB::named(GRASS_COLOUR) } } - (glyph, fg, bg) + (glyph, fg, bg, offset_mod) } fn is_revealed_and_wall(map: &Map, x: i32, y: i32, debug: Option) -> bool { @@ -248,10 +251,17 @@ fn wall_glyph(map: &Map, x: i32, y: i32, debug: Option) -> rltk::FontCharT } } -fn apply_colour_offset(mut fg: RGB, mut bg: RGB, map: &Map, idx: usize) -> (RGB, RGB) { - let offsets = map.colour_offset[idx]; - fg = multiply_by_float(fg.add(map.additional_fg_offset), offsets); - bg = multiply_by_float(bg, offsets); +fn apply_colour_offset(mut fg: RGB, mut bg: RGB, map: &Map, idx: usize, offset_mod: (f32, f32, f32)) -> (RGB, RGB) { + let mut offsets = map.colour_offset[idx]; + let mut additional_fg_offset = map.additional_fg_offset; + offsets.0 = ((offsets.0 as f32) * offset_mod.0) as i32; + offsets.1 = ((offsets.1 as f32) * offset_mod.1) as i32; + offsets.2 = ((offsets.2 as f32) * offset_mod.2) as i32; + additional_fg_offset.r *= offset_mod.0; + additional_fg_offset.g *= offset_mod.1; + additional_fg_offset.b *= offset_mod.2; + fg = add_i32_offsets(fg.add(additional_fg_offset), offsets); + bg = add_i32_offsets(bg, offsets); return (fg, bg); } @@ -262,6 +272,14 @@ fn apply_bloodstain_if_necessary(mut bg: RGB, map: &Map, idx: usize) -> RGB { return bg; } +pub fn add_i32_offsets(rgb: RGB, offsets: (i32, i32, i32)) -> RGB { + let r = rgb.r + (offsets.0 as f32) / 255.0; + let g = rgb.g + (offsets.1 as f32) / 255.0; + let b = rgb.b + (offsets.2 as f32) / 255.0; + + return rltk::RGB::from_f32(r, g, b); +} + pub fn multiply_by_float(rgb: rltk::RGB, offsets: (f32, f32, f32)) -> RGB { let r = rgb.r * offsets.0; let g = rgb.g * offsets.1; diff --git a/src/map/tiletype.rs b/src/map/tiletype.rs index 73d37f2..de646b1 100644 --- a/src/map/tiletype.rs +++ b/src/map/tiletype.rs @@ -3,6 +3,7 @@ use serde::{ Deserialize, Serialize }; #[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)] pub enum TileType { // Walls (opaque) + ImpassableMountain, Wall, // Impassable (transparent) DeepWater, @@ -44,6 +45,7 @@ pub fn tile_walkable(tt: TileType) -> bool { pub fn tile_opaque(tt: TileType) -> bool { match tt { + TileType::ImpassableMountain => true, TileType::Wall => true, _ => false, } diff --git a/src/map_builders/forest.rs b/src/map_builders/forest.rs index 5b21f6d..1c2005a 100644 --- a/src/map_builders/forest.rs +++ b/src/map_builders/forest.rs @@ -20,7 +20,7 @@ pub fn forest_builder( difficulty: i32, initial_player_level: i32 ) -> BuilderChain { - let mut chain = BuilderChain::new(new_id, width, height, difficulty, "the woods", initial_player_level); + let mut chain = BuilderChain::new(false, new_id, width, height, difficulty, "the woods", initial_player_level); chain.start_with(CellularAutomataBuilder::new()); chain.with(AreaStartingPosition::new(XStart::CENTRE, YStart::CENTRE)); chain.with(CullUnreachable::new()); diff --git a/src/map_builders/mod.rs b/src/map_builders/mod.rs index 7357ac5..e2e06d4 100644 --- a/src/map_builders/mod.rs +++ b/src/map_builders/mod.rs @@ -97,6 +97,7 @@ pub struct BuilderChain { impl BuilderChain { pub fn new( + overmap: bool, new_id: i32, width: i32, height: i32, @@ -109,7 +110,7 @@ impl BuilderChain { builders: Vec::new(), build_data: BuilderMap { spawn_list: Vec::new(), - map: Map::new(new_id, width, height, difficulty, name), + map: Map::new(overmap, new_id, width, height, difficulty, name), starting_position: None, rooms: None, corridors: None, @@ -316,6 +317,13 @@ fn random_shape_builder(rng: &mut rltk::RandomNumberGenerator, builder: &mut Bui return want_doors; } +fn overmap_builder() -> BuilderChain { + let mut builder = BuilderChain::new(true, 1, 69, 41, 0, "the world", 1); + builder.start_with(PrefabBuilder::overmap()); + builder.with(AreaStartingPosition::new(XStart::CENTRE, YStart::CENTRE)); + return builder; +} + pub fn random_builder( new_id: i32, rng: &mut rltk::RandomNumberGenerator, @@ -325,7 +333,7 @@ pub fn random_builder( initial_player_level: i32 ) -> BuilderChain { rltk::console::log(format!("DEBUGINFO: Building random (ID:{}, DIFF:{})", new_id, difficulty)); - let mut builder = BuilderChain::new(new_id, width, height, difficulty, "the dungeon", initial_player_level); + let mut builder = BuilderChain::new(false, new_id, width, height, difficulty, "the dungeon", initial_player_level); let type_roll = rng.roll_dice(1, 2); let mut want_doors = true; match type_roll { @@ -378,8 +386,9 @@ pub fn level_builder( // TODO: With difficulty and ID/depth decoupled, this can be used for branches later. let difficulty = new_id; match new_id { - 1 => town_builder(new_id, rng, width, height, 0, initial_player_level), - 2 => forest_builder(new_id, rng, width, height, 1, initial_player_level), + 1 => overmap_builder(), + 2 => town_builder(new_id, rng, width, height, 0, initial_player_level), + 3 => forest_builder(new_id, rng, width, height, 1, initial_player_level), _ => random_builder(new_id, rng, width, height, difficulty, initial_player_level), } } diff --git a/src/map_builders/prefab_builder/mod.rs b/src/map_builders/prefab_builder/mod.rs index 74dd5b2..37bd143 100644 --- a/src/map_builders/prefab_builder/mod.rs +++ b/src/map_builders/prefab_builder/mod.rs @@ -1,4 +1,4 @@ -use super::{spawner, BuilderMap, InitialMapBuilder, MetaMapBuilder, Position, TileType}; +use super::{ spawner, BuilderMap, InitialMapBuilder, MetaMapBuilder, Position, TileType }; use rltk::RandomNumberGenerator; pub mod prefab_levels; pub mod prefab_sections; @@ -8,9 +8,13 @@ use std::collections::HashSet; #[derive(PartialEq, Copy, Clone)] #[allow(dead_code)] pub enum PrefabMode { - RexLevel { template: &'static str }, - Constant { level: prefab_levels::PrefabLevel }, - Sectional { section: prefab_sections::PrefabSection }, + Overmap, + Constant { + level: prefab_levels::PrefabLevel, + }, + Sectional { + section: prefab_sections::PrefabSection, + }, RoomVaults, } @@ -39,8 +43,8 @@ impl PrefabBuilder { } #[allow(dead_code)] - pub fn rex_level(template: &'static str) -> Box { - Box::new(PrefabBuilder { mode: PrefabMode::RexLevel { template } }) + pub fn overmap() -> Box { + Box::new(PrefabBuilder { mode: PrefabMode::Overmap }) } #[allow(dead_code)] @@ -60,8 +64,8 @@ impl PrefabBuilder { fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { match self.mode { - PrefabMode::RexLevel { template } => self.load_rex_map(&template, rng, build_data), - PrefabMode::Constant { level } => self.load_ascii_map(&level, rng, build_data), + PrefabMode::Overmap => self.load_ascii_map(&prefab_levels::OVERMAP, rng, build_data, true), + PrefabMode::Constant { level } => self.load_ascii_map(&level, rng, build_data, false), PrefabMode::Sectional { section } => self.apply_sectional(§ion, rng, build_data), PrefabMode::RoomVaults => self.apply_room_vaults(rng, build_data), } @@ -71,13 +75,24 @@ impl PrefabBuilder { fn char_to_map(&mut self, ch: char, idx: usize, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { let difficulty = (build_data.map.difficulty + build_data.initial_player_level) / 2; match ch { - ' ' => build_data.map.tiles[idx] = TileType::Floor, - '#' => build_data.map.tiles[idx] = TileType::Wall, - '>' => build_data.map.tiles[idx] = TileType::DownStair, - '≈' => build_data.map.tiles[idx] = TileType::Floor, // Placeholder for vines/brush + ' ' => { + build_data.map.tiles[idx] = TileType::Floor; + } + '.' => { + build_data.map.tiles[idx] = TileType::Grass; + } + '#' => { + build_data.map.tiles[idx] = TileType::Wall; + } + '>' => { + build_data.map.tiles[idx] = TileType::DownStair; + } + '≈' => { + build_data.map.tiles[idx] = TileType::DeepWater; + } // Placeholder for vines/brush '@' => { - let x = idx as i32 % build_data.map.width; - let y = idx as i32 / build_data.map.width; + let x = (idx as i32) % build_data.map.width; + let y = (idx as i32) / build_data.map.width; build_data.map.tiles[idx] = TileType::Floor; build_data.starting_position = Some(Position { x: x as i32, y: y as i32 }); } @@ -122,7 +137,48 @@ impl PrefabBuilder { build_data.spawn_list.push((idx, spawner::equipment_table(Some(difficulty)).roll(rng))); } _ => { - rltk::console::log(format!("Unknown glyph '{}' when loading prefab", (ch as u8) as char)); + rltk::console::log(format!("Unknown glyph '{}' when loading prefab", ch as u8 as char)); + } + } + } + + fn overmap_char_to_map( + &mut self, + ch: char, + idx: usize, + _rng: &mut RandomNumberGenerator, + build_data: &mut BuilderMap + ) { + match ch { + ' ' => { + build_data.map.tiles[idx] = TileType::Floor; + } + '.' => { + build_data.map.tiles[idx] = TileType::Grass; + } + '#' => { + build_data.map.tiles[idx] = TileType::Wall; + } + '>' => { + build_data.map.tiles[idx] = TileType::DownStair; + } + '~' => { + build_data.map.tiles[idx] = TileType::ShallowWater; + } + '≈' => { + build_data.map.tiles[idx] = TileType::DeepWater; + } + '@' => { + let x = (idx as i32) % build_data.map.width; + let y = (idx as i32) / build_data.map.width; + build_data.map.tiles[idx] = TileType::Grass; + build_data.starting_position = Some(Position { x: x as i32, y: y as i32 }); + } + '^' => { + build_data.map.tiles[idx] = TileType::ImpassableMountain; + } + _ => { + rltk::console::log(format!("Unknown glyph '{}' when loading overmap", ch as u8 as char)); } } } @@ -135,7 +191,7 @@ impl PrefabBuilder { for y in 0..layer.height { for x in 0..layer.width { let cell = layer.get(x, y).unwrap(); - if x < build_data.map.width as usize && y < build_data.map.height as usize { + if x < (build_data.map.width as usize) && y < (build_data.map.height as usize) { let idx = build_data.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 self.char_to_map(cell.ch as u8 as char, idx, rng, build_data); @@ -146,9 +202,12 @@ impl PrefabBuilder { } fn read_ascii_to_vec(template: &str) -> Vec { - let mut string_vec: Vec = template.chars().filter(|a| *a != '\r' && *a != '\n').collect(); + let mut string_vec: Vec = template + .chars() + .filter(|a| *a != '\r' && *a != '\n') + .collect(); for c in string_vec.iter_mut() { - if *c as u8 == 160u8 { + if (*c as u8) == 160u8 { *c = ' '; } } @@ -161,16 +220,21 @@ impl PrefabBuilder { level: &prefab_levels::PrefabLevel, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap, + overmap: bool ) { let string_vec = PrefabBuilder::read_ascii_to_vec(level.template); let mut i = 0; for ty in 0..level.height { for tx in 0..level.width { - if tx < build_data.map.width as usize && ty < build_data.map.height as usize { + if tx < (build_data.map.width as usize) && ty < (build_data.map.height as usize) { let idx = build_data.map.xy_idx(tx as i32, ty as i32); if i < string_vec.len() { - self.char_to_map(string_vec[i], idx, rng, build_data); + if overmap { + self.overmap_char_to_map(string_vec[i], idx, rng, build_data); + } else { + self.char_to_map(string_vec[i], idx, rng, build_data); + } } } i += 1; @@ -182,14 +246,14 @@ impl PrefabBuilder { &mut self, mut filter: F, _rng: &mut RandomNumberGenerator, - build_data: &mut BuilderMap, - ) where - F: FnMut(i32, i32) -> bool, + build_data: &mut BuilderMap + ) + where F: FnMut(i32, i32) -> bool { let width = build_data.map.width; build_data.spawn_list.retain(|(idx, _name)| { - let x = *idx as i32 % width; - let y = *idx as i32 / width; + let x = (*idx as i32) % width; + let y = (*idx as i32) / width; filter(x, y) }); build_data.take_snapshot(); @@ -200,7 +264,7 @@ impl PrefabBuilder { &mut self, section: &prefab_sections::PrefabSection, rng: &mut RandomNumberGenerator, - build_data: &mut BuilderMap, + build_data: &mut BuilderMap ) { use prefab_sections::*; @@ -209,36 +273,52 @@ impl PrefabBuilder { // Place the new section let chunk_x; match section.placement.0 { - HorizontalPlacement::Left => chunk_x = 0, - HorizontalPlacement::Center => chunk_x = (build_data.map.width / 2) - (section.width as i32 / 2), - HorizontalPlacement::Right => chunk_x = (build_data.map.width - 1) - section.width as i32, + HorizontalPlacement::Left => { + chunk_x = 0; + } + HorizontalPlacement::Center => { + chunk_x = build_data.map.width / 2 - (section.width as i32) / 2; + } + HorizontalPlacement::Right => { + chunk_x = build_data.map.width - 1 - (section.width as i32); + } } let chunk_y; match section.placement.1 { - VerticalPlacement::Top => chunk_y = 0, - VerticalPlacement::Center => chunk_y = (build_data.map.height / 2) - (section.height as i32 / 2), - VerticalPlacement::Bottom => chunk_y = (build_data.map.height - 1) - section.height as i32, + VerticalPlacement::Top => { + chunk_y = 0; + } + VerticalPlacement::Center => { + chunk_y = build_data.map.height / 2 - (section.height as i32) / 2; + } + VerticalPlacement::Bottom => { + chunk_y = build_data.map.height - 1 - (section.height as i32); + } } // Build the map self.apply_previous_iteration( |x, y| { - x < chunk_x - || x > (chunk_x + section.width as i32) - || y < chunk_y - || y > (chunk_y + section.height as i32) + x < chunk_x || + x > chunk_x + (section.width as i32) || + y < chunk_y || + y > chunk_y + (section.height as i32) }, rng, - build_data, + build_data ); let mut i = 0; for ty in 0..section.height { for tx in 0..section.width { - if tx > 0 && tx < build_data.map.width as usize - 1 && ty < build_data.map.height as usize - 1 && ty > 0 + if + tx > 0 && + tx < (build_data.map.width as usize) - 1 && + ty < (build_data.map.height as usize) - 1 && + ty > 0 { - let idx = build_data.map.xy_idx(tx as i32 + chunk_x, ty as i32 + chunk_y); + let idx = build_data.map.xy_idx((tx as i32) + chunk_x, (ty as i32) + chunk_y); if i < string_vec.len() { self.char_to_map(string_vec[i], idx, rng, build_data); } @@ -274,7 +354,7 @@ impl PrefabBuilder { FLUFF2_6X3, HOUSE_NOTRAP_7X7, HOUSE_TRAP_7X7, - ORC_HOUSE_8X8, + ORC_HOUSE_8X8 ]; // Filter the vault list down to ones that are applicable to the current id @@ -313,8 +393,12 @@ impl PrefabBuilder { let roll = rng.roll_dice(1, 4); match roll { 1 => {} - 2 => flip_x = true, - 3 => flip_y = true, + 2 => { + flip_x = true; + } + 3 => { + flip_y = true; + } _ => { flip_x = true; flip_y = true; @@ -328,14 +412,15 @@ impl PrefabBuilder { let mut idx = 0usize; loop { - let x = (idx % build_data.map.width as usize) as i32; - let y = (idx / build_data.map.width as usize) as i32; + let x = (idx % (build_data.map.width as usize)) as i32; + let y = (idx / (build_data.map.width as usize)) as i32; // Check that we won't overflow the map - if x > 1 - && (x + vault.width as i32) < build_data.map.width - 2 - && y > 1 - && (y + vault.height as i32) < build_data.map.height - 2 + if + x > 1 && + x + (vault.width as i32) < build_data.map.width - 2 && + y > 1 && + y + (vault.height as i32) < build_data.map.height - 2 { let mut possible = true; for ty in 0..vault.height as i32 { @@ -379,7 +464,10 @@ impl PrefabBuilder { let idx = e.0 as i32; let x = idx % width; let y = idx / height; - x < chunk_x || x > chunk_x + vault.width as i32 || y < chunk_y || y > chunk_y + vault.height as i32 + x < chunk_x || + x > chunk_x + (vault.width as i32) || + y < chunk_y || + y > chunk_y + (vault.height as i32) }); let string_vec = PrefabBuilder::read_ascii_to_vec(vault.template); @@ -390,17 +478,22 @@ impl PrefabBuilder { let mut y_: i32 = tile_y as i32; // Handle flipping if flip_x { - x_ = vault.width as i32 - 1 - x_; + x_ = (vault.width as i32) - 1 - x_; } if flip_y { - y_ = vault.height as i32 - 1 - y_; + y_ = (vault.height as i32) - 1 - y_; } if x_ < 0 || y_ < 0 { // If either of these go below 0, we run the risk of CTD, so just panic. // Something went wrong with flipping/rotating/defining a vault. panic!( "X or Y went below 0 when trying to place a vault! DEBUGINFO == [H: {}, W: {}; FLIPPED X: {}, FLIPPED Y: {}; X_: {}, Y_: {}]", - vault.width, vault.height, flip_x, flip_y, x_, y_ + vault.width, + vault.height, + flip_x, + flip_y, + x_, + y_ ); } let idx = build_data.map.xy_idx(x_ + chunk_x, y_ + chunk_y); diff --git a/src/map_builders/prefab_builder/overmap b/src/map_builders/prefab_builder/overmap new file mode 100644 index 0000000..994aa3e --- /dev/null +++ b/src/map_builders/prefab_builder/overmap @@ -0,0 +1,41 @@ +~~~~~~~~~.................~~~.......~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~...........................~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~............................~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~....~..........................~~~~~~~~~~~~~.....~~~~~~~ +~~~....~...........................~..~~~~~~~~~~......~~~~~~ +~~~.................~.................~~~~~~~~~........~...~ +~~~.................~....................................... +~~~~........................................................ +~~~~~~...................................................... +~~~~~~..................................~................... +~~~~~........~~.........................~................... +~~~~~......~~~.~............................................ +~~~~.......~~..~...........................................~ +~~~........~...............................................~ +~~~~......~...............................................~~ +~~~~~......................................................~ +~~~~~...~................~.................................. +~~~~~~~~~~~............~~~.................................. +~~~~~~~~~~...........~..~................................... +~~~~~~~~~~~............~.................................... +~~~~~~~~~..............~.................................... +~~~~~~~~.............~~...................................~~ +~~~~~~~..............~.....................................~ +~~~~~......................................................~ +~~~~~.................~~...................................~ +~~~~..................~.~~~................................. +~~~~..............~.......~................................. +~.................~~..................~~.................... +~...............~..~..................~~~................... +..~......~~~~~~~~.....~~~.............~~.................... +..~~.....~~~~~~~~~~...~~~................................... +..~~~~~~~~~~~~~~~~..~~~~~~.................................. +....~~~~~~~~~~~~...~~~~~~~..............~~~~................ +........~~~~~~~~..........~.~....~......~......~.......~.... +~...~...~~~~~~~~...........................................~ +...~~.......~~~~............................................ +...............~............................................ +.................................~.......................... +~~...............................~~.....~................... +~~~..............................~~......................... +~~~......................................~~~.~~~~........... \ No newline at end of file diff --git a/src/map_builders/prefab_builder/prefab_levels.rs b/src/map_builders/prefab_builder/prefab_levels.rs index 23d1d90..0c04cbb 100644 --- a/src/map_builders/prefab_builder/prefab_levels.rs +++ b/src/map_builders/prefab_builder/prefab_levels.rs @@ -7,9 +7,11 @@ pub struct PrefabLevel { #[allow(dead_code)] pub const WFC_POPULATED: PrefabLevel = PrefabLevel { template: LEVEL_MAP, width: 80, height: 43 }; +pub const OVERMAP: PrefabLevel = PrefabLevel { template: OVERMAP_TEMPLATE, width: 69, height: 41 }; #[allow(dead_code)] -const LEVEL_MAP: &str = " +const LEVEL_MAP: &str = + " ################################################################################ #          ########################################################    ######### #    @     ######    #########       ####     ###################        ####### @@ -53,3 +55,47 @@ const LEVEL_MAP: &str = " #!%^   ###  ###     ############### ########      ##### g     ####      # g#   # # %^##  ^   ###     ############### ########      #####       ################## ################################################################################"; + +const OVERMAP_TEMPLATE: &str = + " +^^^^^^^^^^^^^^^^^^^^^^^^^^^≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈........≈≈≈≈≈≈≈≈ +^^^^^^^^^^^^^^^^^^^^^^^^^^≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈...........≈≈≈≈≈≈≈ +^^^^^^^^^^^^^^^....^^^^^^≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈.............≈≈≈≈≈ +^^^^^^^^^^^^^^...........≈≈≈≈≈≈≈≈≈........≈≈≈≈≈≈≈≈..............≈≈≈≈≈ +^^^^^^^^^^^^^............≈≈≈≈≈≈≈≈...........≈≈≈≈≈..............≈≈≈≈≈≈ +^^^^^^^^^^^.............≈≈≈≈≈≈≈≈≈...........≈≈≈≈≈.............≈≈≈≈≈≈≈ +^^^^^^^^^...............≈≈≈≈≈≈≈≈≈............≈≈≈≈............≈≈≈≈≈≈≈≈ +^^^^^^^^................≈≈≈≈≈≈≈≈≈............≈≈≈≈............≈≈≈≈≈≈≈≈ +^^^^^^^..................≈≈≈≈≈≈≈≈≈...........≈≈≈.............≈≈≈≈≈≈≈≈ +^^^^.....................≈≈≈≈≈≈≈≈≈≈≈........≈≈≈≈..............≈≈≈≈≈≈≈ +^^.........................≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈..............≈≈≈≈≈≈≈ +^^..............................≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈................≈≈≈≈≈≈ +^.................................≈≈≈≈≈≈≈≈≈≈≈≈≈.................≈≈≈≈≈ +^..................................≈≈≈≈≈≈≈≈≈≈≈≈.................≈≈≈≈≈ +^....................................≈≈≈≈≈≈≈≈≈..................≈≈≈≈≈ +^......................................≈≈≈≈≈≈...................≈≈≈≈≈ +^........................................≈≈.....................≈≈≈≈≈ +^..............................................................≈≈≈≈≈≈ +^..............................................................≈≈≈≈≈≈ +^^.............................................................≈≈≈≈≈≈ +^^.............................................................≈≈≈≈≈≈ +^^.............................................................≈≈≈≈≈≈ +^^^............................................................≈≈≈≈≈≈ +^^^^............................................................≈≈≈≈≈ +^^^^^...........................................................≈≈≈≈≈ +^^^^^^^^........................................................≈≈≈≈≈ +^^^^^^^^^.......................................................≈≈≈≈≈ +^^^^^^^^^..............................≈≈........................≈≈≈≈ +^^^^^^^^^.............................≈≈≈≈≈≈≈≈≈...................≈≈≈ +^^^^^^^^..............................≈≈≈≈≈≈≈≈≈≈......≈............≈≈ +^^^^^^^..............................≈≈≈≈≈≈≈≈≈≈≈≈≈...≈≈..........≈..≈ +^^^^^^^..........................≈≈.≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈....≈≈≈≈ +^^^^^^^........................≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈.....≈ +^^^^^^^^........@..............≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈....≈ +^^^^^^^^..................≈...≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈...≈≈≈...≈≈≈≈≈≈≈≈.≈≈ +^^^^^^^^^.................≈≈....≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈....≈≈......≈≈≈≈≈≈≈≈≈ +^^^^^^^^^........≈≈≈≈...≈≈≈≈....≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈..≈≈≈......≈≈≈≈≈≈≈≈≈ +^^^^^^^^^^......≈≈≈≈≈≈≈≈≈≈≈≈≈..≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈........≈≈≈≈≈≈≈≈ +^^^^^^^^^^.....≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈........≈≈≈≈≈≈≈≈≈ +^^^^^^^^^^....≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈....≈≈≈≈≈≈≈≈≈≈ +^^^^^^^^^^^^.≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈"; diff --git a/src/map_builders/town.rs b/src/map_builders/town.rs index ee4a1d5..b633bae 100644 --- a/src/map_builders/town.rs +++ b/src/map_builders/town.rs @@ -10,7 +10,7 @@ pub fn town_builder( initial_player_level: i32 ) -> BuilderChain { rltk::console::log(format!("DEBUGINFO: Building town (ID:{}, DIFF:{})", new_id, difficulty)); - let mut chain = BuilderChain::new(new_id, width, height, difficulty, "the town", initial_player_level); + let mut chain = BuilderChain::new(false, new_id, width, height, difficulty, "the town", initial_player_level); chain.start_with(TownBuilder::new()); return chain; diff --git a/src/map_builders/wfc/mod.rs b/src/map_builders/wfc/mod.rs index 46168da..8132e38 100644 --- a/src/map_builders/wfc/mod.rs +++ b/src/map_builders/wfc/mod.rs @@ -1,4 +1,4 @@ -use super::{BuilderMap, Map, MetaMapBuilder, TileType}; +use super::{ BuilderMap, Map, MetaMapBuilder, TileType }; use rltk::RandomNumberGenerator; mod common; use common::*; @@ -32,11 +32,12 @@ impl WaveFunctionCollapseBuilder { self.render_tile_gallery(&constraints, CHUNK_SIZE, build_data); build_data.map = Map::new( + build_data.map.overmap, build_data.map.id, build_data.map.width, build_data.map.height, build_data.map.difficulty, - &build_data.map.name, + &build_data.map.name ); loop { let mut solver = Solver::new(constraints.clone(), CHUNK_SIZE, &build_data.map); @@ -52,7 +53,7 @@ impl WaveFunctionCollapseBuilder { } fn render_tile_gallery(&mut self, constraints: &[MapChunk], chunk_size: i32, build_data: &mut BuilderMap) { - build_data.map = Map::new(0, build_data.width, build_data.height, 0, &build_data.map.name); + build_data.map = Map::new(false, 0, build_data.width, build_data.height, 0, &build_data.map.name); let mut counter = 0; let mut x = 1; let mut y = 1; @@ -68,7 +69,7 @@ impl WaveFunctionCollapseBuilder { if y + chunk_size > build_data.map.height { // Move to the next page build_data.take_snapshot(); - build_data.map = Map::new(0, build_data.width, build_data.height, 0, &build_data.map.name); + build_data.map = Map::new(false, 0, build_data.width, build_data.height, 0, &build_data.map.name); x = 1; y = 1; diff --git a/src/visibility_system.rs b/src/visibility_system.rs index 9496133..d299a7b 100644 --- a/src/visibility_system.rs +++ b/src/visibility_system.rs @@ -45,7 +45,11 @@ impl<'a> System<'a> for VisibilitySystem { for (ent, viewshed, pos) in (&entities, &mut viewshed, &pos).join() { if viewshed.dirty { viewshed.dirty = false; - let range = if let Some(_is_blind) = blind_entities.get(ent) { 1 } else { viewshed.range }; + let range = if let Some(_is_blind) = blind_entities.get(ent) { + 1 + } else { + if map.overmap { viewshed.range / 2 } else { viewshed.range } + }; let origin = Point::new(pos.x, pos.y); viewshed.visible_tiles = SymmetricShadowcasting.field_of_view(origin, range, &*map); viewshed.visible_tiles.retain(|p| {