veloren_world/site2/plot/
desert_city_arena.rs

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    /// Approximate altitude of the door tile
17    pub(crate) alt: i32,
18    pub base: i32,
19    pub center: Vec2<i32>,
20    // arena
21    // config
22    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        // arena
46        // config
47        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        // arena
97        // config
98        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        // clear area for entries
120        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        // top
129        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            // top decor carve
189            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        // pillars and spires
199        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            // pillar
236            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            // carve large
244            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            // carve small
273            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            // upper decor
285            for d in 0..3 {
286                // d1
287                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                // d2
323                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            // arches
359            // a1
360            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            // a2
395            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            // b1
430            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            // b2
465            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            // top
500            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            // decor
523            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                        // top decor carve
534                        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                    // dots
543                    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        // arena
556        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        // decor carve
582        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        // color inlay
619        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                // color decor
647                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        // entries
658        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        // center clear
708        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        // center decor
737        for d in 0..((length / 12) - 2) {
738            // d1
739            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            // d2
850            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        // entry steps
961        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        // clear rooms
976        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            // stands
1015            for s in 0..1 {
1016                // distance from center
1017                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                    // color decor
1192                    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            // campfires & repair benches
1234            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            // lamps
1246            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}