133 lines
4.2 KiB
Rust
133 lines
4.2 KiB
Rust
|
use std::collections::HashMap;
|
||
|
|
||
|
use ::rltk::{Point, RandomNumberGenerator};
|
||
|
use ::serde::{Deserialize, Serialize};
|
||
|
use ::specs::prelude::*;
|
||
|
|
||
|
use crate::components::{Position, Viewshed};
|
||
|
use crate::map::{Map, TileType};
|
||
|
use crate::map_builders::level_builder;
|
||
|
|
||
|
#[derive(Default, Serialize, Deserialize, Clone)]
|
||
|
pub struct MasterDungeonMap {
|
||
|
maps: HashMap<i32, Map>,
|
||
|
}
|
||
|
|
||
|
impl MasterDungeonMap {
|
||
|
pub fn new() -> MasterDungeonMap {
|
||
|
MasterDungeonMap {
|
||
|
maps: HashMap::new(),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn store_map(&mut self, map: &Map) {
|
||
|
self.maps.insert(map.depth, map.clone());
|
||
|
}
|
||
|
|
||
|
pub fn get_map(&self, depth: i32) -> Option<Map> {
|
||
|
if self.maps.contains_key(&depth) {
|
||
|
let mut result = self.maps[&depth].clone();
|
||
|
result.tile_content = vec![Vec::new(); (result.width * result.height) as usize];
|
||
|
|
||
|
Some(result)
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn level_transition(ecs: &mut World, new_depth: i32) -> Option<Vec<Map>> {
|
||
|
// Obtain the master dungeon map
|
||
|
let dungeon_master = ecs.read_resource::<MasterDungeonMap>();
|
||
|
|
||
|
// Do we already have a map?
|
||
|
if dungeon_master.get_map(new_depth).is_some() {
|
||
|
std::mem::drop(dungeon_master);
|
||
|
transition_to_existing_map(ecs, new_depth);
|
||
|
|
||
|
None
|
||
|
} else {
|
||
|
std::mem::drop(dungeon_master);
|
||
|
|
||
|
Some(transition_to_new_map(ecs, new_depth))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn transition_to_new_map(ecs: &mut World, new_depth: i32) -> Vec<Map> {
|
||
|
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
|
||
|
let mut builder = level_builder(new_depth, &mut rng, 80, 50);
|
||
|
builder.build_map(&mut rng);
|
||
|
|
||
|
if new_depth > 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::UpStairs;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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();
|
||
|
player_start = *builder.build_data.starting_position.as_mut().unwrap();
|
||
|
}
|
||
|
|
||
|
// Spawn bad guys
|
||
|
std::mem::drop(rng);
|
||
|
builder.spawn_entities(ecs);
|
||
|
|
||
|
// Place the player and update resources
|
||
|
let (player_x, player_y) = (player_start.x, player_start.y);
|
||
|
let mut player_position = ecs.write_resource::<Point>();
|
||
|
*player_position = player_start.into();
|
||
|
|
||
|
let mut position_components = ecs.write_storage::<Position>();
|
||
|
let player_entity = ecs.fetch::<Entity>();
|
||
|
if let Some(player_pos_comp) = position_components.get_mut(*player_entity) {
|
||
|
player_pos_comp.x = player_x;
|
||
|
player_pos_comp.y = player_y;
|
||
|
}
|
||
|
|
||
|
// Mark the player's visiblity as dirty
|
||
|
let mut viewshed_components = ecs.write_storage::<Viewshed>();
|
||
|
if let Some(vs) = viewshed_components.get_mut(*player_entity) {
|
||
|
vs.dirty = true;
|
||
|
}
|
||
|
|
||
|
// Store the newly minted map
|
||
|
let mut dungeon_master = ecs.write_resource::<MasterDungeonMap>();
|
||
|
dungeon_master.store_map(&builder.build_data.map);
|
||
|
|
||
|
mapgen_history
|
||
|
}
|
||
|
|
||
|
fn transition_to_existing_map(ecs: &mut World, new_depth: i32) {
|
||
|
let dungeon_master = ecs.write_resource::<MasterDungeonMap>();
|
||
|
let map = dungeon_master.get_map(new_depth).unwrap();
|
||
|
let mut worldmap_resource = ecs.write_resource::<Map>();
|
||
|
let player_entity = ecs.fetch::<Entity>();
|
||
|
|
||
|
// Find the down stairs and place the player
|
||
|
let w = map.width;
|
||
|
for (idx, tt) in map.tiles.iter().enumerate() {
|
||
|
if *tt == TileType::DownStairs {
|
||
|
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>();
|
||
|
if let Some(player_pos_comp) = position_components.get_mut(*player_entity) {
|
||
|
player_pos_comp.x = idx as i32 % w;
|
||
|
player_pos_comp.y = idx as i32 / w;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*worldmap_resource = map;
|
||
|
|
||
|
// Mark the player's visibility as dirty
|
||
|
let mut viewshed_components = ecs.write_storage::<Viewshed>();
|
||
|
if let Some(vs) = viewshed_components.get_mut(*player_entity) {
|
||
|
vs.dirty = true;
|
||
|
}
|
||
|
}
|