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