1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
//! Biome data and enums.
//!
//! Biomes are made up of four components: a general biome, a humidity level, an altitude level, and a latitude level.
//! These are then used during map generation to build a map matching the biome.
//!
//! During generation, a bunch of `Marker` biomes are added to a map, and then the `Realm` is used to convert these
//! markers into actual biomes.
//!
//! Currently there are 20 `Marker` biomes which are spread out among elevations. This is very simplistic and will
//! need a rework in the future to be more flexible and to allow for more biomes. Given that we require the latitude,
//! altitude and humidity for each biome, the complexity of the actual biome generation system can be a lot more complex
//! than just assigning biomes based on an elevation value. (Todo..)
//!
//! Other things that should be considered later on:
//!
//! - Rivers and streams (and lakes)
//! - Biome transitions
//! - Biome specific objects (stones, trees, etc)
//! - Biome specific weather (weather?)
//! - Biome specific monsters and animals
//! - Biome specific resources
use bevy::prelude::*;
use bevy::reflect::Reflect;
use crate::colors;
/// A base biome enum. This is then further used with the type of primal realm
/// to determine the actual biome. This biome is set by the noise generator, and
/// it describes the "height" of the terrain, and that should then be interpreted
/// later (see the implementations for this enum) to determine the actual biome.
///
/// Supports maps with up to 10 different biomes.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
PartialOrd,
Ord,
)]
#[serde(rename_all = "camelCase")]
#[allow(clippy::module_name_repetitions)]
pub enum Marker {
/// An empty marker.
#[default]
Empty,
/// The lowest elevation
Elevation0,
/// The second lowest possible biome.
Elevation1,
/// The third lowest possible biome.
Elevation2,
/// The fourth lowest possible biome.
Elevation3,
/// The fifth lowest possible biome.
Elevation4,
/// The sixth lowest possible biome.
Elevation5,
/// The seventh lowest possible biome.
Elevation6,
/// The eighth lowest possible biome.
Elevation7,
/// The ninth lowest possible biome.
Elevation8,
/// The tenth lowest possible biome.
Elevation9,
/// The 11th lowest possible biome.
Elevation10,
/// The 12th lowest possible biome.
Elevation11,
/// The 13th lowest possible biome.
Elevation12,
/// The 14th lowest possible biome.
Elevation13,
/// The 15th lowest possible biome.
Elevation14,
/// The 16th lowest possible biome.
Elevation15,
/// The 17th lowest possible biome.
Elevation16,
/// The 18th lowest possible biome.
Elevation17,
/// The 19th lowest possible biome.
Elevation18,
/// The 20th lowest possible biome.
Elevation19,
}
impl Marker {
/// Convert the marker into an elevation value. If the marker is `Empty`, then
/// the elevation is 0. Otherwise, the elevation is the marker as an integer
/// which matches the `Marker::Elevation1` variant.
///
/// # Returns
///
/// The elevation value of the marker.
#[must_use]
pub const fn as_elevation_idx(&self) -> usize {
match self {
Self::Empty | Self::Elevation0 => 0,
Self::Elevation1 => 1,
Self::Elevation2 => 2,
Self::Elevation3 => 3,
Self::Elevation4 => 4,
Self::Elevation5 => 5,
Self::Elevation6 => 6,
Self::Elevation7 => 7,
Self::Elevation8 => 8,
Self::Elevation9 => 9,
Self::Elevation10 => 10,
Self::Elevation11 => 11,
Self::Elevation12 => 12,
Self::Elevation13 => 13,
Self::Elevation14 => 14,
Self::Elevation15 => 15,
Self::Elevation16 => 16,
Self::Elevation17 => 17,
Self::Elevation18 => 18,
Self::Elevation19 => 19,
}
}
/// Given the noise value, returns the biome marker.
///
/// # Arguments
///
/// * `noise` - The noise value to determine the biome marker for.
///
/// # Returns
///
/// The biome marker for the given noise value.
#[must_use]
pub fn from_noise(noise: f64) -> Self {
match noise {
v if v < -0.9 => Self::Elevation0,
v if v < -0.8 => Self::Elevation1,
v if v < -0.7 => Self::Elevation2,
v if v < -0.6 => Self::Elevation3,
v if v < -0.5 => Self::Elevation4,
v if v < -0.4 => Self::Elevation5,
v if v < -0.3 => Self::Elevation6,
v if v < -0.2 => Self::Elevation7,
v if v < -0.1 => Self::Elevation8,
v if v < 0.0 => Self::Elevation9,
v if v < 0.1 => Self::Elevation10,
v if v < 0.2 => Self::Elevation11,
v if v < 0.3 => Self::Elevation12,
v if v < 0.4 => Self::Elevation13,
v if v < 0.5 => Self::Elevation14,
v if v < 0.6 => Self::Elevation15,
v if v < 0.7 => Self::Elevation16,
v if v < 0.8 => Self::Elevation17,
v if v < 0.9 => Self::Elevation18,
v if v <= 1.0 => Self::Elevation19,
_ => {
tracing::warn!("Noise value out of range: {}", noise);
Self::Empty
}
}
}
}
/// The actual biomes that are used in the game. These are then used to draw the terrain
/// and to determine the type of objects that are placed in the world. Since this the number
/// of actual biomes is much greater than the number of generic biomes, to determine the actual
/// biome the Realm type needs to be used with the `biome_for_realm` method.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
Resource,
Reflect,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub enum Biome {
/// Rainforests are forests characterized by a closed and continuous tree canopy, moisture-dependent
/// vegetation, the presence of epiphytes and lianas and the absence of wildfire.
Rainforest,
/// Seasonal tropical forest, also known as moist deciduous, semi-evergreen seasonal, tropical mixed or
/// monsoon forest, typically contains a range of tree species: many of which drop some or all of
/// their leaves during the dry season.
SeasonalDeciduousRainforest,
/// Seasonal tropical forest, also known as moist deciduous, semi-evergreen seasonal, tropical mixed or
/// monsoon forest, typically contains a range of tree species: only some of which drop some or all of
/// their leaves during the dry season.
SeasonalSemidecidousRainforest,
/// A rainforest with extra large trees.
GiantRainforest,
/// Deciduous or broad-leaf forests are a variety of forest 'dominated' by deciduous trees that lose their
/// leaves each winter.
DeciduousForest,
/// Coniferous forests are made up of coniferous or cone-bearing trees, most of which are evergreens.
ConiferousForest,
/// Characterized by coniferous forests consisting mostly of pines, spruces, and larches.
Taiga,
/// Land covered with woody plants, mainly trees, and shrubs.
Woodland,
/// Plant community dominated by shrubs, often with small or no trees.
Shrubland,
/// Savanna is a type of grassland with scattered trees.
Savanna,
/// Grassland is a type of land with grass and very few trees.
Grassland,
/// A biome where tree growth is hindered by frigid temperatures and short growing seasons.
Tundra,
/// A biome where little precipitation occurs and consequently living conditions are hostile for plant and
/// animal life.
Desert,
/// Plant community dominated by grasses, often with small or no shrubs.
Scrub,
/// A wetland with spongy ground and a lot of moss.
Bog,
/// A wetland that features permanent inundation of large areas of land by shallow bodies of water, generally
/// with substantial tree cover.
FreshwaterSwamp,
/// A wetland that features permanent inundation of large areas of land by shallow bodies of water, generally
/// with little tree cover. This one has saltwater.
SaltwaterSwamp,
/// An area of coastal grassland that is frequently flooded by seawater.
Saltmarsh,
/// A wetland that is dominated by herbaceous rather than woody plant species.
Wetland,
/// A large body of water, either fresh or salt, that is surrounded by land.
LargeLake,
/// A river delta is a landform shaped like a triangle, created by the deposition of sediment that is carried
/// by a river and enters slower-moving or stagnant water. This occurs at a river mouth, when it enters an ocean,
/// sea, estuary, lake, reservoir, or another river that cannot carry away the supplied sediment.
RiverDelta,
/// Rivers that flow into the ocean.
CoastalRiver,
/// Rivers that flow into a lake.
InlandRiver,
/// An area of low-lying ground adjacent to a river, formed mainly of river sediments and subject to flooding.
Floodplain,
/// A fast-flowing river, typically with a steep gradient and a rocky bed.
UplandRiver,
/// An endorheic basin is a drainage basin that normally retains water and allows no outflow to other, external
/// bodies of water; instead, the water drainage flows into permanent and seasonal lakes and swamps that equilibrate
/// through evaporation.
EndorheicBasin,
/// An island that rises to the ocean surface from the ocean floor.
OceanicIsland,
/// A very large body of salt water. Forms beaches next to land, but can also be found in the middle of the ocean.
Sea,
/// A large body of salt water that is extremely deep. This is not found near land.
DeepSea,
/// A large body of salt water with a flat bottom. This is not found near land.
SeaShelf,
/// An area of sea with a lot of coral reefs and other marine life.
CoralReef,
/// An area of sea that has a lot of kelp. Supports a lot of marine life.
KelpForest,
/// A persistent body of dense ice that is constantly moving under its own weight. A glacier forms where the accumulation
/// of snow exceeds its ablation over many years, often centuries.
Glacier,
/// A very large sheet of ice that permanently covers the land.
IceSheet,
/// Nothing
#[default]
Barren,
/// A biome that represents the inside of a building.
Indoor,
/// A cityscape or other urban development.
Urban,
/// Land that has been cleared of trees for farmland.
Cultivated,
/// Forested land that is used for logging or has otherwise been planted intentionally.
Forested,
/// Land that has been cleared of trees and is used for grazing animals.
Rangeland,
}
impl Biome {
/// Get the default color for the biome.
///
/// This is the color that is used when the biome is not assigned a color.
///
/// # Returns
///
/// The default color for the biome.
#[must_use]
pub const fn get_color(&self) -> Color {
match self {
Self::Rainforest => colors::RANGITOTO,
Self::SeasonalDeciduousRainforest
| Self::SeasonalSemidecidousRainforest
| Self::GiantRainforest
| Self::DeciduousForest
| Self::ConiferousForest => colors::COSTA_DEL_SOL,
Self::Taiga => colors::OLIVINE,
Self::Woodland => colors::NANDOR,
Self::Shrubland | Self::Savanna | Self::Grassland => colors::SUSHI,
Self::Tundra => colors::HAMPTON,
Self::Desert => colors::MONGOOSE,
Self::Scrub => colors::LAUREL,
Self::Bog | Self::FreshwaterSwamp | Self::Wetland | Self::SaltwaterSwamp => {
colors::OUTER_SPACE
}
Self::Saltmarsh
| Self::LargeLake
| Self::RiverDelta
| Self::CoastalRiver
| Self::InlandRiver
| Self::Floodplain
| Self::UplandRiver
| Self::EndorheicBasin => colors::STEEL_BLUE,
Self::OceanicIsland => colors::CHALKY,
Self::Sea | Self::DeepSea | Self::SeaShelf | Self::CoralReef | Self::KelpForest => {
colors::CLOUD_BURST
}
Self::Glacier | Self::IceSheet => colors::MYSTIC,
Self::Barren => colors::LIGHTER_SAND_DUNE,
Self::Indoor | Self::Urban => colors::KANGAROO,
Self::Cultivated | Self::Forested | Self::Rangeland => colors::COCOA_BROWN,
}
}
}
/// Humidity of the biome. These are descriptions humidity provinces of the biome. Ordered from driest to wettest.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
Resource,
Reflect,
Default,
serde::Serialize,
serde::Deserialize,
PartialOrd,
Ord,
)]
pub enum Humidity {
/// Extremely dry
Superarid,
/// Very dry
Perarid,
/// Dry
Arid,
/// Somewhat dry
#[default]
Semiarid,
/// Somewhat wet
Subhumid,
/// Wet
Humid,
/// Very wet
Perhumid,
/// Extremely wet
Superhumid,
}
/// Altitude of the biome (altitudinal belts). These are descriptions of the
/// biotemperature of the biome. Ordered from coldest to warmest.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
Resource,
Reflect,
Default,
serde::Serialize,
serde::Deserialize,
PartialOrd,
Ord,
)]
pub enum Altitude {
/// Cooler than 1.5 Celsius
Alvar,
/// Within 1.5-3 Celsius
Alpine,
/// Within 3-6 Celsius
Subalpine,
/// Within 6-12 Celsius
#[default]
Montane,
/// Within 12-24 Celsius
LowerMontane,
/// Warmer than 24 Celsius
Premontane,
}
/// Describes the latitudinal regions of the biome (temperature bands). ordered from warmest to coldest.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
Resource,
Reflect,
Default,
serde::Serialize,
serde::Deserialize,
PartialOrd,
Ord,
)]
pub enum Latitude {
/// Close to the equator
Tropical,
/// 2nd closest to the equator
Subtropical,
/// 3rd closest to the equator
#[default]
WarmTemperate,
/// 4th closest to the equator and poles
CoolTemperate,
/// 3rd closest to the poles
Boreal,
/// Close to the poles
Subpolar,
/// Closest to the poles
Polar,
}