Refactor entity (Enemy, Item, Equipment) spawning

This commit is contained in:
Timothy Warren 2021-12-10 16:34:11 -05:00
parent 8bf63ad876
commit 28692ec50c
11 changed files with 159 additions and 76 deletions

View File

@ -10,7 +10,7 @@ mod simple_map;
mod voronoi;
mod waveform_collapse;
use crate::{Map, Position};
use crate::{spawner, Map, Position};
use bsp_dungeon::BspDungeonBuilder;
use bsp_interior::BspInteriorBuilder;
use cellular_automata::CellularAutomataBuilder;
@ -29,8 +29,14 @@ pub trait MapBuilder {
fn get_starting_position(&self) -> Position;
fn get_snapshot_history(&self) -> Vec<Map>;
fn build_map(&mut self);
fn spawn_entities(&mut self, ecs: &mut World);
fn take_snapshot(&mut self);
fn get_spawn_list(&self) -> &Vec<(usize, String)>;
fn spawn_entities(&mut self, ecs: &mut World) {
for entity in self.get_spawn_list().iter() {
spawner::spawn_entity(ecs, &(&entity.0, &entity.1));
}
}
}
pub fn random_builder(new_depth: i32) -> Box<dyn MapBuilder> {
@ -60,5 +66,8 @@ pub fn random_builder(new_depth: i32) -> Box<dyn MapBuilder> {
//
// result
Box::new(PrefabBuilder::new(new_depth))
Box::new(PrefabBuilder::new(
new_depth,
Some(Box::new(CellularAutomataBuilder::new(new_depth))),
))
}

View File

@ -12,6 +12,7 @@ pub struct BspDungeonBuilder {
rooms: Vec<Rect>,
history: Vec<Map>,
rects: Vec<Rect>,
spawn_list: Vec<(usize, String)>,
}
impl MapBuilder for BspDungeonBuilder {
@ -31,12 +32,6 @@ impl MapBuilder for BspDungeonBuilder {
self.build();
}
fn spawn_entities(&mut self, ecs: &mut World) {
for room in self.rooms.iter().skip(1) {
spawner::spawn_room(ecs, room, self.depth);
}
}
fn take_snapshot(&mut self) {
if SHOW_MAPGEN_VISUALIZER {
let mut snapshot = self.map.clone();
@ -47,6 +42,10 @@ impl MapBuilder for BspDungeonBuilder {
self.history.push(snapshot);
}
}
fn get_spawn_list(&self) -> &Vec<(usize, String)> {
&self.spawn_list
}
}
impl BspDungeonBuilder {
@ -58,6 +57,7 @@ impl BspDungeonBuilder {
rooms: Vec::new(),
history: Vec::new(),
rects: Vec::new(),
spawn_list: Vec::new(),
}
}
@ -113,6 +113,11 @@ impl BspDungeonBuilder {
self.map.tiles[stairs_idx] = TileType::DownStairs;
self.starting_position = Position::from(self.rooms[0].center());
// Spawn some entities
for room in self.rooms.iter().skip(1) {
spawner::spawn_room(&self.map, &mut rng, room, self.depth, &mut self.spawn_list);
}
}
fn add_subrects(&mut self, rect: Rect) {

View File

@ -13,6 +13,7 @@ pub struct BspInteriorBuilder {
rooms: Vec<Rect>,
history: Vec<Map>,
rects: Vec<Rect>,
spawn_list: Vec<(usize, String)>,
}
impl MapBuilder for BspInteriorBuilder {
@ -32,12 +33,6 @@ impl MapBuilder for BspInteriorBuilder {
self.build();
}
fn spawn_entities(&mut self, ecs: &mut World) {
for room in self.rooms.iter().skip(1) {
spawner::spawn_room(ecs, room, self.depth);
}
}
fn take_snapshot(&mut self) {
if SHOW_MAPGEN_VISUALIZER {
let mut snapshot = self.map.clone();
@ -47,17 +42,22 @@ impl MapBuilder for BspInteriorBuilder {
self.history.push(snapshot);
}
}
fn get_spawn_list(&self) -> &Vec<(usize, String)> {
&self.spawn_list
}
}
impl BspInteriorBuilder {
pub fn new(new_depth: i32) -> BspInteriorBuilder {
BspInteriorBuilder {
map: Map::new(new_depth),
starting_position: Position { x: 0, y: 0 },
starting_position: Position::default(),
depth: new_depth,
rooms: Vec::new(),
history: Vec::new(),
rects: Vec::new(),
spawn_list: Vec::new(),
}
}
@ -113,8 +113,12 @@ impl BspInteriorBuilder {
let stairs_idx = self.map.xy_idx(stairs.0, stairs.1);
self.map.tiles[stairs_idx] = TileType::DownStairs;
let start = self.rooms[0].center();
self.starting_position = start.into();
self.starting_position = Position::from(self.rooms[0].center());
// Spawn some entities
for room in self.rooms.iter().skip(1) {
spawner::spawn_room(&self.map, &mut rng, room, self.depth, &mut self.spawn_list);
}
}
fn add_subrects(&mut self, rect: Rect, rng: &mut RandomNumberGenerator) {

View File

@ -13,6 +13,7 @@ pub struct CellularAutomataBuilder {
depth: i32,
history: Vec<Map>,
noise_areas: HashMap<i32, Vec<usize>>,
spawn_list: Vec<(usize, String)>,
}
impl MapBuilder for CellularAutomataBuilder {
@ -32,12 +33,6 @@ impl MapBuilder for CellularAutomataBuilder {
self.build();
}
fn spawn_entities(&mut self, ecs: &mut World) {
for area in self.noise_areas.iter() {
spawner::spawn_region(ecs, area.1, self.depth);
}
}
fn take_snapshot(&mut self) {
if SHOW_MAPGEN_VISUALIZER {
let mut snapshot = self.map.clone();
@ -48,6 +43,10 @@ impl MapBuilder for CellularAutomataBuilder {
self.history.push(snapshot);
}
}
fn get_spawn_list(&self) -> &Vec<(usize, String)> {
&self.spawn_list
}
}
impl CellularAutomataBuilder {
@ -58,6 +57,7 @@ impl CellularAutomataBuilder {
depth: new_depth,
history: Vec::new(),
noise_areas: HashMap::new(),
spawn_list: Vec::new(),
}
}
@ -151,5 +151,16 @@ impl CellularAutomataBuilder {
// Now we build a noise map for use in spawning entities later
self.noise_areas = generate_voronoi_spawn_regions(&self.map, &mut rng);
// Spawn the entities
for area in self.noise_areas.iter() {
spawner::spawn_region(
&self.map,
&mut rng,
area.1,
self.depth,
&mut self.spawn_list,
);
}
}
}

View File

@ -25,6 +25,7 @@ pub struct DLABuilder {
brush_size: i32,
symmetry: Symmetry,
floor_percent: f32,
spawn_list: Vec<(usize, String)>,
}
impl MapBuilder for DLABuilder {
@ -44,12 +45,6 @@ impl MapBuilder for DLABuilder {
self.build();
}
fn spawn_entities(&mut self, ecs: &mut World) {
for area in self.noise_areas.iter() {
spawner::spawn_region(ecs, area.1, self.depth);
}
}
fn take_snapshot(&mut self) {
if SHOW_MAPGEN_VISUALIZER {
let mut snapshot = self.map.clone();
@ -59,6 +54,10 @@ impl MapBuilder for DLABuilder {
self.history.push(snapshot);
}
}
fn get_spawn_list(&self) -> &Vec<(usize, String)> {
&self.spawn_list
}
}
impl DLABuilder {
@ -73,6 +72,7 @@ impl DLABuilder {
brush_size: 1,
symmetry: Symmetry::None,
floor_percent: 0.25,
spawn_list: Vec::new(),
}
}
@ -280,5 +280,16 @@ impl DLABuilder {
// Now we build a noise map for use in spawning entities later
self.noise_areas = generate_voronoi_spawn_regions(&self.map, &mut rng);
// Spawn the entities
for area in self.noise_areas.iter() {
spawner::spawn_region(
&self.map,
&mut rng,
area.1,
self.depth,
&mut self.spawn_list,
);
}
}
}

View File

@ -29,6 +29,7 @@ pub struct DrunkardsWalkBuilder {
history: Vec<Map>,
noise_areas: HashMap<i32, Vec<usize>>,
settings: DrunkardSettings,
spawn_list: Vec<(usize, String)>,
}
impl MapBuilder for DrunkardsWalkBuilder {
@ -48,12 +49,6 @@ impl MapBuilder for DrunkardsWalkBuilder {
self.build();
}
fn spawn_entities(&mut self, ecs: &mut World) {
for area in self.noise_areas.iter() {
spawner::spawn_region(ecs, area.1, self.depth);
}
}
fn take_snapshot(&mut self) {
if SHOW_MAPGEN_VISUALIZER {
let mut snapshot = self.map.clone();
@ -63,6 +58,10 @@ impl MapBuilder for DrunkardsWalkBuilder {
self.history.push(snapshot);
}
}
fn get_spawn_list(&self) -> &Vec<(usize, String)> {
&self.spawn_list
}
}
impl DrunkardsWalkBuilder {
@ -74,6 +73,7 @@ impl DrunkardsWalkBuilder {
history: Vec::new(),
noise_areas: HashMap::new(),
settings,
spawn_list: Vec::new(),
}
}
@ -265,5 +265,16 @@ impl DrunkardsWalkBuilder {
// Now we build a noise map for use in spawning entities later
self.noise_areas = generate_voronoi_spawn_regions(&self.map, &mut rng);
// Spawn the entities
for area in self.noise_areas.iter() {
spawner::spawn_region(
&self.map,
&mut rng,
area.1,
self.depth,
&mut self.spawn_list,
);
}
}
}

View File

@ -12,6 +12,7 @@ pub struct MazeBuilder {
depth: i32,
history: Vec<Map>,
noise_areas: HashMap<i32, Vec<usize>>,
spawn_list: Vec<(usize, String)>,
}
impl MapBuilder for MazeBuilder {
@ -31,12 +32,6 @@ impl MapBuilder for MazeBuilder {
self.build();
}
fn spawn_entities(&mut self, ecs: &mut World) {
for area in self.noise_areas.iter() {
spawner::spawn_region(ecs, area.1, self.depth);
}
}
fn take_snapshot(&mut self) {
if SHOW_MAPGEN_VISUALIZER {
let mut snapshot = self.map.clone();
@ -46,16 +41,21 @@ impl MapBuilder for MazeBuilder {
self.history.push(snapshot);
}
}
fn get_spawn_list(&self) -> &Vec<(usize, String)> {
&self.spawn_list
}
}
impl MazeBuilder {
pub fn new(new_depth: i32) -> MazeBuilder {
MazeBuilder {
map: Map::new(new_depth),
starting_position: Position { x: 0, y: 0 },
starting_position: Position::default(),
depth: new_depth,
history: Vec::new(),
noise_areas: HashMap::new(),
spawn_list: Vec::new(),
}
}

View File

@ -10,6 +10,7 @@ pub struct SimpleMapBuilder {
depth: i32,
rooms: Vec<Rect>,
history: Vec<Map>,
spawn_list: Vec<(usize, String)>,
}
impl MapBuilder for SimpleMapBuilder {
@ -29,12 +30,6 @@ impl MapBuilder for SimpleMapBuilder {
self.rooms_and_corridors();
}
fn spawn_entities(&mut self, ecs: &mut World) {
for room in self.rooms.iter().skip(1) {
spawner::spawn_room(ecs, room, self.depth);
}
}
fn take_snapshot(&mut self) {
if SHOW_MAPGEN_VISUALIZER {
let mut snapshot = self.map.clone();
@ -44,6 +39,10 @@ impl MapBuilder for SimpleMapBuilder {
self.history.push(snapshot);
}
}
fn get_spawn_list(&self) -> &Vec<(usize, String)> {
&self.spawn_list
}
}
impl SimpleMapBuilder {
@ -54,6 +53,7 @@ impl SimpleMapBuilder {
depth: new_depth,
rooms: Vec::new(),
history: Vec::new(),
spawn_list: Vec::new(),
}
}
@ -104,10 +104,11 @@ impl SimpleMapBuilder {
let stairs_idx = self.map.xy_idx(stairs_position.0, stairs_position.1);
self.map.tiles[stairs_idx] = TileType::DownStairs;
let start_pos = self.rooms[0].center();
self.starting_position = Position {
x: start_pos.0,
y: start_pos.1,
};
self.starting_position = Position::from(self.rooms[0].center());
// Spawn some entities
for room in self.rooms.iter().skip(1) {
spawner::spawn_room(&self.map, &mut rng, room, self.depth, &mut self.spawn_list);
}
}
}

View File

@ -23,6 +23,7 @@ pub struct VoronoiCellBuilder {
noise_areas: HashMap<i32, Vec<usize>>,
n_seeds: usize,
distance_algorithm: DistanceAlgorithm,
spawn_list: Vec<(usize, String)>,
}
impl MapBuilder for VoronoiCellBuilder {
@ -42,12 +43,6 @@ impl MapBuilder for VoronoiCellBuilder {
self.build();
}
fn spawn_entities(&mut self, ecs: &mut World) {
for area in self.noise_areas.iter() {
spawner::spawn_region(ecs, area.1, self.depth);
}
}
fn take_snapshot(&mut self) {
if SHOW_MAPGEN_VISUALIZER {
let mut snapshot = self.map.clone();
@ -57,6 +52,10 @@ impl MapBuilder for VoronoiCellBuilder {
self.history.push(snapshot);
}
}
fn get_spawn_list(&self) -> &Vec<(usize, String)> {
&self.spawn_list
}
}
impl VoronoiCellBuilder {
@ -69,6 +68,7 @@ impl VoronoiCellBuilder {
noise_areas: HashMap::new(),
n_seeds: 64,
distance_algorithm: DistanceAlgorithm::Pythagoras,
spawn_list: Vec::new(),
}
}
@ -183,5 +183,16 @@ impl VoronoiCellBuilder {
// Now we build a noise map for use in spawning entities later
self.noise_areas = generate_voronoi_spawn_regions(&self.map, &mut rng);
// Spawn the entities
for area in self.noise_areas.iter() {
spawner::spawn_region(
&self.map,
&mut rng,
area.1,
self.depth,
&mut self.spawn_list,
);
}
}
}

View File

@ -21,6 +21,7 @@ pub struct WaveformCollapseBuilder {
history: Vec<Map>,
noise_areas: HashMap<i32, Vec<usize>>,
derive_from: Option<Box<dyn MapBuilder>>,
spawn_list: Vec<(usize, String)>,
}
impl MapBuilder for WaveformCollapseBuilder {
@ -40,12 +41,6 @@ impl MapBuilder for WaveformCollapseBuilder {
self.build();
}
fn spawn_entities(&mut self, ecs: &mut World) {
for area in self.noise_areas.iter() {
spawner::spawn_region(ecs, area.1, self.depth);
}
}
fn take_snapshot(&mut self) {
if SHOW_MAPGEN_VISUALIZER {
let mut snapshot = self.map.clone();
@ -55,6 +50,10 @@ impl MapBuilder for WaveformCollapseBuilder {
self.history.push(snapshot);
}
}
fn get_spawn_list(&self) -> &Vec<(usize, String)> {
&self.spawn_list
}
}
impl WaveformCollapseBuilder {
@ -68,11 +67,12 @@ impl WaveformCollapseBuilder {
) -> WaveformCollapseBuilder {
WaveformCollapseBuilder {
map: Map::new(new_depth),
starting_position: Position { x: 0, y: 0 },
starting_position: Position::default(),
depth: new_depth,
history: Vec::new(),
noise_areas: HashMap::new(),
derive_from,
spawn_list: Vec::new(),
}
}
@ -141,6 +141,17 @@ impl WaveformCollapseBuilder {
// Now we build a noise map for use in spawning entities later
self.noise_areas = generate_voronoi_spawn_regions(&self.map, &mut rng);
// Spawn the entities
for area in self.noise_areas.iter() {
spawner::spawn_region(
&self.map,
&mut rng,
area.1,
self.depth,
&mut self.spawn_list,
);
}
}
fn render_tile_gallery(&mut self, constraints: &[MapChunk], chunk_size: i32) {

View File

@ -56,12 +56,17 @@ fn room_table(map_depth: i32) -> RandomTable {
/// fills a room with stuff!
#[allow(clippy::map_entry)]
pub fn spawn_room(ecs: &mut World, room: &Rect, map_depth: i32) {
pub fn spawn_room(
map: &Map,
rng: &mut RandomNumberGenerator,
room: &Rect,
map_depth: i32,
spawn_list: &mut Vec<(usize, String)>,
) {
let mut possible_targets: Vec<usize> = Vec::new();
// Borrow scope - to keep access to the map separated
{
let map = ecs.fetch::<Map>();
for y in room.y1 + 1..room.y2 {
for x in room.x1 + 1..room.x2 {
let idx = map.xy_idx(x, y);
@ -72,41 +77,45 @@ pub fn spawn_room(ecs: &mut World, room: &Rect, map_depth: i32) {
}
}
spawn_region(ecs, &possible_targets, map_depth);
spawn_region(map, rng, &possible_targets, map_depth, spawn_list);
}
pub fn spawn_region(ecs: &mut World, area: &[usize], map_depth: i32) {
pub fn spawn_region(
map: &Map,
rng: &mut RandomNumberGenerator,
area: &[usize],
map_depth: i32,
spawn_list: &mut Vec<(usize, String)>,
) {
let spawn_table = room_table(map_depth);
let mut spawn_points: HashMap<usize, String> = HashMap::new();
let mut areas: Vec<usize> = Vec::from(area);
// Scope to keep the borrow checker happy
{
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
let num_spawns = i32::min(
areas.len() as i32,
rng.roll_dice(1, MAX_MONSTERS + 3) + (map_depth - 1) - 3,
);
if num_spawns == 0 {
return;
}
for _i in 0..num_spawns {
let array_index = if areas.len() == 1 {
0usize
0_usize
} else {
(rng.roll_dice(1, areas.len() as i32) - 1) as usize
};
let map_idx = areas[array_index];
spawn_points.insert(map_idx, spawn_table.roll(&mut rng));
spawn_points.insert(map_idx, spawn_table.roll(rng));
areas.remove(array_index);
}
}
// Actually spawn the monsters
for spawn in spawn_points.iter() {
spawn_entity(ecs, &spawn);
spawn_list.push((*spawn.0, spawn.1.to_string()));
}
}