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