Added poi for all biomes

This commit is contained in:
IsseW 2022-01-16 16:54:49 +01:00
parent d5f0ee2fc5
commit 5bd7507f31
2 changed files with 52 additions and 108 deletions

View File

@ -4,10 +4,10 @@ mod econ;
use crate::{
config::CONFIG,
sim::{RiverKind, WorldSim},
sim::WorldSim,
site::{namegen::NameGen, Castle, Settlement, Site as WorldSite, Tree},
site2,
util::{attempt, seed_expan, CARDINALS, NEIGHBORS},
util::{attempt, seed_expan, NEIGHBORS},
Index, Land,
};
use common::{
@ -15,7 +15,7 @@ use common::{
path::Path,
spiral::Spiral2d,
store::{Id, Store},
terrain::{uniform_idx_as_vec2, vec2_as_uniform_idx, MapSizeLg, TerrainChunkSize},
terrain::{uniform_idx_as_vec2, MapSizeLg, TerrainChunkSize},
vol::RectVolSize,
};
use core::{fmt, hash::BuildHasherDefault, ops::Range};
@ -89,8 +89,8 @@ impl Civs {
let mut ctx = GenCtx { sim, rng };
info!("starting peak naming");
this.name_peaks(&mut ctx);
info!("starting lake naming");
this.name_lakes(&mut ctx);
info!("starting biome naming");
this.name_biomes(&mut ctx);
for _ in 0..ctx.sim.get_size().product() / 10_000 {
this.generate_cave(&mut ctx);
@ -468,113 +468,57 @@ impl Civs {
}
/// Adds lake POIs and names them
fn name_lakes(&mut self, ctx: &mut GenCtx<impl Rng>) {
fn name_biomes(&mut self, ctx: &mut GenCtx<impl Rng>) {
let map_size_lg = ctx.sim.map_size_lg();
let rng = &mut ctx.rng;
let sim_chunks = &ctx.sim.chunks;
let lakes = sim_chunks
.iter()
.enumerate()
.filter(|(posi, chunk)| {
let neighbor_alts_min = common::terrain::neighbors(map_size_lg, *posi)
.map(|i| sim_chunks[i].alt as u32)
.min();
chunk
.river
.river_kind
.map_or(false, |r_kind| matches!(r_kind, RiverKind::Lake { .. }))
&& neighbor_alts_min.map_or(false, |n_alt| (chunk.alt as u32) < n_alt)
})
.map(|(posi, chunk)| {
(
uniform_idx_as_vec2(map_size_lg, posi),
chunk.alt as u32,
chunk.water_alt as u32,
)
})
.collect::<Vec<(Vec2<i32>, u32, u32)>>();
let mut removals = vec![false; lakes.len()];
let mut lake_alts = HashSet::new();
for (i, (loc, alt, water_alt)) in lakes.iter().enumerate() {
for (k, (n_loc, n_alt, n_water_alt)) in lakes.iter().enumerate() {
// If the difference in position of this low point and another is
// below a threshold and this chunk's altitude is higher, remove the
// lake from the list. Also remove shallow ponds.
// If this lake water altitude is already accounted for and the lake bed
// altitude is lower than the neighboring lake bed altitude, remove this
// lake from the list. Otherwise, add this lake water altitude to the list
// of counted lake water altitudes.
if i != k
&& (*water_alt <= CONFIG.sea_level as u32
|| (!lake_alts.insert(water_alt)
&& water_alt == n_water_alt
&& alt > n_alt)
|| ((loc).distance_squared(*n_loc) < POI_THINNING_DIST_SQRD
&& alt >= n_alt))
{
// This cannot panic as `removals` is the same length as `lakes`
// i is the index in `lakes`
removals[i] = true;
}
}
}
let mut num_lakes = 0;
for (_j, (loc, alt, water_alt)) in lakes.iter().enumerate().filter(|&(i, _)| !removals[i]) {
// Recenter the location of the lake POI
// Sample every few units to speed this up
let sample_step = 3;
let mut chords: [i32; 4] = [0, 0, 0, 0];
// only search up to 100 chunks in any direction
for (j, chord) in chords.iter_mut().enumerate() {
for i in 0..100 {
let posi = vec2_as_uniform_idx(
map_size_lg,
Vec2::new(loc.x, loc.y) + CARDINALS[j] * sample_step * i,
);
if let Some(r_kind) = sim_chunks[posi].river.river_kind {
if matches!(r_kind, RiverKind::Lake { .. }) {
*chord += sample_step;
} else {
break;
}
let mut biomes: Vec<(common::terrain::BiomeKind, Vec<usize>)> = Vec::new();
let mut explored = HashSet::new();
let mut to_explore = HashSet::new();
let mut to_floodfill = HashSet::new();
// TODO: have start point in center and ignore ocean?
let start_point = 0;
to_explore.insert(start_point);
explored.insert(start_point);
while to_explore.len() > 0 {
let exploring = *to_explore.iter().next().unwrap();
to_explore.remove(&exploring);
to_floodfill.insert(exploring);
// Should always be a chunk on the map
let biome = ctx.sim.chunks[exploring].get_biome();
biomes.push((biome, Vec::new()));
while to_floodfill.len() > 0 {
let filling = *to_floodfill.iter().next().unwrap();
to_explore.remove(&filling);
to_floodfill.remove(&filling);
explored.insert(filling);
biomes.last_mut().unwrap().1.push(filling);
for neighbour in common::terrain::neighbors(map_size_lg, filling) {
if explored.contains(&neighbour) {
continue;
}
let n_biome = ctx.sim.chunks[neighbour].get_biome();
if n_biome == biome {
to_floodfill.insert(neighbour);
} else {
break;
to_explore.insert(neighbour);
}
}
}
let center_y = ((chords[0] + chords[1]) / 2) - chords[1] + loc.y;
let center_x = ((chords[2] + chords[3]) / 2) - chords[3] + loc.x;
let new_loc = Vec2::new(center_x, center_y);
let size_parameter = ((chords[2] + chords[3]) + (chords[0] + chords[1]) / 4) as u32;
let lake = PointOfInterest {
name: {
let name = NameGen::location(rng).generate_biome();
if size_parameter > 30 {
format!("{} Sea", name)
} else if (water_alt - alt) < 30 {
match rng.gen_range(0..5) {
0 => format!("{} Shallows", name),
1 => format!("{} Pool", name),
2 => format!("{} Well", name),
_ => format!("{} Pond", name),
}
} else {
match rng.gen_range(0..6) {
0 => format!("{} Lake", name),
1 => format!("Loch {}", name),
_ => format!("Lake {}", name),
}
}
},
// Size parameter is based on the east west chord length with a smaller factor from
// the north south chord length. This is used for text scaling on the map
kind: PoiKind::Lake(size_parameter),
loc: new_loc,
};
num_lakes += 1;
self.pois.insert(lake);
}
info!(?num_lakes, "all lakes named");
let num_biomes = biomes.len();
for biome in biomes {
// Select point
let idx = biome.1[ctx.rng.gen_range(0..biome.1.len())];
let name = format!("{:?}", biome.0);
self.pois.insert(PointOfInterest {
name,
loc: uniform_idx_as_vec2(map_size_lg, idx),
kind: PoiKind::Biome(biome.1.len() as u32),
});
}
info!(?num_biomes, "all biomes named");
}
/// Adds mountain POIs and name them
@ -934,5 +878,5 @@ pub enum PoiKind {
/// Peak stores the altitude
Peak(u32),
/// Lake stores a metric relating to size
Lake(u32),
Biome(u32),
}

View File

@ -131,7 +131,7 @@ impl World {
name: poi.name.clone(),
kind: match &poi.kind {
civ::PoiKind::Peak(alt) => world_msg::PoiKind::Peak(*alt),
civ::PoiKind::Lake(size) => world_msg::PoiKind::Lake(*size),
civ::PoiKind::Biome(size) => world_msg::PoiKind::Lake(*size),
},
wpos: poi.loc * TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
}