use super::*;
use crate::{
assets::AssetHandle,
site2::gen::PrimitiveTransform,
util::{RandomField, Sampler, 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, sync::Arc};
use vek::*;
pub struct TerracottaYard {
bounds: Aabr<i32>,
pub(crate) alt: i32,
}
impl TerracottaYard {
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 TerracottaYard {
#[cfg(feature = "use-dyn-lib")]
const UPDATE_FN: &'static [u8] = b"render_terracotta_yard\0";
#[cfg_attr(feature = "be-dyn-lib", export_name = "render_terracotta_yard")]
fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
let base = self.alt + 4;
let center = self.bounds.center();
let mut rng = thread_rng();
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 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 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 water_fill = Fill::Block(Block::new(BlockKind::Water, Rgb::zero()));
let sand = Fill::Brick(BlockKind::Misc, Rgb::new(235, 178, 99), 12);
let size = 30;
let room_size = 15 * (size / 10);
let water = RandomField::new(0).get(center.with_z(base)) % 2;
painter
.superquadric(
Aabb {
min: (center - (room_size / 2) - 10).with_z(base - room_size - 15),
max: (center + (room_size / 2) + 10).with_z(base + 5),
},
2.5,
)
.fill(clay_unbroken.clone());
let clear_limit = painter.aabb(Aabb {
min: (center - (room_size / 2) - 5).with_z(base),
max: (center + (room_size / 2) + 5).with_z(base + room_size),
});
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,
)
.intersect(clear_limit)
.clear();
if water < 1 {
painter
.cylinder(Aabb {
min: (center - (room_size / 4)).with_z(base - 12),
max: (center + (room_size / 4)).with_z(base),
})
.clear();
painter
.cylinder(Aabb {
min: (center - (room_size / 4)).with_z(base - 13),
max: (center + (room_size / 4)).with_z(base - 12),
})
.fill(Fill::Block(Block::air(SpriteKind::IronSpike)));
painter
.cylinder(Aabb {
min: (center - (room_size / 4)).with_z(base - 1),
max: (center + (room_size / 4)).with_z(base),
})
.fill(Fill::Block(Block::air(SpriteKind::TerracottaBlock)));
painter
.cylinder(Aabb {
min: (center).with_z(base - 14),
max: (center + 1).with_z(base),
})
.fill(clay_unbroken);
let radius_lamps_main = (room_size / 4) + 6;
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);
}
painter.spawn(
EntityInfo::at((center).with_z(base).as_()).with_asset_expect(
"common.entity.dungeon.terracotta.terracotta_statue_key",
&mut rng,
None,
),
);
} else {
let basin = painter.superquadric(
Aabb {
min: (center - (room_size / 4) - 12).with_z(base - 12),
max: (center + (room_size / 4) + 12).with_z(base + 12),
},
2.5,
);
basin.clear();
let water_level = (RandomField::new(0).get(center.with_z(base)) % 8) as i32;
let water_limit = painter.aabb(Aabb {
min: (center - (room_size / 4) - 12).with_z(base - 12),
max: (center + (room_size / 4) + 12).with_z(base - 4 - water_level),
});
basin.intersect(water_limit).fill(water_fill);
let model_radius = (room_size / 2) + 7;
for dir in NEIGHBORS {
let pos = center + dir * model_radius;
painter
.cylinder(Aabb {
min: (pos - 10).with_z(base - room_size),
max: (pos + 10).with_z(base - 3),
})
.fill(clay_unbroken.clone());
painter
.cylinder(Aabb {
min: (pos - 10).with_z(base - 4),
max: (pos + 10).with_z(base - 3),
})
.fill(clay_broken.clone());
painter
.cylinder(Aabb {
min: (pos - 9).with_z(base - 4),
max: (pos + 9).with_z(base - 3),
})
.fill(sand.clone());
painter
.cylinder(Aabb {
min: (pos - 7).with_z(base - 3),
max: (pos + 7).with_z(base - 2),
})
.fill(grass_fill.clone());
let model_pos = pos.with_z(base - 5);
match RandomField::new(0).get(model_pos) % 2 {
0 => {
lazy_static! {
pub static ref MODEL: AssetHandle<StructuresGroup> =
PrefabStructure::load_group(
"site_structures.terracotta.terracotta_decor_small"
);
}
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));
},
_ => {
lazy_static! {
pub static ref MODEL: AssetHandle<StructuresGroup> =
PrefabStructure::load_group("trees.palms");
}
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));
},
}
}
}
let radius_guards = (room_size / 4) + 12;
let guards = 4.0_f32;
let phi_guards = TAU / guards;
for n in 1..=guards as i32 {
let pos = Vec2::new(
center.x + (radius_guards as f32 * ((n as f32 * phi_guards).cos())) as i32,
center.y + (radius_guards as f32 * ((n as f32 * phi_guards).sin())) as i32,
)
.with_z(base);
terracotta_palace::spawn_random_entity(pos, painter, 1..=1);
}
}
}