banished_game/production/
quarry.rs1use std::sync::Arc;
18
19use crate::nature::seeding::{Cells, Placed};
20use crate::terrain::{CellType, HeightGrid};
21
22#[derive(Debug, Clone, PartialEq)]
24pub struct QuarryTemplate {
25 pub shallow: f32,
28 pub deep: f32,
30 pub vertices: Arc<Vec<[f32; 3]>>,
33}
34
35const HEIGHT_SCALE: f32 = 256.0;
37pub const QUARRY_CELL: CellType = CellType(5);
39
40pub fn dig(heights: &mut [i16], width: usize, q: &QuarryTemplate, p: &Placed, floor: f32) -> bool {
44 let half = ((width - 1) >> 1) as f32;
45 let model = crate::math::Transform::of_model(p.yaw, p.position);
46 let mut changed = false;
47 for &v in q.vertices.iter() {
48 let [x, y, z] = model.apply(v);
50 let z = (z + 0.0).max(floor);
51 let (gx, gy) = ((x + 0.25 + half) as i32, (y + 0.25 + half) as i32);
52 if gx < 0 || gy < 0 || width as i32 <= gx || width as i32 <= gy {
53 continue;
54 }
55 let h = (z * HEIGHT_SCALE) as i32 as i16;
56 let cell = &mut heights[gy as usize * width + gx as usize];
57 changed |= *cell != h;
58 *cell = h;
59 }
60 changed
61}
62
63pub fn claim_steep_cells(cells: &mut Cells, terrain: &HeightGrid, entity: usize, p: &Placed) {
67 let n = cells.size as i32;
68 let half = (n >> 1) as f32 - 0.5;
69 let (x0, y0) = p.cell;
70 let (w, h) = p.footprint;
71 for y in y0..y0 + h {
72 for x in x0..x0 + w {
73 if x < 0 || y < 0 || n <= x || n <= y {
74 continue;
75 }
76 let (cx, cy) = (x as f32 - half, y as f32 - half);
77 for (dx, dy) in [(-0.25, -0.25), (-0.25, 0.25), (0.25, -0.25), (0.25, 0.25)] {
78 let normal = terrain.normal_below(cx + dx, cy + dy, 100.0, 200.0);
82 if normal[2] < 0.85 {
83 let i = (y * n + x) as usize;
84 cells.set_type(i, QUARRY_CELL);
85 cells.objects[i] = Some(entity);
86 }
87 }
88 }
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 fn placed() -> Placed {
97 Placed {
98 template: 0,
99 bucket: 0,
100 cell: (2, 2),
101 footprint: (4, 4),
102 position: [0.0, 0.0, 0.0],
103 yaw: 0.0,
104 variant: 0,
105 mesh: 0,
106 growth: 0.0,
107 growth_state: None,
108 spawn_state: None,
109 alive: true,
110 removal_requested: false,
111 animation: None,
112 scale: [1.0; 4],
113 }
114 }
115
116 #[test]
119 fn the_pit_deepens_to_its_floor_and_claims_steep_cells() {
120 let q = QuarryTemplate {
121 shallow: -1.0,
122 deep: -3.0,
123 vertices: Arc::new(vec![[0.0, 0.0, -5.0], [1.0, 0.0, -0.5], [2.0, 0.0, 0.0]]),
124 };
125 let width = 17;
126 let mut heights = vec![0i16; width * width];
127 let p = placed();
128 assert!(dig(&mut heights, width, &q, &p, q.shallow));
129 let at = |h: &[i16], x: usize| h[8 * width + 8 + x];
130 assert_eq!(
131 (at(&heights, 0), at(&heights, 1), at(&heights, 2)),
132 (-256, -128, 0)
133 );
134 assert!(dig(&mut heights, width, &q, &p, q.deep));
135 assert_eq!(at(&heights, 0), -768);
136 let mut cells = Cells::new(8, vec![CellType::GROUND; 64]);
137 let grid = HeightGrid {
138 width,
139 heights: &heights,
140 };
141 claim_steep_cells(&mut cells, &grid, 7, &p);
142 let n = 8;
143 let claimed: Vec<usize> = (0..n * n)
144 .filter(|&i| cells.types[i] == QUARRY_CELL)
145 .collect();
146 assert!(!claimed.is_empty());
147 assert!(claimed.iter().all(|&i| cells.objects[i] == Some(7)));
148 }
149}