use super::*;
use crate::{
assets::AssetHandle,
site2::gen::{place_circular, PrimitiveTransform},
util::{RandomField, Sampler, DIAGONALS, NEIGHBORS},
Land,
};
use common::{
generation::EntityInfo,
terrain::{BlockKind, SpriteKind, Structure as PrefabStructure, StructuresGroup},
};
use lazy_static::lazy_static;
use rand::prelude::*;
use std::{f32::consts::TAU, ops::RangeInclusive, sync::Arc};
use vek::*;
pub struct TerracottaPalace {
bounds: Aabr<i32>,
pub(crate) alt: i32,
}
impl TerracottaPalace {
pub fn generate(land: &Land, _rng: &mut impl Rng, site: &Site, tile_aabr: Aabr<i32>) -> Self {
let bounds = Aabr {
min: site.tile_wpos(tile_aabr.min),
max: site.tile_wpos(tile_aabr.max),
};
Self {
bounds,
alt: land.get_alt_approx(site.tile_center_wpos((tile_aabr.max - tile_aabr.min) / 2))
as i32
+ 2,
}
}
pub fn spawn_rules(&self, wpos: Vec2<i32>) -> SpawnRules {
SpawnRules {
waypoints: false,
trees: wpos.distance_squared(self.bounds.center()) > (85_i32).pow(2),
..SpawnRules::default()
}
}
}
impl Structure for TerracottaPalace {
#[cfg(feature = "use-dyn-lib")]
const UPDATE_FN: &'static [u8] = b"render_terracotta_palace\0";
#[cfg_attr(feature = "be-dyn-lib", export_name = "render_terracotta_palace")]
fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
let base = self.alt + 1;
let center = self.bounds.center();
let mut rng = thread_rng();
let clay_broken = Fill::Sampling(Arc::new(|center| {
Some(match (RandomField::new(0).get(center)) % 42 {
0..=8 => Block::new(BlockKind::Rock, Rgb::new(242, 161, 53)),
9..=17 => Block::new(BlockKind::Rock, Rgb::new(253, 199, 81)),
18..=26 => Block::new(BlockKind::Rock, Rgb::new(254, 210, 91)),
27..=35 => Block::new(BlockKind::Rock, Rgb::new(254, 216, 101)),
36..=38 => Block::new(BlockKind::Air, Rgb::new(0, 0, 0)),
_ => Block::new(BlockKind::Rock, Rgb::new(250, 185, 71)),
})
}));
let clay_broken_2 = Fill::Sampling(Arc::new(|center| {
Some(match (RandomField::new(0).get(center)) % 64 {
0..=8 => Block::new(BlockKind::Rock, Rgb::new(242, 161, 53)),
9..=17 => Block::new(BlockKind::Rock, Rgb::new(253, 199, 81)),
18..=26 => Block::new(BlockKind::Rock, Rgb::new(254, 210, 91)),
27..=35 => Block::new(BlockKind::Rock, Rgb::new(254, 216, 101)),
36..=40 => Block::new(BlockKind::Rock, Rgb::new(250, 185, 71)),
_ => Block::new(BlockKind::Air, Rgb::new(0, 0, 0)),
})
}));
let clay_unbroken = Fill::Sampling(Arc::new(|center| {
Some(match (RandomField::new(0).get(center)) % 40 {
0..=8 => Block::new(BlockKind::Rock, Rgb::new(242, 161, 53)),
9..=17 => Block::new(BlockKind::Rock, Rgb::new(253, 199, 81)),
18..=26 => Block::new(BlockKind::Rock, Rgb::new(254, 210, 91)),
27..=35 => Block::new(BlockKind::Rock, Rgb::new(254, 216, 101)),
_ => Block::new(BlockKind::Rock, Rgb::new(250, 185, 71)),
})
}));
let grass_fill = Fill::Sampling(Arc::new(|wpos| {
Some(match (RandomField::new(0).get(wpos)) % 20 {
1..=2 => Block::air(SpriteKind::JungleRedGrass),
3..=7 => Block::air(SpriteKind::JungleLeafyPlant),
8 => Block::air(SpriteKind::JungleFern),
_ => Block::new(BlockKind::Air, Rgb::new(0, 0, 0)),
})
}));
let roof_color = Fill::Sampling(Arc::new(|center| {
Some(match (RandomField::new(0).get(center)) % 400 {
0..=4 => Block::new(BlockKind::Rock, Rgb::new(242, 161, 53)),
5..=9 => Block::new(BlockKind::Rock, Rgb::new(253, 199, 81)),
10..=14 => Block::new(BlockKind::Rock, Rgb::new(254, 210, 91)),
15..=19 => Block::new(BlockKind::Rock, Rgb::new(254, 216, 101)),
20..=21 => Block::new(BlockKind::Air, Rgb::new(0, 0, 0)),
22..=23 => Block::new(BlockKind::Rock, Rgb::new(250, 185, 71)),
_ => Block::new(BlockKind::GlowingRock, Rgb::new(73, 53, 42)),
})
}));
let sand = Fill::Brick(BlockKind::Sand, Rgb::new(235, 178, 99), 12);
let size = 60;
let room_size = 15 * (size / 10);
let roof_size = 16 * (size / 10);
let carve_size = 14 * (size / 10);
let roof_height = room_size / 3;
let storeys = 5;
let var = size / 5;
let clear_var = var / 2;
let clear_limit = painter.aabb(Aabb {
min: (center - (room_size / 2) - 2).with_z(base),
max: (center + (room_size / 2) + 2).with_z(base + (2 * room_size)),
});
let clear_limit_down = painter.aabb(Aabb {
min: (center - (room_size / 2) - 5).with_z(base - (2 * room_size)),
max: (center + (room_size / 2) + 5).with_z(base),
});
let spikes_fill = Fill::Sampling(Arc::new(|center| {
Some(match (RandomField::new(0).get(center)) % 8 {
0 => Block::air(SpriteKind::IronSpike),
_ => Block::new(BlockKind::Air, Rgb::new(0, 0, 0)),
})
}));
let mut chamber_npcs = vec![
"common.entity.dungeon.terracotta.cursekeeper_fake",
"common.entity.dungeon.terracotta.cursekeeper_fake",
"common.entity.dungeon.terracotta.cursekeeper_fake",
"common.entity.dungeon.terracotta.cursekeeper",
];
let mut statue_npcs = vec![
"common.entity.dungeon.terracotta.terracotta_statue_key",
"common.entity.dungeon.terracotta.terracotta_statue",
"common.entity.dungeon.terracotta.terracotta_statue",
"common.entity.dungeon.terracotta.terracotta_statue",
];
let mut cellar_statue_npcs = vec![
"common.entity.dungeon.terracotta.terracotta_statue_key",
"common.entity.dungeon.terracotta.terracotta_statue",
"common.entity.dungeon.terracotta.terracotta_statue",
];
let model_radius = (2 * (room_size / 3)) + 6;
for dir in NEIGHBORS {
let pos = center + dir * model_radius;
let palm_model_pos = Vec2::new(pos.x + 2, pos.y);
let found_var_a = (RandomField::new(0).get(pos.with_z(base)) % 10) as i32;
let found_var_b = (RandomField::new(0).get(pos.with_z(base + 1)) % 10) as i32;
let height_var = (found_var_a + found_var_b) / 2;
let foundation_limiter_1 = painter.aabb(Aabb {
min: (pos - (room_size / 3) - 1 - found_var_a).with_z(base - room_size),
max: (pos + (room_size / 3) + 1 + found_var_b).with_z(base - 1 + height_var),
});
painter
.rounded_aabb(Aabb {
min: (pos - (room_size / 3) - 1 - found_var_a).with_z(base - room_size),
max: (pos + (room_size / 3) + 1 + found_var_b).with_z(base + (room_size / 2)),
})
.intersect(foundation_limiter_1)
.fill(clay_unbroken.clone());
let foundation_limiter_2 = painter.aabb(Aabb {
min: (pos - (room_size / 3) - 1 - found_var_a).with_z(base - 2),
max: (pos + (room_size / 3) + 1 + found_var_b).with_z(base + height_var),
});
painter
.rounded_aabb(Aabb {
min: (pos - (room_size / 3) - 1 - found_var_a).with_z(base - (room_size / 2)),
max: (pos + (room_size / 3) + 1 + found_var_b).with_z(base + (room_size / 2)),
})
.intersect(foundation_limiter_2)
.fill(clay_broken_2.clone());
let foundation_limiter_3 = painter.aabb(Aabb {
min: (pos - (room_size / 3) - 1 - found_var_a).with_z(base - 2),
max: (pos + (room_size / 3) + 1 + found_var_b).with_z(base + height_var + 8),
});
painter
.rounded_aabb(Aabb {
min: (pos - (room_size / 3) + 2 - found_var_a).with_z(base - (room_size / 2)),
max: (pos + (room_size / 3) - 2 + found_var_b).with_z(base + (room_size / 2)),
})
.intersect(foundation_limiter_3)
.clear();
let foundation_limiter_4 = painter.aabb(Aabb {
min: (pos - (room_size / 3) - found_var_a).with_z(base - 2),
max: (pos + (room_size / 3) + found_var_b).with_z(base - 1),
});
painter
.rounded_aabb(Aabb {
min: (pos - (room_size / 3) - found_var_a).with_z(base - (room_size / 2)),
max: (pos + (room_size / 3) + found_var_b).with_z(base + (room_size / 2)),
})
.intersect(foundation_limiter_4)
.fill(sand.clone());
for dir in NEIGHBORS {
let decay_pos = pos + (dir * (room_size / 3));
painter
.sphere(Aabb {
min: (decay_pos - 8).with_z(base),
max: (decay_pos + 8).with_z(base + 16),
})
.clear();
}
painter
.cylinder(Aabb {
min: (pos - 12).with_z(base - 1),
max: (pos + 12).with_z(base),
})
.fill(grass_fill.clone());
let model_pos = pos.with_z(base - 5);
lazy_static! {
pub static ref MODEL: AssetHandle<StructuresGroup> = PrefabStructure::load_group(
"site_structures.terracotta.terracotta_decor_large"
);
}
let rng = RandomField::new(0).get(model_pos) % 62;
let model = MODEL.read();
let model = model[rng as usize % model.len()].clone();
painter
.prim(Primitive::Prefab(Box::new(model.clone())))
.translate(model_pos)
.fill(Fill::Prefab(Box::new(model), model_pos, rng));
for dir in DIAGONALS {
let model_pos = palm_model_pos + dir * 12;
match RandomField::new(0).get(model_pos.with_z(base)) % 4 {
0 => {},
_ => {
for p in 0..2 {
let palm_pos = (model_pos + 3 + (2 * p)).with_z(base - 5);
let exit = Aabb {
min: (center - (room_size / 2) - 8).with_z(base - 6),
max: (center - (room_size / 2) + 8).with_z(base - 4),
};
if !exit.contains_point(palm_pos) {
lazy_static! {
pub static ref MODEL: AssetHandle<StructuresGroup> =
PrefabStructure::load_group("trees.palms");
}
let rng = RandomField::new(0).get(palm_pos) % 62;
let model = MODEL.read();
let model = model[rng as usize % model.len()].clone();
painter
.prim(Primitive::Prefab(Box::new(model.clone())))
.translate(palm_pos)
.fill(Fill::Prefab(Box::new(model), palm_pos, rng));
}
}
},
}
}
}
let mut pavillons = vec![];
let pavillon_dist_x = room_size / 3;
let pavillon_dist_y = 2 * (room_size / 3);
let pavillon_size_1 = room_size / 8;
let pavillon_size_2 = room_size / 10;
for dir in DIAGONALS {
pavillons.push(Vec2::new(
center.x + dir.x * pavillon_dist_x,
center.y + dir.y * pavillon_dist_y,
));
pavillons.push(Vec2::new(
center.x + dir.x * pavillon_dist_y,
center.y + dir.y * pavillon_dist_x,
));
}
for pavillon_pos in pavillons {
let entry_carve_limiter = painter.aabb(Aabb {
min: (pavillon_pos - pavillon_size_1).with_z(base - pavillon_size_1),
max: (pavillon_pos + pavillon_size_1).with_z(base + pavillon_size_1),
});
let top_carve_limiter = painter.aabb(Aabb {
min: (pavillon_pos - pavillon_size_2).with_z(base + pavillon_size_1 - 2),
max: (pavillon_pos + pavillon_size_2)
.with_z(base + pavillon_size_1 + pavillon_size_2 - 2),
});
painter
.superquadric(
Aabb {
min: (pavillon_pos - pavillon_size_1).with_z(base - pavillon_size_1),
max: (pavillon_pos + pavillon_size_1).with_z(base + pavillon_size_1),
},
2.5,
)
.fill(clay_broken.clone());
painter
.superquadric(
Aabb {
min: (pavillon_pos - pavillon_size_2).with_z(base + pavillon_size_1 - 2),
max: (pavillon_pos + pavillon_size_2)
.with_z(base + pavillon_size_1 + pavillon_size_2 - 2),
},
2.5,
)
.fill(clay_broken.clone());
painter
.superquadric(
Aabb {
min: (pavillon_pos - pavillon_size_2 + 1)
.with_z(base + pavillon_size_1 - 1),
max: (pavillon_pos + pavillon_size_2 - 1)
.with_z(base + pavillon_size_1 + pavillon_size_2 - 3),
},
2.5,
)
.fill(roof_color.clone());
painter
.aabb(Aabb {
min: (pavillon_pos - 2).with_z(base + pavillon_size_1 + pavillon_size_2 - 3),
max: (pavillon_pos + 2).with_z(base + pavillon_size_1 + pavillon_size_2 - 2),
})
.fill(roof_color.clone());
painter
.aabb(Aabb {
min: (pavillon_pos - 1).with_z(base + pavillon_size_1 + pavillon_size_2 - 2),
max: (pavillon_pos + 1).with_z(base + pavillon_size_1 + pavillon_size_2),
})
.fill(roof_color.clone());
for dir in CARDINALS {
let pavillon_carve_pos = pavillon_pos + dir * pavillon_size_2;
painter
.superquadric(
Aabb {
min: (pavillon_carve_pos - pavillon_size_2 + 3).with_z(base - 1),
max: (pavillon_carve_pos + pavillon_size_2 - 2)
.with_z(base + pavillon_size_2 - 1),
},
2.5,
)
.intersect(entry_carve_limiter)
.clear();
painter
.superquadric(
Aabb {
min: (pavillon_carve_pos - pavillon_size_2 + 2)
.with_z(base + pavillon_size_1 + 2),
max: (pavillon_carve_pos + pavillon_size_2 - 2)
.with_z(base + pavillon_size_1 + pavillon_size_2 + 2),
},
2.5,
)
.intersect(top_carve_limiter)
.clear();
}
painter
.cylinder(Aabb {
min: (pavillon_pos - pavillon_size_2 + 2).with_z(base - 1),
max: (pavillon_pos + pavillon_size_2 - 2).with_z(base + 5),
})
.clear();
painter
.cylinder(Aabb {
min: (pavillon_pos - pavillon_size_2 - 2).with_z(base - 2),
max: (pavillon_pos + pavillon_size_2 + 2).with_z(base - 1),
})
.fill(clay_unbroken.clone());
}
painter
.superquadric(
Aabb {
min: (center - (room_size / 2)).with_z(base - (room_size / 2)),
max: (center + (room_size / 2)).with_z(base + (room_size / 2)),
},
2.5,
)
.fill(clay_broken.clone());
painter
.superquadric(
Aabb {
min: (center - (room_size / 2)).with_z(base - (room_size / 2)),
max: (center + (room_size / 2)).with_z(base + (room_size / 2)),
},
2.5,
)
.intersect(clear_limit_down)
.fill(clay_unbroken.clone());
for s in 0..storeys {
painter
.superquadric(
Aabb {
min: (center - (roof_size / 2) + (s * var)).with_z(
base + roof_height - (size / 4) + (s * (roof_size / 4)) + (s * var),
),
max: (center + (roof_size / 2) - (s * var)).with_z(
base + roof_height - (size / 4) + roof_size + (s * (roof_size / 4))
- (s * var),
),
},
2.5,
)
.fill(clay_broken.clone());
painter
.superquadric(
Aabb {
min: (center - (roof_size / 2) + (s * var) + 1).with_z(
base + roof_height - (size / 4) + (s * (roof_size / 4)) + (s * var) + 1,
),
max: (center + (roof_size / 2) - (s * var) - 1).with_z(
base + roof_height - (size / 4) + roof_size + (s * (roof_size / 4))
- (s * var)
- 1,
),
},
2.5,
)
.fill(roof_color.clone());
for dir in CARDINALS {
let pos = center + dir * (size - (s * var));
painter
.superquadric(
Aabb {
min: (pos - (carve_size / 2) + (s * clear_var)).with_z(
base + roof_height + (s * (roof_size / 4)) + (s * clear_var),
),
max: (pos + (carve_size / 2) - (s * clear_var)).with_z(
base + roof_height + carve_size + (s * (roof_size / 4))
- (s * clear_var),
),
},
2.5,
)
.intersect(clear_limit)
.clear();
}
}
painter
.superquadric(
Aabb {
min: (center - (room_size / 2) + 5).with_z(base - (room_size / 2) + 5),
max: (center + (room_size / 2) - 5).with_z(base + (room_size / 2) - 5),
},
2.5,
)
.union(
painter
.superquadric(
Aabb {
min: Vec2::new(
center.x - (room_size / 4),
center.y - (3 * room_size / 4),
)
.with_z(base - (room_size / 4)),
max: Vec2::new(
center.x + (room_size / 4),
center.y + (3 * room_size / 4),
)
.with_z(base + (room_size / 4)),
},
2.5,
)
.union(
painter.superquadric(
Aabb {
min: Vec2::new(
center.x - (3 * room_size / 4),
center.y - (room_size / 4),
)
.with_z(base - (room_size / 4)),
max: Vec2::new(
center.x + (3 * room_size / 4),
center.y + (room_size / 4),
)
.with_z(base + (room_size / 4)),
},
2.5,
),
),
)
.intersect(clear_limit)
.clear();
painter
.superquadric(
Aabb {
min: (center - (room_size / 3))
.with_z(base + (3 * (room_size / 10)) - (room_size / 3)),
max: (center + (room_size / 3))
.with_z(base + (3 * (room_size / 10)) + (room_size / 4)),
},
2.5,
)
.clear();
painter
.superquadric(
Aabb {
min: (center - (room_size / 4))
.with_z(base + (3 * (room_size / 10)) - (room_size / 4)),
max: (center + (room_size / 4))
.with_z(base + (3 * (room_size / 10)) + (room_size / 3)),
},
2.5,
)
.clear();
painter
.cylinder(Aabb {
min: (center - (room_size / 2) + 8).with_z(base + (3 * (room_size / 10)) - 1),
max: (center + (room_size / 2) - 8).with_z(base + (3 * (room_size / 10)) + 2),
})
.fill(clay_unbroken.clone());
painter
.cylinder(Aabb {
min: (center - (room_size / 4) + 1).with_z(base + (3 * (room_size / 10)) - 1),
max: (center + (room_size / 4) - 1).with_z(base + (3 * (room_size / 10)) + 2),
})
.clear();
painter
.cylinder(Aabb {
min: (center - (room_size / 4) + 1).with_z(base + (3 * (room_size / 10)) + 1),
max: (center + (room_size / 4) - 1).with_z(base + (3 * (room_size / 10)) + 2),
})
.fill(Fill::Block(Block::air(SpriteKind::IronSpike)));
painter
.cylinder(Aabb {
min: (center - (room_size / 4) - 1).with_z(base + (2 * (room_size / 10)) + 3),
max: (center + (room_size / 4) + 1).with_z(base + (2 * (room_size / 10)) + 4),
})
.fill(Fill::Block(Block::air(SpriteKind::IronSpike)));
for chain_pos in place_circular(center, ((room_size / 4) + 1) as f32, 20) {
painter
.aabb(Aabb {
min: (chain_pos - 1).with_z(base + (2 * (room_size / 10)) + 3),
max: chain_pos.with_z(base + (3 * (room_size / 10)) - 1),
})
.fill(Fill::Block(Block::air(SpriteKind::MetalChain)));
painter
.cylinder(Aabb {
min: (chain_pos - 3).with_z(base + (2 * (room_size / 10)) + 2),
max: (chain_pos + 1).with_z(base + (2 * (room_size / 10)) + 3),
})
.fill(roof_color.clone());
}
painter
.cylinder(Aabb {
min: (center - (room_size / 8) - 5).with_z(base - 1),
max: (center + (room_size / 8) + 5).with_z(base),
})
.fill(clay_unbroken.clone());
painter
.cylinder(Aabb {
min: (center - (room_size / 8) - 5).with_z(base),
max: (center + (room_size / 8) + 5).with_z(base + 1),
})
.fill(Fill::Block(Block::air(SpriteKind::IronSpike)));
painter
.cylinder(Aabb {
min: (center - (room_size / 8) - 3).with_z(base + 1),
max: (center + (room_size / 8) + 3).with_z(base + (3 * (room_size / 10)) + 2),
})
.fill(spikes_fill);
painter
.cylinder(Aabb {
min: (center - (room_size / 8) - 2).with_z(base - 20),
max: (center + (room_size / 8) + 2).with_z(base + (3 * (room_size / 10)) + 2),
})
.fill(clay_unbroken.clone());
painter
.cylinder(Aabb {
min: (center - (room_size / 8)).with_z(base + (3 * (room_size / 10)) + 1),
max: (center + (room_size / 8)).with_z(base + (3 * (room_size / 10)) + 2),
})
.fill(roof_color.clone());
painter
.cylinder(Aabb {
min: (center - (room_size / 8)).with_z(base - 10),
max: (center + (room_size / 8)).with_z(base - 15),
})
.fill(roof_color.clone());
painter
.superquadric(
Aabb {
min: (center - (room_size / 2)).with_z(base - 10 - room_size),
max: (center + (room_size / 2)).with_z(base - 10),
},
2.5,
)
.fill(clay_unbroken.clone());
painter
.line(
Vec2::new(center.x - (room_size / 2) - 8, center.y)
.with_z(base - 10 - (room_size / 2)),
Vec2::new(center.x + (room_size / 2) + 8, center.y)
.with_z(base - 10 - (room_size / 2)),
8.0,
)
.fill(clay_unbroken.clone());
painter
.line(
Vec2::new(center.x, center.y - (room_size / 2) - 8)
.with_z(base - 10 - (room_size / 2)),
Vec2::new(center.x, center.y + (room_size / 2) + 8)
.with_z(base - 10 - (room_size / 2)),
8.0,
)
.fill(clay_unbroken.clone());
painter
.line(
Vec2::new(center.x - (room_size / 2) - 8, center.y)
.with_z(base - 10 - (room_size / 2)),
Vec2::new(center.x + (room_size / 2) + 8, center.y)
.with_z(base - 10 - (room_size / 2)),
5.0,
)
.clear();
painter
.line(
Vec2::new(center.x, center.y - (room_size / 2) - 8)
.with_z(base - 10 - (room_size / 2)),
Vec2::new(center.x, center.y + (room_size / 2) + 8)
.with_z(base - 10 - (room_size / 2)),
5.0,
)
.clear();
for dir in CARDINALS {
let room_center = center + dir * ((room_size / 2) + 8);
painter
.cylinder(Aabb {
min: (room_center - 3).with_z(base - 30 - (room_size / 2) - (room_size / 16)),
max: (room_center + 3).with_z(base - 6 - (room_size / 2) - (room_size / 16)),
})
.clear();
let npc_pos = room_center.with_z(base - 24 - (room_size / 2) - (room_size / 16));
let npc = chamber_npcs
.swap_remove(RandomField::new(0).get(npc_pos) as usize % chamber_npcs.len());
painter.spawn(EntityInfo::at(npc_pos.as_()).with_asset_expect(npc, &mut rng, None));
}
painter
.aabb(Aabb {
min: Vec2::new(center.x - (room_size / 2), center.y - 4)
.with_z(base - 10 - (room_size / 2)),
max: Vec2::new(center.x - (room_size / 2) + 1, center.y + 5)
.with_z(base - 10 - (room_size / 2) + 5),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaKeyDoor)));
painter
.aabb(Aabb {
min: Vec2::new(center.x - (room_size / 2), center.y)
.with_z(base - 10 - (room_size / 2) + 1),
max: Vec2::new(center.x - (room_size / 2) + 1, center.y + 1)
.with_z(base - 10 - (room_size / 2) + 2),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaKeyhole)));
painter
.aabb(Aabb {
min: Vec2::new(center.x + (room_size / 2) - 1, center.y - 4)
.with_z(base - 10 - (room_size / 2)),
max: Vec2::new(center.x + (room_size / 2), center.y + 5)
.with_z(base - 10 - (room_size / 2) + 5),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaKeyDoor)));
painter
.aabb(Aabb {
min: Vec2::new(center.x + (room_size / 2) - 1, center.y)
.with_z(base - 10 - (room_size / 2) + 1),
max: Vec2::new(center.x + (room_size / 2), center.y + 1)
.with_z(base - 10 - (room_size / 2) + 2),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaKeyhole)));
painter
.aabb(Aabb {
min: Vec2::new(center.x - 4, center.y - (room_size / 2))
.with_z(base - 10 - (room_size / 2)),
max: Vec2::new(center.x + 5, center.y - (room_size / 2) + 1)
.with_z(base - 10 - (room_size / 2) + 5),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaKeyDoor)));
painter
.aabb(Aabb {
min: Vec2::new(center.x, center.y - (room_size / 2))
.with_z(base - 10 - (room_size / 2) + 1),
max: Vec2::new(center.x + 1, center.y - (room_size / 2) + 1)
.with_z(base - 10 - (room_size / 2) + 2),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaKeyhole)));
painter
.aabb(Aabb {
min: Vec2::new(center.x - 4, center.y + (room_size / 2) - 1)
.with_z(base - 10 - (room_size / 2)),
max: Vec2::new(center.x + 5, center.y + (room_size / 2))
.with_z(base - 10 - (room_size / 2) + 5),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaKeyDoor)));
painter
.aabb(Aabb {
min: Vec2::new(center.x, center.y + (room_size / 2) - 1)
.with_z(base - 10 - (room_size / 2) + 1),
max: Vec2::new(center.x + 1, center.y + (room_size / 2))
.with_z(base - 10 - (room_size / 2) + 2),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaKeyhole)));
painter
.superquadric(
Aabb {
min: (center - (room_size / 2) + 1).with_z(base - 10 - room_size + 1),
max: (center + (room_size / 2) - 1).with_z(base - 10 - 1),
},
2.5,
)
.clear();
let sq_limit = painter.aabb(Aabb {
min: (center - (room_size / 4) - 11).with_z(base - 20 - (room_size / 2)),
max: (center - (room_size / 4) + 16).with_z(base - 1),
});
painter
.superquadric(
Aabb {
min: (center - (room_size / 4) - 9).with_z(base - 20 - (room_size / 2)),
max: (center - (room_size / 4) + 16).with_z(base + 20),
},
3.5,
)
.intersect(sq_limit)
.fill(clay_unbroken.clone());
let cyl_1_pos = Vec2::new(
center.x - (room_size / 4) - 2,
center.y - (room_size / 4) - 13,
);
let cyl_2_pos = Vec2::new(
center.x - (room_size / 4) - 12,
center.y - (room_size / 4) - 5,
);
painter
.aabb(Aabb {
min: (cyl_1_pos - 15).with_z(base - 10 - (room_size / 2)),
max: (cyl_1_pos + 15).with_z(base - 10),
})
.fill(clay_unbroken.clone());
painter
.aabb(Aabb {
min: (cyl_2_pos - 15).with_z(base - 10 - (room_size / 2)),
max: (cyl_2_pos + 15).with_z(base - 10),
})
.fill(clay_unbroken.clone());
painter
.line(
(center - (room_size / 4)).with_z(base - 10 - (room_size / 2)),
(center - (room_size / 2)).with_z(base - 5),
10.0,
)
.fill(clay_unbroken.clone());
let exit_pos = Vec2::new(
center.x - (room_size / 4) + 9,
center.y + 4 - (room_size / 4),
);
painter
.cylinder(Aabb {
min: (exit_pos - 4).with_z(base - 10 - (room_size / 2)),
max: (exit_pos + 5).with_z(base + 4 - (room_size / 2)),
})
.fill(clay_unbroken.clone());
painter
.aabb(Aabb {
min: Vec2::new(exit_pos.x + 5, exit_pos.y - 2).with_z(base - 10 - (room_size / 2)),
max: Vec2::new(exit_pos.x + 6, exit_pos.y + 3).with_z(base + 25 - (room_size / 2)),
})
.fill(clay_unbroken.clone());
painter
.aabb(Aabb {
min: Vec2::new(exit_pos.x + 5, exit_pos.y - 1).with_z(base - 10 - (room_size / 2)),
max: Vec2::new(exit_pos.x + 6, exit_pos.y + 2).with_z(base + 6 - (room_size / 2)),
})
.clear();
painter
.cylinder(Aabb {
min: (exit_pos - 3).with_z(base - 10 - (room_size / 2)),
max: (exit_pos + 4).with_z(base + 10 - (room_size / 2)),
})
.clear();
painter
.aabb(Aabb {
min: Vec2::new(exit_pos.x + 4, exit_pos.y - 1).with_z(base + 3 - (room_size / 2)),
max: Vec2::new(exit_pos.x + 5, exit_pos.y + 2).with_z(base + 6 - (room_size / 2)),
})
.clear();
painter
.aabb(Aabb {
min: Vec2::new(exit_pos.x + 4, exit_pos.y - 1).with_z(base + 2 - (room_size / 2)),
max: Vec2::new(exit_pos.x + 5, exit_pos.y + 2).with_z(base + 3 - (room_size / 2)),
})
.fill(Fill::Block(Block::air(SpriteKind::IronSpike)));
painter
.aabb(Aabb {
min: Vec2::new(exit_pos.x + 5, exit_pos.y - 1).with_z(base - 10 - (room_size / 2)),
max: Vec2::new(exit_pos.x + 6, exit_pos.y + 2).with_z(base + 6 - (room_size / 2)),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaKeyDoor)));
painter
.aabb(Aabb {
min: Vec2::new(exit_pos.x + 5, exit_pos.y).with_z(base - 9 - (room_size / 2)),
max: Vec2::new(exit_pos.x + 6, exit_pos.y + 1).with_z(base - 8 - (room_size / 2)),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaKeyhole)));
let chests_position = exit_pos + 8;
painter
.cylinder(Aabb {
min: (chests_position - 4).with_z(base - 10 - (room_size / 2)),
max: (chests_position + 5).with_z(base - 9 - (room_size / 2)),
})
.fill(roof_color.clone());
painter
.cylinder(Aabb {
min: (chests_position - 3).with_z(base - 10 - (room_size / 2)),
max: (chests_position + 4).with_z(base - 9 - (room_size / 2)),
})
.fill(clay_unbroken.clone());
for dir in CARDINALS {
let chest_pos = chests_position + (dir * 2);
painter.sprite(
chest_pos.with_z(base - 9 - (room_size / 2)),
SpriteKind::TerracottaChest,
);
}
for dir in DIAGONALS {
let pos = center + dir * ((size / 2) + 6);
painter
.cylinder(Aabb {
min: (pos - 3).with_z(base - (room_size / 2)),
max: (pos + 3).with_z(base + 3),
})
.fill(clay_broken.clone());
painter
.cylinder(Aabb {
min: (pos - 4).with_z(base + 3),
max: (pos + 4).with_z(base + 4),
})
.fill(clay_broken_2.clone());
painter
.cylinder(Aabb {
min: (pos - 5).with_z(base + 4),
max: (pos + 5).with_z(base + 5),
})
.fill(clay_broken_2.clone());
painter
.cylinder(Aabb {
min: (pos - 6).with_z(base + 5),
max: (pos + 6).with_z(base + 6),
})
.fill(clay_broken.clone());
painter
.cylinder(Aabb {
min: (pos - 4).with_z(base + 5),
max: (pos + 4).with_z(base + 6),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaBlock)));
painter
.cylinder(Aabb {
min: (pos - 4).with_z(base + 4),
max: (pos + 4).with_z(base + 5),
})
.fill(Fill::Block(Block::air(SpriteKind::IronSpike)));
painter
.cylinder(Aabb {
min: (pos - 1).with_z(base + 4),
max: (pos + 1).with_z(base + 6),
})
.fill(clay_broken.clone());
let pillar_npc_pos = (center + dir * ((size / 2) + 9)).with_z(base + 6);
let statue_pos = (center + dir * ((size / 2) + 5)).with_z(base + 6);
spawn_random_entity(pillar_npc_pos, painter, 1..=1);
let statue = statue_npcs
.swap_remove(RandomField::new(0).get(statue_pos) as usize % statue_npcs.len());
painter.spawn(
EntityInfo::at((statue_pos).as_()).with_asset_expect(statue, &mut rng, None),
);
}
painter
.line(
(center - (room_size / 4)).with_z(base - 10 - (room_size / 2)),
(center - (room_size / 2)).with_z(base),
7.0,
)
.clear();
painter
.cylinder(Aabb {
min: (center - (room_size / 2) - 10).with_z(base),
max: (center - (room_size / 2) + 10).with_z(base + 10),
})
.clear();
painter
.cylinder(Aabb {
min: (center - (room_size / 8) + 3).with_z(base - 20),
max: (center + (room_size / 8) - 3).with_z(base + (3 * (room_size / 10)) + 2),
})
.clear();
painter
.cylinder(Aabb {
min: (center - (room_size / 8) + 3).with_z(base + (3 * (room_size / 10)) + 1),
max: (center + (room_size / 8) - 3).with_z(base + (3 * (room_size / 10)) + 2),
})
.fill(Fill::Block(Block::air(SpriteKind::IronSpike)));
painter
.cylinder(Aabb {
min: (center - 2).with_z(base + (3 * (room_size / 10)) + 1),
max: (center + 2).with_z(base + (3 * (room_size / 10)) + 2),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaKeyDoor)));
painter
.cylinder(Aabb {
min: (center).with_z(base + (3 * (room_size / 10)) + 1),
max: (center + 1).with_z(base + (3 * (room_size / 10)) + 2),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaKeyhole)));
painter
.aabb(Aabb {
min: (center - (room_size / 2)).with_z(base - 10 - room_size),
max: (center + (room_size / 2)).with_z(base - 10 - (room_size / 2)),
})
.fill(clay_unbroken.clone());
let lamps_top = 6.0_f32;
let radius_lamps_top = (room_size / 4) + 3;
let phi_lamps_top = TAU / lamps_top;
for n in 1..=lamps_top as i32 {
let pos = Vec2::new(
center.x + (radius_lamps_top as f32 * ((n as f32 * phi_lamps_top).cos())) as i32,
center.y + (radius_lamps_top as f32 * ((n as f32 * phi_lamps_top).sin())) as i32,
);
painter.sprite(
pos.with_z(base + (3 * (room_size / 10)) + 2),
SpriteKind::TerracottaStatue,
);
}
let chests = 4.0_f32;
let radius_chests = (room_size / 4) + 6;
let phi_chests = TAU / chests;
for n in 1..=chests as i32 {
let pos = Vec2::new(
center.x + (radius_chests as f32 * ((n as f32 * phi_chests).cos())) as i32,
center.y + (radius_chests as f32 * ((n as f32 * phi_chests).sin())) as i32,
);
painter.sprite(
pos.with_z(base + (3 * (room_size / 10)) + 2),
SpriteKind::TerracottaChest,
);
}
let radius_lamps_main = (room_size / 4) + 12;
let lamps_main = 8.0_f32;
let phi_lamps_main = TAU / lamps_main;
for n in 1..=lamps_main as i32 {
let pos = Vec2::new(
center.x + (radius_lamps_main as f32 * ((n as f32 * phi_lamps_main).cos())) as i32,
center.y + (radius_lamps_main as f32 * ((n as f32 * phi_lamps_main).sin())) as i32,
);
painter.sprite(pos.with_z(base), SpriteKind::TerracottaStatue);
}
let radius_statues_cellar = (room_size / 2) - 12;
let statues_cellar = 11.0_f32;
let phi_statues_cellar = TAU / statues_cellar;
for n in 1..=statues_cellar as i32 {
let pos = Vec2::new(
center.x
+ (radius_statues_cellar as f32 * ((n as f32 * phi_statues_cellar).cos()))
as i32,
center.y
+ (radius_statues_cellar as f32 * ((n as f32 * phi_statues_cellar).sin()))
as i32,
);
match n {
1 | 5 | 9 => {
painter
.cylinder(Aabb {
min: (pos - 8).with_z(base - 22 - (room_size / 2)),
max: (pos + 8).with_z(base - 10 - (room_size / 2)),
})
.clear();
painter
.cylinder(Aabb {
min: (pos - 8).with_z(base - 22 - (room_size / 2)),
max: (pos + 8).with_z(base - 21 - (room_size / 2)),
})
.fill(Fill::Block(Block::air(SpriteKind::IronSpike)));
painter
.cylinder(Aabb {
min: (pos - 8).with_z(base - 11 - (room_size / 2)),
max: (pos + 8).with_z(base - 10 - (room_size / 2)),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaBlock)));
painter
.cylinder(Aabb {
min: (pos).with_z(base - 22 - (room_size / 2)),
max: (pos + 1).with_z(base - 10 - (room_size / 2)),
})
.fill(clay_unbroken.clone());
let cellar_statue_pos = pos.with_z(base - 10 - (room_size / 2));
let cellar_statue = cellar_statue_npcs.swap_remove(
RandomField::new(0).get(cellar_statue_pos) as usize
% cellar_statue_npcs.len(),
);
painter.spawn(EntityInfo::at(cellar_statue_pos.as_()).with_asset_expect(
cellar_statue,
&mut rng,
None,
));
},
_ => {
painter.sprite(
pos.with_z(base - 10 - (room_size / 2)),
SpriteKind::TerracottaStatue,
);
},
}
}
let npcs = 5.0_f32;
let radius_npcs = (room_size / 4) + 6;
let phi_npcs = TAU / npcs;
for n in 1..=npcs as i32 {
let pos = Vec2::new(
center.x + (radius_npcs as f32 * ((n as f32 * phi_npcs).cos())) as i32,
center.y + (radius_npcs as f32 * ((n as f32 * phi_npcs).sin())) as i32,
)
.with_z(base + (3 * (room_size / 10)) + 2);
spawn_random_entity(pos, painter, 1..=1);
}
painter.spawn(
EntityInfo::at((center.with_z(base + (3 * (room_size / 10)) + 2)).as_())
.with_asset_expect("common.entity.dungeon.terracotta.mogwai", &mut rng, None),
);
let radius_npcs_main = (room_size / 4) + 10;
let npcs_main = 15.0_f32;
let phi_npcs_main = TAU / npcs_main;
for n in 1..=npcs_main as i32 {
let pos = Vec2::new(
center.x + (radius_npcs_main as f32 * ((n as f32 * phi_npcs_main).cos())) as i32,
center.y + (radius_npcs_main as f32 * ((n as f32 * phi_npcs_main).sin())) as i32,
)
.with_z(base);
spawn_random_entity(pos, painter, 1..=1);
}
}
}
pub fn spawn_random_entity(pos: Vec3<i32>, painter: &Painter, amount: RangeInclusive<i32>) {
let mut rng = thread_rng();
let entities = [
"common.entity.dungeon.terracotta.besieger",
"common.entity.dungeon.terracotta.demolisher",
"common.entity.dungeon.terracotta.punisher",
"common.entity.dungeon.terracotta.pursuer",
"common.entity.dungeon.terracotta.shamanic_spirit",
"common.entity.dungeon.terracotta.jiangshi",
];
for n in amount {
let random_entity_index = rng.gen_range(0..entities.len());
let random_entity = entities[random_entity_index];
let position = Vec3::new(pos.x + n, pos.y + n, pos.z);
painter.spawn(EntityInfo::at(position.as_()).with_asset_expect(
random_entity,
&mut rng,
None,
));
}
}