1use super::*;
2use crate::{
3 Land,
4 util::{CARDINALS, RandomField, Sampler},
5};
6use common::{
7 generation::SpecialEntity,
8 terrain::{BlockKind, SpriteKind},
9};
10use rand::prelude::*;
11use std::sync::Arc;
12use vek::*;
13
14pub struct CoastalWorkshop {
16 pub door_tile: Vec2<i32>,
18 bounds: Aabr<i32>,
20 pub(crate) alt: i32,
22}
23
24impl CoastalWorkshop {
25 pub fn generate(
26 land: &Land,
27 _rng: &mut impl Rng,
28 site: &Site,
29 door_tile: Vec2<i32>,
30 door_dir: Vec2<i32>,
31 tile_aabr: Aabr<i32>,
32 ) -> Self {
33 let door_tile_pos = site.tile_center_wpos(door_tile);
34 let bounds = Aabr {
35 min: site.tile_wpos(tile_aabr.min),
36 max: site.tile_wpos(tile_aabr.max),
37 };
38 Self {
39 door_tile: door_tile_pos,
40 bounds,
41 alt: land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32 + 2,
42 }
43 }
44}
45
46impl Structure for CoastalWorkshop {
47 #[cfg(feature = "use-dyn-lib")]
48 const UPDATE_FN: &'static [u8] = b"render_coastalworkshop\0";
49
50 #[cfg_attr(feature = "be-dyn-lib", export_name = "render_coastalworkshop")]
51 fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
52 let base = self.alt + 1;
53 let center = self.bounds.center();
54 let white = Fill::Sampling(Arc::new(|center| {
55 Some(match (RandomField::new(0).get(center)) % 37 {
56 0..=8 => Block::new(BlockKind::Rock, Rgb::new(251, 251, 227)),
57 9..=17 => Block::new(BlockKind::Rock, Rgb::new(245, 245, 229)),
58 18..=26 => Block::new(BlockKind::Rock, Rgb::new(250, 243, 221)),
59 27..=35 => Block::new(BlockKind::Rock, Rgb::new(240, 240, 230)),
60 _ => Block::new(BlockKind::Rock, Rgb::new(255, 244, 193)),
61 })
62 }));
63 let blue_broken = Fill::Sampling(Arc::new(|center| {
64 Some(match (RandomField::new(0).get(center)) % 20 {
65 0 => Block::new(BlockKind::Rock, Rgb::new(30, 187, 235)),
66 _ => Block::new(BlockKind::Rock, Rgb::new(11, 146, 187)),
67 })
68 }));
69 let length = (14 + RandomField::new(0).get(center.with_z(base)) % 3) as i32;
70 let width = (12 + RandomField::new(0).get((center - 1).with_z(base)) % 3) as i32;
71 let height = (12 + RandomField::new(0).get((center + 1).with_z(base)) % 4) as i32;
72
73 painter
75 .aabb(Aabb {
76 min: Vec2::new(center.x - length - 6, center.y - width - 6).with_z(base - 2),
77 max: Vec2::new(center.x + length + 7, center.y + width + 7).with_z(base - 1),
78 })
79 .fill(blue_broken.clone());
80
81 for dir in CARDINALS {
82 let frame_pos = Vec2::new(
83 center.x + dir.x * (length + 5),
84 center.y + dir.y * (width + 5),
85 );
86 painter
87 .line(center.with_z(base - 1), frame_pos.with_z(base - 1), 3.0)
88 .fill(blue_broken.clone());
89 }
90 painter
92 .aabb(Aabb {
93 min: Vec2::new(center.x - length - 6, center.y - width - 6).with_z(base - height),
94 max: Vec2::new(center.x + length + 7, center.y + width + 7).with_z(base - 2),
95 })
96 .fill(white.clone());
97 for f in 0..8 {
98 painter
99 .aabb(Aabb {
100 min: Vec2::new(center.x - length - 7 - f, center.y - width - 7 - f)
101 .with_z(base - 3 - f),
102 max: Vec2::new(center.x + length + 8 + f, center.y + width + 8 + f)
103 .with_z(base - 2 - f),
104 })
105 .fill(white.clone());
106 }
107 painter
109 .aabb(Aabb {
110 min: Vec2::new(center.x - length - 5, center.y - width - 5).with_z(base - 2),
111 max: Vec2::new(center.x + length + 6, center.y + width + 6).with_z(base + height),
112 })
113 .clear();
114 for dir in CARDINALS {
116 let clear_pos = Vec2::new(
117 center.x + dir.x * (length + 7),
118 center.y + dir.y * (width + 7),
119 );
120 painter
121 .line(center.with_z(base - 1), clear_pos.with_z(base - 1), 2.0)
122 .clear();
123 }
124 painter
126 .aabb(Aabb {
127 min: Vec2::new(center.x - length - 3, center.y - width - 3)
128 .with_z(base - 3 + height),
129 max: Vec2::new(center.x + length + 2, center.y + width + 2)
130 .with_z(base - 2 + height),
131 })
132 .fill(white.clone());
133 painter
134 .aabb(Aabb {
135 min: Vec2::new(center.x - length - 3, center.y - width - 3)
136 .with_z(base - 2 + height),
137 max: Vec2::new(center.x + length + 2, center.y + width + 2)
138 .with_z(base - 1 + height),
139 })
140 .fill(blue_broken.clone());
141 painter
142 .aabb(Aabb {
143 min: Vec2::new(center.x - length - 2, center.y - width - 2)
144 .with_z(base - 2 + height),
145 max: Vec2::new(center.x + length + 1, center.y + width + 1)
146 .with_z(base - 1 + height),
147 })
148 .clear();
149 painter
151 .aabb(Aabb {
152 min: Vec2::new(center.x - length, center.y - width).with_z(base - 2),
153 max: Vec2::new(center.x + length, center.y + width).with_z(base - 1),
154 })
155 .fill(blue_broken.clone());
156 painter
157 .aabb(Aabb {
158 min: Vec2::new(center.x - length + 1, center.y - width + 1).with_z(base - 2),
159 max: Vec2::new(center.x + length - 1, center.y + width - 1)
160 .with_z(base - 1 + height - 1),
161 })
162 .fill(white.clone());
163
164 let entry_limit = painter.aabb(Aabb {
166 min: Vec2::new(center.x - length, center.y - width).with_z(base - 2),
167 max: Vec2::new(center.x + length, center.y + width).with_z(base - 1 + height - 1),
168 });
169 painter
170 .line(
171 Vec2::new(center.x, center.y + 1 - width).with_z(base - 1),
172 Vec2::new(center.x, center.y - 2 + width).with_z(base - 1),
173 8.0,
174 )
175 .intersect(entry_limit)
176 .fill(blue_broken.clone());
177 painter
178 .line(
179 Vec2::new(center.x, center.y - width).with_z(base - 1),
180 Vec2::new(center.x, center.y + width).with_z(base - 1),
181 7.0,
182 )
183 .intersect(entry_limit)
184 .clear();
185 painter
186 .line(
187 Vec2::new(center.x + 1 - length, center.y).with_z(base - 1),
188 Vec2::new(center.x - 2 + length, center.y).with_z(base - 1),
189 8.0,
190 )
191 .intersect(entry_limit)
192 .fill(blue_broken.clone());
193 painter
194 .line(
195 Vec2::new(center.x - length, center.y).with_z(base - 1),
196 Vec2::new(center.x + length, center.y).with_z(base - 1),
197 7.0,
198 )
199 .intersect(entry_limit)
200 .clear();
201 painter
203 .aabb(Aabb {
204 min: Vec2::new(center.x - length + 2, center.y - width + 2).with_z(base - 2),
205 max: Vec2::new(center.x + length - 2, center.y + width - 2)
206 .with_z(base - 2 + height - 1),
207 })
208 .clear();
209
210 painter
212 .aabb(Aabb {
213 min: Vec2::new(center.x - length + 5, center.y - width + 5).with_z(base - 3),
214 max: Vec2::new(center.x + length - 5, center.y + width - 5).with_z(base - 2),
215 })
216 .fill(blue_broken.clone());
217 painter
218 .aabb(Aabb {
219 min: Vec2::new(center.x - length + 6, center.y - width + 6).with_z(base - 3),
220 max: Vec2::new(center.x + length - 6, center.y + width - 6).with_z(base - 2),
221 })
222 .fill(white.clone());
223
224 for d in 0..2 {
226 let door_lamp_pos =
227 Vec2::new(center.x - length + 2 + (d * ((2 * (length)) - 5)), center.y)
228 .with_z(base + 6);
229 painter.rotated_sprite(
230 door_lamp_pos,
231 SpriteKind::WallLampSmall,
232 2 + ((d * 4) as u8),
233 );
234
235 let lamp_pos = Vec2::new(center.x, center.y - width + 2 + (d * ((2 * (width)) - 5)))
236 .with_z(base + 6);
237 painter.rotated_sprite(lamp_pos, SpriteKind::WallLampSmall, 4 - ((d * 4) as u8));
238 }
239 for d in 0..2 {
240 let door_lamp_pos =
241 Vec2::new(center.x - length - 1 + (d * ((2 * (length)) + 1)), center.y)
242 .with_z(base + 6);
243 painter.rotated_sprite(
244 door_lamp_pos,
245 SpriteKind::WallLampSmall,
246 6 + ((d * 4) as u8),
247 );
248
249 let lamp_pos = Vec2::new(center.x, center.y - width - 1 + (d * ((2 * (width)) + 1)))
250 .with_z(base + 6);
251 painter.rotated_sprite(lamp_pos, SpriteKind::WallLampSmall, 8 - ((d * 4) as u8));
252 }
253
254 painter
256 .cylinder(Aabb {
257 min: (center - 4).with_z(base + height - 4),
258 max: (center + 2).with_z(base - 2 + height + (height / 2)),
259 })
260 .fill(blue_broken);
261
262 let top_limit = painter.aabb(Aabb {
263 min: Vec2::new(center.x - length, center.y - width).with_z(base + height - 2),
264 max: Vec2::new(center.x + length, center.y + width)
265 .with_z(base - 2 + height + (height / 2)),
266 });
267 painter
268 .superquadric(
269 Aabb {
270 min: Vec2::new(center.x - length - 1, center.y - width - 1)
271 .with_z(base + height - (height / 2)),
272 max: Vec2::new(center.x + length, center.y + width)
273 .with_z(base - 2 + height + (height / 2)),
274 },
275 1.5,
276 )
277 .intersect(top_limit)
278 .fill(white.clone());
279 painter
281 .cylinder(Aabb {
282 min: (center - 3).with_z(base + height - 4),
283 max: (center + 1).with_z(base - 2 + height + (height / 2)),
284 })
285 .clear();
286
287 painter
288 .cylinder(Aabb {
289 min: (center - 3).with_z(base - 2),
290 max: (center + 1).with_z(base - 1),
291 })
292 .fill(white);
293 painter
294 .aabb(Aabb {
295 min: (center - 2).with_z(base - 2),
296 max: (center).with_z(base - 1),
297 })
298 .clear();
299 painter
300 .aabb(Aabb {
301 min: (center - 2).with_z(base - 3),
302 max: (center).with_z(base - 2),
303 })
304 .fill(Fill::Block(Block::air(SpriteKind::Ember)));
305
306 let mut stations = vec![
307 SpriteKind::CraftingBench,
308 SpriteKind::Forge,
309 SpriteKind::SpinningWheel,
310 SpriteKind::TanningRack,
311 SpriteKind::CookingPot,
312 SpriteKind::Cauldron,
313 SpriteKind::Loom,
314 SpriteKind::Anvil,
315 SpriteKind::DismantlingBench,
316 SpriteKind::RepairBench,
317 ];
318 'outer: for d in 0..3 {
319 for dir in CARDINALS {
320 if stations.is_empty() {
321 break 'outer;
322 }
323 let position = center + dir * (4 + d * 2);
324 let cr_station = stations.swap_remove(
325 RandomField::new(0).get(position.with_z(base)) as usize % stations.len(),
326 );
327 painter.sprite(position.with_z(base - 2), cr_station);
328 }
329 }
330
331 painter.spawn(
332 EntityInfo::at((center - 2).with_z(base - 2).map(|e| e as f32 + 0.5))
333 .into_special(SpecialEntity::Waypoint),
334 );
335 }
336}