1use std::{f32::consts::TAU, sync::Arc};
2
3use crate::{
4 Land,
5 site2::{Dir, Fill, Painter, Site, Structure, gen::spiral_staircase},
6 util::{CARDINALS, DIAGONALS, RandomField, Sampler},
7};
8use common::{
9 generation::{EntityInfo, SpecialEntity},
10 terrain::{Block, BlockKind, SpriteKind},
11};
12use rand::Rng;
13use vek::*;
14
15pub struct DesertCityArena {
16 pub(crate) alt: i32,
18 pub base: i32,
19 pub center: Vec2<i32>,
20 length: i32,
23 width: i32,
24 height: i32,
25 corner: i32,
26 wall_th: i32,
27 pillar_size: i32,
28 top_height: i32,
29 pub stand_dist: i32,
30 pub stand_length: i32,
31 pub stand_width: i32,
32}
33
34impl DesertCityArena {
35 pub fn generate(land: &Land, _rng: &mut impl Rng, site: &Site, tile_aabr: Aabr<i32>) -> Self {
36 let bounds = Aabr {
37 min: site.tile_wpos(tile_aabr.min),
38 max: site.tile_wpos(tile_aabr.max),
39 };
40 let alt = land.get_alt_approx(site.tile_center_wpos((tile_aabr.max - tile_aabr.min) / 2))
41 as i32
42 + 2;
43 let base = alt + 1;
44 let center = bounds.center();
45 let length = 160;
48 let width = length / 2;
49 let height = length / 6;
50 let corner = length / 5;
51 let wall_th = 3;
52 let pillar_size = (length / 15) - wall_th;
53 let top_height = 3;
54 let stand_dist = length / 3;
55 let stand_length = length / 6;
56 let stand_width = length / 16;
57
58 Self {
59 alt,
60 base,
61 center,
62 length,
63 width,
64 height,
65 corner,
66 wall_th,
67 pillar_size,
68 top_height,
69 stand_dist,
70 stand_length,
71 stand_width,
72 }
73 }
74
75 pub fn radius(&self) -> f32 { 100.0 }
76
77 pub fn entity_at(
78 &self,
79 _pos: Vec3<i32>,
80 _above_block: &Block,
81 _dynamic_rng: &mut impl Rng,
82 ) -> Option<EntityInfo> {
83 None
84 }
85}
86
87impl Structure for DesertCityArena {
88 #[cfg(feature = "use-dyn-lib")]
89 const UPDATE_FN: &'static [u8] = b"render_arena\0";
90
91 #[cfg_attr(feature = "be-dyn-lib", export_name = "render_arena")]
92 fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
93 let base = self.base;
94 let center = self.center;
95
96 let length = self.length;
99 let width = self.width;
100 let height = self.height;
101 let corner = self.corner;
102 let wall_th = self.wall_th;
103 let pillar_size = self.pillar_size;
104 let top_height = self.top_height;
105
106 let sandstone = Fill::Sampling(Arc::new(|center| {
107 Some(match (RandomField::new(0).get(center)) % 37 {
108 0..=8 => Block::new(BlockKind::Rock, Rgb::new(245, 212, 129)),
109 9..=17 => Block::new(BlockKind::Rock, Rgb::new(246, 214, 133)),
110 18..=26 => Block::new(BlockKind::Rock, Rgb::new(247, 216, 136)),
111 27..=35 => Block::new(BlockKind::Rock, Rgb::new(248, 219, 142)),
112 _ => Block::new(BlockKind::Rock, Rgb::new(235, 178, 99)),
113 })
114 }));
115 let color = Fill::Block(Block::new(BlockKind::Rock, Rgb::new(19, 48, 76)));
116 let chain = Fill::Block(Block::air(SpriteKind::SeaDecorChain));
117 let lantern = Fill::Block(Block::air(SpriteKind::Lantern));
118
119 for l in 0..8 {
121 painter
122 .aabb(Aabb {
123 min: (center - (length / 2) - l).with_z(base + l),
124 max: (center + (length / 2) + l).with_z(base + 1 + l),
125 })
126 .clear();
127 }
128 let top_1 = painter.aabb(Aabb {
130 min: Vec2::new(
131 center.x - (length / 2) - (2 * wall_th),
132 center.y - (width / 2) - (2 * wall_th),
133 )
134 .with_z(base + height + wall_th),
135 max: Vec2::new(
136 center.x + (length / 2) + (2 * wall_th),
137 center.y + (width / 2) + (2 * wall_th),
138 )
139 .with_z(base + height + wall_th + top_height),
140 });
141 let top_2 = painter.aabb(Aabb {
142 min: Vec2::new(
143 center.x - (length / 2) - (2 * wall_th) + corner,
144 center.y - (width / 2) - corner - (2 * wall_th),
145 )
146 .with_z(base + height + wall_th),
147 max: Vec2::new(
148 center.x + (length / 2) + (2 * wall_th) - corner,
149 center.y + (width / 2) + corner + (2 * wall_th),
150 )
151 .with_z(base + height + wall_th + top_height),
152 });
153 top_1.union(top_2).fill(sandstone.clone());
154 let top_carve_1 = painter.aabb(Aabb {
155 min: Vec2::new(
156 center.x - (length / 2) - (2 * wall_th) + 1,
157 center.y - (width / 2) - (2 * wall_th) + 1,
158 )
159 .with_z(base + height + wall_th + top_height - 2),
160 max: Vec2::new(
161 center.x + (length / 2) + (2 * wall_th) - 1,
162 center.y + (width / 2) + (2 * wall_th) - 1,
163 )
164 .with_z(base + height + wall_th + top_height),
165 });
166 let top_carve_2 = painter.aabb(Aabb {
167 min: Vec2::new(
168 center.x - (length / 2) - (2 * wall_th) + corner + 1,
169 center.y - (width / 2) - corner - (2 * wall_th) + 1,
170 )
171 .with_z(base + height + wall_th + top_height - 2),
172 max: Vec2::new(
173 center.x + (length / 2) + (2 * wall_th) - corner - 1,
174 center.y + (width / 2) + corner + (2 * wall_th) - 1,
175 )
176 .with_z(base + height + wall_th + 3),
177 });
178 top_carve_1.union(top_carve_2).clear();
179
180 let carve_dots = 80.0_f32;
181 let carve_dots_radius = length + (length / 2);
182 let phi_carve_dots = TAU / carve_dots;
183 for n in 1..=carve_dots as i32 {
184 let dot_pos = Vec2::new(
185 center.x + (carve_dots_radius as f32 * ((n as f32 * phi_carve_dots).cos())) as i32,
186 center.y + (carve_dots_radius as f32 * ((n as f32 * phi_carve_dots).sin())) as i32,
187 );
188 painter
190 .line(
191 center.with_z(base + height + wall_th + 2),
192 dot_pos.with_z(base + height + wall_th + 2),
193 1.5,
194 )
195 .clear();
196 }
197
198 let mut pillar_positions = vec![];
200 let mut pillars = vec![];
201 let mut spire_positions = vec![];
202
203 for dir in DIAGONALS {
204 let inner_square_pos = center + (dir * ((length / 2) - corner - wall_th));
205 let outer_square_pos_1 = Vec2::new(
206 center.x + (dir.x * ((length / 2) + (corner / 8) - wall_th)),
207 center.y + (dir.y * ((width / 2) - wall_th)),
208 );
209 let outer_square_pos_2 = Vec2::new(
210 center.x + (dir.x * ((length / 2) - corner - wall_th)),
211 center.y + (dir.y * ((width / 2) + (5 * (corner / 4)) - wall_th)),
212 );
213 pillar_positions.push(inner_square_pos);
214 pillar_positions.push(outer_square_pos_1);
215 pillar_positions.push(outer_square_pos_2);
216
217 let spire_pos_1 = Vec2::new(
218 center.x + (dir.x * (length / 10)),
219 center.y + (dir.y * (2 * (length / 5))),
220 );
221
222 let spire_pos_2 = Vec2::new(
223 center.x + (dir.y * (2 * (length / 5))),
224 center.y + (dir.x * (length / 11)),
225 );
226 spire_positions.push(spire_pos_1);
227 spire_positions.push(spire_pos_2);
228 }
229 for pillar_pos in pillar_positions {
230 let height_var = (RandomField::new(0).get(pillar_pos.with_z(base)) % 20) as i32;
231 let pillar_height = height + 8 + height_var;
232 pillars.push((pillar_pos, pillar_height));
233 }
234 for (pillar_pos, pillar_height) in &pillars {
235 painter
237 .aabb(Aabb {
238 min: (pillar_pos - pillar_size - wall_th).with_z(base - 10),
239 max: (pillar_pos + pillar_size + wall_th)
240 .with_z(base + pillar_height + wall_th),
241 })
242 .fill(sandstone.clone());
243 painter
245 .aabb(Aabb {
246 min: Vec2::new(
247 pillar_pos.x - pillar_size - wall_th,
248 pillar_pos.y - pillar_size,
249 )
250 .with_z(base),
251 max: Vec2::new(
252 pillar_pos.x + pillar_size + wall_th,
253 pillar_pos.y + pillar_size,
254 )
255 .with_z(base + pillar_height),
256 })
257 .clear();
258 painter
259 .aabb(Aabb {
260 min: Vec2::new(
261 pillar_pos.x - pillar_size,
262 pillar_pos.y - pillar_size - wall_th,
263 )
264 .with_z(base),
265 max: Vec2::new(
266 pillar_pos.x + pillar_size,
267 pillar_pos.y + pillar_size + wall_th,
268 )
269 .with_z(base + pillar_height),
270 })
271 .clear();
272 for dir in DIAGONALS {
274 for c in 0..((pillar_height / 2) - 1) {
275 let carve_pos = pillar_pos + (dir * (pillar_size + wall_th));
276 painter
277 .aabb(Aabb {
278 min: (carve_pos - 1).with_z(base + wall_th + (c * 2)),
279 max: (carve_pos + 1).with_z(base + 1 + wall_th + (c * 2)),
280 })
281 .clear();
282 }
283 }
284 for d in 0..3 {
286 painter
288 .horizontal_cylinder(
289 Aabb {
290 min: Vec2::new(
291 pillar_pos.x - pillar_size - 1,
292 pillar_pos.y - 7 + (d * 5),
293 )
294 .with_z(base + pillar_height - 6),
295 max: Vec2::new(
296 pillar_pos.x + pillar_size + 1,
297 pillar_pos.y - 3 + (d * 5),
298 )
299 .with_z(base + pillar_height),
300 },
301 Dir::X,
302 )
303 .fill(sandstone.clone());
304 painter
305 .horizontal_cylinder(
306 Aabb {
307 min: Vec2::new(
308 pillar_pos.x - pillar_size - 1,
309 pillar_pos.y - 6 + (d * 5),
310 )
311 .with_z(base + pillar_height - 5),
312 max: Vec2::new(
313 pillar_pos.x + pillar_size + 1,
314 pillar_pos.y - 4 + (d * 5),
315 )
316 .with_z(base + pillar_height - 1),
317 },
318 Dir::X,
319 )
320 .clear();
321
322 painter
324 .horizontal_cylinder(
325 Aabb {
326 min: Vec2::new(
327 pillar_pos.x - 7 + (d * 5),
328 pillar_pos.y - pillar_size - 1,
329 )
330 .with_z(base + pillar_height - 6),
331 max: Vec2::new(
332 pillar_pos.x - 3 + (d * 5),
333 pillar_pos.y + pillar_size + 1,
334 )
335 .with_z(base + pillar_height),
336 },
337 Dir::Y,
338 )
339 .fill(sandstone.clone());
340 painter
341 .horizontal_cylinder(
342 Aabb {
343 min: Vec2::new(
344 pillar_pos.x - 6 + (d * 5),
345 pillar_pos.y - pillar_size - 1,
346 )
347 .with_z(base + pillar_height - 5),
348 max: Vec2::new(
349 pillar_pos.x - 4 + (d * 5),
350 pillar_pos.y + pillar_size + 1,
351 )
352 .with_z(base + pillar_height - 1),
353 },
354 Dir::Y,
355 )
356 .clear();
357 }
358 painter
361 .vault(
362 Aabb {
363 min: Vec2::new(
364 pillar_pos.x - pillar_size,
365 pillar_pos.y - pillar_size - wall_th + 1,
366 )
367 .with_z(base),
368 max: Vec2::new(
369 pillar_pos.x + pillar_size,
370 pillar_pos.y + pillar_size + wall_th - 1,
371 )
372 .with_z(base + (4 * pillar_size) + 2),
373 },
374 Dir::Y,
375 )
376 .fill(sandstone.clone());
377 painter
378 .vault(
379 Aabb {
380 min: Vec2::new(
381 pillar_pos.x - pillar_size + 2,
382 pillar_pos.y - pillar_size - wall_th + 1,
383 )
384 .with_z(base),
385 max: Vec2::new(
386 pillar_pos.x + pillar_size - 2,
387 pillar_pos.y + pillar_size + wall_th - 1,
388 )
389 .with_z(base + (4 * pillar_size)),
390 },
391 Dir::Y,
392 )
393 .clear();
394 painter
396 .vault(
397 Aabb {
398 min: Vec2::new(
399 pillar_pos.x - pillar_size + 2,
400 pillar_pos.y - pillar_size - wall_th + 2,
401 )
402 .with_z(base),
403 max: Vec2::new(
404 pillar_pos.x + pillar_size - 2,
405 pillar_pos.y + pillar_size + wall_th - 2,
406 )
407 .with_z(base + (4 * pillar_size)),
408 },
409 Dir::Y,
410 )
411 .fill(sandstone.clone());
412 painter
413 .vault(
414 Aabb {
415 min: Vec2::new(
416 pillar_pos.x - pillar_size + 4,
417 pillar_pos.y - pillar_size - wall_th + 2,
418 )
419 .with_z(base),
420 max: Vec2::new(
421 pillar_pos.x + pillar_size - 4,
422 pillar_pos.y + pillar_size + wall_th - 2,
423 )
424 .with_z(base + (4 * pillar_size) - 2),
425 },
426 Dir::Y,
427 )
428 .clear();
429 painter
431 .vault(
432 Aabb {
433 min: Vec2::new(
434 pillar_pos.x - pillar_size - wall_th + 1,
435 pillar_pos.y - pillar_size,
436 )
437 .with_z(base),
438 max: Vec2::new(
439 pillar_pos.x + pillar_size + wall_th - 1,
440 pillar_pos.y + pillar_size,
441 )
442 .with_z(base + (4 * pillar_size) + 2),
443 },
444 Dir::X,
445 )
446 .fill(sandstone.clone());
447 painter
448 .vault(
449 Aabb {
450 min: Vec2::new(
451 pillar_pos.x - pillar_size - wall_th + 1,
452 pillar_pos.y - pillar_size + 2,
453 )
454 .with_z(base),
455 max: Vec2::new(
456 pillar_pos.x + pillar_size + wall_th - 1,
457 pillar_pos.y + pillar_size - 2,
458 )
459 .with_z(base + (4 * pillar_size)),
460 },
461 Dir::X,
462 )
463 .clear();
464 painter
466 .vault(
467 Aabb {
468 min: Vec2::new(
469 pillar_pos.x - pillar_size - wall_th + 2,
470 pillar_pos.y - pillar_size + 2,
471 )
472 .with_z(base),
473 max: Vec2::new(
474 pillar_pos.x + pillar_size + wall_th - 2,
475 pillar_pos.y + pillar_size - 2,
476 )
477 .with_z(base + (4 * pillar_size)),
478 },
479 Dir::X,
480 )
481 .fill(sandstone.clone());
482 painter
483 .vault(
484 Aabb {
485 min: Vec2::new(
486 pillar_pos.x - pillar_size - wall_th + 2,
487 pillar_pos.y - pillar_size + 4,
488 )
489 .with_z(base),
490 max: Vec2::new(
491 pillar_pos.x + pillar_size + wall_th - 2,
492 pillar_pos.y + pillar_size - 4,
493 )
494 .with_z(base + (4 * pillar_size) - 2),
495 },
496 Dir::X,
497 )
498 .clear();
499 painter
501 .aabb(Aabb {
502 min: (pillar_pos - pillar_size - (2 * wall_th))
503 .with_z(base + pillar_height + wall_th),
504 max: (pillar_pos + pillar_size + (2 * wall_th))
505 .with_z(base + pillar_height + wall_th + top_height),
506 })
507 .fill(sandstone.clone());
508 painter
509 .aabb(Aabb {
510 min: (pillar_pos - pillar_size - (2 * wall_th) + 1)
511 .with_z(base + pillar_height + wall_th + top_height - 2),
512 max: (pillar_pos + pillar_size + (2 * wall_th) - 1)
513 .with_z(base + pillar_height + wall_th + top_height),
514 })
515 .clear();
516
517 let pillar_inlay = painter.aabb(Aabb {
518 min: (pillar_pos - pillar_size).with_z(base),
519 max: (pillar_pos + pillar_size).with_z(base + pillar_height),
520 });
521 pillar_inlay.fill(color.clone());
522 for r in 0..(pillar_height - 3) {
524 let dots = 8.0_f32 + (r / 3) as f32;
525 let dots_radius = 2 * pillar_size;
526 let phi_dots = TAU / dots;
527 for n in 1..=dots as i32 {
528 let dot_pos = Vec2::new(
529 pillar_pos.x + (dots_radius as f32 * ((n as f32 * phi_dots).cos())) as i32,
530 pillar_pos.y + (dots_radius as f32 * ((n as f32 * phi_dots).sin())) as i32,
531 );
532 if dots == 16.0_f32 {
533 painter
535 .line(
536 pillar_pos.with_z(base + pillar_height + wall_th + 2),
537 dot_pos.with_z(base + pillar_height + wall_th + 2),
538 1.5,
539 )
540 .clear();
541 }
542 painter
544 .line(
545 pillar_pos.with_z(base + (r * 2)),
546 dot_pos.with_z(base + (r * 2)),
547 0.5,
548 )
549 .intersect(pillar_inlay)
550 .fill(sandstone.clone());
551 }
552 }
553 }
554
555 let outer_aabb_1 = painter.aabb(Aabb {
557 min: Vec2::new(
558 center.x - (length / 2) - wall_th,
559 center.y - (width / 2) - wall_th,
560 )
561 .with_z(base - 10),
562 max: Vec2::new(
563 center.x + (length / 2) + wall_th,
564 center.y + (width / 2) + wall_th,
565 )
566 .with_z(base + height + wall_th),
567 });
568 let outer_aabb_2 = painter.aabb(Aabb {
569 min: Vec2::new(
570 center.x - (length / 2) - wall_th + corner,
571 center.y - (width / 2) - corner - wall_th,
572 )
573 .with_z(base - 10),
574 max: Vec2::new(
575 center.x + (length / 2) + wall_th - corner,
576 center.y + (width / 2) + corner + wall_th,
577 )
578 .with_z(base + height + wall_th),
579 });
580 outer_aabb_1.union(outer_aabb_2).fill(sandstone.clone());
581 let clear_aabb_1 = painter.aabb(Aabb {
583 min: Vec2::new(center.x - (length / 2) - wall_th, center.y - (width / 2)).with_z(base),
584 max: Vec2::new(center.x + (length / 2) + wall_th, center.y + (width / 2))
585 .with_z(base + height),
586 });
587 let clear_aabb_2 = painter.aabb(Aabb {
588 min: Vec2::new(center.x - (length / 2), center.y - (width / 2) - wall_th).with_z(base),
589 max: Vec2::new(center.x + (length / 2), center.y + (width / 2) + wall_th)
590 .with_z(base + height),
591 });
592 clear_aabb_1.union(clear_aabb_2).clear();
593 let clear_aabb_3 = painter.aabb(Aabb {
594 min: Vec2::new(
595 center.x - (length / 2) - wall_th + corner,
596 center.y - (width / 2) - corner,
597 )
598 .with_z(base),
599 max: Vec2::new(
600 center.x + (length / 2) + wall_th - corner,
601 center.y + (width / 2) + corner,
602 )
603 .with_z(base + height),
604 });
605 let clear_aabb_4 = painter.aabb(Aabb {
606 min: Vec2::new(
607 center.x - (length / 2) + corner,
608 center.y - (width / 2) - wall_th - corner,
609 )
610 .with_z(base),
611 max: Vec2::new(
612 center.x + (length / 2) - corner,
613 center.y + (width / 2) + wall_th + corner,
614 )
615 .with_z(base + height),
616 });
617 clear_aabb_3.union(clear_aabb_4).clear();
618 let inlay_aabb_1 = painter.aabb(Aabb {
620 min: Vec2::new(center.x - (length / 2), center.y - (width / 2)).with_z(base),
621 max: Vec2::new(center.x + (length / 2), center.y + (width / 2)).with_z(base + height),
622 });
623 let inlay_aabb_2 = painter.aabb(Aabb {
624 min: Vec2::new(
625 center.x - (length / 2) + corner,
626 center.y - (width / 2) - corner,
627 )
628 .with_z(base),
629 max: Vec2::new(
630 center.x + (length / 2) - corner,
631 center.y + (width / 2) + corner,
632 )
633 .with_z(base + height),
634 });
635 inlay_aabb_1.union(inlay_aabb_2).fill(color.clone());
636 let inlay = inlay_aabb_1.union(inlay_aabb_2);
637 for r in 0..(height - 3) {
638 let dots = 50.0_f32 + (3 * r) as f32;
639 let dots_radius = length + (length / 2);
640 let phi_dots = TAU / dots;
641 for n in 1..=dots as i32 {
642 let dot_pos = Vec2::new(
643 center.x + (dots_radius as f32 * ((n as f32 * phi_dots).cos())) as i32,
644 center.y + (dots_radius as f32 * ((n as f32 * phi_dots).sin())) as i32,
645 );
646 painter
648 .line(
649 center.with_z(base + (r * 2)),
650 dot_pos.with_z(base + (r * 2)),
651 1.0,
652 )
653 .intersect(inlay)
654 .fill(sandstone.clone());
655 }
656 }
657 painter
659 .vault(
660 Aabb {
661 min: Vec2::new(center.x - (length / 2) - wall_th, center.y - 10).with_z(base),
662 max: Vec2::new(center.x + (length / 2) + wall_th, center.y + 10)
663 .with_z(base + (height / 2) + 8),
664 },
665 Dir::X,
666 )
667 .fill(sandstone.clone());
668 painter
669 .vault(
670 Aabb {
671 min: Vec2::new(center.x - 10, center.y - (width / 2) - corner - wall_th)
672 .with_z(base),
673 max: Vec2::new(center.x + 10, center.y + (width / 2) + corner + wall_th)
674 .with_z(base + (height / 2) + 8),
675 },
676 Dir::Y,
677 )
678 .fill(sandstone.clone());
679 painter
680 .vault(
681 Aabb {
682 min: Vec2::new(center.x - (length / 2) - wall_th, center.y - 10 + wall_th)
683 .with_z(base),
684 max: Vec2::new(center.x + (length / 2) + wall_th, center.y + 10 - wall_th)
685 .with_z(base + (height / 2) + 8 - wall_th),
686 },
687 Dir::X,
688 )
689 .clear();
690 painter
691 .vault(
692 Aabb {
693 min: Vec2::new(
694 center.x - 10 + wall_th,
695 center.y - (width / 2) - corner - wall_th,
696 )
697 .with_z(base),
698 max: Vec2::new(
699 center.x + 10 - wall_th,
700 center.y + (width / 2) + corner + wall_th,
701 )
702 .with_z(base + (height / 2) + 8 - wall_th),
703 },
704 Dir::Y,
705 )
706 .clear();
707 painter
709 .aabb(Aabb {
710 min: Vec2::new(
711 center.x - (length / 2) + corner + (2 * wall_th) + pillar_size,
712 center.y - (length / 2) + corner + (2 * wall_th) + pillar_size,
713 )
714 .with_z(base + height),
715 max: Vec2::new(
716 center.x + (length / 2) - corner - (2 * wall_th) - pillar_size,
717 center.y + (length / 2) - corner - (2 * wall_th) - pillar_size,
718 )
719 .with_z(base + height + wall_th + top_height - 2),
720 })
721 .clear();
722 painter
723 .aabb(Aabb {
724 min: Vec2::new(
725 center.x - (length / 2) + corner + wall_th,
726 center.y - (length / 2) + corner + wall_th,
727 )
728 .with_z(base - 1),
729 max: Vec2::new(
730 center.x + (length / 2) - corner - wall_th,
731 center.y + (length / 2) - corner - wall_th,
732 )
733 .with_z(base + height),
734 })
735 .clear();
736 for d in 0..((length / 12) - 2) {
738 painter
740 .horizontal_cylinder(
741 Aabb {
742 min: Vec2::new(
743 center.x - 3 - (length / 2)
744 + corner
745 + (3 * wall_th)
746 + pillar_size
747 + (6 * d)
748 + 2,
749 center.y - (length / 2) + corner + (2 * wall_th) + pillar_size - 1,
750 )
751 .with_z(base + height + wall_th + top_height - 7),
752 max: Vec2::new(
753 center.x + 3 - (length / 2)
754 + corner
755 + (3 * wall_th)
756 + pillar_size
757 + (6 * d)
758 + 2,
759 center.y + (length / 2) - corner - (2 * wall_th) - pillar_size + 1,
760 )
761 .with_z(base + height + wall_th + top_height - 1),
762 },
763 Dir::Y,
764 )
765 .fill(sandstone.clone());
766 painter
767 .horizontal_cylinder(
768 Aabb {
769 min: Vec2::new(
770 center.x - 3 - (length / 2)
771 + corner
772 + (3 * wall_th)
773 + pillar_size
774 + (6 * d)
775 + 2,
776 center.y - (length / 2) + corner + (2 * wall_th) + pillar_size,
777 )
778 .with_z(base + height + wall_th + top_height - 7),
779 max: Vec2::new(
780 center.x + 3 - (length / 2)
781 + corner
782 + (3 * wall_th)
783 + pillar_size
784 + (6 * d)
785 + 2,
786 center.y + (length / 2) - corner - (2 * wall_th) - pillar_size,
787 )
788 .with_z(base + height + wall_th + top_height - 1),
789 },
790 Dir::Y,
791 )
792 .clear();
793 painter
794 .horizontal_cylinder(
795 Aabb {
796 min: Vec2::new(
797 center.x - 2 - (length / 2)
798 + corner
799 + (3 * wall_th)
800 + pillar_size
801 + (6 * d)
802 + 2,
803 center.y - (length / 2) + corner + (2 * wall_th) + pillar_size - 2,
804 )
805 .with_z(base + height + wall_th + top_height - 6),
806 max: Vec2::new(
807 center.x + 2 - (length / 2)
808 + corner
809 + (3 * wall_th)
810 + pillar_size
811 + (6 * d)
812 + 2,
813 center.y + (length / 2) - corner - (2 * wall_th) - pillar_size + 2,
814 )
815 .with_z(base + height + wall_th + top_height - 2),
816 },
817 Dir::Y,
818 )
819 .fill(color.clone());
820 painter
821 .horizontal_cylinder(
822 Aabb {
823 min: Vec2::new(
824 center.x - 2 - (length / 2)
825 + corner
826 + (3 * wall_th)
827 + pillar_size
828 + (6 * d)
829 + 2,
830 center.y - (length / 2) + corner + (2 * wall_th) + pillar_size - 1,
831 )
832 .with_z(base + height + wall_th + top_height - 6),
833 max: Vec2::new(
834 center.x + 2 - (length / 2)
835 + corner
836 + (3 * wall_th)
837 + pillar_size
838 + (6 * d)
839 + 2,
840 center.y + (length / 2) - corner - (2 * wall_th) - pillar_size + 1,
841 )
842 .with_z(base + height + wall_th + top_height - 2),
843 },
844 Dir::Y,
845 )
846 .clear();
847 }
848 for e in 0..(length / 14) {
849 painter
851 .horizontal_cylinder(
852 Aabb {
853 min: Vec2::new(
854 center.x - (length / 2) + corner + (2 * wall_th) + pillar_size - 1,
855 center.y - 3 - (length / 2)
856 + corner
857 + (2 * wall_th)
858 + pillar_size
859 + (6 * e)
860 + 5,
861 )
862 .with_z(base + height + wall_th + top_height - 7),
863 max: Vec2::new(
864 center.x + (length / 2) - corner - (2 * wall_th) - pillar_size + 1,
865 center.y + 3 - (length / 2)
866 + corner
867 + (2 * wall_th)
868 + pillar_size
869 + (6 * e)
870 + 5,
871 )
872 .with_z(base + height + wall_th + top_height - 1),
873 },
874 Dir::X,
875 )
876 .fill(sandstone.clone());
877 painter
878 .horizontal_cylinder(
879 Aabb {
880 min: Vec2::new(
881 center.x - (length / 2) + corner + (2 * wall_th) + pillar_size,
882 center.y - 3 - (length / 2)
883 + corner
884 + (2 * wall_th)
885 + pillar_size
886 + (6 * e)
887 + 5,
888 )
889 .with_z(base + height + wall_th + top_height - 7),
890 max: Vec2::new(
891 center.x + (length / 2) - corner - (2 * wall_th) - pillar_size,
892 center.y + 3 - (length / 2)
893 + corner
894 + (2 * wall_th)
895 + pillar_size
896 + (6 * e)
897 + 5,
898 )
899 .with_z(base + height + wall_th + top_height - 1),
900 },
901 Dir::X,
902 )
903 .clear();
904 painter
905 .horizontal_cylinder(
906 Aabb {
907 min: Vec2::new(
908 center.x - (length / 2) + corner + (2 * wall_th) + pillar_size - 2,
909 center.y - 2 - (length / 2)
910 + corner
911 + (2 * wall_th)
912 + pillar_size
913 + (6 * e)
914 + 5,
915 )
916 .with_z(base + height + wall_th + top_height - 6),
917 max: Vec2::new(
918 center.x + (length / 2) - corner - (2 * wall_th) - pillar_size + 2,
919 center.y + 2 - (length / 2)
920 + corner
921 + (2 * wall_th)
922 + pillar_size
923 + (6 * e)
924 + 5,
925 )
926 .with_z(base + height + wall_th + top_height - 2),
927 },
928 Dir::X,
929 )
930 .fill(color.clone());
931 painter
932 .horizontal_cylinder(
933 Aabb {
934 min: Vec2::new(
935 center.x - (length / 2) + corner + (2 * wall_th) + pillar_size - 1,
936 center.y - 2 - (length / 2)
937 + corner
938 + (2 * wall_th)
939 + pillar_size
940 + (6 * e)
941 + 5,
942 )
943 .with_z(base + height + wall_th + top_height - 6),
944 max: Vec2::new(
945 center.x + (length / 2) - corner - (2 * wall_th) - pillar_size + 1,
946 center.y + 2 - (length / 2)
947 + corner
948 + (2 * wall_th)
949 + pillar_size
950 + (6 * e)
951 + 5,
952 )
953 .with_z(base + height + wall_th + top_height - 2),
954 },
955 Dir::X,
956 )
957 .clear();
958 }
959
960 for dir in CARDINALS {
962 let step_pos = Vec2::new(
963 center.x + (dir.x * (length / 2)),
964 center.y + (dir.y * ((width / 2) + corner)),
965 );
966 for s in 0..9 {
967 painter
968 .aabb(Aabb {
969 min: (step_pos - 7 - s).with_z(base - 2 - s),
970 max: (step_pos + 7 + s).with_z(base - 1 - s),
971 })
972 .fill(sandstone.clone());
973 }
974 }
975 for r in 0..2 {
977 let room_pos_1 = Vec2::new(
978 center.x - (length / 2) + (length / 8) + (r * (length - (length / 4))),
979 center.y,
980 );
981 let room_pos_2 = Vec2::new(
982 center.x,
983 center.y - (width / 2) - (corner / 2) + (r * (width + corner)),
984 );
985
986 painter
987 .aabb(Aabb {
988 min: Vec2::new(
989 room_pos_1.x - (length / 8) + wall_th,
990 room_pos_1.y - (width / 2) + wall_th,
991 )
992 .with_z(base - 1),
993 max: Vec2::new(
994 room_pos_1.x + (length / 8) - wall_th,
995 room_pos_1.y + (width / 2) - wall_th,
996 )
997 .with_z(base + height),
998 })
999 .clear();
1000 painter
1001 .aabb(Aabb {
1002 min: Vec2::new(
1003 room_pos_2.x - (length / 2) + corner + wall_th,
1004 room_pos_2.y - (corner / 2) + wall_th,
1005 )
1006 .with_z(base - 1),
1007 max: Vec2::new(
1008 room_pos_2.x + (length / 2) - corner - wall_th,
1009 room_pos_2.y + (corner / 2) - wall_th,
1010 )
1011 .with_z(base + height),
1012 })
1013 .clear();
1014 for s in 0..1 {
1016 let stand_dist = self.stand_dist;
1018 let stand_length = self.stand_length;
1019 let stand_width = self.stand_width;
1020 let floor = s * (height + wall_th + top_height - 1);
1021
1022 painter
1023 .ramp_inset(
1024 Aabb {
1025 min: Vec2::new(center.x - stand_length - 1, center.y - stand_dist)
1026 .with_z(base - 1 + floor),
1027 max: Vec2::new(
1028 center.x + stand_length + 1,
1029 center.y - stand_dist + stand_width,
1030 )
1031 .with_z(base + (length / 16) - 1 + floor),
1032 },
1033 length / 16,
1034 Dir::NegY,
1035 )
1036 .fill(color.clone());
1037 painter
1038 .ramp_inset(
1039 Aabb {
1040 min: Vec2::new(center.x - stand_length, center.y - stand_dist)
1041 .with_z(base - 1 + floor),
1042 max: Vec2::new(
1043 center.x + stand_length,
1044 center.y - stand_dist + stand_width,
1045 )
1046 .with_z(base + (length / 16) - 1 + floor),
1047 },
1048 length / 16,
1049 Dir::NegY,
1050 )
1051 .fill(sandstone.clone());
1052 painter
1053 .ramp_inset(
1054 Aabb {
1055 min: Vec2::new(
1056 center.x - stand_length - 1,
1057 center.y + stand_dist - stand_width,
1058 )
1059 .with_z(base - 1 + floor),
1060 max: Vec2::new(center.x + stand_length + 1, center.y + stand_dist)
1061 .with_z(base + (length / 16) - 1 + floor),
1062 },
1063 length / 16,
1064 Dir::Y,
1065 )
1066 .fill(color.clone());
1067
1068 painter
1069 .ramp_inset(
1070 Aabb {
1071 min: Vec2::new(
1072 center.x - stand_length,
1073 center.y + stand_dist - stand_width,
1074 )
1075 .with_z(base - 1 + floor),
1076 max: Vec2::new(center.x + stand_length, center.y + stand_dist)
1077 .with_z(base + (length / 16) - 1 + floor),
1078 },
1079 length / 16,
1080 Dir::Y,
1081 )
1082 .fill(sandstone.clone());
1083 painter
1084 .ramp_inset(
1085 Aabb {
1086 min: Vec2::new(center.x - stand_dist, center.y - stand_length - 1)
1087 .with_z(base - 1 + floor),
1088 max: Vec2::new(
1089 center.x - stand_dist + stand_width,
1090 center.y + stand_length + 1,
1091 )
1092 .with_z(base + (length / 16) - 1 + floor),
1093 },
1094 length / 16,
1095 Dir::NegX,
1096 )
1097 .fill(color.clone());
1098 painter
1099 .ramp_inset(
1100 Aabb {
1101 min: Vec2::new(center.x - stand_dist, center.y - stand_length)
1102 .with_z(base - 1 + floor),
1103 max: Vec2::new(
1104 center.x - stand_dist + stand_width,
1105 center.y + stand_length,
1106 )
1107 .with_z(base + (length / 16) - 1 + floor),
1108 },
1109 length / 16,
1110 Dir::NegX,
1111 )
1112 .fill(sandstone.clone());
1113 painter
1114 .ramp_inset(
1115 Aabb {
1116 min: Vec2::new(
1117 center.x + stand_dist - stand_width,
1118 center.y - stand_length - 1,
1119 )
1120 .with_z(base - 1 + floor),
1121 max: Vec2::new(center.x + stand_dist, center.y + stand_length + 1)
1122 .with_z(base + (length / 16) - 1 + floor),
1123 },
1124 length / 16,
1125 Dir::X,
1126 )
1127 .fill(color.clone());
1128 painter
1129 .ramp_inset(
1130 Aabb {
1131 min: Vec2::new(
1132 center.x + stand_dist - stand_width,
1133 center.y - stand_length,
1134 )
1135 .with_z(base - 1 + floor),
1136 max: Vec2::new(center.x + stand_dist, center.y + stand_length)
1137 .with_z(base + (length / 16) - 1 + floor),
1138 },
1139 length / 16,
1140 Dir::X,
1141 )
1142 .fill(sandstone.clone());
1143 }
1144 }
1145 for (pillar_pos, pillar_height) in pillars {
1146 let stairs_radius = pillar_size - 1;
1147 let stairs = painter.aabb(Aabb {
1148 min: (pillar_pos - stairs_radius).with_z(base - 1),
1149 max: (pillar_pos + stairs_radius).with_z(base + pillar_height + wall_th + 1),
1150 });
1151 stairs.clear();
1152 stairs
1153 .sample(spiral_staircase(
1154 pillar_pos.with_z(base + pillar_height + wall_th + 1),
1155 (stairs_radius + 2) as f32,
1156 0.5,
1157 ((pillar_height + wall_th + top_height) / 3) as f32,
1158 ))
1159 .fill(sandstone.clone());
1160 }
1161 for spire_pos in &spire_positions {
1162 let spire_height =
1163 (height / 3) + (RandomField::new(0).get(spire_pos.with_z(base)) % 6) as i32;
1164 painter
1165 .cylinder(Aabb {
1166 min: (spire_pos - pillar_size - 1)
1167 .with_z(base + height + wall_th + top_height - 2),
1168 max: (spire_pos + pillar_size + 2)
1169 .with_z(base + height + wall_th + top_height + 6),
1170 })
1171 .fill(sandstone.clone());
1172 painter
1173 .cylinder(Aabb {
1174 min: (spire_pos - pillar_size).with_z(base + height + wall_th + top_height + 6),
1175 max: (spire_pos + pillar_size + 1)
1176 .with_z(base + height + wall_th + top_height + spire_height),
1177 })
1178 .fill(color.clone());
1179 for r in 0..((spire_height / 2) - 3) {
1180 let spire_dots = 16.0_f32 + (2 * r) as f32;
1181 let spire_dots_radius = pillar_size as f32 + 0.5;
1182 let phi_spire_dots = TAU / spire_dots;
1183
1184 for n in 1..=spire_dots as i32 {
1185 let spire_dot_pos = Vec2::new(
1186 spire_pos.x
1187 + (spire_dots_radius * ((n as f32 * phi_spire_dots).cos())) as i32,
1188 spire_pos.y
1189 + (spire_dots_radius * ((n as f32 * phi_spire_dots).sin())) as i32,
1190 );
1191 painter
1193 .line(
1194 spire_pos.with_z(base + height + wall_th + top_height + 6 + (r * 2)),
1195 spire_dot_pos
1196 .with_z(base + height + wall_th + top_height + 6 + (r * 2)),
1197 1.0,
1198 )
1199 .fill(sandstone.clone());
1200 }
1201 }
1202
1203 painter
1204 .cylinder(Aabb {
1205 min: (spire_pos - pillar_size - 1)
1206 .with_z(base + height + wall_th + top_height + spire_height),
1207 max: (spire_pos + pillar_size + 2)
1208 .with_z(base + height + wall_th + top_height + spire_height + 1),
1209 })
1210 .fill(sandstone.clone());
1211 painter
1212 .sphere(Aabb {
1213 min: (spire_pos - pillar_size)
1214 .with_z(base + height + wall_th + top_height + spire_height - pillar_size),
1215 max: (spire_pos + pillar_size + 1)
1216 .with_z(base + height + wall_th + top_height + spire_height + pillar_size),
1217 })
1218 .fill(color.clone());
1219 painter
1220 .cone(Aabb {
1221 min: (spire_pos - 2)
1222 .with_z(base + height + wall_th + top_height + spire_height + pillar_size),
1223 max: (spire_pos + 3).with_z(
1224 base + height
1225 + wall_th
1226 + top_height
1227 + spire_height
1228 + pillar_size
1229 + (spire_height / 3),
1230 ),
1231 })
1232 .fill(sandstone.clone());
1233 painter.spawn(
1235 EntityInfo::at((spire_pos - 2).with_z(base - 1).as_())
1236 .into_special(SpecialEntity::Waypoint),
1237 );
1238 painter.spawn(EntityInfo::at(center.with_z(base).as_()).into_special(
1239 SpecialEntity::ArenaTotem {
1240 range: length as f32,
1241 },
1242 ));
1243 painter.sprite((spire_pos + 2).with_z(base - 1), SpriteKind::RepairBench);
1244
1245 let lamps = 8.0_f32;
1247 let lamps_radius = 3;
1248 let phi_lamps = TAU / lamps;
1249 for n in 1..=lamps as i32 {
1250 let lamp_pos = Vec2::new(
1251 spire_pos.x + (lamps_radius as f32 * ((n as f32 * phi_lamps).cos())) as i32,
1252 spire_pos.y + (lamps_radius as f32 * ((n as f32 * phi_lamps).sin())) as i32,
1253 );
1254 let lamp_var = (RandomField::new(0).get(lamp_pos.with_z(base)) % 8) as i32;
1255 painter
1256 .aabb(Aabb {
1257 min: lamp_pos.with_z(base + height - 8 - lamp_var),
1258 max: (lamp_pos + 1).with_z(base + height),
1259 })
1260 .fill(chain.clone());
1261 painter
1262 .aabb(Aabb {
1263 min: lamp_pos.with_z(base + height - 9 - lamp_var),
1264 max: (lamp_pos + 1).with_z(base + height - 8 - lamp_var),
1265 })
1266 .fill(lantern.clone());
1267 }
1268 }
1269 }
1270}