about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--proptest-regressions/types/entity_map.txt1
-rw-r--r--proptest-regressions/types/mod.txt1
-rw-r--r--src/game.rs16
-rw-r--r--src/types/entity_map.rs19
-rw-r--r--src/types/mod.rs32
5 files changed, 63 insertions, 6 deletions
diff --git a/proptest-regressions/types/entity_map.txt b/proptest-regressions/types/entity_map.txt
index 1549085b6c2b..7d85b28bf400 100644
--- a/proptest-regressions/types/entity_map.txt
+++ b/proptest-regressions/types/entity_map.txt
@@ -5,3 +5,4 @@
 # It is recommended to check this file in to source control so that
 # everyone who runs the test benefits from these saved cases.
 cc 16afe2473971397314ffa77acf7bad62f0c40bc3f591aff7aa9193c29e5a0921 # shrinks to items = [(Position { x: 92, y: 60 }, ""), (Position { x: 92, y: 60 }, "")]
+cc 3a68a382c3bb8fdf60ea150a369abbdd45859e0c54cd6a4f7c75937a6c783b98 # shrinks to mut em = EntityMap { by_position: {Position { x: 25, y: 33 }: [1]}, by_id: {1: TestEntity { position: Position { x: 25, y: 33 }, name: "" }}, last_id: 1 }, ent = TestEntity { position: Position { x: 25, y: 33 }, name: "" }, new_position = Position { x: 0, y: 0 }
diff --git a/proptest-regressions/types/mod.txt b/proptest-regressions/types/mod.txt
index b18559006799..276466965c44 100644
--- a/proptest-regressions/types/mod.txt
+++ b/proptest-regressions/types/mod.txt
@@ -5,3 +5,4 @@
 # It is recommended to check this file in to source control so that
 # everyone who runs the test benefits from these saved cases.
 cc a51cf37623f0e4024f4ba1450195be296d9b9e8ae954dbbf997ce5b57cd26792 # shrinks to a = Position { x: 44, y: 25 }, b = Position { x: 0, y: 25 }, c = Position { x: 0, y: 0 }
+cc 0816b9348c53ef8c8328f0ea72d5ebef215f6764b1cbbd3c5db958e214c5fa3a # shrinks to pos = Position { x: 0, y: 0 }, dir = Down
diff --git a/src/game.rs b/src/game.rs
index 90d94dc5f220..1a43628b4318 100644
--- a/src/game.rs
+++ b/src/game.rs
@@ -6,6 +6,7 @@ use crate::settings::Settings;
 use crate::types::command::Command;
 use crate::types::entity_map::EntityID;
 use crate::types::entity_map::EntityMap;
+use crate::types::Ticks;
 use crate::types::{
     BoundingBox, Collision, Dimensions, Position, Positioned, PositionedMut,
 };
@@ -99,7 +100,11 @@ impl<'a> Game<'a> {
     }
 
     fn character(&self) -> &Character {
-        debug!("ents: {:?} cid: {:?}", self.entities.ids().map(|id| *id).collect::<Vec<u32>>(), self.character_entity_id);
+        debug!(
+            "ents: {:?} cid: {:?}",
+            self.entities.ids().map(|id| *id).collect::<Vec<u32>>(),
+            self.character_entity_id
+        );
         (*self.entities.get(self.character_entity_id).unwrap())
             .downcast_ref()
             .unwrap()
@@ -113,6 +118,9 @@ impl<'a> Game<'a> {
         Ok(())
     }
 
+    /// Step the game forward the given number of ticks
+    fn tick(&mut self, ticks: Ticks) {}
+
     /// Get a message from the global map based on the rng in this game
     fn message(&mut self, name: &str) -> &'static str {
         message(name, &mut self.rng)
@@ -174,10 +182,14 @@ impl<'a> Game<'a> {
 
             match old_position {
                 Some(old_pos) => {
+                    self.tick(self.character().speed().tiles_to_ticks(
+                        (old_pos - self.character().position).as_tiles(),
+                    ));
                     self.viewport.clear(old_pos)?;
                     self.viewport.draw(
                         // TODO this clone feels unnecessary.
-                        &self.character().clone())?;
+                        &self.character().clone(),
+                    )?;
                 }
                 None => (),
             }
diff --git a/src/types/entity_map.rs b/src/types/entity_map.rs
index 2d9f033a79d4..1846686d1164 100644
--- a/src/types/entity_map.rs
+++ b/src/types/entity_map.rs
@@ -73,8 +73,9 @@ impl<A> EntityMap<A> {
     /// Remove all entities at the given position
     pub fn remove_all_at(&mut self, pos: Position) {
         self.by_position.remove(&pos).map(|eids| {
-            eids.iter()
-                .map(|eid| self.by_id.remove(&eid).expect(BY_POS_INVARIANT));
+            for eid in eids {
+                self.by_id.remove(&eid).expect(BY_POS_INVARIANT);
+            }
         });
     }
 
@@ -227,16 +228,26 @@ mod tests {
             em.update_position(entity_id, new_position);
 
             if new_position != original_position {
-                assert_eq!(em.at(original_position).len(), 0);
+                assert!(em.at(original_position).iter().all(|e| e.name != ent.name));
             }
             assert_eq!(
                 em.get(entity_id).map(|e| e.position()),
                 Some(new_position)
             );
             assert_eq!(
-                em.at(new_position).iter().map(|e| e.name.clone()).collect::<Vec<_>>(),
+                em.at(new_position).iter().map(
+                    |e| e.name.clone()).collect::<Vec<_>>(),
                 vec![ent.name]
             )
         }
+
+        #[test]
+        fn test_remove_all_at(
+            mut em in gen_entity_map(),
+            pos: Position,
+        ) {
+            em.remove_all_at(pos);
+            assert_eq!(em.at(pos).len(), 0);
+        }
     }
 }
diff --git a/src/types/mod.rs b/src/types/mod.rs
index c0375a382fe2..67c773fdb107 100644
--- a/src/types/mod.rs
+++ b/src/types/mod.rs
@@ -1,3 +1,4 @@
+use std::cmp::max;
 use std::cmp::Ordering;
 use std::ops;
 use std::rc::Rc;
@@ -136,6 +137,13 @@ impl Position {
         // + 1 because Goto is 1-based, but position is 0-based
         cursor::Goto(self.x as u16 + 1, self.y as u16 + 1)
     }
+
+    /// Converts this position to the number of `Tiles` away from the origin it
+    /// represents. Usually done after subtracting two positions. Gives distance
+    /// as the crow flies
+    pub fn as_tiles(&self) -> Tiles {
+        Tiles(max(self.x.abs(), self.y.abs()).into())
+    }
 }
 
 impl PartialOrd for Position {
@@ -340,9 +348,17 @@ pub struct Tiles(pub f32);
 pub struct Speed(pub u32);
 
 impl Speed {
+    /// Returns the number of tiles that would be moved in the given number of
+    /// ticks at this speed
     pub fn ticks_to_tiles(self, ticks: Ticks) -> Tiles {
         Tiles(ticks.0 as f32 / self.0 as f32)
     }
+
+    /// Returns the number of ticks required to move the given number of tiles
+    /// at this speed
+    pub fn tiles_to_ticks(self, tiles: Tiles) -> Ticks {
+        Ticks(tiles.0 as u16 * self.0 as u16)
+    }
 }
 
 #[cfg(test)]
@@ -392,5 +408,21 @@ mod tests {
                 assert!(!(a < b))
             }
         }
+
+        #[test]
+        fn test_position_plus_dimension_as_tiles_monoid_action(
+            pos: Position,
+            dir: Direction,
+        ) {
+            prop_assume!(pos.y > 0 && pos.x > 0);
+            assert_eq!(((pos + dir) - pos).as_tiles(), Tiles(1.0));
+        }
+    }
+
+    #[test]
+    fn test_position_as_tiles() {
+        assert_eq!(pos(0, 0).as_tiles(), Tiles(0.0));
+        assert_eq!(pos(1, 1).as_tiles(), Tiles(1.0));
+        assert_eq!(pos(1, 2).as_tiles(), Tiles(2.0));
     }
 }