diff --git a/src/main.rs b/src/main.rs index 6f0f7e7..8cce418 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ mod mobs; mod map; mod progen; mod item; // Import the item module +mod ui_component; use bracket_lib::{prelude::*, color}; use entity::Entity; @@ -68,7 +69,7 @@ impl GameState for State { ctx.quitting = true; } - self.player.update(ctx, &mut self.map); + self.player.update(ctx, &mut self.map, &mut self.ui); ctx.cls(); self.ui.add_message("Hello world!"); diff --git a/src/player.rs b/src/player.rs index c51aee2..73d03d6 100644 --- a/src/player.rs +++ b/src/player.rs @@ -2,27 +2,44 @@ use bracket_lib::prelude::*; use crate::entity::Entity; +use crate::item::Item; use crate::map::{Map, self, TileType}; +use crate::ui::{UI, PopupWindow}; + pub struct Player { entity: Entity, pub hp: i32, pub max_hp: i32, pub score: i32, pub hunger: i32, - pub thirst: i32 + pub thirst: i32, + pub inventory: Vec, } impl Player { pub fn new(x: i32, y: i32) -> Self { let entity = Entity::new(x, y, to_cp437('@'), YELLOW, BLACK); - Player { entity, hp: 100, max_hp: 100, score: 0, hunger: 100, thirst: 100 } + let mut inv = Vec::new(); + + //push some items to the inventory + inv.push(Item::new(0, 0, "data/items/drink/Milk.json").unwrap()); + inv.push(Item::new(0, 0, "data/items/books/The_Bible.json").unwrap()); + Player { + entity, + hp: 100, + max_hp: 100, + score: 0, + hunger: 100, + thirst: 100, + inventory: inv, + } } pub fn draw(&self, ctx: &mut BTerm) { self.entity.draw(ctx); } - pub fn update(&mut self, ctx: &mut BTerm, map: &Map) { + pub fn update(&mut self, ctx: &mut BTerm, map: &Map, ui: &mut UI) { // Handle player movement if let Some(key) = ctx.key { match key { @@ -34,13 +51,14 @@ impl Player { VirtualKeyCode::Numpad9 => self.move_by(1, -1, map), VirtualKeyCode::Numpad1 => self.move_by(-1, 1, map), VirtualKeyCode::Numpad3 => self.move_by(1, 1, map), + VirtualKeyCode::E => self.open_inventory(ui), _ => {} } } } fn move_by(&mut self, dx: i32, dy: i32, map: &Map) { - //wall at were moving, dont move + // Wall at where we're moving, don't move if map.get_tile(self.entity.x + dx, self.entity.y + dy) == TileType::Wall { return; } @@ -50,5 +68,14 @@ impl Player { self.entity.y += dy; } - // Add player-specific methods and behaviors here + fn open_inventory(&self, ui: &mut UI) { + let mut inventory_popup = PopupWindow::new(10, 10, 40, 20, "Inventory"); + + // Add inventory items to the popup content + for item in &self.inventory { + inventory_popup.add_content(&item.data.name); + } + + ui.popup_windows.push(inventory_popup); + } } diff --git a/src/ui.rs b/src/ui.rs index 6c6d6c0..2d5df9e 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -7,13 +7,15 @@ use crate::player::Player; const MESSAGE_LOG_MAX_LINES: usize = 5; // Maximum lines in the message log pub struct UI { - message_log: Vec, + pub message_log: Vec, + pub popup_windows: Vec, } impl UI { pub fn new() -> Self { UI { message_log: Vec::new(), + popup_windows: Vec::new(), } } @@ -27,6 +29,23 @@ impl UI { } } + pub fn create_popup(&mut self, x: i32, y: i32, width: i32, height: i32, title: &str) { + let popup = PopupWindow::new(x, y, width, height, title); + self.popup_windows.push(popup); + } + + pub fn update_popup_title(&mut self, index: usize, title: &str) { + if let Some(popup) = self.popup_windows.get_mut(index) { + popup.update_title(title); + } + } + + pub fn draw_popups(&self, ctx: &mut BTerm) { + for popup in &self.popup_windows { + popup.draw(ctx); + } + } + pub fn draw(&self, ctx: &mut BTerm, player: &Player) { // Draw message log with background ctx.draw_box( @@ -85,5 +104,60 @@ impl UI { RGB::named(BLACK), format!("thirst: {}", player.thirst), ); + + // Draw popup windows + self.draw_popups(ctx); + } + +} + +pub struct PopupWindow { + x: i32, + y: i32, + width: i32, + height: i32, + title: String, + content: Vec, +} + +impl PopupWindow { + pub fn new(x: i32, y: i32, width: i32, height: i32, title: &str) -> Self { + PopupWindow { + x, + y, + width, + height, + title: title.to_string(), + content: Vec::new(), + } + } + + pub fn add_content(&mut self, content: &str) { + self.content.push(content.to_string()); + } + + pub fn update_title(&mut self, title: &str) { + self.title = title.to_string(); + } + + pub fn draw(&self, ctx: &mut BTerm) { + // Draw popup window background + ctx.draw_box( + self.x, + self.y, + self.width, + self.height, + RGB::named(WHITE), + RGB::named(BLACK), + ); + + // Draw popup window title + ctx.print(self.x + 1, self.y + 1, &self.title); + + // Draw popup window content + for (i, line) in self.content.iter().enumerate() { + ctx.print(self.x + 3, self.y + 4 + i as i32, line); + } + } } diff --git a/src/ui_component.rs b/src/ui_component.rs new file mode 100644 index 0000000..200394a --- /dev/null +++ b/src/ui_component.rs @@ -0,0 +1,166 @@ +// ui.rs + +use bracket_lib::prelude::*; +use crate::player::Player; + +const MESSAGE_LOG_MAX_LINES: usize = 5; // Maximum lines in the message log + +pub struct UI { + message_log: Vec, + popup_windows: Vec, +} + +impl UI { + pub fn new() -> Self { + UI { + message_log: Vec::new(), + popup_windows: Vec::new(), + } + } + + pub fn add_message(&mut self, message: &str) { + self.message_log.push(message.to_owned()); + + // Remove oldest messages if log exceeds max lines + if self.message_log.len() > MESSAGE_LOG_MAX_LINES { + let num_to_remove = self.message_log.len() - MESSAGE_LOG_MAX_LINES; + self.message_log.drain(0..num_to_remove); + } + } + + pub fn create_popup(&mut self, x: i32, y: i32, width: i32, height: i32, title: &str) { + let popup = PopupWindow::new(x, y, width, height, title); + self.popup_windows.push(popup); + } + + pub fn update_popup_title(&mut self, index: usize, title: &str) { + if let Some(popup) = self.popup_windows.get_mut(index) { + popup.update_title(title); + } + } + + pub fn draw_popups(&self, ctx: &mut BTerm) { + for popup in &self.popup_windows { + popup.draw(ctx); + } + } + + pub fn draw(&self, ctx: &mut BTerm, player: &Player) { + // Draw message log with background + ctx.draw_box( + 0, + 43, + 79, + 6, + RGB::named(WHITE), + RGB::named(BLACK), + ); + for (i, message) in self.message_log.iter().enumerate() { + ctx.print(1, 44 + i as i32, message); + } + + // Draw player stats with background + ctx.draw_box( + 0, + 0, + 47, + 3, + RGB::named(WHITE), + RGB::named(BLACK), + ); + ctx.print_color( + 1, + 1, + RGB::named(WHITE), + RGB::named(BLACK), + "Player Stats:", + ); + ctx.print_color( + 1, + 2, + RGB::named(GREEN2), + RGB::named(BLACK), + format!("HP: {}/{}", player.hp, player.max_hp), + ); + ctx.print_color( + 13, + 2, + RGB::named(GOLD), + RGB::named(BLACK), + format!("score: {}", player.score), + ); + ctx.print_color( + 22, + 2, + RGB::named(WHEAT), + RGB::named(BLACK), + format!("hunger: {}", player.hunger), + ); + ctx.print_color( + 34, + 2, + RGB::named(CYAN), + RGB::named(BLACK), + format!("thirst: {}", player.thirst), + ); + + // Draw popup windows + self.draw_popups(ctx); + } +} + +pub struct PopupWindow { + x: i32, + y: i32, + width: i32, + height: i32, + title: String, + content: Vec, +} + +impl PopupWindow { + pub fn new(x: i32, y: i32, width: i32, height: i32, title: &str) -> Self { + PopupWindow { + x, + y, + width, + height, + title: title.to_string(), + content: Vec::new(), + } + } + + pub fn add_content(&mut self, content: &str) { + self.content.push(content.to_string()); + } + + pub fn update_title(&mut self, title: &str) { + self.title = title.to_string(); + } + + pub fn draw(&self, ctx: &mut BTerm) { + // Draw the popup window background + ctx.draw_box( + self.x, + self.y, + self.width, + self.height, + RGB::named(WHITE), + RGB::named(BLACK), + ); + + // Draw the title + ctx.print_color( + self.x + 1, + self.y, + RGB::named(WHITE), + RGB::named(BLACK), + &self.title, + ); + + // Draw content within the window + for (i, content) in self.content.iter().enumerate() { + ctx.print(self.x + 1, self.y + 1 + i as i32, content); + } + } +}