mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
add ice
This commit is contained in:
parent
9a6f96b2ba
commit
b9e6e09fe1
Binary file not shown.
|
@ -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::<VecDeque<_>>();
|
||||
|
||||
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,
|
||||
entity_to_update_key,
|
||||
direction,
|
||||
entity.fake_out_wall_effect(),
|
||||
self.map
|
||||
.get(entity_to_update_key)
|
||||
.and_then(|e| e.fake_out_wall_effect()),
|
||||
));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} 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();
|
||||
|
||||
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,53 +177,40 @@ impl EntityMap {
|
|||
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_key) {
|
||||
e.location = desired_location;
|
||||
}
|
||||
let Some(entity) = &self.map.get(entity_key) else {
|
||||
let Some(entity_to_update) = self.map.get(entity_to_update_key) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
animations.push(AnimationInstruction::Move(
|
||||
entity_key,
|
||||
desired_location,
|
||||
entity.move_effect(),
|
||||
));
|
||||
|
||||
let overlap_resolutions: Vec<_> = self
|
||||
.whats_at(desired_location)
|
||||
.filter(|(k, _)| *k != entity_key)
|
||||
.filter(|(k, _)| *k != entity_to_update_key)
|
||||
.map(|(key, other_entity)| {
|
||||
(key, resolve_overlap(entity, 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 {
|
||||
for (other_entity_key, move_resolution) in overlap_resolutions {
|
||||
match move_resolution {
|
||||
OverlapResolution::Pickup => {
|
||||
animations.push(AnimationInstruction::Attach(
|
||||
entity_key,
|
||||
other,
|
||||
entity_to_update_key,
|
||||
other_entity_key,
|
||||
self.map
|
||||
.get(other)
|
||||
.get(other_entity_key)
|
||||
.and_then(|x| x.pickup_sound_effect()),
|
||||
));
|
||||
let other = self.map.remove(other).unwrap();
|
||||
let other = self.map.remove(other_entity_key).unwrap();
|
||||
|
||||
if let Some((location, dropped)) =
|
||||
self.map.get_mut(entity_key).and_then(|x| {
|
||||
self.map.get_mut(entity_to_update_key).and_then(|x| {
|
||||
x.pickup(other.entity).map(|y| (x.location, y))
|
||||
})
|
||||
{
|
||||
|
@ -230,11 +220,9 @@ impl EntityMap {
|
|||
});
|
||||
|
||||
animations.push(AnimationInstruction::Detatch(
|
||||
entity_key,
|
||||
entity_to_update_key,
|
||||
new_key,
|
||||
self.map
|
||||
.get(new_key)
|
||||
.and_then(|x| x.drop_effect()),
|
||||
self.map.get(new_key).and_then(|x| x.drop_effect()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -254,22 +242,31 @@ impl EntityMap {
|
|||
}
|
||||
}
|
||||
OverlapResolution::Die => {
|
||||
// already handled
|
||||
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,
|
||||
entity_to_update_key,
|
||||
direction,
|
||||
if explicit_stay_put {
|
||||
self.map
|
||||
.get(entity_key)
|
||||
.get(entity_to_update_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())
|
||||
self.map
|
||||
.get(entity_to_update_key)
|
||||
.and_then(|e| e.fake_out_effect())
|
||||
})
|
||||
},
|
||||
));
|
||||
|
@ -277,7 +274,6 @@ impl EntityMap {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(
|
||||
if hero_has_died {
|
||||
|
@ -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<SoundEffect> {
|
||||
None
|
||||
}
|
||||
|
||||
fn kill_sound_effect(&self) -> Option<SoundEffect> {
|
||||
match self.holding() {
|
||||
Some(EntityType::Item(Item::Sword)) => Some(SoundEffect::SwordKill),
|
||||
|
@ -719,6 +707,7 @@ impl From<level::Item> for EntityType {
|
|||
direction: Direction::Down,
|
||||
holding: None,
|
||||
})),
|
||||
level::Item::Ice => EntityType::Ice,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ named_tag!(
|
|||
SQUID_DOWN,
|
||||
SQUID_UP_SHADOW,
|
||||
SQUID_DOWN_SHADOW,
|
||||
ICE,
|
||||
]
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in a new issue