diff --git a/Cargo.lock b/Cargo.lock index 3fc26bb..75e743c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,6 +38,12 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + [[package]] name = "cassowary" version = "0.3.0" @@ -89,6 +95,7 @@ dependencies = [ "petgraph", "rand", "ratatui", + "whoami", ] [[package]] @@ -155,6 +162,15 @@ dependencies = [ "either", ] +[[package]] +name = "js-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.149" @@ -435,6 +451,80 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" + +[[package]] +name = "web-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "whoami" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index efafe13..0515c19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,5 @@ edition = "2021" ratatui = "0.24.0" crossterm = "0.27.0" rand = "0.8.5" -petgraph = "0.6.4" \ No newline at end of file +petgraph = "0.6.4" +whoami = "1.4.1" \ No newline at end of file diff --git a/src/game.rs b/src/game.rs index c94b746..fb87d4f 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,11 +1,12 @@ use crate::level::Level; use crate::player::Player; +use crate::position::Position; pub const LEVELS: usize = 2; pub struct Game<'game> { - pub player: &'game mut Player, - pub levels: Vec, + pub(crate) player: &'game mut Player, + pub(crate) levels: Vec, } impl Game<'_> { @@ -20,4 +21,11 @@ impl Game<'_> { levels: v, } } + + pub fn get_player(&self) -> &Player { + &self.player + } + pub fn get_mutable_player(&mut self) -> &mut Player { + &mut self.player + } } \ No newline at end of file diff --git a/src/level_widget.rs b/src/level_widget.rs new file mode 100644 index 0000000..77921f4 --- /dev/null +++ b/src/level_widget.rs @@ -0,0 +1,176 @@ +use ratatui::prelude::*; +use ratatui::widgets::Widget; + +use crate::game::Game; +use crate::artifacts::Artifact; +use crate::level::{Level, StructureElement}; + +const FG_BROWN: Color = Color::Rgb(186, 74, 0); + +//⌂ α Ω +pub struct LevelWidget<'a> { + pub game: &'a Game<'a>, +} + +impl LevelWidget<'_> { + fn set_cell(&self, buf: &mut Buffer, x: u16, y: u16, symbol: &str, fg: Color, bg: Color) { + buf. + get_mut(x, y). + set_symbol(symbol). + set_bg(bg). + set_fg(fg); + } + + fn calculate_wall(top: Option, right: Option, bottom: Option, left: Option) -> String { + let mut val = 0; + val += match top { + Some(n) => { + match n { + StructureElement::Wall => 1, + _ => 0 + } + } + None => 0 + }; + val += match right { + Some(n) => { + match n { + StructureElement::Wall => 2, + _ => 0 + } + } + None => 0 + }; + val += match bottom { + Some(n) => { + match n { + StructureElement::Wall => 4, + _ => 0 + } + } + None => 0 + }; + val += match left { + Some(n) => { + match n { + StructureElement::Wall => 8, + _ => 0 + } + } + None => 0 + }; + [ + "╋", "┃", "━", "┗", + "┃", "┃", "┏", "┣", + "━", "┛", "━", "┻", + "┓", "┫", "┳", "╋", + ][val].to_string() + } +} + +impl Widget for LevelWidget<'_> { + fn render(self, area: Rect, buf: &mut Buffer) { + let player= self.game.get_player(); + // let player = &mut self.game.player; + let player_pos = player.get_immutable_position(); + // let level: &Level = &self.game.levels[player_pos.get_level()]; + + let al: u16 = area.left(); + let at: u16 = area.top(); + + // draw the level elements + for x in al..area.right() { + for y in at..area.bottom() { +// let level_x = (x - al) as i16; +// let level_y = (y - at) as i16; +// match level.get_element(level_x, level_y) { +// (None, _) => {} +// (_, Some(e)) => { +// match e { +// Artifact::Chest { gold: _ } => { +// self.set_cell(buf, x, y, "⌂", Color::Black, Color::Gray); +// } +// } +// } +// (Some(e), _) => { +// match e { +// StructureElement::Wall => { +// let top = level.get_element(level_x, level_y - 1).0; +// let right = level.get_element(level_x + 1, level_y).0; +// let bottom = level.get_element(level_x, level_y + 1).0; +// let left = level.get_element(level_x - 1, level_y).0; +// let symbol = LevelWidget::calculate_wall(top, right, bottom, left); +// self.set_cell(buf, x, y, symbol.as_str(), FG_BROWN, Color::Gray); +// } +// StructureElement::Floor => { +// self.set_cell(buf, x, y, " ", FG_BROWN, Color::Gray); +// } +// StructureElement::StairDown => { +// self.set_cell(buf, x, y, ">", Color::Black, Color::Gray); +// } +// StructureElement::StairUp => { +// self.set_cell(buf, x, y, "<", Color::Black, Color::Gray); +// } +// StructureElement::Unknown => { +// self.set_cell(buf, x, y, "▒", Color::DarkGray, Color::Gray); +// } +// StructureElement::Start => { +// self.set_cell(buf, x, y, "α", Color::Black, Color::Gray); +// } +// StructureElement::End => { +// self.set_cell(buf, x, y, "Ω", Color::Black, Color::Gray); +// } +// } +// } +// } + } + } +// +// // draw player + let player_x = al + player_pos.get_x() as u16; + let player_y = at + player_pos.get_y() as u16; + self.set_cell(buf, player_x, player_y, "8", Color::Red, Color::Gray); + } +} + +#[test] +fn test_get_wall_symbol() { + let wall = Some(StructureElement::Wall); + // 0 + let s = LevelWidget::calculate_wall(None, None, None, None); + assert_eq!(s, "╋"); + // 15 + let s = LevelWidget::calculate_wall(wall, wall, wall, wall); + assert_eq!(s, "╋"); + + // 1 + let s = LevelWidget::calculate_wall(wall, None, None, None); + assert_eq!(s, "┃"); + // 5 + let s = LevelWidget::calculate_wall(wall, None, wall, None); + assert_eq!(s, "┃"); + // 4 + let s = LevelWidget::calculate_wall(None, None, wall, None); + assert_eq!(s, "┃"); + + // 2 + let s = LevelWidget::calculate_wall(None, wall, None, None); + assert_eq!(s, "━"); + // 10 + let s = LevelWidget::calculate_wall(None, wall, None, wall); + assert_eq!(s, "━"); + + // 9 + let s = LevelWidget::calculate_wall(wall, None, None, wall); + assert_eq!(s, "┛"); + // 3 + let s = LevelWidget::calculate_wall(wall, wall, None, None); + assert_eq!(s, "┗"); + // 6 + let s = LevelWidget::calculate_wall(None, wall, wall, None); + assert_eq!(s, "┏"); + // 12 + let s = LevelWidget::calculate_wall(None, None, wall, wall); + assert_eq!(s, "┓"); +} + diff --git a/src/main.rs b/src/main.rs index 203fb06..c4c7d9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,118 @@ +use std::io::{Result, stdout}; +use std::ops::Index; + +use crossterm::{ + event::{self, KeyCode, KeyEventKind}, + ExecutableCommand, + terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, +}; +use ratatui::{ + prelude::{CrosstermBackend, Stylize, Terminal}, + widgets::Paragraph, +}; +use ratatui::prelude::*; +use ratatui::widgets::Block; +use whoami::realname; + use crate::game::Game; +use crate::level::Level; +use crate::level_generator::LevelGenerator; +use crate::level_widget::LevelWidget; use crate::player::Player; mod game; mod player; mod level; mod position; -mod monster; -mod artifacts; +mod level_widget; mod level_generator; +mod artifacts; +mod monster; -fn main() { - let mut p = Player::new("Teddy Tester", 10); - let g = Game::new(&mut p); +fn main() -> Result<()> { + let mut levels = Vec::new(); - println!("{}",g.player.get_name()); - println!("{}",g.player.get_life()); - g.player.change_life(-1); - println!("{}",g.player.get_life()); + for l in 0..25 { + levels.push(LevelGenerator::generate(l).render()); + } + let mut g = Game { + player: &mut Player::new(realname().as_str(), 10), + levels, + }; + + // let first_level = g.levels.index(0); + // g.get_mutable_player().get_position().change(first_level.start.0 as i16, first_level.start.1 as i16); + + stdout().execute(EnterAlternateScreen)?; + enable_raw_mode()?; + let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?; + terminal.clear()?; + + loop { + terminal.draw(|frame| { + let mut area = frame.size(); + frame.render_widget(Block::default().style(Style::default().bg(Color::Green)), area); + + if area.width > 80 { + area.x = (area.width - 80) / 2; + area.width = 80; + } + if area.height > 25 { + area.y = (area.height - 25) / 2; + area.height = 25; + } + + let map_area = Rect { + x: area.x, + y: area.y, + width: level::LEVEL_WIDTH as u16, + height: level::LEVEL_HEIGHT as u16, + }; + frame.render_widget(LevelWidget { game: &g }, map_area); + + let stats_area = Rect { + x: area.x + 50, + y: area.y, + width: 30, + height: 25, + }; + frame.render_widget( + Paragraph::new(format!("{}\nHealth: {}/{}\nGold: {}\nLevel: {}", + g.get_player().get_name(), + g.get_player().get_life(), + g.get_player().get_max_life(), + g.get_player().get_gold(), + g.get_player().get_immutable_position().get_level())) + .white() + .on_blue(), + stats_area, + ); + })?; + if event::poll(std::time::Duration::from_millis(16))? { + if let event::Event::Key(key) = event::read()? { + if key.kind == KeyEventKind::Press && key.code == KeyCode::Char('q') { + break; + } + // if key.kind == KeyEventKind::Press && key.code == KeyCode::Char('d') { + // ; + // } + if key.kind == KeyEventKind::Press && key.code == KeyCode::Left { + g.get_mutable_player().get_position().change(-1, 0); + } + if key.kind == KeyEventKind::Press && key.code == KeyCode::Right { + g.get_mutable_player().get_position().change(1, 0); + } + if key.kind == KeyEventKind::Press && key.code == KeyCode::Up { + g.get_mutable_player().get_position().change(0, -1); + } + if key.kind == KeyEventKind::Press && key.code == KeyCode::Down { + g.get_mutable_player().get_position().change(0, 1); + } + } + } + } + + stdout().execute(LeaveAlternateScreen)?; + disable_raw_mode()?; + Ok(()) } diff --git a/src/player.rs b/src/player.rs index c803073..be21e01 100644 --- a/src/player.rs +++ b/src/player.rs @@ -28,9 +28,15 @@ impl Player { pub fn get_life(&self) -> i16 { self.life } + pub fn get_max_life(&self) -> i16 { + self.max_life + } pub fn get_position(&mut self) -> &mut Position { &mut self.position } + pub fn get_immutable_position(&self) -> &Position { + &self.position + } /// add the given amount to the players gold stash pub fn retrieve_gold(&mut self, amount: usize) { self.gold += amount }