Add cellular automata
This commit is contained in:
112
src/spawner.rs
112
src/spawner.rs
@@ -6,7 +6,12 @@ use specs::saveload::{MarkedBuilder, SimpleMarker};
|
||||
|
||||
use crate::random_table::RandomTable;
|
||||
use crate::rect::Rect;
|
||||
use crate::{AreaOfEffect, BlocksTile, CombatStats, Confusion, Consumable, DefenseBonus, EntryTrigger, EquipmentSlot, Equippable, Hidden, HungerClock, HungerState, InflictsDamage, Item, MagicMapper, MeleePowerBonus, Monster, Name, Player, Position, ProvidesFood, ProvidesHealing, Ranged, Renderable, SerializeMe, SingleActivation, Viewshed, MAP_WIDTH, MAX_MONSTER, Map, TileType};
|
||||
use crate::{
|
||||
AreaOfEffect, BlocksTile, CombatStats, Confusion, Consumable, DefenseBonus, EntryTrigger,
|
||||
EquipmentSlot, Equippable, Hidden, HungerClock, HungerState, InflictsDamage, Item, MagicMapper,
|
||||
Map, MeleePowerBonus, Monster, Name, Player, Position, ProvidesFood, ProvidesHealing, Ranged,
|
||||
Renderable, SerializeMe, SingleActivation, TileType, Viewshed, MAP_WIDTH, MAX_MONSTER,
|
||||
};
|
||||
|
||||
pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
||||
ecs.create_entity()
|
||||
@@ -81,55 +86,78 @@ fn monster<S: ToString>(ecs: &mut World, x: i32, y: i32, glyph: FontCharType, na
|
||||
}
|
||||
|
||||
#[allow(clippy::map_entry)]
|
||||
pub fn spawn_room(ecs: &mut World, room: &Rect, map_depth: i32, map: &Map) {
|
||||
let spawn_table = room_table(map_depth);
|
||||
let mut spawn_points: HashMap<usize, String> = HashMap::new();
|
||||
pub fn spawn_room(ecs: &mut World, room: &Rect, map_depth: i32) {
|
||||
let mut possible_targets: Vec<usize> = Vec::new();
|
||||
|
||||
{
|
||||
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
|
||||
let num_spawns = rng.roll_dice(1, MAX_MONSTER + 3) + (map_depth - 1) - 3;
|
||||
|
||||
for _i in 0..num_spawns {
|
||||
let mut added = false;
|
||||
let mut tried = 0;
|
||||
while !added && tried < 20 {
|
||||
let x = (room.x1 + rng.roll_dice(1, i32::abs(room.x2 - room.x1))) as usize;
|
||||
let y = (room.y1 + rng.roll_dice(1, i32::abs(room.y2 - room.y1))) as usize;
|
||||
let idx = (y * MAP_WIDTH) + x;
|
||||
if !spawn_points.contains_key(&idx) && map.tiles[idx] != TileType::Wall {
|
||||
spawn_points.insert(idx, spawn_table.roll(&mut rng));
|
||||
added = true;
|
||||
} else {
|
||||
tried += 1;
|
||||
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);
|
||||
if map.tiles[idx] == TileType::Floor {
|
||||
possible_targets.push(idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for spawn in spawn_points.iter() {
|
||||
let x = (*spawn.0 % MAP_WIDTH) as i32;
|
||||
let y = (*spawn.0 / MAP_WIDTH) as i32;
|
||||
spawn_region(ecs, &possible_targets, map_depth);
|
||||
}
|
||||
|
||||
match spawn.1.as_ref() {
|
||||
"Goblin" => goblin(ecs, x, y),
|
||||
"Orc" => orc(ecs, x, y),
|
||||
"Health Potion" => health_potion(ecs, x, y),
|
||||
"Fireball Scroll" => fireball_scroll(ecs, x, y),
|
||||
"Confusion Scroll" => confusion_scroll(ecs, x, y),
|
||||
"Magic Missile Scroll" => magic_missile_scroll(ecs, x, y),
|
||||
"Dagger" => dagger(ecs, x, y),
|
||||
"Longsword" => longsword(ecs, x, y),
|
||||
"Shield" => shield(ecs, x, y),
|
||||
"Tower Shield" => tower_shield(ecs, x, y),
|
||||
"Helmet" => helmet(ecs, x, y),
|
||||
"Breastplate" => breastplate(ecs, x, y),
|
||||
"Leggings" => leggings(ecs, x, y),
|
||||
"Sabatons" => sabatons(ecs, x, y),
|
||||
"Rations" => rations(ecs, x, y),
|
||||
"Magic Mapping Scroll" => magic_mapper_scroll(ecs, x, y),
|
||||
"Bear Trap" => bear_trap(ecs, x, y),
|
||||
_ => {}
|
||||
}
|
||||
pub(crate) fn spawn_region(ecs: &mut World, area: &[usize], map_depth: i32) {
|
||||
if let Some(spawn_points) = calculate_spawn_points(ecs, area, map_depth) {
|
||||
spawn_entities(ecs, spawn_points)
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_entities(ecs: &mut World, spawn_points: HashMap<usize, String>) {
|
||||
for spawn in spawn_points.iter() {
|
||||
spawn_entity(ecs, &spawn);
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_spawn_points(ecs: &mut World, area: &[usize], map_depth: i32) -> Option<HashMap<usize, String>> {
|
||||
let mut spawn_points: HashMap<usize, String> = HashMap::new();
|
||||
let spawn_table = room_table(map_depth);
|
||||
let mut areas: Vec<usize> = Vec::from(area);
|
||||
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
|
||||
|
||||
let num_spawns = i32::min(areas.len() as i32, rng.roll_dice(1, MAX_MONSTER + 3));
|
||||
if num_spawns == 0 { return None; }
|
||||
|
||||
for _i in 0..num_spawns {
|
||||
let array_idx = if areas.len() == 1 { 0usize } else { (rng.roll_dice(1, areas.len() as i32 - 1) as usize) };
|
||||
let map_idx = areas[array_idx];
|
||||
spawn_points.insert(map_idx, spawn_table.roll(&mut rng));
|
||||
areas.remove(array_idx);
|
||||
}
|
||||
|
||||
Some(spawn_points)
|
||||
}
|
||||
|
||||
fn spawn_entity(ecs: &mut World, spawn: &(&usize, &String)) {
|
||||
let x = (*spawn.0 % MAP_WIDTH) as i32;
|
||||
let y = (*spawn.0 / MAP_WIDTH) as i32;
|
||||
|
||||
match spawn.1.as_ref() {
|
||||
"Goblin" => goblin(ecs, x, y),
|
||||
"Orc" => orc(ecs, x, y),
|
||||
"Health Potion" => health_potion(ecs, x, y),
|
||||
"Fireball Scroll" => fireball_scroll(ecs, x, y),
|
||||
"Confusion Scroll" => confusion_scroll(ecs, x, y),
|
||||
"Magic Missile Scroll" => magic_missile_scroll(ecs, x, y),
|
||||
"Dagger" => dagger(ecs, x, y),
|
||||
"Longsword" => longsword(ecs, x, y),
|
||||
"Shield" => shield(ecs, x, y),
|
||||
"Tower Shield" => tower_shield(ecs, x, y),
|
||||
"Helmet" => helmet(ecs, x, y),
|
||||
"Breastplate" => breastplate(ecs, x, y),
|
||||
"Leggings" => leggings(ecs, x, y),
|
||||
"Sabatons" => sabatons(ecs, x, y),
|
||||
"Rations" => rations(ecs, x, y),
|
||||
"Magic Mapping Scroll" => magic_mapper_scroll(ecs, x, y),
|
||||
"Bear Trap" => bear_trap(ecs, x, y),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user