Update random spawning, and create next dungeon level

This commit is contained in:
Timothy Warren 2022-01-28 10:24:00 -05:00
parent 2df20956bb
commit 3b62fd9c20
6 changed files with 134 additions and 11 deletions

View File

@ -9,6 +9,7 @@ mod distant_exit;
mod dla; mod dla;
mod door_placement; mod door_placement;
mod drunkard; mod drunkard;
mod dwarf_fort;
mod forest; mod forest;
mod limestone_cavern; mod limestone_cavern;
mod maze; mod maze;
@ -43,6 +44,7 @@ use distant_exit::DistantExit;
use dla::DLABuilder; use dla::DLABuilder;
use door_placement::DoorPlacement; use door_placement::DoorPlacement;
use drunkard::DrunkardsWalkBuilder; use drunkard::DrunkardsWalkBuilder;
use dwarf_fort::*;
use forest::forest_builder; use forest::forest_builder;
use limestone_cavern::{ use limestone_cavern::{
limestone_cavern_builder, limestone_deep_cavern_builder, limestone_transition_builder, limestone_cavern_builder, limestone_deep_cavern_builder, limestone_transition_builder,
@ -354,6 +356,7 @@ pub fn level_builder(
3 => limestone_cavern_builder(new_depth, rng, width, height), 3 => limestone_cavern_builder(new_depth, rng, width, height),
4 => limestone_deep_cavern_builder(new_depth, rng, width, height), 4 => limestone_deep_cavern_builder(new_depth, rng, width, height),
5 => limestone_transition_builder(new_depth, rng, width, height), 5 => limestone_transition_builder(new_depth, rng, width, height),
6 => dwarf_fort_builder(new_depth, rng, width, height),
_ => random_builder(new_depth, rng, width, height), _ => random_builder(new_depth, rng, width, height),
} }
} }

View File

@ -0,0 +1,69 @@
use ::rltk::RandomNumberGenerator;
use super::{
AreaEndingPosition, AreaStartingPosition, BspCorridors, BspDungeonBuilder, BuilderChain,
BuilderMap, CorridorSpawner, CullUnreachable, DLABuilder, DistantExit, MetaMapBuilder,
RoomDrawer, RoomSort, RoomSorter, VoronoiSpawning, XEnd, XStart, YEnd, YStart,
};
use crate::TileType;
pub fn dwarf_fort_builder(
new_depth: i32,
_rng: &mut RandomNumberGenerator,
width: i32,
height: i32,
) -> BuilderChain {
let mut chain = BuilderChain::new(new_depth, width, height, "Dwarven Fortress");
chain
.start_with(BspDungeonBuilder::new())
.with(RoomSorter::new(RoomSort::Central))
.with(RoomDrawer::new())
.with(BspCorridors::new())
.with(CorridorSpawner::new())
.with(DragonsLair::new())
.with(AreaStartingPosition::new(XStart::Left, YStart::Top))
.with(CullUnreachable::new())
.with(AreaEndingPosition::new(XEnd::Right, YEnd::Bottom))
.with(VoronoiSpawning::new())
.with(DistantExit::new());
chain
}
pub struct DragonsLair {}
impl MetaMapBuilder for DragonsLair {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
impl DragonsLair {
#[allow(dead_code)]
pub fn new() -> Box<DragonsLair> {
Box::new(DragonsLair {})
}
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
build_data.map.depth = 7;
build_data.take_snapshot();
let mut builder = BuilderChain::new(6, build_data.width, build_data.height, "New Map");
builder.start_with(DLABuilder::insectoid());
builder.build_map(rng);
// Add the history to our history
for h in builder.build_data.history.iter() {
build_data.history.push(h.clone());
}
build_data.take_snapshot();
// Merge the maps
for (idx, tt) in build_data.map.tiles.iter_mut().enumerate() {
if *tt == TileType::Wall && builder.build_data.map.tiles[idx] == TileType::Floor {
*tt = TileType::Floor;
}
}
build_data.take_snapshot();
}
}

View File

@ -1,5 +1,7 @@
use ::rltk::RandomNumberGenerator; use ::rltk::RandomNumberGenerator;
use crate::raws::{spawn_type_by_name, RawMaster, SpawnTableType};
pub struct RandomEntry { pub struct RandomEntry {
name: String, name: String,
weight: i32, weight: i32,
@ -14,6 +16,41 @@ impl RandomEntry {
} }
} }
#[derive(Default)]
pub struct MasterTable {
items: RandomTable,
mobs: RandomTable,
props: RandomTable,
}
impl MasterTable {
pub fn new() -> MasterTable {
MasterTable {
items: RandomTable::new(),
mobs: RandomTable::new(),
props: RandomTable::new(),
}
}
pub fn add<S: ToString>(&mut self, name: S, weight: i32, raws: &RawMaster) {
match spawn_type_by_name(raws, &name.to_string()) {
SpawnTableType::Item => self.items.add(name, weight),
SpawnTableType::Mob => self.mobs.add(name, weight),
SpawnTableType::Prop => self.props.add(name, weight),
}
}
pub fn roll(&self, rng: &mut RandomNumberGenerator) -> String {
let roll = rng.roll_dice(1, 4);
match roll {
1 => self.items.roll(rng),
2 => self.props.roll(rng),
3 => self.mobs.roll(rng),
_ => "None".to_string(),
}
}
}
#[derive(Default)] #[derive(Default)]
pub struct RandomTable { pub struct RandomTable {
entries: Vec<RandomEntry>, entries: Vec<RandomEntry>,
@ -28,13 +65,11 @@ impl RandomTable {
} }
} }
pub fn add<S: ToString>(mut self, name: S, weight: i32) -> Self { pub fn add<S: ToString>(&mut self, name: S, weight: i32) {
if weight > 0 { if weight > 0 {
self.total_weight += weight; self.total_weight += weight;
self.entries.push(RandomEntry::new(name, weight)); self.entries.push(RandomEntry::new(name, weight));
} }
self
} }
pub fn roll(&self, rng: &mut RandomNumberGenerator) -> String { pub fn roll(&self, rng: &mut RandomNumberGenerator) -> String {

View File

@ -8,7 +8,7 @@ use ::specs::saveload::{MarkedBuilder, SimpleMarker};
use crate::components::*; use crate::components::*;
use crate::gamesystem::{mana_at_level, npc_hp}; use crate::gamesystem::{mana_at_level, npc_hp};
use crate::map::MasterDungeonMap; use crate::map::MasterDungeonMap;
use crate::random_table::RandomTable; use crate::random_table::{MasterTable, RandomTable};
use crate::raws::{Raws, Reaction, RAWS}; use crate::raws::{Raws, Reaction, RAWS};
pub fn parse_dice_string(dice: &str) -> (i32, i32, i32) { pub fn parse_dice_string(dice: &str) -> (i32, i32, i32) {
@ -755,6 +755,22 @@ pub fn spawn_named_entity(
None None
} }
pub enum SpawnTableType {
Item,
Mob,
Prop,
}
pub fn spawn_type_by_name(raws: &RawMaster, key: &str) -> SpawnTableType {
if raws.item_index.contains_key(key) {
SpawnTableType::Item
} else if raws.mob_index.contains_key(key) {
SpawnTableType::Mob
} else {
SpawnTableType::Prop
}
}
pub fn spawn_named_spell(raws: &RawMaster, ecs: &mut World, key: &str) -> Option<Entity> { pub fn spawn_named_spell(raws: &RawMaster, ecs: &mut World, key: &str) -> Option<Entity> {
if raws.spell_index.contains_key(key) { if raws.spell_index.contains_key(key) {
let spell_template = &raws.raws.spells[raws.spell_index[key]]; let spell_template = &raws.raws.spells[raws.spell_index[key]];
@ -775,7 +791,7 @@ pub fn spawn_named_spell(raws: &RawMaster, ecs: &mut World, key: &str) -> Option
None None
} }
pub fn get_spawn_table_for_depth(raws: &RawMaster, depth: i32) -> RandomTable { pub fn get_spawn_table_for_depth(raws: &RawMaster, depth: i32) -> MasterTable {
use super::SpawnTableEntry; use super::SpawnTableEntry;
let available_options: Vec<&SpawnTableEntry> = raws let available_options: Vec<&SpawnTableEntry> = raws
@ -785,13 +801,13 @@ pub fn get_spawn_table_for_depth(raws: &RawMaster, depth: i32) -> RandomTable {
.filter(|a| depth >= a.min_depth && depth <= a.max_depth) .filter(|a| depth >= a.min_depth && depth <= a.max_depth)
.collect(); .collect();
let mut rt = RandomTable::new(); let mut rt = MasterTable::new();
for e in available_options.iter() { for e in available_options.iter() {
let mut weight = e.weight; let mut weight = e.weight;
if e.add_map_depth_to_weight.is_some() { if e.add_map_depth_to_weight.is_some() {
weight += depth; weight += depth;
} }
rt = rt.add(e.name.clone(), weight); rt.add(e.name.clone(), weight, raws);
} }
rt rt
@ -806,7 +822,7 @@ pub fn get_item_drop(
let mut rt = RandomTable::new(); let mut rt = RandomTable::new();
let available_options = &raws.raws.loot_tables[raws.loot_index[table]]; let available_options = &raws.raws.loot_tables[raws.loot_index[table]];
for item in available_options.drops.iter() { for item in available_options.drops.iter() {
rt = rt.add(item.name.clone(), item.weight); rt.add(item.name.clone(), item.weight);
} }
return Some(rt.roll(rng)); return Some(rt.roll(rng));

View File

@ -5,7 +5,7 @@ use ::specs::prelude::*;
use ::specs::saveload::{MarkedBuilder, SimpleMarker}; use ::specs::saveload::{MarkedBuilder, SimpleMarker};
use crate::components::*; use crate::components::*;
use crate::random_table::RandomTable; use crate::random_table::MasterTable;
use crate::raws::{ use crate::raws::{
get_spawn_table_for_depth, spawn_all_spells, spawn_named_entity, SpawnType, RAWS, get_spawn_table_for_depth, spawn_all_spells, spawn_named_entity, SpawnType, RAWS,
}; };
@ -70,7 +70,7 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
const MAX_MONSTERS: i32 = 4; const MAX_MONSTERS: i32 = 4;
fn room_table(map_depth: i32) -> RandomTable { fn room_table(map_depth: i32) -> MasterTable {
get_spawn_table_for_depth(&RAWS.lock().unwrap(), map_depth) get_spawn_table_for_depth(&RAWS.lock().unwrap(), map_depth)
} }

View File

@ -23,7 +23,7 @@ use crate::visibility_system::VisibilitySystem;
use crate::{ai, camera, damage_system, effects, saveload_system, spawner}; use crate::{ai, camera, damage_system, effects, saveload_system, spawner};
/// Whether to show a visual representation of map generation /// Whether to show a visual representation of map generation
pub const SHOW_MAPGEN_VISUALIZER: bool = false; pub const SHOW_MAPGEN_VISUALIZER: bool = true;
/// The main actions possible with a vendor /// The main actions possible with a vendor
#[derive(PartialEq, Copy, Clone)] #[derive(PartialEq, Copy, Clone)]