veloren_world/site/plot/
desert_city_arena.rs

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