diff options
Diffstat (limited to 'dungeon/src/entity.rs')
| -rw-r--r-- | dungeon/src/entity.rs | 155 |
1 files changed, 143 insertions, 12 deletions
diff --git a/dungeon/src/entity.rs b/dungeon/src/entity.rs index da807c2..d6ca7e5 100644 --- a/dungeon/src/entity.rs +++ b/dungeon/src/entity.rs @@ -8,7 +8,7 @@ use std::{ use rand::Rng; use crate::{ - Dungeon, astar, const_pos, + Dungeon, PlayerAction, astar, const_pos, map::Floor, player_input::PlayerInput, pos::{Direction, FPos, Pos}, @@ -46,24 +46,23 @@ pub enum Item { LargeBomb, } impl Item { - pub fn consume(self, dungeon: &mut Dungeon) { + pub fn consume(self, player: &mut Player, floor: &mut Floor) { match self { Self::HeartFragment => { - dungeon.player.entity.heal(1); + player.entity.heal(1); } Self::HealthPotion => { - dungeon.player.entity.heal(3); + player.entity.heal(3); } Self::SpeedPotion => { - dungeon.player.potion_timer = - Instant::now().checked_add(Duration::from_secs(5)); - dungeon.player.entity.speed = dungeon.player.entity.speed.inc(); + player.potion_timer = Instant::now().checked_add(Duration::from_secs(5)); + player.entity.speed = player.entity.speed.inc(); } Self::Bomb => { - dungeon.floor.explode(dungeon.player.entity.pos, 1); + floor.explode(player.entity.pos, 1); } Self::LargeBomb => { - dungeon.floor.explode(dungeon.player.entity.pos, 2); + floor.explode(player.entity.pos, 2); } } } @@ -330,6 +329,14 @@ impl Entity { pub const fn is_alive(&self) -> bool { !self.is_dead() } + + /// Returns the item in the entity (if this entity is an item) + pub const fn get_item(&self) -> Option<Item> { + match &self.kind { + EntityKind::Item(item) => Some(*item), + _ => None, + } + } } /// The current "weapon" level we have @@ -360,6 +367,7 @@ pub struct Player { // How long until we reset potion effects? pub potion_timer: Option<Instant>, pub active_inv_slot: usize, + pub last_drop_time: Instant, } impl Player { /// Instantiates the game player at a given `Pos` @@ -372,18 +380,20 @@ impl Player { /// let pos = Pos::new(1, 2).unwrap(); /// let player = Player::new(pos); /// ``` - pub const fn new(pos: Pos) -> Self { + pub fn new(pos: Pos) -> Self { let entity = Entity::player(pos); let inventory = vec![]; let weapon = Weapon::RustyKnife; let potion_timer = None; let active_inv_slot = 0; + let last_drop_time = Instant::now(); Self { entity, inventory, weapon, potion_timer, active_inv_slot, + last_drop_time, } } } @@ -395,7 +405,7 @@ impl Default for Player { } struct Updater<'a> { - floor: &'a Floor, + floor: &'a mut Floor, rng: &'a mut DungeonRng, player_pos: Pos, input: PlayerInput, @@ -530,11 +540,104 @@ impl Updater<'_> { entity.dir = dir; } } + + /// Update player potion timer + fn update_player_potion_effects(player: &mut Player) { + if let Some(timer) = player.potion_timer + && Instant::now() > timer + { + player.potion_timer = None; + player.entity.speed = player.entity.kind.initial_speed(); + } + } + + /// Handle player "Use Item" + fn handle_player_use_item(&mut self, player: &mut Player, action: &mut PlayerAction) { + if self.input.use_item && player.active_inv_slot < player.inventory.len() { + let item = player.inventory.remove(player.active_inv_slot); + action.potion = item.is_potion(); + action.bomb = item.is_bomb(); + item.consume(player, self.floor); + } + } + + /// Handle player "Drop Item" + fn handle_player_drop_item( + &self, + player: &mut Player, + action: &mut PlayerAction, + entities: &mut Vec<Entity>, + ) { + if self.input.drop && player.active_inv_slot < player.inventory.len() { + let item = player.inventory.remove(player.active_inv_slot); + entities.push(Entity::new( + player.entity.pos, + Direction::East, + EntityKind::Item(item), + )); + player.active_inv_slot = player + .active_inv_slot + .max(player.inventory.len().saturating_sub(1)); + action.drop_item = true; + player.last_drop_time = Instant::now(); + } + } + + /// Handle player "Attack" + const fn handle_player_attack(&self, _player: &mut Player, action: &mut PlayerAction) { + if self.input.attack { + // TODO: attack + action.attack = true; + } + } + + /// Handle player "Pickup Items" + fn handle_player_pickup_items( + player: &mut Player, + action: &mut PlayerAction, + entities: &mut Vec<Entity>, + ) { + if player.last_drop_time.elapsed() < Duration::from_secs(3) { + // delay picking up dropped items + return; + } + + let mut idx = 0; + loop { + if idx >= entities.len() { + break; + } + if entities[idx].fpos.abs_diff(player.entity.fpos).magnitude() >= 0.25 { + idx += 1; + continue; + } + let Some(item) = entities[idx].get_item() else { + idx += 1; + continue; + }; + if player.inventory.len() < PLAYER_INVENTORY_SIZE_USIZE { + entities.remove(idx); + player.inventory.push(item); + action.pickup_item = true; + } else { + idx += 1; + } + } + } + + /// Handle player "Change INV Slot" + const fn handle_player_inv_slot(&self, player: &mut Player) { + if let Some(slot) = self.input.inv_slot + && slot < PLAYER_INVENTORY_SIZE_USIZE + { + player.active_inv_slot = slot; + } + } } impl Dungeon { pub(crate) fn update_entities(&mut self, input: PlayerInput, delta_time: f32) { let mut updater = Updater { - floor: &self.floor, + floor: &mut self.floor, rng: &mut self.game_rng, player_pos: self.player.entity.pos, input, @@ -551,4 +654,32 @@ impl Dungeon { } self.entities.retain(Entity::is_alive); } + + pub(crate) fn update_player( + &mut self, + input: PlayerInput, + delta_time: f32, + ) -> PlayerAction { + let mut updater = Updater { + floor: &mut self.floor, + rng: &mut self.game_rng, + player_pos: self.player.entity.pos, + input, + delta_time, + }; + + let mut action = PlayerAction::default(); + Updater::update_player_potion_effects(&mut self.player); + updater.handle_player_use_item(&mut self.player, &mut action); + updater.handle_player_drop_item(&mut self.player, &mut action, &mut self.entities); + Updater::handle_player_pickup_items( + &mut self.player, + &mut action, + &mut self.entities, + ); + updater.handle_player_attack(&mut self.player, &mut action); + updater.handle_player_inv_slot(&mut self.player); + + action + } } |