use rand::{thread_rng, Rng};
use super::{DoesDunGen, MapId, SupportsDunGen, MAPS};
use crate::geometry::{CardinalDirection, HasHeight, HasWidth, Position};
pub struct ReciprocatePortalsGenerator {}
impl ReciprocatePortalsGenerator {
#[allow(clippy::new_without_default)]
#[must_use]
pub fn new() -> Self {
Self {}
}
}
impl DoesDunGen for ReciprocatePortalsGenerator {
fn dun_gen(&self, target: &mut dyn SupportsDunGen) {
let map_id = target.get_map_id();
self.dun_gen_map(map_id);
}
fn dun_gen_map(&self, map_id: MapId) {
let maps = &MAPS.read();
let map = &mut maps[map_id].write();
let size = *map.size();
if size.width() < 3 || size.height() < 3 {
return;
}
for portal_mut in map.portals_mut() {
let target_map_id = portal_mut.target();
let target_map_mut = &mut maps[target_map_id].write();
let target_map_size = *target_map_mut.size();
if target_map_size.width() < 3 || target_map_size.height() < 3 {
return;
}
let mut found_match = false;
for other_portal in target_map_mut.portals() {
if portal_mut.local_position() == other_portal.portal_to_map_position() {
found_match = true;
}
}
if !found_match {
let mut rng = thread_rng();
let portal_facing = *portal_mut.portal_to_map_facing();
let (portal_x, portal_y) = match portal_facing {
#[allow(clippy::cast_possible_wrap)]
CardinalDirection::North => {
(rng.gen_range(1..(target_map_size.width() - 1)) as i32, 0)
}
#[allow(clippy::cast_possible_wrap)]
CardinalDirection::East => (
target_map_size.width() as i32 - 1,
rng.gen_range(1..(target_map_size.height() - 1)) as i32,
),
#[allow(clippy::cast_possible_wrap)]
CardinalDirection::South => (
rng.gen_range(1..(target_map_size.width() - 1)) as i32,
target_map_size.height() as i32 - 1,
),
#[allow(clippy::cast_possible_wrap)]
CardinalDirection::West => {
(0, rng.gen_range(1..(target_map_size.height() - 1)) as i32)
}
};
let target_local_position = Position::new(portal_x, portal_y);
target_map_mut.add_portal(
target_local_position,
-portal_facing,
*portal_mut.local_position(),
map_id,
);
*portal_mut.portal_to_map_position_mut() = target_local_position;
}
}
}
}