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