1use super::*;
2use crate::{
3 Land,
4 all::ForestKind,
5 site::util::sprites::PainterSpriteExt,
6 util::{DIRS, RandomField, Sampler},
7};
8use common::{
9 calendar::{Calendar, CalendarEvent},
10 terrain::{Block, BlockKind, SpriteKind},
11};
12use rand::{prelude::*, seq::IndexedRandom};
13use strum::IntoEnumIterator;
14use vek::*;
15
16#[derive(Copy, Clone)]
17enum Style {
18 Wooden(Rgb<u8>),
19 Stone,
20 Brick,
21 Daub,
22}
23
24impl Style {
25 fn get_fill(self) -> Fill {
26 match self {
27 Self::Wooden(color) => Fill::PlankWall(BlockKind::Wood, color, 64),
28 Self::Stone => Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 50),
29 Self::Daub => Fill::Brick(BlockKind::Wood, Rgb::new(200, 180, 150), 24),
30 Self::Brick => Fill::Brick(BlockKind::Rock, Rgb::new(100, 32, 20), 48),
31 }
32 }
33}
34
35pub struct House {
37 pub door_tile: Vec2<i32>,
39 tile_aabr: Aabr<i32>,
41 bounds: Aabr<i32>,
43 pub(crate) alt: i32,
45 levels: u32,
47 overhang: i32,
49 roof_color: Rgb<u8>,
51 front: Dir2,
52 christmas_decorations: bool,
53 lower_style: Style,
54 upper_style: Style,
55 gable_style: Style,
56}
57
58impl House {
59 pub fn generate(
60 land: &Land,
61 rng: &mut impl Rng,
62 site: &Site,
63 door_tile: Vec2<i32>,
64 door_dir: Vec2<i32>,
65 tile_aabr: Aabr<i32>,
66 calendar: Option<&Calendar>,
67 alt: Option<i32>,
68 ) -> Self {
69 let levels = rng.random_range(1..2 + (tile_aabr.max - tile_aabr.min).product() / 6) as u32;
70 let bounds = Aabr {
71 min: site.tile_wpos(tile_aabr.min),
72 max: site.tile_wpos(tile_aabr.max),
73 };
74
75 let front = match door_dir {
76 dir if dir.y < 0 => Dir2::NegY,
77 dir if dir.x < 0 => Dir2::NegX,
78 dir if dir.y > 0 => Dir2::Y,
79 _ => Dir2::X,
80 };
81
82 let christmas_decorations = calendar.is_some_and(|c| c.is_event(CalendarEvent::Christmas));
83
84 let door_wpos = site.tile_center_wpos(door_tile);
85 let upper_style = match land.make_forest_lottery(door_wpos).choose_seeded(rng.random())
86 .filter(|_| rng.random_bool(0.75))
88 {
89 Some(
90 ForestKind::Cedar
91 | ForestKind::AutumnTree
92 | ForestKind::Frostpine
93 | ForestKind::Mangrove,
94 ) => Style::Wooden(Rgb::new(63, 28, 12)),
95 Some(ForestKind::Oak | ForestKind::Swamp | ForestKind::Baobab) => {
96 Style::Wooden(Rgb::new(102, 87, 63))
97 },
98 Some(ForestKind::Acacia | ForestKind::Birch | ForestKind::Palm) => {
99 Style::Wooden(Rgb::new(130, 104, 102))
100 },
101 Some(
102 ForestKind::Mapletree | ForestKind::Redwood | ForestKind::Pine | ForestKind::Cherry,
103 ) => Style::Wooden(Rgb::new(117, 95, 46)),
104 _ if rng.random_bool(0.5) => Style::Brick,
105 _ => Style::Daub,
106 };
107 let lower_style = match upper_style {
108 Style::Stone => Style::Stone,
110 Style::Brick => Style::Brick,
111 _ if rng.random_bool(0.3) => Style::Brick,
113 _ if rng.random_bool(0.5) => Style::Stone,
114 _ => upper_style,
115 };
116 let gable_style = match upper_style {
117 Style::Wooden(_) | Style::Daub => upper_style,
118 Style::Stone | Style::Brick => Style::Daub,
119 };
120
121 Self {
122 door_tile,
123 tile_aabr,
124 bounds,
125 alt: alt.unwrap_or_else(|| {
126 land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32
127 }),
128 levels,
129 overhang: if levels > 3 {
130 *[-5, 1, 2].choose(rng).unwrap_or(&-5)
134 } else if levels > 1 {
135 *[-5, 1, 2, 3].choose(rng).unwrap_or(&2)
136 } else {
137 0
139 },
140 roof_color: {
141 let colors = [
142 Rgb::new(21, 43, 48),
143 Rgb::new(11, 23, 38),
144 Rgb::new(45, 28, 21),
145 Rgb::new(10, 55, 40),
146 Rgb::new(5, 35, 15),
147 Rgb::new(40, 5, 11),
148 Rgb::new(55, 45, 11),
149 ];
150 *colors.choose(rng).unwrap_or(&Rgb::new(21, 43, 48))
151 },
152 front,
153 christmas_decorations,
154 lower_style,
155 upper_style,
156 gable_style,
157 }
158 }
159
160 pub fn z_range(&self) -> Range<i32> { self.alt..self.alt + self.levels as i32 * STOREY }
161
162 pub fn roof_color(&self) -> Rgb<u8> { self.roof_color }
163}
164
165const STOREY: i32 = 5;
166
167impl Structure for House {
168 #[cfg(feature = "dyn-lib")]
169 #[unsafe(export_name = "as_dyn_structure_house")]
170 fn as_dyn_outer(&self) -> Option<(&dyn Structure, &'static str)> {
171 Some((Self::as_dyn_impl(self), "as_dyn_structure_house"))
172 }
173
174 fn spawn_rules_inner(
175 &self,
176 spawn_rules: &mut SpawnRules,
177 _land: &Land,
178 _wpos: Vec2<i32>,
179 weight: f32,
180 ) {
181 spawn_rules.prefer_alt(self.alt as f32, weight + weight.powi(8) * 25.0);
182 }
183
184 fn door_tile(&self) -> Option<Vec2<i32>> { Some(self.door_tile) }
185
186 fn render_inner(&self, site: &Site, _land: &Land, painter: &Painter) {
187 let storey = STOREY;
188 let roof = storey * self.levels as i32 - 1;
189 let foundations = 20;
190 let alt = self.alt + 1;
191 let door_tile_wpos = site.tile_center_wpos(self.door_tile);
192
193 let wall_fill_upper = self.upper_style.get_fill();
194 let wall_fill_lower = self.lower_style.get_fill();
195 let wall_fill_gable = self.gable_style.get_fill();
196
197 let pillar_fill = match self.upper_style {
198 Style::Wooden(color) => Fill::Block(Block::new(BlockKind::Wood, color / 2)),
199 Style::Brick => Fill::Block(Block::new(BlockKind::Rock, Rgb::new(85, 35, 8))),
200 _ => Fill::Block(Block::new(BlockKind::Wood, Rgb::new(55, 25, 8))),
202 };
203
204 let roof_lip = 1;
206 let roof_height = (self.bounds.min - self.bounds.max)
207 .map(|e| e.abs())
208 .reduce_min()
209 / 2
210 + roof_lip
211 + 1;
212
213 let (roof_primitive, roof_empty) = match self.front {
214 Dir2::Y => {
215 (
216 painter.prim(Primitive::Gable {
217 aabb: Aabb {
218 min: (self.bounds.min - roof_lip).with_z(alt + roof),
219 max: (Vec2::new(
220 self.bounds.max.x + 1 + roof_lip,
221 self.bounds.max.y
222 + 1
223 + roof_lip
224 + (self.levels as i32 - 1) * self.overhang,
225 ))
226 .with_z(alt + roof + roof_height),
227 },
228 inset: roof_height,
229 dir: Dir2::Y,
230 }),
231 painter.prim(Primitive::Gable {
232 aabb: Aabb {
233 min: (Vec2::new(self.bounds.min.x, self.bounds.min.y - 1))
234 .with_z(alt + roof), max: (Vec2::new(
237 self.bounds.max.x + 1,
238 self.bounds.max.y
239 + 1
240 + (self.levels as i32 - 1) * self.overhang
241 + 1,
242 ))
243 .with_z(alt + roof + roof_height - 1),
244 },
245 inset: roof_height - 1,
246 dir: Dir2::Y,
247 }),
248 )
249 },
250 Dir2::X => {
251 (
252 painter.prim(Primitive::Gable {
253 aabb: Aabb {
254 min: (self.bounds.min - roof_lip).with_z(alt + roof),
255 max: Vec2::new(
256 self.bounds.max.x
257 + 1
258 + roof_lip
259 + (self.levels as i32 - 1) * self.overhang,
260 self.bounds.max.y + 1 + roof_lip,
261 )
262 .with_z(alt + roof + roof_height),
263 },
264 inset: roof_height,
265 dir: Dir2::X,
266 }),
267 painter.prim(Primitive::Gable {
268 aabb: Aabb {
269 min: (Vec2::new(self.bounds.min.x - 1, self.bounds.min.y))
270 .with_z(alt + roof), max: Vec2::new(
273 self.bounds.max.x
274 + 1
275 + (self.levels as i32 - 1) * self.overhang
276 + 1,
277 self.bounds.max.y + 1,
278 )
279 .with_z(alt + roof + roof_height - 1),
280 },
281 inset: roof_height - 1,
282 dir: Dir2::X,
283 }),
284 )
285 },
286 Dir2::NegY => (
287 painter.prim(Primitive::Gable {
288 aabb: Aabb {
289 min: Vec2::new(
290 self.bounds.min.x - roof_lip,
291 self.bounds.min.y - roof_lip - (self.levels as i32 - 1) * self.overhang,
292 )
293 .with_z(alt + roof),
294 max: Vec2::new(
295 self.bounds.max.x + 1 + roof_lip,
296 self.bounds.max.y + roof_lip + 1,
297 )
298 .with_z(alt + roof + roof_height),
299 },
300 inset: roof_height,
301 dir: Dir2::Y,
302 }),
303 painter.prim(Primitive::Gable {
304 aabb: Aabb {
305 min: Vec2::new(
306 self.bounds.min.x,
307 self.bounds.min.y - 1 - (self.levels as i32 - 1) * self.overhang - 1,
308 )
309 .with_z(alt + roof),
310 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + roof_lip + 1)
311 .with_z(alt + roof + roof_height - 1),
312 },
313 inset: roof_height - 1,
314 dir: Dir2::Y,
315 }),
316 ),
317 _ => (
318 painter.prim(Primitive::Gable {
319 aabb: Aabb {
320 min: Vec2::new(
321 self.bounds.min.x - roof_lip - (self.levels as i32 - 1) * self.overhang,
322 self.bounds.min.y - roof_lip,
323 )
324 .with_z(alt + roof),
325 max: Vec2::new(
326 self.bounds.max.x + 1 + roof_lip,
327 self.bounds.max.y + 1 + roof_lip,
328 )
329 .with_z(alt + roof + roof_height),
330 },
331 inset: roof_height,
332 dir: Dir2::X,
333 }),
334 painter.prim(Primitive::Gable {
335 aabb: Aabb {
336 min: Vec2::new(
337 self.bounds.min.x
338 - roof_lip
339 - 1
340 - (self.levels as i32 - 1) * self.overhang,
341 self.bounds.min.y,
342 )
343 .with_z(alt + roof),
344 max: Vec2::new(self.bounds.max.x + 1 + roof_lip, self.bounds.max.y + 1)
345 .with_z(alt + roof + roof_height - 1),
346 },
347 inset: roof_height - 1,
348 dir: Dir2::X,
349 }),
350 ),
351 };
352
353 let (roof_front_wall, roof_rear_wall) = match self.front {
354 Dir2::Y => (
355 painter.prim(Primitive::Aabb(Aabb {
356 min: (Vec2::new(
357 self.bounds.min.x,
358 self.bounds.max.y + (self.levels as i32 - 1) * self.overhang,
359 ))
360 .with_z(alt + roof),
361 max: (Vec2::new(
362 self.bounds.max.x + 1,
363 self.bounds.max.y + (self.levels as i32 - 1) * self.overhang + 1,
364 ))
365 .with_z(alt + roof + roof_height),
366 })),
367 painter.prim(Primitive::Aabb(Aabb {
368 min: (Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof)),
369 max: (Vec2::new(self.bounds.max.x + 1, self.bounds.min.y + 1)
370 .with_z(alt + roof + roof_height)),
371 })),
372 ),
373 Dir2::X => (
374 painter.prim(Primitive::Aabb(Aabb {
375 min: Vec2::new(
376 self.bounds.max.x + (self.levels as i32 - 1) * self.overhang,
377 self.bounds.min.y,
378 )
379 .with_z(alt + roof),
380 max: Vec2::new(
381 self.bounds.max.x + (self.levels as i32 - 1) * self.overhang + 1,
382 self.bounds.max.y + 1,
383 )
384 .with_z(alt + roof + roof_height),
385 })),
386 painter.prim(Primitive::Aabb(Aabb {
387 min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
388 max: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y + 1)
389 .with_z(alt + roof + roof_height),
390 })),
391 ),
392 Dir2::NegY => (
393 painter.prim(Primitive::Aabb(Aabb {
394 min: Vec2::new(
395 self.bounds.min.x,
396 self.bounds.min.y - (self.levels as i32 - 1) * self.overhang,
397 )
398 .with_z(alt + roof),
399 max: Vec2::new(
400 self.bounds.max.x + 1,
401 self.bounds.min.y - (self.levels as i32 - 1) * self.overhang + 1,
402 )
403 .with_z(alt + roof + roof_height),
404 })),
405 painter.prim(Primitive::Aabb(Aabb {
406 min: Vec2::new(self.bounds.min.x, self.bounds.max.y).with_z(alt + roof),
407 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
408 .with_z(alt + roof + roof_height),
409 })),
410 ),
411 _ => (
412 painter.prim(Primitive::Aabb(Aabb {
413 min: Vec2::new(
414 self.bounds.min.x - (self.levels as i32 - 1) * self.overhang,
415 self.bounds.min.y,
416 )
417 .with_z(alt + roof),
418 max: Vec2::new(
419 self.bounds.min.x - (self.levels as i32 - 1) * self.overhang + 1,
420 self.bounds.max.y + 1,
421 )
422 .with_z(alt + roof + roof_height),
423 })),
424 painter.prim(Primitive::Aabb(Aabb {
425 min: Vec2::new(self.bounds.max.x, self.bounds.min.y).with_z(alt + roof),
426 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
427 .with_z(alt + roof + roof_height),
428 })),
429 ),
430 };
431 let roof_front = painter.prim(Primitive::intersect(roof_empty, roof_front_wall));
432 let roof_rear = painter.prim(Primitive::intersect(roof_empty, roof_rear_wall));
433 painter.fill(
434 roof_primitive,
435 Fill::Brick(BlockKind::Wood, self.roof_color, 24),
436 );
437 painter.fill(roof_empty, Fill::Block(Block::empty()));
438 let roof_walls = painter.prim(Primitive::union(roof_front, roof_rear));
439 painter.fill(roof_walls, wall_fill_gable.clone());
440 let max_overhang = (self.levels as i32 - 1) * self.overhang;
441 let (roof_beam, roof_beam_right, roof_beam_left) = match self.front {
442 Dir2::Y => (
443 painter.prim(Primitive::Aabb(Aabb {
444 min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
445 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1 + max_overhang)
446 .with_z(alt + roof + 1),
447 })),
448 painter.prim(Primitive::Aabb(Aabb {
449 min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
450 max: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y + 1 + max_overhang)
451 .with_z(alt + roof + 1),
452 })),
453 painter.prim(Primitive::Aabb(Aabb {
454 min: Vec2::new(self.bounds.max.x, self.bounds.min.y).with_z(alt + roof),
455 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1 + max_overhang)
456 .with_z(alt + roof + 1),
457 })),
458 ),
459 Dir2::X => (
460 painter.prim(Primitive::Aabb(Aabb {
461 min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
462 max: Vec2::new(self.bounds.max.x + max_overhang + 1, self.bounds.max.y + 1)
463 .with_z(alt + roof + 1),
464 })),
465 painter.prim(Primitive::Aabb(Aabb {
466 min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
467 max: Vec2::new(self.bounds.max.x + max_overhang + 1, self.bounds.min.y + 1)
468 .with_z(alt + roof + 1),
469 })),
470 painter.prim(Primitive::Aabb(Aabb {
471 min: Vec2::new(self.bounds.min.x, self.bounds.max.y).with_z(alt + roof),
472 max: Vec2::new(self.bounds.max.x + max_overhang + 1, self.bounds.max.y + 1)
473 .with_z(alt + roof + 1),
474 })),
475 ),
476 Dir2::NegY => (
477 painter.prim(Primitive::Aabb(Aabb {
478 min: Vec2::new(self.bounds.min.x, self.bounds.min.y - max_overhang)
479 .with_z(alt + roof),
480 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
481 .with_z(alt + roof + 1),
482 })),
483 painter.prim(Primitive::Aabb(Aabb {
484 min: Vec2::new(self.bounds.max.x, self.bounds.min.y - max_overhang)
485 .with_z(alt + roof),
486 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
487 .with_z(alt + roof + 1),
488 })),
489 painter.prim(Primitive::Aabb(Aabb {
490 min: Vec2::new(self.bounds.min.x, self.bounds.min.y - max_overhang)
491 .with_z(alt + roof),
492 max: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y + 1)
493 .with_z(alt + roof + 1),
494 })),
495 ),
496 _ => (
497 painter.prim(Primitive::Aabb(Aabb {
498 min: Vec2::new(self.bounds.min.x - max_overhang - 1, self.bounds.min.y)
499 .with_z(alt + roof),
500 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
501 .with_z(alt + roof + 1),
502 })),
503 painter.prim(Primitive::Aabb(Aabb {
504 min: Vec2::new(self.bounds.min.x - max_overhang, self.bounds.min.y)
505 .with_z(alt + roof),
506 max: Vec2::new(self.bounds.max.x + 1, self.bounds.min.y + 1)
507 .with_z(alt + roof + 1),
508 })),
509 painter.prim(Primitive::Aabb(Aabb {
510 min: Vec2::new(self.bounds.min.x - max_overhang, self.bounds.max.y)
511 .with_z(alt + roof),
512 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
513 .with_z(alt + roof + 1),
514 })),
515 ),
516 };
517 let quarter_x = self.bounds.min.x + (self.bounds.max.x - self.bounds.min.x) / 4;
518 let quarter_y = self.bounds.min.y + (self.bounds.max.y - self.bounds.min.y) / 4;
519 let half_x = self.bounds.min.x + (self.bounds.max.x - self.bounds.min.x) / 2;
520 let half_y = self.bounds.min.y + (self.bounds.max.y - self.bounds.min.y) / 2;
521 let three_quarter_x = self.bounds.min.x + 3 * (self.bounds.max.x - self.bounds.min.x) / 4;
522 let three_quarter_y = self.bounds.min.y + 3 * (self.bounds.max.y - self.bounds.min.y) / 4;
523 let top_rafter = if self.front.is_y() {
524 painter.prim(Primitive::Aabb(Aabb {
525 min: (Vec2::new(half_x, self.bounds.min.y - 2 - max_overhang.abs())
526 .with_z(alt + roof)),
527 max: (Vec2::new(half_x + 1, self.bounds.max.y + 2 + max_overhang.abs()))
528 .with_z(alt + roof + roof_height),
529 }))
530 } else {
531 painter.prim(Primitive::Aabb(Aabb {
532 min: (Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y)
533 .with_z(alt + roof)),
534 max: (Vec2::new(self.bounds.max.x + 1 + max_overhang.abs(), half_y + 1))
535 .with_z(alt + roof + roof_height),
536 }))
537 };
538 let left_rafter = if self.front.is_y() {
539 painter.prim(Primitive::Plane(
540 Aabr {
541 min: Vec2::new(half_x, self.bounds.min.y - 1 - max_overhang.abs()),
542 max: Vec2::new(
543 three_quarter_x + 1,
544 self.bounds.max.y + 1 + max_overhang.abs(),
545 ),
546 },
547 Vec2::new(half_x, self.bounds.min.y - 1 - max_overhang.abs()).with_z(alt + roof),
548 Vec2::new(1.0, 0.0),
549 ))
550 } else {
551 painter.prim(Primitive::Plane(
552 Aabr {
553 min: Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y),
554 max: Vec2::new(
555 self.bounds.max.x + 1 + max_overhang.abs(),
556 three_quarter_y + 1,
557 ),
558 },
559 Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y).with_z(alt + roof),
560 Vec2::new(0.0, 1.0),
561 ))
562 };
563 let right_rafter = if self.front.is_y() {
564 painter.prim(Primitive::Plane(
565 Aabr {
566 min: Vec2::new(quarter_x, self.bounds.min.y - 1 - max_overhang.abs()),
567 max: Vec2::new(half_x + 1, self.bounds.max.y + 1 + max_overhang.abs()),
568 },
569 Vec2::new(half_x, self.bounds.min.y - 1 - max_overhang.abs()).with_z(alt + roof),
570 Vec2::new(1.0, 0.0),
571 ))
572 } else {
573 painter.prim(Primitive::Plane(
574 Aabr {
575 min: Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), quarter_y),
576 max: Vec2::new(self.bounds.max.x + 1 + max_overhang.abs(), half_y + 1),
577 },
578 Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y).with_z(alt + roof),
579 Vec2::new(0.0, 1.0),
580 ))
581 };
582 let rafters1 = painter.prim(Primitive::union(left_rafter, right_rafter));
583 let rafters2 = painter.prim(Primitive::union(rafters1, top_rafter));
584
585 painter.fill(
586 painter.prim(Primitive::intersect(roof_beam, roof_walls)),
587 pillar_fill.clone(),
588 );
589 painter.fill(
590 painter.prim(Primitive::union(roof_beam_left, roof_beam_right)),
591 pillar_fill.clone(),
592 );
593 painter.fill(
594 painter.prim(Primitive::intersect(rafters2, roof_walls)),
595 pillar_fill.clone(),
596 );
597
598 for i in 1..self.levels + 1 {
601 let previous_height = (storey * (i as i32 - 1) - 1).max(-1);
602 let height = storey * i as i32 - 1;
603 let window_height = storey - 3;
604 let storey_increase = (i as i32 - 1) * self.overhang;
605
606 let inner_level = if self.overhang < -4 && i > 1 {
608 match self.front {
609 Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
610 min: (self.bounds.min + 1).with_z(alt + previous_height),
611 max: Vec2::new(self.bounds.max.x, self.bounds.max.y + storey_increase + 1)
612 .with_z(alt + height),
613 })),
614 Dir2::X => painter.prim(Primitive::Aabb(Aabb {
615 min: (self.bounds.min + 1).with_z(alt + previous_height),
616 max: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.max.y)
617 .with_z(alt + height),
618 })),
619 Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
620 min: Vec2::new(
621 self.bounds.min.x + 1,
622 self.bounds.min.y - storey_increase + 1,
623 )
624 .with_z(alt + previous_height),
625 max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
626 })),
627 _ => painter.prim(Primitive::Aabb(Aabb {
628 min: Vec2::new(
629 self.bounds.min.x - storey_increase + 1,
630 self.bounds.min.y + 1,
631 )
632 .with_z(alt + previous_height),
633 max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
634 })),
635 }
636 } else {
637 match self.front {
638 Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
639 min: (self.bounds.min + 1).with_z(alt + previous_height),
640 max: Vec2::new(self.bounds.max.x, self.bounds.max.y + storey_increase)
641 .with_z(alt + height),
642 })),
643 Dir2::X => painter.prim(Primitive::Aabb(Aabb {
644 min: (self.bounds.min + 1).with_z(alt + previous_height),
645 max: (Vec2::new(self.bounds.max.x + storey_increase, self.bounds.max.y))
646 .with_z(alt + height),
647 })),
648 Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
649 min: Vec2::new(
650 self.bounds.min.x + 1,
651 self.bounds.min.y - storey_increase + 1,
652 )
653 .with_z(alt + previous_height),
654 max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
655 })),
656 _ => painter.prim(Primitive::Aabb(Aabb {
657 min: Vec2::new(
658 self.bounds.min.x - storey_increase + 1,
659 self.bounds.min.y + 1,
660 )
661 .with_z(alt + previous_height),
662 max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
663 })),
664 }
665 };
666 let outer_level = match self.front {
667 Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
668 min: self.bounds.min.with_z(alt + previous_height),
669 max: (Vec2::new(
670 self.bounds.max.x + 1,
671 self.bounds.max.y + storey_increase + 1,
672 ))
673 .with_z(alt + height),
674 })),
675 Dir2::X => painter.prim(Primitive::Aabb(Aabb {
676 min: self.bounds.min.with_z(alt + previous_height),
677 max: Vec2::new(
678 self.bounds.max.x + storey_increase + 1,
679 self.bounds.max.y + 1,
680 )
681 .with_z(alt + height),
682 })),
683 Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
684 min: Vec2::new(self.bounds.min.x, self.bounds.min.y - storey_increase)
685 .with_z(alt + previous_height),
686 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
687 .with_z(alt + height),
688 })),
689 _ => painter.prim(Primitive::Aabb(Aabb {
690 min: Vec2::new(self.bounds.min.x - storey_increase, self.bounds.min.y)
691 .with_z(alt + previous_height),
692 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
693 .with_z(alt + height),
694 })),
695 };
696
697 let is_lower = i <= 1;
698 let style = if is_lower {
699 self.lower_style
700 } else {
701 self.upper_style
702 };
703 let wall_block_fill = if is_lower {
704 wall_fill_lower.clone()
705 } else {
706 wall_fill_upper.clone()
707 };
708 painter.fill(outer_level, wall_block_fill);
709 painter.fill(inner_level, Fill::Block(Block::empty()));
710
711 let walls = outer_level
712 .union(inner_level)
713 .without(outer_level.intersect(inner_level));
714
715 if !matches!(style, Style::Stone) {
718 let mut pillars_y = painter.prim(Primitive::Empty);
719 let mut overhang_supports = painter.prim(Primitive::Empty);
720
721 for x in self.tile_aabr.min.x - 2..self.tile_aabr.max.x + 2 {
722 if self.overhang >= 2 && self.front.is_y() {
723 let temp = match self.front {
724 Dir2::Y => site.tile_wpos(Vec2::new(x, self.tile_aabr.max.y)),
725 _ => Vec2::zero(),
727 };
728 let support = match self.front {
732 Dir2::Y => painter.line(
733 Vec2::new(
734 temp.x,
735 self.bounds.max.y + storey_increase - self.overhang + 1,
736 )
737 .with_z(alt + previous_height - 3),
738 Vec2::new(
739 temp.x,
740 self.bounds.max.y + storey_increase - self.overhang + 2,
741 )
742 .with_z(alt + previous_height),
743 0.75,
744 ),
745 _ => painter.prim(Primitive::Empty),
753 };
754 if temp.x <= self.bounds.max.x && temp.x >= self.bounds.min.x {
755 overhang_supports =
756 painter.prim(Primitive::union(overhang_supports, support));
757 }
758 }
759 let pillar = painter.prim(Primitive::Aabb(Aabb {
760 min: site
761 .tile_wpos(Vec2::new(x, self.tile_aabr.min.y - 4))
762 .with_z(alt + previous_height),
763 max: (site.tile_wpos(Vec2::new(x, self.tile_aabr.max.y + 4))
764 + Vec2::unit_x())
765 .with_z(alt + height),
766 }));
767 pillars_y = painter.prim(Primitive::union(pillars_y, pillar));
768 }
769 let mut pillars_x = painter.prim(Primitive::Empty);
770 for y in self.tile_aabr.min.y - 2..self.tile_aabr.max.y + 2 {
771 if self.overhang >= 2 && !self.front.is_y() {
772 let temp = match self.front {
773 Dir2::Y => Vec2::zero(),
774 Dir2::X => site.tile_wpos(Vec2::new(self.tile_aabr.max.x, y)),
775 Dir2::NegY => Vec2::zero(),
776 _ => site.tile_wpos(Vec2::new(self.tile_aabr.min.x, y)),
777 };
778 let support = match self.front {
779 Dir2::Y => painter.prim(Primitive::Empty),
780 Dir2::X => painter.line(
781 Vec2::new(
782 self.bounds.max.x + storey_increase - self.overhang + 1,
783 temp.y,
784 )
785 .with_z(alt + previous_height - 3),
786 Vec2::new(
787 self.bounds.max.x + storey_increase - self.overhang + 2,
788 temp.y,
789 )
790 .with_z(alt + previous_height),
791 0.75,
792 ),
793 Dir2::NegY => painter.prim(Primitive::Empty),
794 _ => painter.line(
795 Vec2::new(
796 self.bounds.min.x - storey_increase + self.overhang - 1,
797 temp.y,
798 )
799 .with_z(alt + previous_height - 3),
800 Vec2::new(
801 self.bounds.min.x - storey_increase + self.overhang - 2,
802 temp.y,
803 )
804 .with_z(alt + previous_height),
805 0.75,
806 ),
807 };
808 if temp.y <= self.bounds.max.y && temp.y >= self.bounds.min.y {
809 overhang_supports =
810 painter.prim(Primitive::union(overhang_supports, support));
811 }
812 }
813 let pillar = painter.prim(Primitive::Aabb(Aabb {
814 min: site
815 .tile_wpos(Vec2::new(self.tile_aabr.min.x - 4, y))
816 .with_z(alt + previous_height),
817 max: (site.tile_wpos(Vec2::new(self.tile_aabr.max.x + 4, y))
818 + Vec2::unit_y())
819 .with_z(alt + height),
820 }));
821 pillars_x = painter.prim(Primitive::union(pillars_x, pillar));
822 }
823 let front_wall = if self.overhang < -4 && i > 1 {
824 painter.prim(Primitive::Empty)
825 } else {
826 match self.front {
827 Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
828 min: Vec2::new(
829 self.bounds.min.x - 1,
830 self.bounds.max.y + storey_increase,
831 )
832 .with_z(alt + previous_height),
833 max: Vec2::new(
834 self.bounds.max.x + 1,
835 self.bounds.max.y + storey_increase + 1,
836 )
837 .with_z(alt + height),
838 })),
839 Dir2::X => painter.prim(Primitive::Aabb(Aabb {
840 min: Vec2::new(
841 self.bounds.max.x + storey_increase,
842 self.bounds.min.y - 1,
843 )
844 .with_z(alt + previous_height),
845 max: Vec2::new(
846 self.bounds.max.x + storey_increase + 1,
847 self.bounds.max.y + 1,
848 )
849 .with_z(alt + height),
850 })),
851 Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
852 min: Vec2::new(
853 self.bounds.min.x - 1,
854 self.bounds.min.y - storey_increase,
855 )
856 .with_z(alt + previous_height),
857 max: Vec2::new(
858 self.bounds.max.x + 1,
859 self.bounds.min.y - storey_increase + 1,
860 )
861 .with_z(alt + height),
862 })),
863 _ => painter.prim(Primitive::Aabb(Aabb {
864 min: Vec2::new(
865 self.bounds.min.x - storey_increase,
866 self.bounds.min.y - 1,
867 )
868 .with_z(alt + previous_height),
869 max: Vec2::new(
870 self.bounds.min.x - storey_increase + 1,
871 self.bounds.max.y + 1,
872 )
873 .with_z(alt + height),
874 })),
875 }
876 };
877 let pillars1 = if self.front.is_y() {
878 painter.prim(Primitive::intersect(pillars_y, front_wall))
879 } else {
880 painter.prim(Primitive::intersect(pillars_x, front_wall))
881 };
882 let pillars2 = painter.prim(Primitive::intersect(pillars_x, pillars_y));
883 let pillars3 = painter.prim(Primitive::union(pillars1, pillars2));
884 let pillars4 = match self.front {
885 Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
886 min: Vec2::new(self.bounds.min.x - 1, self.bounds.min.y - 1)
887 .with_z(alt + previous_height),
888 max: Vec2::new(
889 self.bounds.max.x + 1,
890 self.bounds.max.y + storey_increase + 1,
891 )
892 .with_z(alt + previous_height + 1),
893 })),
894 Dir2::X => painter.prim(Primitive::Aabb(Aabb {
895 min: Vec2::new(self.bounds.min.x - 1, self.bounds.min.y - 1)
896 .with_z(alt + previous_height),
897 max: Vec2::new(
898 self.bounds.max.x + storey_increase + 1,
899 self.bounds.max.y + 1,
900 )
901 .with_z(alt + previous_height + 1),
902 })),
903 Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
904 min: Vec2::new(
905 self.bounds.min.x - 1,
906 self.bounds.min.y - storey_increase - 1,
907 )
908 .with_z(alt + previous_height),
909 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
910 .with_z(alt + previous_height + 1),
911 })),
912 _ => painter.prim(Primitive::Aabb(Aabb {
913 min: Vec2::new(
914 self.bounds.min.x - storey_increase - 1,
915 self.bounds.min.y - 1,
916 )
917 .with_z(alt + previous_height),
918 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
919 .with_z(alt + previous_height + 1),
920 })),
921 };
922 let pillars = if matches!(style, Style::Brick) {
923 pillars4
924 } else {
925 painter.prim(Primitive::union(pillars3, pillars4))
926 };
927 painter.fill(
928 painter.prim(Primitive::intersect(walls, pillars)),
929 pillar_fill.clone(),
930 );
931
932 painter.fill(overhang_supports, pillar_fill.clone());
933 }
934
935 {
937 let mut windows = painter.prim(Primitive::Empty);
938 for y in self.tile_aabr.min.y - 2..self.tile_aabr.max.y + 2 {
939 let min = (site.tile_wpos(Vec2::new(self.tile_aabr.min.x - 4, y))
940 + Vec2::unit_y() * 2)
941 .with_z(alt + previous_height + 2);
942 let max = (site.tile_wpos(Vec2::new(self.tile_aabr.max.x + 4, y + 1))
943 + Vec2::new(1, -1))
944 .with_z(alt + previous_height + 2 + window_height);
945 let window = painter.prim(Primitive::Aabb(Aabb { min, max }));
946 let add_windows = match self.front {
947 Dir2::Y => {
948 max.y < self.bounds.max.y + storey_increase && min.y > self.bounds.min.y
949 },
950 Dir2::X => max.y < self.bounds.max.y && min.y > self.bounds.min.y,
951 Dir2::NegY => {
952 max.y < self.bounds.max.y && min.y > self.bounds.min.y - storey_increase
953 },
954 _ => max.y < self.bounds.max.y && min.y > self.bounds.min.y,
955 };
956 if add_windows {
957 windows = painter.prim(Primitive::union(windows, window));
958 }
959 }
960 painter.fill(
961 painter.prim(Primitive::intersect(walls, windows)),
962 Fill::Block(Block::air(SpriteKind::Window1).with_ori(2).unwrap()),
963 );
964 if i == 1 {
966 let mut torches_min = painter.prim(Primitive::Empty);
967 let mut torches_max = painter.prim(Primitive::Empty);
968 for y in self.tile_aabr.min.y..self.tile_aabr.max.y {
969 let pos = site
970 .tile_wpos(Vec2::new(self.tile_aabr.min.x, y))
971 .with_z(alt + previous_height + 3)
972 + Vec3::new(-1, 0, 0);
973 let torch = painter.prim(Primitive::Aabb(Aabb {
974 min: pos,
975 max: pos + 1,
976 }));
977 torches_min = painter.prim(Primitive::union(torches_min, torch));
978
979 let pos = site
980 .tile_wpos(Vec2::new(self.tile_aabr.max.x, y + 1))
981 .with_z(alt + previous_height + 3)
982 + Vec3::new(1, 0, 0);
983 let torch = painter.prim(Primitive::Aabb(Aabb {
984 min: pos,
985 max: pos + 1,
986 }));
987 torches_max = painter.prim(Primitive::union(torches_max, torch));
988 }
989 painter.fill(
990 torches_min,
991 Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(6).unwrap()),
992 );
993 painter.fill(
994 torches_max,
995 Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(2).unwrap()),
996 );
997 }
998 }
999 {
1001 let mut windows = painter.prim(Primitive::Empty);
1002 for x in self.tile_aabr.min.x - 2..self.tile_aabr.max.x + 2 {
1003 let min = (site.tile_wpos(Vec2::new(x, self.tile_aabr.min.y - 4))
1004 + Vec2::unit_x() * 2)
1005 .with_z(alt + previous_height + 2);
1006 let max = (site.tile_wpos(Vec2::new(x + 1, self.tile_aabr.max.y + 4))
1007 + Vec2::new(-1, 1))
1008 .with_z(alt + previous_height + 2 + window_height);
1009 let window = painter.prim(Primitive::Aabb(Aabb { min, max }));
1010 let add_windows = match self.front {
1011 Dir2::Y => max.x < self.bounds.max.x && min.x > self.bounds.min.x,
1012 Dir2::X => {
1013 max.x < self.bounds.max.x + storey_increase && min.x > self.bounds.min.x
1014 },
1015 Dir2::NegY => max.x < self.bounds.max.x && min.x > self.bounds.min.x,
1016 _ => {
1017 max.x < self.bounds.max.x && min.x > self.bounds.min.x - storey_increase
1018 },
1019 };
1020 if add_windows {
1021 windows = painter.prim(Primitive::union(windows, window));
1022 };
1023 }
1024 painter.fill(
1025 painter.prim(Primitive::intersect(walls, windows)),
1026 Fill::Block(Block::air(SpriteKind::Window1).with_ori(0).unwrap()),
1027 );
1028 if i == 1 {
1030 let mut torches_min = painter.prim(Primitive::Empty);
1031 let mut torches_max = painter.prim(Primitive::Empty);
1032 for x in self.tile_aabr.min.x..self.tile_aabr.max.x {
1033 let pos = site
1034 .tile_wpos(Vec2::new(x + 1, self.tile_aabr.min.y))
1035 .with_z(alt + previous_height + 3)
1036 + Vec3::new(0, -1, 0);
1037 let torch = painter.prim(Primitive::Aabb(Aabb {
1038 min: pos,
1039 max: pos + 1,
1040 }));
1041 torches_min = painter.prim(Primitive::union(torches_min, torch));
1042
1043 let pos = site
1044 .tile_wpos(Vec2::new(x, self.tile_aabr.max.y))
1045 .with_z(alt + previous_height + 3)
1046 + Vec3::new(0, 1, 0);
1047 let torch = painter.prim(Primitive::Aabb(Aabb {
1048 min: pos,
1049 max: pos + 1,
1050 }));
1051 torches_max = painter.prim(Primitive::union(torches_max, torch));
1052 }
1053 painter.fill(
1054 torches_min,
1055 Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(0).unwrap()),
1056 );
1057 painter.fill(
1058 torches_max,
1059 Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(4).unwrap()),
1060 );
1061 }
1062 }
1063
1064 if self.overhang < -4 && i > 1 {
1066 let shed = match self.front {
1067 Dir2::Y => painter.prim(Primitive::Ramp {
1068 aabb: Aabb {
1069 min: Vec2::new(
1070 self.bounds.min.x - 1,
1071 self.bounds.max.y + storey_increase + 1,
1072 )
1073 .with_z(alt + previous_height),
1074 max: Vec2::new(
1075 self.bounds.max.x + 1,
1076 self.bounds.max.y + storey_increase + self.overhang.abs() + 1,
1077 )
1078 .with_z(alt + height),
1079 },
1080 inset: storey,
1081 dir: Dir2::NegY,
1082 }),
1083 Dir2::X => painter.prim(Primitive::Ramp {
1084 aabb: Aabb {
1085 min: Vec2::new(
1086 self.bounds.max.x + storey_increase + 1,
1087 self.bounds.min.y - 1,
1088 )
1089 .with_z(alt + previous_height),
1090 max: Vec2::new(
1091 self.bounds.max.x + storey_increase + self.overhang.abs() + 1,
1092 self.bounds.max.y + 1,
1093 )
1094 .with_z(alt + height),
1095 },
1096 inset: storey,
1097 dir: Dir2::NegX,
1098 }),
1099 Dir2::NegY => painter.prim(Primitive::Ramp {
1100 aabb: Aabb {
1101 min: Vec2::new(
1102 self.bounds.min.x - 1,
1103 self.bounds.min.y - storey_increase - self.overhang.abs(),
1104 )
1105 .with_z(alt + previous_height),
1106 max: Vec2::new(
1107 self.bounds.max.x + 2,
1108 self.bounds.min.y - storey_increase,
1109 )
1110 .with_z(alt + height),
1111 },
1112 inset: storey,
1113 dir: Dir2::Y,
1114 }),
1115 _ => painter.prim(Primitive::Ramp {
1116 aabb: Aabb {
1117 min: Vec2::new(
1118 self.bounds.min.x - storey_increase - self.overhang.abs(),
1119 self.bounds.min.y - 1,
1120 )
1121 .with_z(alt + previous_height),
1122 max: Vec2::new(
1123 self.bounds.min.x - storey_increase + 1,
1124 self.bounds.max.y + 2,
1125 )
1126 .with_z(alt + height),
1127 },
1128 inset: storey,
1129 dir: Dir2::X,
1130 }),
1131 };
1132 let shed_empty = match self.front {
1133 Dir2::Y => painter.prim(Primitive::Ramp {
1134 aabb: Aabb {
1135 min: Vec2::new(
1136 self.bounds.min.x - 1,
1137 self.bounds.max.y + storey_increase + 1,
1138 )
1139 .with_z(alt + previous_height),
1140 max: Vec2::new(
1141 self.bounds.max.x + 1,
1142 self.bounds.max.y + storey_increase + self.overhang.abs(),
1143 )
1144 .with_z(alt + height - 1),
1145 },
1146 inset: storey - 1,
1147 dir: Dir2::NegY,
1148 }),
1149 Dir2::X => painter.prim(Primitive::Ramp {
1150 aabb: Aabb {
1151 min: Vec2::new(
1152 self.bounds.max.x + storey_increase + 1,
1153 self.bounds.min.y - 1,
1154 )
1155 .with_z(alt + previous_height),
1156 max: Vec2::new(
1157 self.bounds.max.x + storey_increase + self.overhang.abs(),
1158 self.bounds.max.y + 1,
1159 )
1160 .with_z(alt + height - 1),
1161 },
1162 inset: storey - 1,
1163 dir: Dir2::NegX,
1164 }),
1165 Dir2::NegY => painter.prim(Primitive::Ramp {
1166 aabb: Aabb {
1167 min: Vec2::new(
1168 self.bounds.min.x - 1,
1169 self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1170 )
1171 .with_z(alt + previous_height),
1172 max: Vec2::new(
1173 self.bounds.max.x + 2,
1174 self.bounds.min.y - storey_increase + 1,
1175 )
1176 .with_z(alt + height),
1177 },
1178 inset: storey - 1,
1179 dir: Dir2::Y,
1180 }),
1181 _ => painter.prim(Primitive::Ramp {
1182 aabb: Aabb {
1183 min: Vec2::new(
1184 self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1185 self.bounds.min.y - 1,
1186 )
1187 .with_z(alt + previous_height),
1188 max: Vec2::new(
1189 self.bounds.min.x - storey_increase + 1,
1190 self.bounds.max.y + 2,
1191 )
1192 .with_z(alt + height),
1193 },
1194 inset: storey - 1,
1195 dir: Dir2::X,
1196 }),
1197 };
1198 painter.fill(shed, Fill::Brick(BlockKind::Wood, self.roof_color, 24));
1199 painter.fill(shed_empty, Fill::Block(Block::empty()));
1200 let shed_left_wall = match self.front {
1201 Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
1202 min: Vec2::new(self.bounds.min.x, self.bounds.max.y + storey_increase + 1)
1203 .with_z(alt + previous_height),
1204 max: Vec2::new(
1205 self.bounds.min.x + 1,
1206 self.bounds.max.y + storey_increase + self.overhang.abs(),
1207 )
1208 .with_z(alt + height - 1),
1209 })),
1210 Dir2::X => painter.prim(Primitive::Aabb(Aabb {
1211 min: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.min.y)
1212 .with_z(alt + previous_height),
1213 max: Vec2::new(
1214 self.bounds.max.x + storey_increase + self.overhang.abs(),
1215 self.bounds.min.y + 1,
1216 )
1217 .with_z(alt + height - 1),
1218 })),
1219 Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
1220 min: Vec2::new(
1221 self.bounds.max.x,
1222 self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1223 )
1224 .with_z(alt + previous_height),
1225 max: Vec2::new(
1226 self.bounds.max.x + 1,
1227 self.bounds.min.y - storey_increase + 1,
1228 )
1229 .with_z(alt + height),
1230 })),
1231 _ => painter.prim(Primitive::Aabb(Aabb {
1232 min: Vec2::new(
1233 self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1234 self.bounds.max.y,
1235 )
1236 .with_z(alt + previous_height),
1237 max: Vec2::new(
1238 self.bounds.min.x - storey_increase + 1,
1239 self.bounds.max.y + 1,
1240 )
1241 .with_z(alt + height),
1242 })),
1243 };
1244 let shed_right_wall = match self.front {
1245 Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
1246 min: Vec2::new(self.bounds.max.x, self.bounds.max.y + storey_increase + 1)
1247 .with_z(alt + previous_height),
1248 max: Vec2::new(
1249 self.bounds.max.x + 1,
1250 self.bounds.max.y + storey_increase + self.overhang.abs(),
1251 )
1252 .with_z(alt + height - 1),
1253 })),
1254 Dir2::X => painter.prim(Primitive::Aabb(Aabb {
1255 min: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.max.y)
1256 .with_z(alt + previous_height),
1257 max: Vec2::new(
1258 self.bounds.max.x + storey_increase + self.overhang.abs(),
1259 self.bounds.max.y + 1,
1260 )
1261 .with_z(alt + height - 1),
1262 })),
1263 Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
1264 min: Vec2::new(
1265 self.bounds.min.x,
1266 self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1267 )
1268 .with_z(alt + previous_height),
1269 max: Vec2::new(
1270 self.bounds.min.x + 1,
1271 self.bounds.min.y - storey_increase + 1,
1272 )
1273 .with_z(alt + height),
1274 })),
1275 _ => painter.prim(Primitive::Aabb(Aabb {
1276 min: Vec2::new(
1277 self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1278 self.bounds.min.y,
1279 )
1280 .with_z(alt + previous_height),
1281 max: Vec2::new(
1282 self.bounds.min.x - storey_increase + 1,
1283 self.bounds.min.y + 1,
1284 )
1285 .with_z(alt + height),
1286 })),
1287 };
1288 let shed_wall_beams = match self.front {
1289 Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
1290 min: Vec2::new(self.bounds.min.x, self.bounds.max.y + storey_increase + 1)
1291 .with_z(alt + previous_height),
1292 max: Vec2::new(
1293 self.bounds.max.x + 1,
1294 self.bounds.max.y + storey_increase + self.overhang.abs(),
1295 )
1296 .with_z(alt + previous_height + 1),
1297 })),
1298 Dir2::X => painter.prim(Primitive::Aabb(Aabb {
1299 min: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.min.y)
1300 .with_z(alt + previous_height),
1301 max: Vec2::new(
1302 self.bounds.max.x + storey_increase + self.overhang.abs(),
1303 self.bounds.max.y + 1,
1304 )
1305 .with_z(alt + previous_height + 1),
1306 })),
1307 Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
1308 min: Vec2::new(
1309 self.bounds.min.x,
1310 self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1311 )
1312 .with_z(alt + previous_height),
1313 max: Vec2::new(
1314 self.bounds.max.x + 1,
1315 self.bounds.min.y - storey_increase + 1,
1316 )
1317 .with_z(alt + previous_height + 1),
1318 })),
1319 _ => painter.prim(Primitive::Aabb(Aabb {
1320 min: Vec2::new(
1321 self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1322 self.bounds.min.y,
1323 )
1324 .with_z(alt + previous_height),
1325 max: Vec2::new(
1326 self.bounds.min.x - storey_increase + 1,
1327 self.bounds.max.y + 1,
1328 )
1329 .with_z(alt + previous_height + 1),
1330 })),
1331 };
1332 let shed_walls = painter.prim(Primitive::union(shed_left_wall, shed_right_wall));
1333 painter.fill(
1334 painter.prim(Primitive::intersect(shed_walls, shed_empty)),
1335 wall_fill_upper.clone(),
1336 );
1337 painter.fill(
1338 painter.prim(Primitive::intersect(shed_wall_beams, shed_walls)),
1339 pillar_fill.clone(),
1340 );
1341
1342 let range = if self.front.is_y() {
1344 self.tile_aabr.min.x - 3..self.tile_aabr.max.x + 3
1345 } else {
1346 self.tile_aabr.min.y - 3..self.tile_aabr.max.y + 3
1347 };
1348 for n in range {
1349 let temp = match self.front {
1350 Dir2::Y => site.tile_wpos(Vec2::new(n, self.tile_aabr.max.y)) - 4,
1351 Dir2::X => site.tile_wpos(Vec2::new(self.tile_aabr.max.x, n)) - 4,
1352 Dir2::NegY => site.tile_wpos(Vec2::new(n, self.tile_aabr.min.y)) - 4,
1353 _ => site.tile_wpos(Vec2::new(self.tile_aabr.min.x, n)) - 4,
1354 };
1355 let dormer_box = match self.front {
1356 Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
1357 min: Vec2::new(temp.x - 1, self.bounds.max.y + storey_increase + 1)
1358 .with_z(alt + previous_height),
1359 max: Vec2::new(
1360 temp.x + 4,
1361 self.bounds.max.y + storey_increase + self.overhang.abs(),
1362 )
1363 .with_z(alt + height - 1),
1364 })),
1365 Dir2::X => painter.prim(Primitive::Aabb(Aabb {
1366 min: Vec2::new(self.bounds.max.x + storey_increase + 1, temp.y - 1)
1367 .with_z(alt + previous_height),
1368 max: Vec2::new(
1369 self.bounds.max.x + storey_increase + self.overhang.abs(),
1370 temp.y + 4,
1371 )
1372 .with_z(alt + height - 1),
1373 })),
1374 Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
1375 min: Vec2::new(
1376 temp.x - 1,
1377 self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1378 )
1379 .with_z(alt + previous_height),
1380 max: Vec2::new(temp.x + 4, self.bounds.min.y - storey_increase - 1)
1381 .with_z(alt + height - 1),
1382 })),
1383 _ => painter.prim(Primitive::Aabb(Aabb {
1384 min: Vec2::new(
1385 self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1386 temp.y - 1,
1387 )
1388 .with_z(alt + previous_height),
1389 max: Vec2::new(self.bounds.min.x - storey_increase - 1, temp.y + 4)
1390 .with_z(alt + height - 1),
1391 })),
1392 };
1393 let dormer_roof = match self.front {
1394 Dir2::Y => painter.prim(Primitive::Gable {
1395 aabb: Aabb {
1396 min: Vec2::new(temp.x - 1, self.bounds.max.y + storey_increase + 1)
1397 .with_z(alt + height - 2),
1398 max: Vec2::new(
1399 temp.x + 4,
1400 self.bounds.max.y + storey_increase + self.overhang.abs(),
1401 )
1402 .with_z(alt + height + 1),
1403 },
1404 inset: 3,
1405 dir: Dir2::Y,
1406 }),
1407 Dir2::X => painter.prim(Primitive::Gable {
1408 aabb: Aabb {
1409 min: Vec2::new(self.bounds.max.x + storey_increase + 1, temp.y - 1)
1410 .with_z(alt + height - 2),
1411 max: Vec2::new(
1412 self.bounds.max.x + storey_increase + self.overhang.abs(),
1413 temp.y + 4,
1414 )
1415 .with_z(alt + height + 1),
1416 },
1417 inset: 3,
1418 dir: Dir2::X,
1419 }),
1420 Dir2::NegY => painter.prim(Primitive::Gable {
1421 aabb: Aabb {
1422 min: Vec2::new(
1423 temp.x - 1,
1424 self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1425 )
1426 .with_z(alt + height - 2),
1427 max: Vec2::new(temp.x + 4, self.bounds.min.y - storey_increase)
1428 .with_z(alt + height + 1),
1429 },
1430 inset: 3,
1431 dir: Dir2::Y,
1432 }),
1433 _ => painter.prim(Primitive::Gable {
1434 aabb: Aabb {
1435 min: Vec2::new(
1436 self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1437 temp.y - 1,
1438 )
1439 .with_z(alt + height - 2),
1440 max: Vec2::new(self.bounds.min.x - storey_increase, temp.y + 4)
1441 .with_z(alt + height + 1),
1442 },
1443 inset: 3,
1444 dir: Dir2::X,
1445 }),
1446 };
1447 let window_min = match self.front {
1448 Dir2::Y => Vec2::new(
1449 temp.x,
1450 self.bounds.max.y + storey_increase + self.overhang.abs() - 1,
1451 )
1452 .with_z(alt + previous_height + 2),
1453 Dir2::X => Vec2::new(
1454 self.bounds.max.x + storey_increase + self.overhang.abs() - 1,
1455 temp.y,
1456 )
1457 .with_z(alt + previous_height + 2),
1458 Dir2::NegY => Vec2::new(
1459 temp.x,
1460 self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1461 )
1462 .with_z(alt + previous_height + 2),
1463 _ => Vec2::new(
1464 self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1465 temp.y,
1466 )
1467 .with_z(alt + previous_height + 2),
1468 };
1469 let window_max = match self.front {
1470 Dir2::Y => Vec2::new(
1471 temp.x + 3,
1472 self.bounds.max.y + storey_increase + self.overhang.abs(),
1473 )
1474 .with_z(alt + previous_height + 2 + window_height),
1475 Dir2::X => Vec2::new(
1476 self.bounds.max.x + storey_increase + self.overhang.abs(),
1477 temp.y + 3,
1478 )
1479 .with_z(alt + previous_height + 2 + window_height),
1480 Dir2::NegY => Vec2::new(
1481 temp.x + 3,
1482 self.bounds.min.y - storey_increase - self.overhang.abs() + 2,
1483 )
1484 .with_z(alt + previous_height + 2 + window_height),
1485 _ => Vec2::new(
1486 self.bounds.min.x - storey_increase - self.overhang.abs() + 2,
1487 temp.y + 3,
1488 )
1489 .with_z(alt + previous_height + 2 + window_height),
1490 };
1491 let window = painter.prim(Primitive::Aabb(Aabb {
1492 min: window_min,
1493 max: window_max,
1494 }));
1495 let window_cavity = match self.front {
1496 Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
1497 min: Vec2::new(temp.x, self.bounds.max.y + storey_increase)
1498 .with_z(alt + previous_height),
1499 max: Vec2::new(
1500 temp.x + 3,
1501 self.bounds.max.y + storey_increase + self.overhang.abs() - 1,
1502 )
1503 .with_z(alt + previous_height + 2 + window_height),
1504 })),
1505 Dir2::X => painter.prim(Primitive::Aabb(Aabb {
1506 min: Vec2::new(self.bounds.max.x + storey_increase, temp.y)
1507 .with_z(alt + previous_height),
1508 max: Vec2::new(
1509 self.bounds.max.x + storey_increase + self.overhang.abs() - 1,
1510 temp.y + 3,
1511 )
1512 .with_z(alt + previous_height + 2 + window_height),
1513 })),
1514 Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
1515 min: Vec2::new(
1516 temp.x,
1517 self.bounds.min.y - storey_increase - self.overhang.abs() + 2,
1518 )
1519 .with_z(alt + previous_height),
1520 max: Vec2::new(temp.x + 3, self.bounds.min.y - storey_increase + 1)
1521 .with_z(alt + previous_height + 2 + window_height),
1522 })),
1523 _ => painter.prim(Primitive::Aabb(Aabb {
1524 min: Vec2::new(
1525 self.bounds.min.x - storey_increase - self.overhang.abs() + 2,
1526 temp.y,
1527 )
1528 .with_z(alt + previous_height),
1529 max: Vec2::new(self.bounds.min.x - storey_increase + 1, temp.y + 3)
1530 .with_z(alt + previous_height + 2 + window_height),
1531 })),
1532 };
1533 let valid_dormer = if self.front.is_y() {
1534 window_min.x > self.bounds.min.x && window_max.x < self.bounds.max.x
1535 } else {
1536 window_min.y > self.bounds.min.y && window_max.y < self.bounds.max.y
1537 };
1538 let window_ori = if self.front.is_y() { 0 } else { 2 };
1539 if valid_dormer {
1540 painter.fill(
1541 painter.prim(Primitive::without(dormer_box, shed)),
1542 wall_fill_upper.clone(),
1543 );
1544 painter.fill(
1545 painter.prim(Primitive::without(dormer_roof, shed)),
1546 Fill::Brick(BlockKind::Wood, self.roof_color, 24),
1547 );
1548 painter.fill(window_cavity, Fill::Block(Block::empty()));
1549 painter.fill(
1550 window,
1551 Fill::Block(
1552 Block::air(SpriteKind::Window1)
1553 .with_ori(window_ori)
1554 .unwrap(),
1555 ),
1556 );
1557 }
1558 }
1559 }
1560
1561 if i > 1 {
1564 let floor = if self.overhang < -1 && i > 1 {
1565 match self.front {
1566 Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
1567 min: (self.bounds.min + 1).with_z(alt + previous_height),
1568 max: Vec2::new(
1569 self.bounds.max.x,
1570 self.bounds.max.y + storey_increase + self.overhang.abs(),
1571 )
1572 .with_z(alt + previous_height + 1),
1573 })),
1574 Dir2::X => painter.prim(Primitive::Aabb(Aabb {
1575 min: Vec2::new(self.bounds.min.x + 1, self.bounds.min.y + 1)
1576 .with_z(alt + previous_height),
1577 max: Vec2::new(
1578 self.bounds.max.x + storey_increase + self.overhang.abs(),
1579 self.bounds.max.y,
1580 )
1581 .with_z(alt + previous_height + 1),
1582 })),
1583 Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
1584 min: Vec2::new(
1585 self.bounds.min.x + 1,
1586 self.bounds.min.y + 1 - storey_increase - self.overhang.abs(),
1587 )
1588 .with_z(alt + previous_height),
1589 max: Vec2::new(self.bounds.max.x, self.bounds.max.y)
1590 .with_z(alt + previous_height + 1),
1591 })),
1592 _ => painter.prim(Primitive::Aabb(Aabb {
1593 min: Vec2::new(
1594 self.bounds.min.x + 1 - storey_increase - self.overhang.abs(),
1595 self.bounds.min.y + 1,
1596 )
1597 .with_z(alt + previous_height),
1598 max: Vec2::new(self.bounds.max.x, self.bounds.max.y)
1599 .with_z(alt + previous_height + 1),
1600 })),
1601 }
1602 } else {
1603 match self.front {
1604 Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
1605 min: (self.bounds.min + 1).with_z(alt + previous_height),
1606 max: (Vec2::new(
1607 self.bounds.max.x,
1608 self.bounds.max.y + storey_increase,
1609 ))
1610 .with_z(alt + previous_height + 1),
1611 })),
1612 Dir2::X => painter.prim(Primitive::Aabb(Aabb {
1613 min: (self.bounds.min + 1).with_z(alt + previous_height),
1614 max: (Vec2::new(
1615 self.bounds.max.x + storey_increase,
1616 self.bounds.max.y,
1617 ))
1618 .with_z(alt + previous_height + 1),
1619 })),
1620 Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
1621 min: Vec2::new(
1622 self.bounds.min.x + 1,
1623 self.bounds.min.y + 1 - storey_increase,
1624 )
1625 .with_z(alt + previous_height),
1626 max: (Vec2::new(self.bounds.max.x, self.bounds.max.y))
1627 .with_z(alt + previous_height + 1),
1628 })),
1629 _ => painter.prim(Primitive::Aabb(Aabb {
1630 min: Vec2::new(
1631 self.bounds.min.x + 1 - storey_increase,
1632 self.bounds.min.y + 1,
1633 )
1634 .with_z(alt + previous_height),
1635 max: (Vec2::new(self.bounds.max.x, self.bounds.max.y))
1636 .with_z(alt + previous_height + 1),
1637 })),
1638 }
1639 };
1640 painter.fill(
1641 floor,
1642 Fill::Block(Block::new(BlockKind::Rock, Rgb::new(89, 44, 14))),
1643 );
1644 }
1645
1646 let base = alt + (storey * (i as i32 - 1)).max(0);
1648 if i % 2 == 0 {
1649 let bed_pos = match self.front {
1651 Dir2::X => Vec2::new(half_x, quarter_y),
1652 Dir2::NegY => Vec2::new(three_quarter_x, half_y),
1653 _ => Vec2::new(half_x, half_y),
1654 };
1655 let bed_dir = self.front;
1656 let bed_aabr = painter.bed_wood_woodland(bed_pos.with_z(base), bed_dir);
1657 let nightstand_pos = bed_dir
1658 .opposite()
1659 .select_aabr_with(bed_aabr, bed_dir.rotated_ccw().select_aabr(bed_aabr))
1660 .with_z(base)
1661 + bed_dir.rotated_ccw().to_vec2();
1662 painter.sprite(nightstand_pos.with_z(base), SpriteKind::DrawerWoodWoodlandS);
1664 let rng0 = RandomField::new(0).get(nightstand_pos.with_z(base + 1));
1666 let rng1 = RandomField::new(1).get(nightstand_pos.with_z(base + 1));
1667 painter.owned_resource_sprite(
1668 nightstand_pos.with_z(base + 1),
1669 match rng0 % 5 {
1670 0 => SpriteKind::Lantern,
1671 1 => SpriteKind::PotionMinor,
1672 2 => SpriteKind::VialEmpty,
1673 3 => SpriteKind::Bowl,
1674 _ => SpriteKind::Empty,
1675 },
1676 (rng1 % 4) as u8 * 2,
1677 );
1678 let wardrobe_dir = self.front.rotated_cw();
1680 let bounds = Aabr {
1681 min: Vec2::new(self.bounds.min.x + 1, self.bounds.min.y + 1),
1682 max: Vec2::new(self.bounds.max.x - 2, self.bounds.max.y - 1),
1683 };
1684 let wardrobe_pos = wardrobe_dir
1685 .opposite()
1686 .select_aabr_with(
1687 bounds,
1688 bounds.center()
1689 + wardrobe_dir.vec2(bounds.half_size().w, bounds.half_size().h) / 2,
1690 )
1691 .with_z(base);
1692
1693 let sprite = if RandomField::new(0).chance(wardrobe_pos, 0.5) {
1694 SpriteKind::WardrobedoubleWoodWoodland
1695 } else {
1696 SpriteKind::WardrobedoubleWoodWoodland2
1697 };
1698 painter.mirrored2(wardrobe_pos, wardrobe_dir, sprite);
1699 } else {
1700 for dir in DIRS {
1702 let sprite_pos = self.bounds.center() + dir * 5;
1704 let rng0 = RandomField::new(0).get(sprite_pos.with_z(base));
1705 let rng1 = RandomField::new(1).get(sprite_pos.with_z(base));
1706 painter.owned_resource_sprite(
1707 sprite_pos.with_z(base),
1708 match rng0 % 32 {
1709 0..=2 => SpriteKind::Crate,
1710 3..=4 => SpriteKind::CoatrackWoodWoodland,
1711 5..=7 => SpriteKind::FlowerpotWoodWoodlandS,
1712 8..=9 => SpriteKind::Lantern,
1713 _ => SpriteKind::Empty,
1714 },
1715 (rng1 % 4) as u8 * 2,
1716 );
1717 }
1718
1719 if self.bounds.max.x - self.bounds.min.x < 16
1720 || self.bounds.max.y - self.bounds.min.y < 16
1721 {
1722 let table_pos = Vec2::new(half_x, half_y);
1723 painter.sprite(
1725 table_pos.with_z(base),
1726 SpriteKind::DiningtableWoodWoodlandRound,
1727 );
1728 for dir in Dir2::iter() {
1729 let chair_pos = table_pos + dir.to_vec2();
1730 painter.rotated_sprite(
1731 chair_pos.with_z(base),
1732 SpriteKind::ChairWoodWoodland,
1733 dir.opposite().sprite_ori(),
1734 );
1735 }
1736 } else {
1737 let table_pos = match self.front {
1739 Dir2::Y => Vec2::new(half_x, three_quarter_y),
1740 Dir2::X => Vec2::new(half_x, half_y),
1741 _ => Vec2::new(quarter_x, half_y),
1742 }
1743 .with_z(base);
1744 let table_axis = if RandomField::new(0).chance(table_pos, 0.5) {
1745 Dir2::X
1746 } else {
1747 Dir2::Y
1748 };
1749 let table_bounds = painter.table_wood_fancy_woodland(table_pos, table_axis);
1750 painter.chairs_around(SpriteKind::ChairWoodWoodland, 1, table_bounds, base);
1751 }
1752 let (drawer_pos, drawer_ori) = match self.front {
1754 Dir2::Y => (Vec2::new(self.bounds.max.x - 1, self.bounds.max.y - 2), 6),
1755 Dir2::X => (Vec2::new(self.bounds.max.x - 2, self.bounds.max.y - 1), 0),
1756 Dir2::NegY => (Vec2::new(self.bounds.max.x - 1, self.bounds.min.y + 2), 6),
1757 _ => (Vec2::new(self.bounds.min.x + 2, self.bounds.max.y - 1), 0),
1758 };
1759 painter.rotated_sprite(
1760 drawer_pos.with_z(base),
1761 SpriteKind::DrawerWoodWoodlandL1,
1762 drawer_ori,
1763 );
1764 }
1765
1766 if i > 1 {
1768 let stair_width = 3;
1769 let previous_floor_height = (storey * (i as i32 - 2)).max(0);
1770 let stair_origin = match self.front {
1771 Dir2::Y => self.bounds.min + 1,
1772 Dir2::X => self.bounds.min + 1,
1773 Dir2::NegY => {
1774 Vec2::new(self.bounds.max.x - 12, self.bounds.max.y - stair_width * 2)
1775 },
1776 _ => Vec2::new(self.bounds.max.x - 12, self.bounds.min.y + 1),
1777 };
1778 let staircase = if i < 2 {
1779 painter.prim(Primitive::Empty)
1780 } else if i % 2 == 0 {
1781 let ramp = {
1782 painter.prim(Primitive::Ramp {
1784 aabb: Aabb {
1785 min: Vec2::new(stair_origin.x + 3, stair_origin.y).with_z(alt + previous_floor_height),
1786 max: Vec2::new(stair_origin.x + 10, stair_origin.y + stair_width).with_z(alt + previous_height + 1),
1787 },
1788 inset: storey,
1789 dir: Dir2::X,
1790 })
1791 };
1823 let support = {
1824 painter.prim(Primitive::Aabb(Aabb {
1827 min: Vec2::new(stair_origin.x + 10, stair_origin.y)
1828 .with_z(alt + previous_floor_height),
1829 max: Vec2::new(stair_origin.x + 12, stair_origin.y + stair_width)
1830 .with_z(alt + previous_height + 1),
1831 }))
1832 };
1858 painter.prim(Primitive::union(ramp, support))
1859 } else {
1860 let ramp = {
1861 painter.prim(Primitive::Ramp {
1863 aabb: Aabb {
1864 min: Vec2::new(stair_origin.x + 1, stair_origin.y + stair_width).with_z(alt + previous_floor_height),
1865 max: Vec2::new(stair_origin.x + 8, stair_origin.y + 2 * stair_width).with_z(alt + previous_height + 1),
1866 },
1867 inset: storey,
1868 dir: Dir2::NegX,
1869 })
1870 };
1903 let support = {
1904 painter.prim(Primitive::Aabb(Aabb {
1907 min: Vec2::new(stair_origin.x, stair_origin.y + stair_width)
1908 .with_z(alt + previous_floor_height),
1909 max: Vec2::new(stair_origin.x + 2, stair_origin.y + 2 * stair_width)
1910 .with_z(alt + previous_height + 1),
1911 }))
1912 };
1938 painter.prim(Primitive::union(ramp, support))
1939 };
1940 let stairwell = if i < 2 {
1941 painter.prim(Primitive::Empty)
1942 } else if i % 2 == 0 {
1943 painter.prim(Primitive::Aabb(Aabb {
1944 min: Vec2::new(stair_origin.x + 2, stair_origin.y)
1945 .with_z(alt + previous_floor_height + 1),
1946 max: Vec2::new(stair_origin.x + 9, stair_origin.y + stair_width)
1947 .with_z(alt + previous_height + 1),
1948 }))
1949 } else {
1984 painter.prim(Primitive::Aabb(Aabb {
1985 min: Vec2::new(stair_origin.x + 2, stair_origin.y + stair_width)
1986 .with_z(alt + previous_floor_height + 1),
1987 max: Vec2::new(stair_origin.x + 11, stair_origin.y + 2 * stair_width)
1988 .with_z(alt + previous_height + 1),
1989 }))
1990 };
2029
2030 painter.fill(stairwell, Fill::Block(Block::empty()));
2031 painter.fill(
2032 staircase,
2033 Fill::Block(Block::new(BlockKind::Rock, Rgb::new(89, 44, 14))),
2034 );
2035 }
2036 }
2037
2038 painter.fill(
2040 painter.prim(Primitive::Aabb(Aabb {
2041 min: (self.bounds.min - 1).with_z(self.alt - foundations),
2042 max: (self.bounds.max + 2).with_z(self.alt + 1),
2043 })),
2044 Fill::Block(Block::new(BlockKind::Rock, Rgb::new(31, 33, 32))),
2045 );
2046
2047 let fireplace_origin = {
2064 match self.front {
2065 Dir2::Y => {
2066 Vec2::new(half_x, self.bounds.min.y + 1)
2067 },
2068 Dir2::X => {
2069 Vec2::new(self.bounds.min.x + 1, half_y)
2070 },
2071 Dir2::NegY => {
2072 Vec2::new(half_x - 4, self.bounds.max.y - 3)
2073 },
2074 _ => {
2075 Vec2::new(self.bounds.max.x - 3, half_y)
2076 },
2077 }
2078 };
2079 let chimney = match self.front {
2080 Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
2081 min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
2082 max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 3)
2083 .with_z(alt + roof + roof_height + 2),
2084 })),
2085 Dir2::X => painter.prim(Primitive::Aabb(Aabb {
2086 min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
2087 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 4)
2088 .with_z(alt + roof + roof_height + 2),
2089 })),
2090 Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
2091 min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
2092 max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 3)
2093 .with_z(alt + roof + roof_height + 2),
2094 })),
2095 _ => painter.prim(Primitive::Aabb(Aabb {
2096 min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
2097 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 4)
2098 .with_z(alt + roof + roof_height + 2),
2099 })),
2100 };
2101
2102 let chimney_cavity = match self.front {
2103 Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
2104 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2105 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2)
2106 .with_z(alt + roof + roof_height + 2),
2107 })),
2108 Dir2::X => painter.prim(Primitive::Aabb(Aabb {
2109 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2110 max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3)
2111 .with_z(alt + roof + roof_height + 2),
2112 })),
2113 Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
2114 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2115 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2)
2116 .with_z(alt + roof + roof_height + 2),
2117 })),
2118 _ => painter.prim(Primitive::Aabb(Aabb {
2119 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2120 max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3)
2121 .with_z(alt + roof + roof_height + 2),
2122 })),
2123 };
2124 let fire_embers = match self.front {
2125 Dir2::Y => Aabb {
2126 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2127 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2).with_z(alt + 1),
2128 },
2129 Dir2::X => Aabb {
2130 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2131 max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 1),
2132 },
2133 Dir2::NegY => Aabb {
2134 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2135 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2).with_z(alt + 1),
2136 },
2137 _ => Aabb {
2138 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2139 max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 1),
2140 },
2141 };
2142 let fireplace_cavity = match self.front {
2143 Dir2::Y => Aabb {
2144 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2145 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 3).with_z(alt + 2),
2146 },
2147 Dir2::X => Aabb {
2148 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2149 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 3).with_z(alt + 2),
2150 },
2151 Dir2::NegY => Aabb {
2152 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y).with_z(alt),
2153 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2).with_z(alt + 2),
2154 },
2155 _ => Aabb {
2156 min: Vec2::new(fireplace_origin.x, fireplace_origin.y + 1).with_z(alt),
2157 max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 2),
2158 },
2159 };
2160
2161 painter.fill(
2162 chimney,
2163 Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 24),
2164 );
2165 painter.fill(chimney_cavity, Fill::Block(Block::empty()));
2166 painter.fill(
2167 painter.prim(Primitive::Aabb(fireplace_cavity)),
2168 Fill::Block(Block::empty()),
2169 );
2170 painter.fill(
2171 painter.prim(Primitive::Aabb(fire_embers)),
2172 Fill::Block(Block::air(SpriteKind::Ember)),
2173 );
2174
2175 if self.levels == 1 {
2177 let bed_pos = if self.bounds.max.x - self.bounds.min.x < 16
2179 || self.bounds.max.y - self.bounds.min.y < 16
2180 {
2181 match self.front {
2182 Dir2::Y => Vec2::new(self.bounds.min.x + 4, self.bounds.min.y + 2),
2183 Dir2::X => Vec2::new(self.bounds.min.x + 2, self.bounds.min.y + 4),
2184 Dir2::NegY => Vec2::new(self.bounds.max.x - 4, self.bounds.max.y - 2),
2185 _ => Vec2::new(self.bounds.max.x - 8, self.bounds.max.y - 2),
2186 }
2187 } else {
2188 match self.front {
2189 Dir2::Y => Vec2::new(self.bounds.max.x - 4, self.bounds.min.y + 2),
2190 Dir2::X => Vec2::new(self.bounds.min.x + 8, self.bounds.max.y - 2),
2191 Dir2::NegY => Vec2::new(self.bounds.max.x - 4, self.bounds.max.y - 2),
2192 _ => Vec2::new(self.bounds.max.x - 8, self.bounds.max.y - 2),
2193 }
2194 };
2195 let bed_dir = self.front.abs();
2196
2197 painter.bed_wood_woodland(bed_pos.with_z(alt), bed_dir);
2198 }
2199
2200 if self.christmas_decorations {
2201 let (wreath_pos, wreath_ori) = match self.front {
2202 Dir2::Y => (
2203 Aabb {
2204 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 3)
2205 .with_z(alt + 2),
2206 max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 4)
2207 .with_z(alt + 3),
2208 },
2209 4,
2210 ),
2211 Dir2::X => (
2212 Aabb {
2213 min: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 1)
2214 .with_z(alt + 2),
2215 max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 2)
2216 .with_z(alt + 3),
2217 },
2218 2,
2219 ),
2220 Dir2::NegY => (
2221 Aabb {
2222 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y - 1)
2223 .with_z(alt + 2),
2224 max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y).with_z(alt + 3),
2225 },
2226 0,
2227 ),
2228 _ => (
2229 Aabb {
2230 min: Vec2::new(fireplace_origin.x - 1, fireplace_origin.y + 1)
2231 .with_z(alt + 2),
2232 max: Vec2::new(fireplace_origin.x, fireplace_origin.y + 2).with_z(alt + 3),
2233 },
2234 6,
2235 ),
2236 };
2237 painter.fill(
2238 painter.prim(Primitive::Aabb(wreath_pos)),
2239 Fill::Block(
2240 Block::air(SpriteKind::ChristmasWreath)
2241 .with_ori(wreath_ori)
2242 .unwrap(),
2243 ),
2244 );
2245 }
2246
2247 let doorway1 = match self.front {
2250 Dir2::Y => Aabb {
2251 min: Vec2::new(door_tile_wpos.x - 1, self.bounds.max.y).with_z(alt),
2252 max: Vec2::new(door_tile_wpos.x + 3, self.bounds.max.y + 1).with_z(alt + 4),
2253 },
2254 Dir2::X => Aabb {
2255 min: Vec2::new(self.bounds.max.x, door_tile_wpos.y - 1).with_z(alt),
2256 max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 3).with_z(alt + 4),
2257 },
2258 Dir2::NegY => Aabb {
2259 min: Vec2::new(door_tile_wpos.x - 1, self.bounds.min.y).with_z(alt),
2260 max: Vec2::new(door_tile_wpos.x + 3, self.bounds.min.y + 1).with_z(alt + 4),
2261 },
2262 _ => Aabb {
2263 min: Vec2::new(self.bounds.min.x, door_tile_wpos.y - 1).with_z(alt),
2264 max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 3).with_z(alt + 4),
2265 },
2266 };
2267 painter.fill(painter.prim(Primitive::Aabb(doorway1)), wall_fill_lower);
2268
2269 let doorway2 = match self.front {
2271 Dir2::Y => Aabb {
2272 min: Vec2::new(door_tile_wpos.x, self.bounds.max.y).with_z(alt),
2273 max: Vec2::new(door_tile_wpos.x + 2, self.bounds.max.y + 1).with_z(alt + 3),
2274 },
2275 Dir2::X => Aabb {
2276 min: Vec2::new(self.bounds.max.x, door_tile_wpos.y).with_z(alt),
2277 max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 2).with_z(alt + 3),
2278 },
2279 Dir2::NegY => Aabb {
2280 min: Vec2::new(door_tile_wpos.x, self.bounds.min.y).with_z(alt),
2281 max: Vec2::new(door_tile_wpos.x + 2, self.bounds.min.y + 1).with_z(alt + 3),
2282 },
2283 _ => Aabb {
2284 min: Vec2::new(self.bounds.min.x, door_tile_wpos.y).with_z(alt),
2285 max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 2).with_z(alt + 3),
2286 },
2287 };
2288 painter.fill(
2289 painter.prim(Primitive::Aabb(doorway2)),
2290 Fill::Block(Block::empty()),
2291 );
2292
2293 let (door_gap, door1, door1_ori, door2, door2_ori) = match self.front {
2295 Dir2::Y => (
2296 Aabb {
2297 min: Vec2::new(door_tile_wpos.x - 1, self.bounds.max.y + 1).with_z(alt),
2298 max: Vec2::new(door_tile_wpos.x + 3, self.bounds.max.y + 4).with_z(alt + 3),
2299 },
2300 Aabb {
2301 min: Vec2::new(door_tile_wpos.x, self.bounds.max.y).with_z(alt),
2302 max: Vec2::new(door_tile_wpos.x + 1, self.bounds.max.y + 1).with_z(alt + 1),
2303 },
2304 0,
2305 Aabb {
2306 min: Vec2::new(door_tile_wpos.x + 1, self.bounds.max.y).with_z(alt),
2307 max: Vec2::new(door_tile_wpos.x + 2, self.bounds.max.y + 1).with_z(alt + 1),
2308 },
2309 4,
2310 ),
2311 Dir2::X => (
2312 Aabb {
2313 min: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y - 1).with_z(alt),
2314 max: Vec2::new(self.bounds.max.x + 4, door_tile_wpos.y + 3).with_z(alt + 3),
2315 },
2316 Aabb {
2317 min: Vec2::new(self.bounds.max.x, door_tile_wpos.y).with_z(alt),
2318 max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 1).with_z(alt + 1),
2319 },
2320 2,
2321 Aabb {
2322 min: Vec2::new(self.bounds.max.x, door_tile_wpos.y + 1).with_z(alt),
2323 max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 2).with_z(alt + 1),
2324 },
2325 6,
2326 ),
2327 Dir2::NegY => (
2328 Aabb {
2329 min: Vec2::new(door_tile_wpos.x - 1, self.bounds.min.y - 4).with_z(alt),
2330 max: Vec2::new(door_tile_wpos.x + 3, self.bounds.min.y).with_z(alt + 3),
2331 },
2332 Aabb {
2333 min: Vec2::new(door_tile_wpos.x, self.bounds.min.y).with_z(alt),
2334 max: Vec2::new(door_tile_wpos.x + 1, self.bounds.min.y + 1).with_z(alt + 1),
2335 },
2336 0,
2337 Aabb {
2338 min: Vec2::new(door_tile_wpos.x + 1, self.bounds.min.y).with_z(alt),
2339 max: Vec2::new(door_tile_wpos.x + 2, self.bounds.min.y + 1).with_z(alt + 1),
2340 },
2341 4,
2342 ),
2343 _ => (
2344 Aabb {
2345 min: Vec2::new(self.bounds.min.x - 4, door_tile_wpos.y - 1).with_z(alt),
2346 max: Vec2::new(self.bounds.min.x, door_tile_wpos.y + 3).with_z(alt + 3),
2347 },
2348 Aabb {
2349 min: Vec2::new(self.bounds.min.x, door_tile_wpos.y).with_z(alt),
2350 max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 1).with_z(alt + 1),
2351 },
2352 2,
2353 Aabb {
2354 min: Vec2::new(self.bounds.min.x, door_tile_wpos.y + 1).with_z(alt),
2355 max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 2).with_z(alt + 1),
2356 },
2357 6,
2358 ),
2359 };
2360 painter.fill(
2361 painter.prim(Primitive::Aabb(door_gap)),
2362 Fill::Block(Block::air(SpriteKind::Empty)),
2363 );
2364 painter.fill(
2365 painter.prim(Primitive::Aabb(door1)),
2366 Fill::Block(Block::air(SpriteKind::Door).with_ori(door1_ori).unwrap()),
2367 );
2368 painter.fill(
2369 painter.prim(Primitive::Aabb(door2)),
2370 Fill::Block(Block::air(SpriteKind::Door).with_ori(door2_ori).unwrap()),
2371 );
2372 if self.christmas_decorations {
2373 let rng = RandomField::new(0).get(door_tile_wpos.with_z(alt + 3));
2375 let right = (rng % 2) as i32;
2376 let (door_light_pos, door_light_ori) = match self.front {
2377 Dir2::Y => (
2378 Aabb {
2379 min: Vec2::new(door_tile_wpos.x + right, self.bounds.max.y + 1)
2380 .with_z(alt + 3),
2381 max: Vec2::new(door_tile_wpos.x + 1 + right, self.bounds.max.y + 2)
2382 .with_z(alt + 4),
2383 },
2384 4,
2385 ),
2386 Dir2::X => (
2387 Aabb {
2388 min: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + right)
2389 .with_z(alt + 3),
2390 max: Vec2::new(self.bounds.max.x + 2, door_tile_wpos.y + 1 + right)
2391 .with_z(alt + 4),
2392 },
2393 2,
2394 ),
2395 Dir2::NegY => (
2396 Aabb {
2397 min: Vec2::new(door_tile_wpos.x + right, self.bounds.min.y - 1)
2398 .with_z(alt + 3),
2399 max: Vec2::new(door_tile_wpos.x + 1 + right, self.bounds.min.y)
2400 .with_z(alt + 4),
2401 },
2402 0,
2403 ),
2404 _ => (
2405 Aabb {
2406 min: Vec2::new(self.bounds.min.x - 1, door_tile_wpos.y + right)
2407 .with_z(alt + 3),
2408 max: Vec2::new(self.bounds.min.x, door_tile_wpos.y + 1 + right)
2409 .with_z(alt + 4),
2410 },
2411 6,
2412 ),
2413 };
2414 painter.fill(
2415 painter.prim(Primitive::Aabb(door_light_pos)),
2416 Fill::Block(
2417 Block::air(SpriteKind::ChristmasOrnament)
2418 .with_ori(door_light_ori)
2419 .unwrap(),
2420 ),
2421 );
2422 }
2423 }
2424}