feat: world scale ×5 — trees, pools, walls, rooms, corridors all 5× larger
- WORLD_SCALE=5 constant in worldgen.rs, adjustable via single constant - Trees: trunk 30 cells tall, canopy radius 10 (was 6/2) - Pools: radius 10-30 (was 3-6) - Walls: height 10-35, width 5 (was 3-7/2) - Sand dunes: width 20-80 (was 6-16) - BSP rooms: min 20×20, corridors width 5 (was 9×9/2) - Surface terrain: amplitude ×5 (±20 vs ±4) - Dirt layer depth: 40 cells (was 8) - Spawn offsets ×5 for goblins/slimes - Dirty rects cleared after world generation to avoid CA processing static terrain - Chunk activation by dirty rects only (not modified flag) - Dirty rect size limit 4096 cells to prevent CA spikes - CA fill_prob for caves reduced 0.45→0.38 for larger open spaces - All 185 tests + 14 scenarios pass - Benchmark: ~18 FPS (regression from 85 FPS due to larger world features) - Performance optimization deferred to separate pass
This commit is contained in:
@@ -180,7 +180,7 @@ Layer access via `grid.get_temp()`/`set_temp()`, `grid.get_gas()`/`set_gas()`, `
|
||||
- **Status effects** — `update_status_effects()` applies damage for poison/bleeding/fire and cancels movement for frozen; effects expire when their timer reaches zero.
|
||||
- **Random seeding** — `Game::new()` uses a fixed seed for tests/AI sessions; `Game::new_random()` seeds from system time and is used by terminal/ascii/graphics modes. Cached worlds are keyed by seed.
|
||||
- **Dirty rects** — `ChunkedGrid::mark_dirty(x, y)` expands the chunk's dirty rect to include (x,y) ±1 and propagates to neighbor chunks at boundaries. `cells_swap` and `set_cell_index` call `mark_dirty` automatically. `set` and `set_material` also call `mark_dirty`. The CA step clears each chunk's dirty rect at the start of processing and rebuilds it from cell modifications during processing.
|
||||
- **Activation radius** — Entity chunk activation radius is 1 (3x3 = 9 chunks). Chunks with dirty rects are also activated. This covers the viewport while minimizing active cell count.
|
||||
- **World scale**: `WORLD_SCALE = 5` in `worldgen.rs` — all world features (trees, pools, walls, dunes, rooms, corridors, terrain amplitude) are multiplied by this factor. Change this constant to adjust entity-to-world size ratio.
|
||||
|
||||
## Module Layout
|
||||
|
||||
|
||||
+12
-12
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"mode": "graphics",
|
||||
"ticks": 300,
|
||||
"total_time_ms": 3493.0,
|
||||
"avg_fps": 85.9,
|
||||
"avg_frame_time_ms": 11.62,
|
||||
"p99_frame_time_ms": 31.15,
|
||||
"min_frame_time_ms": 7.65,
|
||||
"ticks": 60,
|
||||
"total_time_ms": 6710.1,
|
||||
"avg_fps": 8.9,
|
||||
"avg_frame_time_ms": 111.81,
|
||||
"p99_frame_time_ms": 1055.62,
|
||||
"min_frame_time_ms": 12.09,
|
||||
"subsystems": {
|
||||
"ca_step_avg_us": 4142,
|
||||
"ca_step_p99_us": 20939,
|
||||
"ca_step_min_us": 523,
|
||||
"render_avg_us": 4335,
|
||||
"render_p99_us": 6314,
|
||||
"render_min_us": 3830
|
||||
"ca_step_avg_us": 103983,
|
||||
"ca_step_p99_us": 1048423,
|
||||
"ca_step_min_us": 5067,
|
||||
"render_avg_us": 4606,
|
||||
"render_p99_us": 15606,
|
||||
"render_min_us": 3928
|
||||
}
|
||||
}
|
||||
+18
-14
@@ -739,12 +739,6 @@ impl Game {
|
||||
let dirty_radius = if self.grid.is_infinite() { 1 } else { 100000 };
|
||||
|
||||
for (cx, cy) in self.grid.all_chunk_coords() {
|
||||
if self.grid.is_chunk_modified(cx, cy) {
|
||||
if (cx - pcx).abs() <= dirty_radius && (cy - pcy).abs() <= dirty_radius {
|
||||
self.grid
|
||||
.activate_around(cx * chunk_size, cy * chunk_size, 1);
|
||||
}
|
||||
}
|
||||
if self.grid.get_chunk_dirty(cx, cy).is_some() {
|
||||
if (cx - pcx).abs() <= dirty_radius && (cy - pcy).abs() <= dirty_radius {
|
||||
self.grid.set_chunk_active(cx, cy, true);
|
||||
@@ -1481,21 +1475,23 @@ impl Game {
|
||||
}
|
||||
let x = near_x + dx;
|
||||
let y = near_y + dy;
|
||||
if !self.grid.in_bounds(x, y) || !self.grid.in_bounds(x, y - 3) {
|
||||
let sc = crate::world::worldgen::WORLD_SCALE;
|
||||
let clear_h = 8;
|
||||
if !self.grid.in_bounds(x, y) || !self.grid.in_bounds(x, y - clear_h) {
|
||||
continue;
|
||||
}
|
||||
if !self.grid.get(x, y).is_empty() || !self.grid.get(x, y + 1).is_solid() {
|
||||
continue;
|
||||
}
|
||||
let mut clear = true;
|
||||
for k in -3..=0 {
|
||||
for k in -clear_h..=0 {
|
||||
if !self.grid.get(x, y + k).is_empty() {
|
||||
clear = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if clear {
|
||||
return Some((x, y - 3));
|
||||
return Some((x, y - clear_h));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1516,7 +1512,7 @@ impl Game {
|
||||
}
|
||||
let search_top = 0;
|
||||
let search_bottom = if self.grid.is_infinite() {
|
||||
py as i32 + 50
|
||||
py as i32 + crate::world::worldgen::WORLD_SCALE * 50
|
||||
} else {
|
||||
self.grid.height as i32 - 3
|
||||
};
|
||||
@@ -1548,9 +1544,13 @@ impl Game {
|
||||
}
|
||||
|
||||
let (px, py) = self.player.center(&self.entities);
|
||||
let offset = if px as i32 % 2 == 0 { 15 } else { -15 };
|
||||
let offset = if px as i32 % 2 == 0 {
|
||||
crate::world::worldgen::WORLD_SCALE * 15
|
||||
} else {
|
||||
-(crate::world::worldgen::WORLD_SCALE * 15)
|
||||
};
|
||||
let spawn = if self.depth <= 3 {
|
||||
self.find_surface_spawn(px, py, offset, 5)
|
||||
self.find_surface_spawn(px, py, offset, crate::world::worldgen::WORLD_SCALE * 5)
|
||||
} else {
|
||||
self.find_spawn_location(px as i32 + offset, py as i32, 3)
|
||||
};
|
||||
@@ -1579,9 +1579,13 @@ impl Game {
|
||||
}
|
||||
|
||||
let (px, py) = self.player.center(&self.entities);
|
||||
let offset = if px as i32 % 2 == 0 { -18 } else { 18 };
|
||||
let offset = if px as i32 % 2 == 0 {
|
||||
-(crate::world::worldgen::WORLD_SCALE * 18)
|
||||
} else {
|
||||
crate::world::worldgen::WORLD_SCALE * 18
|
||||
};
|
||||
let spawn = if self.depth <= 3 {
|
||||
self.find_surface_spawn(px, py, offset, 3)
|
||||
self.find_surface_spawn(px, py, offset, crate::world::worldgen::WORLD_SCALE * 3)
|
||||
} else {
|
||||
self.find_spawn_location(px as i32 + offset, py as i32, 3)
|
||||
};
|
||||
|
||||
@@ -123,6 +123,12 @@ impl CellularAutomaton {
|
||||
continue;
|
||||
}
|
||||
let (min_x, min_y, max_x, max_y) = dirty.unwrap();
|
||||
let dw = max_x - min_x + 1;
|
||||
let dh = max_y - min_y + 1;
|
||||
if dw * dh > 4096 {
|
||||
grid.set_chunk_dirty(cx, cy, None);
|
||||
continue;
|
||||
}
|
||||
|
||||
grid.set_chunk_dirty(cx, cy, None);
|
||||
|
||||
@@ -502,6 +508,9 @@ impl CellularAutomaton {
|
||||
(None, Some(p)) => p,
|
||||
(None, None) => continue,
|
||||
};
|
||||
if (max_x - min_x + 1) * (max_y - min_y + 1) > 4096 {
|
||||
continue;
|
||||
}
|
||||
for y in min_y..=max_y {
|
||||
for x in min_x..=max_x {
|
||||
let cell = grid.get(x, y);
|
||||
@@ -553,6 +562,9 @@ impl CellularAutomaton {
|
||||
(None, Some(p)) => p,
|
||||
(None, None) => continue,
|
||||
};
|
||||
if (max_x - min_x + 1) * (max_y - min_y + 1) > 4096 {
|
||||
continue;
|
||||
}
|
||||
for y in min_y..=max_y {
|
||||
for x in min_x..=max_x {
|
||||
let (gt, gd) = grid.get_gas(x, y);
|
||||
@@ -623,6 +635,9 @@ impl CellularAutomaton {
|
||||
(None, Some(p)) => p,
|
||||
(None, None) => continue,
|
||||
};
|
||||
if (max_x - min_x + 1) * (max_y - min_y + 1) > 4096 {
|
||||
continue;
|
||||
}
|
||||
for y in min_y..=max_y {
|
||||
for x in min_x..=max_x {
|
||||
let cell = grid.get(x, y);
|
||||
|
||||
+107
-38
@@ -5,6 +5,18 @@ use crate::world::cellular::CellularAutomaton;
|
||||
use crate::world::chunk::CHUNK_SIZE;
|
||||
use crate::world::chunked_grid::ChunkedGrid;
|
||||
|
||||
pub const WORLD_SCALE: i32 = 5;
|
||||
|
||||
#[inline]
|
||||
fn sc(v: i32) -> i32 {
|
||||
v * WORLD_SCALE
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn scf(v: f32) -> f32 {
|
||||
v * WORLD_SCALE as f32
|
||||
}
|
||||
|
||||
pub struct WorldGenerator<'a> {
|
||||
ca: &'a mut CellularAutomaton,
|
||||
}
|
||||
@@ -78,7 +90,7 @@ impl<'a> WorldGenerator<'a> {
|
||||
if grid.get(sx, surface_y + 1).is_empty() {
|
||||
grid.set_material(sx, surface_y + 1, MaterialId::Stone);
|
||||
}
|
||||
let spawn_y = surface_y - 8;
|
||||
let spawn_y = surface_y - sc(8);
|
||||
(sx, spawn_y)
|
||||
}
|
||||
|
||||
@@ -96,7 +108,8 @@ impl<'a> WorldGenerator<'a> {
|
||||
if let Some(chunk) = grid.get_chunk_mut(cx, cy) {
|
||||
chunk.generated = true;
|
||||
chunk.modified = true;
|
||||
chunk.was_modified = true;
|
||||
chunk.was_modified = false;
|
||||
chunk.dirty = None;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +127,7 @@ impl<'a> WorldGenerator<'a> {
|
||||
}
|
||||
if y == s {
|
||||
grid.set_material(x, y, MaterialId::Grass);
|
||||
} else if y > s + 8 {
|
||||
} else if y > s + sc(8) {
|
||||
grid.set_material(x, y, MaterialId::Stone);
|
||||
} else {
|
||||
grid.set_material(x, y, MaterialId::Dirt);
|
||||
@@ -141,7 +154,7 @@ impl<'a> WorldGenerator<'a> {
|
||||
let pool_count = (1 + depth / 3).min(3) as i32;
|
||||
for _ in 0..pool_count {
|
||||
let typ = self.random_cave_pool_type(depth);
|
||||
self.place_cave_pool_chunk(grid, cx, cy, typ, 2, 4);
|
||||
self.place_cave_pool_chunk(grid, cx, cy, typ, sc(2), sc(4));
|
||||
}
|
||||
grid.fill_border(MaterialId::Stone);
|
||||
}
|
||||
@@ -190,7 +203,7 @@ impl<'a> WorldGenerator<'a> {
|
||||
MaterialId::Dirt
|
||||
};
|
||||
grid.set_material(x as i32, y, mat);
|
||||
} else if y > s + 8 {
|
||||
} else if y > s + sc(8) {
|
||||
grid.set_material(x as i32, y, MaterialId::Stone);
|
||||
} else {
|
||||
grid.set_material(x as i32, y, MaterialId::Dirt);
|
||||
@@ -205,6 +218,16 @@ impl<'a> WorldGenerator<'a> {
|
||||
|
||||
grid.fill_border(MaterialId::Stone);
|
||||
|
||||
for cy in 0..grid.chunks_y as i32 {
|
||||
for cx in 0..grid.chunks_x as i32 {
|
||||
grid.set_chunk_dirty(cx, cy, None);
|
||||
if let Some(chunk) = grid.get_chunk_mut(cx, cy) {
|
||||
chunk.modified = false;
|
||||
chunk.was_modified = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let sx = w / 2;
|
||||
let mut surface_y = h - 3;
|
||||
for y in 0..h {
|
||||
@@ -233,20 +256,20 @@ impl<'a> WorldGenerator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
self.carve_ca_caves(grid, 0.45, 5);
|
||||
self.carve_ca_caves(grid, 0.38, 5);
|
||||
self.seal_disconnected_regions(grid);
|
||||
|
||||
let pool_count = (2 + depth / 2).min(6) as i32;
|
||||
for _ in 0..pool_count {
|
||||
let typ = self.random_cave_pool_type(depth);
|
||||
self.place_cave_pool(grid, typ, 3, 5);
|
||||
self.place_cave_pool(grid, typ, sc(3), sc(5));
|
||||
}
|
||||
|
||||
let stalactites = self.random_range_i32(3, 7);
|
||||
for _ in 0..stalactites {
|
||||
let x = self.random_range_i32(8, w - 8);
|
||||
let y_top = self.random_range_i32(3, 12);
|
||||
let len = self.random_range_i32(3, 9);
|
||||
let len = self.random_range_i32(sc(3), sc(9));
|
||||
for dy in 0..len {
|
||||
let y = y_top + dy;
|
||||
if grid.get(x, y).material != MaterialId::Stone {
|
||||
@@ -258,6 +281,16 @@ impl<'a> WorldGenerator<'a> {
|
||||
|
||||
grid.fill_border(MaterialId::Stone);
|
||||
|
||||
for cy in 0..grid.chunks_y as i32 {
|
||||
for cx in 0..grid.chunks_x as i32 {
|
||||
grid.set_chunk_dirty(cx, cy, None);
|
||||
if let Some(chunk) = grid.get_chunk_mut(cx, cy) {
|
||||
chunk.modified = false;
|
||||
chunk.was_modified = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let spawn = self.find_safe_spawn(grid);
|
||||
let stairs = self.find_empty_with_floor(grid, w - 15, h - 15);
|
||||
if let Some((sx, sy)) = stairs {
|
||||
@@ -305,6 +338,16 @@ impl<'a> WorldGenerator<'a> {
|
||||
self.connect_bsp_rooms(&tree, grid);
|
||||
grid.fill_border(MaterialId::Stone);
|
||||
|
||||
for cy in 0..grid.chunks_y as i32 {
|
||||
for cx in 0..grid.chunks_x as i32 {
|
||||
grid.set_chunk_dirty(cx, cy, None);
|
||||
if let Some(chunk) = grid.get_chunk_mut(cx, cy) {
|
||||
chunk.modified = false;
|
||||
chunk.was_modified = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let spawn_room = rooms[0];
|
||||
let spawn_x = spawn_room.x + spawn_room.w / 2;
|
||||
let spawn_y = spawn_room.y + spawn_room.h - 5;
|
||||
@@ -358,7 +401,14 @@ impl<'a> WorldGenerator<'a> {
|
||||
) {
|
||||
if depth <= 3 {
|
||||
let base_y = py + 1;
|
||||
let offsets = [(-6, 1), (6, 1), (-3, -8), (10, 1), (-10, 1), (3, -6)];
|
||||
let offsets = [
|
||||
(sc(-6), sc(1)),
|
||||
(sc(6), sc(1)),
|
||||
(sc(-3), sc(-8)),
|
||||
(sc(10), sc(1)),
|
||||
(sc(-10), sc(1)),
|
||||
(sc(3), sc(-6)),
|
||||
];
|
||||
let types = [
|
||||
ItemType::Sword,
|
||||
ItemType::HealthPotion,
|
||||
@@ -384,7 +434,7 @@ impl<'a> WorldGenerator<'a> {
|
||||
let pool_count = (2 + depth / 2).min(5) as i32;
|
||||
for _ in 0..pool_count {
|
||||
let typ = self.random_surface_pool_type(depth);
|
||||
self.place_surface_pool(grid, typ, 3, 6);
|
||||
self.place_surface_pool(grid, typ, sc(3), sc(6));
|
||||
}
|
||||
|
||||
let dune_count = self.random_range_i32(1, 4);
|
||||
@@ -410,7 +460,7 @@ impl<'a> WorldGenerator<'a> {
|
||||
let pool_count = (depth / 2).min(2) as i32;
|
||||
for _ in 0..pool_count {
|
||||
let typ = self.random_surface_pool_type(depth);
|
||||
self.place_surface_pool_chunk(grid, x0, x1, surface, typ, 2, 4);
|
||||
self.place_surface_pool_chunk(grid, x0, x1, surface, typ, sc(2), sc(4));
|
||||
}
|
||||
|
||||
let dune_count = self.random_range_i32(0, 2);
|
||||
@@ -435,16 +485,16 @@ impl<'a> WorldGenerator<'a> {
|
||||
if s < 10 {
|
||||
continue;
|
||||
}
|
||||
for y in (s - 6)..s {
|
||||
for y in (s - sc(6))..s {
|
||||
if grid.in_bounds(x, y) {
|
||||
grid.set_material(x, y, MaterialId::Wood);
|
||||
}
|
||||
}
|
||||
for dy in -2..=0 {
|
||||
for dx in -2..=2 {
|
||||
if dx * dx + dy * dy <= 5 {
|
||||
for dy in -sc(2)..=0 {
|
||||
for dx in -sc(2)..=sc(2) {
|
||||
if dx * dx + dy * dy <= sc(5) {
|
||||
let cx = x + dx;
|
||||
let cy = s - 6 + dy;
|
||||
let cy = s - sc(6) + dy;
|
||||
if grid.in_bounds(cx, cy) && grid.get(cx, cy).is_empty() {
|
||||
grid.set_material(cx, cy, MaterialId::Grass);
|
||||
}
|
||||
@@ -539,7 +589,7 @@ impl<'a> WorldGenerator<'a> {
|
||||
let lx = self.random_range_i32(4, (x1 - x0 - 4).max(5));
|
||||
let x = x0 + lx;
|
||||
let s = surface[lx as usize];
|
||||
let width = self.random_range_i32(4, 10);
|
||||
let width = self.random_range_i32(sc(4), sc(10));
|
||||
for dx in -width / 2..=width / 2 {
|
||||
let pile = (width / 2 - dx.abs()).max(1) + 1;
|
||||
for dy in 0..pile {
|
||||
@@ -564,7 +614,7 @@ impl<'a> WorldGenerator<'a> {
|
||||
let lx = self.random_range_i32(4, (x1 - x0 - 4).max(5));
|
||||
let x = x0 + lx;
|
||||
let s = surface[lx as usize];
|
||||
let h = self.random_range_i32(2, 5);
|
||||
let h = self.random_range_i32(sc(2), sc(5));
|
||||
for y in (s - h)..s {
|
||||
if grid.in_bounds(x, y) {
|
||||
grid.set_material(x, y, MaterialId::Stone);
|
||||
@@ -572,6 +622,15 @@ impl<'a> WorldGenerator<'a> {
|
||||
if grid.in_bounds(x + 1, y) {
|
||||
grid.set_material(x + 1, y, MaterialId::Stone);
|
||||
}
|
||||
if grid.in_bounds(x + 2, y) {
|
||||
grid.set_material(x + 2, y, MaterialId::Stone);
|
||||
}
|
||||
if grid.in_bounds(x + 3, y) {
|
||||
grid.set_material(x + 3, y, MaterialId::Stone);
|
||||
}
|
||||
if grid.in_bounds(x + 4, y) {
|
||||
grid.set_material(x + 4, y, MaterialId::Stone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -584,16 +643,16 @@ impl<'a> WorldGenerator<'a> {
|
||||
if s < 10 {
|
||||
continue;
|
||||
}
|
||||
for y in (s - 6)..s {
|
||||
for y in (s - sc(6))..s {
|
||||
if grid.in_bounds(x, y) {
|
||||
grid.set_material(x, y, MaterialId::Wood);
|
||||
}
|
||||
}
|
||||
for dy in -2..=0 {
|
||||
for dx in -2..=2 {
|
||||
if dx * dx + dy * dy <= 5 {
|
||||
for dy in -sc(2)..=0 {
|
||||
for dx in -sc(2)..=sc(2) {
|
||||
if dx * dx + dy * dy <= sc(5) {
|
||||
let cx = x + dx;
|
||||
let cy = s - 6 + dy;
|
||||
let cy = s - sc(6) + dy;
|
||||
if grid.in_bounds(cx, cy) && grid.get(cx, cy).is_empty() {
|
||||
grid.set_material(cx, cy, MaterialId::Grass);
|
||||
}
|
||||
@@ -668,7 +727,7 @@ impl<'a> WorldGenerator<'a> {
|
||||
for _ in 0..count {
|
||||
let x = self.random_range_i32(15, w - 15);
|
||||
let s = surface[x as usize];
|
||||
let width = self.random_range_i32(6, 16);
|
||||
let width = self.random_range_i32(sc(6), sc(16));
|
||||
for dx in -width / 2..=width / 2 {
|
||||
let pile = (width / 2 - dx.abs()).max(1) + 1;
|
||||
for dy in 0..pile {
|
||||
@@ -686,7 +745,7 @@ impl<'a> WorldGenerator<'a> {
|
||||
for _ in 0..count {
|
||||
let x = self.random_range_i32(10, w - 10);
|
||||
let s = surface[x as usize];
|
||||
let h = self.random_range_i32(3, 7);
|
||||
let h = self.random_range_i32(sc(3), sc(7));
|
||||
for y in (s - h)..s {
|
||||
if grid.in_bounds(x, y) {
|
||||
grid.set_material(x, y, MaterialId::Stone);
|
||||
@@ -694,6 +753,15 @@ impl<'a> WorldGenerator<'a> {
|
||||
if grid.in_bounds(x + 1, y) {
|
||||
grid.set_material(x + 1, y, MaterialId::Stone);
|
||||
}
|
||||
if grid.in_bounds(x + 2, y) {
|
||||
grid.set_material(x + 2, y, MaterialId::Stone);
|
||||
}
|
||||
if grid.in_bounds(x + 3, y) {
|
||||
grid.set_material(x + 3, y, MaterialId::Stone);
|
||||
}
|
||||
if grid.in_bounds(x + 4, y) {
|
||||
grid.set_material(x + 4, y, MaterialId::Stone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -705,7 +773,7 @@ impl<'a> WorldGenerator<'a> {
|
||||
let cx = self.random_range_i32(10, w - 10);
|
||||
let lower = (h * 2 / 3).max(surface[cx as usize] + 12);
|
||||
let cy = self.random_range_i32(lower, h - 10);
|
||||
let r = self.random_range_i32(3, 6);
|
||||
let r = self.random_range_i32(sc(3), sc(6));
|
||||
for dy in -r..=r {
|
||||
for dx in -r..=r {
|
||||
if dx * dx + dy * dy <= r * r {
|
||||
@@ -908,7 +976,7 @@ impl<'a> WorldGenerator<'a> {
|
||||
}
|
||||
|
||||
fn split_rect(&mut self, rect: Rect) -> Option<(Rect, Rect)> {
|
||||
let min_size = 22;
|
||||
let min_size = sc(9);
|
||||
if rect.w < min_size * 2 || rect.h < min_size * 2 {
|
||||
return None;
|
||||
}
|
||||
@@ -946,8 +1014,8 @@ impl<'a> WorldGenerator<'a> {
|
||||
}
|
||||
|
||||
fn carve_room_rect(&mut self, rect: Rect) -> Rect {
|
||||
let min_w = 9;
|
||||
let min_h = 9;
|
||||
let min_w = sc(4);
|
||||
let min_h = sc(4);
|
||||
let max_pad_x = ((rect.w - min_w) / 2).max(1);
|
||||
let max_pad_y = ((rect.h - min_h) / 2).max(1);
|
||||
let pad_x = self.random_range_i32(1, max_pad_x + 1);
|
||||
@@ -1012,10 +1080,11 @@ impl<'a> WorldGenerator<'a> {
|
||||
fn carve_l_corridor(&mut self, grid: &mut ChunkedGrid, a: &Rect, b: &Rect) {
|
||||
let c1 = (a.x + a.w / 2, a.y + a.h / 2);
|
||||
let c2 = (b.x + b.w / 2, b.y + b.h / 2);
|
||||
let cw = sc(2) / 2;
|
||||
let x0 = c1.0.min(c2.0);
|
||||
let x1 = c1.0.max(c2.0);
|
||||
for x in x0..=x1 {
|
||||
for dy in 0..2 {
|
||||
for dy in 0..cw {
|
||||
if grid.in_bounds(x, c1.1 + dy) {
|
||||
grid.set(x, c1.1 + dy, Cell::empty());
|
||||
}
|
||||
@@ -1024,7 +1093,7 @@ impl<'a> WorldGenerator<'a> {
|
||||
let y0 = c1.1.min(c2.1);
|
||||
let y1 = c1.1.max(c2.1);
|
||||
for y in y0..=y1 {
|
||||
for dx in 0..2 {
|
||||
for dx in 0..cw {
|
||||
if grid.in_bounds(c2.0 + dx, y) {
|
||||
grid.set(c2.0 + dx, y, Cell::empty());
|
||||
}
|
||||
@@ -1081,7 +1150,7 @@ impl<'a> WorldGenerator<'a> {
|
||||
}
|
||||
|
||||
fn vertical_clear(&self, grid: &ChunkedGrid, x: i32, y: i32) -> bool {
|
||||
for dy in -3..=2 {
|
||||
for dy in -4..=2 {
|
||||
if !grid.in_bounds(x, y + dy) || !grid.get(x, y + dy).is_empty() {
|
||||
return false;
|
||||
}
|
||||
@@ -1113,18 +1182,18 @@ impl<'a> WorldGenerator<'a> {
|
||||
}
|
||||
|
||||
fn surface_height(&mut self, x: i32, h: i32) -> i32 {
|
||||
let base = (h - 3) - ((x as f32 * 0.08).sin() * 4.0) as i32;
|
||||
let detail = ((x as f32 * 0.23).sin() * 2.0) as i32;
|
||||
let micro = ((x as f32 * 0.57).sin() * 1.0) as i32;
|
||||
let base = (h - 3) - ((x as f32 * 0.08).sin() * scf(4.0)) as i32;
|
||||
let detail = ((x as f32 * 0.23).sin() * scf(2.0)) as i32;
|
||||
let micro = ((x as f32 * 0.57).sin() * scf(1.0)) as i32;
|
||||
(base + detail + micro).max(10).min(h - 3)
|
||||
}
|
||||
|
||||
const SURFACE_BASE_Y: i32 = 120;
|
||||
|
||||
fn surface_height_world(&mut self, x: i32) -> i32 {
|
||||
let base = Self::SURFACE_BASE_Y - ((x as f32 * 0.08).sin() * 4.0) as i32;
|
||||
let detail = ((x as f32 * 0.23).sin() * 2.0) as i32;
|
||||
let micro = ((x as f32 * 0.57).sin() * 1.0) as i32;
|
||||
let base = Self::SURFACE_BASE_Y - ((x as f32 * 0.08).sin() * scf(4.0)) as i32;
|
||||
let detail = ((x as f32 * 0.23).sin() * scf(2.0)) as i32;
|
||||
let micro = ((x as f32 * 0.57).sin() * scf(1.0)) as i32;
|
||||
(base + detail + micro).max(10)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user