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