mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'zesterer/citadel' into 'master'
Two new tree types and disabled citadel site. See merge request veloren/veloren!3652
This commit is contained in:
commit
536bb9b71c
@ -77,9 +77,9 @@ impl<T> Grid<T> {
|
|||||||
&self,
|
&self,
|
||||||
pos: Vec2<i32>,
|
pos: Vec2<i32>,
|
||||||
size: Vec2<i32>,
|
size: Vec2<i32>,
|
||||||
) -> impl Iterator<Item = Option<(Vec2<i32>, &T)>> + '_ {
|
) -> impl Iterator<Item = (Vec2<i32>, &T)> + '_ {
|
||||||
(0..size.x).flat_map(move |x| {
|
(0..size.x).flat_map(move |x| {
|
||||||
(0..size.y).map(move |y| {
|
(0..size.y).flat_map(move |y| {
|
||||||
Some((
|
Some((
|
||||||
pos + Vec2::new(x, y),
|
pos + Vec2::new(x, y),
|
||||||
&self.cells[self.idx(pos + Vec2::new(x, y))?],
|
&self.cells[self.idx(pos + Vec2::new(x, y))?],
|
||||||
|
@ -12,11 +12,13 @@ pub enum ForestKind {
|
|||||||
Chestnut,
|
Chestnut,
|
||||||
Cedar,
|
Cedar,
|
||||||
Pine,
|
Pine,
|
||||||
|
Redwood,
|
||||||
Birch,
|
Birch,
|
||||||
Mangrove,
|
Mangrove,
|
||||||
Giant,
|
Giant,
|
||||||
Swamp,
|
Swamp,
|
||||||
Frostpine,
|
Frostpine,
|
||||||
|
Dead,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Environment {
|
pub struct Environment {
|
||||||
@ -35,10 +37,12 @@ impl ForestKind {
|
|||||||
ForestKind::Chestnut => 0.35..1.5,
|
ForestKind::Chestnut => 0.35..1.5,
|
||||||
ForestKind::Cedar => 0.275..1.45,
|
ForestKind::Cedar => 0.275..1.45,
|
||||||
ForestKind::Pine => 0.2..1.4,
|
ForestKind::Pine => 0.2..1.4,
|
||||||
|
ForestKind::Redwood => 0.6..1.0,
|
||||||
ForestKind::Frostpine => 0.2..1.4,
|
ForestKind::Frostpine => 0.2..1.4,
|
||||||
ForestKind::Birch => 0.0..0.6,
|
ForestKind::Birch => 0.0..0.6,
|
||||||
ForestKind::Mangrove => 0.5..1.3,
|
ForestKind::Mangrove => 0.5..1.3,
|
||||||
ForestKind::Swamp => 0.5..1.1,
|
ForestKind::Swamp => 0.5..1.1,
|
||||||
|
ForestKind::Dead => 0.0..1.5,
|
||||||
_ => 0.0..0.0,
|
_ => 0.0..0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,10 +56,12 @@ impl ForestKind {
|
|||||||
ForestKind::Chestnut => -0.35..0.45,
|
ForestKind::Chestnut => -0.35..0.45,
|
||||||
ForestKind::Cedar => -0.65..0.15,
|
ForestKind::Cedar => -0.65..0.15,
|
||||||
ForestKind::Pine => -0.85..-0.2,
|
ForestKind::Pine => -0.85..-0.2,
|
||||||
|
ForestKind::Redwood => -0.5..-0.3,
|
||||||
ForestKind::Frostpine => -1.8..-0.8,
|
ForestKind::Frostpine => -1.8..-0.8,
|
||||||
ForestKind::Birch => -0.7..0.25,
|
ForestKind::Birch => -0.7..0.25,
|
||||||
ForestKind::Mangrove => 0.35..1.6,
|
ForestKind::Mangrove => 0.35..1.6,
|
||||||
ForestKind::Swamp => -0.6..0.8,
|
ForestKind::Swamp => -0.6..0.8,
|
||||||
|
ForestKind::Dead => -1.5..1.0,
|
||||||
_ => 0.0..0.0,
|
_ => 0.0..0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,10 +84,12 @@ impl ForestKind {
|
|||||||
ForestKind::Chestnut => 0.3,
|
ForestKind::Chestnut => 0.3,
|
||||||
ForestKind::Cedar => 0.3,
|
ForestKind::Cedar => 0.3,
|
||||||
ForestKind::Pine => 1.0,
|
ForestKind::Pine => 1.0,
|
||||||
|
ForestKind::Redwood => 2.5,
|
||||||
ForestKind::Frostpine => 1.0,
|
ForestKind::Frostpine => 1.0,
|
||||||
ForestKind::Birch => 0.65,
|
ForestKind::Birch => 0.65,
|
||||||
ForestKind::Mangrove => 2.0,
|
ForestKind::Mangrove => 2.0,
|
||||||
ForestKind::Swamp => 1.0,
|
ForestKind::Swamp => 1.0,
|
||||||
|
ForestKind::Dead => 0.01,
|
||||||
_ => 0.0,
|
_ => 0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,7 @@ impl Civs {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
32..=37 => (SiteKind::Gnarling, (&gnarling_enemies, 40)),
|
32..=37 => (SiteKind::Gnarling, (&gnarling_enemies, 40)),
|
||||||
|
// 32..=37 => (SiteKind::Citadel, (&castle_enemies, 20)),
|
||||||
38..=43 => (SiteKind::ChapelSite, (&chapel_site_enemies, 40)),
|
38..=43 => (SiteKind::ChapelSite, (&chapel_site_enemies, 40)),
|
||||||
_ => (SiteKind::Dungeon, (&dungeon_enemies, 40)),
|
_ => (SiteKind::Dungeon, (&dungeon_enemies, 40)),
|
||||||
};
|
};
|
||||||
@ -178,7 +179,7 @@ impl Civs {
|
|||||||
let wpos = site.center * TerrainChunkSize::RECT_SIZE.map(|e: u32| e as i32);
|
let wpos = site.center * TerrainChunkSize::RECT_SIZE.map(|e: u32| e as i32);
|
||||||
|
|
||||||
let (radius, flatten_radius) = match &site.kind {
|
let (radius, flatten_radius) = match &site.kind {
|
||||||
SiteKind::Settlement => (32i32, 10.0),
|
SiteKind::Settlement => (32i32, 10.0f32),
|
||||||
SiteKind::Dungeon => (8i32, 3.0),
|
SiteKind::Dungeon => (8i32, 3.0),
|
||||||
SiteKind::Castle => (16i32, 5.0),
|
SiteKind::Castle => (16i32, 5.0),
|
||||||
SiteKind::Refactor => (32i32, 10.0),
|
SiteKind::Refactor => (32i32, 10.0),
|
||||||
@ -188,6 +189,7 @@ impl Civs {
|
|||||||
SiteKind::Tree => (12i32, 8.0),
|
SiteKind::Tree => (12i32, 8.0),
|
||||||
SiteKind::GiantTree => (12i32, 8.0),
|
SiteKind::GiantTree => (12i32, 8.0),
|
||||||
SiteKind::Gnarling => (16i32, 10.0),
|
SiteKind::Gnarling => (16i32, 10.0),
|
||||||
|
SiteKind::Citadel => (16i32, 0.0),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (raise, raise_dist, make_waypoint): (f32, i32, bool) = match &site.kind {
|
let (raise, raise_dist, make_waypoint): (f32, i32, bool) = match &site.kind {
|
||||||
@ -207,7 +209,8 @@ impl Civs {
|
|||||||
}; // Raise the town centre up a little
|
}; // Raise the town centre up a little
|
||||||
let pos = site.center + offs;
|
let pos = site.center + offs;
|
||||||
let factor = ((1.0
|
let factor = ((1.0
|
||||||
- (site.center - pos).map(|e| e as f32).magnitude() / flatten_radius)
|
- (site.center - pos).map(|e| e as f32).magnitude()
|
||||||
|
/ flatten_radius.max(0.01))
|
||||||
* 1.25)
|
* 1.25)
|
||||||
.min(1.0);
|
.min(1.0);
|
||||||
let rng = &mut ctx.rng;
|
let rng = &mut ctx.rng;
|
||||||
@ -288,6 +291,11 @@ impl Civs {
|
|||||||
SiteKind::ChapelSite => WorldSite::chapel_site(
|
SiteKind::ChapelSite => WorldSite::chapel_site(
|
||||||
site2::Site::generate_chapel_site(&Land::from_sim(ctx.sim), &mut rng, wpos),
|
site2::Site::generate_chapel_site(&Land::from_sim(ctx.sim), &mut rng, wpos),
|
||||||
),
|
),
|
||||||
|
SiteKind::Citadel => WorldSite::gnarling(site2::Site::generate_citadel(
|
||||||
|
&Land::from_sim(ctx.sim),
|
||||||
|
&mut rng,
|
||||||
|
wpos,
|
||||||
|
)),
|
||||||
});
|
});
|
||||||
sim_site.site_tmp = Some(site);
|
sim_site.site_tmp = Some(site);
|
||||||
let site_ref = &index.sites[site];
|
let site_ref = &index.sites[site];
|
||||||
@ -1245,6 +1253,7 @@ pub enum SiteKind {
|
|||||||
Tree,
|
Tree,
|
||||||
GiantTree,
|
GiantTree,
|
||||||
Gnarling,
|
Gnarling,
|
||||||
|
Citadel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SiteKind {
|
impl SiteKind {
|
||||||
@ -1378,6 +1387,7 @@ impl SiteKind {
|
|||||||
&& chunk.tree_density > 0.4
|
&& chunk.tree_density > 0.4
|
||||||
&& (-0.3..0.4).contains(&chunk.temp)
|
&& (-0.3..0.4).contains(&chunk.temp)
|
||||||
},
|
},
|
||||||
|
SiteKind::Citadel => true,
|
||||||
SiteKind::CliffTown => {
|
SiteKind::CliffTown => {
|
||||||
(-0.6..0.4).contains(&chunk.temp)
|
(-0.6..0.4).contains(&chunk.temp)
|
||||||
&& chunk.near_cliffs()
|
&& chunk.near_cliffs()
|
||||||
|
@ -141,6 +141,15 @@ pub fn apply_trees_to(
|
|||||||
StructureBlock::TemperateLeaves,
|
StructureBlock::TemperateLeaves,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
ForestKind::Dead => {
|
||||||
|
break 'model TreeModel::Procedural(
|
||||||
|
ProceduralTree::generate(
|
||||||
|
TreeConfig::dead(&mut RandomPerm::new(seed), scale),
|
||||||
|
&mut RandomPerm::new(seed),
|
||||||
|
),
|
||||||
|
StructureBlock::TemperateLeaves,
|
||||||
|
);
|
||||||
|
},
|
||||||
ForestKind::Chestnut => {
|
ForestKind::Chestnut => {
|
||||||
break 'model TreeModel::Procedural(
|
break 'model TreeModel::Procedural(
|
||||||
ProceduralTree::generate(
|
ProceduralTree::generate(
|
||||||
@ -168,6 +177,15 @@ pub fn apply_trees_to(
|
|||||||
StructureBlock::PineLeaves,
|
StructureBlock::PineLeaves,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
ForestKind::Redwood => {
|
||||||
|
break 'model TreeModel::Procedural(
|
||||||
|
ProceduralTree::generate(
|
||||||
|
TreeConfig::redwood(&mut RandomPerm::new(seed), scale),
|
||||||
|
&mut RandomPerm::new(seed),
|
||||||
|
),
|
||||||
|
StructureBlock::PineLeaves,
|
||||||
|
);
|
||||||
|
},
|
||||||
ForestKind::Birch => {
|
ForestKind::Birch => {
|
||||||
break 'model TreeModel::Procedural(
|
break 'model TreeModel::Procedural(
|
||||||
ProceduralTree::generate(
|
ProceduralTree::generate(
|
||||||
@ -395,6 +413,30 @@ impl TreeConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dead(rng: &mut impl Rng, scale: f32) -> Self {
|
||||||
|
let scale = scale * (0.8 + rng.gen::<f32>().powi(2) * 0.5);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
trunk_len: 9.0 * scale,
|
||||||
|
trunk_radius: 2.0 * scale,
|
||||||
|
branch_child_len: 0.9,
|
||||||
|
branch_child_radius: 0.7,
|
||||||
|
branch_child_radius_lerp: true,
|
||||||
|
leaf_radius: 0.0..0.1,
|
||||||
|
leaf_radius_scaled: 0.0,
|
||||||
|
straightness: 0.35,
|
||||||
|
max_depth: 3,
|
||||||
|
splits: 2.25..3.25,
|
||||||
|
split_range: 0.75..1.5,
|
||||||
|
branch_len_bias: 0.0,
|
||||||
|
leaf_vertical_scale: 1.0,
|
||||||
|
proportionality: 0.0,
|
||||||
|
inhabited: false,
|
||||||
|
hanging_sprites: &[(0.0002, SpriteKind::Apple), (0.00007, SpriteKind::Beehive)],
|
||||||
|
trunk_block: StructureBlock::Filled(BlockKind::Wood, Rgb::new(55, 34, 32)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn apple(rng: &mut impl Rng, scale: f32) -> Self {
|
pub fn apple(rng: &mut impl Rng, scale: f32) -> Self {
|
||||||
let scale = scale * (0.8 + rng.gen::<f32>().powi(2) * 0.5);
|
let scale = scale * (0.8 + rng.gen::<f32>().powi(2) * 0.5);
|
||||||
let log_scale = 1.0 + scale.log2().max(0.0);
|
let log_scale = 1.0 + scale.log2().max(0.0);
|
||||||
@ -607,10 +649,10 @@ impl TreeConfig {
|
|||||||
branch_child_radius_lerp: false,
|
branch_child_radius_lerp: false,
|
||||||
leaf_radius: 1.9..2.1,
|
leaf_radius: 1.9..2.1,
|
||||||
leaf_radius_scaled: 1.5 * log_scale,
|
leaf_radius_scaled: 1.5 * log_scale,
|
||||||
straightness: 0.0,
|
straightness: -0.25,
|
||||||
max_depth: 1,
|
max_depth: 1,
|
||||||
splits: 34.0 * scale..35.0 * scale,
|
splits: 34.0 * scale..35.0 * scale,
|
||||||
split_range: 0.165..1.2,
|
split_range: 0.2..1.2,
|
||||||
branch_len_bias: 0.75,
|
branch_len_bias: 0.75,
|
||||||
leaf_vertical_scale: 0.3,
|
leaf_vertical_scale: 0.3,
|
||||||
proportionality: 1.0,
|
proportionality: 1.0,
|
||||||
@ -624,6 +666,31 @@ impl TreeConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn redwood(rng: &mut impl Rng, scale: f32) -> Self {
|
||||||
|
let scale = scale * (1.0 + rng.gen::<f32>().powi(4) * 0.5);
|
||||||
|
let log_scale = 1.0 + scale.log2().max(0.0);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
trunk_len: 80.0 * scale,
|
||||||
|
trunk_radius: 3.25 * scale,
|
||||||
|
branch_child_len: 0.25 / scale,
|
||||||
|
branch_child_radius: 0.0,
|
||||||
|
branch_child_radius_lerp: false,
|
||||||
|
leaf_radius: 2.0..3.0,
|
||||||
|
leaf_radius_scaled: 1.5 * log_scale,
|
||||||
|
straightness: -0.3,
|
||||||
|
max_depth: 1,
|
||||||
|
splits: 45.0 * scale..50.0 * scale,
|
||||||
|
split_range: 0.45..1.2,
|
||||||
|
branch_len_bias: 0.75,
|
||||||
|
leaf_vertical_scale: 0.45,
|
||||||
|
proportionality: 1.0,
|
||||||
|
inhabited: false,
|
||||||
|
hanging_sprites: &[(0.001, SpriteKind::Beehive)],
|
||||||
|
trunk_block: StructureBlock::Filled(BlockKind::Wood, Rgb::new(110, 55, 10)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn giant(_rng: &mut impl Rng, scale: f32, inhabited: bool) -> Self {
|
pub fn giant(_rng: &mut impl Rng, scale: f32, inhabited: bool) -> Self {
|
||||||
let log_scale = 1.0 + scale.log2().max(0.0);
|
let log_scale = 1.0 + scale.log2().max(0.0);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
)]
|
)]
|
||||||
#![allow(clippy::branches_sharing_code)] // TODO: evaluate
|
#![allow(clippy::branches_sharing_code)] // TODO: evaluate
|
||||||
#![deny(clippy::clone_on_ref_ptr)]
|
#![deny(clippy::clone_on_ref_ptr)]
|
||||||
#![feature(option_zip, arbitrary_enum_discriminant)]
|
#![feature(option_zip, arbitrary_enum_discriminant, int_log, map_first_last)]
|
||||||
|
|
||||||
mod all;
|
mod all;
|
||||||
mod block;
|
mod block;
|
||||||
@ -156,6 +156,7 @@ impl World {
|
|||||||
// TODO: Maybe change?
|
// TODO: Maybe change?
|
||||||
civ::SiteKind::Gnarling => world_msg::SiteKind::Gnarling,
|
civ::SiteKind::Gnarling => world_msg::SiteKind::Gnarling,
|
||||||
civ::SiteKind::ChapelSite => world_msg::SiteKind::ChapelSite,
|
civ::SiteKind::ChapelSite => world_msg::SiteKind::ChapelSite,
|
||||||
|
civ::SiteKind::Citadel => world_msg::SiteKind::Castle,
|
||||||
},
|
},
|
||||||
wpos: site.center * TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
|
wpos: site.center * TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
|
||||||
}
|
}
|
||||||
@ -484,9 +485,9 @@ impl World {
|
|||||||
Some(lod::Object {
|
Some(lod::Object {
|
||||||
kind: match tree.forest_kind {
|
kind: match tree.forest_kind {
|
||||||
all::ForestKind::Oak => lod::ObjectKind::Oak,
|
all::ForestKind::Oak => lod::ObjectKind::Oak,
|
||||||
all::ForestKind::Pine | all::ForestKind::Frostpine => {
|
all::ForestKind::Pine
|
||||||
lod::ObjectKind::Pine
|
| all::ForestKind::Frostpine
|
||||||
},
|
| all::ForestKind::Redwood => lod::ObjectKind::Pine,
|
||||||
_ => lod::ObjectKind::Oak,
|
_ => lod::ObjectKind::Oak,
|
||||||
},
|
},
|
||||||
pos: {
|
pos: {
|
||||||
|
@ -318,7 +318,7 @@ impl Fill {
|
|||||||
let a: f32 = aabb.max.x as f32 - center.x - 0.5;
|
let a: f32 = aabb.max.x as f32 - center.x - 0.5;
|
||||||
let b: f32 = aabb.max.y as f32 - center.y - 0.5;
|
let b: f32 = aabb.max.y as f32 - center.y - 0.5;
|
||||||
let c: f32 = aabb.max.z as f32 - center.z - 0.5;
|
let c: f32 = aabb.max.z as f32 - center.z - 0.5;
|
||||||
let rpos = pos.as_::<f32>() - center;
|
let rpos = pos.as_::<f32>() + 0.5 - center;
|
||||||
aabb_contains(*aabb, pos)
|
aabb_contains(*aabb, pos)
|
||||||
&& (rpos.x / a).abs().powf(degree)
|
&& (rpos.x / a).abs().powf(degree)
|
||||||
+ (rpos.y / b).abs().powf(degree)
|
+ (rpos.y / b).abs().powf(degree)
|
||||||
|
@ -386,6 +386,34 @@ impl Site {
|
|||||||
site
|
site
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generate_citadel(land: &Land, rng: &mut impl Rng, origin: Vec2<i32>) -> Self {
|
||||||
|
let mut rng = reseed(rng);
|
||||||
|
let mut site = Site {
|
||||||
|
origin,
|
||||||
|
..Site::default()
|
||||||
|
};
|
||||||
|
site.demarcate_obstacles(land);
|
||||||
|
let citadel = plot::Citadel::generate(origin, land, &mut rng);
|
||||||
|
site.name = citadel.name().to_string();
|
||||||
|
let size = citadel.radius() / tile::TILE_SIZE as i32;
|
||||||
|
let aabr = Aabr {
|
||||||
|
min: Vec2::broadcast(-size),
|
||||||
|
max: Vec2::broadcast(size),
|
||||||
|
};
|
||||||
|
let plot = site.create_plot(Plot {
|
||||||
|
kind: PlotKind::Citadel(citadel),
|
||||||
|
root_tile: aabr.center(),
|
||||||
|
tiles: aabr_tiles(aabr).collect(),
|
||||||
|
seed: rng.gen(),
|
||||||
|
});
|
||||||
|
site.blit_aabr(aabr, Tile {
|
||||||
|
kind: TileKind::Building,
|
||||||
|
plot: Some(plot),
|
||||||
|
hard_alt: None,
|
||||||
|
});
|
||||||
|
site
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generate_gnarling(land: &Land, rng: &mut impl Rng, origin: Vec2<i32>) -> Self {
|
pub fn generate_gnarling(land: &Land, rng: &mut impl Rng, origin: Vec2<i32>) -> Self {
|
||||||
let mut rng = reseed(rng);
|
let mut rng = reseed(rng);
|
||||||
let mut site = Site {
|
let mut site = Site {
|
||||||
@ -1174,6 +1202,7 @@ impl Site {
|
|||||||
PlotKind::DesertCityTemple(desert_city_temple) => {
|
PlotKind::DesertCityTemple(desert_city_temple) => {
|
||||||
desert_city_temple.render_collect(self, canvas)
|
desert_city_temple.render_collect(self, canvas)
|
||||||
},
|
},
|
||||||
|
PlotKind::Citadel(citadel) => citadel.render_collect(self, canvas),
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
mod castle;
|
mod castle;
|
||||||
|
mod citadel;
|
||||||
mod cliff_tower;
|
mod cliff_tower;
|
||||||
mod desert_city_multiplot;
|
mod desert_city_multiplot;
|
||||||
mod desert_city_temple;
|
mod desert_city_temple;
|
||||||
@ -10,9 +11,10 @@ mod sea_chapel;
|
|||||||
mod workshop;
|
mod workshop;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
castle::Castle, cliff_tower::CliffTower, desert_city_multiplot::DesertCityMultiPlot,
|
castle::Castle, citadel::Citadel, cliff_tower::CliffTower,
|
||||||
desert_city_temple::DesertCityTemple, dungeon::Dungeon, giant_tree::GiantTree,
|
desert_city_multiplot::DesertCityMultiPlot, desert_city_temple::DesertCityTemple,
|
||||||
gnarling::GnarlingFortification, house::House, sea_chapel::SeaChapel, workshop::Workshop,
|
dungeon::Dungeon, giant_tree::GiantTree, gnarling::GnarlingFortification, house::House,
|
||||||
|
sea_chapel::SeaChapel, workshop::Workshop,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -61,4 +63,5 @@ pub enum PlotKind {
|
|||||||
Gnarling(GnarlingFortification),
|
Gnarling(GnarlingFortification),
|
||||||
GiantTree(GiantTree),
|
GiantTree(GiantTree),
|
||||||
CliffTower(CliffTower),
|
CliffTower(CliffTower),
|
||||||
|
Citadel(Citadel),
|
||||||
}
|
}
|
||||||
|
164
world/src/site2/plot/citadel.rs
Normal file
164
world/src/site2/plot/citadel.rs
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
use super::*;
|
||||||
|
use crate::{util::NEIGHBORS, Land};
|
||||||
|
use rand::prelude::*;
|
||||||
|
use std::ops::{Add, Div, Mul};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
struct Cell {
|
||||||
|
alt: i32,
|
||||||
|
colonade: Option<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
const CELL_SIZE: i32 = 16;
|
||||||
|
|
||||||
|
pub struct Citadel {
|
||||||
|
name: String,
|
||||||
|
_seed: u32,
|
||||||
|
origin: Vec3<i32>,
|
||||||
|
radius: i32,
|
||||||
|
grid: Grid<Option<Cell>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Citadel {
|
||||||
|
pub fn generate(wpos: Vec2<i32>, land: &Land, rng: &mut impl Rng) -> Self {
|
||||||
|
let alt = land.get_alt_approx(wpos) as i32;
|
||||||
|
|
||||||
|
let name = NameGen::location(rng).generate_town();
|
||||||
|
let seed = rng.gen();
|
||||||
|
let origin = wpos.with_z(alt);
|
||||||
|
|
||||||
|
let radius = 150;
|
||||||
|
|
||||||
|
let cell_radius = radius / CELL_SIZE;
|
||||||
|
let mut grid = Grid::populate_from(Vec2::broadcast((cell_radius + 1) * 2), |pos| {
|
||||||
|
let rpos = pos - cell_radius;
|
||||||
|
if rpos.magnitude_squared() < cell_radius.pow(2) {
|
||||||
|
let height = Lerp::lerp(
|
||||||
|
120.0,
|
||||||
|
24.0,
|
||||||
|
rpos.map(i32::abs).reduce_max() as f32 / cell_radius as f32,
|
||||||
|
);
|
||||||
|
let level_height = 32.0;
|
||||||
|
Some(Cell {
|
||||||
|
alt: land
|
||||||
|
.get_alt_approx(wpos + rpos * CELL_SIZE + CELL_SIZE / 2)
|
||||||
|
.add(height)
|
||||||
|
.div(level_height)
|
||||||
|
.floor()
|
||||||
|
.mul(level_height) as i32,
|
||||||
|
colonade: None,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for y in 0..grid.size().y {
|
||||||
|
for x in 0..grid.size().x {
|
||||||
|
let pos = Vec2::new(x, y);
|
||||||
|
if let Some(min_alt) = NEIGHBORS
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|rpos| Some(grid.get(pos + rpos)?.as_ref()?.alt))
|
||||||
|
.min()
|
||||||
|
{
|
||||||
|
let Some(Some(cell)) = grid.get_mut(pos)
|
||||||
|
else { continue };
|
||||||
|
if min_alt < cell.alt {
|
||||||
|
cell.colonade = Some(min_alt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
_seed: seed,
|
||||||
|
origin,
|
||||||
|
radius,
|
||||||
|
grid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str { &self.name }
|
||||||
|
|
||||||
|
pub fn radius(&self) -> i32 { self.radius }
|
||||||
|
|
||||||
|
pub fn spawn_rules(&self, wpos: Vec2<i32>) -> SpawnRules {
|
||||||
|
SpawnRules {
|
||||||
|
trees: (wpos - self.origin).map(i32::abs).reduce_max() > self.radius,
|
||||||
|
waypoints: false,
|
||||||
|
..SpawnRules::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wpos_cell(&self, wpos: Vec2<i32>) -> Vec2<i32> {
|
||||||
|
(wpos - self.origin) / CELL_SIZE + self.grid.size() / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cell_wpos(&self, pos: Vec2<i32>) -> Vec2<i32> {
|
||||||
|
(pos - self.grid.size() / 2) * CELL_SIZE + self.origin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Structure for Citadel {
|
||||||
|
fn render(&self, _site: &Site, land: &Land, painter: &Painter) {
|
||||||
|
for (pos, cell) in self.grid.iter_area(
|
||||||
|
self.wpos_cell(painter.render_aabr().min) - 1,
|
||||||
|
Vec2::<i32>::from(painter.render_aabr().size()) / CELL_SIZE + 2,
|
||||||
|
) {
|
||||||
|
if let Some(cell) = cell {
|
||||||
|
let wpos = self.cell_wpos(pos);
|
||||||
|
// Clear space above
|
||||||
|
painter
|
||||||
|
.aabb(Aabb {
|
||||||
|
min: wpos.with_z(cell.alt),
|
||||||
|
max: (wpos + CELL_SIZE).with_z(cell.alt + 16),
|
||||||
|
})
|
||||||
|
.clear();
|
||||||
|
|
||||||
|
let mut prim = painter.aabb(Aabb {
|
||||||
|
min: wpos.with_z(land.get_alt_approx(wpos + CELL_SIZE / 2) as i32 - 32),
|
||||||
|
max: (wpos + CELL_SIZE).with_z(cell.alt),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Colonades under cells
|
||||||
|
if let Some(colonade_alt) = cell.colonade {
|
||||||
|
let hole = painter
|
||||||
|
.aabb(Aabb {
|
||||||
|
min: wpos.with_z(colonade_alt),
|
||||||
|
max: (wpos + CELL_SIZE).with_z(cell.alt),
|
||||||
|
})
|
||||||
|
.intersect(painter.prim(Primitive::Superquadric {
|
||||||
|
aabb: Aabb {
|
||||||
|
min: (wpos - 1).with_z(colonade_alt - 32),
|
||||||
|
max: (wpos + 1 + CELL_SIZE).with_z(cell.alt - 1),
|
||||||
|
},
|
||||||
|
degree: 2.5,
|
||||||
|
}));
|
||||||
|
hole.clear();
|
||||||
|
prim = prim.without(hole);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walls around cells
|
||||||
|
for dir in CARDINALS {
|
||||||
|
if self
|
||||||
|
.grid
|
||||||
|
.get(pos + dir)
|
||||||
|
.and_then(Option::as_ref)
|
||||||
|
.map_or(true, |near| near.alt < cell.alt)
|
||||||
|
{
|
||||||
|
let offset = wpos + CELL_SIZE / 2 + dir * CELL_SIZE / 2;
|
||||||
|
let rad = dir.map(|e| if e == 0 { CELL_SIZE / 2 + 1 } else { 1 });
|
||||||
|
let height = if pos.sum() % 2 == 0 { 5 } else { 2 };
|
||||||
|
prim = prim.union(painter.aabb(Aabb {
|
||||||
|
min: (offset - rad).with_z(cell.alt - 6),
|
||||||
|
max: (offset + rad).with_z(cell.alt + height),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prim.fill(Fill::Brick(BlockKind::Rock, Rgb::new(100, 100, 100), 20));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user