doors are now static when rooms are placed
This commit is contained in:
@@ -11,9 +11,24 @@ use super::super::utils::{
|
|||||||
SimpleRng, corridor_cells, normalized_cell_edge, room_index_at_cell, shared_opening_width,
|
SimpleRng, corridor_cells, normalized_cell_edge, room_index_at_cell, shared_opening_width,
|
||||||
};
|
};
|
||||||
use super::connections::{room_collision_edges, room_exit_edge, shared_room_boundaries};
|
use super::connections::{room_collision_edges, room_exit_edge, shared_room_boundaries};
|
||||||
|
use crate::exporter::types::door_edges_for;
|
||||||
use crate::seed;
|
use crate::seed;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
// Helper to get a stable RNG for a specific edge to keep generation static.
|
||||||
|
fn get_stable_rng(
|
||||||
|
master_seed: u64,
|
||||||
|
edge: ((usize, usize), (usize, usize)),
|
||||||
|
salt: u64,
|
||||||
|
) -> SimpleRng {
|
||||||
|
let mut h = edge.0.0 as u64;
|
||||||
|
h = h.wrapping_mul(31).wrapping_add(edge.0.1 as u64);
|
||||||
|
h = h.wrapping_mul(31).wrapping_add(edge.1.0 as u64);
|
||||||
|
h = h.wrapping_mul(31).wrapping_add(edge.1.1 as u64);
|
||||||
|
h = h.wrapping_mul(31).wrapping_add(salt);
|
||||||
|
SimpleRng::new(seed::derive_seed(master_seed, h))
|
||||||
|
}
|
||||||
|
|
||||||
// Applies generated doors and archways to room-corridor transitions.
|
// Applies generated doors and archways to room-corridor transitions.
|
||||||
pub fn apply_doors(
|
pub fn apply_doors(
|
||||||
layout: &mut DungeonLayout,
|
layout: &mut DungeonLayout,
|
||||||
@@ -22,20 +37,25 @@ pub fn apply_doors(
|
|||||||
cols: usize,
|
cols: usize,
|
||||||
rows: usize,
|
rows: usize,
|
||||||
) {
|
) {
|
||||||
layout.doors.clear();
|
layout.doors.retain(|d| d.manual);
|
||||||
|
|
||||||
if layout.packed_rooms {
|
if layout.packed_rooms {
|
||||||
apply_packed_room_doors(layout, seed, settings);
|
apply_packed_room_doors(layout, seed, settings, cols, rows);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut rng = SimpleRng::new(seed::derive_seed(seed, 0xD005_5EED_u64));
|
|
||||||
let base = (settings.frequency_percent.min(100) as f32) / 100.0;
|
let base = (settings.frequency_percent.min(100) as f32) / 100.0;
|
||||||
let room_hall = (settings.room_hallway_percent.min(100) as f32) / 100.0;
|
let room_hall = (settings.room_hallway_percent.min(100) as f32) / 100.0;
|
||||||
let locked = (settings.locked_percent.min(100) as f32) / 100.0;
|
let locked = (settings.locked_percent.min(100) as f32) / 100.0;
|
||||||
|
|
||||||
let corridor_cells = corridor_cells(layout, cols, rows);
|
let corridor_cells = corridor_cells(layout, cols, rows);
|
||||||
let mut seen_edges = HashSet::new();
|
let mut seen_edges = HashSet::new();
|
||||||
|
for door in &layout.doors {
|
||||||
|
for edge in door_edges_for(door, cols, rows) {
|
||||||
|
seen_edges.insert(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let door_chance = base * room_hall;
|
let door_chance = base * room_hall;
|
||||||
for corridor in &layout.corridors {
|
for corridor in &layout.corridors {
|
||||||
if corridor.path.len() < 2 {
|
if corridor.path.len() < 2 {
|
||||||
@@ -48,13 +68,14 @@ pub fn apply_doors(
|
|||||||
if let Some(edge) = room_exit_edge(&corridor.path, start_room, true)
|
if let Some(edge) = room_exit_edge(&corridor.path, start_room, true)
|
||||||
&& seen_edges.insert(edge)
|
&& seen_edges.insert(edge)
|
||||||
{
|
{
|
||||||
let place_door = door_chance > 0.0 && rng.next_f32() <= door_chance;
|
let mut edge_rng = get_stable_rng(seed, edge, 0x1111_2222_u64);
|
||||||
|
let place_door = door_chance > 0.0 && edge_rng.next_f32() <= door_chance;
|
||||||
layout.doors.push(Door {
|
layout.doors.push(Door {
|
||||||
from: edge.0,
|
from: edge.0,
|
||||||
to: edge.1,
|
to: edge.1,
|
||||||
width: corridor.width.max(1),
|
width: corridor.width.max(1),
|
||||||
span_width: true,
|
span_width: true,
|
||||||
locked: place_door && rng.next_f32() <= locked,
|
locked: place_door && edge_rng.next_f32() <= locked,
|
||||||
archway: !place_door,
|
archway: !place_door,
|
||||||
secret: false,
|
secret: false,
|
||||||
manual: false,
|
manual: false,
|
||||||
@@ -64,13 +85,14 @@ pub fn apply_doors(
|
|||||||
if let Some(edge) = room_exit_edge(&corridor.path, end_room, false)
|
if let Some(edge) = room_exit_edge(&corridor.path, end_room, false)
|
||||||
&& seen_edges.insert(edge)
|
&& seen_edges.insert(edge)
|
||||||
{
|
{
|
||||||
let place_door = door_chance > 0.0 && rng.next_f32() <= door_chance;
|
let mut edge_rng = get_stable_rng(seed, edge, 0x1111_2222_u64);
|
||||||
|
let place_door = door_chance > 0.0 && edge_rng.next_f32() <= door_chance;
|
||||||
layout.doors.push(Door {
|
layout.doors.push(Door {
|
||||||
from: edge.0,
|
from: edge.0,
|
||||||
to: edge.1,
|
to: edge.1,
|
||||||
width: corridor.width.max(1),
|
width: corridor.width.max(1),
|
||||||
span_width: true,
|
span_width: true,
|
||||||
locked: place_door && rng.next_f32() <= locked,
|
locked: place_door && edge_rng.next_f32() <= locked,
|
||||||
archway: !place_door,
|
archway: !place_door,
|
||||||
secret: false,
|
secret: false,
|
||||||
manual: false,
|
manual: false,
|
||||||
@@ -84,13 +106,14 @@ pub fn apply_doors(
|
|||||||
|
|
||||||
for edge in room_collision_edges(&corridor.path, room) {
|
for edge in room_collision_edges(&corridor.path, room) {
|
||||||
if seen_edges.insert(edge) {
|
if seen_edges.insert(edge) {
|
||||||
let place_door = door_chance > 0.0 && rng.next_f32() <= door_chance;
|
let mut edge_rng = get_stable_rng(seed, edge, 0x3333_4444_u64);
|
||||||
|
let place_door = door_chance > 0.0 && edge_rng.next_f32() <= door_chance;
|
||||||
layout.doors.push(Door {
|
layout.doors.push(Door {
|
||||||
from: edge.0,
|
from: edge.0,
|
||||||
to: edge.1,
|
to: edge.1,
|
||||||
width: corridor.width.max(1),
|
width: corridor.width.max(1),
|
||||||
span_width: true,
|
span_width: true,
|
||||||
locked: place_door && rng.next_f32() <= locked,
|
locked: place_door && edge_rng.next_f32() <= locked,
|
||||||
archway: !place_door,
|
archway: !place_door,
|
||||||
secret: false,
|
secret: false,
|
||||||
manual: false,
|
manual: false,
|
||||||
@@ -106,32 +129,38 @@ pub fn apply_doors(
|
|||||||
let bottom = (x, y + 1);
|
let bottom = (x, y + 1);
|
||||||
if x + 1 < cols && corridor_cells.contains(&right) {
|
if x + 1 < cols && corridor_cells.contains(&right) {
|
||||||
let edge = normalized_cell_edge((x, y), right);
|
let edge = normalized_cell_edge((x, y), right);
|
||||||
if seen_edges.insert(edge) && base > 0.0 && rng.next_f32() <= base {
|
if seen_edges.insert(edge) {
|
||||||
layout.doors.push(Door {
|
let mut edge_rng = get_stable_rng(seed, edge, 0x5555_6666_u64);
|
||||||
from: edge.0,
|
if base > 0.0 && edge_rng.next_f32() <= base {
|
||||||
to: edge.1,
|
layout.doors.push(Door {
|
||||||
width: 1,
|
from: edge.0,
|
||||||
span_width: false,
|
to: edge.1,
|
||||||
locked: rng.next_f32() <= locked,
|
width: 1,
|
||||||
archway: false,
|
span_width: false,
|
||||||
secret: false,
|
locked: edge_rng.next_f32() <= locked,
|
||||||
manual: false,
|
archway: false,
|
||||||
});
|
secret: false,
|
||||||
|
manual: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if y + 1 < rows && corridor_cells.contains(&bottom) {
|
if y + 1 < rows && corridor_cells.contains(&bottom) {
|
||||||
let edge = normalized_cell_edge((x, y), bottom);
|
let edge = normalized_cell_edge((x, y), bottom);
|
||||||
if seen_edges.insert(edge) && base > 0.0 && rng.next_f32() <= base {
|
if seen_edges.insert(edge) {
|
||||||
layout.doors.push(Door {
|
let mut edge_rng = get_stable_rng(seed, edge, 0x5555_6666_u64);
|
||||||
from: edge.0,
|
if base > 0.0 && edge_rng.next_f32() <= base {
|
||||||
to: edge.1,
|
layout.doors.push(Door {
|
||||||
width: 1,
|
from: edge.0,
|
||||||
span_width: false,
|
to: edge.1,
|
||||||
locked: rng.next_f32() <= locked,
|
width: 1,
|
||||||
archway: false,
|
span_width: false,
|
||||||
secret: false,
|
locked: edge_rng.next_f32() <= locked,
|
||||||
manual: false,
|
archway: false,
|
||||||
});
|
secret: false,
|
||||||
|
manual: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,37 +170,59 @@ pub fn apply_doors(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Applies packed room doors.
|
// Applies packed room doors.
|
||||||
pub fn apply_packed_room_doors(layout: &mut DungeonLayout, seed: u64, settings: DoorSettings) {
|
pub fn apply_packed_room_doors(
|
||||||
let mut rng = SimpleRng::new(seed::derive_seed(seed, 0xD005_5EED_u64));
|
layout: &mut DungeonLayout,
|
||||||
|
seed: u64,
|
||||||
|
settings: DoorSettings,
|
||||||
|
cols: usize,
|
||||||
|
rows: usize,
|
||||||
|
) {
|
||||||
|
let mut seen_edges = HashSet::new();
|
||||||
|
for door in &layout.doors {
|
||||||
|
for edge in door_edges_for(door, cols, rows) {
|
||||||
|
seen_edges.insert(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let door_chance = ((settings.frequency_percent.min(100) as f32) / 100.0)
|
let door_chance = ((settings.frequency_percent.min(100) as f32) / 100.0)
|
||||||
* ((settings.room_hallway_percent.min(100) as f32) / 100.0);
|
* ((settings.room_hallway_percent.min(100) as f32) / 100.0);
|
||||||
let locked = (settings.locked_percent.min(100) as f32) / 100.0;
|
let locked = (settings.locked_percent.min(100) as f32) / 100.0;
|
||||||
|
|
||||||
for (a_idx, b_idx, shared_edges) in shared_room_boundaries(&layout.rooms) {
|
for (a_idx, b_idx, shared_edges) in shared_room_boundaries(&layout.rooms) {
|
||||||
|
if shared_edges.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let edge = shared_edges[0];
|
||||||
|
let mut edge_rng = get_stable_rng(seed, edge, 0xAAAA_BBBB_u64);
|
||||||
|
|
||||||
let edge_idx = if shared_edges.len() <= 1 {
|
let edge_idx = if shared_edges.len() <= 1 {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
rng.range_inclusive(0, shared_edges.len() - 1)
|
edge_rng.range_inclusive(0, shared_edges.len() - 1)
|
||||||
};
|
};
|
||||||
let edge = shared_edges[edge_idx];
|
let chosen_edge = shared_edges[edge_idx];
|
||||||
let place_door = door_chance > 0.0 && rng.next_f32() <= door_chance;
|
|
||||||
|
|
||||||
let width = shared_opening_width(
|
if seen_edges.insert(chosen_edge) {
|
||||||
&layout.rooms[a_idx],
|
let place_door = door_chance > 0.0 && edge_rng.next_f32() <= door_chance;
|
||||||
&layout.rooms[b_idx],
|
|
||||||
shared_edges.len(),
|
let width = shared_opening_width(
|
||||||
1,
|
&layout.rooms[a_idx],
|
||||||
);
|
&layout.rooms[b_idx],
|
||||||
layout.doors.push(Door {
|
shared_edges.len(),
|
||||||
from: edge.0,
|
1,
|
||||||
to: edge.1,
|
);
|
||||||
width,
|
layout.doors.push(Door {
|
||||||
span_width: width > 1,
|
from: chosen_edge.0,
|
||||||
locked: place_door && rng.next_f32() <= locked,
|
to: chosen_edge.1,
|
||||||
archway: !place_door,
|
width,
|
||||||
secret: false,
|
span_width: width > 1,
|
||||||
manual: false,
|
locked: place_door && edge_rng.next_f32() <= locked,
|
||||||
});
|
archway: !place_door,
|
||||||
|
secret: false,
|
||||||
|
manual: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
apply_secret_doors(layout, seed, settings);
|
apply_secret_doors(layout, seed, settings);
|
||||||
@@ -185,12 +236,12 @@ pub fn apply_secret_doors(layout: &mut DungeonLayout, seed: u64, settings: DoorS
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut rng = SimpleRng::new(seed::derive_seed(seed, 0x5EC2_E700_u64));
|
|
||||||
let room_door_map = room_to_door_indices(layout);
|
let room_door_map = room_to_door_indices(layout);
|
||||||
let eligible_secret_doors = (0..layout.doors.len())
|
let eligible_secret_doors = (0..layout.doors.len())
|
||||||
.filter(|&door_idx| {
|
.filter(|&door_idx| {
|
||||||
let door = &layout.doors[door_idx];
|
let door = &layout.doors[door_idx];
|
||||||
!door.archway
|
!door.manual
|
||||||
|
&& !door.archway
|
||||||
&& !door.locked
|
&& !door.locked
|
||||||
&& door_is_secret_eligible_for_rooms(layout, &room_door_map, door_idx)
|
&& door_is_secret_eligible_for_rooms(layout, &room_door_map, door_idx)
|
||||||
})
|
})
|
||||||
@@ -201,7 +252,8 @@ pub fn apply_secret_doors(layout: &mut DungeonLayout, seed: u64, settings: DoorS
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if rng.next_f32() <= chance {
|
let mut door_rng = get_stable_rng(seed, (door.from, door.to), 0x7777_8888_u64);
|
||||||
|
if door_rng.next_f32() <= chance {
|
||||||
door.locked = false;
|
door.locked = false;
|
||||||
door.archway = false;
|
door.archway = false;
|
||||||
door.secret = true;
|
door.secret = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user