Refactors worldmap gen, now uses a master list of maps for backtracking
This commit is contained in:
parent
557b7095b9
commit
25befa9343
7 changed files with 119 additions and 48 deletions
51
src/main.rs
51
src/main.rs
|
|
@ -81,50 +81,9 @@ impl State {
|
||||||
self.mapgen_index = 0;
|
self.mapgen_index = 0;
|
||||||
self.mapgen_timer = 0.0;
|
self.mapgen_timer = 0.0;
|
||||||
self.mapgen_history.clear();
|
self.mapgen_history.clear();
|
||||||
let mut rng = self.ecs.write_resource::<rltk::RandomNumberGenerator>();
|
let map_building_info = map::level_transition(&mut self.ecs, new_id);
|
||||||
let mut player_level = 1;
|
if let Some(history) = map_building_info {
|
||||||
{
|
self.mapgen_history = history;
|
||||||
let player = self.ecs.read_storage::<Player>();
|
|
||||||
let pools = self.ecs.read_storage::<Pools>();
|
|
||||||
for (_p, pool) in (&player, &pools).join() {
|
|
||||||
player_level = pool.level;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut builder = map_builders::level_builder(new_id, &mut rng, 100, 50, player_level);
|
|
||||||
builder.build_map(&mut rng);
|
|
||||||
std::mem::drop(rng);
|
|
||||||
self.mapgen_history = builder.build_data.history.clone();
|
|
||||||
let player_start;
|
|
||||||
{
|
|
||||||
let mut worldmap_resource = self.ecs.write_resource::<Map>();
|
|
||||||
*worldmap_resource = builder.build_data.map.clone();
|
|
||||||
// Unwrap so we get a CTD if there's no starting pos.
|
|
||||||
player_start = builder.build_data.starting_position.as_mut().unwrap().clone();
|
|
||||||
}
|
|
||||||
// Spawn entities
|
|
||||||
builder.spawn_entities(&mut self.ecs);
|
|
||||||
|
|
||||||
// Place player and update resources
|
|
||||||
let mut player_position = self.ecs.write_resource::<Point>();
|
|
||||||
*player_position = Point::new(player_start.x, player_start.y);
|
|
||||||
let mut position_components = self.ecs.write_storage::<Position>();
|
|
||||||
let player_entity = self.ecs.fetch::<Entity>();
|
|
||||||
let player_pos_component = position_components.get_mut(*player_entity);
|
|
||||||
if let Some(player_pos_component) = player_pos_component {
|
|
||||||
player_pos_component.x = player_start.x;
|
|
||||||
player_pos_component.y = player_start.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark viewshed as dirty (force refresh)
|
|
||||||
let mut viewshed_components = self.ecs.write_storage::<Viewshed>();
|
|
||||||
let mut telepath_components = self.ecs.write_storage::<Telepath>();
|
|
||||||
let vision_vs = viewshed_components.get_mut(*player_entity);
|
|
||||||
let telepath_vs = telepath_components.get_mut(*player_entity);
|
|
||||||
if let Some(vs) = vision_vs {
|
|
||||||
vs.dirty = true;
|
|
||||||
}
|
|
||||||
if let Some(vs) = telepath_vs {
|
|
||||||
vs.dirty = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -266,6 +225,8 @@ impl State {
|
||||||
let mut player_entity_writer = self.ecs.write_resource::<Entity>();
|
let mut player_entity_writer = self.ecs.write_resource::<Entity>();
|
||||||
*player_entity_writer = player_entity;
|
*player_entity_writer = player_entity;
|
||||||
}
|
}
|
||||||
|
// Replace map list
|
||||||
|
self.ecs.insert(map::dungeon::MasterDungeonMap::new());
|
||||||
self.generate_world_map(1);
|
self.generate_world_map(1);
|
||||||
|
|
||||||
gamelog::setup_log();
|
gamelog::setup_log();
|
||||||
|
|
@ -615,7 +576,9 @@ fn main() -> rltk::BError {
|
||||||
|
|
||||||
raws::load_raws();
|
raws::load_raws();
|
||||||
|
|
||||||
|
// Insert calls
|
||||||
gs.ecs.insert(rltk::RandomNumberGenerator::new());
|
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(1, 64, 64, 0, "New Map")); // Map
|
||||||
gs.ecs.insert(Point::new(0, 0)); // Player pos
|
gs.ecs.insert(Point::new(0, 0)); // Player pos
|
||||||
let player_entity = spawner::player(&mut gs.ecs, 0, 0);
|
let player_entity = spawner::player(&mut gs.ecs, 0, 0);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ pub const BLOODSTAIN_COLOUR: (u8, u8, u8) = (153, 0, 0);
|
||||||
pub const DEFAULT_BG_COLOUR: (u8, u8, u8) = (29, 50, 50);
|
pub const DEFAULT_BG_COLOUR: (u8, u8, u8) = (29, 50, 50);
|
||||||
pub const WALL_COLOUR: (u8, u8, u8) = (229, 191, 94);
|
pub const WALL_COLOUR: (u8, u8, u8) = (229, 191, 94);
|
||||||
pub const FLOOR_COLOUR: (u8, u8, u8) = (25, 204, 122);
|
pub const FLOOR_COLOUR: (u8, u8, u8) = (25, 204, 122);
|
||||||
pub const DOWN_STAIR_COLOUR: (u8, u8, u8) = (200, 200, 0);
|
pub const STAIR_COLOUR: (u8, u8, u8) = (200, 200, 0);
|
||||||
pub const WOOD_FLOOR_COLOUR: (u8, u8, u8) = (41, 30, 20);
|
pub const WOOD_FLOOR_COLOUR: (u8, u8, u8) = (41, 30, 20);
|
||||||
pub const FENCE_FG_COLOUR: (u8, u8, u8) = (110, 24, 0);
|
pub const FENCE_FG_COLOUR: (u8, u8, u8) = (110, 24, 0);
|
||||||
pub const FENCE_COLOUR: (u8, u8, u8) = (45, 30, 10);
|
pub const FENCE_COLOUR: (u8, u8, u8) = (45, 30, 10);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
use super::Map;
|
use super::{Map, TileType};
|
||||||
|
use crate::{gamelog, map_builders, Position, Telepath, Viewshed};
|
||||||
|
use rltk::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use specs::prelude::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize, Clone)]
|
#[derive(Default, Serialize, Deserialize, Clone)]
|
||||||
|
|
@ -27,3 +30,103 @@ impl MasterDungeonMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn level_transition(ecs: &mut World, new_id: i32) -> Option<Vec<Map>> {
|
||||||
|
// Obtain master
|
||||||
|
let dungeon_master = ecs.read_resource::<MasterDungeonMap>();
|
||||||
|
if dungeon_master.get_map(new_id).is_some() {
|
||||||
|
std::mem::drop(dungeon_master);
|
||||||
|
transition_to_existing_map(ecs, new_id);
|
||||||
|
return None;
|
||||||
|
} else {
|
||||||
|
std::mem::drop(dungeon_master);
|
||||||
|
return Some(transition_to_new_map(ecs, new_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transition_to_existing_map(ecs: &mut World, new_id: i32) {
|
||||||
|
let dungeon_master = ecs.read_resource::<MasterDungeonMap>();
|
||||||
|
// Unwrapping here panics if new_id isn't present. But this should
|
||||||
|
// never be called without new_id being present by level_transition.
|
||||||
|
let map = dungeon_master.get_map(new_id).unwrap();
|
||||||
|
let mut worldmap_resource = ecs.write_resource::<Map>();
|
||||||
|
let player_entity = ecs.fetch::<Entity>();
|
||||||
|
// Find down stairs, place player
|
||||||
|
let w = map.width;
|
||||||
|
for (idx, tt) in map.tiles.iter().enumerate() {
|
||||||
|
if *tt == TileType::DownStair {
|
||||||
|
let mut player_position = ecs.write_resource::<Point>();
|
||||||
|
*player_position = Point::new(idx as i32 % w, idx as i32 / w);
|
||||||
|
let mut position_components = ecs.write_storage::<Position>();
|
||||||
|
let player_pos_component = position_components.get_mut(*player_entity);
|
||||||
|
if let Some(player_pos_component) = player_pos_component {
|
||||||
|
player_pos_component.x = idx as i32 % w;
|
||||||
|
player_pos_component.y = idx as i32 / w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*worldmap_resource = map;
|
||||||
|
// Dirtify viewsheds (forces refresh)
|
||||||
|
let mut viewshed_components = ecs.write_storage::<Viewshed>();
|
||||||
|
let mut telepath_components = ecs.write_storage::<Telepath>();
|
||||||
|
let vision_vs = viewshed_components.get_mut(*player_entity);
|
||||||
|
let telepath_vs = telepath_components.get_mut(*player_entity);
|
||||||
|
if let Some(vs) = vision_vs {
|
||||||
|
vs.dirty = true;
|
||||||
|
}
|
||||||
|
if let Some(vs) = telepath_vs {
|
||||||
|
vs.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transition_to_new_map(ecs: &mut World, new_id: i32) -> Vec<Map> {
|
||||||
|
let mut rng = ecs.write_resource::<rltk::RandomNumberGenerator>();
|
||||||
|
// Might need this to fallback to 1, but if player
|
||||||
|
// level isn't found at all, there's a bigger concern
|
||||||
|
// concern than just this function not working.
|
||||||
|
let player_level = gamelog::get_event_count("player_level");
|
||||||
|
let mut builder = map_builders::level_builder(new_id, &mut rng, 100, 50, player_level);
|
||||||
|
builder.build_map(&mut rng);
|
||||||
|
std::mem::drop(rng);
|
||||||
|
if new_id > 1 {
|
||||||
|
if let Some(pos) = &builder.build_data.starting_position {
|
||||||
|
let up_idx = builder.build_data.map.xy_idx(pos.x, pos.y);
|
||||||
|
builder.build_data.map.tiles[up_idx] = TileType::UpStair;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mapgen_history = builder.build_data.history.clone();
|
||||||
|
let player_start;
|
||||||
|
{
|
||||||
|
let mut worldmap_resource = ecs.write_resource::<Map>();
|
||||||
|
*worldmap_resource = builder.build_data.map.clone();
|
||||||
|
// Unwrap so we get a CTD if there's no starting pos.
|
||||||
|
player_start = builder.build_data.starting_position.as_mut().unwrap().clone();
|
||||||
|
}
|
||||||
|
// Spawn entities
|
||||||
|
builder.spawn_entities(ecs);
|
||||||
|
// Place player and update resources
|
||||||
|
let mut player_position = ecs.write_resource::<Point>();
|
||||||
|
*player_position = Point::new(player_start.x, player_start.y);
|
||||||
|
let mut position_components = ecs.write_storage::<Position>();
|
||||||
|
let player_entity = ecs.fetch::<Entity>();
|
||||||
|
let player_pos_component = position_components.get_mut(*player_entity);
|
||||||
|
if let Some(player_pos_component) = player_pos_component {
|
||||||
|
player_pos_component.x = player_start.x;
|
||||||
|
player_pos_component.y = player_start.y;
|
||||||
|
}
|
||||||
|
// Mark viewshed as dirty (force refresh)
|
||||||
|
let mut viewshed_components = ecs.write_storage::<Viewshed>();
|
||||||
|
let mut telepath_components = ecs.write_storage::<Telepath>();
|
||||||
|
let vision_vs = viewshed_components.get_mut(*player_entity);
|
||||||
|
let telepath_vs = telepath_components.get_mut(*player_entity);
|
||||||
|
if let Some(vs) = vision_vs {
|
||||||
|
vs.dirty = true;
|
||||||
|
}
|
||||||
|
if let Some(vs) = telepath_vs {
|
||||||
|
vs.dirty = true;
|
||||||
|
}
|
||||||
|
// Store newly minted map
|
||||||
|
let mut dungeon_master = ecs.write_resource::<MasterDungeonMap>();
|
||||||
|
dungeon_master.store_map(&builder.build_data.map);
|
||||||
|
return mapgen_history;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
pub const WALL_GLYPH: char = '#';
|
pub const WALL_GLYPH: char = '#';
|
||||||
pub const FLOOR_GLYPH: char = '.';
|
pub const FLOOR_GLYPH: char = '.';
|
||||||
pub const DOWN_STAIR_GLYPH: char = '>';
|
pub const DOWN_STAIR_GLYPH: char = '>';
|
||||||
|
pub const UP_STAIR_GLYPH: char = '<';
|
||||||
pub const WOOD_FLOOR_GLYPH: char = '.';
|
pub const WOOD_FLOOR_GLYPH: char = '.';
|
||||||
pub const FENCE_GLYPH: char = '=';
|
pub const FENCE_GLYPH: char = '=';
|
||||||
pub const BRIDGE_GLYPH: char = '.';
|
pub const BRIDGE_GLYPH: char = '.';
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ pub use tiletype::{tile_cost, tile_opaque, tile_walkable, TileType};
|
||||||
mod interval_spawning_system;
|
mod interval_spawning_system;
|
||||||
pub use interval_spawning_system::try_spawn_interval;
|
pub use interval_spawning_system::try_spawn_interval;
|
||||||
pub mod dungeon;
|
pub mod dungeon;
|
||||||
|
pub use dungeon::{level_transition, MasterDungeonMap};
|
||||||
pub mod themes;
|
pub mod themes;
|
||||||
|
|
||||||
// FIXME: If the map size gets too small, entities stop being rendered starting from the right.
|
// FIXME: If the map size gets too small, entities stop being rendered starting from the right.
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@ pub fn get_default_theme_renderables(idx: usize, map: &Map) -> (rltk::FontCharTy
|
||||||
TileType::WoodFloor => { glyph = rltk::to_cp437(WOOD_FLOOR_GLYPH); bg = RGB::named(WOOD_FLOOR_COLOUR); }
|
TileType::WoodFloor => { glyph = rltk::to_cp437(WOOD_FLOOR_GLYPH); bg = RGB::named(WOOD_FLOOR_COLOUR); }
|
||||||
TileType::Fence => { glyph = rltk::to_cp437(FENCE_GLYPH); fg = RGB::named(FENCE_FG_COLOUR); bg = RGB::named(FENCE_COLOUR); }
|
TileType::Fence => { glyph = rltk::to_cp437(FENCE_GLYPH); fg = RGB::named(FENCE_FG_COLOUR); bg = RGB::named(FENCE_COLOUR); }
|
||||||
TileType::Wall => { let x = idx as i32 % map.width; let y = idx as i32 / map.width; glyph = wall_glyph(&*map, x, y); fg = RGB::named(WALL_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); }
|
TileType::Wall => { let x = idx as i32 % map.width; let y = idx as i32 / map.width; glyph = wall_glyph(&*map, x, y); fg = RGB::named(WALL_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); }
|
||||||
TileType::DownStair => { glyph = rltk::to_cp437(DOWN_STAIR_GLYPH); fg = RGB::named(DOWN_STAIR_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); }
|
TileType::DownStair => { glyph = rltk::to_cp437(DOWN_STAIR_GLYPH); fg = RGB::named(STAIR_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); }
|
||||||
|
TileType::UpStair => { glyph = rltk::to_cp437(UP_STAIR_GLYPH); fg = RGB::named(STAIR_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); }
|
||||||
TileType::Bridge => { glyph = rltk::to_cp437(BRIDGE_GLYPH); bg = RGB::named(BRIDGE_COLOUR); }
|
TileType::Bridge => { glyph = rltk::to_cp437(BRIDGE_GLYPH); bg = RGB::named(BRIDGE_COLOUR); }
|
||||||
TileType::Gravel => { glyph = rltk::to_cp437(GRAVEL_GLYPH); bg = RGB::named(GRAVEL_COLOUR); }
|
TileType::Gravel => { glyph = rltk::to_cp437(GRAVEL_GLYPH); bg = RGB::named(GRAVEL_COLOUR); }
|
||||||
TileType::Road => { glyph = rltk::to_cp437(ROAD_GLYPH); bg = RGB::named(ROAD_COLOUR); }
|
TileType::Road => { glyph = rltk::to_cp437(ROAD_GLYPH); bg = RGB::named(ROAD_COLOUR); }
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ pub enum TileType {
|
||||||
Bridge,
|
Bridge,
|
||||||
// Stairs (changes floor)
|
// Stairs (changes floor)
|
||||||
DownStair,
|
DownStair,
|
||||||
|
UpStair,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tile_walkable(tt: TileType) -> bool {
|
pub fn tile_walkable(tt: TileType) -> bool {
|
||||||
|
|
@ -35,7 +36,8 @@ pub fn tile_walkable(tt: TileType) -> bool {
|
||||||
| TileType::Sand
|
| TileType::Sand
|
||||||
| TileType::ShallowWater
|
| TileType::ShallowWater
|
||||||
| TileType::Bridge
|
| TileType::Bridge
|
||||||
| TileType::DownStair => true,
|
| TileType::DownStair
|
||||||
|
| TileType::UpStair => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue