Skip to main content

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