mirror of
https://github.com/louis-e/arnis.git
synced 2026-01-05 12:48:08 -05:00
Add more natural elements
This commit is contained in:
@@ -108,6 +108,8 @@ pub fn generate_world(
|
||||
buildings::generate_building_from_relation(&mut editor, rel, args);
|
||||
} else if rel.tags.contains_key("water") {
|
||||
water_areas::generate_water_areas(&mut editor, rel);
|
||||
} else if rel.tags.contains_key("natural") {
|
||||
natural::generate_natural_from_relation(&mut editor, rel, args);
|
||||
} else if rel.tags.get("leisure") == Some(&"park".to_string()) {
|
||||
leisure::generate_leisure_from_relation(&mut editor, rel, args);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use crate::args::Args;
|
||||
use crate::block_definitions::*;
|
||||
use crate::bresenham::bresenham_line;
|
||||
use crate::coordinate_system::cartesian::XZPoint;
|
||||
use crate::element_processing::tree::Tree;
|
||||
use crate::floodfill::flood_fill_area;
|
||||
use crate::osm_parser::ProcessedElement;
|
||||
use crate::osm_parser::{ProcessedElement, ProcessedMemberRole, ProcessedRelation, ProcessedWay};
|
||||
use crate::world_editor::WorldEditor;
|
||||
use rand::Rng;
|
||||
|
||||
@@ -38,10 +39,19 @@ pub fn generate_natural(editor: &mut WorldEditor, element: &ProcessedElement, ar
|
||||
"blockfield" => COBBLESTONE,
|
||||
"glacier" => PACKED_ICE,
|
||||
"mud" | "wetland" => MUD,
|
||||
"mountain_range" => COBBLESTONE,
|
||||
"saddle" | "ridge" => STONE,
|
||||
"shrubbery" | "tundra" | "hill" => GRASS_BLOCK,
|
||||
"cliff" => STONE,
|
||||
_ => GRASS_BLOCK,
|
||||
};
|
||||
|
||||
let ProcessedElement::Way(way) = element else {
|
||||
println!(
|
||||
"Warning: Element with natural type '{}' is not a way, skipping.",
|
||||
natural_type
|
||||
);
|
||||
print!("Element: {element:?}");
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -82,16 +92,14 @@ pub fn generate_natural(editor: &mut WorldEditor, element: &ProcessedElement, ar
|
||||
// Generate custom layer instead of dirt, must be stone on the lowest level
|
||||
match natural_type.as_str() {
|
||||
"beach" | "sand" | "dune" | "shoal" => {
|
||||
editor.set_block(SAND, x, -1, z, None, None);
|
||||
editor.set_block(STONE, x, -2, z, None, None);
|
||||
editor.set_block(SAND, x, 0, z, None, None);
|
||||
}
|
||||
"glacier" => {
|
||||
editor.set_block(PACKED_ICE, x, -1, z, None, None);
|
||||
editor.set_block(STONE, x, -2, z, None, None);
|
||||
editor.set_block(PACKED_ICE, x, 0, z, None, None);
|
||||
editor.set_block(STONE, x, -1, z, None, None);
|
||||
}
|
||||
"bare_rock" => {
|
||||
editor.set_block(STONE, x, -1, z, None, None);
|
||||
editor.set_block(STONE, x, -2, z, None, None);
|
||||
editor.set_block(STONE, x, 0, z, None, None);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -254,6 +262,149 @@ pub fn generate_natural(editor: &mut WorldEditor, element: &ProcessedElement, ar
|
||||
editor.set_block(GRASS, x, 1, z, None, None);
|
||||
}
|
||||
}
|
||||
"mountain_range" => {
|
||||
// Create block clusters instead of random placement
|
||||
let cluster_chance = rng.gen_range(0..1000);
|
||||
|
||||
if cluster_chance < 50 { // 5% chance to start a new cluster
|
||||
let cluster_block = match rng.gen_range(0..7) {
|
||||
0 => DIRT,
|
||||
1 => STONE,
|
||||
2 => GRAVEL,
|
||||
3 => GRANITE,
|
||||
4 => DIORITE,
|
||||
5 => ANDESITE,
|
||||
_ => GRASS_BLOCK,
|
||||
};
|
||||
|
||||
// Generate cluster size (5-10 blocks radius)
|
||||
let cluster_size = rng.gen_range(5..=10);
|
||||
|
||||
// Create cluster around current position
|
||||
for dx in -(cluster_size as i32)..=(cluster_size as i32) {
|
||||
for dz in -(cluster_size as i32)..=(cluster_size as i32) {
|
||||
let cluster_x = x + dx;
|
||||
let cluster_z = z + dz;
|
||||
|
||||
// Use distance to create more natural cluster shape
|
||||
let distance = ((dx * dx + dz * dz) as f32).sqrt();
|
||||
if distance <= cluster_size as f32 {
|
||||
// Probability decreases with distance from center
|
||||
let place_prob = 1.0 - (distance / cluster_size as f32);
|
||||
if rng.gen::<f32>() < place_prob {
|
||||
editor.set_block(cluster_block, cluster_x, 0, cluster_z, None, None);
|
||||
|
||||
// Add vegetation on grass blocks
|
||||
if cluster_block == GRASS_BLOCK {
|
||||
let vegetation_chance = rng.gen_range(0..100);
|
||||
if vegetation_chance == 0 { // 1% chance for rare trees
|
||||
Tree::create(editor, (cluster_x, 1, cluster_z));
|
||||
} else if vegetation_chance < 15 { // 15% chance for grass
|
||||
editor.set_block(GRASS, cluster_x, 1, cluster_z, None, None);
|
||||
} else if vegetation_chance < 25 { // 10% chance for oak leaves
|
||||
editor.set_block(OAK_LEAVES, cluster_x, 1, cluster_z, None, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"saddle" => {
|
||||
// Saddle areas - lowest point between peaks, mix of stone and grass
|
||||
let terrain_chance = rng.gen_range(0..100);
|
||||
if terrain_chance < 30 { // 30% chance for exposed stone
|
||||
editor.set_block(STONE, x, 0, z, None, None);
|
||||
} else if terrain_chance < 50 { // 20% chance for gravel/rocky terrain
|
||||
editor.set_block(GRAVEL, x, 0, z, None, None);
|
||||
} else { // 50% chance for grass
|
||||
editor.set_block(GRASS_BLOCK, x, 0, z, None, None);
|
||||
if rng.gen_bool(0.4) { // 40% chance for grass on top
|
||||
editor.set_block(GRASS, x, 1, z, None, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
"ridge" => {
|
||||
// Ridge areas - elevated crest, mostly rocky with some vegetation
|
||||
let ridge_chance = rng.gen_range(0..100);
|
||||
if ridge_chance < 60 { // 60% chance for stone/rocky terrain
|
||||
let rock_type = match rng.gen_range(0..4) {
|
||||
0 => STONE,
|
||||
1 => COBBLESTONE,
|
||||
2 => GRANITE,
|
||||
_ => ANDESITE,
|
||||
};
|
||||
editor.set_block(rock_type, x, 0, z, None, None);
|
||||
} else { // 40% chance for grass with sparse vegetation
|
||||
editor.set_block(GRASS_BLOCK, x, 0, z, None, None);
|
||||
let vegetation_chance = rng.gen_range(0..100);
|
||||
if vegetation_chance < 20 { // 20% chance for grass
|
||||
editor.set_block(GRASS, x, 1, z, None, None);
|
||||
} else if vegetation_chance < 25 { // 5% chance for small shrubs
|
||||
editor.set_block(OAK_LEAVES, x, 1, z, None, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
"shrubbery" => {
|
||||
// Manicured shrubs and decorative vegetation
|
||||
editor.set_block(OAK_LEAVES, x, 1, z, None, None);
|
||||
editor.set_block(OAK_LEAVES, x, 2, z, None, None);
|
||||
}
|
||||
"tundra" => {
|
||||
// Treeless habitat with low vegetation, mosses, lichens
|
||||
if !editor.check_for_block(x, 0, z, Some(&[GRASS_BLOCK])) {
|
||||
continue;
|
||||
}
|
||||
let tundra_chance = rng.gen_range(0..100);
|
||||
if tundra_chance < 40 { // 40% chance for grass (sedges, grasses)
|
||||
editor.set_block(GRASS, x, 1, z, None, None);
|
||||
} else if tundra_chance < 60 { // 20% chance for moss
|
||||
editor.set_block(MOSS_BLOCK, x, 0, z, Some(&[GRASS_BLOCK]), None);
|
||||
} else if tundra_chance < 70 { // 10% chance for dead bush (lichens)
|
||||
editor.set_block(DEAD_BUSH, x, 1, z, None, None);
|
||||
}
|
||||
// 30% chance for bare ground (no surface block)
|
||||
}
|
||||
"cliff" => {
|
||||
// Cliff areas - predominantly stone with minimal vegetation
|
||||
let cliff_chance = rng.gen_range(0..100);
|
||||
if cliff_chance < 90 { // 90% chance for stone variants
|
||||
let stone_type = match rng.gen_range(0..4) {
|
||||
0 => STONE,
|
||||
1 => COBBLESTONE,
|
||||
2 => ANDESITE,
|
||||
_ => DIORITE,
|
||||
};
|
||||
editor.set_block(stone_type, x, 0, z, None, None);
|
||||
} else { // 10% chance for gravel/loose rock
|
||||
editor.set_block(GRAVEL, x, 0, z, None, None);
|
||||
}
|
||||
}
|
||||
"hill" => {
|
||||
// Hill areas - elevated terrain with sparse trees and mostly grass
|
||||
if !editor.check_for_block(x, 0, z, Some(&[GRASS_BLOCK])) {
|
||||
continue;
|
||||
}
|
||||
let hill_chance = rng.gen_range(0..1000);
|
||||
if hill_chance == 0 { // 0.1% chance for rare trees
|
||||
Tree::create(editor, (x, 1, z));
|
||||
} else if hill_chance < 50 { // 5% chance for flowers
|
||||
let flower_block = match rng.gen_range(1..=4) {
|
||||
1 => RED_FLOWER,
|
||||
2 => BLUE_FLOWER,
|
||||
3 => YELLOW_FLOWER,
|
||||
_ => WHITE_FLOWER,
|
||||
};
|
||||
editor.set_block(flower_block, x, 1, z, None, None);
|
||||
} else if hill_chance < 600 { // 55% chance for grass
|
||||
editor.set_block(GRASS, x, 1, z, None, None);
|
||||
} else if hill_chance < 650 { // 5% chance for tall grass
|
||||
editor.set_block(TALL_GRASS_BOTTOM, x, 1, z, None, None);
|
||||
editor.set_block(TALL_GRASS_TOP, x, 2, z, None, None);
|
||||
}
|
||||
// 35% chance for bare grass block
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -261,3 +412,39 @@ pub fn generate_natural(editor: &mut WorldEditor, element: &ProcessedElement, ar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_natural_from_relation(
|
||||
editor: &mut WorldEditor,
|
||||
rel: &ProcessedRelation,
|
||||
args: &Args,
|
||||
) {
|
||||
if rel.tags.contains_key("natural") {
|
||||
// Generate individual ways with their original tags
|
||||
for member in &rel.members {
|
||||
if member.role == ProcessedMemberRole::Outer {
|
||||
generate_natural(editor, &ProcessedElement::Way(member.way.clone()), args);
|
||||
}
|
||||
}
|
||||
|
||||
// Combine all outer ways into one with relation tags
|
||||
let mut combined_nodes = Vec::new();
|
||||
for member in &rel.members {
|
||||
if member.role == ProcessedMemberRole::Outer {
|
||||
combined_nodes.extend(member.way.nodes.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Only process if we have nodes
|
||||
if !combined_nodes.is_empty() {
|
||||
// Create combined way with relation tags
|
||||
let combined_way = ProcessedWay {
|
||||
id: rel.id,
|
||||
nodes: combined_nodes,
|
||||
tags: rel.tags.clone(),
|
||||
};
|
||||
|
||||
// Generate natural area from combined way
|
||||
generate_natural(editor, &ProcessedElement::Way(combined_way), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user