diff options
-rw-r--r-- | proptest-regressions/types/entity_map.txt | 1 | ||||
-rw-r--r-- | proptest-regressions/types/mod.txt | 1 | ||||
-rw-r--r-- | src/game.rs | 16 | ||||
-rw-r--r-- | src/types/entity_map.rs | 19 | ||||
-rw-r--r-- | src/types/mod.rs | 32 |
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)); } } |