From 3b62fd9c20b70e34fa0677748559764627d2537e Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Fri, 28 Jan 2022 10:24:00 -0500 Subject: [PATCH] Update random spawning, and create next dungeon level --- src/map_builders.rs | 3 ++ src/map_builders/dwarf_fort.rs | 69 ++++++++++++++++++++++++++++++++++ src/random_table.rs | 41 ++++++++++++++++++-- src/raws/rawmaster.rs | 26 ++++++++++--- src/spawner.rs | 4 +- src/state.rs | 2 +- 6 files changed, 134 insertions(+), 11 deletions(-) create mode 100644 src/map_builders/dwarf_fort.rs diff --git a/src/map_builders.rs b/src/map_builders.rs index 28c0eb4..f0b38fb 100644 --- a/src/map_builders.rs +++ b/src/map_builders.rs @@ -9,6 +9,7 @@ mod distant_exit; mod dla; mod door_placement; mod drunkard; +mod dwarf_fort; mod forest; mod limestone_cavern; mod maze; @@ -43,6 +44,7 @@ use distant_exit::DistantExit; use dla::DLABuilder; use door_placement::DoorPlacement; use drunkard::DrunkardsWalkBuilder; +use dwarf_fort::*; use forest::forest_builder; use limestone_cavern::{ 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), 4 => limestone_deep_cavern_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), } } diff --git a/src/map_builders/dwarf_fort.rs b/src/map_builders/dwarf_fort.rs new file mode 100644 index 0000000..5096871 --- /dev/null +++ b/src/map_builders/dwarf_fort.rs @@ -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 { + 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(); + } +} diff --git a/src/random_table.rs b/src/random_table.rs index 4f536f2..a292bde 100644 --- a/src/random_table.rs +++ b/src/random_table.rs @@ -1,5 +1,7 @@ use ::rltk::RandomNumberGenerator; +use crate::raws::{spawn_type_by_name, RawMaster, SpawnTableType}; + pub struct RandomEntry { name: String, 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(&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)] pub struct RandomTable { entries: Vec, @@ -28,13 +65,11 @@ impl RandomTable { } } - pub fn add(mut self, name: S, weight: i32) -> Self { + pub fn add(&mut self, name: S, weight: i32) { if weight > 0 { self.total_weight += weight; self.entries.push(RandomEntry::new(name, weight)); } - - self } pub fn roll(&self, rng: &mut RandomNumberGenerator) -> String { diff --git a/src/raws/rawmaster.rs b/src/raws/rawmaster.rs index 2dea6ac..ca756b0 100644 --- a/src/raws/rawmaster.rs +++ b/src/raws/rawmaster.rs @@ -8,7 +8,7 @@ use ::specs::saveload::{MarkedBuilder, SimpleMarker}; use crate::components::*; use crate::gamesystem::{mana_at_level, npc_hp}; use crate::map::MasterDungeonMap; -use crate::random_table::RandomTable; +use crate::random_table::{MasterTable, RandomTable}; use crate::raws::{Raws, Reaction, RAWS}; pub fn parse_dice_string(dice: &str) -> (i32, i32, i32) { @@ -755,6 +755,22 @@ pub fn spawn_named_entity( 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 { if raws.spell_index.contains_key(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 } -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; 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) .collect(); - let mut rt = RandomTable::new(); + let mut rt = MasterTable::new(); for e in available_options.iter() { let mut weight = e.weight; if e.add_map_depth_to_weight.is_some() { weight += depth; } - rt = rt.add(e.name.clone(), weight); + rt.add(e.name.clone(), weight, raws); } rt @@ -806,7 +822,7 @@ pub fn get_item_drop( let mut rt = RandomTable::new(); let available_options = &raws.raws.loot_tables[raws.loot_index[table]]; 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)); diff --git a/src/spawner.rs b/src/spawner.rs index e40bee9..41af50b 100644 --- a/src/spawner.rs +++ b/src/spawner.rs @@ -5,7 +5,7 @@ use ::specs::prelude::*; use ::specs::saveload::{MarkedBuilder, SimpleMarker}; use crate::components::*; -use crate::random_table::RandomTable; +use crate::random_table::MasterTable; use crate::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; -fn room_table(map_depth: i32) -> RandomTable { +fn room_table(map_depth: i32) -> MasterTable { get_spawn_table_for_depth(&RAWS.lock().unwrap(), map_depth) } diff --git a/src/state.rs b/src/state.rs index e285968..f0b0222 100644 --- a/src/state.rs +++ b/src/state.rs @@ -23,7 +23,7 @@ use crate::visibility_system::VisibilitySystem; use crate::{ai, camera, damage_system, effects, saveload_system, spawner}; /// 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 #[derive(PartialEq, Copy, Clone)]