diff options
| -rw-r--r-- | dungeon/src/entity.rs | 5 | ||||
| -rw-r--r-- | dungeon/src/lib.rs | 50 | ||||
| -rw-r--r-- | dungeon/src/player_input.rs | 9 | ||||
| -rw-r--r-- | game/src/lib.rs | 36 | ||||
| -rw-r--r-- | graphics/src/lib.rs | 34 | ||||
| -rw-r--r-- | graphics/src/render.rs | 47 |
6 files changed, 145 insertions, 36 deletions
diff --git a/dungeon/src/entity.rs b/dungeon/src/entity.rs index a0750dd..9af27bd 100644 --- a/dungeon/src/entity.rs +++ b/dungeon/src/entity.rs @@ -337,6 +337,7 @@ pub struct Player { pub weapon: Weapon, // How long until we reset potion effects? pub potion_timer: Option<Instant>, + pub active_inv_slot: usize, } impl Player { /// Instantiates the game player at a given `Pos` @@ -354,11 +355,13 @@ impl Player { let inventory = vec![]; let weapon = Weapon::RustyKnife; let potion_timer = None; + let active_inv_slot = 0; Self { entity, inventory, weapon, potion_timer, + active_inv_slot, } } } @@ -517,7 +520,7 @@ impl Dungeon { }; updater.update_entity(&mut self.player.entity); - for enemy in &mut self.enemies { + for enemy in &mut self.entities { updater.update_entity(enemy); } } diff --git a/dungeon/src/lib.rs b/dungeon/src/lib.rs index 13ab397..0076f26 100644 --- a/dungeon/src/lib.rs +++ b/dungeon/src/lib.rs @@ -15,11 +15,11 @@ use std::time::Instant; use rand::{Rng, SeedableRng, TryRngCore, rngs::OsRng}; use crate::{ - entity::{Entity, Player}, + entity::{Entity, EntityKind, PLAYER_INVENTORY_SIZE_USIZE, Player}, map::{Floor, Tile}, msg::Message, player_input::PlayerInput, - pos::FPos, + pos::{Direction, FPos}, rng::DungeonRng, }; @@ -43,7 +43,7 @@ pub enum UpdateResult { pub struct Dungeon { pub floor: Floor, pub player: Player, - pub enemies: Vec<Entity>, + pub entities: Vec<Entity>, pub msg: Message, seed: u64, level_rng: DungeonRng, @@ -66,12 +66,12 @@ impl Dungeon { let mut level_rng = DungeonRng::seed_from_u64(game_rng.random()); let floor = bsp::generate(&mut level_rng); let player = Player::new(floor.player_start()); - let enemies = vec![]; + let entities = vec![]; let msg = Message::empty(); let mut dungeon = Self { floor, player, - enemies, + entities, msg, seed, level_rng, @@ -121,12 +121,13 @@ impl Dungeon { UpdateResult::MessageUpdated(changed) } else { self.update_entities(player_input, delta_time); - self.update_player(); + self.update_player(player_input); if self.floor.get(self.player.entity.pos) == Tile::Stairs { // we are moving to a new floor self.floor = bsp::generate(&mut self.level_rng); self.player.entity.teleport(self.floor.player_start()); + self.entities.clear(); self.spawn_enimies(); return UpdateResult::NextFloor; } @@ -135,19 +136,50 @@ impl Dungeon { } } - fn update_player(&mut self) { + fn update_player(&mut self, player_input: PlayerInput) { + // update potion timer if let Some(timer) = self.player.potion_timer && Instant::now() > timer { self.player.potion_timer = None; self.player.entity.speed = self.player.entity.kind.initial_speed(); } + + // use item + if player_input.use_item + && self.player.active_inv_slot < self.player.inventory.len() + { + let item = self.player.inventory.remove(self.player.active_inv_slot); + item.consume(self); + } + + // TODO: attack + + // check for drop input + if player_input.drop && self.player.active_inv_slot < self.player.inventory.len() { + let item = self.player.inventory.remove(self.player.active_inv_slot); + self.entities.push(Entity::new( + self.player.entity.pos, + Direction::East, + EntityKind::Item(item), + )); + self.player.active_inv_slot = self + .player + .active_inv_slot + .max(self.player.inventory.len().saturating_sub(1)); + } + + // check for inv slot request + if let Some(slot) = player_input.inv_slot + && slot < PLAYER_INVENTORY_SIZE_USIZE + { + self.player.active_inv_slot = slot; + } } fn spawn_enimies(&mut self) { // TODO: better entity spawning let zombie = Entity::zombie(self.floor.random_walkable_pos(&mut self.level_rng)); - self.enemies.clear(); - self.enemies.push(zombie); + self.entities.push(zombie); } } diff --git a/dungeon/src/player_input.rs b/dungeon/src/player_input.rs index ddaad9f..7fe85c3 100644 --- a/dungeon/src/player_input.rs +++ b/dungeon/src/player_input.rs @@ -15,5 +15,12 @@ pub struct PlayerInput { /// If the player is currently attempting to interact /// with some object, entity, etc. pub interact: bool, - // other player actions are to be added later + /// If the player wants to use an item + pub use_item: bool, + /// If the player is currently attempting to attack + pub attack: bool, + /// If the player is attempting to drop an item + pub drop: bool, + /// If the player is attempting to switch the active inv slot + pub inv_slot: Option<usize>, } diff --git a/game/src/lib.rs b/game/src/lib.rs index 77942b4..f123326 100644 --- a/game/src/lib.rs +++ b/game/src/lib.rs @@ -1,4 +1,7 @@ -use dungeon::{Dungeon, UpdateResult, player_input::PlayerInput, pos::Direction}; +use dungeon::{ + Dungeon, UpdateResult, entity::PLAYER_INVENTORY_SIZE, player_input::PlayerInput, + pos::Direction, +}; use graphics::{Key, Window}; pub struct Game { @@ -57,6 +60,26 @@ impl Game { None } + fn get_player_input(&mut self) -> PlayerInput { + let direction = self.player_dir(); + let interact = self.window.is_key_pressed(Key::Return); + let use_item = self.window.is_key_pressed(Key::E); + let attack = self.window.is_key_pressed(Key::F); + let drop = self.window.is_key_pressed(Key::Q); + let inv_slot = (0..PLAYER_INVENTORY_SIZE) + .filter_map(|u16| u8::try_from(u16).ok()) + .find(|u8| self.window.is_key_pressed(Key::Number(*u8 + 1))) + .map(|u8| u8 as usize); + PlayerInput { + direction, + interact, + use_item, + attack, + drop, + inv_slot, + } + } + pub fn run(&mut self) { // Main game loop while self.window.is_open() { @@ -70,12 +93,8 @@ impl Game { .set_message("Lorem ipsum dolor sit amet consectetur adipiscing elit"); } - let inputs = PlayerInput { - direction: self.player_dir(), - interact: self.window.is_key_pressed(Key::Return), - }; - // Update game state + let inputs = self.get_player_input(); let result = self .dungeon .update(inputs, self.window.delta_time().as_secs_f32()); @@ -91,11 +110,6 @@ impl Game { } } - // Update on screen message - if self.dungeon.msg.update(inputs) { - self.window.audio().speak.play(); - } - // Draw a single frame self.window.draw_frame(&self.dungeon); } diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs index 0fdcedb..02eb97f 100644 --- a/graphics/src/lib.rs +++ b/graphics/src/lib.rs @@ -34,6 +34,11 @@ pub enum Key { Right, // Interact Return, + E, + F, + Q, + // Number + Number(u8), // Debug keys F3, F4, @@ -56,6 +61,20 @@ impl From<KeyboardKey> for Key { K::KEY_RIGHT => Self::Right, // Interact K::KEY_ENTER => Self::Return, + K::KEY_E => Self::E, + K::KEY_F => Self::F, + K::KEY_Q => Self::Q, + // Number + K::KEY_ZERO | K::KEY_KP_0 => Self::Number(0), + K::KEY_ONE | K::KEY_KP_1 => Self::Number(1), + K::KEY_TWO | K::KEY_KP_2 => Self::Number(2), + K::KEY_THREE | K::KEY_KP_3 => Self::Number(3), + K::KEY_FOUR | K::KEY_KP_4 => Self::Number(4), + K::KEY_FIVE | K::KEY_KP_5 => Self::Number(5), + K::KEY_SIX | K::KEY_KP_6 => Self::Number(6), + K::KEY_SEVEN | K::KEY_KP_7 => Self::Number(7), + K::KEY_EIGHT | K::KEY_KP_8 => Self::Number(8), + K::KEY_NINE | K::KEY_KP_9 => Self::Number(9), // Debug keys K::KEY_F3 => Self::F3, K::KEY_F4 => Self::F4, @@ -79,6 +98,21 @@ impl From<Key> for KeyboardKey { Key::Right => Self::KEY_RIGHT, // Interact Key::Return => Self::KEY_ENTER, + Key::E => Self::KEY_E, + Key::F => Self::KEY_F, + Key::Q => Self::KEY_Q, + // Number + Key::Number(0) => Self::KEY_ZERO, + Key::Number(1) => Self::KEY_ONE, + Key::Number(2) => Self::KEY_TWO, + Key::Number(3) => Self::KEY_THREE, + Key::Number(4) => Self::KEY_FOUR, + Key::Number(5) => Self::KEY_FIVE, + Key::Number(6) => Self::KEY_SIX, + Key::Number(7) => Self::KEY_SEVEN, + Key::Number(8) => Self::KEY_EIGHT, + Key::Number(9) => Self::KEY_NINE, + Key::Number(_) => Self::KEY_NULL, // Debug keys Key::F3 => Self::KEY_F3, Key::F4 => Self::KEY_F4, diff --git a/graphics/src/render.rs b/graphics/src/render.rs index 5841a7b..89f9dc3 100644 --- a/graphics/src/render.rs +++ b/graphics/src/render.rs @@ -331,6 +331,7 @@ impl Renderer { ys, TEXTURE_SIZE, 0.0, + Color::WHITE, ); // draw top wall borders @@ -344,6 +345,7 @@ impl Renderer { ys, TEXTURE_SIZE, 0.0, + Color::WHITE, ); } if !is_wall(Direction::East) { @@ -354,6 +356,7 @@ impl Renderer { ys, TEXTURE_SIZE, 90.0, + Color::WHITE, ); } if !is_wall(Direction::South) { @@ -364,6 +367,7 @@ impl Renderer { ys, TEXTURE_SIZE, 180.0, + Color::WHITE, ); } if !is_wall(Direction::West) { @@ -374,6 +378,7 @@ impl Renderer { ys, TEXTURE_SIZE, 270.0, + Color::WHITE, ); } } @@ -404,6 +409,7 @@ impl Renderer { y * TEXTURE_SIZE, TEXTURE_SIZE, 0.0, + Color::WHITE, ); if idx == ATLAS_FLOOR { // add possible extentions @@ -424,6 +430,7 @@ impl Renderer { y * TEXTURE_SIZE, TEXTURE_SIZE, 0.0, + Color::WHITE, ); } } @@ -478,10 +485,10 @@ impl Renderer { where R: RaylibDraw, { - self.draw_entity(r, &dungeon.player.entity); - for enemy in &dungeon.enemies { + for enemy in &dungeon.entities { self.draw_entity(r, enemy); } + self.draw_entity(r, &dungeon.player.entity); } /// Draws an entity @@ -519,6 +526,7 @@ impl Renderer { dest_rec.y - WALL_HEIGHT as f32, size, 0.0, + Color::WHITE, ); if self.debug { @@ -592,9 +600,15 @@ impl Renderer { ); }; - // Draw enemy dots - for enemy in &dungeon.enemies { - draw_dot(enemy.pos, Color::RED); + // Draw entity dots + for entity in &dungeon.entities { + use EntityKind as K; + let color = match entity.kind { + K::Player => Color::LIME, + K::Zombie(_) => Color::RED, + K::Item(_) => Color::TURQUOISE, + }; + draw_dot(entity.pos, color); } // Draw player dot @@ -630,6 +644,11 @@ impl Renderer { let slot_x = SLOTS_X + SLOT_LEN * idx; // Draw slot container + let tint = if (idx as usize) == player.active_inv_slot { + Color::YELLOW + } else { + Color::WHITE + }; r.draw_atlas( &self.textures.atlas, ATLAS_INV_CONTAINER, @@ -637,6 +656,7 @@ impl Renderer { UI_PADDING, SLOT_LEN, 0.0, + tint, ); if let Some(item) = player.inventory.get(idx as usize) { @@ -682,6 +702,7 @@ impl Renderer { HEART_Y, ICON_WIDTH, 0.0, + Color::WHITE, ); draw_text!(self, r, TEXT_X, HEART_Y, "x{health:02}"); @@ -694,6 +715,7 @@ impl Renderer { DAMAGE_Y, ICON_WIDTH, 0.0, + Color::WHITE, ); draw_text!(self, r, TEXT_X, DAMAGE_Y, "x{damage:02}"); } @@ -830,6 +852,7 @@ impl Renderer { y, FONT_SIZE, 0.0, + Color::WHITE, ); } } @@ -886,6 +909,8 @@ where Self: RaylibDraw, { /// Draw an atlas texture index + #[inline] + #[expect(clippy::too_many_arguments)] fn draw_atlas( &mut self, tex: &Texture2D, @@ -894,6 +919,7 @@ where y: impl Into<f32>, size: impl Into<f32>, rotation: impl Into<f32>, + tint: Color, ) { let size_into = size.into(); let source_rec = rect! { @@ -912,14 +938,7 @@ where dest_rec.width / 2.0, dest_rec.height / 2.0, }; - self.draw_texture_pro( - tex, - source_rec, - dest_rec, - origin, - rotation.into(), - Color::WHITE, - ); + self.draw_texture_pro(tex, source_rec, dest_rec, origin, rotation.into(), tint); } /// Draw dungeon tiles helper function @@ -961,7 +980,7 @@ where } fn draw_pathing_deug(&mut self, dungeon: &Dungeon) { - for enemy in &dungeon.enemies { + for enemy in &dungeon.entities { let Some(ai) = enemy.get_ai() else { continue; }; |