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