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 core::ops::Neg;
|
||||||
|
|
||||||
use agb::fixnum::Vector2D;
|
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 slotmap::{new_key_type, SlotMap};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -91,82 +91,85 @@ impl EntityMap {
|
||||||
|
|
||||||
let mut animations = Vec::new();
|
let mut animations = Vec::new();
|
||||||
|
|
||||||
let desired_actions: Vec<(EntityKey, Action)> = self
|
let mut entities_to_try_update = self
|
||||||
.map
|
.map
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(key, entity)| (key, entity.desired_action(map, self, hero)))
|
.map(|(key, entity)| (key, entity.desired_action(map, self, hero)))
|
||||||
.collect();
|
.collect::<VecDeque<_>>();
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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) => {
|
Action::Direction(direction) | Action::ChangeDirection(direction) => {
|
||||||
if matches!(action, Action::ChangeDirection(_)) {
|
if matches!(desired_action, Action::ChangeDirection(_)) {
|
||||||
if let Some(change) = self
|
// first change the direction before processing the rest of the instructions
|
||||||
|
if let Some((Some(change), change_effect)) = self
|
||||||
.map
|
.map
|
||||||
.get_mut(entity_key)
|
.get_mut(entity_to_update_key)
|
||||||
.and_then(|e| e.change_direction())
|
.map(|e| (e.change_direction(), e.change_effect()))
|
||||||
{
|
{
|
||||||
animations.push(AnimationInstruction::PriorityChange(
|
animations.push(AnimationInstruction::PriorityChange(
|
||||||
entity_key,
|
entity_to_update_key,
|
||||||
change,
|
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;
|
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);
|
let surface = map.get(desired_location);
|
||||||
if surface == MapElement::Wall {
|
if surface == MapElement::Wall {
|
||||||
let wall_resolution = resolve_wall_move(&entity.entity);
|
|
||||||
match wall_resolution {
|
|
||||||
WallResolution::StayPut => {
|
|
||||||
animations.push(AnimationInstruction::FakeOutMove(
|
animations.push(AnimationInstruction::FakeOutMove(
|
||||||
entity_key,
|
entity_to_update_key,
|
||||||
direction,
|
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 can_move = true;
|
||||||
let mut explicit_stay_put = false;
|
let mut explicit_stay_put = false;
|
||||||
let mut fake_out_effect = None;
|
let mut fake_out_effect = None;
|
||||||
|
|
||||||
for (other, resolution) in resolutions {
|
let move_attempt_resolutions: Vec<_> = self
|
||||||
match resolution {
|
.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 => {
|
MoveAttemptResolution::KillDie => {
|
||||||
hero_has_died |= self.kill_entity(other, &mut animations);
|
hero_has_died |=
|
||||||
hero_has_died |= self.kill_entity(entity_key, &mut animations);
|
self.kill_entity(other_entity_key, &mut animations);
|
||||||
|
hero_has_died |=
|
||||||
|
self.kill_entity(entity_to_update_key, &mut animations);
|
||||||
can_move = false;
|
can_move = false;
|
||||||
}
|
}
|
||||||
MoveAttemptResolution::Kill => {
|
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
|
fake_out_effect = self
|
||||||
.map
|
.map
|
||||||
.get(entity_key)
|
.get(entity_to_update_key)
|
||||||
.and_then(|x| x.kill_sound_effect());
|
.and_then(|x| x.kill_sound_effect());
|
||||||
can_move = false;
|
can_move = false;
|
||||||
}
|
}
|
||||||
MoveAttemptResolution::Die => {
|
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;
|
can_move = false;
|
||||||
}
|
}
|
||||||
MoveAttemptResolution::CoExist => {}
|
MoveAttemptResolution::CoExist => {}
|
||||||
|
@ -174,53 +177,40 @@ impl EntityMap {
|
||||||
can_move = false;
|
can_move = false;
|
||||||
explicit_stay_put = true;
|
explicit_stay_put = true;
|
||||||
}
|
}
|
||||||
|
MoveAttemptResolution::AttemptPush => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(can_move, explicit_stay_put, fake_out_effect)
|
||||||
|
};
|
||||||
|
|
||||||
if can_move {
|
if can_move {
|
||||||
if let Some(e) = self.map.get_mut(entity_key) {
|
let Some(entity_to_update) = self.map.get(entity_to_update_key) else {
|
||||||
e.location = desired_location;
|
|
||||||
}
|
|
||||||
let Some(entity) = &self.map.get(entity_key) else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
animations.push(AnimationInstruction::Move(
|
|
||||||
entity_key,
|
|
||||||
desired_location,
|
|
||||||
entity.move_effect(),
|
|
||||||
));
|
|
||||||
|
|
||||||
let overlap_resolutions: Vec<_> = self
|
let overlap_resolutions: Vec<_> = self
|
||||||
.whats_at(desired_location)
|
.whats_at(desired_location)
|
||||||
.filter(|(k, _)| *k != entity_key)
|
.filter(|(k, _)| *k != entity_to_update_key)
|
||||||
.map(|(key, other_entity)| {
|
.map(|(key, other_entity)| {
|
||||||
(key, resolve_overlap(entity, other_entity))
|
(key, resolve_overlap(entity_to_update, other_entity))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if overlap_resolutions
|
for (other_entity_key, move_resolution) in overlap_resolutions {
|
||||||
.iter()
|
match move_resolution {
|
||||||
.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 => {
|
OverlapResolution::Pickup => {
|
||||||
animations.push(AnimationInstruction::Attach(
|
animations.push(AnimationInstruction::Attach(
|
||||||
entity_key,
|
entity_to_update_key,
|
||||||
other,
|
other_entity_key,
|
||||||
self.map
|
self.map
|
||||||
.get(other)
|
.get(other_entity_key)
|
||||||
.and_then(|x| x.pickup_sound_effect()),
|
.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)) =
|
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))
|
x.pickup(other.entity).map(|y| (x.location, y))
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
|
@ -230,11 +220,9 @@ impl EntityMap {
|
||||||
});
|
});
|
||||||
|
|
||||||
animations.push(AnimationInstruction::Detatch(
|
animations.push(AnimationInstruction::Detatch(
|
||||||
entity_key,
|
entity_to_update_key,
|
||||||
new_key,
|
new_key,
|
||||||
self.map
|
self.map.get(new_key).and_then(|x| x.drop_effect()),
|
||||||
.get(new_key)
|
|
||||||
.and_then(|x| x.drop_effect()),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,22 +242,31 @@ impl EntityMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OverlapResolution::Die => {
|
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 {
|
} else {
|
||||||
animations.push(AnimationInstruction::FakeOutMove(
|
animations.push(AnimationInstruction::FakeOutMove(
|
||||||
entity_key,
|
entity_to_update_key,
|
||||||
direction,
|
direction,
|
||||||
if explicit_stay_put {
|
if explicit_stay_put {
|
||||||
self.map
|
self.map
|
||||||
.get(entity_key)
|
.get(entity_to_update_key)
|
||||||
.and_then(|e| e.fake_out_wall_effect())
|
.and_then(|e| e.fake_out_wall_effect())
|
||||||
} else {
|
} else {
|
||||||
fake_out_effect.or_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 {
|
if hero_has_died {
|
||||||
|
@ -298,22 +294,20 @@ enum MoveAttemptResolution {
|
||||||
KillDie,
|
KillDie,
|
||||||
CoExist,
|
CoExist,
|
||||||
StayPut,
|
StayPut,
|
||||||
|
AttemptPush,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||||
pub struct SwitchSystem(usize);
|
pub struct SwitchSystem(usize);
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
enum OverlapResolution {
|
enum OverlapResolution {
|
||||||
Pickup,
|
Pickup,
|
||||||
CoExist,
|
CoExist,
|
||||||
Win,
|
Win,
|
||||||
ToggleSystem(SwitchSystem),
|
ToggleSystem(SwitchSystem),
|
||||||
Die,
|
Die,
|
||||||
}
|
MoveAgain,
|
||||||
|
|
||||||
enum WallResolution {
|
|
||||||
StayPut,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_spikes(switable: &Switchable) -> OverlapResolution {
|
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::Spikes(switch)) => resolve_spikes(switch),
|
||||||
(_, EntityType::Switch(switch)) => OverlapResolution::ToggleSystem(switch.system),
|
(_, EntityType::Switch(switch)) => OverlapResolution::ToggleSystem(switch.system),
|
||||||
(_, EntityType::Enemy(_) | EntityType::Hero(_)) => OverlapResolution::Die,
|
(_, EntityType::Enemy(_) | EntityType::Hero(_)) => OverlapResolution::Die,
|
||||||
|
(_, EntityType::Ice) => OverlapResolution::MoveAgain,
|
||||||
|
|
||||||
_ => OverlapResolution::CoExist,
|
_ => OverlapResolution::CoExist,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_wall_move(_entity: &EntityType) -> WallResolution {
|
|
||||||
WallResolution::StayPut
|
|
||||||
}
|
|
||||||
|
|
||||||
fn holding_attack_resolve(holding: Option<&EntityType>) -> MoveAttemptResolution {
|
fn holding_attack_resolve(holding: Option<&EntityType>) -> MoveAttemptResolution {
|
||||||
match holding {
|
match holding {
|
||||||
Some(&EntityType::Item(Item::Sword)) => MoveAttemptResolution::Kill,
|
Some(&EntityType::Item(Item::Sword)) => MoveAttemptResolution::Kill,
|
||||||
|
@ -438,6 +429,7 @@ pub enum EntityType {
|
||||||
SwitchedDoor(Switchable),
|
SwitchedDoor(Switchable),
|
||||||
Switch(Switchable),
|
Switch(Switchable),
|
||||||
Spikes(Switchable),
|
Spikes(Switchable),
|
||||||
|
Ice,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -577,10 +569,6 @@ impl Entity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_effect(&self) -> Option<SoundEffect> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn kill_sound_effect(&self) -> Option<SoundEffect> {
|
fn kill_sound_effect(&self) -> Option<SoundEffect> {
|
||||||
match self.holding() {
|
match self.holding() {
|
||||||
Some(EntityType::Item(Item::Sword)) => Some(SoundEffect::SwordKill),
|
Some(EntityType::Item(Item::Sword)) => Some(SoundEffect::SwordKill),
|
||||||
|
@ -719,6 +707,7 @@ impl From<level::Item> for EntityType {
|
||||||
direction: Direction::Down,
|
direction: Direction::Down,
|
||||||
holding: None,
|
holding: None,
|
||||||
})),
|
})),
|
||||||
|
level::Item::Ice => EntityType::Ice,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ pub enum Item {
|
||||||
SpikesDown,
|
SpikesDown,
|
||||||
SquidUp,
|
SquidUp,
|
||||||
SquidDown,
|
SquidDown,
|
||||||
|
Ice,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item {
|
impl Item {
|
||||||
|
@ -37,6 +38,7 @@ impl Item {
|
||||||
Item::SpikesDown => resources::SPIKES_OFF,
|
Item::SpikesDown => resources::SPIKES_OFF,
|
||||||
Item::SquidUp => resources::SQUID_UP_SHADOW,
|
Item::SquidUp => resources::SQUID_UP_SHADOW,
|
||||||
Item::SquidDown => resources::SQUID_DOWN_SHADOW,
|
Item::SquidDown => resources::SQUID_DOWN_SHADOW,
|
||||||
|
Item::Ice => resources::ICE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +58,7 @@ impl Item {
|
||||||
Item::SpikesDown => resources::SPIKES_OFF,
|
Item::SpikesDown => resources::SPIKES_OFF,
|
||||||
Item::SquidUp => resources::SQUID_UP,
|
Item::SquidUp => resources::SQUID_UP,
|
||||||
Item::SquidDown => resources::SQUID_DOWN,
|
Item::SquidDown => resources::SQUID_DOWN,
|
||||||
|
Item::Ice => resources::ICE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +81,7 @@ impl Item {
|
||||||
Item::SpikesDown => ZERO,
|
Item::SpikesDown => ZERO,
|
||||||
Item::SquidUp => STANDARD,
|
Item::SquidUp => STANDARD,
|
||||||
Item::SquidDown => STANDARD,
|
Item::SquidDown => STANDARD,
|
||||||
|
Item::Ice => ZERO,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ named_tag!(
|
||||||
SQUID_DOWN,
|
SQUID_DOWN,
|
||||||
SQUID_UP_SHADOW,
|
SQUID_UP_SHADOW,
|
||||||
SQUID_DOWN_SHADOW,
|
SQUID_DOWN_SHADOW,
|
||||||
|
ICE,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue