Add cellular automata

This commit is contained in:
2022-01-30 15:50:36 +01:00
parent 5a00ebf1f1
commit d4892e33bd
9 changed files with 275 additions and 76 deletions

View File

@@ -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),
_ => {}
}
}