From b9e6e09fe1919ad58bb238540da75fdbb6334add Mon Sep 17 00:00:00 2001 From: Corwin Date: Sun, 27 Aug 2023 16:47:00 +0100 Subject: [PATCH 01/71] add ice --- .../gfx/sprites16x16.aseprite | Bin 11756 -> 11874 bytes .../src/game/simulation/entity.rs | 279 +++++++++--------- .../the-dungeon-puzzlers-lament/src/level.rs | 4 + .../src/resources.rs | 1 + 4 files changed, 139 insertions(+), 145 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite b/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite index 5c818a91b92ecde38631d83a436701cf268c4310..9bcfb9351c7fde07b876be418bc222cada29be07 100644 GIT binary patch delta 141 zcmaD8{V0Y#Nsocy!BWGC?3Ijd8yn>r*?%)JFi0p!ZC=iJk4emc!GHk;Ff({MyKZh} zN!Jui080G&$jFcaq#1!YVDdv9@yQ!>Sxl_Ie7XAHxtV3TuDzGYG8cV4;|WiBRy|KR hdgR6NrQ&yc0{?Eg=%4xLqB1XEiJkK?2ELu_Y5@D5EtLQO delta 39 vcmaD9^Cp`8jV=SjgQW%&*((_fHa5yLvOi^FV31Id+`OFe9@FO8Ea{p6CsGZI diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 95a1474b..a4ec2bf9 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -5,7 +5,7 @@ use core::ops::Neg; use agb::fixnum::Vector2D; -use alloc::{boxed::Box, vec::Vec}; +use alloc::{boxed::Box, collections::VecDeque, vec::Vec}; use slotmap::{new_key_type, SlotMap}; use crate::{ @@ -91,82 +91,85 @@ impl EntityMap { let mut animations = Vec::new(); - let desired_actions: Vec<(EntityKey, Action)> = self + let mut entities_to_try_update = self .map .iter() .map(|(key, entity)| (key, entity.desired_action(map, self, hero))) - .collect(); - - for (entity_key, action) in desired_actions { - if !self.map.contains_key(entity_key) { - continue; - } - match action { - Action::Nothing => { - // nothing does nothing and causes nothing to happen - } + .collect::>(); + while let Some((entity_to_update_key, desired_action)) = entities_to_try_update.pop_front() + { + match desired_action { + Action::Nothing => {} Action::Direction(direction) | Action::ChangeDirection(direction) => { - if matches!(action, Action::ChangeDirection(_)) { - if let Some(change) = self + if matches!(desired_action, Action::ChangeDirection(_)) { + // first change the direction before processing the rest of the instructions + if let Some((Some(change), change_effect)) = self .map - .get_mut(entity_key) - .and_then(|e| e.change_direction()) + .get_mut(entity_to_update_key) + .map(|e| (e.change_direction(), e.change_effect())) { animations.push(AnimationInstruction::PriorityChange( - entity_key, + entity_to_update_key, change, - self.map.get(entity_key).and_then(|e| e.change_effect()), + change_effect, )); } } - let Some(entity) = &self.map.get(entity_key) else { + let Some(entity_to_update) = self.map.get(entity_to_update_key) else { continue; }; - let desired_location = entity.location + direction.into(); + let entity_location = entity_to_update.location; + + let desired_location = entity_location + direction.into(); let surface = map.get(desired_location); if surface == MapElement::Wall { - let wall_resolution = resolve_wall_move(&entity.entity); - match wall_resolution { - WallResolution::StayPut => { - animations.push(AnimationInstruction::FakeOutMove( - entity_key, - direction, - entity.fake_out_wall_effect(), - )); - } - } - } else { - // what is at that location - let resolutions: Vec<_> = self - .whats_at(desired_location) - .filter(|(k, _)| *k != entity_key) - .map(|(key, other_entity)| (key, resolve_move(entity, other_entity))) - .collect(); + animations.push(AnimationInstruction::FakeOutMove( + entity_to_update_key, + direction, + self.map + .get(entity_to_update_key) + .and_then(|e| e.fake_out_wall_effect()), + )); + continue; + } + let (can_move, explicit_stay_put, fake_out_effect) = { let mut can_move = true; let mut explicit_stay_put = false; let mut fake_out_effect = None; - for (other, resolution) in resolutions { - match resolution { + let move_attempt_resolutions: Vec<_> = self + .whats_at(desired_location) + .filter(|(k, _)| *k != entity_to_update_key) + .map(|(key, other_entity)| { + (key, resolve_move(entity_to_update, other_entity)) + }) + .collect(); + + for (other_entity_key, move_resolution) in move_attempt_resolutions { + match move_resolution { MoveAttemptResolution::KillDie => { - hero_has_died |= self.kill_entity(other, &mut animations); - hero_has_died |= self.kill_entity(entity_key, &mut animations); + hero_has_died |= + self.kill_entity(other_entity_key, &mut animations); + hero_has_died |= + self.kill_entity(entity_to_update_key, &mut animations); can_move = false; } MoveAttemptResolution::Kill => { - hero_has_died |= self.kill_entity(other, &mut animations); + hero_has_died |= + self.kill_entity(other_entity_key, &mut animations); fake_out_effect = self .map - .get(entity_key) + .get(entity_to_update_key) .and_then(|x| x.kill_sound_effect()); can_move = false; } MoveAttemptResolution::Die => { - hero_has_died |= self.kill_entity(entity_key, &mut animations); + hero_has_died |= + self.kill_entity(entity_to_update_key, &mut animations); can_move = false; } MoveAttemptResolution::CoExist => {} @@ -174,106 +177,99 @@ impl EntityMap { can_move = false; explicit_stay_put = true; } + MoveAttemptResolution::AttemptPush => todo!(), } } - if can_move { - if let Some(e) = self.map.get_mut(entity_key) { - e.location = desired_location; - } - let Some(entity) = &self.map.get(entity_key) else { - continue; - }; + (can_move, explicit_stay_put, fake_out_effect) + }; - animations.push(AnimationInstruction::Move( - entity_key, - desired_location, - entity.move_effect(), - )); + if can_move { + let Some(entity_to_update) = self.map.get(entity_to_update_key) else { + continue; + }; - let overlap_resolutions: Vec<_> = self - .whats_at(desired_location) - .filter(|(k, _)| *k != entity_key) - .map(|(key, other_entity)| { - (key, resolve_overlap(entity, other_entity)) - }) - .collect(); + let overlap_resolutions: Vec<_> = self + .whats_at(desired_location) + .filter(|(k, _)| *k != entity_to_update_key) + .map(|(key, other_entity)| { + (key, resolve_overlap(entity_to_update, other_entity)) + }) + .collect(); - if overlap_resolutions - .iter() - .filter(|(_, r)| *r == OverlapResolution::Die) - .count() - != 0 - { - hero_has_died |= self.kill_entity(entity_key, &mut animations); - } else { - for (other, resolution) in overlap_resolutions { - match resolution { - OverlapResolution::Pickup => { - animations.push(AnimationInstruction::Attach( - entity_key, - other, - self.map - .get(other) - .and_then(|x| x.pickup_sound_effect()), + for (other_entity_key, move_resolution) in overlap_resolutions { + match move_resolution { + OverlapResolution::Pickup => { + animations.push(AnimationInstruction::Attach( + entity_to_update_key, + other_entity_key, + self.map + .get(other_entity_key) + .and_then(|x| x.pickup_sound_effect()), + )); + let other = self.map.remove(other_entity_key).unwrap(); + + if let Some((location, dropped)) = + self.map.get_mut(entity_to_update_key).and_then(|x| { + x.pickup(other.entity).map(|y| (x.location, y)) + }) + { + let new_key = self.map.insert(Entity { + location, + entity: dropped, + }); + + animations.push(AnimationInstruction::Detatch( + entity_to_update_key, + new_key, + self.map.get(new_key).and_then(|x| x.drop_effect()), + )); + } + } + OverlapResolution::CoExist => {} + OverlapResolution::Win => { + win_has_triggered = true; + } + OverlapResolution::ToggleSystem(system) => { + for (k, e) in self.map.iter_mut() { + if let Some(change) = e.switch(system) { + animations.push(AnimationInstruction::Change( + k, + change, + e.change_effect(), )); - let other = self.map.remove(other).unwrap(); - - if let Some((location, dropped)) = - self.map.get_mut(entity_key).and_then(|x| { - x.pickup(other.entity).map(|y| (x.location, y)) - }) - { - let new_key = self.map.insert(Entity { - location, - entity: dropped, - }); - - animations.push(AnimationInstruction::Detatch( - entity_key, - new_key, - self.map - .get(new_key) - .and_then(|x| x.drop_effect()), - )); - } - } - OverlapResolution::CoExist => {} - OverlapResolution::Win => { - win_has_triggered = true; - } - OverlapResolution::ToggleSystem(system) => { - for (k, e) in self.map.iter_mut() { - if let Some(change) = e.switch(system) { - animations.push(AnimationInstruction::Change( - k, - change, - e.change_effect(), - )); - } - } - } - OverlapResolution::Die => { - // already handled } } } + OverlapResolution::Die => { + hero_has_died |= + self.kill_entity(entity_to_update_key, &mut animations); + break; + } + OverlapResolution::MoveAgain => { + entities_to_try_update.push_front(( + entity_to_update_key, + Action::Direction(direction), + )); + } } - } else { - animations.push(AnimationInstruction::FakeOutMove( - entity_key, - direction, - if explicit_stay_put { - self.map - .get(entity_key) - .and_then(|e| e.fake_out_wall_effect()) - } else { - fake_out_effect.or_else(|| { - self.map.get(entity_key).and_then(|e| e.fake_out_effect()) - }) - }, - )); } + } else { + animations.push(AnimationInstruction::FakeOutMove( + entity_to_update_key, + direction, + if explicit_stay_put { + self.map + .get(entity_to_update_key) + .and_then(|e| e.fake_out_wall_effect()) + } else { + fake_out_effect.or_else(|| { + self.map + .get(entity_to_update_key) + .and_then(|e| e.fake_out_effect()) + }) + }, + )); } } } @@ -298,22 +294,20 @@ enum MoveAttemptResolution { KillDie, CoExist, StayPut, + AttemptPush, } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub struct SwitchSystem(usize); -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] enum OverlapResolution { Pickup, CoExist, Win, ToggleSystem(SwitchSystem), Die, -} - -enum WallResolution { - StayPut, + MoveAgain, } fn resolve_spikes(switable: &Switchable) -> OverlapResolution { @@ -331,15 +325,12 @@ fn resolve_overlap(me: &Entity, other: &Entity) -> OverlapResolution { (_, EntityType::Spikes(switch)) => resolve_spikes(switch), (_, EntityType::Switch(switch)) => OverlapResolution::ToggleSystem(switch.system), (_, EntityType::Enemy(_) | EntityType::Hero(_)) => OverlapResolution::Die, + (_, EntityType::Ice) => OverlapResolution::MoveAgain, _ => OverlapResolution::CoExist, } } -fn resolve_wall_move(_entity: &EntityType) -> WallResolution { - WallResolution::StayPut -} - fn holding_attack_resolve(holding: Option<&EntityType>) -> MoveAttemptResolution { match holding { Some(&EntityType::Item(Item::Sword)) => MoveAttemptResolution::Kill, @@ -438,6 +429,7 @@ pub enum EntityType { SwitchedDoor(Switchable), Switch(Switchable), Spikes(Switchable), + Ice, } #[derive(Debug)] @@ -577,10 +569,6 @@ impl Entity { } } - fn move_effect(&self) -> Option { - None - } - fn kill_sound_effect(&self) -> Option { match self.holding() { Some(EntityType::Item(Item::Sword)) => Some(SoundEffect::SwordKill), @@ -719,6 +707,7 @@ impl From for EntityType { direction: Direction::Down, holding: None, })), + level::Item::Ice => EntityType::Ice, } } } diff --git a/examples/the-dungeon-puzzlers-lament/src/level.rs b/examples/the-dungeon-puzzlers-lament/src/level.rs index 3452f30a..48da44cb 100644 --- a/examples/the-dungeon-puzzlers-lament/src/level.rs +++ b/examples/the-dungeon-puzzlers-lament/src/level.rs @@ -18,6 +18,7 @@ pub enum Item { SpikesDown, SquidUp, SquidDown, + Ice, } impl Item { @@ -37,6 +38,7 @@ impl Item { Item::SpikesDown => resources::SPIKES_OFF, Item::SquidUp => resources::SQUID_UP_SHADOW, Item::SquidDown => resources::SQUID_DOWN_SHADOW, + Item::Ice => resources::ICE, } } @@ -56,6 +58,7 @@ impl Item { Item::SpikesDown => resources::SPIKES_OFF, Item::SquidUp => resources::SQUID_UP, Item::SquidDown => resources::SQUID_DOWN, + Item::Ice => resources::ICE, } } @@ -78,6 +81,7 @@ impl Item { Item::SpikesDown => ZERO, Item::SquidUp => STANDARD, Item::SquidDown => STANDARD, + Item::Ice => ZERO, } } } diff --git a/examples/the-dungeon-puzzlers-lament/src/resources.rs b/examples/the-dungeon-puzzlers-lament/src/resources.rs index c4af40f7..af80b31a 100644 --- a/examples/the-dungeon-puzzlers-lament/src/resources.rs +++ b/examples/the-dungeon-puzzlers-lament/src/resources.rs @@ -49,6 +49,7 @@ named_tag!( SQUID_DOWN, SQUID_UP_SHADOW, SQUID_DOWN_SHADOW, + ICE, ] ); From e33eee7d11a982b8bfaa217fba194429b1ce7b61 Mon Sep 17 00:00:00 2001 From: Corwin Date: Sun, 27 Aug 2023 17:27:43 +0100 Subject: [PATCH 02/71] fix mistakes copy over --- .../src/game/simulation/entity.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index a4ec2bf9..e7be632e 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -185,10 +185,19 @@ impl EntityMap { }; if can_move { + if let Some(e) = self.map.get_mut(entity_to_update_key) { + e.location = desired_location; + } let Some(entity_to_update) = self.map.get(entity_to_update_key) else { continue; }; + animations.push(AnimationInstruction::Move( + entity_to_update_key, + desired_location, + entity_to_update.move_effect(), + )); + let overlap_resolutions: Vec<_> = self .whats_at(desired_location) .filter(|(k, _)| *k != entity_to_update_key) @@ -569,6 +578,10 @@ impl Entity { } } + fn move_effect(&self) -> Option { + None + } + fn kill_sound_effect(&self) -> Option { match self.holding() { Some(EntityType::Item(Item::Sword)) => Some(SoundEffect::SwordKill), From a0ab3e9fb4d4c81b6475ab9901419cf8ffe9497a Mon Sep 17 00:00:00 2001 From: Corwin Date: Sun, 27 Aug 2023 18:31:30 +0100 Subject: [PATCH 03/71] add ice level --- examples/the-dungeon-puzzlers-lament/build.rs | 4 +++ .../maps/levels/a_familiar_sight.tmx | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/a_familiar_sight.tmx diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index 7e4a297a..f0a4f1dd 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -9,6 +9,7 @@ use std::{ use proc_macro2::TokenStream; const LEVEL_NAMES: &[&str] = &[ + "a_familiar_sight", "level1", "level2", "level3", @@ -100,6 +101,7 @@ enum Entity { SpikesDown, SquidUp, SquidDown, + Ice, } impl FromStr for Entity { @@ -123,6 +125,7 @@ impl FromStr for Entity { "SPIKES_DOWN" => SpikesDown, "SQUID_UP" => SquidUp, "SQUID_DOWN" => SquidDown, + "ICE" => Ice, _ => return Err(()), }) } @@ -147,6 +150,7 @@ impl quote::ToTokens for Entity { SpikesDown => quote!(Item::SpikesDown), SquidUp => quote!(Item::SquidUp), SquidDown => quote!(Item::SquidDown), + Ice => quote!(Item::Ice), }) } } diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/a_familiar_sight.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/a_familiar_sight.tmx new file mode 100644 index 00000000..4a4d07d1 --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/a_familiar_sight.tmx @@ -0,0 +1,31 @@ + + + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,1,6,5,2,2,6,4,8,9,0, +0,10,17,17,12,15,13,17,17,38,0, +0,19,20,20,20,25,20,22,21,27,0, +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + From 36603d5446a4d71f4e290490ee18dda27a7b0a68 Mon Sep 17 00:00:00 2001 From: Corwin Date: Sun, 27 Aug 2023 19:49:37 +0100 Subject: [PATCH 04/71] add block --- examples/the-dungeon-puzzlers-lament/build.rs | 28 +- .../gfx/sprites16x16.aseprite | Bin 11874 -> 12132 bytes .../maps/levels/block_push_1.tmx | 37 ++ .../maps/levels/block_push_2.tmx | 40 ++ .../maps/levels/block_push_3.tmx | 40 ++ .../src/game/simulation/entity.rs | 371 ++++++++++-------- .../the-dungeon-puzzlers-lament/src/level.rs | 8 + .../src/resources.rs | 2 + 8 files changed, 349 insertions(+), 177 deletions(-) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/block_push_1.tmx create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/block_push_2.tmx create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/block_push_3.tmx diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index f0a4f1dd..2981feca 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -10,25 +10,9 @@ use proc_macro2::TokenStream; const LEVEL_NAMES: &[&str] = &[ "a_familiar_sight", - "level1", - "level2", - "level3", - "level4", - "level5", - "level6", - "level_switch", - "level_spikes", - "level_spikes2", - "level_squid_force_button", - "level_squid_intro", - "level_squid2", - "level_squid1", - "level_squid_item", - "level_squid_button", - "level_squid_drop", - "level_spikes3", - "level_around", - "level_squidprogramming", + "block_push_1", + "block_push_2", + "block_push_3", ]; fn main() { @@ -102,6 +86,8 @@ enum Entity { SquidUp, SquidDown, Ice, + MovableBlock, + Glove, } impl FromStr for Entity { @@ -126,6 +112,8 @@ impl FromStr for Entity { "SQUID_UP" => SquidUp, "SQUID_DOWN" => SquidDown, "ICE" => Ice, + "BLOCK" => MovableBlock, + "GLOVE" => Glove, _ => return Err(()), }) } @@ -151,6 +139,8 @@ impl quote::ToTokens for Entity { SquidUp => quote!(Item::SquidUp), SquidDown => quote!(Item::SquidDown), Ice => quote!(Item::Ice), + MovableBlock => quote!(Item::MovableBlock), + Glove => quote!(Item::Glove), }) } } diff --git a/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite b/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite index 9bcfb9351c7fde07b876be418bc222cada29be07..112b25d7786e49052b37f8efd414a4992503ed33 100644 GIT binary patch delta 259 zcmaD9^CXTvMW2D;!BXRi?3Ik$Ha5yLvTHLlFi0rKY+lazg-PF#!H@w3urfIL_&a+W zF&Lo;Gq5ta`}l`#p2c!Pb25{jPQCG#;=lP89t9pXT7ff!_U<_2Fm3j(9Of{ep1PQ- zi)SUS`b+T(rAir1Zr*=kWG7={XWA{0w1AvoitIa#7>} delta 39 vcmaD7_b7%vNsocy!BWGC?3Ijd8yn>r*?%)JFi0p!ZC=j!g=zC?mgAZL8XOJL diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_1.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_1.tmx new file mode 100644 index 00000000..4deac7d6 --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_1.tmx @@ -0,0 +1,37 @@ + + + + + + + + + + +0,1,3,2,6,9,0,0,0,0,0, +0,46,15,14,13,3221225500,4,6,7,7,9, +0,46,12,11,15,16,11,13,15,14,38, +0,46,12,13,14,16,17,14,11,12,18, +0,10,13,16,15,14,12,14,13,15,18, +0,46,16,17,17,13,15,14,16,15,18, +0,19,28,17,11,16,12,15,17,15,38, +0,0,19,20,28,17,17,15,17,2147483676,27, +0,0,0,0,19,21,25,20,23,27,0, +0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_2.tmx new file mode 100644 index 00000000..560a1c96 --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_2.tmx @@ -0,0 +1,40 @@ + + + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,4,3,9,0,0,0, +0,0,0,1,1073741852,16,15,3221225500,8,9,0, +0,0,0,46,12,15,13,17,11,38,0, +0,0,0,19,24,28,17,2147483676,25,27,0, +0,0,0,0,0,10,13,47,0,0,0, +0,0,0,0,0,19,20,27,0,0,0, +0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_3.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_3.tmx new file mode 100644 index 00000000..178c36c1 --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_3.tmx @@ -0,0 +1,40 @@ + + + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0, +0,0,1,6,2,8,8,9,0,0,0, +0,1,1073741852,17,12,16,12,3221225500,9,0,0, +0,46,11,16,12,17,17,12,38,0,0, +0,46,17,16,12,16,11,14,38,0,0, +0,19,26,28,14,12,14,15,38,0,0, +0,0,0,19,24,28,11,2147483676,27,0,0, +0,0,0,0,0,19,23,27,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index e7be632e..ada631a5 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -85,6 +85,195 @@ impl EntityMap { AnimationInstruction::Add(idx, entity, location, None) } + fn attempt_move_in_direction( + &mut self, + map: &Map, + animations: &mut Vec, + entities_to_try_update: &mut VecDeque<(EntityKey, Action)>, + entity_to_update_key: EntityKey, + direction: Direction, + depth: i32, + ) -> (bool, bool, bool) { + let mut hero_has_died = false; + let mut win_has_triggered = false; + + let Some(entity_to_update) = self.map.get(entity_to_update_key) else { + return (false, hero_has_died, win_has_triggered); + }; + + let entity_location = entity_to_update.location; + + let desired_location = entity_location + direction.into(); + let surface = map.get(desired_location); + if surface == MapElement::Wall { + animations.push(AnimationInstruction::FakeOutMove( + entity_to_update_key, + direction, + self.map + .get(entity_to_update_key) + .and_then(|e| e.fake_out_wall_effect()), + )); + return (false, hero_has_died, win_has_triggered); + } + + let (can_move, explicit_stay_put, fake_out_effect) = { + let mut can_move = true; + let mut explicit_stay_put = false; + let mut fake_out_effect = None; + + let move_attempt_resolutions: Vec<_> = self + .whats_at(desired_location) + .filter(|(k, _)| *k != entity_to_update_key) + .map(|(key, other_entity)| (key, resolve_move(entity_to_update, other_entity))) + .collect(); + + for (other_entity_key, move_resolution) in move_attempt_resolutions { + match move_resolution { + MoveAttemptResolution::KillDie => { + hero_has_died |= self.kill_entity(other_entity_key, animations); + hero_has_died |= self.kill_entity(entity_to_update_key, animations); + can_move = false; + } + MoveAttemptResolution::Kill => { + hero_has_died |= self.kill_entity(other_entity_key, animations); + fake_out_effect = self + .map + .get(entity_to_update_key) + .and_then(|x| x.kill_sound_effect()); + can_move = false; + } + MoveAttemptResolution::Die => { + hero_has_died |= self.kill_entity(entity_to_update_key, animations); + can_move = false; + } + MoveAttemptResolution::CoExist => {} + MoveAttemptResolution::StayPut => { + can_move = false; + explicit_stay_put = true; + } + MoveAttemptResolution::AttemptPush => { + let depth = depth - 1; + if depth >= 0 { + let (can_move_result, hero_has_died_result, win_has_triggered_result) = + self.attempt_move_in_direction( + map, + animations, + entities_to_try_update, + other_entity_key, + direction, + depth, + ); + + if !can_move_result { + can_move = false; + } + hero_has_died |= hero_has_died_result; + win_has_triggered |= win_has_triggered_result; + } else { + can_move = false; + } + } + } + } + + (can_move, explicit_stay_put, fake_out_effect) + }; + + if can_move { + if let Some(e) = self.map.get_mut(entity_to_update_key) { + e.location = desired_location; + } + let Some(entity_to_update) = self.map.get(entity_to_update_key) else { + return (can_move, hero_has_died, win_has_triggered); + }; + + animations.push(AnimationInstruction::Move( + entity_to_update_key, + desired_location, + entity_to_update.move_effect(), + )); + + let overlap_resolutions: Vec<_> = self + .whats_at(desired_location) + .filter(|(k, _)| *k != entity_to_update_key) + .map(|(key, other_entity)| (key, resolve_overlap(entity_to_update, other_entity))) + .collect(); + + for (other_entity_key, move_resolution) in overlap_resolutions { + match move_resolution { + OverlapResolution::Pickup => { + animations.push(AnimationInstruction::Attach( + entity_to_update_key, + other_entity_key, + self.map + .get(other_entity_key) + .and_then(|x| x.pickup_sound_effect()), + )); + let other = self.map.remove(other_entity_key).unwrap(); + + if let Some((location, dropped)) = self + .map + .get_mut(entity_to_update_key) + .and_then(|x| x.pickup(other.entity).map(|y| (x.location, y))) + { + let new_key = self.map.insert(Entity { + location, + entity: dropped, + }); + + animations.push(AnimationInstruction::Detatch( + entity_to_update_key, + new_key, + self.map.get(new_key).and_then(|x| x.drop_effect()), + )); + } + } + OverlapResolution::CoExist => {} + OverlapResolution::Win => { + win_has_triggered = true; + } + OverlapResolution::ToggleSystem(system) => { + for (k, e) in self.map.iter_mut() { + if let Some(change) = e.switch(system) { + animations.push(AnimationInstruction::Change( + k, + change, + e.change_effect(), + )); + } + } + } + OverlapResolution::Die => { + hero_has_died |= self.kill_entity(entity_to_update_key, animations); + break; + } + OverlapResolution::MoveAgain => { + entities_to_try_update + .push_front((entity_to_update_key, Action::Direction(direction))); + } + } + } + } else { + animations.push(AnimationInstruction::FakeOutMove( + entity_to_update_key, + direction, + if explicit_stay_put { + self.map + .get(entity_to_update_key) + .and_then(|e| e.fake_out_wall_effect()) + } else { + fake_out_effect.or_else(|| { + self.map + .get(entity_to_update_key) + .and_then(|e| e.fake_out_effect()) + }) + }, + )); + } + + (can_move, hero_has_died, win_has_triggered) + } + pub fn tick(&mut self, map: &Map, hero: Action) -> (Outcome, Vec) { let mut hero_has_died = false; let mut win_has_triggered = false; @@ -117,169 +306,21 @@ impl EntityMap { } } - let Some(entity_to_update) = self.map.get(entity_to_update_key) else { - continue; - }; - - let entity_location = entity_to_update.location; - - let desired_location = entity_location + direction.into(); - let surface = map.get(desired_location); - if surface == MapElement::Wall { - animations.push(AnimationInstruction::FakeOutMove( + let (_, hero_has_died_result, win_has_triggered_result) = self + .attempt_move_in_direction( + map, + &mut animations, + &mut entities_to_try_update, entity_to_update_key, direction, self.map .get(entity_to_update_key) - .and_then(|e| e.fake_out_wall_effect()), - )); - continue; - } + .and_then(|e| e.push_depth()) + .unwrap_or(0), + ); - let (can_move, explicit_stay_put, fake_out_effect) = { - let mut can_move = true; - let mut explicit_stay_put = false; - let mut fake_out_effect = None; - - let move_attempt_resolutions: Vec<_> = self - .whats_at(desired_location) - .filter(|(k, _)| *k != entity_to_update_key) - .map(|(key, other_entity)| { - (key, resolve_move(entity_to_update, other_entity)) - }) - .collect(); - - for (other_entity_key, move_resolution) in move_attempt_resolutions { - match move_resolution { - MoveAttemptResolution::KillDie => { - hero_has_died |= - self.kill_entity(other_entity_key, &mut animations); - hero_has_died |= - self.kill_entity(entity_to_update_key, &mut animations); - can_move = false; - } - MoveAttemptResolution::Kill => { - hero_has_died |= - self.kill_entity(other_entity_key, &mut animations); - fake_out_effect = self - .map - .get(entity_to_update_key) - .and_then(|x| x.kill_sound_effect()); - can_move = false; - } - MoveAttemptResolution::Die => { - hero_has_died |= - self.kill_entity(entity_to_update_key, &mut animations); - can_move = false; - } - MoveAttemptResolution::CoExist => {} - MoveAttemptResolution::StayPut => { - can_move = false; - explicit_stay_put = true; - } - MoveAttemptResolution::AttemptPush => todo!(), - } - } - - (can_move, explicit_stay_put, fake_out_effect) - }; - - if can_move { - if let Some(e) = self.map.get_mut(entity_to_update_key) { - e.location = desired_location; - } - let Some(entity_to_update) = self.map.get(entity_to_update_key) else { - continue; - }; - - animations.push(AnimationInstruction::Move( - entity_to_update_key, - desired_location, - entity_to_update.move_effect(), - )); - - let overlap_resolutions: Vec<_> = self - .whats_at(desired_location) - .filter(|(k, _)| *k != entity_to_update_key) - .map(|(key, other_entity)| { - (key, resolve_overlap(entity_to_update, other_entity)) - }) - .collect(); - - for (other_entity_key, move_resolution) in overlap_resolutions { - match move_resolution { - OverlapResolution::Pickup => { - animations.push(AnimationInstruction::Attach( - entity_to_update_key, - other_entity_key, - self.map - .get(other_entity_key) - .and_then(|x| x.pickup_sound_effect()), - )); - let other = self.map.remove(other_entity_key).unwrap(); - - if let Some((location, dropped)) = - self.map.get_mut(entity_to_update_key).and_then(|x| { - x.pickup(other.entity).map(|y| (x.location, y)) - }) - { - let new_key = self.map.insert(Entity { - location, - entity: dropped, - }); - - animations.push(AnimationInstruction::Detatch( - entity_to_update_key, - new_key, - self.map.get(new_key).and_then(|x| x.drop_effect()), - )); - } - } - OverlapResolution::CoExist => {} - OverlapResolution::Win => { - win_has_triggered = true; - } - OverlapResolution::ToggleSystem(system) => { - for (k, e) in self.map.iter_mut() { - if let Some(change) = e.switch(system) { - animations.push(AnimationInstruction::Change( - k, - change, - e.change_effect(), - )); - } - } - } - OverlapResolution::Die => { - hero_has_died |= - self.kill_entity(entity_to_update_key, &mut animations); - break; - } - OverlapResolution::MoveAgain => { - entities_to_try_update.push_front(( - entity_to_update_key, - Action::Direction(direction), - )); - } - } - } - } else { - animations.push(AnimationInstruction::FakeOutMove( - entity_to_update_key, - direction, - if explicit_stay_put { - self.map - .get(entity_to_update_key) - .and_then(|e| e.fake_out_wall_effect()) - } else { - fake_out_effect.or_else(|| { - self.map - .get(entity_to_update_key) - .and_then(|e| e.fake_out_effect()) - }) - }, - )); - } + hero_has_died |= hero_has_died_result; + win_has_triggered |= win_has_triggered_result; } } } @@ -331,6 +372,7 @@ fn resolve_overlap(me: &Entity, other: &Entity) -> OverlapResolution { match (&me.entity, &other.entity) { (EntityType::Hero(_), EntityType::Stairs) => OverlapResolution::Win, (_, EntityType::Item(_)) => OverlapResolution::Pickup, + (EntityType::MovableBlock, EntityType::Spikes(_)) => OverlapResolution::CoExist, (_, EntityType::Spikes(switch)) => resolve_spikes(switch), (_, EntityType::Switch(switch)) => OverlapResolution::ToggleSystem(switch.system), (_, EntityType::Enemy(_) | EntityType::Hero(_)) => OverlapResolution::Die, @@ -408,6 +450,7 @@ fn resolve_move(mover: &Entity, into: &Entity) -> MoveAttemptResolution { holding_door_resolve(squid.holding.as_deref()) } (_, EntityType::Door) => MoveAttemptResolution::StayPut, + (_, EntityType::MovableBlock) => MoveAttemptResolution::AttemptPush, (_, _) => MoveAttemptResolution::CoExist, } } @@ -439,6 +482,7 @@ pub enum EntityType { Switch(Switchable), Spikes(Switchable), Ice, + MovableBlock, } #[derive(Debug)] @@ -457,6 +501,7 @@ pub enum Enemy { pub enum Item { Sword, Key, + Glove, } #[derive(PartialEq, Eq, Clone, Copy, Debug)] @@ -552,6 +597,14 @@ impl Entity { } } + fn push_depth(&self) -> Option { + if matches!(self.holding(), Some(&EntityType::Item(Item::Glove))) { + Some(i32::MAX) + } else { + Some(1) + } + } + fn holding(&self) -> Option<&EntityType> { match &self.entity { EntityType::Hero(hero) => hero.holding.as_deref(), @@ -721,6 +774,8 @@ impl From for EntityType { holding: None, })), level::Item::Ice => EntityType::Ice, + level::Item::MovableBlock => EntityType::MovableBlock, + level::Item::Glove => EntityType::Item(Item::Glove), } } } diff --git a/examples/the-dungeon-puzzlers-lament/src/level.rs b/examples/the-dungeon-puzzlers-lament/src/level.rs index 48da44cb..2825d7ba 100644 --- a/examples/the-dungeon-puzzlers-lament/src/level.rs +++ b/examples/the-dungeon-puzzlers-lament/src/level.rs @@ -19,6 +19,8 @@ pub enum Item { SquidUp, SquidDown, Ice, + MovableBlock, + Glove, } impl Item { @@ -39,6 +41,8 @@ impl Item { Item::SquidUp => resources::SQUID_UP_SHADOW, Item::SquidDown => resources::SQUID_DOWN_SHADOW, Item::Ice => resources::ICE, + Item::MovableBlock => resources::BLOCK, + Item::Glove => resources::GLOVE, } } @@ -59,6 +63,8 @@ impl Item { Item::SquidUp => resources::SQUID_UP, Item::SquidDown => resources::SQUID_DOWN, Item::Ice => resources::ICE, + Item::MovableBlock => resources::BLOCK, + Item::Glove => resources::GLOVE, } } @@ -82,6 +88,8 @@ impl Item { Item::SquidUp => STANDARD, Item::SquidDown => STANDARD, Item::Ice => ZERO, + Item::MovableBlock => ZERO, + Item::Glove => STANDARD, } } } diff --git a/examples/the-dungeon-puzzlers-lament/src/resources.rs b/examples/the-dungeon-puzzlers-lament/src/resources.rs index af80b31a..afcc1646 100644 --- a/examples/the-dungeon-puzzlers-lament/src/resources.rs +++ b/examples/the-dungeon-puzzlers-lament/src/resources.rs @@ -50,6 +50,8 @@ named_tag!( SQUID_UP_SHADOW, SQUID_DOWN_SHADOW, ICE, + BLOCK, + GLOVE, ] ); From 248cdae7a355a148c10d0014bead4004aafbfd67 Mon Sep 17 00:00:00 2001 From: Corwin Date: Sun, 27 Aug 2023 20:34:20 +0100 Subject: [PATCH 05/71] change squid change direction behaviour --- .../src/game/simulation/entity.rs | 97 ++++++++----------- 1 file changed, 43 insertions(+), 54 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index ada631a5..ca5b92b6 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -92,7 +92,8 @@ impl EntityMap { entities_to_try_update: &mut VecDeque<(EntityKey, Action)>, entity_to_update_key: EntityKey, direction: Direction, - depth: i32, + can_turn_around: bool, + push_depth: i32, ) -> (bool, bool, bool) { let mut hero_has_died = false; let mut win_has_triggered = false; @@ -105,18 +106,9 @@ impl EntityMap { let desired_location = entity_location + direction.into(); let surface = map.get(desired_location); - if surface == MapElement::Wall { - animations.push(AnimationInstruction::FakeOutMove( - entity_to_update_key, - direction, - self.map - .get(entity_to_update_key) - .and_then(|e| e.fake_out_wall_effect()), - )); - return (false, hero_has_died, win_has_triggered); - } - - let (can_move, explicit_stay_put, fake_out_effect) = { + let (can_move, explicit_stay_put, fake_out_effect) = if surface == MapElement::Wall { + (false, true, None) + } else { let mut can_move = true; let mut explicit_stay_put = false; let mut fake_out_effect = None; @@ -152,7 +144,7 @@ impl EntityMap { explicit_stay_put = true; } MoveAttemptResolution::AttemptPush => { - let depth = depth - 1; + let depth = push_depth - 1; if depth >= 0 { let (can_move_result, hero_has_died_result, win_has_triggered_result) = self.attempt_move_in_direction( @@ -161,16 +153,19 @@ impl EntityMap { entities_to_try_update, other_entity_key, direction, + true, depth, ); if !can_move_result { can_move = false; + explicit_stay_put = true; } hero_has_died |= hero_has_died_result; win_has_triggered |= win_has_triggered_result; } else { can_move = false; + explicit_stay_put = true; } } } @@ -253,6 +248,31 @@ impl EntityMap { } } } + } else if explicit_stay_put + && can_turn_around + && self.map.get(entity_to_update_key).map(|e| e.turns_around()) == Some(true) + { + if let Some((Some(change), change_effect)) = self + .map + .get_mut(entity_to_update_key) + .map(|e| (e.change_direction(), e.change_effect())) + { + animations.push(AnimationInstruction::PriorityChange( + entity_to_update_key, + change, + change_effect, + )); + + return self.attempt_move_in_direction( + map, + animations, + entities_to_try_update, + entity_to_update_key, + -direction, + false, + push_depth, + ); + } } else { animations.push(AnimationInstruction::FakeOutMove( entity_to_update_key, @@ -283,29 +303,14 @@ impl EntityMap { let mut entities_to_try_update = self .map .iter() - .map(|(key, entity)| (key, entity.desired_action(map, self, hero))) + .map(|(key, entity)| (key, entity.desired_action(hero))) .collect::>(); while let Some((entity_to_update_key, desired_action)) = entities_to_try_update.pop_front() { match desired_action { Action::Nothing => {} - Action::Direction(direction) | Action::ChangeDirection(direction) => { - if matches!(desired_action, Action::ChangeDirection(_)) { - // first change the direction before processing the rest of the instructions - if let Some((Some(change), change_effect)) = self - .map - .get_mut(entity_to_update_key) - .map(|e| (e.change_direction(), e.change_effect())) - { - animations.push(AnimationInstruction::PriorityChange( - entity_to_update_key, - change, - change_effect, - )); - } - } - + Action::Direction(direction) => { let (_, hero_has_died_result, win_has_triggered_result) = self .attempt_move_in_direction( map, @@ -313,6 +318,7 @@ impl EntityMap { &mut entities_to_try_update, entity_to_update_key, direction, + true, self.map .get(entity_to_update_key) .and_then(|e| e.push_depth()) @@ -546,38 +552,21 @@ impl From<&Direction> for Vector2D { pub enum Action { Nothing, Direction(Direction), - ChangeDirection(Direction), } impl Entity { - fn desired_action(&self, walls: &Map, entities: &EntityMap, hero_action: Action) -> Action { + fn desired_action(&self, hero_action: Action) -> Action { match &self.entity { EntityType::Hero(_) => hero_action, - EntityType::Enemy(Enemy::Squid(squid)) => { - let desired_location = self.location + squid.direction.into(); - let wall = walls.get(desired_location); - - if matches!(wall, MapElement::Wall) { - Action::ChangeDirection(-squid.direction) - } else { - let can_move = entities - .whats_at(desired_location) - .map(|(_, other_entity)| resolve_move(self, other_entity)) - .filter(|resolution| matches!(resolution, MoveAttemptResolution::StayPut)) - .count() - == 0; - - if can_move { - Action::Direction(squid.direction) - } else { - Action::ChangeDirection(-squid.direction) - } - } - } + EntityType::Enemy(Enemy::Squid(squid)) => Action::Direction(squid.direction), _ => Action::Nothing, } } + fn turns_around(&self) -> bool { + matches!(self.entity, EntityType::Enemy(Enemy::Squid(_))) + } + fn pickup(&mut self, item: EntityType) -> Option { let holding = match &mut self.entity { EntityType::Hero(hero) => &mut hero.holding, From 04ee5646ef7d7fe819a44398ab42663a3c73adb9 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Mon, 28 Aug 2023 09:32:48 +0100 Subject: [PATCH 06/71] Add some new sprites for Corwin --- .../gfx/concept.aseprite | Bin 44613 -> 45011 bytes .../gfx/sprites16x16.aseprite | Bin 12132 -> 14325 bytes .../the-dungeon-puzzlers-lament/src/level.rs | 10 +++++----- .../src/resources.rs | 6 ++++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/gfx/concept.aseprite b/examples/the-dungeon-puzzlers-lament/gfx/concept.aseprite index 69259a09730f25a81aac5d0ca2079c1187c0fcce..dc8da1a4183c70dc3686ae016b11fb7b978cbde6 100644 GIT binary patch delta 2549 zcmZXVc~Fzr8peYlVo?@r2}s!Fs#PHr*)Bwghzp3Kl}cnUa23k-$r?xqpSFOdEYVVp zvWtMwh=3s=Bw>9A&*;p3oxORE z0`D`DCS$}`8NIE9-x+8yQbj?%)k~UCX3+A}`r=kBwyQ3Lb#CuR-Ac@i<*=JxNX6r( z+S#ElS%7DW&+ux<4NQj5z(r)B3C0#=jG77hqG}GYgBM`iG%mSA*S16VxhJ`+H=v+G z_G(Ql+dSkd7??PJt#4KMZd4vpn92oWtT_)1=i`Q-9?=C)o6%lRKf0*>_std32HJb9Of-Ft)V;zdlv5d2pmZz9uXj1)XnAAr6B6g473q9RfWa1_#O!ig;Zk^SO zE|T48|8^pi9=syn@*gtb2QR1%%6petHMpW&8(aYopMGuJ=EfEVYO(HY?HC`>IAs@Q z6y3I{JOuy)5xDqMX=b$@uh&nqx2{EU@=s$n@O3}fxy4Q1zM5azH zYn4eu(7(SFCx2SfqMUi9QyZLh#yDHcR`}7V_Sy?*Yv9STLS5GHoL~9ccqpC?t8W(% zJ{2bi_!x7}DF0hT%mF z^lnS9bI$x3cA?zTDVmT?9Q?GeIANyYHQ#HdvFt^Cu6n*YSc3fvX|HPNoc8C8 zLF=p4a7P%i?Gg&p~0Efs0HK2ZRXZ16I6UJd>iem@h z{D6VN01ulmNPTOo2%8W%HM z0^;9eQZY-TODl6Zgt9uXMs=?I6a2I>N_Vom3+(to*x9ZbkZ$^aEh~V+j!iF-`KQRC z){Mbk-Q^EMbg2x7Um9$&4Yk&|iUR2upIE9+5DTrpoK)(sg^(J2`ONA1~6cSJFj>AtzP6^&iP?hZR( z%k-v<yTvFLa*L_T(88$?Dwe%L2sNFERmi*eT(wn!w z)Ji{LPis-unPBQxhXOGzQF_$RQsX}D+4%|=bMA^3oK9Z9SKwvDw#pLRjv5MM1nSft zI$q}4036+qE1@#IY0b**r$V12hE3QPvr_2StE0J>k+bDVB;;EUoGB^7V{^~0s=o-f z=L^9!vceMffGR(Kckr&CO5yXY)U*f*gtP7OPjwvy&)u^8&BmmbBu63O6naNf*X2I% zX5>Ee8>3E@n!(taVfu@T+F-t{+UUB8aGmxo?eNQ)>}7_oLpOQ#1h}9iq{a|OBWfDL zi)E2X)wLT5hr62GN~^=m1@#W+WURI?%=(oJL@+_%y&)^nt>=^onP@13VPLZjsy)vI6Wj9A=|??8_&^A4$9^wrK;Q@ZFh)k$ z@Dk6^s0#Bmr^tP6`-3U2 zyA>Q9{f^w!oEx~Q^t1j=cQ&WL-vgm%fAWL8l7^dxWvyMBWn*in`&t&4*Cm>xVQ-_w zTY9iq(WiE1m*DABtR*J$wF*7oZuXM@jLb_Lg*HK?m2=G)Yy3|e@6Jn>B?VhH2Q4;f zO*S(|!Rf1@u;Zi3_x-?=U+{sI>!0n$&4&sw+jh;Y?6DRtzR~Ej48M^cpvpw(P<;BW zs;o-L=wRRqyz4IPtC-od602VZ{UY`p>!ir80H2{r-zvGXz#lGV=N)WE6pK)I&d zOCbelb-_1H@JuOb!KwZ(0txnszPlYf7X+5)F55|AW`dF9=zy(D>}THZ^13s;X~>lx z+oQbA61oYQx?jp$?dShvir(X!v8lo<-8oNDcni+g1-iUD3o41tdRX2#EIm4~ikQuL zT-cf?A=m_Be7$;JPF2K+!Fa_Yu%a)y^gtkJf`jj$ln_SWIBQyTFt?CHB8_IV>P%DM*A33Ml}(!vMFPN z#URkj>_hz$j+578jm7uaE<`zRjp!iFT7{12vPVyjor5owf^P!Aj>*itYKjub@pe*i zi6F4HYejU%DZ?c^JS47g7j$(eFU~EckUoRt6 zTbT8G(^2p}sxfs(fD5UVGSXKI5s3@VWYvf|3*g64cDiO%P}46cF1(yrMGTPUCHSfm z-BC^zS>PO;fF2*&-c0JDjfx`Y51>0-<^%arLq*AIXO#?+{fW8m z!v}D+;a?~4A5+8+EGe-MDV7t5O2#U(2HnqbMw=PrmCLV;M+&Iq^PPEA^1b}1y41vr Y&%CK8r6D=rqCq((W-*4Oe%BoSZ^djeM*si- delta 2145 zcmZvceKgc*8^KCqJiCxJ=kwC-&FO}u^)Ac5N?+zVTjaeW znw&M9*RA$hQZKFfn)Pr^;qf&-EN2g;wUG`&wMN;JMJ5?1wq;#_JuYBoxONFlKj;A= z>VYY_{IrrVWVF@wk#Oft`1d{d8Hi7H&jp0dknNijw39eiO^#xd61(h>aAlg zic@E_+Nva;FK%hPZL3eAde?ZQhQS-VZQgjQu0~Q11whG7QI}3`rT7~gWnB%m58T`L zOYN3*c2~pdNxs4!+2Y3X2OhVshK7Y=$641$kQlfPSu+tIJ~surbB?G_tN+DXv1rYqvRi> z>ZI=Wzyax8dGbXtuJBYfkG-Jp6(5c6Y<+r3{-mZWwi5@W4iXnSi3fpGPhz~8u7rIG zVU6R`qsjp*)n^fM4ZVbM3Hr%gdRW)eZz~{hHcL=Tzqt$XEdxZJm)EwrJLHAqSpHD# zj=F+yryJ0o;of)C+=NYBfaXTPBq_$#u25!XD$wO$br-x={SJFg>|NME%aZ&mx(&bh zyEeuO0HL7LKGlXw;NpbYDL7iz3O(QL?!~E?X_N_1l*uS8Ds|?#y`&idOQq4{aDWqU z4hVMx@BmIf?W0))xm(jjQK$JT9KbkN^D>R!IV}El>Ye!)GVP}uv_c%fAzEP8Hh7h= zG5C9K4PMHifc5|I z&Q4Z?Jg?ia;|)pVp@I)0ZZle*Pi}?v4sBX>X~wit|7Otz)ENP!47Oe!or8DELsl}kW?Ib7kj<4X-OV|kRk34&liL@4@hw-lMOHS#iERTFX=9#WZ-*ld z!ZQzp{)SmX*r)HNvs6LL8;l;?v!<>otjVB3n(?l620rbBto-pES4VaOateZbG%0sB zd46Kci7v#g0#rtJ9|58wGXsqex}4h^8vY(}Ixosfzwf@id#g~9MBgpl^<5n`_-NH+ z8JbQ;Pxijn1)?enM|JE2d>#cm^Kn17SBAfVi1m5L+@08meJ!p69+!lUj41hQAt!zS zq>U49GkJW559aoA!0^mR@0zr_Rb>7Zx3;bH&ktdcJH>Xhr2$@y#@F+yhVq+%<+x&{ zBf;q_0#JsI84QX(^wfM% z3{Ke7M8}U2^gr8B%W@O_F!bQ0j-P5AjtYp6$h^U2!D2T+$>2hduQ0^H^LLzHN06U* z)vq`g9pOQ9I2xzAW&I3t@E4{ErZ{VO{%p1ew;z?65U%%iw@`K{VfADIa&%HiIEK8h zRSxvd?Sm;lbY)UfWH{sq{{sdOR76KQOvv`bq)oy0{ED4GisoGYWcvs@#Z}s?4PQw0 z7YN|0Z40oP$R2hU_F@Gg$U$PTh=E?_+xNi}7T zI|NvD#>$;_1D=2k)~F@nXgPmkWWs? zI9KQjX`?FQzlfJM;*LWuO%J>KcCdnn5gNpzc7hAjfC;nV>iJF6pYs(mEU%fE|Nk*E z5bG{{+h#O!-*Nf;LDMNot}RJFSDHItV91)f^VoqY&N#F=NSlwSWyEl2G|zKZF(OAc zTK}i1$~?m0<$sxYy0IxFdMg_Jp6RES>_`)R4vg=)Ihf9xHE;x1F4=70h-{T3wnA5O+HOA0lCCK@ z8>scyM@Dce1SQn&$%%ZT_52L{3>9;xUcSiNpuod&;ob8i|E#+I?Py^;t2+I3;4L*? z&QA+CT>cckyWPyw6=`2DUl{ZK`llZk+e>1<5 zJeCom^IpIDuwrKQs!tp5^X*UGU6Z0+b8KG4*MFk_O45#%-#Br+`q{6_w9S!W|DFCS zi|%GHub#*`9Ud%Dx3nXN%VbBs0}320KjY)?tj^EW|Lan1U?RLpDd&)Dxq!&oW$Qjy z*z!cJEuO!q{?2)Mt^R5aBP|>DzoGL=ODopTv<xg4|8ui{tKFWDpS`)eZS47fW$K?2P39mwvu?8pa-p9BBSi&uZut@crAH$PVEFa(aN6 zRe_O#adIG=NPWTqzE?aF|C$Z>GUvRS|KFktS;DBKQWgs7L zDQpK07*KR^GyI3!v0*(|=4q`-#6mDR&fKp6DgM-=9|1V}R zax-+UH=5hmc=2lUkH32iB_w87rEE2*OtI73dLnDW)k9Yv7cui3{=;;+*Xn|^%+ zr%!O4g6eQq1qNV9up&8v3z%3TdFP4C(*KVqNU>%x#77)_;$UJpLt?9fDZ_gq=^%vr zNeIMx3PW)hn)}V5?q@-9KL^bHEJceh{olyZ@4>*uT_Z7HYC@F^gD8)13&QR63wr>( C3u00L delta 449 zcmeyG|0GT^MW2D;!BS%e0U%UhU}RumNC9F55S*wO&%2FT+H}@$;AMw9!fDYcsjcp zG8m$YvNAaN_&a+WF&LqXyZiWuxo+OWmaZw70F?XnkrC`5kedT0U(lC!wf^$u>VM~E zmgTzkULwm}^!1D1-|Y$fyXB&P=AVnoynH2g&c_(|cCxEsGfAd? zOYz@)3y%Vi8m+(?LVI_dahNuHR}OQSPfuM;)y1T(rAir1Zr*=kWG7={XWA{0w1AvoirMy?uEA diff --git a/examples/the-dungeon-puzzlers-lament/src/level.rs b/examples/the-dungeon-puzzlers-lament/src/level.rs index 2825d7ba..d827f9b4 100644 --- a/examples/the-dungeon-puzzlers-lament/src/level.rs +++ b/examples/the-dungeon-puzzlers-lament/src/level.rs @@ -41,8 +41,8 @@ impl Item { Item::SquidUp => resources::SQUID_UP_SHADOW, Item::SquidDown => resources::SQUID_DOWN_SHADOW, Item::Ice => resources::ICE, - Item::MovableBlock => resources::BLOCK, - Item::Glove => resources::GLOVE, + Item::MovableBlock => resources::ROCK_SHADOW, + Item::Glove => resources::POW_GLOVE_SHADOW, } } @@ -63,8 +63,8 @@ impl Item { Item::SquidUp => resources::SQUID_UP, Item::SquidDown => resources::SQUID_DOWN, Item::Ice => resources::ICE, - Item::MovableBlock => resources::BLOCK, - Item::Glove => resources::GLOVE, + Item::MovableBlock => resources::ROCK, + Item::Glove => resources::POW_GLOVE, } } @@ -88,7 +88,7 @@ impl Item { Item::SquidUp => STANDARD, Item::SquidDown => STANDARD, Item::Ice => ZERO, - Item::MovableBlock => ZERO, + Item::MovableBlock => STANDARD, Item::Glove => STANDARD, } } diff --git a/examples/the-dungeon-puzzlers-lament/src/resources.rs b/examples/the-dungeon-puzzlers-lament/src/resources.rs index afcc1646..ae22aff9 100644 --- a/examples/the-dungeon-puzzlers-lament/src/resources.rs +++ b/examples/the-dungeon-puzzlers-lament/src/resources.rs @@ -50,8 +50,10 @@ named_tag!( SQUID_UP_SHADOW, SQUID_DOWN_SHADOW, ICE, - BLOCK, - GLOVE, + ROCK, + ROCK_SHADOW, + POW_GLOVE, + POW_GLOVE_SHADOW, ] ); From 5846a1c02428d3acd259c940fa8d7628efe975f3 Mon Sep 17 00:00:00 2001 From: Corwin Date: Mon, 28 Aug 2023 11:34:08 +0100 Subject: [PATCH 07/71] fix wonky ice animation next to wall --- .../src/game/simulation/animation.rs | 65 ++++++++++++++----- .../src/game/simulation/entity.rs | 18 +++-- 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs index b4a2b4a0..025ea47e 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs @@ -6,7 +6,7 @@ use core::ops::{Deref, DerefMut}; use agb::{ display::object::{OamIterator, ObjectUnmanaged, SpriteLoader}, - fixnum::{Num, Vector2D}, + fixnum::{num, Num, Vector2D}, }; use alloc::vec::Vec; use slotmap::SecondaryMap; @@ -52,7 +52,10 @@ impl ToPlay { AnimationInstruction::Move(e, p, s) => { self.moves.push(Move(e, convert_to_real_space(p), s)); } - AnimationInstruction::FakeOutMove(e, d, s) => self.fakeout.push(FakeOutMove(e, d, s)), + AnimationInstruction::FakeOutMove(e, d, p, s) => { + self.fakeout + .push(FakeOutMove(e, d, p.map(|p| convert_to_real_space(p)), s)) + } AnimationInstruction::Detatch(e, nk, s) => self.detatch.push(Detatch(e, nk, s)), AnimationInstruction::Attach(e, o, s) => { if let Some(entity_to_attach) = map.get(o) { @@ -249,8 +252,13 @@ impl Animation { for m in self.to_play.fakeout.drain(0..) { let entity = m.0; + let destination = m.2; - self.map.set_entity_to_start_location(entity); + if let Some(destination) = destination { + self.map.set_entity_start_location(entity, destination); + } else { + self.map.set_entity_to_start_location(entity); + } } for m in self.to_play.attach_progress.drain(0..) { @@ -281,18 +289,33 @@ impl Animation { for m in self.to_play.fakeout.iter_mut() { let entity = m.0; - let direction = m.1; - let direction = convert_to_real_space(direction.into()); - - sfx.play_sound_effect(m.2.take()); - - let go_to = direction / 2; - - let start = (self.ease * 2 - 1).abs(); - let end_multiplier = -start + 1; - if let Some(entity) = self.map.get_mut(entity) { - let location = entity.start_position + go_to * end_multiplier; + let direction = m.1; + let destination = m.2.unwrap_or(entity.start_position); + let direction = convert_to_real_space(direction.into()); + + sfx.play_sound_effect(m.3.take()); + + let go_to = destination + direction / 2; + + let mix = (self.ease * 2 - 1).abs(); + let start_position_mix = if self.ease <= num!(0.5) { + mix + } else { + 0.into() + }; + + let end_position_mix = if self.ease >= num!(0.5) { + mix + } else { + 0.into() + }; + + let intermediate_position_mix = -mix + 1; + + let location = entity.start_position * start_position_mix + + go_to * intermediate_position_mix + + destination * end_position_mix; entity.rendered_position = location; } @@ -386,7 +409,12 @@ impl Animation { } struct Move(EntityKey, Vector2D>, Option); -struct FakeOutMove(EntityKey, Direction, Option); +struct FakeOutMove( + EntityKey, + Direction, + Option>>, + Option, +); struct Detatch(EntityKey, EntityKey, Option); struct Attach(EntityKey, Item, EntityKey, Option); struct AttachProgress(EntityKey, Option); @@ -397,7 +425,12 @@ struct Change(EntityKey, Item, Option); pub enum AnimationInstruction { Add(EntityKey, Item, Vector2D, Option), Move(EntityKey, Vector2D, Option), - FakeOutMove(EntityKey, Direction, Option), + FakeOutMove( + EntityKey, + Direction, + Option>, + Option, + ), Detatch(EntityKey, EntityKey, Option), Attach(EntityKey, EntityKey, Option), Change(EntityKey, Item, Option), diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index ca5b92b6..09541d5c 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -182,11 +182,7 @@ impl EntityMap { return (can_move, hero_has_died, win_has_triggered); }; - animations.push(AnimationInstruction::Move( - entity_to_update_key, - desired_location, - entity_to_update.move_effect(), - )); + let move_effect = entity_to_update.move_effect(); let overlap_resolutions: Vec<_> = self .whats_at(desired_location) @@ -194,6 +190,17 @@ impl EntityMap { .map(|(key, other_entity)| (key, resolve_overlap(entity_to_update, other_entity))) .collect(); + if !overlap_resolutions + .iter() + .any(|x| matches!(x.1, OverlapResolution::MoveAgain)) + { + animations.push(AnimationInstruction::Move( + entity_to_update_key, + desired_location, + move_effect, + )); + } + for (other_entity_key, move_resolution) in overlap_resolutions { match move_resolution { OverlapResolution::Pickup => { @@ -277,6 +284,7 @@ impl EntityMap { animations.push(AnimationInstruction::FakeOutMove( entity_to_update_key, direction, + self.map.get(entity_to_update_key).map(|e| e.location), if explicit_stay_put { self.map .get(entity_to_update_key) From ae0b86c7b91e75c90d835c2c75e1e30745d798e3 Mon Sep 17 00:00:00 2001 From: Corwin Date: Mon, 28 Aug 2023 11:36:22 +0100 Subject: [PATCH 08/71] fix lints --- .../src/game/simulation/animation.rs | 2 +- .../src/game/simulation/entity.rs | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs index 025ea47e..21141c09 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs @@ -54,7 +54,7 @@ impl ToPlay { } AnimationInstruction::FakeOutMove(e, d, p, s) => { self.fakeout - .push(FakeOutMove(e, d, p.map(|p| convert_to_real_space(p)), s)) + .push(FakeOutMove(e, d, p.map(convert_to_real_space), s)) } AnimationInstruction::Detatch(e, nk, s) => self.detatch.push(Detatch(e, nk, s)), AnimationInstruction::Attach(e, o, s) => { diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 09541d5c..bb343820 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -89,7 +89,6 @@ impl EntityMap { &mut self, map: &Map, animations: &mut Vec, - entities_to_try_update: &mut VecDeque<(EntityKey, Action)>, entity_to_update_key: EntityKey, direction: Direction, can_turn_around: bool, @@ -150,7 +149,6 @@ impl EntityMap { self.attempt_move_in_direction( map, animations, - entities_to_try_update, other_entity_key, direction, true, @@ -250,8 +248,14 @@ impl EntityMap { break; } OverlapResolution::MoveAgain => { - entities_to_try_update - .push_front((entity_to_update_key, Action::Direction(direction))); + self.attempt_move_in_direction( + map, + animations, + other_entity_key, + direction, + false, + push_depth, + ); } } } @@ -273,7 +277,6 @@ impl EntityMap { return self.attempt_move_in_direction( map, animations, - entities_to_try_update, entity_to_update_key, -direction, false, @@ -323,7 +326,6 @@ impl EntityMap { .attempt_move_in_direction( map, &mut animations, - &mut entities_to_try_update, entity_to_update_key, direction, true, From dacecef900cdc1bd010af398f33f43459fe66bf0 Mon Sep 17 00:00:00 2001 From: Corwin Date: Mon, 28 Aug 2023 11:38:04 +0100 Subject: [PATCH 09/71] fix bug where the ice is the one to get moved --- .../the-dungeon-puzzlers-lament/src/game/simulation/entity.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index bb343820..97645e2c 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -251,7 +251,7 @@ impl EntityMap { self.attempt_move_in_direction( map, animations, - other_entity_key, + entity_to_update_key, direction, false, push_depth, From 4bd175cd7b0f147ad0cc4035eb018b925e26499d Mon Sep 17 00:00:00 2001 From: Corwin Date: Mon, 28 Aug 2023 11:45:21 +0100 Subject: [PATCH 10/71] defined update order --- .../src/game/simulation/entity.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 97645e2c..43dbb675 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -315,7 +315,13 @@ impl EntityMap { .map .iter() .map(|(key, entity)| (key, entity.desired_action(hero))) - .collect::>(); + .collect::>(); + + entities_to_try_update.sort_unstable_by_key(|(e, _)| { + let e = self.map.get(*e).unwrap(); + e.location.x + e.location.y * 1000 + }); + let mut entities_to_try_update = VecDeque::from(entities_to_try_update); while let Some((entity_to_update_key, desired_action)) = entities_to_try_update.pop_front() { From 0b45c006c8427b993722c19d5a06d95e8fbed45f Mon Sep 17 00:00:00 2001 From: Corwin Date: Mon, 28 Aug 2023 11:45:29 +0100 Subject: [PATCH 11/71] ice on bottom --- .../src/game/simulation/animation.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs index 21141c09..1fb03bbe 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs @@ -121,7 +121,12 @@ impl RenderCache { let mut score = 0; if matches!( self.item, - Item::Stairs | Item::Switch | Item::SwitchPressed | Item::SpikesDown | Item::SpikesUp + Item::Stairs + | Item::Switch + | Item::SwitchPressed + | Item::SpikesDown + | Item::SpikesUp + | Item::Ice ) { score += 100000; } From 2a02da1c2f6a2a73b91a69c186fb1cfefb33021b Mon Sep 17 00:00:00 2001 From: Corwin Date: Mon, 28 Aug 2023 14:00:39 +0100 Subject: [PATCH 12/71] simplify entity update loop --- .../src/game/simulation/entity.rs | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 43dbb675..a9c46b04 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -315,36 +315,35 @@ impl EntityMap { .map .iter() .map(|(key, entity)| (key, entity.desired_action(hero))) + .filter_map(|(key, action)| match action { + Action::Nothing => None, + Action::Direction(direction) => Some((key, direction)), + }) .collect::>(); entities_to_try_update.sort_unstable_by_key(|(e, _)| { let e = self.map.get(*e).unwrap(); e.location.x + e.location.y * 1000 }); - let mut entities_to_try_update = VecDeque::from(entities_to_try_update); - while let Some((entity_to_update_key, desired_action)) = entities_to_try_update.pop_front() - { - match desired_action { - Action::Nothing => {} - Action::Direction(direction) => { - let (_, hero_has_died_result, win_has_triggered_result) = self - .attempt_move_in_direction( - map, - &mut animations, - entity_to_update_key, - direction, - true, - self.map - .get(entity_to_update_key) - .and_then(|e| e.push_depth()) - .unwrap_or(0), - ); + let entities_to_try_update = entities_to_try_update; - hero_has_died |= hero_has_died_result; - win_has_triggered |= win_has_triggered_result; - } - } + for (entity_to_update_key, direction) in entities_to_try_update.iter().copied() { + let (_, hero_has_died_result, win_has_triggered_result) = self + .attempt_move_in_direction( + map, + &mut animations, + entity_to_update_key, + direction, + true, + self.map + .get(entity_to_update_key) + .and_then(|e| e.push_depth()) + .unwrap_or(0), + ); + + hero_has_died |= hero_has_died_result; + win_has_triggered |= win_has_triggered_result; } ( From 31c5519bc8bdfb3405b215d85b30c9139002d21b Mon Sep 17 00:00:00 2001 From: Corwin Date: Mon, 28 Aug 2023 15:59:20 +0100 Subject: [PATCH 13/71] base update order on initial positions --- .../src/game/simulation.rs | 5 ++++- .../src/game/simulation/entity.rs | 11 ++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs index ce42c8ec..8d9e36bb 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs @@ -41,7 +41,10 @@ impl Simulation { let mut entities = EntityMap::default(); let mut animation = Animation::default(); - for (item, location) in a { + let mut entities_to_add: Vec<_> = a.collect(); + entities_to_add.sort_unstable_by_key(|(_, location)| location.x + location.y * 100); + + for (item, location) in entities_to_add { animation.populate(entities.add(item, location), sfx); } diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index a9c46b04..72b06082 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -5,7 +5,7 @@ use core::ops::Neg; use agb::fixnum::Vector2D; -use alloc::{boxed::Box, collections::VecDeque, vec::Vec}; +use alloc::{boxed::Box, vec::Vec}; use slotmap::{new_key_type, SlotMap}; use crate::{ @@ -311,7 +311,7 @@ impl EntityMap { let mut animations = Vec::new(); - let mut entities_to_try_update = self + let entities_to_try_update = self .map .iter() .map(|(key, entity)| (key, entity.desired_action(hero))) @@ -321,13 +321,6 @@ impl EntityMap { }) .collect::>(); - entities_to_try_update.sort_unstable_by_key(|(e, _)| { - let e = self.map.get(*e).unwrap(); - e.location.x + e.location.y * 1000 - }); - - let entities_to_try_update = entities_to_try_update; - for (entity_to_update_key, direction) in entities_to_try_update.iter().copied() { let (_, hero_has_died_result, win_has_triggered_result) = self .attempt_move_in_direction( From b275db90da1af412f64fbba1fdf1fdce48fefa88 Mon Sep 17 00:00:00 2001 From: Corwin Date: Mon, 28 Aug 2023 23:05:35 +0100 Subject: [PATCH 14/71] make correct solution more obvious --- .../maps/levels/level_around.tmx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_around.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_around.tmx index a2e0cee9..5a59fbdf 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_around.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_around.tmx @@ -1,5 +1,5 @@ - + @@ -8,16 +8,16 @@ -0,0,1,7,4,7,5,2,2,2,9, -0,0,46,11,11,17,13,12,14,16,18, -1,6,1073741852,13,16,11,12,12,13,12,18, -46,16,13,13,15,14,13,16,15,13,47, -37,17,12,14,12,13,17,11,2147483676,26,27, -19,28,11,13,14,11,16,16,18,0,0, -0,37,16,12,13,17,17,15,18,0,0, -0,19,28,16,15,17,15,11,47,0,0, -0,0,46,12,15,12,16,2147483676,27,0,0, -0,0,19,21,25,23,22,27,0,0,0 +0,0,0,0,1,7,5,6,9,0,0, +0,0,1,4,1073741852,17,13,13,3221225500,9,0, +0,1,1073741852,13,16,11,12,16,16,18,0, +0,37,13,13,15,14,13,11,11,47,0, +0,46,12,14,12,13,17,17,2147483676,27,0, +0,46,11,13,14,11,16,13,47,0,0, +0,19,28,12,13,17,17,16,47,0,0, +0,0,19,28,15,17,15,2147483676,27,0,0, +0,0,0,19,22,25,20,27,0,0,0, +0,0,0,0,0,0,0,0,0,0,0 From afed1542febac9381f96f4e183769bf50aef2e22 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 09:50:00 +0100 Subject: [PATCH 15/71] Move the new sprites to the correct place --- .../gfx/sprites16x16.aseprite | Bin 14325 -> 14325 bytes .../the-dungeon-puzzlers-lament/src/level.rs | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite b/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite index 2206f636c63b113330a810fbcac0f5cb8bdc0c6a..dceeb1e4e9451afa75393fed91bfa6fb71c60841 100644 GIT binary patch delta 40 lcmeyG|22PuwZUW!X_3kP2JK+_6_jo@YzFZ+%NX5c1prV04+H=J delta 40 lcmeyG|22PuwZY^a+ STANDARD, Item::SquidDown => STANDARD, Item::Ice => ZERO, - Item::MovableBlock => STANDARD, + Item::MovableBlock => ZERO, Item::Glove => STANDARD, } } From b5da20d748f9301eaa74e93705be6839e628c1d3 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 20:11:55 +0100 Subject: [PATCH 16/71] blocks can't intersect heros or enemies --- .../the-dungeon-puzzlers-lament/src/game/simulation/entity.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 72b06082..63b09808 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -465,6 +465,9 @@ fn resolve_move(mover: &Entity, into: &Entity) -> MoveAttemptResolution { } (_, EntityType::Door) => MoveAttemptResolution::StayPut, (_, EntityType::MovableBlock) => MoveAttemptResolution::AttemptPush, + (EntityType::MovableBlock, EntityType::Hero(_) | EntityType::Enemy(_)) => { + MoveAttemptResolution::StayPut + } (_, _) => MoveAttemptResolution::CoExist, } } From d781a413579f85c0134adb4f9dd47af7c3a8d6eb Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 20:37:50 +0100 Subject: [PATCH 17/71] Add teleporter --- .../gfx/concept.aseprite | Bin 45011 -> 64548 bytes .../gfx/sprites16x16.aseprite | Bin 14325 -> 15554 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/gfx/concept.aseprite b/examples/the-dungeon-puzzlers-lament/gfx/concept.aseprite index dc8da1a4183c70dc3686ae016b11fb7b978cbde6..78cf8352792129f0b77c4faabe8c35a9ba7b020a 100644 GIT binary patch delta 2320 zcmdtk`BRfg8UWxA!=cWYpmM1oheB{f8P<_w!==c0!>B8;AVgsV1VV&>F$Va+15_?C z8p`2T85SgfB1HJ26e0xVhzv&(Nw||JR=?fVKRn%i zBkP_oz|42A0KjOe4ln~017?5*002L$`=8Ay#~iJ3DJR7eQK1fQGc)=lWtd~PHK+Zi zE&#~PAFiHNM>W@08=)z{K?f^Er2&OtfM}p=$ z4SXg$O|? zqa_=yauj11PMY?Z%bxkV6*YD#Zm83rxXP;q{Jq5eHbiV`0A|GhiVrDB89u-qq!do< zt-v~xzW3E9%_MFBqx;?UJgN6@AJIGW{P0t=r`{eZdK>m^(I1dMder}EcEe943BVRD zeXUKHca~QcHav^`YU!K(WcIpC2r-}dyzI#-8Y;-tC0oJnh^E4`Y=h#QUd|^~WlHH` zCc(nU6Ws_T5?vU_q=L)#`T;V$RDcP~IRGCWot}kUX$Ty+eLDgJuIG!)p<9N@3`Z-!TqiaAn&!abh0t&^9u&IaR4q!D|B&g&gm)ele^ST@%PEYJ54 zW*34Zi?wytWYjGwd{(JEZW_?-6jG_K#Da%}3$E&nS{u~yFKh>0oZ8S|wjbbE)w|Ig z_Vl+BX_y31OemUjFnK|2 z(Q*Fghq>qslpKlY&5C1VuVz53B_zIY4EJk;$Me{$?SbD-Rv9Ny)_FTQIkpzu;hb&} z_tH77gNGUdcH#`B`kl??;z`Q4D^Xgg6SA^5Bx>yQL6mfA*(qNCT4~ta^!IU;_u^ne z*cSdCtgTw31Z|nZ=aMy_~Q53ZPwrnw%VykL0o?~jy%!}yNuB<>C z@-R9E0ZA7H9^yeQC?w55UR!rkQvHSwg}B91lg>^*$?V8ms~GWAGKdKtY2a14OjZR> zR-JzH;~xCCK(J*v`Vf{KCZwX?~b#mP{OqnWb zCH_hs4X;`|XZ~Lvg^d5Aa9{6`ZmR9yb)Dg`U57rktZacD($(Dctb5a@%!AU+dYZEu zny_84t>=n7x8f#pz+zg_t43;A88P&R(#<-w3LjdAb*+G?p%O2z`et?u(c^d}mqCdk zD1+Tkxs(mc#wJ&~Gsl)0=m~p6`jmuDExYA;9F=^F8pddwaqR-H^zSrLqd<8Kjo^nd z!v|@=iYhs=q}yUHJc*@KUnBvIhH7|n|6u@{P_F(?!zysPBMG1{vLKG9Dj~3S<)s6>riFufo~c9)&3jOO{L*}LOMO68g%|+i|gGM$hJ`sEMKGeU0#7oEQ z`Z(sXPHz~2;Qq;~oiv}6vWLd`6FrB;{7Z~4=fr2F#T-g@!^y=HywMBzIUgNWv=-{4 zh!KOt%G$f}`~gXB|9RHqcchWj#7O;XxgSv;pxaBE;lPNd4+VZ?|GM!1!;G39zlYpt z2fs?L;Td?s>?-d;lPj29rYL%s(JVgu@*3ExFYFN%AsU7Zgjpv3EJl4G)HJ?PlBI0t z$~(Hl2CcAbbcNq@4N%-m1<*5BO7y{ozQ;n4p5S+9MOV!i+0-%OJR delta 110 zcmZ4TgZc7(CdJF^85kZcWo7uluz*2jINs(G3p2~GEY7)D9+5nz_R(J;GXi$Z?BrG0RU!P8JqwB diff --git a/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite b/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite index dceeb1e4e9451afa75393fed91bfa6fb71c60841..32697c846b6fb9c5bb7172119a0b6428224aa856 100644 GIT binary patch delta 1308 zcmeyGf2dONkPQRFgQZRk0zjz1z{tSBkOIUAATm)gp4XI}f#KIj4X~8P#9m4MNk9dX z3L;Qt!V?XJC!RN9LCb>Xv5$DH3douGK9GLxCZzKg}4UA2YWcW_=h_(IHIcILQ=C?ku{ESvOa6l zi+eS3G93(AiEfdSrtHjWn=gc5! z1}=t*ImrnJSk|4I_Wz=xSZc)8@1Kt)B*Z*husS}~N|t%?Z01Yq>RP>5 zg*zo@&!2d=*H_-dwkV?che6NTvnM|NcqA1mYxk9*etq5DtCny-FdcOiEKLMS5S5Z07s^?2LJ#7 delta 132 zcmX?9`88kht2qP1gQYeM0zjz1z{tSBkOIUAAT&`io_9GL1H-S6s$ePAiM^8iZ9oN* z3PMn2f)fpeC!R>*ascvKKxPO{c49PR&u3;}kWi4@+{*ZfiIHh?221Pa39NC9lP9pc OO@7B_yV;A~(hvZ_tsANU From 346f62f328df0b9cebb9f9cac3eee2f859eadd1e Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 20:51:42 +0100 Subject: [PATCH 18/71] resolve overlaps after all moves --- .../src/game/simulation/entity.rs | 222 ++++++++++-------- 1 file changed, 129 insertions(+), 93 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 63b09808..25d32ebf 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -93,6 +93,7 @@ impl EntityMap { direction: Direction, can_turn_around: bool, push_depth: i32, + entities_that_have_moved: &mut Vec<(EntityKey, Direction)>, ) -> (bool, bool, bool) { let mut hero_has_died = false; let mut win_has_triggered = false; @@ -153,6 +154,7 @@ impl EntityMap { direction, true, depth, + entities_that_have_moved, ); if !can_move_result { @@ -176,89 +178,19 @@ impl EntityMap { if let Some(e) = self.map.get_mut(entity_to_update_key) { e.location = desired_location; } + entities_that_have_moved.push((entity_to_update_key, direction)); + let Some(entity_to_update) = self.map.get(entity_to_update_key) else { return (can_move, hero_has_died, win_has_triggered); }; let move_effect = entity_to_update.move_effect(); - let overlap_resolutions: Vec<_> = self - .whats_at(desired_location) - .filter(|(k, _)| *k != entity_to_update_key) - .map(|(key, other_entity)| (key, resolve_overlap(entity_to_update, other_entity))) - .collect(); - - if !overlap_resolutions - .iter() - .any(|x| matches!(x.1, OverlapResolution::MoveAgain)) - { - animations.push(AnimationInstruction::Move( - entity_to_update_key, - desired_location, - move_effect, - )); - } - - for (other_entity_key, move_resolution) in overlap_resolutions { - match move_resolution { - OverlapResolution::Pickup => { - animations.push(AnimationInstruction::Attach( - entity_to_update_key, - other_entity_key, - self.map - .get(other_entity_key) - .and_then(|x| x.pickup_sound_effect()), - )); - let other = self.map.remove(other_entity_key).unwrap(); - - if let Some((location, dropped)) = self - .map - .get_mut(entity_to_update_key) - .and_then(|x| x.pickup(other.entity).map(|y| (x.location, y))) - { - let new_key = self.map.insert(Entity { - location, - entity: dropped, - }); - - animations.push(AnimationInstruction::Detatch( - entity_to_update_key, - new_key, - self.map.get(new_key).and_then(|x| x.drop_effect()), - )); - } - } - OverlapResolution::CoExist => {} - OverlapResolution::Win => { - win_has_triggered = true; - } - OverlapResolution::ToggleSystem(system) => { - for (k, e) in self.map.iter_mut() { - if let Some(change) = e.switch(system) { - animations.push(AnimationInstruction::Change( - k, - change, - e.change_effect(), - )); - } - } - } - OverlapResolution::Die => { - hero_has_died |= self.kill_entity(entity_to_update_key, animations); - break; - } - OverlapResolution::MoveAgain => { - self.attempt_move_in_direction( - map, - animations, - entity_to_update_key, - direction, - false, - push_depth, - ); - } - } - } + animations.push(AnimationInstruction::Move( + entity_to_update_key, + desired_location, + move_effect, + )); } else if explicit_stay_put && can_turn_around && self.map.get(entity_to_update_key).map(|e| e.turns_around()) == Some(true) @@ -281,6 +213,7 @@ impl EntityMap { -direction, false, push_depth, + entities_that_have_moved, ); } } else { @@ -305,13 +238,99 @@ impl EntityMap { (can_move, hero_has_died, win_has_triggered) } + fn resolve_overlap_from_move( + &mut self, + animations: &mut Vec, + entity_to_update_key: EntityKey, + ) -> (bool, bool, bool) { + let mut win_has_triggered = false; + let mut hero_has_died = false; + let mut should_move_again = false; + + let Some(entity_to_update) = self.map.get(entity_to_update_key) else { + return (should_move_again, hero_has_died, win_has_triggered); + }; + + let location = entity_to_update.location; + + let overlap_resolutions: Vec<_> = self + .whats_at(location) + .filter(|(k, _)| *k != entity_to_update_key) + .map(|(key, other_entity)| (key, resolve_overlap(entity_to_update, other_entity))) + .collect(); + + for (other_entity_key, move_resolution) in overlap_resolutions { + match move_resolution { + OverlapResolution::Pickup => { + animations.push(AnimationInstruction::Attach( + entity_to_update_key, + other_entity_key, + self.map + .get(other_entity_key) + .and_then(|x| x.pickup_sound_effect()), + )); + let other = self.map.remove(other_entity_key).unwrap(); + + if let Some((location, dropped)) = self + .map + .get_mut(entity_to_update_key) + .and_then(|x| x.pickup(other.entity).map(|y| (x.location, y))) + { + let new_key = self.map.insert(Entity { + location, + entity: dropped, + }); + + animations.push(AnimationInstruction::Detatch( + entity_to_update_key, + new_key, + self.map.get(new_key).and_then(|x| x.drop_effect()), + )); + } + } + OverlapResolution::CoExist => {} + OverlapResolution::Win => { + win_has_triggered = true; + } + OverlapResolution::ToggleSystem(system) => { + for (k, e) in self.map.iter_mut() { + if let Some(change) = e.switch(system) { + animations.push(AnimationInstruction::Change( + k, + change, + e.change_effect(), + )); + } + } + } + OverlapResolution::Die => { + hero_has_died |= self.kill_entity(entity_to_update_key, animations); + break; + } + OverlapResolution::MoveAgain => { + if let Some(existing_animation) = animations.iter().position(|x| { + if let AnimationInstruction::Move(entity, _, _) = x { + *entity == entity_to_update_key + } else { + false + } + }) { + animations.swap_remove(existing_animation); + } + should_move_again = true; + } + } + } + (should_move_again, hero_has_died, win_has_triggered) + } + pub fn tick(&mut self, map: &Map, hero: Action) -> (Outcome, Vec) { let mut hero_has_died = false; let mut win_has_triggered = false; let mut animations = Vec::new(); - let entities_to_try_update = self + let mut entities_to_try_update = self .map .iter() .map(|(key, entity)| (key, entity.desired_action(hero))) @@ -321,22 +340,39 @@ impl EntityMap { }) .collect::>(); - for (entity_to_update_key, direction) in entities_to_try_update.iter().copied() { - let (_, hero_has_died_result, win_has_triggered_result) = self - .attempt_move_in_direction( - map, - &mut animations, - entity_to_update_key, - direction, - true, - self.map - .get(entity_to_update_key) - .and_then(|e| e.push_depth()) - .unwrap_or(0), - ); + while !entities_to_try_update.is_empty() { + let mut entities_that_have_moved = Vec::new(); - hero_has_died |= hero_has_died_result; - win_has_triggered |= win_has_triggered_result; + for (entity_to_update_key, direction) in entities_to_try_update.drain(..) { + let (_, hero_has_died_result, win_has_triggered_result) = self + .attempt_move_in_direction( + map, + &mut animations, + entity_to_update_key, + direction, + true, + self.map + .get(entity_to_update_key) + .and_then(|e| e.push_depth()) + .unwrap_or(0), + &mut entities_that_have_moved, + ); + + hero_has_died |= hero_has_died_result; + win_has_triggered |= win_has_triggered_result; + } + + for (entity_to_update_key, direction) in entities_that_have_moved { + let (should_move_again, hero_has_died_result, win_has_triggered_result) = + self.resolve_overlap_from_move(&mut animations, entity_to_update_key); + + if should_move_again { + entities_to_try_update.push((entity_to_update_key, direction)); + } + + hero_has_died |= hero_has_died_result; + win_has_triggered |= win_has_triggered_result; + } } ( From f72ff398672c5747aba7e09b32e5907f3d9a0602 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 20:49:54 +0100 Subject: [PATCH 19/71] Make the spikes more obvious --- .../gfx/sprites16x16.aseprite | Bin 15554 -> 15452 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite b/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite index 32697c846b6fb9c5bb7172119a0b6428224aa856..304e937bf7f5136dede2f7390687a95f4630557e 100644 GIT binary patch delta 443 zcmX?9d8dLgW+USb$;o;=67@_BObq{-7@&Zcfrp`DPIAHlK0e#puk!68eh#bTwiW&U zuVAb2X18POg18C4R-QI%Fx>cS!q)>|K7Qv+y4w7vZh~D(&*_?)x?^hYC(gg9;`k{! zyYk1Mp7S;_b!w_S7w`7v$uaD&TC=njXw9#Wj0`D2nh}Ug874dMaAecb1(O4~CBm5) zSWx`T1@SY>pW3GXwdN}h7>cQCG_1Yz@Bful>3{5OY=;aLYYl8q{Brmvlq_zfwq#y} lL#}1^l7jOX7#MziWMoJI(u_ddH(5|Xw4R?qfT3bea>4ydvaxWQoQGUnXQ8m- z=YpM`BA+kZb?K_yaj0WLWy>MS`ISEowN9A%0bm>6DK zfBACt|H{*54ThS(5~~t_Iewe`NNs`*kMLu)q(2>JeV5E=f2S67M)_EO%b^~D17c}g qI;xW%@y)jH;LVQtC-Ek+mxnQHvlRfwA@I}y From fef393c39cfb153ccf4f4575ad308ea3ccda0be1 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 20:54:31 +0100 Subject: [PATCH 20/71] We can now make a lot more levels --- .../src/game/numbers.rs | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/numbers.rs b/examples/the-dungeon-puzzlers-lament/src/game/numbers.rs index 346e42bd..76ad61dc 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/numbers.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/numbers.rs @@ -19,4 +19,84 @@ pub const NUMBERS: &[&str] = &[ "Eighteen", "Ninteen", "Twenty", + "Twenty One", + "Twenty Two", + "Twenty Three", + "Twenty Four", + "Twenty Five", + "Twenty Six", + "Twenty Seven", + "Twenty Eight", + "Twenty Nine", + "Thirty", + "Thirty One", + "Thirty Two", + "Thirty Three", + "Thirty Four", + "Thirty Five", + "Thirty Six", + "Thirty Seven", + "Thirty Eight", + "Thirty Nine", + "Forty", + "Forty One", + "Forty Two", + "Forty Three", + "Forty Four", + "Forty Five", + "Forty Six", + "Forty Seven", + "Forty Eight", + "Forty Nine", + "Fifty", + "Fifty One", + "Fifty Two", + "Fifty Three", + "Fifty Four", + "Fifty Five", + "Fifty Six", + "Fifty Seven", + "Fifty Eight", + "Fifty Nine", + "Sixty", + "Sixty One", + "Sixty Two", + "Sixty Three", + "Sixty Four", + "Sixty Five", + "Sixty Six", + "Sixty Seven", + "Sixty Eight", + "Sixty Nine", + "Seventy", + "Seventy One", + "Seventy Two", + "Seventy Three", + "Seventy Four", + "Seventy Five", + "Seventy Six", + "Seventy Seven", + "Seventy Eight", + "Seventy Nine", + "Eighty", + "Eighty One", + "Eighty Two", + "Eighty Three", + "Eighty Four", + "Eighty Five", + "Eighty Six", + "Eighty Seven", + "Eighty Eight", + "Eighty Nine", + "Ninety", + "Ninety One", + "Ninety Two", + "Ninety Three", + "Ninety Four", + "Ninety Five", + "Ninety Six", + "Ninety Seven", + "Ninety Eight", + "Ninety Nine", + "One Hundred", ]; From 15d075a1c8657fc7e09d9bfa76de84455f52441e Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 20:56:29 +0100 Subject: [PATCH 21/71] Maybe we'll have this many levels one day --- .../src/game/numbers.rs | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/numbers.rs b/examples/the-dungeon-puzzlers-lament/src/game/numbers.rs index 76ad61dc..c2fc371e 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/numbers.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/numbers.rs @@ -99,4 +99,104 @@ pub const NUMBERS: &[&str] = &[ "Ninety Eight", "Ninety Nine", "One Hundred", + "One Hundred and One", + "One Hundred and Two", + "One Hundred and Three", + "One Hundred and Four", + "One Hundred and Five", + "One Hundred and Six", + "One Hundred and Seven", + "One Hundred and Eight", + "One Hundred and Nine", + "One Hundred and Ten", + "One Hundred and Eleven", + "One Hundred and Twelve", + "One Hundred and Thirteen", + "One Hundred and Fourteen", + "One Hundred and Fifteen", + "One Hundred and Sixteen", + "One Hundred and Seventeen", + "One Hundred and Eighteen", + "One Hundred and Nineteen", + "One Hundred and Twenty", + "One Hundred and Twenty One", + "One Hundred and Twenty Two", + "One Hundred and Twenty Three", + "One Hundred and Twenty Four", + "One Hundred and Twenty Five", + "One Hundred and Twenty Six", + "One Hundred and Twenty Seven", + "One Hundred and Twenty Eight", + "One Hundred and Twenty Nine", + "One Hundred and Thirty", + "One Hundred and Thirty One", + "One Hundred and Thirty Two", + "One Hundred and Thirty Three", + "One Hundred and Thirty Four", + "One Hundred and Thirty Five", + "One Hundred and Thirty Six", + "One Hundred and Thirty Seven", + "One Hundred and Thirty Eight", + "One Hundred and Thirty Nine", + "One Hundred and Forty", + "One Hundred and Forty One", + "One Hundred and Forty Two", + "One Hundred and Forty Three", + "One Hundred and Forty Four", + "One Hundred and Forty Five", + "One Hundred and Forty Six", + "One Hundred and Forty Seven", + "One Hundred and Forty Eight", + "One Hundred and Forty Nine", + "One Hundred and Fifty", + "One Hundred and Fifty One", + "One Hundred and Fifty Two", + "One Hundred and Fifty Three", + "One Hundred and Fifty Four", + "One Hundred and Fifty Five", + "One Hundred and Fifty Six", + "One Hundred and Fifty Seven", + "One Hundred and Fifty Eight", + "One Hundred and Fifty Nine", + "One Hundred and Sixty", + "One Hundred and Sixty One", + "One Hundred and Sixty Two", + "One Hundred and Sixty Three", + "One Hundred and Sixty Four", + "One Hundred and Sixty Five", + "One Hundred and Sixty Six", + "One Hundred and Sixty Seven", + "One Hundred and Sixty Eight", + "One Hundred and Sixty Nine", + "One Hundred and Seventy", + "One Hundred and Seventy One", + "One Hundred and Seventy Two", + "One Hundred and Seventy Three", + "One Hundred and Seventy Four", + "One Hundred and Seventy Five", + "One Hundred and Seventy Six", + "One Hundred and Seventy Seven", + "One Hundred and Seventy Eight", + "One Hundred and Seventy Nine", + "One Hundred and Eighty", + "One Hundred and Eighty One", + "One Hundred and Eighty Two", + "One Hundred and Eighty Three", + "One Hundred and Eighty Four", + "One Hundred and Eighty Five", + "One Hundred and Eighty Six", + "One Hundred and Eighty Seven", + "One Hundred and Eighty Eight", + "One Hundred and Eighty Nine", + "One Hundred and Ninety", + "One Hundred and Ninety One", + "One Hundred and Ninety Two", + "One Hundred and Ninety Three", + "One Hundred and Ninety Four", + "One Hundred and Ninety Five", + "One Hundred and Ninety Six", + "One Hundred and Ninety Seven", + "One Hundred and Ninety Eight", + "One Hundred and Ninety Nine", + "Two Hundred", ]; From 078f4f22a94a2544287a117cb19a423917f5d885 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 20:57:21 +0100 Subject: [PATCH 22/71] make obtuse return values understandable --- .../src/game/simulation/entity.rs | 108 +++++++++++------- 1 file changed, 69 insertions(+), 39 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 25d32ebf..b516d364 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -30,6 +30,23 @@ pub enum Outcome { Win, } +struct ActionResult { + hero_has_died: bool, + win_has_triggered: bool, +} + +impl ActionResult { + fn new(hero_has_died: bool, win_has_triggered: bool) -> Self { + Self { + hero_has_died, + win_has_triggered, + } + } +} + +struct HasMoved(bool); +struct WantsToMoveAgain(bool); + impl EntityMap { fn whats_at(&self, location: Vector2D) -> impl Iterator { self.map @@ -94,12 +111,15 @@ impl EntityMap { can_turn_around: bool, push_depth: i32, entities_that_have_moved: &mut Vec<(EntityKey, Direction)>, - ) -> (bool, bool, bool) { + ) -> (HasMoved, ActionResult) { let mut hero_has_died = false; let mut win_has_triggered = false; let Some(entity_to_update) = self.map.get(entity_to_update_key) else { - return (false, hero_has_died, win_has_triggered); + return ( + HasMoved(false), + ActionResult::new(hero_has_died, win_has_triggered), + ); }; let entity_location = entity_to_update.location; @@ -146,23 +166,22 @@ impl EntityMap { MoveAttemptResolution::AttemptPush => { let depth = push_depth - 1; if depth >= 0 { - let (can_move_result, hero_has_died_result, win_has_triggered_result) = - self.attempt_move_in_direction( - map, - animations, - other_entity_key, - direction, - true, - depth, - entities_that_have_moved, - ); + let (can_move_result, action_result) = self.attempt_move_in_direction( + map, + animations, + other_entity_key, + direction, + true, + depth, + entities_that_have_moved, + ); - if !can_move_result { + if !can_move_result.0 { can_move = false; explicit_stay_put = true; } - hero_has_died |= hero_has_died_result; - win_has_triggered |= win_has_triggered_result; + hero_has_died |= action_result.hero_has_died; + win_has_triggered |= action_result.win_has_triggered; } else { can_move = false; explicit_stay_put = true; @@ -181,7 +200,10 @@ impl EntityMap { entities_that_have_moved.push((entity_to_update_key, direction)); let Some(entity_to_update) = self.map.get(entity_to_update_key) else { - return (can_move, hero_has_died, win_has_triggered); + return ( + HasMoved(can_move), + ActionResult::new(hero_has_died, win_has_triggered), + ); }; let move_effect = entity_to_update.move_effect(); @@ -235,20 +257,26 @@ impl EntityMap { )); } - (can_move, hero_has_died, win_has_triggered) + ( + HasMoved(can_move), + ActionResult::new(hero_has_died, win_has_triggered), + ) } fn resolve_overlap_from_move( &mut self, animations: &mut Vec, entity_to_update_key: EntityKey, - ) -> (bool, bool, bool) { + ) -> (WantsToMoveAgain, ActionResult) { let mut win_has_triggered = false; let mut hero_has_died = false; let mut should_move_again = false; let Some(entity_to_update) = self.map.get(entity_to_update_key) else { - return (should_move_again, hero_has_died, win_has_triggered); + return ( + WantsToMoveAgain(should_move_again), + ActionResult::new(hero_has_died, win_has_triggered), + ); }; let location = entity_to_update.location; @@ -321,7 +349,10 @@ impl EntityMap { } } } - (should_move_again, hero_has_died, win_has_triggered) + ( + WantsToMoveAgain(should_move_again), + ActionResult::new(hero_has_died, win_has_triggered), + ) } pub fn tick(&mut self, map: &Map, hero: Action) -> (Outcome, Vec) { @@ -344,34 +375,33 @@ impl EntityMap { let mut entities_that_have_moved = Vec::new(); for (entity_to_update_key, direction) in entities_to_try_update.drain(..) { - let (_, hero_has_died_result, win_has_triggered_result) = self - .attempt_move_in_direction( - map, - &mut animations, - entity_to_update_key, - direction, - true, - self.map - .get(entity_to_update_key) - .and_then(|e| e.push_depth()) - .unwrap_or(0), - &mut entities_that_have_moved, - ); + let (_, action_result) = self.attempt_move_in_direction( + map, + &mut animations, + entity_to_update_key, + direction, + true, + self.map + .get(entity_to_update_key) + .and_then(|e| e.push_depth()) + .unwrap_or(0), + &mut entities_that_have_moved, + ); - hero_has_died |= hero_has_died_result; - win_has_triggered |= win_has_triggered_result; + hero_has_died |= action_result.hero_has_died; + win_has_triggered |= action_result.win_has_triggered; } for (entity_to_update_key, direction) in entities_that_have_moved { - let (should_move_again, hero_has_died_result, win_has_triggered_result) = + let (should_move_again, action_result) = self.resolve_overlap_from_move(&mut animations, entity_to_update_key); - if should_move_again { + if should_move_again.0 { entities_to_try_update.push((entity_to_update_key, direction)); } - hero_has_died |= hero_has_died_result; - win_has_triggered |= win_has_triggered_result; + hero_has_died |= action_result.hero_has_died; + win_has_triggered |= action_result.win_has_triggered; } } From 56f1b68055746c5f8b74f0624d88e91eb71acffa Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 21:01:35 +0100 Subject: [PATCH 23/71] allow with justification --- .../the-dungeon-puzzlers-lament/src/game/simulation/entity.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index b516d364..e264efd4 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -102,6 +102,8 @@ impl EntityMap { AnimationInstruction::Add(idx, entity, location, None) } + // allow because while it's a lot of arguments, it's not confusing because they are all of different types + #[allow(clippy::too_many_arguments)] fn attempt_move_in_direction( &mut self, map: &Map, From 98c96080f917f3c60b605174789a83c6dff7e4d4 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 21:11:58 +0100 Subject: [PATCH 24/71] environment variable to run specific level --- examples/the-dungeon-puzzlers-lament/build.rs | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index 2981feca..d32ab2d7 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -9,6 +9,25 @@ use std::{ use proc_macro2::TokenStream; const LEVEL_NAMES: &[&str] = &[ + "level1", + "level2", + "level3", + "level4", + "level5", + "level6", + "level_switch", + "level_spikes", + "level_spikes2", + "level_squid_force_button", + "level_squid_intro", + "level_squid2", + "level_squid1", + "level_squid_item", + "level_squid_button", + "level_squid_drop", + "level_spikes3", + "level_around", + "level_squidprogramming", "a_familiar_sight", "block_push_1", "block_push_2", @@ -23,7 +42,18 @@ fn main() { let ui_map = load_tmx(&mut tile_loader, "maps/UI.tmx"); let ui_tiles = export_ui_tiles(&ui_map, quote!(ui)); - let levels = LEVEL_NAMES + const DPL_LEVELS_ENVIRONMENT_VARIABLE: &str = "DPL_LEVELS"; + + println!( + "cargo:rerun-if-env-changed={}", + DPL_LEVELS_ENVIRONMENT_VARIABLE + ); + + let levels: Vec = env::var(DPL_LEVELS_ENVIRONMENT_VARIABLE) + .map(|x| x.split(',').map(|x| x.trim().to_string()).collect()) + .unwrap_or(LEVEL_NAMES.iter().map(|x| x.to_string()).collect()); + + let levels = levels .iter() .map(|level| load_level(&mut tile_loader, &format!("maps/levels/{level}.tmx"))) .collect::>(); From a7cbb60b20cb6023809ae1f105a175cba74c8e5c Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 21:13:57 +0100 Subject: [PATCH 25/71] Add a squid rock level --- examples/the-dungeon-puzzlers-lament/build.rs | 1 + .../maps/levels/squid_rock.tmx | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/squid_rock.tmx diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index d32ab2d7..ebc0a1e7 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -30,6 +30,7 @@ const LEVEL_NAMES: &[&str] = &[ "level_squidprogramming", "a_familiar_sight", "block_push_1", + "squid_rock", "block_push_2", "block_push_3", ]; diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/squid_rock.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/squid_rock.tmx new file mode 100644 index 00000000..584de271 --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/squid_rock.tmx @@ -0,0 +1,37 @@ + + + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,6,2,7,5,9,0, +0,0,1,8,1073741852,17,15,13,17,38,0, +0,0,46,15,15,11,11,17,15,47,0, +0,0,10,15,12,17,17,15,11,38,0, +0,0,19,21,28,14,17,14,16,18,0, +0,0,0,0,19,24,28,16,13,38,0, +0,0,0,0,0,0,19,22,23,27,0, +0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + + + + + + + From 07c5afb9905d5e19dd686cf78bcfb7a405da5937 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 21:24:30 +0100 Subject: [PATCH 26/71] add teleporter entity type --- .../the-dungeon-puzzlers-lament/src/game/simulation/entity.rs | 2 ++ examples/the-dungeon-puzzlers-lament/src/level.rs | 4 ++++ examples/the-dungeon-puzzlers-lament/src/resources.rs | 1 + 3 files changed, 7 insertions(+) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index e264efd4..04851cef 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -568,6 +568,7 @@ pub enum EntityType { Spikes(Switchable), Ice, MovableBlock, + Teleporter, } #[derive(Debug)] @@ -844,6 +845,7 @@ impl From for EntityType { level::Item::Ice => EntityType::Ice, level::Item::MovableBlock => EntityType::MovableBlock, level::Item::Glove => EntityType::Item(Item::Glove), + level::Item::Teleporter => EntityType::Teleporter, } } } diff --git a/examples/the-dungeon-puzzlers-lament/src/level.rs b/examples/the-dungeon-puzzlers-lament/src/level.rs index 4ddff314..50974ee3 100644 --- a/examples/the-dungeon-puzzlers-lament/src/level.rs +++ b/examples/the-dungeon-puzzlers-lament/src/level.rs @@ -21,6 +21,7 @@ pub enum Item { Ice, MovableBlock, Glove, + Teleporter, } impl Item { @@ -43,6 +44,7 @@ impl Item { Item::Ice => resources::ICE, Item::MovableBlock => resources::ROCK_SHADOW, Item::Glove => resources::POW_GLOVE_SHADOW, + Item::Teleporter => resources::TELEPORTER, } } @@ -65,6 +67,7 @@ impl Item { Item::Ice => resources::ICE, Item::MovableBlock => resources::ROCK, Item::Glove => resources::POW_GLOVE, + Item::Teleporter => resources::TELEPORTER, } } @@ -90,6 +93,7 @@ impl Item { Item::Ice => ZERO, Item::MovableBlock => ZERO, Item::Glove => STANDARD, + Item::Teleporter => ZERO, } } } diff --git a/examples/the-dungeon-puzzlers-lament/src/resources.rs b/examples/the-dungeon-puzzlers-lament/src/resources.rs index ae22aff9..c5d0e645 100644 --- a/examples/the-dungeon-puzzlers-lament/src/resources.rs +++ b/examples/the-dungeon-puzzlers-lament/src/resources.rs @@ -54,6 +54,7 @@ named_tag!( ROCK_SHADOW, POW_GLOVE, POW_GLOVE_SHADOW, + TELEPORTER, ] ); From df2f45797b9cd37e8633357884beafee5443d40d Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 21:31:36 +0100 Subject: [PATCH 27/71] only hero and squid can pick up items --- .../the-dungeon-puzzlers-lament/src/game/simulation/entity.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 04851cef..35835401 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -453,7 +453,9 @@ fn resolve_spikes(switable: &Switchable) -> OverlapResolution { fn resolve_overlap(me: &Entity, other: &Entity) -> OverlapResolution { match (&me.entity, &other.entity) { (EntityType::Hero(_), EntityType::Stairs) => OverlapResolution::Win, - (_, EntityType::Item(_)) => OverlapResolution::Pickup, + (EntityType::Hero(_) | EntityType::Enemy(Enemy::Squid(_)), EntityType::Item(_)) => { + OverlapResolution::Pickup + } (EntityType::MovableBlock, EntityType::Spikes(_)) => OverlapResolution::CoExist, (_, EntityType::Spikes(switch)) => resolve_spikes(switch), (_, EntityType::Switch(switch)) => OverlapResolution::ToggleSystem(switch.system), From 86607eeab0ade8fe2964e927f6c1481888514160 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 21:33:21 +0100 Subject: [PATCH 28/71] Glove and key --- .../maps/levels/glove_key.tmx | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx new file mode 100644 index 00000000..f58e7713 --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx @@ -0,0 +1,37 @@ + + + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,1,8,3,2,2,8,5,4,9,0, +0,10,17,15,17,11,13,15,16,38,0, +1,1073741852,11,12,11,13,17,13,16,47,0, +10,12,17,14,15,13,13,11,13,18,0, +19,28,12,15,13,13,14,15,13,38,0, +0,19,25,26,24,22,25,24,24,27,0, +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + + + + + + + From 2ce7d91c7494db27d15bd30b5b7efffcadadec3b Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 21:43:37 +0100 Subject: [PATCH 29/71] Add a level with just rocks --- examples/the-dungeon-puzzlers-lament/build.rs | 2 + .../maps/levels/just_rocks.tmx | 43 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index ebc0a1e7..184c26ef 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -30,8 +30,10 @@ const LEVEL_NAMES: &[&str] = &[ "level_squidprogramming", "a_familiar_sight", "block_push_1", + "just_rocks", "squid_rock", "block_push_2", + "glove_key", "block_push_3", ]; diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx new file mode 100644 index 00000000..753a283c --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx @@ -0,0 +1,43 @@ + + + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,1,6,3,5,4,5,1073741872,7,9,0, +0,10,15,17,13,15,11,1073741863,16,38,0, +0,46,15,12,17,15,13,15,15,47,0, +0,46,14,17,12,13,17,11,17,18,0, +0,46,13,11,11,17,12,16,15,47,0, +0,46,12,14,17,13,14,11,11,38,0, +0,19,22,20,22,23,26,25,24,27,0, +0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + + + + + + + + + + + + + From 8b8f94ae7ff9133beacfd44d8a53a162adda6537 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 21:44:28 +0100 Subject: [PATCH 30/71] teleporters --- examples/the-dungeon-puzzlers-lament/build.rs | 3 ++ .../src/game/simulation/entity.rs | 50 +++++++++++++++---- .../the-dungeon-puzzlers-lament/src/sfx.rs | 2 + 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index 184c26ef..6ff0d31c 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -121,6 +121,7 @@ enum Entity { Ice, MovableBlock, Glove, + Teleporter, } impl FromStr for Entity { @@ -147,6 +148,7 @@ impl FromStr for Entity { "ICE" => Ice, "BLOCK" => MovableBlock, "GLOVE" => Glove, + "TELEPORTER" => Teleporter, _ => return Err(()), }) } @@ -174,6 +176,7 @@ impl quote::ToTokens for Entity { Ice => quote!(Item::Ice), MovableBlock => quote!(Item::MovableBlock), Glove => quote!(Item::Glove), + Teleporter => quote!(Item::Teleporter), }) } } diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 35835401..48a7208c 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -44,6 +44,21 @@ impl ActionResult { } } +fn remove_move_animation_for_entity( + animations: &mut Vec, + entity_key: EntityKey, +) { + if let Some(existing_animation) = animations.iter().position(|x| { + if let AnimationInstruction::Move(entity, _, _) = x { + *entity == entity_key + } else { + false + } + }) { + animations.swap_remove(existing_animation); + } +} + struct HasMoved(bool); struct WantsToMoveAgain(bool); @@ -338,17 +353,32 @@ impl EntityMap { break; } OverlapResolution::MoveAgain => { - if let Some(existing_animation) = animations.iter().position(|x| { - if let AnimationInstruction::Move(entity, _, _) = x { - *entity == entity_to_update_key - } else { - false - } - }) { - animations.swap_remove(existing_animation); - } + remove_move_animation_for_entity(animations, entity_to_update_key); should_move_again = true; } + OverlapResolution::Teleport => { + // find other teleporter + let other_teleporter = self.map.iter().find(|(entity_key, entity)| { + *entity_key != other_entity_key + && matches!(entity.entity, EntityType::Teleporter) + }); + + if let Some((_other_teleporter_key, other_teleporter)) = other_teleporter { + let location_to_teleport_to = other_teleporter.location; + if self.whats_at(location_to_teleport_to).count() != 0 { + //ok, we can teleport + remove_move_animation_for_entity(animations, entity_to_update_key); + animations.push(AnimationInstruction::Move( + entity_to_update_key, + location_to_teleport_to, + Some(SoundEffect::TeleportEffect), + )); + if let Some(entity) = self.map.get_mut(entity_to_update_key) { + entity.location = location_to_teleport_to; + } + } + } + } } } ( @@ -440,6 +470,7 @@ enum OverlapResolution { ToggleSystem(SwitchSystem), Die, MoveAgain, + Teleport, } fn resolve_spikes(switable: &Switchable) -> OverlapResolution { @@ -461,6 +492,7 @@ fn resolve_overlap(me: &Entity, other: &Entity) -> OverlapResolution { (_, EntityType::Switch(switch)) => OverlapResolution::ToggleSystem(switch.system), (_, EntityType::Enemy(_) | EntityType::Hero(_)) => OverlapResolution::Die, (_, EntityType::Ice) => OverlapResolution::MoveAgain, + (_, EntityType::Teleporter) => OverlapResolution::Teleport, _ => OverlapResolution::CoExist, } diff --git a/examples/the-dungeon-puzzlers-lament/src/sfx.rs b/examples/the-dungeon-puzzlers-lament/src/sfx.rs index b4b9cd18..47c1c1ea 100644 --- a/examples/the-dungeon-puzzlers-lament/src/sfx.rs +++ b/examples/the-dungeon-puzzlers-lament/src/sfx.rs @@ -74,6 +74,7 @@ impl<'a> Sfx<'a> { SoundEffect::SwordDrop => {} SoundEffect::SwitchedDoorToggle => {} SoundEffect::SpikesToggle => {} + SoundEffect::TeleportEffect => {} } } } @@ -94,4 +95,5 @@ pub enum SoundEffect { SwitchedDoorToggle, SpikesToggle, WallHit, + TeleportEffect, } From 712301bd2e4f9c9b077481fd17006caf915bedcb Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 21:44:36 +0100 Subject: [PATCH 31/71] teleporter level --- .../maps/levels/teleporter_1.tmx | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_1.tmx diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_1.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_1.tmx new file mode 100644 index 00000000..4f9c4457 --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_1.tmx @@ -0,0 +1,34 @@ + + + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0, +0,1,4,5,4,3,7,2,8,9,0, +0,37,11,17,13,16,13,12,17,38,0, +0,19,21,22,20,26,26,20,25,27,0, +0,0,0,1,7,3,3,9,0,0,0, +0,0,1,1073741852,13,16,17,3221225500,9,0,0, +0,0,37,13,11,12,14,13,18,0,0, +0,0,19,21,28,16,2147483676,25,27,0,0, +0,0,0,0,19,25,27,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + + + + From 70cbc7a608798ea36bb2c0c5b6b2cf7c12746e61 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 21:45:07 +0100 Subject: [PATCH 32/71] ignore tiled session --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1910c368..2252919b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ target /out template/Cargo.lock -agb*/Cargo.lock \ No newline at end of file +agb*/Cargo.lock +*.tiled-session \ No newline at end of file From 657637aa8eccac45a2053408c29555d0adb62a6d Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 21:45:24 +0100 Subject: [PATCH 33/71] Make just rocks more interesting --- .../maps/levels/just_rocks.tmx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx index 753a283c..d38c55cf 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx @@ -10,13 +10,13 @@ 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, -0,1,6,3,5,4,5,1073741872,7,9,0, -0,10,15,17,13,15,11,1073741863,16,38,0, -0,46,15,12,17,15,13,15,15,47,0, -0,46,14,17,12,13,17,11,17,18,0, -0,46,13,11,11,17,12,16,15,47,0, -0,46,12,14,17,13,14,11,11,38,0, -0,19,22,20,22,23,26,25,24,27,0, +0,0,1,3,5,4,5,9,0,0,0, +0,0,46,17,13,15,11,3221225500,9,0,0, +0,1,1073741852,12,17,15,13,15,3221225500,9,0, +0,10,12,17,12,13,17,11,17,18,0, +0,19,20,28,11,17,12,16,15,47,0, +0,0,0,46,15,13,14,2147483676,21,27,0, +0,0,0,19,21,23,26,27,0,0,0, 0,0,0,0,0,0,0,0,0,0,0 From 8cb4f0c40f21fe17fc7e7158ef3ed132aa75f155 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 21:47:25 +0100 Subject: [PATCH 34/71] Make the reason the solution works not the wall --- .../the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx index d38c55cf..3798b556 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx @@ -13,9 +13,9 @@ 0,0,1,3,5,4,5,9,0,0,0, 0,0,46,17,13,15,11,3221225500,9,0,0, 0,1,1073741852,12,17,15,13,15,3221225500,9,0, -0,10,12,17,12,13,17,11,17,18,0, -0,19,20,28,11,17,12,16,15,47,0, -0,0,0,46,15,13,14,2147483676,21,27,0, +0,10,13,13,13,15,17,11,17,18,0, +0,10,14,13,11,15,12,16,15,47,0, +0,19,20,28,17,16,14,2147483676,21,27,0, 0,0,0,19,21,23,26,27,0,0,0, 0,0,0,0,0,0,0,0,0,0,0 From da89a8a6cb50dfe3e19e246e368468749c38f974 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 21:52:58 +0100 Subject: [PATCH 35/71] add teleporter shadow --- examples/the-dungeon-puzzlers-lament/src/level.rs | 2 +- examples/the-dungeon-puzzlers-lament/src/resources.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/level.rs b/examples/the-dungeon-puzzlers-lament/src/level.rs index 50974ee3..f87f1723 100644 --- a/examples/the-dungeon-puzzlers-lament/src/level.rs +++ b/examples/the-dungeon-puzzlers-lament/src/level.rs @@ -44,7 +44,7 @@ impl Item { Item::Ice => resources::ICE, Item::MovableBlock => resources::ROCK_SHADOW, Item::Glove => resources::POW_GLOVE_SHADOW, - Item::Teleporter => resources::TELEPORTER, + Item::Teleporter => resources::TELEPORTER_SHADOW, } } diff --git a/examples/the-dungeon-puzzlers-lament/src/resources.rs b/examples/the-dungeon-puzzlers-lament/src/resources.rs index c5d0e645..69672669 100644 --- a/examples/the-dungeon-puzzlers-lament/src/resources.rs +++ b/examples/the-dungeon-puzzlers-lament/src/resources.rs @@ -55,6 +55,7 @@ named_tag!( POW_GLOVE, POW_GLOVE_SHADOW, TELEPORTER, + TELEPORTER_SHADOW, ] ); From b7c10742aff40986c5c2685103d5d56b6b4fc246 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 21:58:02 +0100 Subject: [PATCH 36/71] add teleporter to build.rs --- examples/the-dungeon-puzzlers-lament/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index 6ff0d31c..c34bf3da 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -35,6 +35,7 @@ const LEVEL_NAMES: &[&str] = &[ "block_push_2", "glove_key", "block_push_3", + "teleporter_1", ]; fn main() { From 7d907d014fa43432e224874e6180e2d42baccb6d Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 22:03:42 +0100 Subject: [PATCH 37/71] the check should be for one entity --- .../the-dungeon-puzzlers-lament/src/game/simulation/entity.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 48a7208c..3aa263ac 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -365,7 +365,7 @@ impl EntityMap { if let Some((_other_teleporter_key, other_teleporter)) = other_teleporter { let location_to_teleport_to = other_teleporter.location; - if self.whats_at(location_to_teleport_to).count() != 0 { + if self.whats_at(location_to_teleport_to).count() == 1 { //ok, we can teleport remove_move_animation_for_entity(animations, entity_to_update_key); animations.push(AnimationInstruction::Move( From a8e8f30f91798b3e85b14ad5c1e377f242e44de2 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 22:26:19 +0100 Subject: [PATCH 38/71] Remove invalid solution for glove_key --- .../the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx index f58e7713..c66b3ee2 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx @@ -1,5 +1,5 @@ - + @@ -33,5 +33,8 @@ + + + From 7af1b010067c53f8703af823d2d2af2d5ffc9a9a Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 22:26:39 +0100 Subject: [PATCH 39/71] Add a level where a squid teleports --- examples/the-dungeon-puzzlers-lament/build.rs | 1 + .../maps/levels/squid_teleport.tmx | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index c34bf3da..97d92c87 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -36,6 +36,7 @@ const LEVEL_NAMES: &[&str] = &[ "glove_key", "block_push_3", "teleporter_1", + "squid_teleport", ]; fn main() { diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx new file mode 100644 index 00000000..da6ca571 --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx @@ -0,0 +1,46 @@ + + + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0, +1,7,4,2,6,9,0,1,8,9,0, +10,15,11,17,15,18,0,46,11,18,0, +46,16,14,39,14,47,0,37,14,18,0, +46,11,13,1073741863,17,18,0,46,17,18,0, +10,16,17,11,2147483676,27,0,46,13,38,0, +19,28,14,14,47,0,0,19,22,27,0, +0,19,20,23,27,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + + + + + + + + + + + + + + + + From 36e912bcb086fec8334e1218ad15f93621e9143c Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 22:18:43 +0100 Subject: [PATCH 40/71] nothing should get killed from overlapping the hero --- .../the-dungeon-puzzlers-lament/src/game/simulation/entity.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 3aa263ac..71317592 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -490,7 +490,7 @@ fn resolve_overlap(me: &Entity, other: &Entity) -> OverlapResolution { (EntityType::MovableBlock, EntityType::Spikes(_)) => OverlapResolution::CoExist, (_, EntityType::Spikes(switch)) => resolve_spikes(switch), (_, EntityType::Switch(switch)) => OverlapResolution::ToggleSystem(switch.system), - (_, EntityType::Enemy(_) | EntityType::Hero(_)) => OverlapResolution::Die, + (_, EntityType::Enemy(_)) => OverlapResolution::Die, (_, EntityType::Ice) => OverlapResolution::MoveAgain, (_, EntityType::Teleporter) => OverlapResolution::Teleport, From f3d0757fa318d7227e8eda5f8705ef7bdd5857d7 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 22:27:49 +0100 Subject: [PATCH 41/71] squid hero phasing --- .../src/game/simulation/entity.rs | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 71317592..3a96d0de 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -143,6 +143,9 @@ impl EntityMap { let desired_location = entity_location + direction.into(); let surface = map.get(desired_location); + + let mut should_die_later = false; + let (can_move, explicit_stay_put, fake_out_effect) = if surface == MapElement::Wall { (false, true, None) } else { @@ -153,7 +156,9 @@ impl EntityMap { let move_attempt_resolutions: Vec<_> = self .whats_at(desired_location) .filter(|(k, _)| *k != entity_to_update_key) - .map(|(key, other_entity)| (key, resolve_move(entity_to_update, other_entity))) + .map(|(key, other_entity)| { + (key, resolve_move(entity_to_update, other_entity, direction)) + }) .collect(); for (other_entity_key, move_resolution) in move_attempt_resolutions { @@ -204,6 +209,9 @@ impl EntityMap { explicit_stay_put = true; } } + MoveAttemptResolution::DieLater => { + should_die_later = true; + } } } @@ -274,6 +282,10 @@ impl EntityMap { )); } + if should_die_later { + hero_has_died |= self.kill_entity(entity_to_update_key, animations); + } + ( HasMoved(can_move), ActionResult::new(hero_has_died, win_has_triggered), @@ -455,6 +467,7 @@ enum MoveAttemptResolution { Die, KillDie, CoExist, + DieLater, StayPut, AttemptPush, } @@ -498,9 +511,16 @@ fn resolve_overlap(me: &Entity, other: &Entity) -> OverlapResolution { } } -fn holding_attack_resolve(holding: Option<&EntityType>) -> MoveAttemptResolution { - match holding { - Some(&EntityType::Item(Item::Sword)) => MoveAttemptResolution::Kill, +fn holding_attack_resolve( + holding: Option<&EntityType>, + other: &Entity, + direction: Direction, +) -> MoveAttemptResolution { + match (holding, &other.entity) { + (Some(&EntityType::Item(Item::Sword)), _) => MoveAttemptResolution::Kill, + (_, EntityType::Enemy(Enemy::Squid(squid))) => { + hero_walk_into_squid_interaction(squid, direction) + } _ => MoveAttemptResolution::CoExist, } } @@ -549,10 +569,18 @@ fn switch_door_resolve(door: &Switchable) -> MoveAttemptResolution { } } -fn resolve_move(mover: &Entity, into: &Entity) -> MoveAttemptResolution { +fn hero_walk_into_squid_interaction(squid: &Squid, direction: Direction) -> MoveAttemptResolution { + if direction == -squid.direction { + MoveAttemptResolution::DieLater + } else { + MoveAttemptResolution::CoExist + } +} + +fn resolve_move(mover: &Entity, into: &Entity, direction: Direction) -> MoveAttemptResolution { match (&mover.entity, &into.entity) { (EntityType::Hero(hero), EntityType::Hero(_) | EntityType::Enemy(_)) => { - holding_attack_resolve(hero.holding.as_deref()) + holding_attack_resolve(hero.holding.as_deref(), into, direction) } (EntityType::Hero(hero), EntityType::Door) => holding_door_resolve(hero.holding.as_deref()), (EntityType::Enemy(Enemy::Squid(squid)), EntityType::Hero(_) | EntityType::Enemy(_)) => { From b78f7345b9b8495c00529f61853fa02e37121211 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 22:32:03 +0100 Subject: [PATCH 42/71] replace existing animation for pushed entity --- .../the-dungeon-puzzlers-lament/src/game/simulation/entity.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 3a96d0de..c45ca646 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -51,6 +51,8 @@ fn remove_move_animation_for_entity( if let Some(existing_animation) = animations.iter().position(|x| { if let AnimationInstruction::Move(entity, _, _) = x { *entity == entity_key + } else if let AnimationInstruction::FakeOutMove(entity, _, _, _) = x { + *entity == entity_key } else { false } @@ -188,6 +190,7 @@ impl EntityMap { MoveAttemptResolution::AttemptPush => { let depth = push_depth - 1; if depth >= 0 { + remove_move_animation_for_entity(animations, other_entity_key); let (can_move_result, action_result) = self.attempt_move_in_direction( map, animations, From be316a305b4d8e9effd6e470c0c99d6f27342af3 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 22:35:41 +0100 Subject: [PATCH 43/71] BAD CORWIN! --- .../maps/levels/squid_teleport.tmx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx index da6ca571..9c917b6b 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx @@ -14,9 +14,9 @@ 46,16,14,39,14,47,0,37,14,18,0, 46,11,13,1073741863,17,18,0,46,17,18,0, 10,16,17,11,2147483676,27,0,46,13,38,0, -19,28,14,14,47,0,0,19,22,27,0, -0,19,20,23,27,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0, +19,28,11,14,47,0,0,19,22,27,0, +0,37,15,2147483676,27,0,0,0,0,0,0, +0,19,25,27,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0 From 45059029fad117cf52deb8b928337ee9145b07d5 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 22:56:05 +0100 Subject: [PATCH 44/71] another teleporter level --- examples/the-dungeon-puzzlers-lament/build.rs | 1 + .../maps/levels/teleporter_2.tmx | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index 97d92c87..bb93eb7e 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -37,6 +37,7 @@ const LEVEL_NAMES: &[&str] = &[ "block_push_3", "teleporter_1", "squid_teleport", + "teleporter_2", ]; fn main() { diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx new file mode 100644 index 00000000..3f19019e --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx @@ -0,0 +1,43 @@ + + + + + + + + + + +0,0,1,8,7,7,5,2,9,0,0, +1,6,1073741852,15,16,15,13,14,3221225500,2,9, +46,15,11,17,17,12,11,14,14,14,47, +46,13,14,13,14,13,12,17,15,16,47, +46,15,16,17,13,12,17,16,16,13,47, +19,28,13,12,17,12,11,16,13,11,38, +0,19,25,28,15,11,16,12,2147483676,24,27, +0,0,0,19,28,17,2147483676,22,27,0,0, +0,0,0,0,46,15,38,0,0,0,0, +0,0,0,0,19,23,27,0,0,0,0 + + + + + + + + + + + + + + + + + + + + + + + From 3c08880b5dcdf9ad3bfe3af01c245e488588e026 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 22:56:44 +0100 Subject: [PATCH 45/71] add a slime + teleport level --- examples/the-dungeon-puzzlers-lament/build.rs | 1 + .../maps/levels/slime_teleporter.tmx | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index bb93eb7e..af1d51a7 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -38,6 +38,7 @@ const LEVEL_NAMES: &[&str] = &[ "teleporter_1", "squid_teleport", "teleporter_2", + "slime_teleporter", ]; fn main() { diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx new file mode 100644 index 00000000..ab902972 --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx @@ -0,0 +1,43 @@ + + + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0, +0,1,8,5,6,4,3,9,0,0,0, +0,37,17,16,14,15,15,3221225500,8,9,0, +1,1073741852,16,17,15,12,14,17,16,38,0, +37,16,11,39,14,39,15,17,11,18,0, +32,13,16,1073741863,12,1073741863,15,14,12,38,0, +2147483689,2147483688,17,29,2147483677,15,15,11,12,18,0, +3221225513,3221225512,11,11,17,13,11,11,13,47,0, +1073741856,11,13,11,11,16,14,15,2147483676,27,0, +19,22,21,20,22,26,22,22,27,0,0 + + + + + + + + + + + + + + + + + + + + + + + From 32eee32fb1ebbad847b1f37c21438ef5064efefd Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 22:58:50 +0100 Subject: [PATCH 46/71] make teleporter_2 better --- .../maps/levels/teleporter_2.tmx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx index 3f19019e..73ec616b 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx @@ -1,8 +1,8 @@ - + - + @@ -30,7 +30,7 @@ - + @@ -39,5 +39,8 @@ + + + From f357787711aa0c278ed91081ca063c30a70ba87e Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 23:08:17 +0100 Subject: [PATCH 47/71] Neaten up the slime_teleporter a little --- .../maps/levels/slime_teleporter.tmx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx index ab902972..9ef70e31 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx @@ -9,15 +9,15 @@ 0,0,0,0,0,0,0,0,0,0,0, -0,1,8,5,6,4,3,9,0,0,0, -0,37,17,16,14,15,15,3221225500,8,9,0, -1,1073741852,16,17,15,12,14,17,16,38,0, -37,16,11,39,14,39,15,17,11,18,0, -32,13,16,1073741863,12,1073741863,15,14,12,38,0, -2147483689,2147483688,17,29,2147483677,15,15,11,12,18,0, -3221225513,3221225512,11,11,17,13,11,11,13,47,0, -1073741856,11,13,11,11,16,14,15,2147483676,27,0, -19,22,21,20,22,26,22,22,27,0,0 +0,0,0,1,6,4,3,9,0,0,0, +0,0,1,1073741852,14,15,15,3221225500,8,9,0, +0,1,1073741852,17,15,12,14,17,16,38,0, +0,10,11,39,14,39,15,17,11,18,0, +0,37,16,1073741863,12,1073741863,15,14,12,38,0, +0,46,17,29,2147483677,15,15,11,12,18,0, +0,19,20,28,17,13,11,11,13,47,0, +0,0,0,19,24,28,14,15,2147483676,27,0, +0,0,0,0,0,19,22,22,27,0,0 From 50495d88b7ba744d26c7bc14c08450b14dceee38 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 23:08:24 +0100 Subject: [PATCH 48/71] remove cheese --- .../maps/levels/teleporter_2.tmx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx index 73ec616b..c8cae9cc 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx @@ -8,13 +8,13 @@ -0,0,1,8,7,7,5,2,9,0,0, -1,6,1073741852,15,16,15,13,14,3221225500,2,9, -46,15,11,17,17,12,11,14,14,14,47, -46,13,14,13,14,13,12,17,15,16,47, -46,15,16,17,13,12,17,16,16,13,47, -19,28,13,12,17,12,11,16,13,11,38, -0,19,25,28,15,11,16,12,2147483676,24,27, +0,0,1,8,7,7,5,9,0,0,0, +1,6,1073741852,15,16,15,13,3221225500,9,0,0, +46,15,11,17,17,12,11,14,47,0,0, +46,13,14,13,14,13,12,2147483676,27,0,0, +46,15,16,17,13,12,17,3221225500,8,9,0, +19,28,13,12,17,12,11,16,13,47,0, +0,19,25,28,15,11,16,12,2147483676,27,0, 0,0,0,19,28,17,2147483676,22,27,0,0, 0,0,0,0,46,15,38,0,0,0,0, 0,0,0,0,19,23,27,0,0,0,0 From 0b24fdebd058b743db7083e54f0094b12d595949 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 23:09:56 +0100 Subject: [PATCH 49/71] teleporters are on the ground --- .../the-dungeon-puzzlers-lament/src/game/simulation/animation.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs index 1fb03bbe..316804f4 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs @@ -127,6 +127,7 @@ impl RenderCache { | Item::SpikesDown | Item::SpikesUp | Item::Ice + | Item::Teleporter ) { score += 100000; } From 36e8fca49a384a8c02f5c5e670c7acf23799ce2c Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 29 Aug 2023 23:36:30 +0100 Subject: [PATCH 50/71] really bad ice level --- .../maps/levels/another_ice.tmx | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/another_ice.tmx diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice.tmx new file mode 100644 index 00000000..2487605d --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice.tmx @@ -0,0 +1,46 @@ + + + + + + + + + + +0,0,0,1,2,9,0,1,8,6,9, +0,0,0,10,17,18,1,1073741852,17,12,18, +0,1,5,1073741852,17,3221225500,1073741852,14,13,15,47, +0,46,16,17,15,12,16,12,2147483676,26,27, +0,10,12,3221225505,1073741857,3221225505,1073741857,16,18,0,0, +0,37,15,1073741863,2147483689,41,1073741863,13,3221225500,9,0, +0,46,13,17,1073741864,3221225512,14,11,15,18,0, +0,19,28,11,17,16,12,13,11,47,0, +0,0,19,20,22,20,28,15,14,18,0, +0,0,0,0,0,0,19,26,23,27,0 + + + + + + + + + + + + + + + + + + + + + + + + + + From c784cd759c2a459271dba96223114b65ae7afa8c Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 23:52:35 +0100 Subject: [PATCH 51/71] Level with multiple ice --- examples/the-dungeon-puzzlers-lament/build.rs | 1 + .../maps/levels/ice_ice.tmx | 49 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index af1d51a7..a83358a3 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -32,6 +32,7 @@ const LEVEL_NAMES: &[&str] = &[ "block_push_1", "just_rocks", "squid_rock", + "ice_ice", "block_push_2", "glove_key", "block_push_3", diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx new file mode 100644 index 00000000..7ff04986 --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx @@ -0,0 +1,49 @@ + + + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,1,2,4,8,6,5,4,6,9,0, +0,10,16,13,16,11,17,14,15,47,0, +0,46,13,17,15,17,11,11,11,18,0, +0,37,13,14,12,11,15,11,11,18,0, +0,10,17,14,11,15,14,17,15,18,0, +0,10,16,13,11,17,16,14,11,18,0, +0,19,21,21,23,28,16,2147483676,26,27,0, +0,0,0,0,0,19,26,27,0,0,0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 7f10cdb86939dfcf4c41b769b1b6c99ad4c7a891 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 23:54:58 +0100 Subject: [PATCH 52/71] Less square --- .../the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx index 7ff04986..332ecc02 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx @@ -10,10 +10,10 @@ 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, -0,1,2,4,8,6,5,4,6,9,0, -0,10,16,13,16,11,17,14,15,47,0, -0,46,13,17,15,17,11,11,11,18,0, -0,37,13,14,12,11,15,11,11,18,0, +0,1,6,9,0,0,0,1,6,9,0, +0,10,16,3221225500,9,0,1,1073741852,15,47,0, +0,46,13,17,47,0,37,11,11,18,0, +0,37,13,14,3221225500,7,1073741852,11,11,18,0, 0,10,17,14,11,15,14,17,15,18,0, 0,10,16,13,11,17,16,14,11,18,0, 0,19,21,21,23,28,16,2147483676,26,27,0, From 45a9dbfeac84426d59068c95e448335fc71bd340 Mon Sep 17 00:00:00 2001 From: Corwin Date: Wed, 30 Aug 2023 00:08:29 +0100 Subject: [PATCH 53/71] fix block pushing on ice --- .../src/game/simulation/entity.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index c45ca646..de128708 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -734,8 +734,13 @@ impl Entity { fn push_depth(&self) -> Option { if matches!(self.holding(), Some(&EntityType::Item(Item::Glove))) { Some(i32::MAX) - } else { + } else if matches!( + self.entity, + EntityType::Hero(_) | EntityType::Enemy(Enemy::Squid(_)) + ) { Some(1) + } else { + None } } From a0b87d50c69ca1693a2f2a9b7b8b4654efcc74e2 Mon Sep 17 00:00:00 2001 From: Corwin Date: Wed, 30 Aug 2023 00:08:40 +0100 Subject: [PATCH 54/71] I have no idea what I have just made --- .../maps/levels/another_ice_2.tmx | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx new file mode 100644 index 00000000..b4f61d74 --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx @@ -0,0 +1,107 @@ + + + + + + To walk to your own death is stupid. +To slide to your own death is fun, until the death part. + + + + +1,8,2,7,8,8,3,7,4,2,9, +46,17,13,17,13,12,12,15,11,16,38, +10,14,12,11,16,15,16,13,14,17,47, +37,13,16,15,16,13,16,14,16,13,38, +46,17,17,17,17,17,11,17,15,11,38, +46,17,13,12,17,15,15,16,17,15,38, +10,15,17,11,15,12,11,12,17,16,18, +10,13,13,17,15,17,16,13,2147483676,20,27, +19,28,15,13,17,12,2147483676,22,27,0,0, +0,19,24,20,25,20,27,0,0,0,0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From cfa846ddd3226225ae8b24db175530878eef347b Mon Sep 17 00:00:00 2001 From: Corwin Date: Wed, 30 Aug 2023 00:08:53 +0100 Subject: [PATCH 55/71] add both levels --- examples/the-dungeon-puzzlers-lament/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index a83358a3..d00d5b60 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -40,6 +40,8 @@ const LEVEL_NAMES: &[&str] = &[ "squid_teleport", "teleporter_2", "slime_teleporter", + "another_ice", + "another_ice_2", ]; fn main() { From c44b131d73e14d0614c7e7e09e5529a3e719f20a Mon Sep 17 00:00:00 2001 From: Corwin Date: Wed, 30 Aug 2023 00:43:39 +0100 Subject: [PATCH 56/71] another not so good ice level --- .../maps/levels/another_ice_3.tmx | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx new file mode 100644 index 00000000..db0915aa --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx @@ -0,0 +1,50 @@ + + + + + + To walk to your own death is stupid. +To slide to your own death is fun, until the death part. + + + + +1,8,2,7,8,8,3,9,1,2,9, +46,2147483676,22,23,28,12,12,38,19,26,27, +19,27,1,9,46,15,16,38,1,5,9, +1,8,32,2147483680,1073741852,13,16,18,37,13,38, +46,17,3221225504,1073741856,17,17,17,38,19,23,27, +19,22,27,19,22,28,16,18,1,7,9, +0,0,0,1,2,32,15,18,19,26,27, +1,4,7,1073741852,15,1073741863,16,3221225500,5,3,9, +37,13,16,13,17,11,13,12,12,11,38, +19,22,22,20,25,22,26,25,26,24,27 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 20794d152caa082d58816ba4cc80e2cf4f864778 Mon Sep 17 00:00:00 2001 From: Corwin Date: Wed, 30 Aug 2023 00:49:46 +0100 Subject: [PATCH 57/71] a more basic ice level --- .../maps/levels/another_ice_4.tmx | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx new file mode 100644 index 00000000..4dfdc38c --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx @@ -0,0 +1,40 @@ + + + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0, +0,0,1,3,2,9,0,0,0,0,0, +0,0,37,11,11,3221225500,3,3,9,0,0, +0,0,10,15,13,14,15,14,47,0,0, +0,0,37,16,14,17,14,11,18,0,0, +0,0,10,17,13,17,11,12,38,0,0, +0,0,46,12,13,17,13,13,18,0,0, +0,0,19,28,15,14,12,2147483676,27,0,0, +0,0,0,19,21,20,25,27,0,0,0, +0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + + + + + + + + + + From b29fc6bb6c5cc1d9ad717bab420cc73c044aacf3 Mon Sep 17 00:00:00 2001 From: Corwin Date: Wed, 30 Aug 2023 00:53:31 +0100 Subject: [PATCH 58/71] update laments --- .../the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx | 3 +-- .../the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx index b4f61d74..79c166ef 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx @@ -3,8 +3,7 @@ - To walk to your own death is stupid. -To slide to your own death is fun, until the death part. + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx index db0915aa..04f0ee15 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx @@ -3,8 +3,7 @@ - To walk to your own death is stupid. -To slide to your own death is fun, until the death part. + From c142184bc0222a92ae536c8b971a65e64bf46fe1 Mon Sep 17 00:00:00 2001 From: Corwin Date: Wed, 30 Aug 2023 00:54:00 +0100 Subject: [PATCH 59/71] add ice levels --- examples/the-dungeon-puzzlers-lament/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index d00d5b60..edeb23c1 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -42,6 +42,8 @@ const LEVEL_NAMES: &[&str] = &[ "slime_teleporter", "another_ice", "another_ice_2", + "another_ice_3", + "another_ice_4", ]; fn main() { From 025e76b8bdc4d751832920b266108fb0b7ce1596 Mon Sep 17 00:00:00 2001 From: Corwin Date: Wed, 30 Aug 2023 00:55:25 +0100 Subject: [PATCH 60/71] you can only turn around if this is your first movement --- .../src/game/simulation/entity.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index de128708..d4ef4f48 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -418,6 +418,8 @@ impl EntityMap { }) .collect::>(); + let mut first_loop = true; + while !entities_to_try_update.is_empty() { let mut entities_that_have_moved = Vec::new(); @@ -427,7 +429,7 @@ impl EntityMap { &mut animations, entity_to_update_key, direction, - true, + first_loop, self.map .get(entity_to_update_key) .and_then(|e| e.push_depth()) @@ -450,6 +452,8 @@ impl EntityMap { hero_has_died |= action_result.hero_has_died; win_has_triggered |= action_result.win_has_triggered; } + + first_loop = false; } ( From 1bcbeb056e21bd7228e093348aa2536a9eef7ed5 Mon Sep 17 00:00:00 2001 From: Corwin Date: Wed, 30 Aug 2023 17:43:24 +0100 Subject: [PATCH 61/71] more advanced movement system --- .../src/game/simulation/animation.rs | 171 +++++++++--------- .../src/game/simulation/entity.rs | 21 --- 2 files changed, 84 insertions(+), 108 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs index 316804f4..e6df07e6 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/animation.rs @@ -6,8 +6,9 @@ use core::ops::{Deref, DerefMut}; use agb::{ display::object::{OamIterator, ObjectUnmanaged, SpriteLoader}, - fixnum::{num, Num, Vector2D}, + fixnum::{Num, Vector2D}, }; +use alloc::vec; use alloc::vec::Vec; use slotmap::SecondaryMap; @@ -26,11 +27,15 @@ struct AnimationEntity { attached: Option<(Item, Num)>, } +struct MovePoints { + sound_effect: Option, + points: Vec>>, +} + #[derive(Default)] struct ToPlay { - moves: Vec, + move_points: SecondaryMap, attach_progress: Vec, - fakeout: Vec, detatch: Vec, attach: Vec, change: Vec, @@ -50,11 +55,44 @@ impl ToPlay { ) { match instruction { AnimationInstruction::Move(e, p, s) => { - self.moves.push(Move(e, convert_to_real_space(p), s)); + let move_points = + self.move_points + .entry(e) + .unwrap() + .or_insert_with(|| MovePoints { + sound_effect: s, + points: map + .get(e) + .map(|x| vec![x.start_position]) + .unwrap_or_default(), + }); + move_points.points.push(convert_to_real_space(p)); + if let Some(sound_effect) = s { + move_points.sound_effect.get_or_insert(sound_effect); + } } - AnimationInstruction::FakeOutMove(e, d, p, s) => { - self.fakeout - .push(FakeOutMove(e, d, p.map(convert_to_real_space), s)) + AnimationInstruction::FakeOutMove(e, d, s) => { + let move_points = + self.move_points + .entry(e) + .unwrap() + .or_insert_with(|| MovePoints { + sound_effect: s, + points: map + .get(e) + .map(|x| vec![x.start_position]) + .unwrap_or_default(), + }); + + if let Some(sound_effect) = s { + move_points.sound_effect.get_or_insert(sound_effect); + } + + let &most_recent_position = move_points.points.last().unwrap(); + move_points + .points + .push(most_recent_position + convert_to_real_space(d.into()) / 2); + move_points.points.push(most_recent_position); } AnimationInstruction::Detatch(e, nk, s) => self.detatch.push(Detatch(e, nk, s)), AnimationInstruction::Attach(e, o, s) => { @@ -157,12 +195,6 @@ impl Map { entity.start_position = destination; } } - - fn set_entity_to_start_location(&mut self, entity: EntityKey) { - if let Some(entity) = self.map.get_mut(entity) { - entity.rendered_position = entity.start_position; - } - } } impl Deref for Map { @@ -179,6 +211,31 @@ impl DerefMut for Map { } } +fn lerp_points, Output = N> + core::ops::Add>( + points: &[N], + t: Num, +) -> N { + let number_of_points = points.len() as i32; + let slope_for_spike_fn = number_of_points - 1; + + let relevant_points_pair_idx = (t * slope_for_spike_fn).floor(); + + let spike_function_for_first = t * -slope_for_spike_fn + relevant_points_pair_idx + 1; + let spike_function_for_second = t * slope_for_spike_fn - relevant_points_pair_idx; + let first_point_idx = relevant_points_pair_idx as usize; + + let &first = points + .get(first_point_idx) + .expect("Maybe input to lerp is out of range?"); + let second = points.get(first_point_idx + 1); + + if let Some(&second) = second { + first * spike_function_for_first + second * spike_function_for_second + } else { + first + } +} + impl Animation { pub fn populate(&mut self, instruction: AnimationInstruction, sfx: &mut Sfx) { self.to_play.populate(instruction, &mut self.map, sfx); @@ -243,30 +300,16 @@ impl Animation { } pub fn update(&mut self, sfx: &mut Sfx) -> bool { - if !self.to_play.moves.is_empty() - || !self.to_play.fakeout.is_empty() - || !self.to_play.attach_progress.is_empty() - { + if !self.to_play.move_points.is_empty() || !self.to_play.attach_progress.is_empty() { if self.time >= 1.into() { // finalise animations - for m in self.to_play.moves.drain(0..) { + for m in self.to_play.move_points.drain() { let entity = m.0; - let destination = m.1; + let &destination = m.1.points.last().unwrap(); self.map.set_entity_start_location(entity, destination); } - for m in self.to_play.fakeout.drain(0..) { - let entity = m.0; - let destination = m.2; - - if let Some(destination) = destination { - self.map.set_entity_start_location(entity, destination); - } else { - self.map.set_entity_to_start_location(entity); - } - } - for m in self.to_play.attach_progress.drain(0..) { if let Some(ease) = self .map @@ -279,49 +322,11 @@ impl Animation { } } else { // play moves and fakeouts - for m in self.to_play.moves.iter_mut() { - let entity = m.0; - let destination = m.1; - - sfx.play_sound_effect(m.2.take()); + for (entity, move_points) in self.to_play.move_points.iter_mut() { + sfx.play_sound_effect(move_points.sound_effect.take()); if let Some(entity) = self.map.get_mut(entity) { - let location = entity.start_position * (Num::::new(1) - self.ease) - + destination * self.ease; - - entity.rendered_position = location; - } - } - - for m in self.to_play.fakeout.iter_mut() { - let entity = m.0; - if let Some(entity) = self.map.get_mut(entity) { - let direction = m.1; - let destination = m.2.unwrap_or(entity.start_position); - let direction = convert_to_real_space(direction.into()); - - sfx.play_sound_effect(m.3.take()); - - let go_to = destination + direction / 2; - - let mix = (self.ease * 2 - 1).abs(); - let start_position_mix = if self.ease <= num!(0.5) { - mix - } else { - 0.into() - }; - - let end_position_mix = if self.ease >= num!(0.5) { - mix - } else { - 0.into() - }; - - let intermediate_position_mix = -mix + 1; - - let location = entity.start_position * start_position_mix - + go_to * intermediate_position_mix - + destination * end_position_mix; + let location = lerp_points(&move_points.points, self.ease); entity.rendered_position = location; } @@ -363,9 +368,13 @@ impl Animation { attached: None, }, ); - self.to_play - .moves - .push(Move(new_key, destination_position, None)); + self.to_play.move_points.insert( + new_key, + MovePoints { + sound_effect: None, + points: vec![position, destination_position], + }, + ); } } } else if !self.to_play.attach.is_empty() { @@ -414,13 +423,6 @@ impl Animation { } } -struct Move(EntityKey, Vector2D>, Option); -struct FakeOutMove( - EntityKey, - Direction, - Option>>, - Option, -); struct Detatch(EntityKey, EntityKey, Option); struct Attach(EntityKey, Item, EntityKey, Option); struct AttachProgress(EntityKey, Option); @@ -431,12 +433,7 @@ struct Change(EntityKey, Item, Option); pub enum AnimationInstruction { Add(EntityKey, Item, Vector2D, Option), Move(EntityKey, Vector2D, Option), - FakeOutMove( - EntityKey, - Direction, - Option>, - Option, - ), + FakeOutMove(EntityKey, Direction, Option), Detatch(EntityKey, EntityKey, Option), Attach(EntityKey, EntityKey, Option), Change(EntityKey, Item, Option), diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index d4ef4f48..cf173c29 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -44,23 +44,6 @@ impl ActionResult { } } -fn remove_move_animation_for_entity( - animations: &mut Vec, - entity_key: EntityKey, -) { - if let Some(existing_animation) = animations.iter().position(|x| { - if let AnimationInstruction::Move(entity, _, _) = x { - *entity == entity_key - } else if let AnimationInstruction::FakeOutMove(entity, _, _, _) = x { - *entity == entity_key - } else { - false - } - }) { - animations.swap_remove(existing_animation); - } -} - struct HasMoved(bool); struct WantsToMoveAgain(bool); @@ -190,7 +173,6 @@ impl EntityMap { MoveAttemptResolution::AttemptPush => { let depth = push_depth - 1; if depth >= 0 { - remove_move_animation_for_entity(animations, other_entity_key); let (can_move_result, action_result) = self.attempt_move_in_direction( map, animations, @@ -270,7 +252,6 @@ impl EntityMap { animations.push(AnimationInstruction::FakeOutMove( entity_to_update_key, direction, - self.map.get(entity_to_update_key).map(|e| e.location), if explicit_stay_put { self.map .get(entity_to_update_key) @@ -368,7 +349,6 @@ impl EntityMap { break; } OverlapResolution::MoveAgain => { - remove_move_animation_for_entity(animations, entity_to_update_key); should_move_again = true; } OverlapResolution::Teleport => { @@ -382,7 +362,6 @@ impl EntityMap { let location_to_teleport_to = other_teleporter.location; if self.whats_at(location_to_teleport_to).count() == 1 { //ok, we can teleport - remove_move_animation_for_entity(animations, entity_to_update_key); animations.push(AnimationInstruction::Move( entity_to_update_key, location_to_teleport_to, From 73a0b482a5481f7375858d4656db1112768b78a2 Mon Sep 17 00:00:00 2001 From: Corwin Date: Wed, 30 Aug 2023 19:55:43 +0100 Subject: [PATCH 62/71] fix unintended solution --- .../maps/levels/another_ice_4.tmx | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx index 4dfdc38c..98140e23 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx @@ -1,39 +1,42 @@ - + - + -0,0,0,0,0,0,0,0,0,0,0, -0,0,1,3,2,9,0,0,0,0,0, -0,0,37,11,11,3221225500,3,3,9,0,0, -0,0,10,15,13,14,15,14,47,0,0, +0,0,0,1,7,9,0,0,0,0,0, +0,0,1,1073741852,13,3221225500,8,9,0,0,0, +0,0,37,12,17,16,15,3221225500,9,0,0, +0,0,10,15,11,16,13,15,47,0,0, 0,0,37,16,14,17,14,11,18,0,0, 0,0,10,17,13,17,11,12,38,0,0, -0,0,46,12,13,17,13,13,18,0,0, -0,0,19,28,15,14,12,2147483676,27,0,0, -0,0,0,19,21,20,25,27,0,0,0, -0,0,0,0,0,0,0,0,0,0,0 +0,0,46,17,16,12,13,11,47,0,0, +0,0,19,28,16,15,17,14,38,0,0, +0,0,0,19,22,28,11,2147483676,27,0,0, +0,0,0,0,0,19,24,27,0,0,0 - + - + - + - + - + + + + From a97248cd68abe6abd5dccc3ce7cbdf68fe9b1de7 Mon Sep 17 00:00:00 2001 From: Corwin Date: Fri, 1 Sep 2023 00:42:43 +0100 Subject: [PATCH 63/71] add hole and rotating enemy --- examples/the-dungeon-puzzlers-lament/build.rs | 17 ++ .../gfx/sprites16x16.aseprite | Bin 15452 -> 15618 bytes .../maps/levels/hole_introduction.tmx | 34 +++ .../maps/levels/rotator_1.tmx | 43 ++++ .../src/game/simulation/entity.rs | 210 ++++++++++++++---- .../the-dungeon-puzzlers-lament/src/level.rs | 20 ++ .../src/resources.rs | 5 + 7 files changed, 286 insertions(+), 43 deletions(-) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/hole_introduction.tmx create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/rotator_1.tmx diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index edeb23c1..805a7839 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -44,6 +44,8 @@ const LEVEL_NAMES: &[&str] = &[ "another_ice_2", "another_ice_3", "another_ice_4", + "hole_introduction", + "rotator_1", ]; fn main() { @@ -131,6 +133,11 @@ enum Entity { MovableBlock, Glove, Teleporter, + Hole, + RotatorUp, + RotatorDown, + RotatorLeft, + RotatorRight, } impl FromStr for Entity { @@ -158,6 +165,11 @@ impl FromStr for Entity { "BLOCK" => MovableBlock, "GLOVE" => Glove, "TELEPORTER" => Teleporter, + "HOLE" => Hole, + "ROTATOR_LEFT" => RotatorLeft, + "ROTATOR_RIGHT" => RotatorRight, + "ROTATOR_UP" => RotatorUp, + "ROTATOR_DOWN" => RotatorDown, _ => return Err(()), }) } @@ -186,6 +198,11 @@ impl quote::ToTokens for Entity { MovableBlock => quote!(Item::MovableBlock), Glove => quote!(Item::Glove), Teleporter => quote!(Item::Teleporter), + Hole => quote!(Item::Hole), + RotatorUp => quote!(Item::RotatorUp), + RotatorDown => quote!(Item::RotatorDown), + RotatorLeft => quote!(Item::RotatorLeft), + RotatorRight => quote!(Item::RotatorRight), }) } } diff --git a/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite b/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite index 304e937bf7f5136dede2f7390687a95f4630557e..0cfa162ed2a1730b1d1332280a669b8e8d666cb7 100644 GIT binary patch delta 674 zcmcap(Nx9GWXr(tV5$2=_DWuMHU@@YA2}FO7#J8hCiZ@u{EjV#-HC;PK|(=wb1UOY z=6WXvC!ib>U}5m^_i=S*a7GdXGI<$-{6ic={Db0yJl#D)To_zX<+~uyTI~9mo6+kQ|hW|`J3Jmyx z4y%}xoZ!%)ZoT(^vw_ik#(tYkJLaq~kvM!sVe`eOg)fh`pS;?>Zn{YAjxYQzcbB|c z8fFn}-S=T;tG|7f#e(I!G4GD0sp;7gFN>l`E)B>s_OGT6P#fbJDo z9apk-$CZVvSyvuz)ij(Q^8FF>mM&%iHlU{~7KewUx!Ikto8eBj7rAoi%7V)~&aj?5 TY_RoiH=jqZHqczrMHPzyz)Z7^ delta 506 zcmZpwx>La(W5dAkV5!qY_DWt;b_RxDA2k?K7#J8dCiZ@0-@wekAfceJ`61&<=6XJ$ osDc6$kOYGNbm!FrZ5=@C8G!Z=r1cEWRIq+>9b?R988#tP0EntQJOBUy diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/hole_introduction.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/hole_introduction.tmx new file mode 100644 index 00000000..8da8ed63 --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/hole_introduction.tmx @@ -0,0 +1,34 @@ + + + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,1,6,5,2,2,6,4,8,9,0, +0,10,17,17,12,15,13,17,17,38,0, +0,19,20,20,20,25,20,22,21,27,0, +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_1.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_1.tmx new file mode 100644 index 00000000..3847f552 --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_1.tmx @@ -0,0 +1,43 @@ + + + + + + + + + + +1,6,7,7,4,5,3,2,4,7,9, +37,12,14,13,12,15,12,16,14,13,47, +19,22,26,26,26,25,23,22,24,26,27, +1,7,4,7,2,2,8,2,2,5,9, +10,11,14,13,15,11,14,14,12,17,38, +46,12,12,14,12,16,17,15,17,13,18, +10,14,17,14,17,14,16,15,16,11,38, +10,15,16,16,11,11,11,13,16,15,18, +10,12,14,16,14,12,14,13,12,17,47, +19,23,24,26,22,20,24,25,26,25,27 + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index cf173c29..1b4d5421 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -223,32 +223,82 @@ impl EntityMap { desired_location, move_effect, )); - } else if explicit_stay_put + } else if !should_die_later + && explicit_stay_put && can_turn_around && self.map.get(entity_to_update_key).map(|e| e.turns_around()) == Some(true) { - if let Some((Some(change), change_effect)) = self + if let Some(directions_to_attempt) = self .map - .get_mut(entity_to_update_key) - .map(|e| (e.change_direction(), e.change_effect())) + .get(entity_to_update_key) + .and_then(|e| e.directions_to_attempt()) { - animations.push(AnimationInstruction::PriorityChange( + #[allow(clippy::indexing_slicing)] + for &direction_to_attempt in directions_to_attempt { + let (can_move, action) = self.attempt_move_in_direction( + map, + animations, + entity_to_update_key, + direction_to_attempt, + false, + push_depth, + entities_that_have_moved, + ); + + if can_move.0 { + if let Some((Some(change), change_effect)) = self + .map + .get_mut(entity_to_update_key) + .map(|e| (e.change_direction(direction_to_attempt), e.change_effect())) + { + animations.push(AnimationInstruction::PriorityChange( + entity_to_update_key, + change, + change_effect, + )); + } + + return ( + can_move, + ActionResult::new( + hero_has_died || action.hero_has_died, + win_has_triggered || action.win_has_triggered, + ), + ); + } + } + + let last_direction_attempt = *directions_to_attempt.last().unwrap(); + + animations.push(AnimationInstruction::FakeOutMove( entity_to_update_key, - change, - change_effect, + last_direction_attempt, + self.map + .get(entity_to_update_key) + .and_then(|e| e.fake_out_wall_effect()), )); - return self.attempt_move_in_direction( - map, - animations, - entity_to_update_key, - -direction, - false, - push_depth, - entities_that_have_moved, + if let Some((Some(change), change_effect)) = + self.map.get_mut(entity_to_update_key).map(|e| { + ( + e.change_direction(last_direction_attempt), + e.change_effect(), + ) + }) + { + animations.push(AnimationInstruction::PriorityChange( + entity_to_update_key, + change, + change_effect, + )); + } + + return ( + HasMoved(false), + ActionResult::new(hero_has_died, win_has_triggered), ); } - } else { + } else if can_turn_around { animations.push(AnimationInstruction::FakeOutMove( entity_to_update_key, direction, @@ -348,6 +398,11 @@ impl EntityMap { hero_has_died |= self.kill_entity(entity_to_update_key, animations); break; } + OverlapResolution::KillDie => { + hero_has_died |= self.kill_entity(other_entity_key, animations); + hero_has_died |= self.kill_entity(entity_to_update_key, animations); + break; + } OverlapResolution::MoveAgain => { should_move_again = true; } @@ -468,6 +523,7 @@ enum OverlapResolution { Win, ToggleSystem(SwitchSystem), Die, + KillDie, MoveAgain, Teleport, } @@ -483,7 +539,7 @@ fn resolve_spikes(switable: &Switchable) -> OverlapResolution { fn resolve_overlap(me: &Entity, other: &Entity) -> OverlapResolution { match (&me.entity, &other.entity) { (EntityType::Hero(_), EntityType::Stairs) => OverlapResolution::Win, - (EntityType::Hero(_) | EntityType::Enemy(Enemy::Squid(_)), EntityType::Item(_)) => { + (EntityType::Hero(_) | EntityType::Enemy(Enemy::Moving(_)), EntityType::Item(_)) => { OverlapResolution::Pickup } (EntityType::MovableBlock, EntityType::Spikes(_)) => OverlapResolution::CoExist, @@ -492,6 +548,8 @@ fn resolve_overlap(me: &Entity, other: &Entity) -> OverlapResolution { (_, EntityType::Enemy(_)) => OverlapResolution::Die, (_, EntityType::Ice) => OverlapResolution::MoveAgain, (_, EntityType::Teleporter) => OverlapResolution::Teleport, + (EntityType::MovableBlock, EntityType::Hole) => OverlapResolution::KillDie, + (_, EntityType::Hole) => OverlapResolution::Die, _ => OverlapResolution::CoExist, } @@ -504,18 +562,18 @@ fn holding_attack_resolve( ) -> MoveAttemptResolution { match (holding, &other.entity) { (Some(&EntityType::Item(Item::Sword)), _) => MoveAttemptResolution::Kill, - (_, EntityType::Enemy(Enemy::Squid(squid))) => { + (_, EntityType::Enemy(Enemy::Moving(squid))) => { hero_walk_into_squid_interaction(squid, direction) } _ => MoveAttemptResolution::CoExist, } } -fn squid_holding_attack_resolve(me: &Squid, other: &Entity) -> MoveAttemptResolution { +fn squid_holding_attack_resolve(me: &Moving, other: &Entity) -> MoveAttemptResolution { match (me.holding.as_deref(), &other.entity, other.holding()) { ( Some(&EntityType::Item(Item::Sword)), - EntityType::Enemy(Enemy::Squid(squid)), + EntityType::Enemy(Enemy::Moving(squid)), Some(&EntityType::Item(Item::Sword)), ) => { if squid.direction == -me.direction { @@ -527,7 +585,7 @@ fn squid_holding_attack_resolve(me: &Squid, other: &Entity) -> MoveAttemptResolu (Some(&EntityType::Item(Item::Sword)), EntityType::Enemy(_), None) => { MoveAttemptResolution::Kill } - (_, EntityType::Enemy(Enemy::Squid(squid)), Some(&EntityType::Item(Item::Sword))) => { + (_, EntityType::Enemy(Enemy::Moving(squid)), Some(&EntityType::Item(Item::Sword))) => { if squid.direction == -me.direction { MoveAttemptResolution::Die } else { @@ -555,7 +613,7 @@ fn switch_door_resolve(door: &Switchable) -> MoveAttemptResolution { } } -fn hero_walk_into_squid_interaction(squid: &Squid, direction: Direction) -> MoveAttemptResolution { +fn hero_walk_into_squid_interaction(squid: &Moving, direction: Direction) -> MoveAttemptResolution { if direction == -squid.direction { MoveAttemptResolution::DieLater } else { @@ -569,14 +627,14 @@ fn resolve_move(mover: &Entity, into: &Entity, direction: Direction) -> MoveAtte holding_attack_resolve(hero.holding.as_deref(), into, direction) } (EntityType::Hero(hero), EntityType::Door) => holding_door_resolve(hero.holding.as_deref()), - (EntityType::Enemy(Enemy::Squid(squid)), EntityType::Hero(_) | EntityType::Enemy(_)) => { + (EntityType::Enemy(Enemy::Moving(squid)), EntityType::Hero(_) | EntityType::Enemy(_)) => { squid_holding_attack_resolve(squid, into) } (EntityType::Enemy(_), EntityType::Hero(_) | EntityType::Enemy(_)) => { MoveAttemptResolution::Kill } (_, EntityType::SwitchedDoor(door)) => switch_door_resolve(door), - (EntityType::Enemy(Enemy::Squid(squid)), EntityType::Door) => { + (EntityType::Enemy(Enemy::Moving(squid)), EntityType::Door) => { holding_door_resolve(squid.holding.as_deref()) } (_, EntityType::Door) => MoveAttemptResolution::StayPut, @@ -611,6 +669,7 @@ pub enum EntityType { Enemy(Enemy), Stairs, Door, + Hole, SwitchedDoor(Switchable), Switch(Switchable), Spikes(Switchable), @@ -620,15 +679,22 @@ pub enum EntityType { } #[derive(Debug)] -pub struct Squid { +pub struct Moving { direction: Direction, holding: Option>, + movable_enemy_type: MovableEnemyType, +} + +#[derive(Debug, PartialEq, Eq)] +enum MovableEnemyType { + Squid, + Rotator, } #[derive(Debug)] pub enum Enemy { Slime, - Squid(Squid), + Moving(Moving), } #[derive(Debug)] @@ -686,19 +752,19 @@ impl Entity { fn desired_action(&self, hero_action: Action) -> Action { match &self.entity { EntityType::Hero(_) => hero_action, - EntityType::Enemy(Enemy::Squid(squid)) => Action::Direction(squid.direction), + EntityType::Enemy(Enemy::Moving(squid)) => Action::Direction(squid.direction), _ => Action::Nothing, } } fn turns_around(&self) -> bool { - matches!(self.entity, EntityType::Enemy(Enemy::Squid(_))) + matches!(self.entity, EntityType::Enemy(Enemy::Moving(_))) } fn pickup(&mut self, item: EntityType) -> Option { let holding = match &mut self.entity { EntityType::Hero(hero) => &mut hero.holding, - EntityType::Enemy(Enemy::Squid(squid)) => &mut squid.holding, + EntityType::Enemy(Enemy::Moving(squid)) => &mut squid.holding, _ => panic!("this entity can't pick up things"), }; @@ -709,7 +775,7 @@ impl Entity { fn take_holding(&mut self) -> Option { match &mut self.entity { EntityType::Hero(hero) => hero.holding.take().map(|x| *x), - EntityType::Enemy(Enemy::Squid(squid)) => squid.holding.take().map(|x| *x), + EntityType::Enemy(Enemy::Moving(squid)) => squid.holding.take().map(|x| *x), _ => None, } } @@ -719,7 +785,7 @@ impl Entity { Some(i32::MAX) } else if matches!( self.entity, - EntityType::Hero(_) | EntityType::Enemy(Enemy::Squid(_)) + EntityType::Hero(_) | EntityType::Enemy(Enemy::Moving(_)) ) { Some(1) } else { @@ -730,7 +796,7 @@ impl Entity { fn holding(&self) -> Option<&EntityType> { match &self.entity { EntityType::Hero(hero) => hero.holding.as_deref(), - EntityType::Enemy(Enemy::Squid(squid)) => squid.holding.as_deref(), + EntityType::Enemy(Enemy::Moving(squid)) => squid.holding.as_deref(), _ => None, } } @@ -740,7 +806,11 @@ impl Entity { EntityType::Hero(_) => Some(SoundEffect::HeroDie), EntityType::Door => Some(SoundEffect::DoorOpen), EntityType::Enemy(Enemy::Slime) => Some(SoundEffect::SlimeDie), - EntityType::Enemy(Enemy::Squid(_)) => Some(SoundEffect::SquidDie), + EntityType::Enemy(Enemy::Moving(e)) + if e.movable_enemy_type == MovableEnemyType::Squid => + { + Some(SoundEffect::SquidDie) + } _ => None, } } @@ -792,15 +862,46 @@ impl Entity { None } - fn change_direction(&mut self) -> Option { - match &mut self.entity { - EntityType::Enemy(Enemy::Squid(squid)) => { - squid.direction = -squid.direction; + fn directions_to_attempt(&self) -> Option<&'static [Direction]> { + match &self.entity { + EntityType::Enemy(Enemy::Moving(moving_type)) => { + Some(match moving_type.movable_enemy_type { + MovableEnemyType::Squid => match moving_type.direction { + Direction::Up => &[Direction::Down], + Direction::Down => &[Direction::Up], + _ => panic!("Left and right movements are not valid for a squid"), + }, + MovableEnemyType::Rotator => match moving_type.direction { + Direction::Up => &[Direction::Right, Direction::Left, Direction::Down], + Direction::Down => &[Direction::Left, Direction::Right, Direction::Up], + Direction::Left => &[Direction::Up, Direction::Down, Direction::Right], + Direction::Right => &[Direction::Down, Direction::Up, Direction::Left], + }, + }) + } + _ => None, + } + } - if squid.direction == Direction::Up { - Some(level::Item::SquidUp) - } else { - Some(level::Item::SquidDown) + fn change_direction(&mut self, direction: Direction) -> Option { + match &mut self.entity { + EntityType::Enemy(Enemy::Moving(moving)) => { + moving.direction = direction; + + match moving.movable_enemy_type { + MovableEnemyType::Squid => { + if direction == Direction::Up { + Some(level::Item::SquidUp) + } else { + Some(level::Item::SquidDown) + } + } + MovableEnemyType::Rotator => Some(match direction { + Direction::Up => level::Item::RotatorUp, + Direction::Down => level::Item::RotatorDown, + Direction::Left => level::Item::RotatorLeft, + Direction::Right => level::Item::RotatorRight, + }), } } _ => None, @@ -887,18 +988,41 @@ impl From for EntityType { system: SwitchSystem(0), active: false, }), - level::Item::SquidUp => EntityType::Enemy(Enemy::Squid(Squid { + level::Item::SquidUp => EntityType::Enemy(Enemy::Moving(Moving { direction: Direction::Up, holding: None, + movable_enemy_type: MovableEnemyType::Squid, })), - level::Item::SquidDown => EntityType::Enemy(Enemy::Squid(Squid { + level::Item::SquidDown => EntityType::Enemy(Enemy::Moving(Moving { direction: Direction::Down, holding: None, + movable_enemy_type: MovableEnemyType::Squid, })), level::Item::Ice => EntityType::Ice, level::Item::MovableBlock => EntityType::MovableBlock, level::Item::Glove => EntityType::Item(Item::Glove), level::Item::Teleporter => EntityType::Teleporter, + level::Item::Hole => EntityType::Hole, + level::Item::RotatorRight => EntityType::Enemy(Enemy::Moving(Moving { + direction: Direction::Right, + holding: None, + movable_enemy_type: MovableEnemyType::Rotator, + })), + level::Item::RotatorLeft => EntityType::Enemy(Enemy::Moving(Moving { + direction: Direction::Left, + holding: None, + movable_enemy_type: MovableEnemyType::Rotator, + })), + level::Item::RotatorUp => EntityType::Enemy(Enemy::Moving(Moving { + direction: Direction::Up, + holding: None, + movable_enemy_type: MovableEnemyType::Rotator, + })), + level::Item::RotatorDown => EntityType::Enemy(Enemy::Moving(Moving { + direction: Direction::Down, + holding: None, + movable_enemy_type: MovableEnemyType::Rotator, + })), } } } diff --git a/examples/the-dungeon-puzzlers-lament/src/level.rs b/examples/the-dungeon-puzzlers-lament/src/level.rs index f87f1723..f883d59d 100644 --- a/examples/the-dungeon-puzzlers-lament/src/level.rs +++ b/examples/the-dungeon-puzzlers-lament/src/level.rs @@ -22,6 +22,11 @@ pub enum Item { MovableBlock, Glove, Teleporter, + Hole, + RotatorRight, + RotatorLeft, + RotatorUp, + RotatorDown, } impl Item { @@ -45,6 +50,11 @@ impl Item { Item::MovableBlock => resources::ROCK_SHADOW, Item::Glove => resources::POW_GLOVE_SHADOW, Item::Teleporter => resources::TELEPORTER_SHADOW, + Item::Hole => resources::HOLE, + Item::RotatorRight => resources::ROTATOR_RIGHT, + Item::RotatorLeft => resources::ROTATOR_LEFT, + Item::RotatorUp => resources::ROTATOR_UP, + Item::RotatorDown => resources::ROTATOR_DOWN, } } @@ -68,6 +78,11 @@ impl Item { Item::MovableBlock => resources::ROCK, Item::Glove => resources::POW_GLOVE, Item::Teleporter => resources::TELEPORTER, + Item::Hole => resources::HOLE, + Item::RotatorRight => resources::ROTATOR_RIGHT, + Item::RotatorLeft => resources::ROTATOR_LEFT, + Item::RotatorUp => resources::ROTATOR_UP, + Item::RotatorDown => resources::ROTATOR_DOWN, } } @@ -94,6 +109,11 @@ impl Item { Item::MovableBlock => ZERO, Item::Glove => STANDARD, Item::Teleporter => ZERO, + Item::Hole => ZERO, + Item::RotatorRight => STANDARD, + Item::RotatorLeft => STANDARD, + Item::RotatorUp => STANDARD, + Item::RotatorDown => STANDARD, } } } diff --git a/examples/the-dungeon-puzzlers-lament/src/resources.rs b/examples/the-dungeon-puzzlers-lament/src/resources.rs index 69672669..a4dfef88 100644 --- a/examples/the-dungeon-puzzlers-lament/src/resources.rs +++ b/examples/the-dungeon-puzzlers-lament/src/resources.rs @@ -56,6 +56,11 @@ named_tag!( POW_GLOVE_SHADOW, TELEPORTER, TELEPORTER_SHADOW, + HOLE, + ROTATOR_RIGHT, + ROTATOR_UP, + ROTATOR_LEFT, + ROTATOR_DOWN, ] ); From 9757608ab4803b1f940c74a111bd0d49208ed0cb Mon Sep 17 00:00:00 2001 From: Corwin Date: Fri, 1 Sep 2023 17:56:50 +0100 Subject: [PATCH 64/71] add snail rotator --- .../gfx/sprites16x16.aseprite | Bin 15618 -> 18838 bytes .../the-dungeon-puzzlers-lament/src/level.rs | 8 ++++---- .../src/resources.rs | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite b/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite index 0cfa162ed2a1730b1d1332280a669b8e8d666cb7..25387fa7de6d5925004af8744a826c26b5b28b8c 100644 GIT binary patch delta 3452 zcmeHJX;4#F6uvJZL`WncOQHgaP_@*WuvoUXNf>3*un4F`0RsV1#0{4cEIc*=2N}T> z38F($M1`mY2C)bf8*qcFhziyXwJ6BAP{J09=}p+;I{dI5XWBRO&fGh5=G-~ocg}ZC zeAHecg5T>3K93ufI>4X zeSmzehB^Zm=&17P0WS|92Okfwm0qsSE)d;pU!rlVW z`2tboidE){g^^-}Is_w>Hu*0+W=ff7{)WtsEqc*g)rswnzf+;O%L$u!IhXbI#MS|q;Yqq6|yUtB4e+fv(g%=P7yhW86-97#13ToR+;zE z07!Nl?DT>!;b<6u0XQJXz>D(J0Gc3jKc5$i#(LtC}|a)_vC@%7n}WljfP zoNPP#{fTg~_hreI$R*6*t9;W0>mTKOd&V6lX~ zh@Rt?2i%LR?XgMn3z3^NS(@hxNd6?c6+3KDz<;G%MB*}z$#_u?GPcNA#P({ z6S%Q6p##@px|H$dbBCxv*`yBqF+7;Y8PxVrBCMe7ourL&hQ3YOmd#z+3H7A*FxM_C zroitp0;;@h>=utOhMzcNl+%D2n1T2@^@+)CLSr>7f zII${mu&zdmpp~UfYa-fSkLxeu9FaR4oG&2z8(Bxwz?As~#U0MgD?)2tQWG75%%dP^ z6yYKA0^MtbrsgZt6AqHOEDH$A&PIaJ`DSXkI)}lTdpIg%h}1OwLP264mCHCKjT4h{ zVnpcFpCBSB0pYSh-Zp+y@(FUzP`@;&iPV(pMg{ZjX0PBY*;7-N8PpSCr^EvqShM3z zp$#iKa=%bF^VJphtaR+t%tM|mOShd><`zK~94atFD5wALS^ss&A_e#3V16?pFn0v{ zJ#3F?k>(Z6Hh5Gj^sNHy3UiYfAzh!0Dw>_o`}dSkO@(x*gy^ttjds=BP4!+S9PKMb zO^w&l2bJ(0edVvxSbZ>(tP7*8RE1iz;g6$10|+WFkf1IMS1JQvOZ*Jj9W@T-6f%RE zW>FeDbq>OsIg&v_a`9lF8D@JQQpS1~*itzug>;|bEb#dm7#{3OWt zn=ghXCOq2bgPk$&P8KU{)zYM&_xVQeGMz3phO^^RsQ9Vrz59k%Mo)T!(sFP2%gATk z=Mt)I7+cVR@PH>}PUk9|hdd>BxvMju{gztY@aN^$s6i*xVS`~;%QAU(&b{P-?;Pn5 zO{^=p=Pao=7C)P;m>#@0^v8ZI*$?Yad`v`xLvzA<0}Dz%2?Sm>%>9qgoh3>j9md7S zdO}D#p8KJFCfPg4*o6va)zWWlQ<0s2eulpxH=}BUzHjk*_Y5E1y6`aL32M!Iwk|{o zBF1w}WIjsoeHt48`koB{E+jEMU zgX_d?z7@{&`7vU~QX%(of%ume(Qa(Se7G-9q4a{tJ+=w delta 451 zcmbO>nX##goynGg;lWb(iR_iU>}(7Szdmv>q%bfraBS@LVdOA!VqsvAP*B~(WX-~v z4HRZoU}RvLe4kx(^9MFNLq?{_`WCx@VGcfpIzcK6LRpr&JosSPq znc=;%dgIEatZWP~CRQwt1nNRI)f31Ey9?dadbqJlX$P1;tmNh4`QzUcHNi^a*m5zo ze!t+uyv?qy9f6SF^4>+^T6fJ>>f%=EN;s z%mQpcUso&+M{~0~E;qwXMmX7C*~pKx0K0RV)Sow8ww( diff --git a/examples/the-dungeon-puzzlers-lament/src/level.rs b/examples/the-dungeon-puzzlers-lament/src/level.rs index f883d59d..81ce5489 100644 --- a/examples/the-dungeon-puzzlers-lament/src/level.rs +++ b/examples/the-dungeon-puzzlers-lament/src/level.rs @@ -51,10 +51,10 @@ impl Item { Item::Glove => resources::POW_GLOVE_SHADOW, Item::Teleporter => resources::TELEPORTER_SHADOW, Item::Hole => resources::HOLE, - Item::RotatorRight => resources::ROTATOR_RIGHT, - Item::RotatorLeft => resources::ROTATOR_LEFT, - Item::RotatorUp => resources::ROTATOR_UP, - Item::RotatorDown => resources::ROTATOR_DOWN, + Item::RotatorRight => resources::ROTATOR_RIGHT_SHADOW, + Item::RotatorLeft => resources::ROTATOR_LEFT_SHADOW, + Item::RotatorUp => resources::ROTATOR_UP_SHADOW, + Item::RotatorDown => resources::ROTATOR_DOWN_SHADOW, } } diff --git a/examples/the-dungeon-puzzlers-lament/src/resources.rs b/examples/the-dungeon-puzzlers-lament/src/resources.rs index a4dfef88..a65b9961 100644 --- a/examples/the-dungeon-puzzlers-lament/src/resources.rs +++ b/examples/the-dungeon-puzzlers-lament/src/resources.rs @@ -61,6 +61,10 @@ named_tag!( ROTATOR_UP, ROTATOR_LEFT, ROTATOR_DOWN, + ROTATOR_RIGHT_SHADOW, + ROTATOR_UP_SHADOW, + ROTATOR_LEFT_SHADOW, + ROTATOR_DOWN_SHADOW, ] ); From 832605ff22b60b824758597ac12ded0f23ec84e5 Mon Sep 17 00:00:00 2001 From: Corwin Date: Fri, 1 Sep 2023 21:42:09 +0100 Subject: [PATCH 65/71] improve snail sprites --- .../gfx/sprites16x16.aseprite | Bin 18838 -> 18835 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite b/examples/the-dungeon-puzzlers-lament/gfx/sprites16x16.aseprite index 25387fa7de6d5925004af8744a826c26b5b28b8c..56a76ea9e1656532ed007f4b13dbefe1188f049c 100644 GIT binary patch delta 391 zcmbO>nQ`)DM#jk-86#{MwI@f}+-LNjY-KB}oseMgAn@P$1{Q}uq027+7gpv=`u_Qt zz*@0Lp4o9lM-yr!+{D@w1>_mTzfW$o-N~pj+1l<3qyJ<9ds%%424=aZ|9LXNIu9SY z_|srx-8~5r)5aVxiL47pH@sZx!gH)WF{My~?IWXv+~hd>eT*raWgR3KA(rcrV7XOn z_T~mhX-1&cbDT)Fdh;u%Z;Xs_n;*LHflL58-iSoUTO@~Vc68$cx!lKHmNb_$PM+=& KviX(!8b$!3w4o9J delta 387 zcmbO{nQ_`=M#gCy86#{MwI)Z|+-LNfY-KB})xf|k_w+xH2g8y0RI9)Cn=JG;*4>-& z|H+Hv%cjQ|O31fOJenwRgq`8ip5V^R1OTU>lx6?` From cc5e805d82f1ce9773aae848da09c7dae2027219 Mon Sep 17 00:00:00 2001 From: Corwin Date: Fri, 1 Sep 2023 22:43:09 +0100 Subject: [PATCH 66/71] show movement options of the snail --- .../maps/levels/rotator_demonstration.tmx | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/rotator_demonstration.tmx diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_demonstration.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_demonstration.tmx new file mode 100644 index 00000000..69b1604e --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_demonstration.tmx @@ -0,0 +1,40 @@ + + + + + + + + + + +0,1,8,3,9,1,7,9,0,0,0, +1,1073741852,11,11,3221225500,1073741852,13,38,0,0,0, +37,17,16,14,16,14,15,3221225500,7,9,0, +10,11,39,16,2147483676,28,16,16,11,47,0, +37,13,3221225504,24,27,10,15,14,29,30,0, +37,12,3221225500,9,0,37,15,12,15,38,0, +37,11,13,3221225500,6,1073741852,12,15,14,47,0, +19,28,12,11,13,17,11,39,15,38,0, +0,19,22,28,14,15,12,3221225504,26,27,0, +0,0,0,19,20,24,21,27,0,0,0 + + + + + + + + + + + + + + + + + + + + From 98d2dc0022f89a2dd57afbf17090db568f1861fb Mon Sep 17 00:00:00 2001 From: Corwin Date: Sat, 2 Sep 2023 18:32:02 +0100 Subject: [PATCH 67/71] another simple snail level --- .../maps/levels/rotator_2.tmx | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 examples/the-dungeon-puzzlers-lament/maps/levels/rotator_2.tmx diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_2.tmx new file mode 100644 index 00000000..ba90804c --- /dev/null +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_2.tmx @@ -0,0 +1,40 @@ + + + + + + + + + + +0,0,0,0,0,1,6,8,5,4,9, +0,0,1,7,8,32,11,17,12,17,38, +0,0,10,14,17,1073741863,14,2147483676,28,13,38, +0,0,37,11,11,13,13,38,46,15,18, +1,8,1073741852,16,16,11,13,18,10,11,38, +37,16,17,12,13,11,17,18,46,11,47, +10,12,2147483676,22,26,23,23,27,10,17,38, +46,16,3221225500,5,6,7,5,3,1073741852,15,47, +10,13,16,15,13,13,12,14,11,12,47, +19,26,20,21,25,20,22,24,21,24,27 + + + + + + + + + + + + + + + + + + + + From 962b503751c328be9b9b23572f96845afe6e6ff8 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 5 Sep 2023 22:52:10 +0100 Subject: [PATCH 68/71] test all the levels --- examples/the-dungeon-puzzlers-lament/build.rs | 51 ++++++- .../maps/levels/a_familiar_sight.tmx | 11 +- .../maps/levels/another_ice.tmx | 23 ++- .../maps/levels/another_ice_2.tmx | 32 ++++- .../maps/levels/another_ice_3.tmx | 29 +++- .../maps/levels/another_ice_4.tmx | 17 ++- .../maps/levels/block_push_1.tmx | 14 +- .../maps/levels/block_push_2.tmx | 11 +- .../maps/levels/block_push_3.tmx | 14 +- .../maps/levels/glove_key.tmx | 14 +- .../maps/levels/hole_introduction.tmx | 11 +- .../maps/levels/ice_ice.tmx | 17 ++- .../maps/levels/just_rocks.tmx | 11 +- .../maps/levels/level1.tmx | 11 +- .../maps/levels/level2.tmx | 11 +- .../maps/levels/level3.tmx | 11 +- .../maps/levels/level4.tmx | 11 +- .../maps/levels/level5.tmx | 14 +- .../maps/levels/level6.tmx | 11 +- .../maps/levels/level_around.tmx | 20 ++- .../maps/levels/level_spikes.tmx | 14 +- .../maps/levels/level_spikes2.tmx | 20 ++- .../maps/levels/level_spikes3.tmx | 17 ++- .../maps/levels/level_squid1.tmx | 17 ++- .../maps/levels/level_squid2.tmx | 17 ++- .../maps/levels/level_squid_button.tmx | 23 ++- .../maps/levels/level_squid_drop.tmx | 23 ++- .../maps/levels/level_squid_force_button.tmx | 14 +- .../maps/levels/level_squid_intro.tmx | 14 +- .../maps/levels/level_squid_item.tmx | 17 ++- .../maps/levels/level_squidprogramming.tmx | 17 ++- .../maps/levels/level_switch.tmx | 11 +- .../maps/levels/rotator_1.tmx | 20 ++- .../maps/levels/rotator_2.tmx | 14 +- .../maps/levels/rotator_demonstration.tmx | 11 +- .../maps/levels/slime_teleporter.tmx | 20 ++- .../maps/levels/squid_rock.tmx | 17 ++- .../maps/levels/squid_teleport.tmx | 17 ++- .../maps/levels/teleporter_1.tmx | 11 +- .../maps/levels/teleporter_2.tmx | 26 +++- .../src/game/simulation.rs | 16 ++- .../src/game/simulation/entity.rs | 134 +++++++++++++++++- .../the-dungeon-puzzlers-lament/src/level.rs | 8 +- .../the-dungeon-puzzlers-lament/src/map.rs | 2 +- 44 files changed, 711 insertions(+), 133 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index 805a7839..7a41a96a 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -5,6 +5,7 @@ use std::{ io::{BufWriter, Write}, str::FromStr, }; +use tiled::{Map, ObjectLayer, TileLayer}; use proc_macro2::TokenStream; @@ -259,6 +260,7 @@ impl quote::ToTokens for EntityWithPosition { struct Level { starting_items: Vec, fixed_positions: Vec, + solution_positions: Vec, directions: Vec, wall_bitmap: Vec, name: String, @@ -268,6 +270,7 @@ impl quote::ToTokens for Level { fn to_tokens(&self, tokens: &mut TokenStream) { let wall_bitmap = &self.wall_bitmap; let fixed_positions = &self.fixed_positions; + let solution_positions = &self.solution_positions; let directions = &self.directions; let starting_items = &self.starting_items; let name = &self.name; @@ -276,6 +279,7 @@ impl quote::ToTokens for Level { Level::new( Map::new(11, 10, &[#(#wall_bitmap),*]), &[#(#fixed_positions),*], + &[#(#solution_positions),*], &[#(#directions),*], &[#(#starting_items),*], #name, @@ -284,10 +288,10 @@ impl quote::ToTokens for Level { } } -fn export_level(map: &tiled::Map) -> Level { - let objects = map.get_layer(1).unwrap().as_object_layer().unwrap(); - - let fixed_positions = objects.objects().map(|obj| { +fn extract_objects_from_layer( + objects: ObjectLayer<'_>, +) -> impl Iterator + '_ { + objects.objects().map(|obj| { let entity: Entity = obj .name .parse() @@ -297,7 +301,20 @@ fn export_level(map: &tiled::Map) -> Level { let y = (obj.y / 16.0) as i32; EntityWithPosition(entity, (x, y)) - }); + }) +} + +fn export_level(map: &tiled::Map) -> Level { + let objects = map + .get_object_layer("Puzzle") + .expect("The puzzle object layer should exist"); + + let fixed_positions = extract_objects_from_layer(objects); + + let solution_positions = extract_objects_from_layer( + map.get_object_layer("Solution") + .expect("Should have an object layer called 'Solution'"), + ); let Some(tiled::PropertyValue::StringValue(starting_items)) = map.properties.get("ITEMS") else { @@ -352,6 +369,7 @@ fn export_level(map: &tiled::Map) -> Level { Level { starting_items: starting_items.collect(), fixed_positions: fixed_positions.collect(), + solution_positions: solution_positions.collect(), directions: directions.collect(), wall_bitmap: bool_to_bit(&are_walls.collect::>()), name: level_name.clone(), @@ -359,7 +377,9 @@ fn export_level(map: &tiled::Map) -> Level { } fn export_tiles(map: &tiled::Map, background: TokenStream) -> TokenStream { - let map_tiles = map.get_layer(0).unwrap().as_tile_layer().unwrap(); + let map_tiles = map + .get_tile_layer("Ground") + .expect("The ground layer should exist"); let width = map_tiles.width().unwrap() * 2; let height = map_tiles.height().unwrap() * 2; @@ -446,3 +466,22 @@ fn check_bool_to_bit() { let bools = [true, false, false, false, true, true, true, true]; assert_eq!(bool_to_bit(&bools), [0b11110001]); } + +trait TiledMapExtensions { + fn get_object_layer(&self, name: &str) -> Option; + fn get_tile_layer(&self, name: &str) -> Option; +} + +impl TiledMapExtensions for Map { + fn get_object_layer(&self, name: &str) -> Option { + self.layers() + .find(|x| x.name == name) + .and_then(|x| x.as_object_layer()) + } + + fn get_tile_layer(&self, name: &str) -> Option { + self.layers() + .find(|x| x.name == name) + .and_then(|x| x.as_tile_layer()) + } +} diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/a_familiar_sight.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/a_familiar_sight.tmx index 4a4d07d1..e6583806 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/a_familiar_sight.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/a_familiar_sight.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -28,4 +28,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice.tmx index 2487605d..5b79dfd8 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,1,2,9,0,1,8,6,9, 0,0,0,10,17,18,1,1073741852,17,12,18, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,19,26,23,27,0 - + @@ -43,4 +43,21 @@ + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx index 79c166ef..5d1d638b 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_2.tmx @@ -1,12 +1,12 @@ - + - + 1,8,2,7,8,8,3,7,4,2,9, 46,17,13,17,13,12,12,15,11,16,38, @@ -20,7 +20,7 @@ 0,19,24,20,25,20,27,0,0,0,0 - + @@ -103,4 +103,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx index 04f0ee15..8004709d 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_3.tmx @@ -1,12 +1,12 @@ - + - + 1,8,2,7,8,8,3,9,1,2,9, 46,2147483676,22,23,28,12,12,38,19,26,27, @@ -20,7 +20,7 @@ 19,22,22,20,25,22,26,25,26,24,27 - + @@ -46,4 +46,27 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx index 98140e23..8069e5f1 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/another_ice_4.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,1,7,9,0,0,0,0,0, 0,0,1,1073741852,13,3221225500,8,9,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,19,24,27,0,0,0 - + @@ -40,4 +40,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_1.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_1.tmx index 4deac7d6..883df163 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_1.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_1.tmx @@ -1,12 +1,12 @@ - + - + 0,1,3,2,6,9,0,0,0,0,0, 0,46,15,14,13,3221225500,4,6,7,7,9, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -34,4 +34,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_2.tmx index 560a1c96..2aaef9c0 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_2.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -37,4 +37,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_3.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_3.tmx index 178c36c1..48c2c3ec 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_3.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/block_push_3.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,1,6,2,8,8,9,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -37,4 +37,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx index c66b3ee2..ff6161be 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/glove_key.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -37,4 +37,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/hole_introduction.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/hole_introduction.tmx index 8da8ed63..434cc987 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/hole_introduction.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/hole_introduction.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -31,4 +31,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx index 332ecc02..616beb28 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/ice_ice.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,19,26,27,0,0,0 - + @@ -46,4 +46,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx index 3798b556..d0fc2bcc 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/just_rocks.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -40,4 +40,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level1.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level1.tmx index 2db372a0..047ea962 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level1.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level1.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -31,4 +31,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level2.tmx index 39e6acef..d8464078 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level2.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,3,9,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -28,4 +28,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level3.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level3.tmx index 28abd513..d4d8e227 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level3.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level3.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -34,4 +34,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level4.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level4.tmx index f306fbfc..e6337c49 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level4.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level4.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -31,4 +31,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level5.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level5.tmx index c1fe7171..35b5a899 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level5.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level5.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -28,4 +28,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level6.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level6.tmx index 5e1bc8cd..5d433dcc 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level6.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level6.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -37,4 +37,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_around.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_around.tmx index 5a59fbdf..ce43a108 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_around.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_around.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,1,7,5,6,9,0,0, 0,0,1,4,1073741852,17,13,13,3221225500,9,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -28,4 +28,18 @@ + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes.tmx index d50168d9..845fa321 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -37,4 +37,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes2.tmx index f1e28c2f..1f3fbde5 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes2.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -40,4 +40,18 @@ + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes3.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes3.tmx index e8e67c6e..fe1fefb3 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes3.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_spikes3.tmx @@ -1,12 +1,12 @@ - + - + 0,0,1,8,4,1073741872,2,7,9,0,0, 0,0,37,15,15,1073741863,15,13,3221225500,3,9, @@ -20,7 +20,7 @@ 0,0,0,0,0,19,21,22,23,27,0 - + @@ -43,4 +43,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid1.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid1.tmx index 79dcfd30..0e062937 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid1.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid1.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,1,8,2,6,9,0,0, 0,0,0,0,46,11,11,11,38,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,19,23,27,0,0,0 - + @@ -34,4 +34,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid2.tmx index a740e0fc..327ce03b 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid2.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,1,5,9,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -37,4 +37,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_button.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_button.tmx index a6d7a077..05481924 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_button.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_button.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,1,2,9,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -40,4 +40,21 @@ + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_drop.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_drop.tmx index 1dc5cabd..f00d08fc 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_drop.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_drop.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,1,4,8,3,2,3,9,0, 0,0,0,46,11,12,14,16,14,38,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -34,4 +34,21 @@ + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_force_button.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_force_button.tmx index 918dd3c5..b962a0ca 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_force_button.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_force_button.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,1,7,9,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -37,4 +37,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_intro.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_intro.tmx index f16222ce..d121b081 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_intro.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_intro.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,1,8,9,0,0,0,0,0, 1,7,2,32,16,3221225500,9,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,19,23,25,48,22,27,0,0 - + @@ -40,4 +40,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_item.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_item.tmx index 8c250cdb..d60fe025 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_item.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squid_item.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,3,7,6,9,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -40,4 +40,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squidprogramming.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squidprogramming.tmx index b7c12c53..c422f7d3 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_squidprogramming.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_squidprogramming.tmx @@ -1,12 +1,12 @@ - + - + 0,1,4,3221225492,7,2147483655,3,1073741844,1073741850,2147483649,0, 0,37,2147483659,11,2147483659,2147483665,3221225486,3221225484,1073741839,3221225518,0, @@ -20,7 +20,7 @@ 19,2147483672,2147483673,1073741831,1073741832,1073741829,21,1073741826,22,22,27 - + @@ -49,4 +49,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/level_switch.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/level_switch.tmx index 333cba05..f81b4dbb 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/level_switch.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/level_switch.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -34,4 +34,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_1.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_1.tmx index 3847f552..a07675ac 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_1.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_1.tmx @@ -1,12 +1,12 @@ - + - + 1,6,7,7,4,5,3,2,4,7,9, 37,12,14,13,12,15,12,16,14,13,47, @@ -20,7 +20,7 @@ 19,23,24,26,22,20,24,25,26,25,27 - + @@ -40,4 +40,18 @@ + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_2.tmx index ba90804c..4783ebeb 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_2.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,1,6,8,5,4,9, 0,0,1,7,8,32,11,17,12,17,38, @@ -20,7 +20,7 @@ 19,26,20,21,25,20,22,24,21,24,27 - + @@ -37,4 +37,12 @@ + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_demonstration.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_demonstration.tmx index 69b1604e..896034e4 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_demonstration.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/rotator_demonstration.tmx @@ -1,12 +1,12 @@ - + - + 0,1,8,3,9,1,7,9,0,0,0, 1,1073741852,11,11,3221225500,1073741852,13,38,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,19,20,24,21,27,0,0,0 - + @@ -37,4 +37,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx index 9ef70e31..1dab8d70 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/slime_teleporter.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,1,6,4,3,9,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,19,22,22,27,0,0 - + @@ -40,4 +40,18 @@ + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/squid_rock.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/squid_rock.tmx index 584de271..5c5f5ba6 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/squid_rock.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/squid_rock.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -34,4 +34,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx index 9c917b6b..5807282d 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/squid_teleport.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 1,7,4,2,6,9,0,1,8,9,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -43,4 +43,15 @@ + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_1.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_1.tmx index 4f9c4457..1d30a67a 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_1.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_1.tmx @@ -1,12 +1,12 @@ - + - + 0,0,0,0,0,0,0,0,0,0,0, 0,1,4,5,4,3,7,2,8,9,0, @@ -20,7 +20,7 @@ 0,0,0,0,0,0,0,0,0,0,0 - + @@ -31,4 +31,9 @@ + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx index c8cae9cc..f3ee9d48 100644 --- a/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx +++ b/examples/the-dungeon-puzzlers-lament/maps/levels/teleporter_2.tmx @@ -1,12 +1,12 @@ - + - + 0,0,1,8,7,7,5,9,0,0,0, 1,6,1073741852,15,16,15,13,3221225500,9,0,0, @@ -20,7 +20,7 @@ 0,0,0,0,19,23,27,0,0,0,0 - + @@ -43,4 +43,24 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs index 8d9e36bb..574fda1b 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs @@ -11,7 +11,7 @@ use crate::{ use self::{ animation::{Animation, RenderCache}, - entity::{Action, EntityMap}, + entity::{Action, EntityMap, EntityMapMaker}, }; mod animation; @@ -33,19 +33,21 @@ pub struct Simulation { impl Simulation { pub fn generate( - a: impl Iterator)>, + entities_to_add: impl Iterator)>, level: &'static Level, sfx: &mut Sfx, loader: &mut SpriteLoader, ) -> Simulation { - let mut entities = EntityMap::default(); + let mut entities = EntityMapMaker::new(); let mut animation = Animation::default(); - let mut entities_to_add: Vec<_> = a.collect(); - entities_to_add.sort_unstable_by_key(|(_, location)| location.x + location.y * 100); - for (item, location) in entities_to_add { - animation.populate(entities.add(item, location), sfx); + entities.add(item, location); + } + + let (entities, animations) = entities.to_entity_map(); + for ani in animations { + animation.populate(ani, sfx); } let mut simulation = Simulation { diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 1b4d5421..6d38b2ee 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -18,11 +18,39 @@ use super::animation::AnimationInstruction; new_key_type! { pub struct EntityKey; } -#[derive(Default)] pub struct EntityMap { map: SlotMap, } +pub struct EntityMapMaker { + map: Vec<(crate::level::Item, Vector2D)>, +} + +impl EntityMapMaker { + pub fn new() -> Self { + Self { + map: Default::default(), + } + } + + pub fn add(&mut self, entity: crate::level::Item, location: Vector2D) { + let idx = self.map.push((entity, location)); + } + + pub fn to_entity_map(mut self) -> (EntityMap, Vec) { + self.map + .sort_unstable_by_key(|(_, location)| location.x + location.y * 100); + let mut entity_map = EntityMap { + map: Default::default(), + }; + let mut animations = Vec::new(); + for (entity, location) in self.map { + animations.push(entity_map.add(entity, location)); + } + (entity_map, animations) + } +} + #[derive(Clone, Copy, PartialEq, PartialOrd, Debug)] pub enum Outcome { Continue, @@ -1026,3 +1054,107 @@ impl From for EntityType { } } } + +#[cfg(test)] +mod tests { + + use super::*; + use agb::hash_map::HashMap; + + #[test_case] + fn check_all_puzzle_solutions_work(_gba: &mut agb::Gba) { + let number_of_levels = crate::level::Level::num_levels(); + let mut failed_levels = Vec::new(); + + #[derive(Debug)] + enum CompleteSimulationResult { + Success, + ExplicitLoss, + InputSequenceOver, + MismatchedItems(HashMap), + } + + fn check_level_has_valid_items(level: usize) -> HashMap { + let level = crate::level::Level::get_level(level); + + let mut given_items = HashMap::new(); + + for &item in level.items.iter() { + *given_items.entry(item).or_insert(0) += 1; + } + + let mut solution_items = HashMap::new(); + + for entity in level.solution.iter() { + *solution_items.entry(entity.0).or_insert(0) += 1; + } + + let mut mismatched = HashMap::new(); + + for (&item, &count) in solution_items.iter() { + if *given_items.entry(item).or_insert(0) < count { + mismatched.insert(item, ()); + } + } + + mismatched + } + + fn check_level_works(level: usize) -> CompleteSimulationResult { + let level = crate::level::Level::get_level(level); + + let mut simulator = EntityMapMaker::new(); + for entity in level.entities { + simulator.add(entity.0, entity.1); + } + for solution_entity in level.solution { + simulator.add(solution_entity.0, solution_entity.1); + } + + let (mut simulator, _) = simulator.to_entity_map(); + + for &direction in level.directions { + let (outcome, _) = simulator.tick(&level.map, Action::Direction(direction)); + match outcome { + Outcome::Continue => {} + Outcome::Loss => return CompleteSimulationResult::ExplicitLoss, + Outcome::Win => return CompleteSimulationResult::Success, + } + } + + CompleteSimulationResult::InputSequenceOver + } + + for level_idx in 0..number_of_levels { + let mismatched_items = check_level_has_valid_items(level_idx); + if !mismatched_items.is_empty() { + failed_levels.push(( + level_idx, + CompleteSimulationResult::MismatchedItems(mismatched_items), + )) + } + let outcome = check_level_works(level_idx); + match outcome { + CompleteSimulationResult::ExplicitLoss + | CompleteSimulationResult::InputSequenceOver => { + failed_levels.push((level_idx, outcome)) + } + _ => {} + } + } + + if !failed_levels.is_empty() { + agb::println!("Levels that failed were:"); + for (level, outcome) in failed_levels { + agb::println!( + "Level: {}, reason {:?}, lament: {}", + level, + outcome, + crate::level::Level::get_level(level).name + ); + } + + panic!("Level check failed"); + } + } +} diff --git a/examples/the-dungeon-puzzlers-lament/src/level.rs b/examples/the-dungeon-puzzlers-lament/src/level.rs index 81ce5489..ff779e0b 100644 --- a/examples/the-dungeon-puzzlers-lament/src/level.rs +++ b/examples/the-dungeon-puzzlers-lament/src/level.rs @@ -2,7 +2,7 @@ use agb::{display::object::Tag, fixnum::Vector2D}; use crate::{game::Direction, map::Map, resources}; -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub enum Item { Sword, Slime, @@ -123,15 +123,19 @@ pub struct Entity(pub Item, pub Vector2D); pub struct Level { pub map: Map<'static>, pub entities: &'static [Entity], + #[cfg(test)] + pub solution: &'static [Entity], pub directions: &'static [Direction], pub items: &'static [Item], pub name: &'static str, } impl Level { + #[allow(unused_variables)] const fn new( map: Map<'static>, entities: &'static [Entity], + solution: &'static [Entity], directions: &'static [Direction], items: &'static [Item], name: &'static str, @@ -139,6 +143,8 @@ impl Level { Self { map, entities, + #[cfg(test)] + solution, directions, items, name, diff --git a/examples/the-dungeon-puzzlers-lament/src/map.rs b/examples/the-dungeon-puzzlers-lament/src/map.rs index c0d9c6a3..558d2779 100644 --- a/examples/the-dungeon-puzzlers-lament/src/map.rs +++ b/examples/the-dungeon-puzzlers-lament/src/map.rs @@ -22,7 +22,7 @@ impl<'map> Map<'map> { pub const fn get(&self, index: Vector2D) -> MapElement { let (x, y) = (index.x, index.y); - if x > self.width as i32 || y > self.height as i32 { + if x > self.width as i32 || x < 0 || y > self.height as i32 || y < 0 { MapElement::Wall } else { let position = x as usize + y as usize * self.width; From 5fc302dec99f9974633884a8e989d9b067b8e276 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 5 Sep 2023 22:53:10 +0100 Subject: [PATCH 69/71] make names better --- examples/the-dungeon-puzzlers-lament/src/game/simulation.rs | 2 +- .../src/game/simulation/entity.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs index 574fda1b..997c332a 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation.rs @@ -45,7 +45,7 @@ impl Simulation { entities.add(item, location); } - let (entities, animations) = entities.to_entity_map(); + let (entities, animations) = entities.make_entity_map(); for ani in animations { animation.populate(ani, sfx); } diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index 6d38b2ee..b697dff2 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -34,10 +34,10 @@ impl EntityMapMaker { } pub fn add(&mut self, entity: crate::level::Item, location: Vector2D) { - let idx = self.map.push((entity, location)); + self.map.push((entity, location)); } - pub fn to_entity_map(mut self) -> (EntityMap, Vec) { + pub fn make_entity_map(mut self) -> (EntityMap, Vec) { self.map .sort_unstable_by_key(|(_, location)| location.x + location.y * 100); let mut entity_map = EntityMap { @@ -1111,7 +1111,7 @@ mod tests { simulator.add(solution_entity.0, solution_entity.1); } - let (mut simulator, _) = simulator.to_entity_map(); + let (mut simulator, _) = simulator.make_entity_map(); for &direction in level.directions { let (outcome, _) = simulator.tick(&level.map, Action::Direction(direction)); From 11fc38d840711bcea737c2e0398e2721e9c12528 Mon Sep 17 00:00:00 2001 From: Corwin Date: Tue, 5 Sep 2023 23:02:49 +0100 Subject: [PATCH 70/71] report mismatch counts --- .../src/game/simulation/entity.rs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs index b697dff2..c8248890 100644 --- a/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs +++ b/examples/the-dungeon-puzzlers-lament/src/game/simulation/entity.rs @@ -1066,15 +1066,22 @@ mod tests { let number_of_levels = crate::level::Level::num_levels(); let mut failed_levels = Vec::new(); + #[derive(Debug)] + #[allow(dead_code)] + struct MismatchCount { + given: i32, + used: i32, + } + #[derive(Debug)] enum CompleteSimulationResult { Success, ExplicitLoss, InputSequenceOver, - MismatchedItems(HashMap), + MismatchedItems(HashMap), } - fn check_level_has_valid_items(level: usize) -> HashMap { + fn check_level_has_valid_items(level: usize) -> HashMap { let level = crate::level::Level::get_level(level); let mut given_items = HashMap::new(); @@ -1092,8 +1099,15 @@ mod tests { let mut mismatched = HashMap::new(); for (&item, &count) in solution_items.iter() { - if *given_items.entry(item).or_insert(0) < count { - mismatched.insert(item, ()); + let given_count = given_items.get(&item).copied().unwrap_or(0); + if given_count < count { + mismatched.insert( + item, + MismatchCount { + given: given_count, + used: count, + }, + ); } } From 6a8106977d5b40d77e0f7a27f24d6370eeca2d54 Mon Sep 17 00:00:00 2001 From: Corwin Date: Thu, 14 Sep 2023 12:29:13 +0100 Subject: [PATCH 71/71] run tests for dpl in ci --- justfile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/justfile b/justfile index 1cbabf36..bfac29b9 100644 --- a/justfile +++ b/justfile @@ -68,7 +68,7 @@ check-linker-script-consistency: find -type f -name gba.ld -print0 | xargs -0 -n1 cmp -- agb/gba.ld find -type f -name gba_mb.ld -print0 | xargs -0 -n1 cmp -- agb/gba_mb.ld -ci: check-linker-script-consistency build-debug clippy fmt-check test miri build-release test-release doctest-agb build-roms build-book check-docs +ci: check-linker-script-consistency build-debug clippy fmt-check test miri build-release test-release doctest-agb test-games build-roms build-book check-docs build-roms: just _build-rom "examples/the-purple-night" "PURPLENIGHT" @@ -103,6 +103,12 @@ _run-tool +tool: (cd tools && cargo build) "$CARGO_TARGET_DIR/debug/tools" {{tool}} +test-games: + just test-game the-dungeon-puzzlers-lament + +test-game game: + (cd "examples/{{game}}" && CARGO_TARGET_THUMBV4T_NONE_EABI_RUNNER=mgba-test-runner cargo test) + _build-rom folder name: #!/usr/bin/env bash set -euxo pipefail