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 pub(crate) alt: i32,
19 pub base: i32,
20 pub center: Vec2<i32>,
21 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 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 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 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 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 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 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 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 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 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 for d in 0..3 {
304 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 for d in 0..((length / 12) - 2) {
756 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 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 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 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 for s in 0..1 {
1034 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 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 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 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}