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 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 = "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 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 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 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 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 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 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 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 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 for d in 0..3 {
292 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 for d in 0..((length / 12) - 2) {
744 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 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 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 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 for s in 0..1 {
1022 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 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 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 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}