veloren_world/site2/plot/desert_city_multiplot.rs
1use super::*;
2use crate::{
3 Land,
4 assets::AssetHandle,
5 site2::gen::{PrimitiveTransform, spiral_staircase},
6 util::{DIAGONALS, NEIGHBORS, RandomField, Sampler},
7};
8use common::{
9 generation::{EntityInfo, SpecialEntity},
10 terrain::{Block, BlockKind, SpriteKind, Structure as PrefabStructure, StructuresGroup},
11};
12use lazy_static::lazy_static;
13use rand::prelude::*;
14use std::sync::Arc;
15use vek::*;
16
17enum PlotKind {
18 MarketHall {
19 floors: i32,
20 towers: [(WatchTower, Vec2<i32>); 4],
21 },
22 Multiple {
23 subplots: Vec<(SubPlotKind, Vec2<i32>)>,
24 },
25}
26
27enum SubPlotKind {
28 WorkshopHouse { floors: i32 },
29 Library,
30 WatchTower(WatchTower),
31 PalmTree,
32 AnimalShed,
33}
34
35struct WatchTower {
36 length: i32,
37 height: i32,
38}
39
40/// Represents house data generated by the `generate()` method
41pub struct DesertCityMultiPlot {
42 /// Tile position of the door tile
43 pub door_tile: Vec2<i32>,
44 /// Axis aligned bounding region for the house
45 bounds: Aabr<i32>,
46 /// Approximate altitude of the door tile
47 pub(crate) alt: i32,
48 diameter: i32,
49 plot_kind: PlotKind,
50 campfire: bool,
51}
52
53impl DesertCityMultiPlot {
54 pub fn generate(
55 land: &Land,
56 rng: &mut impl Rng,
57 site: &Site,
58 door_tile: Vec2<i32>,
59 door_dir: Vec2<i32>,
60 tile_aabr: Aabr<i32>,
61 campfire: bool,
62 alt: Option<i32>,
63 ) -> Self {
64 let door_tile_pos = site.tile_center_wpos(door_tile);
65 let bounds = Aabr {
66 min: site.tile_wpos(tile_aabr.min),
67 max: site.tile_wpos(tile_aabr.max),
68 };
69 let diameter = 10 + (bounds.max.x - bounds.min.x).min(bounds.max.y - bounds.min.y);
70 let plot_kind = match rng.gen_range(0..5) {
71 0 => {
72 let floors = rng.gen_range(2..5);
73 let towers = {
74 let center = bounds.center();
75 let room_length = diameter / 4;
76 let tower_length = diameter / 14;
77 let mut tower = |i| {
78 let tower_center = center
79 + DIAGONALS[i]
80 * (Vec2::new(
81 room_length + tower_length + 1,
82 room_length + 2 * tower_length,
83 ));
84 let height = rng.gen_range(25..35);
85 (
86 WatchTower {
87 length: tower_length,
88 height,
89 },
90 tower_center,
91 )
92 };
93 [tower(0), tower(1), tower(2), tower(3)]
94 };
95 PlotKind::MarketHall { floors, towers }
96 },
97 _ => {
98 let mut subplot_kind = || match rng.gen_range(0..15) {
99 0..=5 => SubPlotKind::WorkshopHouse {
100 floors: rng.gen_range(1..4),
101 },
102 6..=7 => SubPlotKind::Library,
103 8..=9 => SubPlotKind::AnimalShed,
104 10..=11 => SubPlotKind::WatchTower(WatchTower {
105 length: diameter / 14,
106 height: rng.gen_range(25..35),
107 }),
108 _ => SubPlotKind::PalmTree,
109 };
110 let subplot_center = |i| {
111 let corner_pos = bounds.min + diameter / 5;
112 corner_pos + SQUARE_4[i] * (diameter / 2 - 5)
113 };
114
115 let sw_plot = (subplot_kind(), subplot_center(0));
116 let se_plot = (subplot_kind(), subplot_center(1));
117 let nw_plot = (subplot_kind(), subplot_center(2));
118 let ne_plot = (subplot_kind(), subplot_center(3));
119
120 PlotKind::Multiple {
121 subplots: vec![ne_plot, se_plot, sw_plot, nw_plot],
122 }
123 },
124 };
125 Self {
126 bounds,
127 door_tile: door_tile_pos,
128 alt: alt.unwrap_or_else(|| {
129 land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32
130 }),
131 diameter,
132 plot_kind,
133 campfire,
134 }
135 }
136}
137
138impl Structure for DesertCityMultiPlot {
139 #[cfg(feature = "use-dyn-lib")]
140 const UPDATE_FN: &'static [u8] = b"render_desertcitymultiplot\0";
141
142 #[cfg_attr(feature = "be-dyn-lib", export_name = "render_desertcitymultiplot")]
143 fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
144 let sandstone = Fill::Sampling(Arc::new(|center| {
145 Some(match (RandomField::new(0).get(center)) % 37 {
146 0..=8 => Block::new(BlockKind::Rock, Rgb::new(245, 212, 129)),
147 9..=17 => Block::new(BlockKind::Rock, Rgb::new(246, 214, 133)),
148 18..=26 => Block::new(BlockKind::Rock, Rgb::new(247, 216, 136)),
149 27..=35 => Block::new(BlockKind::Rock, Rgb::new(248, 219, 142)),
150 _ => Block::new(BlockKind::Rock, Rgb::new(235, 178, 99)),
151 })
152 }));
153 let sandstone_broken = Fill::Sampling(Arc::new(|center| {
154 Some(match (RandomField::new(0).get(center)) % 42 {
155 0..=8 => Block::new(BlockKind::Rock, Rgb::new(245, 212, 129)),
156 9..=17 => Block::new(BlockKind::Rock, Rgb::new(246, 214, 133)),
157 18..=26 => Block::new(BlockKind::Rock, Rgb::new(247, 216, 136)),
158 27..=35 => Block::new(BlockKind::Rock, Rgb::new(248, 219, 142)),
159 36..=40 => Block::new(BlockKind::Air, Rgb::new(0, 0, 0)),
160 _ => Block::new(BlockKind::Rock, Rgb::new(235, 178, 99)),
161 })
162 }));
163 let wood = Fill::Brick(BlockKind::Wood, Rgb::new(71, 33, 11), 12);
164 let base = self.alt + 1;
165 let center = self.bounds.center();
166 // Fence
167 painter
168 .aabb(Aabb {
169 min: Vec2::new(self.bounds.min.x + 1, self.bounds.min.y + 1).with_z(base - 20),
170 max: Vec2::new(self.bounds.min.x + 2, self.bounds.max.y).with_z(base + 2),
171 })
172 .union(painter.aabb(Aabb {
173 min: Vec2::new(self.bounds.max.x - 1, self.bounds.min.y + 1).with_z(base - 20),
174 max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(base + 2),
175 }))
176 .union(painter.aabb(Aabb {
177 min: Vec2::new(self.bounds.min.x + 1, self.bounds.min.y + 1).with_z(base - 20),
178 max: Vec2::new(self.bounds.max.x, self.bounds.min.y + 2).with_z(base + 2),
179 }))
180 .union(painter.aabb(Aabb {
181 min: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y - 1).with_z(base - 20),
182 max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(base + 2),
183 }))
184 .fill(sandstone_broken.clone());
185
186 // Gate1
187 painter
188 .aabb(Aabb {
189 min: Vec2::new(self.bounds.min.x + 1, center.y - 3).with_z(base - 20),
190 max: Vec2::new(self.bounds.max.x, center.y + 3).with_z(base + 10),
191 })
192 .fill(sandstone.clone());
193
194 painter
195 .aabb(Aabb {
196 min: Vec2::new(self.bounds.min.x + 1, center.y - 3).with_z(base + 9),
197 max: Vec2::new(self.bounds.max.x, center.y - 1).with_z(base + 10),
198 })
199 .clear();
200 painter
201 .aabb(Aabb {
202 min: Vec2::new(self.bounds.min.x + 1, center.y + 1).with_z(base + 9),
203 max: Vec2::new(self.bounds.max.x, center.y + 3).with_z(base + 10),
204 })
205 .clear();
206 painter
207 .aabb(Aabb {
208 min: Vec2::new(self.bounds.min.x + 2, center.y - 3).with_z(base + 8),
209 max: Vec2::new(self.bounds.max.x - 1, center.y + 3).with_z(base + 10),
210 })
211 .clear();
212 painter
213 .aabb(Aabb {
214 min: Vec2::new(self.bounds.min.x + 3, center.y - 3).with_z(base - 20),
215 max: Vec2::new(self.bounds.max.x - 2, center.y + 3).with_z(base + 10),
216 })
217 .clear();
218 // Gate2
219 painter
220 .aabb(Aabb {
221 min: Vec2::new(center.x - 2, self.bounds.min.y + 1).with_z(base - 20),
222 max: Vec2::new(center.x + 4, self.bounds.max.y).with_z(base + 10),
223 })
224 .fill(sandstone.clone());
225 painter
226 .aabb(Aabb {
227 min: Vec2::new(center.x + 2, self.bounds.min.y + 1).with_z(base + 9),
228 max: Vec2::new(center.x + 4, self.bounds.max.y).with_z(base + 10),
229 })
230 .clear();
231 painter
232 .aabb(Aabb {
233 min: Vec2::new(center.x - 2, self.bounds.min.y + 1).with_z(base + 9),
234 max: Vec2::new(center.x, self.bounds.max.y).with_z(base + 10),
235 })
236 .clear();
237 painter
238 .aabb(Aabb {
239 min: Vec2::new(center.x - 2, self.bounds.min.y + 2).with_z(base + 8),
240 max: Vec2::new(center.x + 4, self.bounds.max.y - 1).with_z(base + 10),
241 })
242 .clear();
243 painter
244 .aabb(Aabb {
245 min: Vec2::new(center.x - 2, self.bounds.min.y + 3).with_z(base - 20),
246 max: Vec2::new(center.x + 4, self.bounds.max.y - 2).with_z(base + 10),
247 })
248 .clear();
249 // gate clear
250 painter
251 .aabb(Aabb {
252 min: Vec2::new(self.bounds.min.x + 1, center.y - 2).with_z(base),
253 max: Vec2::new(self.bounds.max.x, center.y + 2).with_z(base + 7),
254 })
255 .clear();
256 painter
257 .aabb(Aabb {
258 min: Vec2::new(center.x - 1, self.bounds.min.y + 1).with_z(base),
259 max: Vec2::new(center.x + 3, self.bounds.max.y).with_z(base + 7),
260 })
261 .clear();
262 // Foundation
263 painter
264 .aabb(Aabb {
265 min: (self.bounds.min + 1).with_z(base - 20),
266 max: (self.bounds.max).with_z(base),
267 })
268 .fill(sandstone.clone());
269
270 // buildings
271 match &self.plot_kind {
272 // Market Hall with Watchtowers
273 PlotKind::MarketHall { floors, towers } => {
274 for floor in 0..*floors {
275 let room_height = self.diameter / 6;
276 let floor_level = base + (room_height * floor);
277 let room_length = (self.diameter / 4) - (2 * floor);
278 // Windowsills
279 painter
280 .aabb(Aabb {
281 min: Vec2::new(center.x - room_length - 1, center.y)
282 .with_z(floor_level + 1),
283 max: Vec2::new(center.x + room_length + 1, center.y + 2)
284 .with_z(floor_level + 2),
285 })
286 .fill(wood.clone());
287 // Room
288 painter
289 .aabb(Aabb {
290 min: Vec2::new(center.x - room_length, center.y - room_length + 3)
291 .with_z(floor_level),
292 max: Vec2::new(center.x + room_length, center.y + room_length - 1)
293 .with_z(floor_level + room_height),
294 })
295 .fill(sandstone.clone());
296 // Window Sprites
297 painter
298 .aabb(Aabb {
299 min: Vec2::new(center.x - room_length, center.y)
300 .with_z(floor_level + 2),
301 max: Vec2::new(center.x + room_length, center.y + 2)
302 .with_z(floor_level + 5),
303 })
304 .fill(Fill::Block(
305 Block::air(SpriteKind::WindowArabic).with_ori(4).unwrap(),
306 ));
307 // Clear Room
308 painter
309 .aabb(Aabb {
310 min: Vec2::new(center.x - room_length + 1, center.y - room_length + 4)
311 .with_z(floor_level),
312 max: Vec2::new(center.x + room_length - 1, center.y + room_length - 2)
313 .with_z(floor_level + room_height - 2),
314 })
315 .clear();
316 // Overhang1
317 painter
318 .aabb(Aabb {
319 min: Vec2::new(center.x - room_length + 1, center.y + room_length - 1)
320 .with_z(floor_level + room_height - 1),
321 max: Vec2::new(center.x + room_length - 1, center.y + room_length)
322 .with_z(floor_level + room_height),
323 })
324 .fill(wood.clone());
325 // Overhang2
326 painter
327 .aabb(Aabb {
328 min: Vec2::new(center.x + room_length, center.y - room_length + 2)
329 .with_z(floor_level + room_height - 1),
330 max: Vec2::new(center.x + room_length + 1, center.y + room_length - 2)
331 .with_z(floor_level + room_height),
332 })
333 .fill(wood.clone());
334 // Overhang3
335 painter
336 .aabb(Aabb {
337 min: Vec2::new(center.x - room_length - 1, center.y - room_length + 4)
338 .with_z(floor_level + room_height - 1),
339 max: Vec2::new(center.x - room_length, center.y + room_length - 2)
340 .with_z(floor_level + room_height),
341 })
342 .fill(wood.clone());
343 // Door Frame
344 painter
345 .aabb(Aabb {
346 min: Vec2::new(center.x - 2, center.y + room_length - 1)
347 .with_z(floor_level),
348 max: Vec2::new(center.x + 2, center.y + room_length)
349 .with_z(floor_level + 5),
350 })
351 .fill(sandstone.clone());
352 // Clear Door
353 painter
354 .aabb(Aabb {
355 min: Vec2::new(center.x - 1, center.y + room_length - 2)
356 .with_z(floor_level),
357 max: Vec2::new(center.x + 1, center.y + room_length)
358 .with_z(floor_level + 4),
359 })
360 .clear();
361 // Remove Terrain in front of doors
362 painter
363 .aabb(Aabb {
364 min: Vec2::new(center.x - 2, center.y + room_length)
365 .with_z(floor_level),
366 max: Vec2::new(center.x + 2, center.y + room_length + 4)
367 .with_z(floor_level + 5),
368 })
369 .clear();
370 // Stairs for each storey
371 painter
372 .ramp_inset(
373 Aabb {
374 min: Vec2::new(center.x - room_length, center.y - room_length + 1)
375 .with_z(floor_level),
376 max: Vec2::new(center.x + room_length, center.y - room_length + 3)
377 .with_z(floor_level + room_height),
378 },
379 2 * room_length,
380 Dir::X,
381 )
382 .fill(sandstone.clone());
383 //interior room compartment with entries
384 painter
385 .aabb(Aabb {
386 min: Vec2::new(
387 center.x - (2 * room_length / 3) + 1,
388 center.y - (2 * room_length / 3) + 4,
389 )
390 .with_z(floor_level),
391 max: Vec2::new(
392 center.x + (2 * room_length / 3) - 1,
393 center.y + (2 * room_length / 3) - 2,
394 )
395 .with_z(floor_level + room_height - 2),
396 })
397 .fill(sandstone.clone());
398
399 painter
400 .aabb(Aabb {
401 min: Vec2::new(
402 center.x - (2 * room_length / 3) + 2,
403 center.y - (2 * room_length / 3) + 5,
404 )
405 .with_z(floor_level),
406 max: Vec2::new(
407 center.x + (2 * room_length / 3) - 2,
408 center.y + (2 * room_length / 3) - 3,
409 )
410 .with_z(floor_level + room_height - 2),
411 })
412 .clear();
413
414 painter
415 .aabb(Aabb {
416 min: Vec2::new(
417 center.x - (room_length / 6),
418 center.y - (2 * room_length / 3) + 4,
419 )
420 .with_z(floor_level),
421 max: Vec2::new(
422 center.x + (room_length / 6),
423 center.y + (2 * room_length / 3) - 2,
424 )
425 .with_z(floor_level + 3),
426 })
427 .clear();
428 painter
429 .aabb(Aabb {
430 min: Vec2::new(
431 center.x - (2 * room_length / 3) + 1,
432 center.y + 1 + (room_length / 6),
433 )
434 .with_z(floor_level),
435 max: Vec2::new(
436 center.x + (2 * room_length / 3) - 1,
437 center.y + 1 - (room_length / 6),
438 )
439 .with_z(floor_level + 3),
440 })
441 .clear();
442
443 // interior room Wall Lamps
444 painter
445 .aabb(Aabb {
446 min: Vec2::new(center.x - 1, center.y - (2 * room_length / 3) + 5)
447 .with_z(floor_level + 4),
448 max: Vec2::new(center.x + 1, center.y - (2 * room_length / 3) + 6)
449 .with_z(floor_level + 5),
450 })
451 .fill(Fill::Block(
452 Block::air(SpriteKind::WallLampSmall).with_ori(4).unwrap(),
453 ));
454
455 painter
456 .aabb(Aabb {
457 min: Vec2::new(center.x - 1, center.y + (2 * room_length / 3) - 2)
458 .with_z(floor_level + 4),
459 max: Vec2::new(center.x + 1, center.y + (2 * room_length / 3) - 1)
460 .with_z(floor_level + 5),
461 })
462 .fill(Fill::Block(
463 Block::air(SpriteKind::WallLampSmall).with_ori(4).unwrap(),
464 ));
465
466 // Wall Lamps
467 painter
468 .aabb(Aabb {
469 min: Vec2::new(center.x - 1, center.y - room_length + 4)
470 .with_z(floor_level + 4),
471 max: Vec2::new(center.x + 1, center.y - room_length + 5)
472 .with_z(floor_level + 5),
473 })
474 .fill(Fill::Block(
475 Block::air(SpriteKind::WallLampSmall).with_ori(4).unwrap(),
476 ));
477
478 painter
479 .aabb(Aabb {
480 min: Vec2::new(center.x - 1, center.y + room_length)
481 .with_z(floor_level + 4),
482 max: Vec2::new(center.x + 1, center.y + room_length + 1)
483 .with_z(floor_level + 5),
484 })
485 .fill(Fill::Block(
486 Block::air(SpriteKind::WallLampSmall).with_ori(4).unwrap(),
487 ));
488
489 // Floor specific stuff
490 match floor {
491 // Ground level room furniture - bank
492 0 => {
493 for dir in NEIGHBORS {
494 let pos = center + dir * 4;
495 painter.owned_resource_sprite(
496 pos.with_z(floor_level),
497 SpriteKind::Crate,
498 0,
499 );
500 }
501 for dir in NEIGHBORS {
502 let pos = center + dir * 8;
503 painter.sprite(pos.with_z(floor_level), SpriteKind::DrawerSmall);
504 }
505
506 for dir in SQUARE_4 {
507 let corner_pos =
508 Vec2::new(center.x - 4, center.y - room_length + 4);
509 let planter_pos = Vec2::new(
510 corner_pos.x + dir.x * 7,
511 corner_pos.y + dir.y * ((2 * room_length) - 7),
512 );
513 painter.rotated_sprite(
514 planter_pos.with_z(floor_level),
515 SpriteKind::DrawerMedium,
516 4 - (4 * dir.y) as u8,
517 );
518 }
519 },
520 // First floor room furniture
521 1 => {
522 for dir in NEIGHBORS {
523 let pos = center + dir * 7;
524 painter.sprite(pos.with_z(floor_level), SpriteKind::Planter);
525 }
526
527 for dir in SQUARE_4 {
528 let corner_pos =
529 Vec2::new(center.x - 4, center.y - room_length + 4);
530 let planter_pos = Vec2::new(
531 corner_pos.x + dir.x * 7,
532 corner_pos.y + dir.y * ((2 * room_length) - 7),
533 );
534 painter.rotated_sprite(
535 planter_pos.with_z(floor_level),
536 SpriteKind::DrawerSmall,
537 4 - (4 * dir.y) as u8,
538 );
539 }
540 },
541 _ => {},
542 }
543 // On top floor, carve the roof terrace
544 if floor == (*floors - 1) {
545 painter
546 .aabb(Aabb {
547 min: Vec2::new(
548 center.x - room_length + 1,
549 center.y - room_length + 4,
550 )
551 .with_z(floor_level + room_height - 1),
552 max: Vec2::new(
553 center.x + room_length - 1,
554 center.y + room_length - 2,
555 )
556 .with_z(floor_level + room_height),
557 })
558 .clear();
559 painter
560 .aabb(Aabb {
561 min: Vec2::new(
562 center.x + room_length - 3,
563 center.y - room_length + 1,
564 )
565 .with_z(floor_level + room_height - 1),
566 max: Vec2::new(
567 center.x + room_length - 1,
568 center.y - room_length + 4,
569 )
570 .with_z(floor_level + room_height),
571 })
572 .clear();
573 // Roof Ornament
574 painter
575 .aabb(Aabb {
576 min: Vec2::new(center.x - room_length, center.y + room_length - 2)
577 .with_z(floor_level + room_height),
578 max: Vec2::new(center.x + room_length, center.y + room_length - 1)
579 .with_z(floor_level + room_height + 2),
580 })
581 .fill(sandstone.clone());
582 painter
583 .aabb(Aabb {
584 min: Vec2::new(
585 center.x - room_length + 2,
586 center.y + room_length - 2,
587 )
588 .with_z(floor_level + room_height + 2),
589 max: Vec2::new(
590 center.x + room_length - 2,
591 center.y + room_length - 1,
592 )
593 .with_z(floor_level + room_height + 3),
594 })
595 .fill(sandstone.clone());
596 painter
597 .aabb(Aabb {
598 min: Vec2::new(center.x - 2, center.y + room_length - 2)
599 .with_z(floor_level + room_height + 3),
600 max: Vec2::new(center.x + 2, center.y + room_length - 1)
601 .with_z(floor_level + room_height + 4),
602 })
603 .fill(sandstone.clone());
604 // Wood Beams
605 for dir in SQUARE_4 {
606 let corner_pos =
607 Vec2::new(center.x - room_length + 3, center.y - room_length + 7);
608 let pos = Vec2::new(
609 corner_pos.x + dir.x * ((2 * room_length) - 8),
610 corner_pos.y + dir.y * ((2 * room_length) - 12),
611 );
612 painter
613 .aabb(Aabb {
614 min: pos.with_z(floor_level + room_height - 1),
615 max: (pos + 1)
616 .with_z(floor_level + room_height + (room_height / 2)),
617 })
618 .fill(wood.clone());
619 }
620 painter
621 .aabb(Aabb {
622 min: Vec2::new(
623 center.x - room_length + 2,
624 center.y - room_length + 6,
625 )
626 .with_z(floor_level + room_height + (room_height / 2) - 1),
627 max: Vec2::new(
628 center.x + room_length - 3,
629 center.y + room_length - 3,
630 )
631 .with_z(floor_level + room_height + (room_height / 2)),
632 })
633 .fill(wood.clone());
634
635 painter
636 .aabb(Aabb {
637 min: Vec2::new(
638 center.x - room_length + 3,
639 center.y - room_length + 7,
640 )
641 .with_z(floor_level + room_height + (room_height / 2) - 1),
642 max: Vec2::new(
643 center.x + room_length - 4,
644 center.y + room_length - 4,
645 )
646 .with_z(floor_level + room_height + (room_height / 2)),
647 })
648 .clear();
649
650 for b in 0..(room_length - 3) {
651 painter
652 .aabb(Aabb {
653 min: Vec2::new(
654 center.x - room_length + 3 + (b * 2),
655 center.y - room_length + 5,
656 )
657 .with_z(floor_level + room_height + (room_height / 2)),
658 max: Vec2::new(
659 center.x - room_length + 4 + (b * 2),
660 center.y + room_length - 2,
661 )
662 .with_z(floor_level + room_height + (room_height / 2) + 1),
663 })
664 .fill(wood.clone());
665 }
666 // roof furniture
667 for d in 0..2 {
668 for dir in NEIGHBORS {
669 let pos = center + dir * (3 + d * 3);
670 painter.sprite(
671 pos.with_z(floor_level + room_height - 1),
672 SpriteKind::Planter,
673 );
674 }
675 }
676 }
677 }
678 // WatchTowers
679 for (tower, tower_center) in towers {
680 // Tower Windowsills
681 for h in 0..4 {
682 painter
683 .aabb(Aabb {
684 min: Vec2::new(
685 tower_center.x - 1,
686 tower_center.y - tower.length - 1,
687 )
688 .with_z(base + 8 + (h * (tower.height / 5))),
689 max: Vec2::new(
690 tower_center.x + 1,
691 tower_center.y + tower.length + 1,
692 )
693 .with_z(base + 9 + (h * (tower.height / 5))),
694 })
695 .fill(wood.clone());
696 }
697 for h in 0..4 {
698 painter
699 .aabb(Aabb {
700 min: Vec2::new(
701 tower_center.x - tower.length - 1,
702 tower_center.y - 1,
703 )
704 .with_z(base + 8 + (h * (tower.height / 5))),
705 max: Vec2::new(
706 tower_center.x + tower.length + 1,
707 tower_center.y + 1,
708 )
709 .with_z(base + 9 + (h * (tower.height / 5))),
710 })
711 .fill(wood.clone());
712 }
713 // Tower base
714 painter
715 .aabb(Aabb {
716 min: (tower_center - tower.length - 1).with_z(base - 10),
717 max: (tower_center + tower.length + 1).with_z(base + 6),
718 })
719 .fill(sandstone.clone());
720 // Tower
721 painter
722 .aabb(Aabb {
723 min: (tower_center - tower.length).with_z(base),
724 max: (tower_center + tower.length).with_z(base + tower.height),
725 })
726 .fill(sandstone.clone());
727 // Tower Windows
728 for h in 0..4 {
729 painter
730 .aabb(Aabb {
731 min: Vec2::new(tower_center.x - 1, tower_center.y - tower.length)
732 .with_z(base + 9 + (h * (tower.height / 5))),
733 max: Vec2::new(tower_center.x + 1, tower_center.y + tower.length)
734 .with_z(base + 12 + (h * (tower.height / 5))),
735 })
736 .fill(Fill::Block(
737 Block::air(SpriteKind::WindowArabic).with_ori(2).unwrap(),
738 ));
739 }
740 for h in 0..4 {
741 painter
742 .aabb(Aabb {
743 min: Vec2::new(tower_center.x - tower.length, tower_center.y - 1)
744 .with_z(base + 9 + (h * (tower.height / 5))),
745 max: Vec2::new(tower_center.x + tower.length, tower_center.y + 1)
746 .with_z(base + 12 + (h * (tower.height / 5))),
747 })
748 .fill(Fill::Block(
749 Block::air(SpriteKind::WindowArabic).with_ori(4).unwrap(),
750 ));
751 }
752 // Tower entries1
753 painter
754 .aabb(Aabb {
755 min: Vec2::new(tower_center.x - tower.length - 2, tower_center.y - 2)
756 .with_z(base - 20),
757 max: Vec2::new(tower_center.x + tower.length + 2, tower_center.y + 2)
758 .with_z(base + 5),
759 })
760 .fill(sandstone.clone());
761 painter
762 .aabb(Aabb {
763 min: Vec2::new(tower_center.x - tower.length - 4, tower_center.y - 1)
764 .with_z(base),
765 max: Vec2::new(tower_center.x + tower.length + 4, tower_center.y + 1)
766 .with_z(base + 4),
767 })
768 .clear();
769 // Tower entries2
770 painter
771 .aabb(Aabb {
772 min: Vec2::new(tower_center.x - 2, tower_center.y - tower.length - 2)
773 .with_z(base - 20),
774 max: Vec2::new(tower_center.x + 2, tower_center.y + tower.length + 2)
775 .with_z(base + 5),
776 })
777 .fill(sandstone.clone());
778 painter
779 .aabb(Aabb {
780 min: Vec2::new(tower_center.x - 1, tower_center.y - tower.length - 4)
781 .with_z(base),
782 max: Vec2::new(tower_center.x + 1, tower_center.y + tower.length + 4)
783 .with_z(base + 4),
784 })
785 .clear();
786 // clear Tower base
787 painter
788 .aabb(Aabb {
789 min: (tower_center - tower.length).with_z(base),
790 max: (tower_center + tower.length).with_z(base + 5),
791 })
792 .clear();
793 // Tower Entry Lamps
794 for d in 0..2 {
795 painter
796 .aabb(Aabb {
797 min: Vec2::new(
798 tower_center.x - 1,
799 tower_center.y - tower.length - 3
800 + (d * ((2 * tower.length) + 6)),
801 )
802 .with_z(base + 4),
803 max: Vec2::new(
804 tower_center.x + 1,
805 tower_center.y - tower.length - 2
806 + (d * ((2 * tower.length) + 4)),
807 )
808 .with_z(base + 5),
809 })
810 .fill(Fill::Block(
811 Block::air(SpriteKind::WallLampSmall)
812 .with_ori(0 + (4 * d) as u8)
813 .unwrap(),
814 ));
815 }
816 // Platform
817 painter
818 .aabb(Aabb {
819 min: (tower_center - tower.length - 2).with_z(base + tower.height),
820 max: (tower_center + tower.length + 2).with_z(base + tower.height + 4),
821 })
822 .fill(sandstone.clone());
823 painter
824 .aabb(Aabb {
825 min: (tower_center - tower.length - 1).with_z(base + tower.height + 2),
826 max: (tower_center + tower.length + 1).with_z(base + tower.height + 4),
827 })
828 .clear();
829
830 painter
831 .aabb(Aabb {
832 min: Vec2::new(tower_center.x - tower.length - 2, tower_center.y - 2)
833 .with_z(base + tower.height + 3),
834 max: Vec2::new(tower_center.x + tower.length + 2, tower_center.y + 2)
835 .with_z(base + tower.height + 4),
836 })
837 .clear();
838 painter
839 .aabb(Aabb {
840 min: Vec2::new(tower_center.x - 2, tower_center.y - tower.length - 2)
841 .with_z(base + tower.height + 3),
842 max: Vec2::new(tower_center.x + 2, tower_center.y + tower.length + 2)
843 .with_z(base + tower.height + 4),
844 })
845 .clear();
846
847 // clear Tower
848 let tower_clear = painter.aabb(Aabb {
849 min: (tower_center - tower.length + 1).with_z(base),
850 max: (tower_center + tower.length - 1).with_z(base + tower.height + 3),
851 });
852 tower_clear.clear();
853 // stairway
854 let stair_radius = tower.length + 1;
855 let stairs_clear = painter.aabb(Aabb {
856 min: (tower_center - stair_radius).with_z(base),
857 max: (tower_center + stair_radius).with_z(base + tower.height + 2),
858 });
859 stairs_clear
860 .sample(spiral_staircase(
861 tower_center.with_z(base + tower.height + 2),
862 stair_radius as f32,
863 0.5,
864 (2 * tower.length) as f32,
865 ))
866 .intersect(tower_clear)
867 .fill(sandstone.clone());
868 }
869 },
870 PlotKind::Multiple { subplots } => {
871 // House, Workshop, Library, Palm, WatchTower
872 for (subplot_kind, subplot_center) in subplots {
873 match subplot_kind {
874 // House or Workshop (one storey house)
875 SubPlotKind::WorkshopHouse { floors } => {
876 for floor in 0..*floors {
877 let room_height = self.diameter / 6;
878 let floor_level = base + (room_height * floor);
879 let room_length = (self.diameter / 7) - (2 * floor);
880 // Windowsills
881 painter
882 .aabb(Aabb {
883 min: Vec2::new(
884 subplot_center.x - room_length - 1,
885 subplot_center.y,
886 )
887 .with_z(floor_level + 1),
888 max: Vec2::new(
889 subplot_center.x + room_length + 1,
890 subplot_center.y + 2,
891 )
892 .with_z(floor_level + 2),
893 })
894 .fill(wood.clone());
895 // Room
896 painter
897 .aabb(Aabb {
898 min: Vec2::new(
899 subplot_center.x - room_length,
900 subplot_center.y - room_length + 3,
901 )
902 .with_z(floor_level),
903 max: Vec2::new(
904 subplot_center.x + room_length,
905 subplot_center.y + room_length - 1,
906 )
907 .with_z(floor_level + room_height),
908 })
909 .fill(sandstone.clone());
910 // Window Sprites
911 painter
912 .aabb(Aabb {
913 min: Vec2::new(
914 subplot_center.x - room_length,
915 subplot_center.y,
916 )
917 .with_z(floor_level + 2),
918 max: Vec2::new(
919 subplot_center.x + room_length,
920 subplot_center.y + 2,
921 )
922 .with_z(floor_level + 5),
923 })
924 .fill(Fill::Block(
925 Block::air(SpriteKind::WindowArabic).with_ori(4).unwrap(),
926 ));
927 // Clear Room
928 painter
929 .aabb(Aabb {
930 min: Vec2::new(
931 subplot_center.x - room_length + 1,
932 subplot_center.y - room_length + 4,
933 )
934 .with_z(floor_level),
935 max: Vec2::new(
936 subplot_center.x + room_length - 1,
937 subplot_center.y + room_length - 2,
938 )
939 .with_z(floor_level + room_height - 2),
940 })
941 .clear();
942 // Overhang1
943 painter
944 .aabb(Aabb {
945 min: Vec2::new(
946 subplot_center.x - room_length + 1,
947 subplot_center.y + room_length - 1,
948 )
949 .with_z(floor_level + room_height - 1),
950 max: Vec2::new(
951 subplot_center.x + room_length - 1,
952 subplot_center.y + room_length,
953 )
954 .with_z(floor_level + room_height),
955 })
956 .fill(wood.clone());
957 // Overhang2
958 painter
959 .aabb(Aabb {
960 min: Vec2::new(
961 subplot_center.x + room_length,
962 subplot_center.y - room_length + 2,
963 )
964 .with_z(floor_level + room_height - 1),
965 max: Vec2::new(
966 subplot_center.x + room_length + 1,
967 subplot_center.y + room_length - 2,
968 )
969 .with_z(floor_level + room_height),
970 })
971 .fill(wood.clone());
972 // Overhang3
973 painter
974 .aabb(Aabb {
975 min: Vec2::new(
976 subplot_center.x - room_length - 1,
977 subplot_center.y - room_length + 4,
978 )
979 .with_z(floor_level + room_height - 1),
980 max: Vec2::new(
981 subplot_center.x - room_length,
982 subplot_center.y + room_length - 2,
983 )
984 .with_z(floor_level + room_height),
985 })
986 .fill(wood.clone());
987 // Door Frame
988 painter
989 .aabb(Aabb {
990 min: Vec2::new(
991 subplot_center.x - 2,
992 subplot_center.y + room_length - 1,
993 )
994 .with_z(floor_level),
995 max: Vec2::new(
996 subplot_center.x + 2,
997 subplot_center.y + room_length,
998 )
999 .with_z(floor_level + 5),
1000 })
1001 .fill(sandstone.clone());
1002 // Clear Door
1003 painter
1004 .aabb(Aabb {
1005 min: Vec2::new(
1006 subplot_center.x - 1,
1007 subplot_center.y + room_length - 2,
1008 )
1009 .with_z(floor_level),
1010 max: Vec2::new(
1011 subplot_center.x + 1,
1012 subplot_center.y + room_length,
1013 )
1014 .with_z(floor_level + 4),
1015 })
1016 .clear();
1017 // Remove Terrain in front of doors
1018 painter
1019 .aabb(Aabb {
1020 min: Vec2::new(
1021 subplot_center.x - 2,
1022 subplot_center.y + room_length,
1023 )
1024 .with_z(floor_level),
1025 max: Vec2::new(
1026 subplot_center.x + 2,
1027 subplot_center.y + room_length + 4,
1028 )
1029 .with_z(floor_level + 5),
1030 })
1031 .clear();
1032 // Stairs for each storey
1033 painter
1034 .ramp_inset(
1035 Aabb {
1036 min: Vec2::new(
1037 subplot_center.x - room_length,
1038 subplot_center.y - room_length + 1,
1039 )
1040 .with_z(floor_level),
1041 max: Vec2::new(
1042 subplot_center.x + room_length,
1043 subplot_center.y - room_length + 3,
1044 )
1045 .with_z(floor_level + room_height),
1046 },
1047 2 * room_length,
1048 Dir::X,
1049 )
1050 .fill(sandstone.clone());
1051 // Carve Roof Terrace
1052 if floor == floors - 1 {
1053 painter
1054 .aabb(Aabb {
1055 min: Vec2::new(
1056 subplot_center.x - room_length + 1,
1057 subplot_center.y - room_length + 4,
1058 )
1059 .with_z(floor_level + room_height - 1),
1060 max: Vec2::new(
1061 subplot_center.x + room_length - 1,
1062 subplot_center.y + room_length - 2,
1063 )
1064 .with_z(floor_level + room_height),
1065 })
1066 .clear();
1067 painter
1068 .aabb(Aabb {
1069 min: Vec2::new(
1070 subplot_center.x + room_length - 3,
1071 subplot_center.y - room_length + 1,
1072 )
1073 .with_z(floor_level + room_height - 1),
1074 max: Vec2::new(
1075 subplot_center.x + room_length - 1,
1076 subplot_center.y - room_length + 4,
1077 )
1078 .with_z(floor_level + room_height),
1079 })
1080 .clear();
1081 // Roof Ornament
1082 painter
1083 .aabb(Aabb {
1084 min: Vec2::new(
1085 subplot_center.x - room_length,
1086 subplot_center.y + room_length - 2,
1087 )
1088 .with_z(floor_level + room_height),
1089 max: Vec2::new(
1090 subplot_center.x + room_length,
1091 subplot_center.y + room_length - 1,
1092 )
1093 .with_z(floor_level + room_height + 2),
1094 })
1095 .fill(sandstone.clone());
1096 painter
1097 .aabb(Aabb {
1098 min: Vec2::new(
1099 subplot_center.x - room_length + 2,
1100 subplot_center.y + room_length - 2,
1101 )
1102 .with_z(floor_level + room_height + 2),
1103 max: Vec2::new(
1104 subplot_center.x + room_length - 2,
1105 subplot_center.y + room_length - 1,
1106 )
1107 .with_z(floor_level + room_height + 3),
1108 })
1109 .fill(sandstone.clone());
1110 painter
1111 .aabb(Aabb {
1112 min: Vec2::new(
1113 subplot_center.x - 2,
1114 subplot_center.y + room_length - 2,
1115 )
1116 .with_z(floor_level + room_height + 3),
1117 max: Vec2::new(
1118 subplot_center.x + 2,
1119 subplot_center.y + room_length - 1,
1120 )
1121 .with_z(floor_level + room_height + 4),
1122 })
1123 .fill(sandstone.clone());
1124 };
1125 // furniture
1126 if *floors == 1 {
1127 // Workshop in one-storey buildings
1128 painter
1129 .aabb(Aabb {
1130 min: (subplot_center - 2).with_z(floor_level),
1131 max: (subplot_center + 2)
1132 .with_z(floor_level + room_height + 1),
1133 })
1134 .fill(sandstone.clone());
1135
1136 painter
1137 .aabb(Aabb {
1138 min: (subplot_center - 2).with_z(floor_level + 1),
1139 max: (subplot_center + 2)
1140 .with_z(floor_level + room_height - 2),
1141 })
1142 .clear();
1143 painter
1144 .aabb(Aabb {
1145 min: (subplot_center - 1).with_z(floor_level),
1146 max: (subplot_center + 1)
1147 .with_z(floor_level + room_height + 1),
1148 })
1149 .clear();
1150 painter
1151 .aabb(Aabb {
1152 min: (subplot_center - 1).with_z(floor_level - 1),
1153 max: (subplot_center + 1).with_z(floor_level),
1154 })
1155 .fill(Fill::Block(Block::air(SpriteKind::Ember)));
1156 let mut stations = vec![
1157 SpriteKind::CraftingBench,
1158 SpriteKind::Forge,
1159 SpriteKind::SpinningWheel,
1160 SpriteKind::TanningRack,
1161 SpriteKind::Loom,
1162 SpriteKind::Anvil,
1163 SpriteKind::DismantlingBench,
1164 SpriteKind::RepairBench,
1165 ];
1166 'outer: for d in 0..2 {
1167 for dir in NEIGHBORS {
1168 if stations.is_empty() {
1169 break 'outer;
1170 }
1171 let position = subplot_center + dir * (4 + d * 2);
1172 let cr_station = stations.swap_remove(
1173 RandomField::new(0).get(position.with_z(base))
1174 as usize
1175 % stations.len(),
1176 );
1177 painter
1178 .sprite(position.with_z(floor_level), cr_station);
1179 }
1180 }
1181 } else {
1182 // kitchen, bath, living room in buildings with 2-3 storeys
1183 match floor {
1184 0 => {
1185 // kitchen
1186 // cupboards / ovens / cushions / jugs
1187 for d in 0..2 {
1188 let a_pos = Vec2::new(
1189 subplot_center.x + 3 - (d * 6),
1190 subplot_center.y - room_length + 4,
1191 );
1192 painter.rotated_sprite(
1193 a_pos.with_z(floor_level),
1194 match (RandomField::new(0)
1195 .get(a_pos.with_z(floor_level)))
1196 % 2
1197 {
1198 0 => SpriteKind::CupboardArabic,
1199 _ => SpriteKind::OvenArabic,
1200 },
1201 4,
1202 );
1203 let b_pos = Vec2::new(
1204 subplot_center.x + 3 - (d * 6),
1205 subplot_center.y + room_length - 3,
1206 );
1207 painter.rotated_sprite(
1208 b_pos.with_z(floor_level),
1209 match (RandomField::new(0)
1210 .get(b_pos.with_z(floor_level)))
1211 % 4
1212 {
1213 0 => SpriteKind::CupboardArabic,
1214 1 => SpriteKind::OvenArabic,
1215 2 => SpriteKind::CushionArabic,
1216 _ => SpriteKind::JugArabic,
1217 },
1218 0,
1219 );
1220 // wall tables with varying items
1221 let c_pos = Vec2::new(
1222 subplot_center.x - room_length
1223 + 1
1224 + (d * ((2 * room_length) - 3)),
1225 subplot_center.y,
1226 );
1227 painter.rotated_sprite(
1228 c_pos.with_z(floor_level),
1229 SpriteKind::WallTableArabic,
1230 6 - (4 * d) as u8,
1231 );
1232 painter.owned_resource_sprite(
1233 c_pos.with_z(floor_level + 1),
1234 match (RandomField::new(0)
1235 .get(c_pos.with_z(floor_level)))
1236 % 5
1237 {
1238 0 => SpriteKind::Melon,
1239 1 => SpriteKind::JugAndBowlArabic,
1240 2 => SpriteKind::Bowl,
1241 3 => SpriteKind::JugArabic,
1242 _ => SpriteKind::VialEmpty,
1243 },
1244 6 - (4 * d) as u8,
1245 );
1246 }
1247 // CookingPot, Cauldron
1248 painter.sprite(
1249 (subplot_center - 2).with_z(floor_level),
1250 SpriteKind::CookingPot,
1251 );
1252 painter.sprite(
1253 (subplot_center + 2).with_z(floor_level),
1254 SpriteKind::Cauldron,
1255 );
1256 },
1257 1 => {
1258 // living room
1259 // canape
1260 let canape_pos = Vec2::new(
1261 subplot_center.x - 4 + 7,
1262 subplot_center.y - room_length
1263 + 5
1264 + ((2 * room_length) - 9),
1265 );
1266
1267 painter.rotated_sprite(
1268 canape_pos.with_z(floor_level),
1269 SpriteKind::CanapeArabic,
1270 4_u8,
1271 );
1272
1273 // bed
1274 let bed_pos = Vec2::new(
1275 subplot_center.x - 4,
1276 subplot_center.y - room_length + 5,
1277 );
1278
1279 painter.rotated_sprite(
1280 bed_pos.with_z(floor_level),
1281 // TODO: create bed sprite specific for desert
1282 // houses
1283 SpriteKind::Bed,
1284 4_u8,
1285 );
1286
1287 for d in 0..2 {
1288 // other sprites
1289 let b_pos = Vec2::new(
1290 subplot_center.x + 3 - (d * 7),
1291 subplot_center.y - room_length
1292 + 5
1293 + (d * ((2 * room_length) - 9)),
1294 );
1295 painter.sprite(
1296 b_pos.with_z(floor_level),
1297 match (RandomField::new(0)
1298 .get(b_pos.with_z(floor_level - d)))
1299 % 6
1300 {
1301 0 => SpriteKind::TableArabicLarge,
1302 1 => SpriteKind::DecorSetArabic,
1303 2 => SpriteKind::DrawerSmall,
1304 3 => SpriteKind::CoatRack,
1305 4 => SpriteKind::TableArabicSmall,
1306 _ => SpriteKind::SepareArabic,
1307 },
1308 )
1309 }
1310 },
1311 _ => {
1312 // bath
1313 // wall tables with varying items
1314 for d in 0..2 {
1315 // wall tables with varying items
1316 let a_pos = Vec2::new(
1317 subplot_center.x - room_length
1318 + 1
1319 + (d * ((2 * room_length) - 3)),
1320 subplot_center.y,
1321 );
1322 painter.rotated_sprite(
1323 a_pos.with_z(floor_level),
1324 SpriteKind::WallTableArabic,
1325 6 - (4 * d) as u8,
1326 );
1327 painter.owned_resource_sprite(
1328 a_pos.with_z(floor_level + 1),
1329 match (RandomField::new(0)
1330 .get(a_pos.with_z(floor_level)))
1331 % 4
1332 {
1333 0 => SpriteKind::Bowl,
1334 1 => SpriteKind::VialEmpty,
1335 2 => SpriteKind::JugArabic,
1336 _ => SpriteKind::JugAndBowlArabic,
1337 },
1338 6 - (4 * d) as u8,
1339 );
1340 // fountain
1341 painter.sprite(
1342 subplot_center.with_z(floor_level),
1343 SpriteKind::FountainArabic,
1344 )
1345 }
1346 },
1347 }
1348 }
1349 // Wall Lamps
1350 painter
1351 .aabb(Aabb {
1352 min: Vec2::new(
1353 subplot_center.x - 1,
1354 subplot_center.y - room_length + 4,
1355 )
1356 .with_z(floor_level + 4),
1357 max: Vec2::new(
1358 subplot_center.x + 1,
1359 subplot_center.y - room_length + 5,
1360 )
1361 .with_z(floor_level + 5),
1362 })
1363 .fill(Fill::Block(
1364 Block::air(SpriteKind::WallLampSmall).with_ori(4).unwrap(),
1365 ));
1366 painter
1367 .aabb(Aabb {
1368 min: Vec2::new(
1369 subplot_center.x - 1,
1370 subplot_center.y + room_length,
1371 )
1372 .with_z(floor_level + 4),
1373 max: Vec2::new(
1374 subplot_center.x + 1,
1375 subplot_center.y + room_length + 1,
1376 )
1377 .with_z(floor_level + 5),
1378 })
1379 .fill(Fill::Block(
1380 Block::air(SpriteKind::WallLampSmall).with_ori(4).unwrap(),
1381 ));
1382 }
1383 },
1384 SubPlotKind::Library => {
1385 // Library with stairway
1386 let tower_length = self.diameter / 14;
1387 let tower_height = 23;
1388 let bldg_a_center = Vec2::new(
1389 subplot_center.x - (2 * tower_length) + 1,
1390 subplot_center.y,
1391 );
1392 let bldg_b_center =
1393 Vec2::new(subplot_center.x + tower_length + 1, subplot_center.y);
1394 // Library windowsills
1395 let sq_corner = Vec2::new(
1396 bldg_b_center.x - 3,
1397 bldg_b_center.y - (2 * tower_length) + 1,
1398 );
1399 for dir in SQUARE_4 {
1400 for h in 0..2 {
1401 for n in 0..2 {
1402 let window_sill_pos = Vec2::new(
1403 sq_corner.x - 1 + (dir.x * 7),
1404 sq_corner.y - 2 + (dir.y * ((4 * tower_length) + 1)),
1405 );
1406 painter
1407 .aabb(Aabb {
1408 min: Vec2::new(
1409 window_sill_pos.x - 1,
1410 window_sill_pos.y,
1411 )
1412 .with_z(
1413 base + 1 + (n * (tower_height / 2)) + (h * 4),
1414 ),
1415 max: Vec2::new(
1416 window_sill_pos.x + 1,
1417 window_sill_pos.y + 1,
1418 )
1419 .with_z(
1420 base + 2 + (n * (tower_height / 2)) + (h * 4),
1421 ),
1422 })
1423 .fill(wood.clone());
1424 }
1425 }
1426 }
1427 for w in 0..2 {
1428 for h in 0..2 {
1429 for n in 0..2 {
1430 painter
1431 .aabb(Aabb {
1432 min: Vec2::new(
1433 bldg_b_center.x + (2 * tower_length),
1434 bldg_b_center.y - 4 + (6 * w),
1435 )
1436 .with_z(
1437 base + 1 + (n * (tower_height / 2)) + (h * 4),
1438 ),
1439 max: Vec2::new(
1440 bldg_b_center.x + (2 * tower_length) + 1,
1441 bldg_b_center.y - 2 + (6 * w),
1442 )
1443 .with_z(
1444 base + 2 + (n * (tower_height / 2)) + (h * 4),
1445 ),
1446 })
1447 .fill(wood.clone());
1448 }
1449 }
1450 }
1451 // Library
1452 painter
1453 .aabb(Aabb {
1454 min: (bldg_b_center - (2 * tower_length)).with_z(base),
1455 max: (bldg_b_center + (2 * tower_length))
1456 .with_z(base + tower_height),
1457 })
1458 .fill(sandstone.clone());
1459 // Library windows
1460 for dir in SQUARE_4 {
1461 for h in 0..2 {
1462 for n in 0..2 {
1463 let window_pos = Vec2::new(
1464 sq_corner.x - 1 + (dir.x * 7),
1465 sq_corner.y - 1 + (dir.y * ((4 * tower_length) - 1)),
1466 );
1467 painter
1468 .aabb(Aabb {
1469 min: Vec2::new(window_pos.x - 1, window_pos.y)
1470 .with_z(
1471 base + 2
1472 + (n * (tower_height / 2))
1473 + (h * 4),
1474 ),
1475 max: Vec2::new(window_pos.x + 1, window_pos.y + 1)
1476 .with_z(
1477 base + 5
1478 + (n * (tower_height / 2))
1479 + (h * 4),
1480 ),
1481 })
1482 .fill(Fill::Block(
1483 Block::air(SpriteKind::WindowArabic)
1484 .with_ori(2)
1485 .unwrap(),
1486 ));
1487 }
1488 }
1489 }
1490 for h in 0..2 {
1491 for n in 0..2 {
1492 painter
1493 .aabb(Aabb {
1494 min: Vec2::new(
1495 bldg_b_center.x + (2 * tower_length) - 1,
1496 bldg_b_center.y - 4,
1497 )
1498 .with_z(base + 2 + (n * (tower_height / 2)) + (h * 4)),
1499 max: Vec2::new(
1500 bldg_b_center.x + (2 * tower_length),
1501 bldg_b_center.y - 2,
1502 )
1503 .with_z(base + 5 + (n * (tower_height / 2)) + (h * 4)),
1504 })
1505 .fill(Fill::Block(
1506 Block::air(SpriteKind::WindowArabic)
1507 .with_ori(4)
1508 .unwrap(),
1509 ));
1510 painter
1511 .aabb(Aabb {
1512 min: Vec2::new(
1513 bldg_b_center.x + (2 * tower_length) - 1,
1514 bldg_b_center.y + 2,
1515 )
1516 .with_z(base + 2 + (n * (tower_height / 2)) + (h * 4)),
1517 max: Vec2::new(
1518 bldg_b_center.x + (2 * tower_length),
1519 bldg_b_center.y + 4,
1520 )
1521 .with_z(base + 5 + (n * (tower_height / 2)) + (h * 4)),
1522 })
1523 .fill(Fill::Block(
1524 Block::air(SpriteKind::WindowArabic)
1525 .with_ori(4)
1526 .unwrap(),
1527 ));
1528 }
1529 }
1530 // roof carve out
1531 painter
1532 .aabb(Aabb {
1533 min: Vec2::new(
1534 bldg_b_center.x - (2 * tower_length) + 2,
1535 bldg_b_center.y - (2 * tower_length) + 1,
1536 )
1537 .with_z(base + tower_height - 1),
1538 max: Vec2::new(
1539 bldg_b_center.x + (2 * tower_length) - 1,
1540 bldg_b_center.y + (2 * tower_length) - 1,
1541 )
1542 .with_z(base + tower_height),
1543 })
1544 .clear();
1545
1546 // Clear Library
1547 painter
1548 .aabb(Aabb {
1549 min: (bldg_b_center - (2 * tower_length) + 1).with_z(base),
1550 max: (bldg_b_center + (2 * tower_length) - 1)
1551 .with_z(base + tower_height - 2),
1552 })
1553 .clear();
1554 // Library Floor
1555 painter
1556 .aabb(Aabb {
1557 min: (bldg_b_center - (2 * tower_length))
1558 .with_z(base + (tower_height / 2) - 1),
1559 max: (bldg_b_center + (2 * tower_length))
1560 .with_z(base + (tower_height / 2)),
1561 })
1562 .fill(sandstone.clone());
1563 // furniture
1564 for h in 0..2 {
1565 for dir in NEIGHBORS {
1566 let sprite_pos = (bldg_b_center
1567 + (dir * ((2 * tower_length) - 4)))
1568 .with_z(base + ((tower_height / 2) * h));
1569 painter.sprite(
1570 sprite_pos,
1571 match (RandomField::new(0).get(sprite_pos)) % 6 {
1572 0 => SpriteKind::DrawerSmall,
1573 1 => SpriteKind::ChairSingle,
1574 2 => SpriteKind::CoatRack,
1575 3 => SpriteKind::Bench,
1576 4 => SpriteKind::ChairDouble,
1577 _ => SpriteKind::TableDining,
1578 },
1579 );
1580 }
1581
1582 for d in 0..2 {
1583 for e in 0..2 {
1584 // bookshelfs
1585 let a_pos = Vec2::new(
1586 bldg_b_center.x - 3 + (e * 6),
1587 bldg_b_center.y - (2 * tower_length)
1588 + 1
1589 + (d * ((2 * (2 * tower_length)) - 3)),
1590 );
1591 painter.rotated_sprite(
1592 a_pos.with_z(base + 1 + ((tower_height / 2) * h)),
1593 SpriteKind::BookshelfArabic,
1594 4 - (4 * d) as u8,
1595 );
1596 }
1597 }
1598 }
1599 // Library Wall Lamps
1600 for h in 0..2 {
1601 for n in 0..2 {
1602 painter
1603 .aabb(Aabb {
1604 min: Vec2::new(
1605 bldg_b_center.x + (2 * tower_length) - 2,
1606 bldg_b_center.y - 1,
1607 )
1608 .with_z(base + 4 + (n * (tower_height / 2)) + (h * 4)),
1609 max: Vec2::new(
1610 bldg_b_center.x + (2 * tower_length) - 1,
1611 bldg_b_center.y + 1,
1612 )
1613 .with_z(base + 5 + (n * (tower_height / 2)) + (h * 4)),
1614 })
1615 .fill(Fill::Block(
1616 Block::air(SpriteKind::WallLampSmall)
1617 .with_ori(6)
1618 .unwrap(),
1619 ));
1620 }
1621 }
1622 // Library Roof Overhangs
1623 for d in 0..2 {
1624 painter
1625 .aabb(Aabb {
1626 min: Vec2::new(
1627 bldg_b_center.x - (2 * tower_length) + 1,
1628 bldg_b_center.y + (2 * tower_length)
1629 - (d * ((4 * tower_length) + 1)),
1630 )
1631 .with_z(base + tower_height - 1),
1632 max: Vec2::new(
1633 bldg_b_center.x + (2 * tower_length) - 1,
1634 bldg_b_center.y + (2 * tower_length) + 1
1635 - (d * ((4 * tower_length) + 1)),
1636 )
1637 .with_z(base + tower_height),
1638 })
1639 .fill(wood.clone());
1640 }
1641 painter
1642 .aabb(Aabb {
1643 min: Vec2::new(
1644 bldg_b_center.x + (2 * tower_length),
1645 bldg_b_center.y - (2 * tower_length) + 1,
1646 )
1647 .with_z(base + tower_height - 1),
1648 max: Vec2::new(
1649 bldg_b_center.x + (2 * tower_length) + 1,
1650 bldg_b_center.y + (2 * tower_length) - 1,
1651 )
1652 .with_z(base + tower_height),
1653 })
1654 .fill(wood.clone());
1655 // Stairs to Tower Top
1656 painter
1657 .ramp(
1658 Aabb {
1659 min: Vec2::new(
1660 bldg_b_center.x - (2 * tower_length) + 2,
1661 bldg_b_center.y - 1,
1662 )
1663 .with_z(base + tower_height - 1),
1664 max: Vec2::new(
1665 bldg_b_center.x - (2 * tower_length) + 4,
1666 bldg_b_center.y + 1,
1667 )
1668 .with_z(base + tower_height + 1),
1669 },
1670 Dir::NegX,
1671 )
1672 .fill(sandstone.clone());
1673 // Library Top Room
1674 painter
1675 .aabb(Aabb {
1676 min: Vec2::new(
1677 bldg_b_center.x - tower_length + 2,
1678 bldg_b_center.y - tower_length,
1679 )
1680 .with_z(base + tower_height - 1),
1681 max: Vec2::new(
1682 bldg_b_center.x + tower_length + 2,
1683 bldg_b_center.y + tower_length,
1684 )
1685 .with_z(base + tower_height + tower_length),
1686 })
1687 .fill(sandstone.clone());
1688 painter
1689 .aabb(Aabb {
1690 min: Vec2::new(
1691 bldg_b_center.x - tower_length + 3,
1692 bldg_b_center.y - tower_length + 1,
1693 )
1694 .with_z(base + tower_height - 1),
1695 max: Vec2::new(
1696 bldg_b_center.x + tower_length + 1,
1697 bldg_b_center.y + tower_length - 1,
1698 )
1699 .with_z(base + tower_height + tower_length - 2),
1700 })
1701 .clear();
1702 painter
1703 .aabb(Aabb {
1704 min: Vec2::new(
1705 bldg_b_center.x - tower_length + 3,
1706 bldg_b_center.y - tower_length + 1,
1707 )
1708 .with_z(base + tower_height + tower_length - 1),
1709 max: Vec2::new(
1710 bldg_b_center.x + tower_length + 1,
1711 bldg_b_center.y + tower_length - 1,
1712 )
1713 .with_z(base + tower_height + tower_length),
1714 })
1715 .clear();
1716 painter
1717 .aabb(Aabb {
1718 min: Vec2::new(
1719 bldg_b_center.x + 1,
1720 bldg_b_center.y - tower_length - 1,
1721 )
1722 .with_z(base + tower_height - 1),
1723 max: Vec2::new(
1724 bldg_b_center.x + 3,
1725 bldg_b_center.y + tower_length + 1,
1726 )
1727 .with_z(base + tower_height + 2),
1728 })
1729 .clear();
1730 painter
1731 .aabb(Aabb {
1732 min: Vec2::new(
1733 bldg_b_center.x - tower_length + 1,
1734 bldg_b_center.y - 1,
1735 )
1736 .with_z(base + tower_height - 1),
1737 max: Vec2::new(
1738 bldg_b_center.x + tower_length + 3,
1739 bldg_b_center.y + 1,
1740 )
1741 .with_z(base + tower_height + 2),
1742 })
1743 .clear();
1744
1745 // Library Top Room Overhangs
1746 for d in 0..2 {
1747 painter
1748 .aabb(Aabb {
1749 min: Vec2::new(
1750 bldg_b_center.x - tower_length + 3,
1751 bldg_b_center.y + tower_length
1752 - (d * ((2 * tower_length) + 1)),
1753 )
1754 .with_z(base + tower_height + tower_length - 1),
1755 max: Vec2::new(
1756 bldg_b_center.x + tower_length + 1,
1757 bldg_b_center.y + tower_length + 1
1758 - (d * ((2 * tower_length) + 1)),
1759 )
1760 .with_z(base + tower_height + tower_length),
1761 })
1762 .fill(wood.clone());
1763 }
1764 painter
1765 .aabb(Aabb {
1766 min: Vec2::new(
1767 bldg_b_center.x + tower_length + 2,
1768 bldg_b_center.y - tower_length + 1,
1769 )
1770 .with_z(base + tower_height + tower_length - 1),
1771 max: Vec2::new(
1772 bldg_b_center.x + tower_length + 3,
1773 bldg_b_center.y + tower_length - 1,
1774 )
1775 .with_z(base + tower_height + tower_length),
1776 })
1777 .fill(wood.clone());
1778 // Library Top Room Roof Ornament
1779 painter
1780 .aabb(Aabb {
1781 min: Vec2::new(
1782 bldg_b_center.x + tower_length + 1,
1783 bldg_b_center.y - tower_length,
1784 )
1785 .with_z(base + tower_height + tower_length),
1786 max: Vec2::new(
1787 bldg_b_center.x + tower_length + 2,
1788 bldg_b_center.y + tower_length,
1789 )
1790 .with_z(base + tower_height + tower_length + 2),
1791 })
1792 .fill(sandstone.clone());
1793 painter
1794 .aabb(Aabb {
1795 min: Vec2::new(
1796 bldg_b_center.x + tower_length + 1,
1797 bldg_b_center.y - tower_length + 2,
1798 )
1799 .with_z(base + tower_height + tower_length + 2),
1800 max: Vec2::new(
1801 bldg_b_center.x + tower_length + 2,
1802 bldg_b_center.y + tower_length - 2,
1803 )
1804 .with_z(base + tower_height + tower_length + 3),
1805 })
1806 .fill(sandstone.clone());
1807 painter
1808 .aabb(Aabb {
1809 min: Vec2::new(
1810 bldg_b_center.x + tower_length + 1,
1811 bldg_b_center.y - 1,
1812 )
1813 .with_z(base + tower_height + tower_length + 3),
1814 max: Vec2::new(
1815 bldg_b_center.x + tower_length + 2,
1816 bldg_b_center.y + 1,
1817 )
1818 .with_z(base + tower_height + tower_length + 4),
1819 })
1820 .fill(sandstone.clone());
1821 // Stairway Tower windowsills
1822 for h in 0..2 {
1823 painter
1824 .aabb(Aabb {
1825 min: Vec2::new(
1826 bldg_a_center.x - 1,
1827 bldg_a_center.y - tower_length - 1,
1828 )
1829 .with_z(base + (tower_height / 2) - 4 + (h * 6)),
1830 max: Vec2::new(
1831 bldg_a_center.x + 1,
1832 bldg_a_center.y + tower_length + 1,
1833 )
1834 .with_z(base + (tower_height / 2) - 3 + (h * 6)),
1835 })
1836 .fill(wood.clone());
1837 }
1838 // Stairway Tower base
1839 painter
1840 .aabb(Aabb {
1841 min: (bldg_a_center - tower_length - 1).with_z(base),
1842 max: (bldg_a_center + tower_length + 1).with_z(base + 6),
1843 })
1844 .fill(sandstone.clone());
1845 // Tower
1846 painter
1847 .aabb(Aabb {
1848 min: (bldg_a_center - tower_length).with_z(base),
1849 max: (bldg_a_center + tower_length).with_z(base + tower_height),
1850 })
1851 .fill(sandstone.clone());
1852 // Stairway Tower windows
1853 for h in 0..2 {
1854 painter
1855 .aabb(Aabb {
1856 min: Vec2::new(
1857 bldg_a_center.x - 1,
1858 bldg_a_center.y - tower_length,
1859 )
1860 .with_z(base + (tower_height / 2) - 3 + (h * 6)),
1861 max: Vec2::new(
1862 bldg_a_center.x + 1,
1863 bldg_a_center.y + tower_length,
1864 )
1865 .with_z(base + (tower_height / 2) + (h * 6)),
1866 })
1867 .fill(Fill::Block(
1868 Block::air(SpriteKind::WindowArabic).with_ori(2).unwrap(),
1869 ));
1870 }
1871 // Stairway Tower entry
1872 painter
1873 .aabb(Aabb {
1874 min: Vec2::new(
1875 bldg_a_center.x - 2,
1876 bldg_a_center.y - tower_length - 2,
1877 )
1878 .with_z(base),
1879 max: Vec2::new(
1880 bldg_a_center.x + 2,
1881 bldg_a_center.y + tower_length + 2,
1882 )
1883 .with_z(base + 5),
1884 })
1885 .fill(sandstone.clone());
1886 // clear Stairway Tower entry
1887 painter
1888 .aabb(Aabb {
1889 min: Vec2::new(
1890 bldg_a_center.x - 1,
1891 bldg_a_center.y - tower_length - 5,
1892 )
1893 .with_z(base),
1894 max: Vec2::new(
1895 bldg_a_center.x + 1,
1896 bldg_a_center.y + tower_length + 5,
1897 )
1898 .with_z(base + 4),
1899 })
1900 .clear();
1901 // clear Stairway Tower base
1902 painter
1903 .aabb(Aabb {
1904 min: (bldg_a_center - tower_length).with_z(base),
1905 max: (bldg_a_center + tower_length).with_z(base + 6),
1906 })
1907 .clear();
1908 // Stairway Tower Entry Lamps
1909 for d in 0..2 {
1910 painter
1911 .aabb(Aabb {
1912 min: Vec2::new(
1913 bldg_a_center.x - 1,
1914 bldg_a_center.y - tower_length - 3
1915 + (d * ((2 * tower_length) + 6)),
1916 )
1917 .with_z(base + 4),
1918 max: Vec2::new(
1919 bldg_a_center.x + 1,
1920 bldg_a_center.y - tower_length - 2
1921 + (d * ((2 * tower_length) + 4)),
1922 )
1923 .with_z(base + 5),
1924 })
1925 .fill(Fill::Block(
1926 Block::air(SpriteKind::WallLampSmall)
1927 .with_ori(0 + (4 * d) as u8)
1928 .unwrap(),
1929 ));
1930 }
1931 // Library entries from Stairway Tower
1932 for h in 0..2 {
1933 painter
1934 .aabb(Aabb {
1935 min: Vec2::new(
1936 bldg_a_center.x + tower_length - 1,
1937 bldg_a_center.y - 1,
1938 )
1939 .with_z(base + (h * (tower_height / 2))),
1940 max: Vec2::new(
1941 bldg_a_center.x + tower_length + 1,
1942 bldg_a_center.y + 1,
1943 )
1944 .with_z(base + (h * (tower_height / 2)) + 3),
1945 })
1946 .clear();
1947 }
1948 // Stairway Tower Platform
1949 painter
1950 .aabb(Aabb {
1951 min: (bldg_a_center - tower_length - 2)
1952 .with_z(base + tower_height),
1953 max: (bldg_a_center + tower_length + 2)
1954 .with_z(base + tower_height + 3),
1955 })
1956 .fill(sandstone.clone());
1957
1958 painter
1959 .aabb(Aabb {
1960 min: (bldg_a_center - tower_length - 1)
1961 .with_z(base + tower_height + 2),
1962 max: (bldg_a_center + tower_length + 1)
1963 .with_z(base + tower_height + 3),
1964 })
1965 .clear();
1966
1967 painter
1968 .aabb(Aabb {
1969 min: Vec2::new(
1970 bldg_a_center.x + tower_length + 1,
1971 bldg_a_center.y - 1,
1972 )
1973 .with_z(base + tower_height + 2),
1974 max: Vec2::new(
1975 bldg_a_center.x + tower_length + 2,
1976 bldg_a_center.y + 1,
1977 )
1978 .with_z(base + tower_height + 3),
1979 })
1980 .clear();
1981 // clear Tower
1982 let tower_clear = painter.aabb(Aabb {
1983 min: (bldg_a_center - tower_length + 1).with_z(base),
1984 max: (bldg_a_center + tower_length - 1)
1985 .with_z(base + tower_height + 3),
1986 });
1987 tower_clear.clear();
1988 // stairway
1989 let stair_radius = tower_length + 1;
1990 let stairs_clear = painter.aabb(Aabb {
1991 min: (bldg_a_center - stair_radius).with_z(base),
1992 max: (bldg_a_center + stair_radius).with_z(base + tower_height + 2),
1993 });
1994 stairs_clear
1995 .sample(spiral_staircase(
1996 bldg_a_center.with_z(base + tower_height + 2),
1997 stair_radius as f32,
1998 0.5,
1999 ((2 * tower_length) - 1) as f32,
2000 ))
2001 .intersect(tower_clear)
2002 .fill(sandstone.clone());
2003 },
2004 SubPlotKind::WatchTower(tower) => {
2005 // WatchTower Windowsills
2006 for h in 0..4 {
2007 painter
2008 .aabb(Aabb {
2009 min: Vec2::new(
2010 subplot_center.x - 1,
2011 subplot_center.y - tower.length - 1,
2012 )
2013 .with_z(base + 8 + (h * (tower.height / 5))),
2014 max: Vec2::new(
2015 subplot_center.x + 1,
2016 subplot_center.y + tower.length + 1,
2017 )
2018 .with_z(base + 9 + (h * (tower.height / 5))),
2019 })
2020 .fill(wood.clone());
2021 }
2022 for h in 0..4 {
2023 painter
2024 .aabb(Aabb {
2025 min: Vec2::new(
2026 subplot_center.x - tower.length - 1,
2027 subplot_center.y - 1,
2028 )
2029 .with_z(base + 8 + (h * (tower.height / 5))),
2030 max: Vec2::new(
2031 subplot_center.x + tower.length + 1,
2032 subplot_center.y + 1,
2033 )
2034 .with_z(base + 9 + (h * (tower.height / 5))),
2035 })
2036 .fill(wood.clone());
2037 }
2038 // Watch Tower base
2039 painter
2040 .aabb(Aabb {
2041 min: (subplot_center - tower.length - 1).with_z(base),
2042 max: (subplot_center + tower.length + 1).with_z(base + 6),
2043 })
2044 .fill(sandstone.clone());
2045 // WatchTower
2046 painter
2047 .aabb(Aabb {
2048 min: (subplot_center - tower.length).with_z(base),
2049 max: (subplot_center + tower.length)
2050 .with_z(base + tower.height),
2051 })
2052 .fill(sandstone.clone());
2053 // WatchTower Windows
2054 for h in 0..4 {
2055 painter
2056 .aabb(Aabb {
2057 min: Vec2::new(
2058 subplot_center.x - 1,
2059 subplot_center.y - tower.length,
2060 )
2061 .with_z(base + 9 + (h * (tower.height / 5))),
2062 max: Vec2::new(
2063 subplot_center.x + 1,
2064 subplot_center.y + tower.length,
2065 )
2066 .with_z(base + 12 + (h * (tower.height / 5))),
2067 })
2068 .fill(Fill::Block(
2069 Block::air(SpriteKind::WindowArabic).with_ori(2).unwrap(),
2070 ));
2071 }
2072 for h in 0..4 {
2073 painter
2074 .aabb(Aabb {
2075 min: Vec2::new(
2076 subplot_center.x - tower.length,
2077 subplot_center.y - 1,
2078 )
2079 .with_z(base + 9 + (h * (tower.height / 5))),
2080 max: Vec2::new(
2081 subplot_center.x + tower.length,
2082 subplot_center.y + 1,
2083 )
2084 .with_z(base + 12 + (h * (tower.height / 5))),
2085 })
2086 .fill(Fill::Block(
2087 Block::air(SpriteKind::WindowArabic).with_ori(4).unwrap(),
2088 ));
2089 }
2090 // Watch Tower entries
2091 painter
2092 .aabb(Aabb {
2093 min: Vec2::new(
2094 subplot_center.x - 2,
2095 subplot_center.y - tower.length - 2,
2096 )
2097 .with_z(base),
2098 max: Vec2::new(
2099 subplot_center.x + 2,
2100 subplot_center.y + tower.length + 2,
2101 )
2102 .with_z(base + 5),
2103 })
2104 .fill(sandstone.clone());
2105 painter
2106 .aabb(Aabb {
2107 min: Vec2::new(
2108 subplot_center.x - 1,
2109 subplot_center.y - tower.length - 2,
2110 )
2111 .with_z(base),
2112 max: Vec2::new(
2113 subplot_center.x + 1,
2114 subplot_center.y + tower.length + 2,
2115 )
2116 .with_z(base + 4),
2117 })
2118 .clear();
2119 // clear Watch Tower base
2120 painter
2121 .aabb(Aabb {
2122 min: (subplot_center - tower.length).with_z(base),
2123 max: (subplot_center + tower.length).with_z(base + 5),
2124 })
2125 .clear();
2126 // WatchTower Entry Lamps
2127 for d in 0..2 {
2128 painter
2129 .aabb(Aabb {
2130 min: Vec2::new(
2131 subplot_center.x - 1,
2132 subplot_center.y - tower.length - 3
2133 + (d * ((2 * tower.length) + 6)),
2134 )
2135 .with_z(base + 4),
2136 max: Vec2::new(
2137 subplot_center.x + 1,
2138 subplot_center.y - tower.length - 2
2139 + (d * ((2 * tower.length) + 4)),
2140 )
2141 .with_z(base + 5),
2142 })
2143 .fill(Fill::Block(
2144 Block::air(SpriteKind::WallLampSmall)
2145 .with_ori(0 + (4 * d) as u8)
2146 .unwrap(),
2147 ));
2148 }
2149 // Watchtower Platform
2150 painter
2151 .aabb(Aabb {
2152 min: (subplot_center - tower.length - 2)
2153 .with_z(base + tower.height),
2154 max: (subplot_center + tower.length + 2)
2155 .with_z(base + tower.height + 4),
2156 })
2157 .fill(sandstone.clone());
2158
2159 painter
2160 .aabb(Aabb {
2161 min: (subplot_center - tower.length - 1)
2162 .with_z(base + tower.height + 2),
2163 max: (subplot_center + tower.length + 1)
2164 .with_z(base + tower.height + 4),
2165 })
2166 .clear();
2167
2168 painter
2169 .aabb(Aabb {
2170 min: Vec2::new(
2171 subplot_center.x - tower.length - 2,
2172 subplot_center.y - 2,
2173 )
2174 .with_z(base + tower.height + 3),
2175 max: Vec2::new(
2176 subplot_center.x + tower.length + 2,
2177 subplot_center.y + 2,
2178 )
2179 .with_z(base + tower.height + 4),
2180 })
2181 .clear();
2182 painter
2183 .aabb(Aabb {
2184 min: Vec2::new(
2185 subplot_center.x - 2,
2186 subplot_center.y - tower.length - 2,
2187 )
2188 .with_z(base + tower.height + 3),
2189 max: Vec2::new(
2190 subplot_center.x + 2,
2191 subplot_center.y + tower.length + 2,
2192 )
2193 .with_z(base + tower.height + 4),
2194 })
2195 .clear();
2196
2197 // clear Tower
2198 let tower_clear = painter.aabb(Aabb {
2199 min: (subplot_center - tower.length + 1).with_z(base),
2200 max: (subplot_center + tower.length - 1)
2201 .with_z(base + tower.height + 3),
2202 });
2203 tower_clear.clear();
2204 // stairway
2205 let stair_radius = tower.length + 1;
2206 let stairs_clear = painter.aabb(Aabb {
2207 min: (subplot_center - stair_radius).with_z(base),
2208 max: (subplot_center + stair_radius)
2209 .with_z(base + tower.height + 2),
2210 });
2211 stairs_clear
2212 .sample(spiral_staircase(
2213 subplot_center.with_z(base + tower.height + 2),
2214 stair_radius as f32,
2215 0.5,
2216 (2 * tower.length) as f32,
2217 ))
2218 .intersect(tower_clear)
2219 .fill(sandstone.clone());
2220 },
2221 SubPlotKind::AnimalShed => {
2222 // fenced animal shed
2223 let shed_length = self.diameter / 14;
2224 // small fence
2225 painter
2226 .aabb(Aabb {
2227 min: Vec2::new(
2228 subplot_center.x - (2 * shed_length),
2229 subplot_center.y - (2 * shed_length) - 1,
2230 )
2231 .with_z(base),
2232 max: Vec2::new(
2233 subplot_center.x - (2 * shed_length) + 1,
2234 subplot_center.y + (2 * shed_length) + 1,
2235 )
2236 .with_z(base + 2),
2237 })
2238 .union(
2239 painter.aabb(Aabb {
2240 min: Vec2::new(
2241 subplot_center.x + (2 * shed_length) + 1,
2242 subplot_center.y - (2 * shed_length) - 1,
2243 )
2244 .with_z(base),
2245 max: Vec2::new(
2246 subplot_center.x + (2 * shed_length) + 2,
2247 subplot_center.y + (2 * shed_length) + 1,
2248 )
2249 .with_z(base + 2),
2250 }),
2251 )
2252 .union(
2253 painter.aabb(Aabb {
2254 min: Vec2::new(
2255 subplot_center.x - (2 * shed_length),
2256 subplot_center.y - (2 * shed_length) - 1,
2257 )
2258 .with_z(base),
2259 max: Vec2::new(
2260 subplot_center.x + (2 * shed_length) + 2,
2261 subplot_center.y - (2 * shed_length),
2262 )
2263 .with_z(base + 2),
2264 }),
2265 )
2266 .union(
2267 painter.aabb(Aabb {
2268 min: Vec2::new(
2269 subplot_center.x - (2 * shed_length),
2270 subplot_center.y + (2 * shed_length),
2271 )
2272 .with_z(base),
2273 max: Vec2::new(
2274 subplot_center.x + (2 * shed_length) + 2,
2275 subplot_center.y + (2 * shed_length) + 1,
2276 )
2277 .with_z(base + 2),
2278 }),
2279 )
2280 .fill(sandstone_broken.clone());
2281 // shed
2282 painter
2283 .aabb(Aabb {
2284 min: Vec2::new(
2285 subplot_center.x - shed_length + 2,
2286 subplot_center.y - shed_length,
2287 )
2288 .with_z(base),
2289 max: Vec2::new(
2290 subplot_center.x + shed_length + 2,
2291 subplot_center.y + shed_length,
2292 )
2293 .with_z(base + shed_length + 1),
2294 })
2295 .fill(sandstone.clone());
2296 painter
2297 .aabb(Aabb {
2298 min: Vec2::new(
2299 subplot_center.x - shed_length + 3,
2300 subplot_center.y - shed_length + 1,
2301 )
2302 .with_z(base),
2303 max: Vec2::new(
2304 subplot_center.x + shed_length + 1,
2305 subplot_center.y + shed_length - 1,
2306 )
2307 .with_z(base + shed_length - 1),
2308 })
2309 .clear();
2310 painter
2311 .aabb(Aabb {
2312 min: Vec2::new(
2313 subplot_center.x - shed_length + 3,
2314 subplot_center.y - shed_length + 1,
2315 )
2316 .with_z(base + shed_length),
2317 max: Vec2::new(
2318 subplot_center.x + shed_length + 1,
2319 subplot_center.y + shed_length - 1,
2320 )
2321 .with_z(base + shed_length + 1),
2322 })
2323 .clear();
2324 painter
2325 .aabb(Aabb {
2326 min: Vec2::new(
2327 subplot_center.x + 1,
2328 subplot_center.y - shed_length - 1,
2329 )
2330 .with_z(base),
2331 max: Vec2::new(
2332 subplot_center.x + 3,
2333 subplot_center.y + shed_length + 1,
2334 )
2335 .with_z(base + 3),
2336 })
2337 .clear();
2338 painter
2339 .aabb(Aabb {
2340 min: Vec2::new(
2341 subplot_center.x - shed_length + 1,
2342 subplot_center.y - 1,
2343 )
2344 .with_z(base),
2345 max: Vec2::new(
2346 subplot_center.x + shed_length + 3,
2347 subplot_center.y + 1,
2348 )
2349 .with_z(base + 3),
2350 })
2351 .clear();
2352 // Shed Overhangs
2353 for d in 0..2 {
2354 painter
2355 .aabb(Aabb {
2356 min: Vec2::new(
2357 subplot_center.x - shed_length + 3,
2358 subplot_center.y + shed_length
2359 - (d * ((2 * shed_length) + 1)),
2360 )
2361 .with_z(base + shed_length - 1),
2362 max: Vec2::new(
2363 subplot_center.x + shed_length + 1,
2364 subplot_center.y + shed_length + 1
2365 - (d * ((2 * shed_length) + 1)),
2366 )
2367 .with_z(base + shed_length),
2368 })
2369 .fill(wood.clone());
2370 }
2371 painter
2372 .aabb(Aabb {
2373 min: Vec2::new(
2374 subplot_center.x + shed_length + 2,
2375 subplot_center.y - shed_length + 1,
2376 )
2377 .with_z(base + shed_length - 1),
2378 max: Vec2::new(
2379 subplot_center.x + shed_length + 3,
2380 subplot_center.y + shed_length - 1,
2381 )
2382 .with_z(base + shed_length),
2383 })
2384 .fill(wood.clone());
2385 // Shed Roof Ornament
2386 painter
2387 .aabb(Aabb {
2388 min: Vec2::new(
2389 subplot_center.x + shed_length + 1,
2390 subplot_center.y - shed_length,
2391 )
2392 .with_z(base + shed_length),
2393 max: Vec2::new(
2394 subplot_center.x + shed_length + 2,
2395 subplot_center.y + shed_length,
2396 )
2397 .with_z(base + shed_length + 2),
2398 })
2399 .fill(sandstone.clone());
2400 painter
2401 .aabb(Aabb {
2402 min: Vec2::new(
2403 subplot_center.x + shed_length + 1,
2404 subplot_center.y - shed_length + 2,
2405 )
2406 .with_z(base + shed_length + 2),
2407 max: Vec2::new(
2408 subplot_center.x + shed_length + 2,
2409 subplot_center.y + shed_length - 2,
2410 )
2411 .with_z(base + shed_length + 3),
2412 })
2413 .fill(sandstone.clone());
2414 painter
2415 .aabb(Aabb {
2416 min: Vec2::new(
2417 subplot_center.x + shed_length + 1,
2418 subplot_center.y - 1,
2419 )
2420 .with_z(base + shed_length + 3),
2421 max: Vec2::new(
2422 subplot_center.x + shed_length + 2,
2423 subplot_center.y + 1,
2424 )
2425 .with_z(base + shed_length + 4),
2426 })
2427 .fill(sandstone.clone());
2428 },
2429 SubPlotKind::PalmTree => {
2430 // Palm
2431 painter
2432 .cylinder(Aabb {
2433 min: (subplot_center - 8).with_z(base),
2434 max: (subplot_center + 14).with_z(base + 1),
2435 })
2436 .fill(sandstone.clone());
2437 painter
2438 .cylinder(Aabb {
2439 min: (subplot_center - 7).with_z(base),
2440 max: (subplot_center + 13).with_z(base + 1),
2441 })
2442 .fill(Fill::Brick(BlockKind::Rock, Rgb::new(235, 178, 99), 12));
2443 for p in 0..2 {
2444 let palm_pos = (subplot_center + 3 + (2 * p)).with_z(base);
2445 lazy_static! {
2446 pub static ref PALM: AssetHandle<StructuresGroup> =
2447 PrefabStructure::load_group("trees.palms");
2448 }
2449 let rng = RandomField::new(0).get(palm_pos) % 10;
2450 let palm = PALM.read();
2451 let palm = palm[rng as usize % palm.len()].clone();
2452 painter
2453 .prim(Primitive::Prefab(Box::new(palm.clone())))
2454 .translate(palm_pos)
2455 .fill(Fill::Prefab(Box::new(palm), palm_pos, rng));
2456 }
2457 },
2458 }
2459 }
2460 // spawn campfire in some multiplots that are not markethall
2461 let campfire_pos = (center).with_z(base + 1);
2462 if self.campfire {
2463 painter.spawn(
2464 EntityInfo::at(campfire_pos.map(|e| e as f32))
2465 .into_special(SpecialEntity::Waypoint),
2466 )
2467 }
2468 },
2469 }
2470 }
2471}