From 6dae58c8a6151a31ec030c3f395aeacf657827f2 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Fri, 11 Jun 2021 07:09:58 +0100
Subject: [PATCH] Prevent creatures spawning in the ground

---
 world/src/layer/mod.rs      | 116 +++++++++++++++++++-----------------
 world/src/layer/wildlife.rs |  52 ++++++++--------
 2 files changed, 88 insertions(+), 80 deletions(-)

diff --git a/world/src/layer/mod.rs b/world/src/layer/mod.rs
index c44d21492e..9c12b4c130 100644
--- a/world/src/layer/mod.rs
+++ b/world/src/layer/mod.rs
@@ -439,62 +439,70 @@ pub fn apply_caves_supplement<'a>(
                 let cave_depth = (col_sample.alt - cave.alt).max(0.0); //slightly different from earlier cave depth?
 
                 // Scatter things in caves
-                if RandomField::new(index.seed).chance(wpos2d.into(), 0.0018)
-                    && cave_base < surface_z as i32 - 40
-                {
-                    let is_hostile: bool;
-                    let entity = EntityInfo::at(Vec3::new(
-                        wpos2d.x as f32,
-                        wpos2d.y as f32,
-                        cave_base as f32,
-                    ))
-                    .with_body(if cave_depth < 70.0 {
-                        is_hostile = false;
-                        let species = match dynamic_rng.gen_range(0..4) {
-                            0 => comp::quadruped_small::Species::Truffler,
-                            1 => comp::quadruped_small::Species::Dodarock,
-                            2 => comp::quadruped_small::Species::Holladon,
-                            _ => comp::quadruped_small::Species::Batfox,
-                        };
-                        comp::quadruped_small::Body::random_with(dynamic_rng, &species).into()
-                    } else if cave_depth < 120.0 {
-                        is_hostile = true;
-                        let species = match dynamic_rng.gen_range(0..3) {
-                            0 => comp::quadruped_low::Species::Rocksnapper,
-                            1 => comp::quadruped_low::Species::Salamander,
-                            _ => comp::quadruped_low::Species::Asp,
-                        };
-                        comp::quadruped_low::Body::random_with(dynamic_rng, &species).into()
-                    } else if cave_depth < 200.0 {
-                        is_hostile = true;
-                        let species = match dynamic_rng.gen_range(0..3) {
-                            0 => comp::quadruped_low::Species::Rocksnapper,
-                            1 => comp::quadruped_low::Species::Lavadrake,
-                            _ => comp::quadruped_low::Species::Basilisk,
-                        };
-                        comp::quadruped_low::Body::random_with(dynamic_rng, &species).into()
-                    } else {
-                        is_hostile = true;
-                        let species = match dynamic_rng.gen_range(0..5) {
-                            0 => comp::biped_large::Species::Ogre,
-                            1 => comp::biped_large::Species::Cyclops,
-                            2 => comp::biped_large::Species::Wendigo,
-                            3 => match dynamic_rng.gen_range(0..2) {
-                                0 => comp::biped_large::Species::Blueoni,
-                                _ => comp::biped_large::Species::Redoni,
-                            },
-                            _ => comp::biped_large::Species::Troll,
-                        };
-                        comp::biped_large::Body::random_with(dynamic_rng, &species).into()
+                if let Some(z) = (-4..8).map(|z| cave_base + z).find(|z| {
+                    (0..2).all(|z_offs| {
+                        vol.get(offs.with_z(z + z_offs))
+                            .map_or(true, |b| b.is_fluid())
                     })
-                    .with_alignment(if is_hostile {
-                        comp::Alignment::Enemy
-                    } else {
-                        comp::Alignment::Wild
-                    })
-                    .with_automatic_name();
+                }) {
+                    if RandomField::new(index.seed).chance(wpos2d.into(), 0.0018)
+                        && cave_base < surface_z as i32 - 40
+                    {
+                        let is_hostile: bool;
+                        let entity =
+                            EntityInfo::at(Vec3::new(wpos2d.x as f32, wpos2d.y as f32, z as f32))
+                                .with_body(if cave_depth < 70.0 {
+                                    is_hostile = false;
+                                    let species = match dynamic_rng.gen_range(0..4) {
+                                        0 => comp::quadruped_small::Species::Truffler,
+                                        1 => comp::quadruped_small::Species::Dodarock,
+                                        2 => comp::quadruped_small::Species::Holladon,
+                                        _ => comp::quadruped_small::Species::Batfox,
+                                    };
+                                    comp::quadruped_small::Body::random_with(dynamic_rng, &species)
+                                        .into()
+                                } else if cave_depth < 120.0 {
+                                    is_hostile = true;
+                                    let species = match dynamic_rng.gen_range(0..3) {
+                                        0 => comp::quadruped_low::Species::Rocksnapper,
+                                        1 => comp::quadruped_low::Species::Salamander,
+                                        _ => comp::quadruped_low::Species::Asp,
+                                    };
+                                    comp::quadruped_low::Body::random_with(dynamic_rng, &species)
+                                        .into()
+                                } else if cave_depth < 200.0 {
+                                    is_hostile = true;
+                                    let species = match dynamic_rng.gen_range(0..3) {
+                                        0 => comp::quadruped_low::Species::Rocksnapper,
+                                        1 => comp::quadruped_low::Species::Lavadrake,
+                                        _ => comp::quadruped_low::Species::Basilisk,
+                                    };
+                                    comp::quadruped_low::Body::random_with(dynamic_rng, &species)
+                                        .into()
+                                } else {
+                                    is_hostile = true;
+                                    let species = match dynamic_rng.gen_range(0..5) {
+                                        0 => comp::biped_large::Species::Ogre,
+                                        1 => comp::biped_large::Species::Cyclops,
+                                        2 => comp::biped_large::Species::Wendigo,
+                                        3 => match dynamic_rng.gen_range(0..2) {
+                                            0 => comp::biped_large::Species::Blueoni,
+                                            _ => comp::biped_large::Species::Redoni,
+                                        },
+                                        _ => comp::biped_large::Species::Troll,
+                                    };
+                                    comp::biped_large::Body::random_with(dynamic_rng, &species)
+                                        .into()
+                                })
+                                .with_alignment(if is_hostile {
+                                    comp::Alignment::Enemy
+                                } else {
+                                    comp::Alignment::Wild
+                                })
+                                .with_automatic_name();
 
-                    supplement.add_entity(entity);
+                        supplement.add_entity(entity);
+                    }
                 }
             }
         }
diff --git a/world/src/layer/wildlife.rs b/world/src/layer/wildlife.rs
index 8e2c007608..f15ec3a9bc 100644
--- a/world/src/layer/wildlife.rs
+++ b/world/src/layer/wildlife.rs
@@ -1063,37 +1063,37 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
                 },
             );
 
+            let alt = col_sample.alt as i32;
+
             if let Some((make_entity, group_size)) = entity_group {
-                let alt = col_sample.alt as i32;
-                // Find the intersection between ground and air, if there is one near the
-                // surface
-                if let Some(solid_end) = (-4..8)
-                    .find(|z| {
-                        vol.get(Vec3::new(offs.x, offs.y, alt + z))
-                            .map(|b| b.is_solid())
-                            .unwrap_or(false)
-                    })
-                    .and_then(|solid_start| {
-                        (1..8).map(|z| solid_start + z).find(|z| {
-                            vol.get(Vec3::new(offs.x, offs.y, alt + z))
+                let group_size = dynamic_rng.gen_range(group_size.start..group_size.end);
+                let entity = make_entity(
+                    (wpos2d.map(|e| e as f32) + 0.5).with_z(alt as f32),
+                    dynamic_rng,
+                );
+                for e in 0..group_size {
+                    // Choose a nearby position
+                    let offs_wpos2d = (Vec2::new(
+                        (e as f32 / group_size as f32 * 2.0 * f32::consts::PI).sin(),
+                        (e as f32 / group_size as f32 * 2.0 * f32::consts::PI).cos(),
+                    ) * (5.0 + dynamic_rng.gen::<f32>().powf(0.5) * 5.0))
+                        .map(|e| e as i32);
+                    // Clamp position to chunk
+                    let offs_wpos2d = (offs + offs_wpos2d)
+                        .clamped(Vec2::zero(), vol.size_xy().map(|e| e as i32) - 1)
+                        - offs;
+
+                    // Find the intersection between ground and air, if there is one near the
+                    // surface
+                    if let Some(solid_end) = (-8..8).find(|z| {
+                        (0..2).all(|z2| {
+                            vol.get(Vec3::new(offs.x, offs.y, alt) + offs_wpos2d.with_z(z + z2))
                                 .map(|b| !b.is_solid())
                                 .unwrap_or(true)
                         })
-                    })
-                {
-                    let group_size = dynamic_rng.gen_range(group_size.start..group_size.end);
-                    let entity = make_entity(
-                        Vec3::new(wpos2d.x, wpos2d.y, alt + solid_end).map(|e| e as f32),
-                        dynamic_rng,
-                    );
-                    for e in 0..group_size {
+                    }) {
                         let mut entity = entity.clone();
-                        entity.pos = entity.pos.map(|e| e + dynamic_rng.gen::<f32>())
-                            + Vec3::new(
-                                (e as f32 / group_size as f32 * 2.0 * f32::consts::PI).sin(),
-                                (e as f32 / group_size as f32 * 2.0 * f32::consts::PI).cos(),
-                                0.0,
-                            ) * (5.0 + dynamic_rng.gen::<f32>().powf(0.5) * 5.0);
+                        entity.pos += offs_wpos2d.with_z(solid_end).map(|e| e as f32);
                         supplement.add_entity(entity.with_automatic_name());
                     }
                 }