veloren_world/site2/plot/
vampire_castle.rs

1use super::*;
2use crate::{
3    Land,
4    site2::gen::wall_staircase,
5    util::{CARDINALS, DIAGONALS, NEIGHBORS, RandomField, sampler::Sampler},
6};
7use common::{generation::EntityInfo, terrain::SpriteKind};
8use rand::prelude::*;
9use std::{f32::consts::TAU, sync::Arc};
10use vek::*;
11
12pub struct CastleData {
13    plot_base: i32,
14    center: Vec2<i32>,
15    side_bldg_pos_1: Vec2<i32>,
16    side_bldg_pos_2: Vec2<i32>,
17    side_bldg_positions: Vec<Vec2<i32>>,
18    tower_positions: Vec<Vec2<i32>>,
19}
20
21pub struct VampireCastle {
22    bounds: Aabr<i32>,
23    pub(crate) alt: i32,
24    pub(crate) castle_data: CastleData,
25}
26impl VampireCastle {
27    pub fn generate(land: &Land, _rng: &mut impl Rng, site: &Site, tile_aabr: Aabr<i32>) -> Self {
28        let bounds = Aabr {
29            min: site.tile_wpos(tile_aabr.min),
30            max: site.tile_wpos(tile_aabr.max),
31        };
32        let center = bounds.center();
33        let plot_base = land.get_alt_approx(center) as i32;
34        let castle_length = 24;
35        let castle_width = 18;
36        let tower_base = plot_base + 1;
37        let mut tower_positions = vec![];
38        let mut side_bldg_positions = vec![];
39        let towers = 12.0;
40        let tower_radius_raw = 105;
41        let tower_phi = TAU / towers;
42        let side_bldg_var = (RandomField::new(0).get(center.with_z(plot_base)) % 2) as i32;
43        let side_bldg_pos_1 = Vec2::new(
44            center.x,
45            center.y - (2 * (castle_length + 4)) + side_bldg_var * (4 * (castle_length + 4)),
46        );
47        let side_bldg_pos_2 = Vec2::new(
48            center.x,
49            center.y + (2 * (castle_length + 4)) - side_bldg_var * (4 * (castle_length + 4)),
50        );
51        side_bldg_positions.push(side_bldg_pos_1);
52        side_bldg_positions.push(side_bldg_pos_2);
53
54        // castle towers
55        for dir in DIAGONALS {
56            let tower_pos = Vec2::new(
57                center.x + dir.x * (castle_length + 10),
58                center.y + dir.y * (castle_width + 10),
59            );
60            tower_positions.push(tower_pos);
61        }
62        // outer towers
63        for n in 1..=towers as i32 {
64            let tower_pos_var = RandomField::new(0).get((center + n).with_z(tower_base)) % 10;
65            let tower_radius = tower_radius_raw + tower_pos_var as i32;
66            let tower_pos = Vec2::new(
67                center.x + (tower_radius as f32 * ((n as f32 * tower_phi).cos())) as i32,
68                center.y + (tower_radius as f32 * ((n as f32 * tower_phi).sin())) as i32,
69            );
70
71            if RandomField::new(0).get((center + n).with_z(tower_base)) % 8 < 3 {
72                tower_positions.push(tower_pos)
73            } else {
74                side_bldg_positions.push(tower_pos);
75            }
76        }
77        let castle_data = CastleData {
78            plot_base,
79            center,
80            side_bldg_pos_1,
81            side_bldg_pos_2,
82            side_bldg_positions,
83            tower_positions,
84        };
85
86        Self {
87            bounds,
88            alt: land.get_alt_approx(site.tile_center_wpos((tile_aabr.max - tile_aabr.min) / 2))
89                as i32,
90            castle_data,
91        }
92    }
93
94    pub fn spawn_rules(&self, wpos: Vec2<i32>) -> SpawnRules {
95        SpawnRules {
96            waypoints: false,
97            trees: wpos.distance_squared(self.bounds.center()) > (75_i32).pow(2),
98            ..SpawnRules::default()
99        }
100    }
101}
102
103impl Structure for VampireCastle {
104    #[cfg(feature = "use-dyn-lib")]
105    const UPDATE_FN: &'static [u8] = b"render_vampire_castle\0";
106
107    #[cfg_attr(feature = "be-dyn-lib", export_name = "render_vampire_castle")]
108    fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
109        let mut thread_rng = thread_rng();
110        let brick = Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 24);
111        let roof_color = Fill::Block(Block::new(BlockKind::GlowingRock, Rgb::new(30, 37, 55)));
112        let wood = Fill::Brick(BlockKind::Rock, Rgb::new(71, 33, 11), 12);
113        let chain = Fill::Block(Block::air(SpriteKind::MetalChain));
114        let window_ver = Fill::Block(Block::air(SpriteKind::WitchWindow));
115        let window_ver2 = Fill::Block(Block::air(SpriteKind::WitchWindow));
116        let key_door = Fill::Block(Block::air(SpriteKind::VampireKeyDoor));
117        let key_hole = Fill::Block(Block::air(SpriteKind::VampireKeyhole));
118        let onewaydoor = Fill::Block(Block::air(SpriteKind::OneWayWall).with_ori(2).unwrap());
119        let candles = Fill::Sampling(Arc::new(|wpos| {
120            Some(match (RandomField::new(0).get(wpos)) % 4 {
121                0 => Block::new(BlockKind::Air, Rgb::new(0, 0, 0)),
122                _ => Block::air(SpriteKind::Candle),
123            })
124        }));
125        let candles_lite = Fill::Sampling(Arc::new(|wpos| {
126            Some(match (RandomField::new(0).get(wpos)) % 30 {
127                0 => Block::air(SpriteKind::Candle),
128                _ => Block::new(BlockKind::Air, Rgb::new(0, 0, 0)),
129            })
130        }));
131        // castle
132        let center = self.castle_data.center;
133        let plot_base = self.castle_data.plot_base;
134        let side_bldg_pos_1 = self.castle_data.side_bldg_pos_1;
135        let side_bldg_pos_2 = self.castle_data.side_bldg_pos_2;
136        let side_bldg_positions = &self.castle_data.side_bldg_positions;
137        let tower_positions = &self.castle_data.tower_positions;
138
139        let castle_base = plot_base + 1;
140        let castle_length = 24;
141        let castle_width = 18;
142        let castle_height = castle_length;
143        // entry
144        let entry_length = 12;
145        let entry_width = 9;
146        let entry_height = entry_length;
147        let entry_base = castle_base - 2;
148        // towers
149        let tower_base = plot_base + 1;
150        let tower_width = 16;
151        let tower_height_raw = 70;
152        let roof_width = tower_width + 2;
153        let roof_height = 3 * (tower_width / 2);
154        let top_height = 20;
155        // side buildings
156        let side_bldg_length = 12;
157        let side_bldg_width = 9;
158        let side_bldg_height = 12;
159        let side_bldg_roof_height_raw = 32;
160        let side_bldg_base_raw = castle_base;
161        let side_bldg_var = (RandomField::new(0).get(center.with_z(plot_base)) % 2) as i32;
162        let side_bldg_stairs_pos = side_bldg_pos_1;
163        let mut bat_positions = vec![];
164        let mut harlequin_positions = vec![];
165        let mut random_npc_positions = vec![];
166        // castle main entry
167        let entry_pos = Vec2::new(center.x - castle_length - 20, center.y);
168        let entry_pillar_pos = Vec2::new(center.x - castle_length - 24, center.y);
169        painter
170            .aabb(Aabb {
171                min: Vec2::new(
172                    entry_pos.x - entry_length - 10,
173                    entry_pos.y - entry_width - 10,
174                )
175                .with_z(entry_base + (entry_height / 2) + (2 * entry_height)),
176                max: Vec2::new(
177                    entry_pos.x + entry_length + 10,
178                    entry_pos.y + entry_width + 10,
179                )
180                .with_z(entry_base + (entry_height / 2) + (3 * entry_height)),
181            })
182            .fill(brick.clone());
183        painter
184            .aabb(Aabb {
185                min: Vec2::new(
186                    entry_pos.x - entry_length - 9,
187                    entry_pos.y - entry_width - 9,
188                )
189                .with_z(entry_base + (entry_height / 2) + (2 * entry_height)),
190                max: Vec2::new(
191                    entry_pos.x + entry_length + 9,
192                    entry_pos.y + entry_width + 9,
193                )
194                .with_z(entry_base + (entry_height / 2) + (3 * entry_height)),
195            })
196            .fill(roof_color.clone());
197        painter
198            .aabb(Aabb {
199                min: Vec2::new(
200                    entry_pos.x - entry_length - 5,
201                    entry_pos.y - entry_width - 5,
202                )
203                .with_z(entry_base + (entry_height / 2) + (2 * entry_height) - 3),
204                max: Vec2::new(
205                    entry_pos.x + entry_length + 5,
206                    entry_pos.y + entry_width + 5,
207                )
208                .with_z(entry_base + (entry_height / 2) + (2 * entry_height)),
209            })
210            .fill(brick.clone());
211        // entry decor
212        let entry_decor_limiter = painter.aabb(Aabb {
213            min: Vec2::new(
214                entry_pos.x - entry_length - 9,
215                entry_pos.y - entry_width - 9,
216            )
217            .with_z(entry_base + (entry_height / 2) + (2 * entry_height) - 1),
218            max: Vec2::new(
219                entry_pos.x + entry_length + 9,
220                entry_pos.y + entry_width + 9,
221            )
222            .with_z(entry_base + (entry_height / 2) + (2 * entry_height)),
223        });
224        let entry_decor_var = RandomField::new(0).get(center.with_z(tower_base)) % 12;
225        let entry_decors = 12.0 + entry_decor_var as f32;
226        let entry_phi = TAU / entry_decors;
227        let entry_decor_radius = entry_length + 10;
228        for d in 1..=entry_decors as i32 {
229            let entry_decors_pos = Vec2::new(
230                entry_pos.x + (entry_decor_radius as f32 * ((d as f32 * entry_phi).cos())) as i32,
231                entry_pos.y + (entry_decor_radius as f32 * ((d as f32 * entry_phi).sin())) as i32,
232            );
233            painter
234                .line(
235                    entry_pos.with_z(entry_base + (entry_height / 2) + (2 * entry_height) - 1),
236                    entry_decors_pos
237                        .with_z(entry_base + (entry_height / 2) + (2 * entry_height) - 1),
238                    1.0,
239                )
240                .intersect(entry_decor_limiter)
241                .fill(brick.clone());
242        }
243        // entry roof carve
244        for c in 0..2 {
245            let w_carve_pos = Vec2::new(
246                entry_pos.x,
247                entry_pos.y - (2 * entry_width) + (c * (4 * entry_width)),
248            );
249            let l_carve_pos = Vec2::new(
250                entry_pos.x - (4 * (entry_length / 2)) + (c * (8 * (entry_length / 2))),
251                entry_pos.y,
252            );
253            painter
254                .superquadric(
255                    Aabb {
256                        min: Vec2::new(
257                            w_carve_pos.x - entry_length - 20,
258                            w_carve_pos.y - entry_width - 10,
259                        )
260                        .with_z(entry_base + (entry_height / 2) + (2 * entry_height)),
261                        max: Vec2::new(
262                            w_carve_pos.x + entry_length + 20,
263                            w_carve_pos.y + entry_width + 10,
264                        )
265                        .with_z(entry_base + (6 * entry_height)),
266                    },
267                    2.0,
268                )
269                .clear();
270
271            painter
272                .superquadric(
273                    Aabb {
274                        min: Vec2::new(
275                            l_carve_pos.x - entry_length - 10,
276                            l_carve_pos.y - entry_width - 20,
277                        )
278                        .with_z(entry_base + (entry_height / 2) + (2 * entry_height)),
279                        max: Vec2::new(
280                            l_carve_pos.x + entry_length + 10,
281                            l_carve_pos.y + entry_width + 20,
282                        )
283                        .with_z(entry_base + (6 * entry_height)),
284                    },
285                    2.0,
286                )
287                .clear();
288        }
289        for p in 0..2 {
290            let entry_pyramid_pos = Vec2::new(
291                entry_pos.x - (entry_length - 4) + (p * (2 * (entry_length - 4))),
292                entry_pos.y,
293            );
294            painter
295                .pyramid(Aabb {
296                    min: (entry_pyramid_pos - entry_length)
297                        .with_z(entry_base + (entry_height / 2) + (2 * entry_height)),
298                    max: (entry_pyramid_pos + entry_length).with_z(
299                        entry_base
300                            + (entry_height / 2)
301                            + (2 * entry_height)
302                            + (2 * entry_length)
303                            + 1,
304                    ),
305                })
306                .fill(roof_color.clone());
307        }
308
309        // entry pillars
310        for dir in DIAGONALS {
311            let pillar_pos = entry_pillar_pos + dir * (entry_length - 4);
312            painter
313                .cylinder(Aabb {
314                    min: (pillar_pos - 4).with_z(entry_base - 2),
315                    max: (pillar_pos + 4)
316                        .with_z(entry_base + (entry_height / 2) + (2 * entry_height) - 2),
317                })
318                .fill(brick.clone());
319        }
320
321        // castle roof
322        painter
323            .aabb(Aabb {
324                min: Vec2::new(center.x - castle_length - 10, center.y - castle_width - 10)
325                    .with_z(castle_base + (castle_height / 2) + (2 * castle_height)),
326                max: Vec2::new(center.x + castle_length + 10, center.y + castle_width + 10)
327                    .with_z(castle_base + (castle_height / 2) + (3 * castle_height)),
328            })
329            .fill(brick.clone());
330        painter
331            .aabb(Aabb {
332                min: Vec2::new(center.x - castle_length - 9, center.y - castle_width - 9)
333                    .with_z(castle_base + (castle_height / 2) + (2 * castle_height)),
334                max: Vec2::new(center.x + castle_length + 9, center.y + castle_width + 9)
335                    .with_z(castle_base + (castle_height / 2) + (3 * castle_height)),
336            })
337            .fill(roof_color.clone());
338        // roof carve
339        for c in 0..2 {
340            let w_carve_pos = Vec2::new(
341                center.x,
342                center.y - (2 * castle_width) + (c * (4 * castle_width)),
343            );
344            let l_carve_pos = Vec2::new(
345                center.x - (4 * (castle_length / 2)) + (c * (8 * (castle_length / 2))),
346                center.y,
347            );
348            painter
349                .superquadric(
350                    Aabb {
351                        min: Vec2::new(
352                            w_carve_pos.x - castle_length - 40,
353                            w_carve_pos.y - castle_width - 20,
354                        )
355                        .with_z(castle_base + (castle_height / 2) + (2 * castle_height)),
356                        max: Vec2::new(
357                            w_carve_pos.x + castle_length + 40,
358                            w_carve_pos.y + castle_width + 20,
359                        )
360                        .with_z(castle_base + (6 * castle_height)),
361                    },
362                    2.0,
363                )
364                .clear();
365
366            painter
367                .superquadric(
368                    Aabb {
369                        min: Vec2::new(
370                            l_carve_pos.x - castle_length - 20,
371                            l_carve_pos.y - castle_width - 40,
372                        )
373                        .with_z(castle_base + (castle_height / 2) + (2 * castle_height)),
374                        max: Vec2::new(
375                            l_carve_pos.x + castle_length + 20,
376                            l_carve_pos.y + castle_width + 40,
377                        )
378                        .with_z(castle_base + (6 * castle_height)),
379                    },
380                    2.0,
381                )
382                .clear();
383        }
384        // towers
385        let tower_access = RandomField::new(0).get(center.with_z(plot_base)) % 4;
386        let harlequin_0 = (RandomField::new(0).get(center.with_z(tower_base)) % 4) as usize;
387        let harlequin_1 = (RandomField::new(0).get(center.with_z(tower_base + 1)) % 4) as usize;
388        for (t, tower_center) in tower_positions.iter().enumerate() {
389            let height_var = RandomField::new(0).get(tower_center.with_z(tower_base)) % 30;
390            let tower_height = tower_height_raw + height_var as i32;
391            let top_base = tower_base + tower_height;
392            let cone_height = 20;
393            let tower_radius = (tower_width - 6) as f32;
394            let access = t == tower_access as usize;
395            let tower_top_var = if access {
396                0
397            } else if t < 4 {
398                1
399            } else {
400                RandomField::new(0).get((tower_center).with_z(tower_base)) % 3
401            };
402            if t < 4 && access {
403                // tower top chain
404                painter
405                    .line(
406                        (tower_center + ((center - tower_center) / 2))
407                            .with_z(castle_base + (3 * castle_height) + 5),
408                        (tower_center + ((center - tower_center) / 2))
409                            .with_z(top_base + top_height - 1),
410                        1.0,
411                    )
412                    .fill(chain.clone());
413                painter
414                    .line(
415                        tower_center.with_z(top_base + top_height),
416                        (tower_center + ((center - tower_center) / 2))
417                            .with_z(top_base + top_height),
418                        1.0,
419                    )
420                    .fill(wood.clone());
421            };
422            // tower
423            painter
424                .cylinder(Aabb {
425                    min: (tower_center - tower_width + 6).with_z(tower_base - castle_height - 30),
426                    max: (tower_center + 1 + tower_width - 6).with_z(tower_base + tower_height),
427                })
428                .fill(brick.clone());
429            // tower top
430            painter
431                .cylinder(Aabb {
432                    min: (tower_center - tower_width + 1).with_z(top_base),
433                    max: (tower_center + 1 + tower_width - 1).with_z(top_base + top_height),
434                })
435                .fill(brick.clone());
436
437            // carve outs
438            let carve_limiter = painter.aabb(Aabb {
439                min: (tower_center - (tower_width / 2) - 3).with_z(top_base),
440                max: (tower_center + 1 + (tower_width / 2) + 3).with_z(top_base + top_height),
441            });
442            for dir in CARDINALS {
443                let carve_pos = tower_center + dir * (tower_width + (tower_width / 4));
444                painter
445                    .superquadric(
446                        Aabb {
447                            min: (carve_pos - tower_width + 3).with_z(top_base + 1),
448                            max: (carve_pos + tower_width - 3).with_z(top_base + top_height - 1),
449                        },
450                        2.5,
451                    )
452                    .intersect(carve_limiter)
453                    .clear()
454            }
455            // outside decor
456            let decor_var = RandomField::new(0).get(tower_center.with_z(tower_base)) % 6;
457            let decor_radius = (tower_width / 3) * 2;
458            let decors = 4.0 + decor_var as f32;
459            let decor_phi = TAU / decors;
460            for n in 1..=decors as i32 {
461                let pos = Vec2::new(
462                    tower_center.x + (decor_radius as f32 * ((n as f32 * decor_phi).cos())) as i32,
463                    tower_center.y + (decor_radius as f32 * ((n as f32 * decor_phi).sin())) as i32,
464                );
465                painter
466                    .cubic_bezier(
467                        pos.with_z(tower_base + (tower_height / 2) + (tower_height / 6)),
468                        (pos - ((tower_center - pos) / 4))
469                            .with_z(tower_base + (tower_height / 2) + (tower_height / 3)),
470                        (pos - ((tower_center - pos) / 2)).with_z(
471                            tower_base
472                                + (tower_height / 2)
473                                + (tower_height / 3)
474                                + (tower_height / 6),
475                        ),
476                        pos.with_z(top_base + 1),
477                        1.5,
478                    )
479                    .fill(brick.clone());
480            }
481            // top platform outside low
482            painter
483                .cylinder(Aabb {
484                    min: (tower_center - (3 * (tower_width / 2)) + 11).with_z(top_base - 5),
485                    max: (tower_center + 1 + (3 * (tower_width / 2)) - 11).with_z(top_base - 4),
486                })
487                .fill(brick.clone());
488            painter
489                .cylinder(Aabb {
490                    min: (tower_center - (3 * (tower_width / 2)) + 10).with_z(top_base - 4),
491                    max: (tower_center + 1 + (3 * (tower_width / 2)) - 10).with_z(top_base - 2),
492                })
493                .fill(brick.clone());
494            painter
495                .cylinder(Aabb {
496                    min: (tower_center - (3 * (tower_width / 2)) + 8).with_z(top_base - 2),
497                    max: (tower_center + 1 + (3 * (tower_width / 2)) - 8).with_z(top_base),
498                })
499                .fill(brick.clone());
500            painter
501                .cylinder(Aabb {
502                    min: (tower_center - (3 * (tower_width / 2)) + 6).with_z(top_base),
503                    max: (tower_center + 1 + (3 * (tower_width / 2)) - 6).with_z(top_base + 2),
504                })
505                .fill(brick.clone());
506            // top platform outside high
507            painter
508                .cylinder(Aabb {
509                    min: (tower_center - (3 * (tower_width / 2)) + 5).with_z(top_base + top_height),
510                    max: (tower_center + 1 + (3 * (tower_width / 2)) - 5)
511                        .with_z(top_base + top_height + 2),
512                })
513                .fill(brick.clone());
514            // repaint tower room
515            painter
516                .cylinder(Aabb {
517                    min: (tower_center - tower_width + 2).with_z(top_base),
518                    max: (tower_center + 1 + tower_width - 2).with_z(top_base + top_height),
519                })
520                .fill(brick.clone());
521            // top windows
522            for h in 0..2 {
523                // clear windows
524                painter
525                    .line(
526                        Vec2::new(tower_center.x - tower_width, tower_center.y)
527                            .with_z(top_base + (top_height / 2) - 3 + (4 * h)),
528                        Vec2::new(tower_center.x + 1 + tower_width, tower_center.y)
529                            .with_z(top_base + (top_height / 2) - 3 + (4 * h)),
530                        2.5,
531                    )
532                    .clear();
533                painter
534                    .line(
535                        Vec2::new(tower_center.x, tower_center.y - tower_width)
536                            .with_z(top_base + (top_height / 2) - 3 + (4 * h)),
537                        Vec2::new(tower_center.x, tower_center.y + 1 + tower_width)
538                            .with_z(top_base + (top_height / 2) - 3 + (4 * h)),
539                        2.5,
540                    )
541                    .clear();
542            }
543            // top window sprites
544            let top_window_limiter = painter.aabb(Aabb {
545                min: (tower_center - tower_width + 2).with_z(top_base + 1),
546                max: (tower_center + 1 + tower_width - 2).with_z(top_base + tower_height - 1),
547            });
548            for h in 0..2 {
549                painter
550                    .line(
551                        Vec2::new(tower_center.x - tower_width, tower_center.y)
552                            .with_z(top_base + (top_height / 2) - 3 + (4 * h)),
553                        Vec2::new(tower_center.x + 1 + tower_width, tower_center.y)
554                            .with_z(top_base + (top_height / 2) - 3 + (4 * h)),
555                        2.5,
556                    )
557                    .intersect(top_window_limiter)
558                    .fill(window_ver2.clone());
559                painter
560                    .line(
561                        Vec2::new(tower_center.x, tower_center.y - tower_width)
562                            .with_z(top_base + (top_height / 2) - 3 + (4 * h)),
563                        Vec2::new(tower_center.x, tower_center.y + 1 + tower_width)
564                            .with_z(top_base + (top_height / 2) - 3 + (4 * h)),
565                        2.5,
566                    )
567                    .intersect(top_window_limiter)
568                    .fill(window_ver.clone());
569            }
570            // tower top window sills
571            painter
572                .aabb(Aabb {
573                    min: Vec2::new(tower_center.x - 1, tower_center.y - tower_width)
574                        .with_z(top_base + (top_height / 2) - 5),
575                    max: Vec2::new(tower_center.x + 2, tower_center.y + tower_width + 1)
576                        .with_z(top_base + (top_height / 2) - 4),
577                })
578                .fill(wood.clone());
579
580            painter
581                .aabb(Aabb {
582                    min: Vec2::new(tower_center.x - tower_width, tower_center.y - 1)
583                        .with_z(top_base + (top_height / 2) - 5),
584                    max: Vec2::new(tower_center.x + tower_width + 1, tower_center.y + 2)
585                        .with_z(top_base + (top_height / 2) - 4),
586                })
587                .fill(wood.clone());
588            // clear top room
589            painter
590                .cylinder(Aabb {
591                    min: (tower_center - tower_width + 3).with_z(top_base + 1),
592                    max: (tower_center + 1 + tower_width - 3).with_z(top_base + top_height),
593                })
594                .clear();
595            // top room candles and wood ring
596            painter
597                .cylinder(Aabb {
598                    min: (tower_center - tower_width + 3).with_z(top_base + 1),
599                    max: (tower_center + 1 + tower_width - 3).with_z(top_base + 2),
600                })
601                .fill(candles_lite.clone());
602            painter
603                .cylinder(Aabb {
604                    min: (tower_center - tower_width + 3).with_z(top_base + top_height - 1),
605                    max: (tower_center + 1 + tower_width - 3).with_z(top_base + top_height),
606                })
607                .fill(wood.clone());
608            painter
609                .cylinder(Aabb {
610                    min: (tower_center - tower_width + 8).with_z(top_base + 1),
611                    max: (tower_center + 1 + tower_width - 8).with_z(top_base + top_height),
612                })
613                .clear();
614            // tower windows and decor
615            let tower_window_limiter = painter.aabb(Aabb {
616                min: (tower_center + 1 - tower_radius as i32).with_z(tower_base),
617                max: (tower_center + tower_radius as i32).with_z(tower_base + tower_height + 1),
618            });
619            let decor_var = RandomField::new(0).get(tower_center.with_z(tower_base)) % 10;
620            let decors = 10.0 + decor_var as f32;
621            let tower_decor_phi = TAU / decors;
622            let decor_radius = (tower_width / 2) + 4;
623            for h in 0..2 {
624                for n in 0..2 {
625                    // tower decor
626                    for d in 1..=decors as i32 {
627                        let decor_pos = Vec2::new(
628                            tower_center.x
629                                + (decor_radius as f32 * ((d as f32 * tower_decor_phi).cos()))
630                                    as i32,
631                            tower_center.y
632                                + (decor_radius as f32 * ((d as f32 * tower_decor_phi).sin()))
633                                    as i32,
634                        );
635                        painter
636                            .line(
637                                tower_center.with_z(
638                                    tower_base + (tower_height / 3) + ((tower_height / 3) * n),
639                                ),
640                                decor_pos.with_z(
641                                    tower_base + (tower_height / 3) + ((tower_height / 3) * n),
642                                ),
643                                1.0,
644                            )
645                            .fill(brick.clone());
646                    }
647                    // clear windows
648                    painter
649                        .line(
650                            Vec2::new(tower_center.x - tower_width + 5, tower_center.y).with_z(
651                                tower_base
652                                    + (tower_height / 4)
653                                    + (4 * h)
654                                    + ((tower_height / 4) * n),
655                            ),
656                            Vec2::new(tower_center.x + 1 + tower_width - 5, tower_center.y).with_z(
657                                tower_base
658                                    + (tower_height / 4)
659                                    + (4 * h)
660                                    + ((tower_height / 4) * n),
661                            ),
662                            2.5,
663                        )
664                        .clear();
665                    painter
666                        .line(
667                            Vec2::new(tower_center.x, tower_center.y - tower_width + 5).with_z(
668                                tower_base
669                                    + (tower_height / 4)
670                                    + (4 * h)
671                                    + ((tower_height / 4) * n),
672                            ),
673                            Vec2::new(tower_center.x, tower_center.y + 1 + tower_width - 5).with_z(
674                                tower_base
675                                    + (tower_height / 4)
676                                    + (4 * h)
677                                    + ((tower_height / 4) * n),
678                            ),
679                            2.5,
680                        )
681                        .clear();
682                    // tower window sprites
683                    painter
684                        .line(
685                            Vec2::new(tower_center.x - tower_width + 4, tower_center.y).with_z(
686                                tower_base
687                                    + (tower_height / 4)
688                                    + (4 * h)
689                                    + ((tower_height / 4) * n),
690                            ),
691                            Vec2::new(tower_center.x + 1 + tower_width - 4, tower_center.y).with_z(
692                                tower_base
693                                    + (tower_height / 4)
694                                    + (4 * h)
695                                    + ((tower_height / 4) * n),
696                            ),
697                            2.5,
698                        )
699                        .intersect(tower_window_limiter)
700                        .fill(window_ver2.clone());
701                    painter
702                        .line(
703                            Vec2::new(tower_center.x, tower_center.y - tower_width + 4).with_z(
704                                tower_base
705                                    + (tower_height / 4)
706                                    + (4 * h)
707                                    + ((tower_height / 4) * n),
708                            ),
709                            Vec2::new(tower_center.x, tower_center.y + 1 + tower_width - 4).with_z(
710                                tower_base
711                                    + (tower_height / 4)
712                                    + (4 * h)
713                                    + ((tower_height / 4) * n),
714                            ),
715                            2.5,
716                        )
717                        .intersect(tower_window_limiter)
718                        .fill(window_ver.clone());
719                    // tower window sills
720                    painter
721                        .aabb(Aabb {
722                            min: Vec2::new(
723                                tower_center.x - 1,
724                                tower_center.y - (tower_width / 2) - 3,
725                            )
726                            .with_z(tower_base + (tower_height / 4) - 3 + ((tower_height / 4) * n)),
727                            max: Vec2::new(
728                                tower_center.x + 2,
729                                tower_center.y + (tower_width / 2) + 4,
730                            )
731                            .with_z(tower_base + (tower_height / 4) - 2 + ((tower_height / 4) * n)),
732                        })
733                        .fill(wood.clone());
734
735                    painter
736                        .aabb(Aabb {
737                            min: Vec2::new(
738                                tower_center.x - (tower_width / 2) - 3,
739                                tower_center.y - 1,
740                            )
741                            .with_z(tower_base + (tower_height / 4) - 3 + ((tower_height / 4) * n)),
742                            max: Vec2::new(
743                                tower_center.x + (tower_width / 2) + 4,
744                                tower_center.y + 2,
745                            )
746                            .with_z(tower_base + (tower_height / 4) - 2 + ((tower_height / 4) * n)),
747                        })
748                        .fill(wood.clone());
749                }
750            }
751            // roof
752            painter
753                .cylinder(Aabb {
754                    min: (tower_center - roof_width).with_z(top_base + top_height),
755                    max: (tower_center + 1 + roof_width)
756                        .with_z(top_base + top_height + roof_height),
757                })
758                .fill(brick.clone());
759            let tower_roof_filling = painter.cylinder(Aabb {
760                min: (tower_center - roof_width + 1).with_z(top_base + top_height),
761                max: (tower_center + 1 + roof_width - 1)
762                    .with_z(top_base + top_height + roof_height),
763            });
764            if tower_top_var > 0 {
765                tower_roof_filling.fill(roof_color.clone());
766            } else {
767                tower_roof_filling.clear();
768            }
769            // roof carve outs
770            for dir in NEIGHBORS {
771                let carve_pos = tower_center + dir * roof_width;
772                let carve_z_offset = roof_height / 20;
773
774                painter
775                    .superquadric(
776                        Aabb {
777                            min: (carve_pos - 3 * (tower_width / 4))
778                                .with_z(top_base + top_height + carve_z_offset),
779                            max: (carve_pos + 3 * (tower_width / 4))
780                                .with_z(top_base + top_height + (2 * roof_height) + carve_z_offset),
781                        },
782                        2.5,
783                    )
784                    .clear();
785            }
786            if tower_top_var > 0 {
787                // cones
788                painter
789                    .cone(Aabb {
790                        min: (tower_center - (roof_width / 3) - 2).with_z(top_base + top_height),
791                        max: (tower_center + (roof_width / 3) + 2)
792                            .with_z(top_base + cone_height + (4 * roof_height) - 4),
793                    })
794                    .fill(roof_color.clone());
795
796                for dir in DIAGONALS {
797                    let cone_center = tower_center + dir * 6;
798                    let cone_var = RandomField::new(0).get(cone_center.with_z(tower_base)) % 60;
799                    painter
800                        .cone(Aabb {
801                            min: (cone_center - 4).with_z(top_base + top_height + 2),
802                            max: (cone_center + 4)
803                                .with_z(top_base + top_height + 30 + cone_var as i32),
804                        })
805                        .fill(roof_color.clone());
806                }
807            } else {
808                // top platform variant
809                painter
810                    .cylinder(Aabb {
811                        min: (tower_center - (3 * (tower_width / 2)) + 6)
812                            .with_z(top_base + top_height),
813                        max: (tower_center + 1 + (3 * (tower_width / 2)) - 6)
814                            .with_z(top_base + top_height + 2),
815                    })
816                    .fill(brick.clone());
817            }
818
819            // tower clear
820            let tower_radius = (tower_width - 7) as f32;
821            let add_on = if tower_top_var > 0 { 0 } else { top_height + 1 };
822            painter
823                .cylinder(Aabb {
824                    min: (tower_center + 1 - tower_radius as i32)
825                        .with_z(tower_base - castle_height + 1),
826                    max: (tower_center + tower_radius as i32)
827                        .with_z(tower_base + tower_height + 1 + add_on),
828                })
829                .clear();
830            // entries and floor for far towers
831            if t > 3 {
832                for dir in DIAGONALS {
833                    let entry_pos = tower_center + (dir * ((tower_width / 3) + 3));
834                    painter
835                        .line(
836                            tower_center.with_z(tower_base + (top_height / 3) + 5),
837                            entry_pos.with_z(tower_base + (top_height / 3)),
838                            4.5,
839                        )
840                        .clear();
841                    painter
842                        .cylinder(Aabb {
843                            min: (tower_center - tower_width + 7)
844                                .with_z(tower_base - castle_height + 1),
845                            max: (tower_center + 1 + tower_width - 7)
846                                .with_z(tower_base + (top_height / 3)),
847                        })
848                        .fill(brick.clone());
849                }
850                // floor candles
851                painter
852                    .cylinder(Aabb {
853                        min: (tower_center - tower_width + 8).with_z(tower_base + (top_height / 3)),
854                        max: (tower_center + 1 + tower_width - 8)
855                            .with_z(tower_base + (top_height / 3) + 1),
856                    })
857                    .fill(candles_lite.clone());
858            }
859            if tower_top_var < 1 {
860                // center clear
861                let ground_floor = if t < 4 {
862                    -castle_height - 1
863                } else {
864                    top_height / 3
865                };
866                painter
867                    .cylinder(Aabb {
868                        min: (tower_center - 2).with_z(tower_base + ground_floor),
869                        max: (tower_center + 3).with_z(tower_base + tower_height + 1 + add_on),
870                    })
871                    .clear();
872                if t < 4 && access {
873                    // tower top entry door
874                    painter
875                        .cylinder(Aabb {
876                            min: (tower_center + 1 - tower_radius as i32)
877                                .with_z(tower_base + tower_height + add_on),
878                            max: (tower_center + tower_radius as i32)
879                                .with_z(tower_base + tower_height + 1 + add_on),
880                        })
881                        .fill(key_door.clone());
882                    painter
883                        .cylinder(Aabb {
884                            min: (tower_center).with_z(tower_base + tower_height + add_on),
885                            max: (tower_center + 1).with_z(tower_base + tower_height + 1 + add_on),
886                        })
887                        .fill(key_hole.clone());
888                    painter
889                        .cylinder(Aabb {
890                            min: (tower_center + 1 - tower_radius as i32)
891                                .with_z(tower_base + tower_height + 1 + add_on),
892                            max: (tower_center + tower_radius as i32)
893                                .with_z(tower_base + tower_height + 2 + add_on),
894                        })
895                        .fill(onewaydoor.clone());
896                    painter
897                        .cylinder(Aabb {
898                            min: (tower_center + 2 - tower_radius as i32)
899                                .with_z(tower_base + tower_height + 1 + add_on),
900                            max: (tower_center - 1 + tower_radius as i32)
901                                .with_z(tower_base + tower_height + 2 + add_on),
902                        })
903                        .clear();
904                    let top_bat_pos = tower_center.with_z(tower_base + tower_height + 2 + add_on);
905                    bat_positions.push(top_bat_pos);
906                }
907            }
908            let bat_z = if t > 3 {
909                tower_base + (top_height / 3)
910            } else {
911                castle_base - castle_height + 1
912            };
913            let bat_pos_bottom = tower_center.with_z(bat_z);
914            bat_positions.push(bat_pos_bottom);
915            // tower platforms, chests and harlequins
916            for p in 0..4 {
917                painter
918                    .cylinder(Aabb {
919                        min: (tower_center - (tower_width / 4) - 3)
920                            .with_z(tower_base + (p * (tower_height / 3))),
921                        max: (tower_center - (tower_width / 4) + 3)
922                            .with_z(tower_base + (p * (tower_height / 3)) + 1),
923                    })
924                    .fill(roof_color.clone());
925                painter.sprite(
926                    (tower_center - (tower_width / 4) + 1)
927                        .with_z(tower_base + 1 + (p * (tower_height / 3))),
928                    SpriteKind::Candle,
929                );
930            }
931            let chest_pos =
932                (tower_center + (tower_width / 2)).with_z(tower_base + tower_height + 1);
933            let rand_npc_pos =
934                (tower_center + (tower_width / 2) + 1).with_z(tower_base + tower_height + 1);
935            let chest_var = RandomField::new(0).get(chest_pos) % 2;
936            if chest_var > 0 {
937                painter.sprite(chest_pos, SpriteKind::DungeonChest3);
938                random_npc_positions.push(rand_npc_pos);
939            }
940            if t == harlequin_0 {
941                let harlequin_pos_0 =
942                    (tower_center - (tower_width / 2)).with_z(tower_base + tower_height + 1);
943                harlequin_positions.push(harlequin_pos_0);
944            }
945            if t == harlequin_1 {
946                let harlequin_pos_1 =
947                    (tower_center - (tower_width / 2) + 1).with_z(tower_base + tower_height + 1);
948                harlequin_positions.push(harlequin_pos_1);
949            }
950        }
951        let mut harlequin_2_positions = vec![];
952        for pos in side_bldg_positions.iter().skip(2) {
953            harlequin_2_positions.push(*pos)
954        }
955        for pos in tower_positions.iter().skip(4) {
956            harlequin_2_positions.push(*pos)
957        }
958        let harlequin_2 = (RandomField::new(0).get(center.with_z(tower_base))
959            % harlequin_2_positions.len() as u32) as usize;
960        let harlequin_pos_2 = harlequin_2_positions[harlequin_2].with_z(tower_base + 8);
961        harlequin_positions.push(harlequin_pos_2);
962        // castle base
963        painter
964            .aabb(Aabb {
965                min: Vec2::new(center.x - castle_length - 3, center.y - castle_width - 3)
966                    .with_z(castle_base),
967                max: Vec2::new(center.x + castle_length + 3, center.y + castle_width + 3)
968                    .with_z(castle_base + (castle_height / 2)),
969            })
970            .fill(brick.clone());
971        // castle room
972        painter
973            .aabb(Aabb {
974                min: Vec2::new(center.x - castle_length - 5, center.y - castle_width - 5)
975                    .with_z(castle_base + (castle_height / 2)),
976                max: Vec2::new(center.x + castle_length + 5, center.y + castle_width + 5)
977                    .with_z(castle_base + (castle_height / 2) + (2 * castle_height)),
978            })
979            .fill(brick.clone());
980        // castle decor and windows
981        let castle_limiter = painter.aabb(Aabb {
982            min: Vec2::new(center.x - castle_length - 6, center.y - castle_width - 6)
983                .with_z(castle_base),
984            max: Vec2::new(center.x + castle_length + 6, center.y + castle_width + 6)
985                .with_z(castle_base + (castle_height / 2) + (2 * castle_height)),
986        });
987        let castle_window_limiter = painter.aabb(Aabb {
988            min: Vec2::new(center.x - castle_length - 4, center.y - castle_width - 4)
989                .with_z(castle_base + (castle_height / 2) + 1),
990            max: Vec2::new(center.x + castle_length + 4, center.y + castle_width + 4)
991                .with_z(castle_base + (castle_height / 2) + (2 * castle_height) - 1),
992        });
993        // castle decor
994        let castle_decor_var = RandomField::new(0).get(center.with_z(tower_base)) % 25;
995        let castle_decors = 25.0 + castle_decor_var as f32;
996        let castle_decor_phi = TAU / castle_decors;
997        let castle_decor_radius = castle_length + 10;
998        // tower decor
999        for d in 1..=castle_decors as i32 {
1000            let castle_decor_pos = Vec2::new(
1001                center.x
1002                    + (castle_decor_radius as f32 * ((d as f32 * castle_decor_phi).cos())) as i32,
1003                center.y
1004                    + (castle_decor_radius as f32 * ((d as f32 * castle_decor_phi).sin())) as i32,
1005            );
1006            for l in 0..2 {
1007                painter
1008                    .line(
1009                        center.with_z(
1010                            castle_base + (castle_height / 2) + ((2 * l) * castle_height) - 1,
1011                        ),
1012                        castle_decor_pos.with_z(
1013                            castle_base + (castle_height / 2) + ((2 * l) * castle_height) - 1,
1014                        ),
1015                        1.0,
1016                    )
1017                    .intersect(castle_limiter)
1018                    .fill(brick.clone());
1019                painter
1020                    .line(
1021                        center.with_z(
1022                            castle_base + 3 + castle_height + (l * ((castle_height / 2) + 5)),
1023                        ),
1024                        castle_decor_pos.with_z(
1025                            castle_base + 3 + castle_height + (l * ((castle_height / 2) + 5)),
1026                        ),
1027                        1.0,
1028                    )
1029                    .intersect(castle_limiter)
1030                    .fill(brick.clone());
1031            }
1032        }
1033        // castle windows
1034        for h in 0..2 {
1035            for s in 1..=2 {
1036                for r in 0..=2 {
1037                    // clear windows
1038                    painter
1039                        .line(
1040                            Vec2::new(
1041                                center.x - castle_length - 5,
1042                                center.y - (castle_width / 2) + (r * (castle_width / 2)),
1043                            )
1044                            .with_z(castle_base + (s * ((castle_height / 2) + 5)) + (4 * h)),
1045                            Vec2::new(
1046                                center.x + 1 + castle_length + 5,
1047                                center.y - (castle_width / 2) + (r * (castle_width / 2)),
1048                            )
1049                            .with_z(castle_base + (s * ((castle_height / 2) + 5)) + (4 * h)),
1050                            2.5,
1051                        )
1052                        .clear();
1053                    painter
1054                        .line(
1055                            Vec2::new(
1056                                center.x - (castle_length / 2) + (r * (castle_length / 2)),
1057                                center.y - castle_width - 5,
1058                            )
1059                            .with_z(castle_base + (s * ((castle_height / 2) + 5)) + (4 * h)),
1060                            Vec2::new(
1061                                center.x - (castle_length / 2) + (r * (castle_length / 2)),
1062                                center.y + 1 + castle_width + 5,
1063                            )
1064                            .with_z(castle_base + (s * ((castle_height / 2) + 5)) + (4 * h)),
1065                            2.5,
1066                        )
1067                        .clear();
1068
1069                    // castle window sills
1070                    painter
1071                        .aabb(Aabb {
1072                            min: Vec2::new(
1073                                center.x - 1 - (castle_length / 2) + (r * (castle_length / 2)),
1074                                center.y - castle_width - 6,
1075                            )
1076                            .with_z(castle_base + (s * ((castle_height / 2) + 2)) + (3 * (s - 1))),
1077                            max: Vec2::new(
1078                                center.x + 2 - (castle_length / 2) + (r * (castle_length / 2)),
1079                                center.y + castle_width + 6,
1080                            )
1081                            .with_z(
1082                                castle_base + 1 + (s * ((castle_height / 2) + 2)) + (3 * (s - 1)),
1083                            ),
1084                        })
1085                        .fill(wood.clone());
1086
1087                    painter
1088                        .aabb(Aabb {
1089                            min: Vec2::new(
1090                                center.x - castle_length - 6,
1091                                center.y - 1 - (castle_width / 2) + (r * (castle_width / 2)),
1092                            )
1093                            .with_z(castle_base + (s * ((castle_height / 2) + 2)) + (3 * (s - 1))),
1094                            max: Vec2::new(
1095                                center.x + castle_length + 6,
1096                                center.y + 2 - (castle_width / 2) + (r * (castle_width / 2)),
1097                            )
1098                            .with_z(
1099                                castle_base + 1 + (s * ((castle_height / 2) + 2)) + (3 * (s - 1)),
1100                            ),
1101                        })
1102                        .fill(wood.clone());
1103                    // castle window sprites
1104                    painter
1105                        .line(
1106                            Vec2::new(
1107                                center.x - castle_length - 5,
1108                                center.y - (castle_width / 2) + (r * (castle_width / 2)),
1109                            )
1110                            .with_z(castle_base + (s * ((castle_height / 2) + 5)) + (4 * h)),
1111                            Vec2::new(
1112                                center.x + 1 + castle_length + 5,
1113                                center.y - (castle_width / 2) + (r * (castle_width / 2)),
1114                            )
1115                            .with_z(castle_base + (s * ((castle_height / 2) + 5)) + (4 * h)),
1116                            2.5,
1117                        )
1118                        .intersect(castle_window_limiter)
1119                        .fill(window_ver2.clone());
1120                    painter
1121                        .line(
1122                            Vec2::new(
1123                                center.x - (castle_length / 2) + (r * (castle_length / 2)),
1124                                center.y - castle_width - 5,
1125                            )
1126                            .with_z(castle_base + (s * ((castle_height / 2) + 5)) + (4 * h)),
1127                            Vec2::new(
1128                                center.x - (castle_length / 2) + (r * (castle_length / 2)),
1129                                center.y + 1 + castle_width + 5,
1130                            )
1131                            .with_z(castle_base + (s * ((castle_height / 2) + 5)) + (4 * h)),
1132                            2.5,
1133                        )
1134                        .intersect(castle_window_limiter)
1135                        .fill(window_ver.clone());
1136                }
1137            }
1138        }
1139        // main entry stairs
1140        painter
1141            .line(
1142                entry_pos.with_z(castle_base - 2),
1143                center.with_z(castle_base + castle_height - 5),
1144                5.0,
1145            )
1146            .fill(brick.clone());
1147        painter
1148            .line(
1149                entry_pos.with_z(castle_base),
1150                center.with_z(castle_base + castle_height - 3),
1151                5.0,
1152            )
1153            .clear();
1154        painter
1155            .aabb(Aabb {
1156                min: (entry_pos - 10).with_z(castle_base - 5),
1157                max: (entry_pos + 10).with_z(castle_base),
1158            })
1159            .fill(brick.clone());
1160        // main entry door
1161        painter
1162            .horizontal_cylinder(
1163                Aabb {
1164                    min: Vec2::new(center.x - castle_length - 3, center.y - 4)
1165                        .with_z(entry_base + 6),
1166                    max: Vec2::new(center.x - castle_length - 2, center.y + 5)
1167                        .with_z(entry_base + 15),
1168                },
1169                Dir::NegX,
1170            )
1171            .fill(onewaydoor.clone());
1172        // castle cellar
1173        painter
1174            .aabb(Aabb {
1175                min: Vec2::new(center.x - castle_length - 2, center.y - castle_width - 2)
1176                    .with_z(castle_base - castle_height),
1177                max: Vec2::new(center.x + castle_length + 2, center.y + castle_width + 2)
1178                    .with_z(castle_base + (castle_height / 8)),
1179            })
1180            .fill(brick.clone());
1181        // cellar stairs to side_bldgs
1182        painter
1183            .line(
1184                center.with_z(castle_base - castle_height - 3),
1185                side_bldg_stairs_pos.with_z(side_bldg_base_raw),
1186                6.0,
1187            )
1188            .fill(brick.clone());
1189        painter
1190            .line(
1191                center.with_z(castle_base - castle_height - 3),
1192                side_bldg_stairs_pos.with_z(side_bldg_base_raw),
1193                5.0,
1194            )
1195            .clear();
1196        // clear castle cellar
1197        painter
1198            .aabb(Aabb {
1199                min: Vec2::new(center.x - castle_length - 1, center.y - castle_width - 1)
1200                    .with_z(castle_base - castle_height + 1),
1201                max: Vec2::new(center.x + castle_length + 1, center.y + castle_width + 1)
1202                    .with_z(castle_base + (castle_height / 8) - 1),
1203            })
1204            .clear();
1205
1206        random_npc_positions.push(center.with_z(castle_base - castle_height + 1));
1207
1208        // castle cellar tower entries
1209        for dir in DIAGONALS {
1210            let entry_pos = Vec2::new(
1211                center.x + dir.x * (castle_length + 2),
1212                center.y + dir.y * (castle_width + 2),
1213            );
1214            painter
1215                .line(
1216                    entry_pos.with_z(castle_base - castle_height),
1217                    entry_pos.with_z(castle_base - castle_height + 6),
1218                    8.0,
1219                )
1220                .clear();
1221            painter
1222                .cylinder(Aabb {
1223                    min: (entry_pos - 8).with_z(castle_base - castle_height - 5),
1224                    max: (entry_pos + 8).with_z(castle_base - castle_height + 1),
1225                })
1226                .fill(brick.clone());
1227        }
1228        // castle cellar floor
1229        painter
1230            .aabb(Aabb {
1231                min: Vec2::new(center.x - castle_length - 20, center.y - castle_width - 20)
1232                    .with_z(castle_base - castle_height - 8),
1233                max: Vec2::new(center.x + castle_length + 20, center.y + castle_width + 20)
1234                    .with_z(castle_base - castle_height + 1),
1235            })
1236            .fill(brick.clone());
1237        // cellar wood decor and candles
1238        painter
1239            .aabb(Aabb {
1240                min: Vec2::new(center.x - castle_length - 1, center.y - castle_width - 1)
1241                    .with_z(castle_base + (castle_height / 8) - 6),
1242                max: Vec2::new(center.x + castle_length + 1, center.y + castle_width + 1)
1243                    .with_z(castle_base + (castle_height / 8) - 1),
1244            })
1245            .fill(wood.clone());
1246        painter
1247            .aabb(Aabb {
1248                min: Vec2::new(center.x - castle_length + 1, center.y - castle_width + 1)
1249                    .with_z(castle_base + (castle_height / 8) - 6),
1250                max: Vec2::new(center.x + castle_length - 1, center.y + castle_width - 1)
1251                    .with_z(castle_base + (castle_height / 8) - 1),
1252            })
1253            .clear();
1254        let cellar_podium_limiter = painter.aabb(Aabb {
1255            min: Vec2::new(center.x - castle_length - 1, center.y - castle_width - 1)
1256                .with_z(castle_base - castle_height + 1),
1257            max: Vec2::new(center.x + castle_length + 1, center.y + castle_width + 1)
1258                .with_z(castle_base - castle_height + 4),
1259        });
1260        let mut cellar_beam_postions = vec![];
1261        for dir in DIAGONALS {
1262            let beam_pos = Vec2::new(
1263                center.x + (dir.x * (castle_length / 3)),
1264                center.y + (dir.y * (castle_width + 1)),
1265            );
1266            cellar_beam_postions.push(beam_pos);
1267        }
1268        for b in 0..2 {
1269            let beam_pos = Vec2::new(
1270                center.x - castle_length - 2 + (b * ((2 * castle_length) + 3)),
1271                center.y,
1272            );
1273            cellar_beam_postions.push(beam_pos);
1274        }
1275        for beam_pos in cellar_beam_postions {
1276            for n in 0..3 {
1277                painter
1278                    .cylinder_with_radius(
1279                        beam_pos.with_z(castle_base - castle_height + 1 + n),
1280                        (5 - n) as f32,
1281                        1.0,
1282                    )
1283                    .intersect(cellar_podium_limiter)
1284                    .fill(match n {
1285                        2 => candles.clone(),
1286                        _ => wood.clone(),
1287                    });
1288            }
1289            painter
1290                .line(
1291                    beam_pos.with_z(castle_base - castle_height + 1),
1292                    beam_pos.with_z(castle_base + (castle_height / 8) - 5),
1293                    2.0,
1294                )
1295                .fill(wood.clone());
1296        }
1297        // side buildings
1298        for (b, side_bldg_pos) in side_bldg_positions.iter().enumerate() {
1299            let side_bldg_roof_height = side_bldg_roof_height_raw
1300                + (RandomField::new(0).get(side_bldg_pos.with_z(tower_base)) % 12) as i32;
1301            let side_bldg_base = if b > 1 {
1302                side_bldg_base_raw - (side_bldg_height / 2) - side_bldg_roof_height
1303            } else {
1304                side_bldg_base_raw
1305            };
1306            // side_bldg roof
1307            let side_bldg_roof = painter.aabb(Aabb {
1308                min: Vec2::new(
1309                    side_bldg_pos.x - side_bldg_length - 10,
1310                    side_bldg_pos.y - side_bldg_width - 10,
1311                )
1312                .with_z(side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height)),
1313                max: Vec2::new(
1314                    side_bldg_pos.x + side_bldg_length + 10,
1315                    side_bldg_pos.y + side_bldg_width + 10,
1316                )
1317                .with_z(side_bldg_base + side_bldg_roof_height + (3 * side_bldg_height)),
1318            });
1319            side_bldg_roof.fill(brick.clone());
1320            painter
1321                .aabb(Aabb {
1322                    min: Vec2::new(
1323                        side_bldg_pos.x - side_bldg_length - 9,
1324                        side_bldg_pos.y - side_bldg_width - 9,
1325                    )
1326                    .with_z(side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height)),
1327                    max: Vec2::new(
1328                        side_bldg_pos.x + side_bldg_length + 9,
1329                        side_bldg_pos.y + side_bldg_width + 9,
1330                    )
1331                    .with_z(side_bldg_base + side_bldg_roof_height + (3 * side_bldg_height)),
1332                })
1333                .fill(roof_color.clone());
1334            // side_bldg room
1335            painter
1336                .aabb(Aabb {
1337                    min: Vec2::new(
1338                        side_bldg_pos.x - side_bldg_length - 5,
1339                        side_bldg_pos.y - side_bldg_width - 5,
1340                    )
1341                    .with_z(side_bldg_base - 2),
1342                    max: Vec2::new(
1343                        side_bldg_pos.x + side_bldg_length + 5,
1344                        side_bldg_pos.y + side_bldg_width + 5,
1345                    )
1346                    .with_z(side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height)),
1347                })
1348                .fill(brick.clone());
1349            // side_bldg roof carve
1350            for c in 0..2 {
1351                let w_carve_pos = Vec2::new(
1352                    side_bldg_pos.x,
1353                    side_bldg_pos.y - (2 * side_bldg_width) + (c * (4 * side_bldg_width)),
1354                );
1355                let l_carve_pos = Vec2::new(
1356                    side_bldg_pos.x - (4 * (side_bldg_length / 2))
1357                        + (c * (8 * (side_bldg_length / 2))),
1358                    side_bldg_pos.y,
1359                );
1360                painter
1361                    .superquadric(
1362                        Aabb {
1363                            min: Vec2::new(
1364                                w_carve_pos.x - side_bldg_length - 20,
1365                                w_carve_pos.y - side_bldg_width - 10,
1366                            )
1367                            .with_z(
1368                                side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height),
1369                            ),
1370                            max: Vec2::new(
1371                                w_carve_pos.x + side_bldg_length + 20,
1372                                w_carve_pos.y + side_bldg_width + 10,
1373                            )
1374                            .with_z(
1375                                side_bldg_base + side_bldg_roof_height - (side_bldg_height / 2)
1376                                    + (6 * side_bldg_height),
1377                            ),
1378                        },
1379                        2.0,
1380                    )
1381                    .intersect(side_bldg_roof)
1382                    .clear();
1383
1384                painter
1385                    .superquadric(
1386                        Aabb {
1387                            min: Vec2::new(
1388                                l_carve_pos.x - side_bldg_length - 10,
1389                                l_carve_pos.y - side_bldg_width - 20,
1390                            )
1391                            .with_z(
1392                                side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height),
1393                            ),
1394                            max: Vec2::new(
1395                                l_carve_pos.x + side_bldg_length + 10,
1396                                l_carve_pos.y + side_bldg_width + 20,
1397                            )
1398                            .with_z(
1399                                side_bldg_base + side_bldg_roof_height - (side_bldg_height / 2)
1400                                    + (6 * side_bldg_height),
1401                            ),
1402                        },
1403                        2.0,
1404                    )
1405                    .intersect(side_bldg_roof)
1406                    .clear();
1407            }
1408            for p in 0..2 {
1409                let pyramid_pos = Vec2::new(
1410                    side_bldg_pos.x - (side_bldg_length - 4) + (p * (2 * (side_bldg_length - 4))),
1411                    side_bldg_pos.y,
1412                );
1413                painter
1414                    .pyramid(Aabb {
1415                        min: (pyramid_pos - side_bldg_length).with_z(
1416                            side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height),
1417                        ),
1418                        max: (pyramid_pos + side_bldg_length).with_z(
1419                            side_bldg_base
1420                                + side_bldg_roof_height
1421                                + (2 * side_bldg_height)
1422                                + (2 * side_bldg_length)
1423                                + 1,
1424                        ),
1425                    })
1426                    .fill(roof_color.clone());
1427            }
1428
1429            // side_bldg decor
1430            let side_bldg_decor_limiter_1 = painter.aabb(Aabb {
1431                min: Vec2::new(
1432                    side_bldg_pos.x - side_bldg_length - 9,
1433                    side_bldg_pos.y - side_bldg_width - 9,
1434                )
1435                .with_z(side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height) - 1),
1436                max: Vec2::new(
1437                    side_bldg_pos.x + side_bldg_length + 9,
1438                    side_bldg_pos.y + side_bldg_width + 9,
1439                )
1440                .with_z(side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height)),
1441            });
1442            let side_bldg_decor_limiter_2 = painter.aabb(Aabb {
1443                min: Vec2::new(
1444                    side_bldg_pos.x - side_bldg_length - 6,
1445                    side_bldg_pos.y - side_bldg_width - 6,
1446                )
1447                .with_z(side_bldg_base + 8),
1448                max: Vec2::new(
1449                    side_bldg_pos.x + side_bldg_length + 6,
1450                    side_bldg_pos.y + side_bldg_width + 6,
1451                )
1452                .with_z(side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height) - 2),
1453            });
1454            let side_bldg_window_limiter = painter.aabb(Aabb {
1455                min: Vec2::new(
1456                    side_bldg_pos.x - side_bldg_length - 4,
1457                    side_bldg_pos.y - side_bldg_width - 4,
1458                )
1459                .with_z(side_bldg_base),
1460                max: Vec2::new(
1461                    side_bldg_pos.x + side_bldg_length + 4,
1462                    side_bldg_pos.y + side_bldg_width + 4,
1463                )
1464                .with_z(side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height) - 2),
1465            });
1466            let side_bldg_decor_rows = (side_bldg_roof_height + (2 * side_bldg_height)) / 6;
1467            for r in 0..=6 {
1468                let side_bldg_decor_limiter = if r == 0 {
1469                    side_bldg_decor_limiter_1
1470                } else {
1471                    side_bldg_decor_limiter_2
1472                };
1473                let side_bldg_decor_var =
1474                    RandomField::new(0).get((side_bldg_pos + r).with_z(tower_base)) % 12;
1475                let side_bldg_decors = 12.0 + side_bldg_decor_var as f32;
1476                let side_bldg_phi = TAU / side_bldg_decors;
1477                let side_bldg_decor_radius = side_bldg_length + 10;
1478                for d in 1..=side_bldg_decors as i32 {
1479                    let side_bldg_decors_pos = Vec2::new(
1480                        side_bldg_pos.x
1481                            + (side_bldg_decor_radius as f32 * ((d as f32 * side_bldg_phi).cos()))
1482                                as i32,
1483                        side_bldg_pos.y
1484                            + (side_bldg_decor_radius as f32 * ((d as f32 * side_bldg_phi).sin()))
1485                                as i32,
1486                    );
1487                    painter
1488                        .line(
1489                            side_bldg_pos.with_z(
1490                                side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height)
1491                                    - 1
1492                                    - (r * side_bldg_decor_rows),
1493                            ),
1494                            side_bldg_decors_pos.with_z(
1495                                side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height)
1496                                    - 1
1497                                    - (r * side_bldg_decor_rows),
1498                            ),
1499                            1.0,
1500                        )
1501                        .intersect(side_bldg_decor_limiter)
1502                        .fill(brick.clone());
1503                }
1504            }
1505            // side bldg close, windows, gangway to main room
1506            if b < 2 {
1507                // side bldg windows
1508                for r in 0..2 {
1509                    for t in 0..=2 {
1510                        for h in 0..2 {
1511                            // clear windows
1512                            painter
1513                                .line(
1514                                    Vec2::new(
1515                                        side_bldg_pos.x - side_bldg_length - 7,
1516                                        side_bldg_pos.y - 1 - (side_bldg_width / 2)
1517                                            + (r * ((side_bldg_length) - 2)),
1518                                    )
1519                                    .with_z(
1520                                        side_bldg_base
1521                                            + (side_bldg_roof_height / 4)
1522                                            + (t * (side_bldg_roof_height / 3))
1523                                            + (4 * h),
1524                                    ),
1525                                    Vec2::new(
1526                                        side_bldg_pos.x + 1 + side_bldg_length + 7,
1527                                        side_bldg_pos.y - 1 - (side_bldg_width / 2)
1528                                            + (r * ((side_bldg_length) - 2)),
1529                                    )
1530                                    .with_z(
1531                                        side_bldg_base
1532                                            + (side_bldg_roof_height / 4)
1533                                            + (t * (side_bldg_roof_height / 3))
1534                                            + (4 * h),
1535                                    ),
1536                                    2.5,
1537                                )
1538                                .clear();
1539                            painter
1540                                .line(
1541                                    Vec2::new(
1542                                        side_bldg_pos.x - (side_bldg_length / 2)
1543                                            + (r * side_bldg_width),
1544                                        side_bldg_pos.y - side_bldg_width - 7,
1545                                    )
1546                                    .with_z(
1547                                        side_bldg_base
1548                                            + (side_bldg_roof_height / 4)
1549                                            + (t * (side_bldg_roof_height / 3))
1550                                            + (4 * h),
1551                                    ),
1552                                    Vec2::new(
1553                                        side_bldg_pos.x - (side_bldg_length / 2)
1554                                            + (r * side_bldg_width),
1555                                        side_bldg_pos.y + 1 + side_bldg_width + 7,
1556                                    )
1557                                    .with_z(
1558                                        side_bldg_base
1559                                            + (side_bldg_roof_height / 4)
1560                                            + (t * (side_bldg_roof_height / 3))
1561                                            + (4 * h),
1562                                    ),
1563                                    2.5,
1564                                )
1565                                .clear();
1566
1567                            // side bldg window sprites
1568                            painter
1569                                .line(
1570                                    Vec2::new(
1571                                        side_bldg_pos.x - side_bldg_length - 7,
1572                                        side_bldg_pos.y - 1 - (side_bldg_width / 2)
1573                                            + (r * ((side_bldg_length) - 2)),
1574                                    )
1575                                    .with_z(
1576                                        side_bldg_base
1577                                            + (side_bldg_roof_height / 4)
1578                                            + (t * (side_bldg_roof_height / 3))
1579                                            + (4 * h),
1580                                    ),
1581                                    Vec2::new(
1582                                        side_bldg_pos.x + 1 + side_bldg_length + 7,
1583                                        side_bldg_pos.y - 1 - (side_bldg_width / 2)
1584                                            + (r * ((side_bldg_length) - 2)),
1585                                    )
1586                                    .with_z(
1587                                        side_bldg_base
1588                                            + (side_bldg_roof_height / 4)
1589                                            + (t * (side_bldg_roof_height / 3))
1590                                            + (4 * h),
1591                                    ),
1592                                    2.5,
1593                                )
1594                                .intersect(side_bldg_window_limiter)
1595                                .fill(window_ver2.clone());
1596                            painter
1597                                .line(
1598                                    Vec2::new(
1599                                        side_bldg_pos.x - (side_bldg_length / 2)
1600                                            + (r * side_bldg_width),
1601                                        side_bldg_pos.y - side_bldg_width - 7,
1602                                    )
1603                                    .with_z(
1604                                        side_bldg_base
1605                                            + (side_bldg_roof_height / 4)
1606                                            + (t * (side_bldg_roof_height / 3))
1607                                            + (4 * h),
1608                                    ),
1609                                    Vec2::new(
1610                                        side_bldg_pos.x - (side_bldg_length / 2)
1611                                            + (r * side_bldg_width),
1612                                        side_bldg_pos.y + 1 + side_bldg_width + 7,
1613                                    )
1614                                    .with_z(
1615                                        side_bldg_base
1616                                            + (side_bldg_roof_height / 4)
1617                                            + (t * (side_bldg_roof_height / 3))
1618                                            + (4 * h),
1619                                    ),
1620                                    2.5,
1621                                )
1622                                .intersect(side_bldg_window_limiter)
1623                                .fill(window_ver.clone());
1624                        }
1625                        // side_bldg window sills
1626                        painter
1627                            .aabb(Aabb {
1628                                min: Vec2::new(
1629                                    side_bldg_pos.x - 1 - (side_bldg_length / 2)
1630                                        + (r * ((side_bldg_length) - 3)),
1631                                    side_bldg_pos.y - side_bldg_width - 6,
1632                                )
1633                                .with_z(
1634                                    side_bldg_base - 2
1635                                        + (side_bldg_roof_height / 4)
1636                                        + (t * (side_bldg_roof_height / 3)),
1637                                ),
1638                                max: Vec2::new(
1639                                    side_bldg_pos.x + 2 - (side_bldg_length / 2)
1640                                        + (r * (side_bldg_length - 3)),
1641                                    side_bldg_pos.y + side_bldg_width + 6,
1642                                )
1643                                .with_z(
1644                                    side_bldg_base - 1
1645                                        + (side_bldg_roof_height / 4)
1646                                        + (t * (side_bldg_roof_height / 3)),
1647                                ),
1648                            })
1649                            .fill(wood.clone());
1650
1651                        painter
1652                            .aabb(Aabb {
1653                                min: Vec2::new(
1654                                    side_bldg_pos.x - side_bldg_length - 6,
1655                                    side_bldg_pos.y - 2 - (side_bldg_width / 2)
1656                                        + (r * (side_bldg_width + 1)),
1657                                )
1658                                .with_z(
1659                                    side_bldg_base - 2
1660                                        + (side_bldg_roof_height / 4)
1661                                        + (t * (side_bldg_roof_height / 3)),
1662                                ),
1663                                max: Vec2::new(
1664                                    side_bldg_pos.x + side_bldg_length + 6,
1665                                    side_bldg_pos.y + 1 - (side_bldg_width / 2)
1666                                        + (r * (side_bldg_width + 1)),
1667                                )
1668                                .with_z(
1669                                    side_bldg_base - 1
1670                                        + (side_bldg_roof_height / 4)
1671                                        + (t * (side_bldg_roof_height / 3)),
1672                                ),
1673                            })
1674                            .fill(wood.clone());
1675                    }
1676                }
1677                // top gangway
1678                let gangway_handle = 2;
1679                // mark loot entry with light
1680                painter
1681                    .line(
1682                        center.with_z(side_bldg_base + (2 * castle_height) + gangway_handle),
1683                        side_bldg_pos_2
1684                            .with_z(side_bldg_base + (2 * castle_height) + gangway_handle),
1685                        6.0,
1686                    )
1687                    .fill(roof_color.clone());
1688                painter
1689                    .line(
1690                        center.with_z(side_bldg_base + (2 * castle_height) + gangway_handle),
1691                        side_bldg_pos.with_z(side_bldg_base + (2 * castle_height) + gangway_handle),
1692                        5.0,
1693                    )
1694                    .fill(wood.clone());
1695                painter
1696                    .line(
1697                        center.with_z(side_bldg_base + (2 * castle_height) + gangway_handle),
1698                        side_bldg_pos.with_z(side_bldg_base + (2 * castle_height) + gangway_handle),
1699                        4.0,
1700                    )
1701                    .clear();
1702            }
1703            // clear side_bldg room
1704            painter
1705                .aabb(Aabb {
1706                    min: Vec2::new(
1707                        side_bldg_pos.x - side_bldg_length - 3,
1708                        side_bldg_pos.y - side_bldg_width - 3,
1709                    )
1710                    .with_z(side_bldg_base),
1711                    max: Vec2::new(
1712                        side_bldg_pos.x + side_bldg_length + 3,
1713                        side_bldg_pos.y + side_bldg_width + 3,
1714                    )
1715                    .with_z(side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height) - 1),
1716                })
1717                .clear();
1718            // side bldg room decor
1719            for r in 0..2 {
1720                let row = r * (side_bldg_roof_height + (2 * side_bldg_height) - 2);
1721                painter
1722                    .aabb(Aabb {
1723                        min: Vec2::new(
1724                            side_bldg_pos.x - side_bldg_length - 3,
1725                            side_bldg_pos.y - side_bldg_width - 3,
1726                        )
1727                        .with_z(side_bldg_base + row),
1728                        max: Vec2::new(
1729                            side_bldg_pos.x + side_bldg_length + 3,
1730                            side_bldg_pos.y + side_bldg_width + 3,
1731                        )
1732                        .with_z(side_bldg_base + row + 1),
1733                    })
1734                    .fill(wood.clone());
1735                painter
1736                    .aabb(Aabb {
1737                        min: Vec2::new(
1738                            side_bldg_pos.x - side_bldg_length - 1,
1739                            side_bldg_pos.y - side_bldg_width - 1,
1740                        )
1741                        .with_z(side_bldg_base + row),
1742                        max: Vec2::new(
1743                            side_bldg_pos.x + side_bldg_length + 1,
1744                            side_bldg_pos.y + side_bldg_width + 1,
1745                        )
1746                        .with_z(side_bldg_base + row + 1),
1747                    })
1748                    .clear();
1749            }
1750            // wood decor and podiums with candle sprites
1751            let podium_limiter_1 = painter.aabb(Aabb {
1752                min: Vec2::new(
1753                    side_bldg_pos.x - side_bldg_length - 3,
1754                    side_bldg_pos.y - side_bldg_width - 3,
1755                )
1756                .with_z(side_bldg_base),
1757                max: Vec2::new(
1758                    side_bldg_pos.x + side_bldg_length + 3,
1759                    side_bldg_pos.y + side_bldg_width + 3,
1760                )
1761                .with_z(side_bldg_base + 3),
1762            });
1763            let podium_limiter_2 = painter.aabb(Aabb {
1764                min: Vec2::new(
1765                    side_bldg_pos.x - side_bldg_length - 3,
1766                    side_bldg_pos.y - side_bldg_width - 3,
1767                )
1768                .with_z(side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height) - 10),
1769                max: Vec2::new(
1770                    side_bldg_pos.x + side_bldg_length + 3,
1771                    side_bldg_pos.y + side_bldg_width + 3,
1772                )
1773                .with_z(side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height) - 6),
1774            });
1775            let mut side_bldg_beam_pos = vec![];
1776            for dir in DIAGONALS {
1777                let corner_pos = Vec2::new(
1778                    side_bldg_pos.x + (dir.x * (side_bldg_length + 2)),
1779                    side_bldg_pos.y + (dir.y * (side_bldg_width + 2)),
1780                );
1781                side_bldg_beam_pos.push(corner_pos);
1782            }
1783            for corner_pos in &side_bldg_beam_pos {
1784                for n in 0..3 {
1785                    painter
1786                        .cylinder_with_radius(
1787                            corner_pos.with_z(side_bldg_base + n),
1788                            (5 - n) as f32,
1789                            1.0,
1790                        )
1791                        .intersect(podium_limiter_1)
1792                        .fill(match n {
1793                            2 => candles.clone(),
1794                            _ => wood.clone(),
1795                        });
1796                    painter
1797                        .cylinder_with_radius(
1798                            corner_pos.with_z(
1799                                side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height)
1800                                    - 10
1801                                    + n,
1802                            ),
1803                            (2 + n) as f32,
1804                            1.0,
1805                        )
1806                        .intersect(podium_limiter_2)
1807                        .fill(wood.clone());
1808                }
1809                painter
1810                    .cylinder_with_radius(
1811                        corner_pos.with_z(
1812                            side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height) - 7,
1813                        ),
1814                        4.0,
1815                        1.0,
1816                    )
1817                    .intersect(podium_limiter_2)
1818                    .fill(candles.clone());
1819            }
1820            if b < 2 {
1821                // side_bldg stairway
1822                let side_bldg_room_stairs = painter.aabb(Aabb {
1823                    min: Vec2::new(
1824                        side_bldg_pos.x - side_bldg_length - 3,
1825                        side_bldg_pos.y - side_bldg_width - 3,
1826                    )
1827                    .with_z(side_bldg_base),
1828                    max: Vec2::new(
1829                        side_bldg_pos.x + side_bldg_length + 3,
1830                        side_bldg_pos.y + side_bldg_width + 3,
1831                    )
1832                    .with_z(side_bldg_base + (2 * castle_height) + 2),
1833                });
1834                side_bldg_room_stairs
1835                    .sample(wall_staircase(
1836                        side_bldg_pos.with_z(side_bldg_base + 1),
1837                        (side_bldg_width + 3) as f32,
1838                        side_bldg_roof_height as f32,
1839                    ))
1840                    .fill(candles_lite.clone());
1841                side_bldg_room_stairs
1842                    .sample(wall_staircase(
1843                        side_bldg_pos.with_z(side_bldg_base),
1844                        (side_bldg_width + 3) as f32,
1845                        side_bldg_roof_height as f32,
1846                    ))
1847                    .fill(wood.clone());
1848                // platforms
1849                for dir in DIAGONALS {
1850                    let chain_pos = Vec2::new(
1851                        side_bldg_pos.x + dir.x * (side_bldg_length - 4),
1852                        side_bldg_pos.y + dir.y * (side_bldg_width - 4),
1853                    );
1854                    painter
1855                        .aabb(Aabb {
1856                            min: chain_pos.with_z(castle_base + side_bldg_height - 1),
1857                            max: (chain_pos + 1).with_z(
1858                                side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height) - 1,
1859                            ),
1860                        })
1861                        .fill(chain.clone());
1862                }
1863                for p in 1..=4 {
1864                    let npc_var =
1865                        RandomField::new(0).get(side_bldg_pos.with_z(castle_base + p)) % 5;
1866
1867                    painter
1868                        .aabb(Aabb {
1869                            min: Vec2::new(
1870                                side_bldg_pos.x - side_bldg_length + 4,
1871                                side_bldg_pos.y - side_bldg_width + 4,
1872                            )
1873                            .with_z(castle_base + (side_bldg_height * p) - 2),
1874                            max: Vec2::new(
1875                                side_bldg_pos.x + side_bldg_length - 3,
1876                                side_bldg_pos.y + side_bldg_width - 3,
1877                            )
1878                            .with_z(castle_base + (side_bldg_height * p) - 1),
1879                        })
1880                        .fill(wood.clone());
1881                    if npc_var > 0 {
1882                        random_npc_positions
1883                            .push(side_bldg_pos.with_z(castle_base + (side_bldg_height * p) + 2));
1884                    }
1885                }
1886            } else {
1887                // side bldg far, foundation, entries, stairs for surrounding side bldg
1888                // side bldg entries
1889                let entry_limiter = painter.aabb(Aabb {
1890                    min: (side_bldg_pos - (2 * side_bldg_length))
1891                        .with_z(side_bldg_base + side_bldg_roof_height + (side_bldg_height / 2)),
1892                    max: (side_bldg_pos + (2 * side_bldg_length)).with_z(
1893                        side_bldg_base + side_bldg_roof_height + (side_bldg_height / 2) + 7,
1894                    ),
1895                });
1896                for dir in CARDINALS {
1897                    let entry_pos = side_bldg_pos + dir * (side_bldg_length + 4);
1898                    painter
1899                        .line(
1900                            side_bldg_pos.with_z(
1901                                side_bldg_base + side_bldg_roof_height + (side_bldg_height / 2),
1902                            ),
1903                            entry_pos.with_z(
1904                                side_bldg_base + side_bldg_roof_height + (side_bldg_height / 2),
1905                            ),
1906                            6.5,
1907                        )
1908                        .intersect(entry_limiter)
1909                        .clear();
1910                }
1911                let side_bldg_npc_pos = side_bldg_pos
1912                    .with_z(side_bldg_base + side_bldg_roof_height + (side_bldg_height / 2) + 2);
1913                random_npc_positions.push(side_bldg_npc_pos);
1914
1915                // foundation
1916                painter
1917                    .aabb(Aabb {
1918                        min: Vec2::new(
1919                            side_bldg_pos.x - side_bldg_length - 20,
1920                            side_bldg_pos.y - side_bldg_width - 20,
1921                        )
1922                        .with_z(side_bldg_base - 40),
1923                        max: Vec2::new(
1924                            side_bldg_pos.x + side_bldg_length + 20,
1925                            side_bldg_pos.y + side_bldg_width + 20,
1926                        )
1927                        .with_z(side_bldg_base + 2),
1928                    })
1929                    .fill(brick.clone());
1930                painter
1931                    .aabb(Aabb {
1932                        min: Vec2::new(
1933                            side_bldg_pos.x - side_bldg_length - 8,
1934                            side_bldg_pos.y - side_bldg_width - 8,
1935                        )
1936                        .with_z(side_bldg_base + 1),
1937                        max: Vec2::new(
1938                            side_bldg_pos.x + side_bldg_length + 8,
1939                            side_bldg_pos.y + side_bldg_width + 8,
1940                        )
1941                        .with_z(side_bldg_base + side_bldg_roof_height + (side_bldg_height / 2)),
1942                    })
1943                    .fill(brick.clone());
1944                // stairs
1945                painter
1946                    .ramp_inset(
1947                        Aabb {
1948                            min: Vec2::new(
1949                                side_bldg_pos.x - (2 * side_bldg_length) - 4,
1950                                side_bldg_pos.y - side_bldg_width - 12,
1951                            )
1952                            .with_z(side_bldg_base + 2),
1953                            max: Vec2::new(
1954                                side_bldg_pos.x + side_bldg_length + 8,
1955                                side_bldg_pos.y - side_bldg_width - 8,
1956                            )
1957                            .with_z(
1958                                side_bldg_base + side_bldg_roof_height + (side_bldg_height / 2),
1959                            ),
1960                        },
1961                        (2 * side_bldg_length) + 20,
1962                        Dir::X,
1963                    )
1964                    .fill(brick.clone());
1965                painter
1966                    .ramp_inset(
1967                        Aabb {
1968                            min: Vec2::new(
1969                                side_bldg_pos.x - side_bldg_length - 8,
1970                                side_bldg_pos.y + side_bldg_width + 8,
1971                            )
1972                            .with_z(side_bldg_base + 2),
1973                            max: Vec2::new(
1974                                side_bldg_pos.x + (2 * side_bldg_length) + 4,
1975                                side_bldg_pos.y + side_bldg_width + 12,
1976                            )
1977                            .with_z(
1978                                side_bldg_base + side_bldg_roof_height + (side_bldg_height / 2),
1979                            ),
1980                        },
1981                        (2 * side_bldg_length) + 20,
1982                        Dir::NegX,
1983                    )
1984                    .fill(brick.clone());
1985            }
1986            // side bldg wood beams
1987            for corner_pos in side_bldg_beam_pos {
1988                painter
1989                    .line(
1990                        corner_pos.with_z(side_bldg_base),
1991                        corner_pos.with_z(
1992                            side_bldg_base + side_bldg_roof_height + (2 * side_bldg_height) - 1,
1993                        ),
1994                        2.0,
1995                    )
1996                    .fill(wood.clone());
1997            }
1998        }
1999        // re clear floor cellar entry
2000        painter
2001            .cylinder(Aabb {
2002                min: (side_bldg_stairs_pos - 6).with_z(side_bldg_base_raw - 2),
2003                max: (side_bldg_stairs_pos + 6).with_z(side_bldg_base_raw - 1),
2004            })
2005            .clear();
2006        // cellar door to side_bldg
2007        painter
2008            .cylinder(Aabb {
2009                min: (side_bldg_stairs_pos - 7).with_z(side_bldg_base_raw - 1),
2010                max: (side_bldg_stairs_pos + 7).with_z(side_bldg_base_raw),
2011            })
2012            .fill(key_door.clone());
2013        painter
2014            .cylinder(Aabb {
2015                min: (side_bldg_stairs_pos - 2).with_z(side_bldg_base_raw - 1),
2016                max: (side_bldg_stairs_pos - 1).with_z(side_bldg_base_raw),
2017            })
2018            .fill(key_hole.clone());
2019        // clear castle room
2020        painter
2021            .aabb(Aabb {
2022                min: Vec2::new(center.x - castle_length - 3, center.y - castle_width - 3)
2023                    .with_z(castle_base + (castle_height / 2) + 1),
2024                max: Vec2::new(center.x + castle_length + 3, center.y + castle_width + 3)
2025                    .with_z(castle_base + (castle_height / 2) + (2 * castle_height) - 1),
2026            })
2027            .clear();
2028        // side_bldg exit to main roon
2029        let entry_side = if side_bldg_var < 1 {
2030            side_bldg_width + 3
2031        } else {
2032            -(side_bldg_width + 4)
2033        };
2034        painter
2035            .horizontal_cylinder(
2036                Aabb {
2037                    min: Vec2::new(side_bldg_pos_1.x - 4, side_bldg_pos_1.y + entry_side)
2038                        .with_z(side_bldg_base_raw + (2 * castle_height) - 2),
2039                    max: Vec2::new(side_bldg_pos_1.x + 5, side_bldg_pos_1.y + entry_side + 1)
2040                        .with_z(side_bldg_base_raw + (2 * castle_height) + 7),
2041                },
2042                Dir::NegY,
2043            )
2044            .fill(key_door.clone());
2045        painter
2046            .aabb(Aabb {
2047                min: Vec2::new(side_bldg_pos_1.x, side_bldg_pos_1.y + entry_side)
2048                    .with_z(side_bldg_base_raw + (2 * castle_height)),
2049                max: Vec2::new(side_bldg_pos_1.x + 1, side_bldg_pos_1.y + entry_side + 1)
2050                    .with_z(side_bldg_base_raw + (2 * castle_height) + 1),
2051            })
2052            .fill(key_hole.clone());
2053        painter
2054            .aabb(Aabb {
2055                min: Vec2::new(side_bldg_pos_1.x - 2, side_bldg_pos_1.y + entry_side - 7)
2056                    .with_z(side_bldg_base_raw + (2 * castle_height) - 2),
2057                max: Vec2::new(side_bldg_pos_1.x + 3, side_bldg_pos_1.y + entry_side + 8)
2058                    .with_z(side_bldg_base_raw + (2 * castle_height) - 1),
2059            })
2060            .fill(wood.clone());
2061        painter.sprite(
2062            side_bldg_pos_2.with_z(side_bldg_base_raw),
2063            SpriteKind::DungeonChest3,
2064        );
2065        // main room bossfight
2066        painter
2067            .aabb(Aabb {
2068                min: Vec2::new(center.x - castle_length - 3, center.y - castle_width - 3)
2069                    .with_z(castle_base + (2 * castle_height) - 7),
2070                max: Vec2::new(center.x + castle_length + 3, center.y + castle_width + 3)
2071                    .with_z(castle_base + (2 * castle_height) - 6),
2072            })
2073            .fill(candles_lite.clone());
2074        painter
2075            .aabb(Aabb {
2076                min: Vec2::new(center.x - castle_length - 3, center.y - castle_width - 3)
2077                    .with_z(castle_base + (2 * castle_height) - 8),
2078                max: Vec2::new(center.x + castle_length + 3, center.y + castle_width + 3)
2079                    .with_z(castle_base + (2 * castle_height) - 7),
2080            })
2081            .fill(wood.clone());
2082        painter
2083            .aabb(Aabb {
2084                min: Vec2::new(center.x - castle_length + 3, center.y - castle_width + 3)
2085                    .with_z(castle_base + (2 * castle_height) - 8),
2086                max: Vec2::new(center.x + castle_length - 3, center.y + castle_width - 3)
2087                    .with_z(castle_base + (2 * castle_height) - 6),
2088            })
2089            .clear();
2090        // castle room decor
2091        for r in 0..2 {
2092            let row = r * ((2 * castle_height) - 3);
2093            painter
2094                .aabb(Aabb {
2095                    min: Vec2::new(center.x - castle_length - 3, center.y - castle_width - 3)
2096                        .with_z(castle_base + (castle_height / 2) + 1 + row),
2097                    max: Vec2::new(center.x + castle_length + 3, center.y + castle_width + 3)
2098                        .with_z(castle_base + (castle_height / 2) + 2 + row),
2099                })
2100                .fill(wood.clone());
2101            painter
2102                .aabb(Aabb {
2103                    min: Vec2::new(center.x - castle_length - 1, center.y - castle_width - 1)
2104                        .with_z(castle_base + (castle_height / 2) + 1 + row),
2105                    max: Vec2::new(center.x + castle_length + 1, center.y + castle_width + 1)
2106                        .with_z(castle_base + (castle_height / 2) + 2 + row),
2107                })
2108                .clear();
2109        }
2110
2111        // wood decor and podiums with candle sprites
2112        let castle_podium_limiter_1 = painter.aabb(Aabb {
2113            min: Vec2::new(center.x - castle_length - 3, center.y - castle_width - 3)
2114                .with_z(castle_base + (castle_height / 2) + 1),
2115            max: Vec2::new(center.x + castle_length + 3, center.y + castle_width + 3)
2116                .with_z(castle_base + (castle_height / 2) + 4),
2117        });
2118        let castle_podium_limiter_2 = painter.aabb(Aabb {
2119            min: Vec2::new(center.x - castle_length - 3, center.y - castle_width - 3)
2120                .with_z(castle_base + (2 * castle_height) - 10),
2121            max: Vec2::new(center.x + castle_length + 3, center.y + castle_width + 3)
2122                .with_z(castle_base + (2 * castle_height) - 6),
2123        });
2124        let mut wood_beam_postions = vec![];
2125        let mut outer_beam_postions = vec![];
2126        for dir in DIAGONALS {
2127            let beam_pos_outer = Vec2::new(
2128                center.x + (dir.x * (castle_length + 2)),
2129                center.y + (dir.y * (castle_width + 2)),
2130            );
2131            let beam_pos_inner = Vec2::new(
2132                center.x + (dir.x * (castle_length / 4)),
2133                center.y + (dir.y * (castle_width + 2)),
2134            );
2135            wood_beam_postions.push(beam_pos_outer);
2136            outer_beam_postions.push(beam_pos_outer);
2137            wood_beam_postions.push(beam_pos_inner);
2138        }
2139        for beam_pos in wood_beam_postions {
2140            for n in 0..2 {
2141                painter
2142                    .cylinder_with_radius(
2143                        beam_pos.with_z(castle_base + (castle_height / 2) + 1 + n),
2144                        (5 - n) as f32,
2145                        1.0,
2146                    )
2147                    .intersect(castle_podium_limiter_1)
2148                    .fill(wood.clone());
2149            }
2150        }
2151        for beam_pos in outer_beam_postions {
2152            for n in 0..3 {
2153                painter
2154                    .cylinder_with_radius(
2155                        beam_pos.with_z(castle_base + (2 * castle_height) - 10 + n),
2156                        (2 + n) as f32,
2157                        1.0,
2158                    )
2159                    .intersect(castle_podium_limiter_2)
2160                    .fill(wood.clone());
2161            }
2162            painter
2163                .cylinder_with_radius(
2164                    beam_pos.with_z(castle_base + (2 * castle_height) - 7),
2165                    4.0,
2166                    1.0,
2167                )
2168                .intersect(castle_podium_limiter_2)
2169                .fill(candles.clone());
2170            painter
2171                .line(
2172                    beam_pos.with_z(castle_base + (castle_height / 2) + 1),
2173                    beam_pos.with_z(castle_base + (castle_height / 2) + (2 * castle_height) - 1),
2174                    2.0,
2175                )
2176                .fill(wood.clone());
2177        }
2178        // boss
2179        let boss_pos = center.with_z(castle_base + (castle_height / 2) + 2);
2180        painter.spawn(EntityInfo::at(boss_pos.as_()).with_asset_expect(
2181            "common.entity.dungeon.vampire.bloodmoon_bat",
2182            &mut thread_rng,
2183            None,
2184        ));
2185        // bats
2186        for bat_pos in bat_positions {
2187            for _ in 0..2 {
2188                painter.spawn(EntityInfo::at(bat_pos.as_()).with_asset_expect(
2189                    "common.entity.dungeon.vampire.vampire_bat",
2190                    &mut thread_rng,
2191                    None,
2192                ))
2193            }
2194        }
2195        // harlequins
2196        for harlequin_pos in harlequin_positions {
2197            painter.spawn(EntityInfo::at(harlequin_pos.as_()).with_asset_expect(
2198                "common.entity.dungeon.vampire.harlequin",
2199                &mut thread_rng,
2200                None,
2201            ))
2202        }
2203        for npc_pos in random_npc_positions {
2204            spawn_random_entity(npc_pos, painter);
2205        }
2206    }
2207}
2208
2209pub fn spawn_random_entity(pos: Vec3<i32>, painter: &Painter) {
2210    let mut rng = thread_rng();
2211    let entities = [
2212        "common.entity.dungeon.vampire.strigoi",
2213        "common.entity.dungeon.vampire.executioner",
2214        "common.entity.dungeon.vampire.bloodservant",
2215    ];
2216    let random_entity_index = rng.gen_range(0..entities.len());
2217    let random_entity = entities[random_entity_index];
2218    painter.spawn(EntityInfo::at(pos.as_()).with_asset_expect(random_entity, &mut rng, None));
2219}