From 2d8b75046f6c15e9263f1fc06f8d4f708af55e2e Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Sun, 19 Apr 2020 16:34:23 +0100
Subject: [PATCH] Agent adjustments, better dungeon stairwells

---
 common/src/sys/agent.rs       | 22 ++++++----
 world/src/site/dungeon/mod.rs | 79 ++++++++++++++++++-----------------
 2 files changed, 54 insertions(+), 47 deletions(-)

diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs
index ea8c63d3de..504ecb336d 100644
--- a/common/src/sys/agent.rs
+++ b/common/src/sys/agent.rs
@@ -154,7 +154,7 @@ impl<'a> System<'a> for Sys {
                         }
 
                         // Sometimes try searching for new targets
-                        if thread_rng().gen::<f32>() < 0.05  {
+                        if thread_rng().gen::<f32>() < 0.1  {
                             choose_target = true;
                         }
                     },
@@ -240,7 +240,7 @@ impl<'a> System<'a> for Sys {
                                     inputs.roll.set_state(true);
                                 }
                             } else if dist_sqrd < MAX_CHASE_DIST.powf(2.0)
-                                || (dist_sqrd < SIGHT_DIST.powf(2.0) && !*been_close)
+                                || (dist_sqrd < SIGHT_DIST.powf(2.0) && (!*been_close || !matches!(tactic, Tactic::Melee)))
                             {
                                 let can_see_tgt = terrain
                                     .ray(pos.0 + Vec3::unit_z(), tgt_pos.0 + Vec3::unit_z())
@@ -264,10 +264,10 @@ impl<'a> System<'a> for Sys {
 
                                         inputs.secondary.set_state(true);
                                     }
+                                }
 
-                                    if dist_sqrd < MAX_CHASE_DIST.powf(2.0) {
-                                        *been_close = true;
-                                    }
+                                if dist_sqrd < MAX_CHASE_DIST.powf(2.0) {
+                                    *been_close = true;
                                 }
 
                                 // Long-range chase
@@ -280,8 +280,9 @@ impl<'a> System<'a> for Sys {
                                     inputs.jump.set_state(bearing.z > 1.0);
                                 }
 
-                                if dist_sqrd < (MAX_CHASE_DIST * 0.65).powf(2.0)
-                                    && thread_rng().gen::<f32>() < 0.01
+                                if dist_sqrd < 16.0f32.powf(2.0)
+                                    && matches!(tactic, Tactic::Melee)
+                                    && thread_rng().gen::<f32>() < 0.02
                                 {
                                     inputs.roll.set_state(true);
                                 }
@@ -307,8 +308,11 @@ impl<'a> System<'a> for Sys {
                 let closest_entity = (&entities, &positions, &stats, alignments.maybe())
                     .join()
                     .filter(|(e, e_pos, e_stats, e_alignment)| {
-                        ((e_pos.0.distance_squared(pos.0) < SEARCH_DIST.powf(2.0) && (e_pos.0 - pos.0).try_normalized().map(|v| v.dot(*inputs.look_dir) > 0.3).unwrap_or(true))
-                            || e_pos.0.distance_squared(pos.0) < LISTEN_DIST.powf(2.0))
+                        ((e_pos.0.distance_squared(pos.0) < SEARCH_DIST.powf(2.0) &&
+                            // Within our view
+                            (e_pos.0 - pos.0).try_normalized().map(|v| v.dot(*inputs.look_dir) > 0.15).unwrap_or(true))
+                                // Within listen distance
+                                || e_pos.0.distance_squared(pos.0) < LISTEN_DIST.powf(2.0))
                             && *e != entity
                             && !e_stats.is_dead
                             && alignment
diff --git a/world/src/site/dungeon/mod.rs b/world/src/site/dungeon/mod.rs
index c3164e1304..4fff9c4c94 100644
--- a/world/src/site/dungeon/mod.rs
+++ b/world/src/site/dungeon/mod.rs
@@ -104,9 +104,10 @@ impl Dungeon {
 
                 let mut z = self.alt;
                 for floor in &self.floors {
-                    let mut sampler = floor.col_sampler(rpos);
-
                     z -= floor.total_depth();
+
+                    let mut sampler = floor.col_sampler(rpos, z);
+
                     for rz in 0..floor.total_depth() {
                         if let Some(block) = sampler(rz).finish() {
                             vol.set(Vec3::new(offs.x, offs.y, z + rz), block);
@@ -182,7 +183,6 @@ impl Tile {
 
 pub struct Room {
     seed: u32,
-    enemies: bool,
     loot_density: f32,
     enemy_density: f32,
     area: Rect<i32, i32>,
@@ -206,7 +206,7 @@ impl Floor {
         level: i32,
     ) -> (Self, Vec2<i32>) {
         let new_stair_tile = std::iter::from_fn(|| {
-            Some(FLOOR_SIZE.map(|sz| ctx.rng.gen_range(-sz / 2 + 1, sz / 2)))
+            Some(FLOOR_SIZE.map(|sz| ctx.rng.gen_range(-sz / 2 + 2, sz / 2 - 1)))
         })
         .filter(|pos| *pos != stair_tile)
         .take(8)
@@ -222,28 +222,46 @@ impl Floor {
             hollow_depth: 13,
             stair_tile: new_stair_tile - tile_offset,
         };
-        this.create_rooms(ctx, level, 10);
+
+        // Create rooms for entrance and exit
+        this.create_room(Room {
+            seed: ctx.rng.gen(),
+            loot_density: 0.0,
+            enemy_density: 0.0,
+            area: Rect::from((stair_tile - tile_offset - 1, Extent2::broadcast(3))),
+        });
+        this.tiles.set(stair_tile - tile_offset, Tile::UpStair);
+        this.create_room(Room {
+            seed: ctx.rng.gen(),
+            loot_density: 0.0,
+            enemy_density: 0.0,
+            area: Rect::from((new_stair_tile - tile_offset - 1, Extent2::broadcast(3))),
+        });
+        this.tiles.set(new_stair_tile - tile_offset, Tile::DownStair);
+
+        this.create_rooms(ctx, level, 7);
         // Create routes between all rooms
         let room_areas = this.rooms.iter().map(|r| r.area).collect::<Vec<_>>();
         for a in room_areas.iter() {
             for b in room_areas.iter() {
-                this.create_route(ctx, a.center(), b.center(), true);
+                this.create_route(ctx, a.center(), b.center());
             }
         }
-        this.create_route(
-            ctx,
-            stair_tile - tile_offset,
-            new_stair_tile - tile_offset,
-            false,
-        );
-
-        this.tiles.set(stair_tile - tile_offset, Tile::UpStair);
-        this.tiles
-            .set(new_stair_tile - tile_offset, Tile::DownStair);
 
         (this, new_stair_tile)
     }
 
+    fn create_room(&mut self, room: Room) -> Id<Room> {
+        let area = room.area;
+        let id = self.rooms.insert(room);
+        for x in 0..area.extent().w {
+            for y in 0..area.extent().h {
+                self.tiles.set(area.position() + Vec2::new(x, y), Tile::Room(id));
+            }
+        }
+        id
+    }
+
     fn create_rooms(&mut self, ctx: &mut GenCtx<impl Rng>, level: i32, n: usize) {
         let dim_limits = (3, 6);
 
@@ -258,31 +276,23 @@ impl Floor {
 
                 // Ensure no overlap
                 if self.rooms.iter().any(|r| {
-                    r.area.collides_with_rect(area_border) || r.area.contains_point(self.stair_tile)
+                    r.area.collides_with_rect(area_border)
                 }) {
                     return None;
                 }
 
                 Some(area)
             }) {
-                Some(room) => room,
+                Some(area) => area,
                 None => return,
             };
 
-            let room = self.rooms.insert(Room {
+            self.create_room(Room {
                 seed: ctx.rng.gen(),
-                enemies: ctx.rng.gen(),
                 loot_density: 0.00005 + level as f32 * 0.00015,
                 enemy_density: 0.0005 + level as f32 * 0.00015,
                 area,
             });
-
-            for x in 0..area.extent().w {
-                for y in 0..area.extent().h {
-                    self.tiles
-                        .set(area.position() + Vec2::new(x, y), Tile::Room(room));
-                }
-            }
         }
     }
 
@@ -291,16 +301,9 @@ impl Floor {
         ctx: &mut GenCtx<impl Rng>,
         a: Vec2<i32>,
         b: Vec2<i32>,
-        optimise_longest: bool,
     ) {
         let sim = &ctx.sim;
-        let heuristic = move |l: &Vec2<i32>| {
-            if optimise_longest {
-                (l.distance_squared(b) as f32).sqrt()
-            } else {
-                100.0 - (l.distance_squared(b) as f32).sqrt()
-            }
-        };
+        let heuristic = move |l: &Vec2<i32>| (l - b).map(|e| e.abs()).reduce_max() as f32;
         let neighbors = |l: &Vec2<i32>| {
             let l = *l;
             CARDINALS
@@ -364,7 +367,7 @@ impl Floor {
                         for y in 0..TILE_SIZE {
                             let pos = tile_pos * TILE_SIZE + Vec2::new(x, y);
 
-                            if room.enemies && (pos.x + pos.y * TILE_SIZE * FLOOR_SIZE.x).rem_euclid(room.enemy_density.recip() as i32) == 0 {
+                            if (pos.x + pos.y * TILE_SIZE * FLOOR_SIZE.x).rem_euclid(room.enemy_density.recip() as i32) == 0 {
                                 // Bad
                                 let entity = EntityInfo::at(
                                     (origin
@@ -421,7 +424,7 @@ impl Floor {
             .min_by_key(|nearest| rpos.distance_squared(*nearest))
     }
 
-    pub fn col_sampler(&self, pos: Vec2<i32>) -> impl FnMut(i32) -> BlockMask + '_ {
+    pub fn col_sampler(&self, pos: Vec2<i32>, floor_z: i32) -> impl FnMut(i32) -> BlockMask + '_ {
         let rpos = pos - self.tile_offset * TILE_SIZE;
         let tile_pos = rpos.map(|e| e.div_euclid(TILE_SIZE));
         let tile_center = tile_pos * TILE_SIZE + TILE_SIZE / 2;
@@ -436,7 +439,7 @@ impl Floor {
                 stone
             } else if (pos.xy().magnitude_squared() as f32) < radius.powf(2.0) {
                 if ((pos.x as f32).atan2(pos.y as f32) / (f32::consts::PI * 2.0) * stretch
-                    + pos.z as f32)
+                    + (floor_z + pos.z) as f32)
                     .rem_euclid(stretch)
                     < 1.5
                 {