From 206a49fb083c47ac592ef7b453204581d8e8e206 Mon Sep 17 00:00:00 2001 From: Joachim Lusiardi Date: Sat, 9 Dec 2023 20:11:02 +0100 Subject: [PATCH] reworked level widget to stateful widget --- src/game.rs | 80 +++++++++++++++- src/level_widget.rs | 221 ++++++++++++++------------------------------ src/main.rs | 45 +++------ 3 files changed, 161 insertions(+), 185 deletions(-) diff --git a/src/game.rs b/src/game.rs index 8693f75..136d3ce 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,5 +1,7 @@ -use crate::level::Level; +use crate::artifacts::Artifact; +use crate::level::{Level, StructureElement}; use crate::level_generator::LevelGenerator; +use crate::monster::Monster; use crate::player::Player; use crate::position::Position; @@ -20,11 +22,12 @@ impl Game { player: p, levels: v, }; - let mut start = (0,0); + let mut start = (0, 0); { start = g.get_level(0).start; } - g.get_mutable_player().get_position().set(0,start.0, start.1); + g.get_mutable_player().get_position().set(0, start.0, start.1); + g.get_mutable_level(0).discover(&Position::new(0, start.0, start.1)); g } @@ -36,6 +39,77 @@ impl Game { } pub fn get_level(&self, level: usize) -> &Level { &self.levels[level] } pub fn get_mutable_level(&mut self, level: usize) -> &mut Level { &mut self.levels[level] } + fn can_move(&mut self, dx: i16, dy: i16) -> bool { + let player_pos = &self.player.get_position(); + let new_x: i16 = player_pos.get_x() as i16 + dx; + let new_y: i16 = player_pos.get_y() as i16 + dy; + let level = &mut self.levels[player_pos.get_level()]; + match level.get_element(new_x, new_y) { + (None, _, _) => { return false; } + (Some(t), _, _) => { + match t { + StructureElement::Wall => { return false; } + _ => {} + } + } + }; + true + } + fn next_start(&self) -> (usize, usize, usize) { + let level = self.player.get_immutable_position().get_level() + 1; + let (x, y) = self.levels[level].start; + (level, x, y) + } + fn next_element(&mut self, dx: i16, dy: i16) -> (Option, Option<&mut Monster>, Option<&mut Box<(dyn Artifact + 'static)>>) { + let player_pos = &self.player.get_position(); + let new_x: i16 = player_pos.get_x() as i16 + dx; + let new_y: i16 = player_pos.get_y() as i16 + dy; + let player_level = player_pos.get_level(); + let level = &mut self.levels[player_level]; + level.get_element(new_x, new_y) + } + pub fn move_player(&mut self, dx: i16, dy: i16) { + // verify the player can do the move + if !self.can_move(dx, dy) { + return; + } + + // // let player_pos = &self.player.get_position(); + // // let new_x: i16 = player_pos.get_x() as i16 + dx; + // // let new_y: i16 = player_pos.get_y() as i16 + dy; + // // let player_level = player_pos.get_level(); + // // let level = &mut self.levels[player_level]; + // let element = self.next_element(dx, dy); + // + // // use stairs if walked onto one + // match element { + // (Some(e), _, _) => { + // match e { + // StructureElement::StairDown => { + // let (next_level, x, y) = self.next_start(); + // self.get_mutable_player().get_position().set(next_level, x, y); + // self.levels[next_level].discover(self.player.get_position()); + // } + // StructureElement::StairUp => {} + // _ => {} + // } + // } + // (_, _, _) => {} + // } + // + // // interact with monsters / artifacts + // match element { + // (_, _, Some(a)) => { + // // a.collect(&mut self.player); + // // level.remove_artifact(&Position::new(player_level, new_x as usize, new_y as usize)).expect("Could not collect artifact"); + // } + // (_, _, _) => {} + // } + + // update position and discover area on new position + let (new_x, new_y) = self.get_mutable_player().get_position().change(dx, dy); + self.get_mutable_level(0).discover(&Position::new(0, new_x, new_y)); + } } #[test] diff --git a/src/level_widget.rs b/src/level_widget.rs index 847b1f9..cbe84b9 100644 --- a/src/level_widget.rs +++ b/src/level_widget.rs @@ -1,18 +1,17 @@ -use ratatui::prelude::*; -use ratatui::widgets::Widget; +use ratatui::buffer::Buffer; +use ratatui::layout::Rect; +use ratatui::style::Color; +use ratatui::widgets::{StatefulWidget, Widget}; -use crate::game::Game; use crate::artifacts::Artifact; -use crate::level::{Level, StructureElement}; +use crate::game::Game; +use crate::level::StructureElement; const FG_BROWN: Color = Color::Rgb(186, 74, 0); -//⌂ α Ω -pub struct LevelWidget<'a> { - pub game: &'a Game, -} +pub struct LevelWidget {} -impl LevelWidget<'_> { +impl LevelWidget { fn set_cell(&self, buf: &mut Buffer, x: u16, y: u16, symbol: &str, fg: Color, bg: Color) { buf. get_mut(x, y). @@ -20,157 +19,75 @@ impl LevelWidget<'_> { 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()]; +impl StatefulWidget for LevelWidget { + type State = Game; + fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) { 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); -// } -// } -// } -// } + { + let player = state.get_mutable_player(); + let player_pos = player.get_immutable_position(); + let player_level = player_pos.get_level(); + + // draw the level elements + for x in al..area.right() { + for y in at..area.bottom() { + let level = state.get_mutable_level(player_level); + let level_x = (x - al) as i16; + let level_y = (y - at) as i16; + match level.get_element(level_x, level_y) { + (Some(structure_element), None, None) => { + match structure_element { + StructureElement::Start => { + self.set_cell(buf, x, y, "α", Color::Black, Color::Gray); + } + StructureElement::End => { + self.set_cell(buf, x, y, "Ω", Color::Black, Color::Gray); + } + StructureElement::Wall => { + // TODO add fancy walls + self.set_cell(buf, x, y, "#", 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); + } + } + } + (_, Some(t), _) => { + self.set_cell(buf, x, y, "M", Color::Red, Color::Gray); + } + (_, _, Some(t)) => { + let (s, c) = t.get_representation(); + self.set_cell(buf, x, y, s, c, Color::Gray); + } + (None, None, None) => {} + }; + } } } -// -// // 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); + { + let player = state.get_mutable_player(); + let player_pos = player.get_immutable_position(); + 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, "┓"); -} - +impl Widget for LevelWidget { + fn render(self, area: Rect, buf: &mut Buffer) {} +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 2f58dd6..94fb2e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ -use std::io::{Result, stdout}; -use std::ops::Index; +use std::io::Result; +use std::io::stdout; use crossterm::{ event::{self, KeyCode, KeyEventKind}, @@ -15,9 +15,8 @@ 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::level_widget::LevelWidget; use crate::player::Player; mod game; @@ -28,20 +27,9 @@ mod level_widget; mod level_generator; mod artifacts; mod monster; - +// fn main() -> Result<()> { - let mut levels = Vec::new(); - - for l in 0..25 { - levels.push(LevelGenerator::generate(l).render()); - } - let mut g = Game { - player: 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); + let mut game = Game::new(Player::new(realname().as_str(), 10)); stdout().execute(EnterAlternateScreen)?; enable_raw_mode()?; @@ -68,7 +56,7 @@ fn main() -> Result<()> { width: level::LEVEL_WIDTH as u16, height: level::LEVEL_HEIGHT as u16, }; - frame.render_widget(LevelWidget { game: &g }, map_area); + frame.render_stateful_widget(LevelWidget{}, map_area, &mut game); let stats_area = Rect { x: area.x + 50, @@ -78,11 +66,11 @@ fn main() -> Result<()> { }; 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())) + game.get_player().get_name(), + game.get_player().get_life(), + game.get_player().get_max_life(), + game.get_player().get_gold(), + game.get_player().get_immutable_position().get_level())) .white() .on_blue(), stats_area, @@ -93,20 +81,17 @@ fn main() -> Result<()> { 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); + game.move_player(-1, 0); } if key.kind == KeyEventKind::Press && key.code == KeyCode::Right { - g.get_mutable_player().get_position().change(1, 0); + game.move_player(1, 0); } if key.kind == KeyEventKind::Press && key.code == KeyCode::Up { - g.get_mutable_player().get_position().change(0, -1); + game.move_player(0, -1); } if key.kind == KeyEventKind::Press && key.code == KeyCode::Down { - g.get_mutable_player().get_position().change(0, 1); + game.move_player(0, 1); } } }