diff --git a/src/app/keybind.rs b/src/app/keybind.rs index e7ffdb4..4ff35eb 100644 --- a/src/app/keybind.rs +++ b/src/app/keybind.rs @@ -1,6 +1,6 @@ use crate::app::{ App, - keybindings::{default_keybindings, main_menu_keybindings, settings_keybindings}, + keybindings::{default_keybindings, main_menu_keybindings, skirmish_keybindings}, view::View, }; use ratatui::crossterm::event::KeyEvent; @@ -8,7 +8,7 @@ use ratatui::crossterm::event::KeyEvent; pub fn handle_keybindings(app: &mut App, key_event: KeyEvent) { match app.view { View::MainMenu => main_menu_keybindings(app, &key_event), - View::Settings => settings_keybindings(app, &key_event), + View::Skirmish => skirmish_keybindings(app, &key_event), _ => default_keybindings(app, &key_event), } } diff --git a/src/app/keybindings/main_menu.rs b/src/app/keybindings/main_menu.rs index e6f0e2a..e29cd87 100644 --- a/src/app/keybindings/main_menu.rs +++ b/src/app/keybindings/main_menu.rs @@ -15,7 +15,7 @@ pub fn main_menu_keybindings(app: &mut App, event: &KeyEvent) { } Action::Down => { app.states.main_menu.selected_view = - app.states.main_menu.selected_view.saturating_add(1).min(4); + app.states.main_menu.selected_view.saturating_add(1).min(3); } Action::Space => { let selected_view: usize = app.states.main_menu.selected_view; @@ -26,8 +26,6 @@ pub fn main_menu_keybindings(app: &mut App, event: &KeyEvent) { app.view = View::PerkDecks; } else if selected_view == 3 { app.view = View::SkillsConfig; - } else if selected_view == 4 { - app.view = View::Settings; } } _ => (), diff --git a/src/app/keybindings/mod.rs b/src/app/keybindings/mod.rs index 66e8e40..5f0dc81 100644 --- a/src/app/keybindings/mod.rs +++ b/src/app/keybindings/mod.rs @@ -1,9 +1,9 @@ pub mod default; pub mod keybindings; pub mod main_menu; -pub mod settings; +pub mod skirmish; pub use default::default_keybindings; pub use keybindings::{Action, Group, KEYBINDINGS, KeyBinding, binding_for, event_to_action}; pub use main_menu::main_menu_keybindings; -pub use settings::settings_keybindings; +pub use skirmish::skirmish_keybindings; diff --git a/src/app/keybindings/settings.rs b/src/app/keybindings/settings.rs deleted file mode 100644 index 360656d..0000000 --- a/src/app/keybindings/settings.rs +++ /dev/null @@ -1,105 +0,0 @@ -use crate::app::{ - App, View, - keybindings::{Action, event_to_action}, - states::SettingsValue, -}; -use ratatui::crossterm::event::KeyEvent; -use std::any::type_name_of_val; - -pub fn settings_keybindings(app: &mut App, key_event: &KeyEvent) { - if let Some(action) = event_to_action(&key_event) { - match action { - Action::Up => { - app.states.settings.selected_setting = app - .states - .settings - .selected_setting - .saturating_sub(1) - .max(0) - } - Action::Down => { - app.states.settings.selected_setting = app - .states - .settings - .selected_setting - .saturating_add(1) - .min(9) - } - Action::Esc => app.view = View::MainMenu, - Action::Space => app.states.settings.show_popup = !app.states.settings.show_popup, - Action::Enter => { - // FIXME: No feedback - // FIXME: Extract match block into a function - if app.states.settings.show_popup { - let option = - &app.states.settings.options[app.states.settings.selected_setting].value; - - let option_type: &'static str = type_name_of_val(option); - - let new_value: String = app.states.settings.selected_setting_new_value.clone(); - - match option_type { - "u8" => { - if let Ok(value) = new_value.parse::() { - app.states.settings.options[app.states.settings.selected_setting] - .value = SettingsValue::U8(value); - - app.states.settings.selected_setting_new_value = "".to_string(); - app.states.settings.error_message = "".to_string(); - app.states.settings.show_popup = false; - } else { - app.states.settings.error_message = "Invalid value".to_string(); - } - } - "f32" => { - if let Ok(value) = new_value.parse::() { - app.states.settings.options[app.states.settings.selected_setting] - .value = SettingsValue::F32(value); - - app.states.settings.selected_setting_new_value = "".to_string(); - app.states.settings.error_message = "".to_string(); - app.states.settings.show_popup = false; - } else { - app.states.settings.error_message = "Invalid value".to_string(); - } - } - "u16" => { - if let Ok(value) = new_value.parse::() { - app.states.settings.options[app.states.settings.selected_setting] - .value = SettingsValue::U16(value); - - app.states.settings.selected_setting_new_value = "".to_string(); - app.states.settings.error_message = "".to_string(); - app.states.settings.show_popup = false; - } else { - app.states.settings.error_message = "Invalid value".to_string(); - } - } - "std::string::String" => { - app.states.settings.options[app.states.settings.selected_setting] - .value = SettingsValue::Text(new_value); - - app.states.settings.selected_setting_new_value = "".to_string(); - app.states.settings.error_message = "".to_string(); - app.states.settings.show_popup = false; - } - _ => (), - } - } - } - Action::Backspace => { - if app.states.settings.show_popup { - app.states.settings.selected_setting_new_value.pop(); - } - } - Action::WildCard(c) => { - if app.states.settings.show_popup { - app.states.settings.selected_setting_new_value.push(c); - } - } - Action::Quit => app.exit = true, - Action::Quit2 => app.exit = true, - // _ => (), - } - } -} diff --git a/src/app/keybindings/skirmish.rs b/src/app/keybindings/skirmish.rs new file mode 100644 index 0000000..7ac9b39 --- /dev/null +++ b/src/app/keybindings/skirmish.rs @@ -0,0 +1,16 @@ +use crate::app::{ + App, View, + keybindings::{Action, event_to_action}, +}; +use ratatui::crossterm::event::KeyEvent; + +pub fn skirmish_keybindings(app: &mut App, key_event: &KeyEvent) { + if let Some(action) = event_to_action(&key_event) { + match action { + Action::Quit => app.exit = true, + Action::Quit2 => app.exit = true, + Action::Esc => app.view = View::MainMenu, + _ => (), + } + } +} diff --git a/src/app/state.rs b/src/app/state.rs index fa912e6..a8a5779 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -1,8 +1,5 @@ use crate::{ - app::states::{ - MainMenuState, PerkDecksState, SettingsOption, SettingsState, SettingsValue, - SkillsConfigState, SkirmishState, - }, + app::states::{MainMenuState, PerkDecksState, SettingsState, SkillsConfigState, SkirmishState}, cli::Cli, }; @@ -38,54 +35,16 @@ impl GameStates { selected_skill: 0, }, settings: SettingsState { - id: 4, - name: "Settings", - selected_setting: 0, - show_popup: false, - selected_setting_new_value: String::new(), - error_message: String::new(), - options: vec![ - SettingsOption { - name: "Username", - value: SettingsValue::Text(args.username), - }, - SettingsOption { - name: "Game Mode", - value: SettingsValue::GameMode(args.game_mode), - }, - SettingsOption { - name: "Map Width", - value: SettingsValue::U8(args.map_width), - }, - SettingsOption { - name: "Map Height", - value: SettingsValue::U8(args.map_height), - }, - SettingsOption { - name: "Perk Deck", - value: SettingsValue::PerkDeck(args.perk_deck), - }, - SettingsOption { - name: "Starting Wood", - value: SettingsValue::U8(args.starting_wood), - }, - SettingsOption { - name: "Starting Iron", - value: SettingsValue::U8(args.starting_iron), - }, - SettingsOption { - name: "Supply Limit", - value: SettingsValue::U8(args.supply_limit), - }, - SettingsOption { - name: "XP Modifier", - value: SettingsValue::F32(args.xp_modifier), - }, - SettingsOption { - name: "Skill Points Limit", - value: SettingsValue::U16(args.skill_points_limit), - }, - ], + username: args.username, + game_mode: args.game_mode, + map_width: args.map_width, + map_height: args.map_height, + perk_deck: args.perk_deck, + starting_wood: args.starting_wood, + starting_iron: args.starting_iron, + supply_limit: args.supply_limit, + xp_modifier: args.xp_modifier, + skill_points_limit: args.skill_points_limit, }, } } diff --git a/src/app/states/mod.rs b/src/app/states/mod.rs index 199dc12..25fdf15 100644 --- a/src/app/states/mod.rs +++ b/src/app/states/mod.rs @@ -6,6 +6,6 @@ pub mod skirmish; pub use main_menu::MainMenuState; pub use perk_decks::{PerkDecks, PerkDecksState}; -pub use settings::{GameMode, SettingsOption, SettingsState, SettingsValue}; +pub use settings::SettingsState; pub use skills_config::SkillsConfigState; -pub use skirmish::SkirmishState; +pub use skirmish::{GameMode, SkirmishState}; diff --git a/src/app/states/settings.rs b/src/app/states/settings.rs index abd18de..cea07de 100644 --- a/src/app/states/settings.rs +++ b/src/app/states/settings.rs @@ -1,58 +1,15 @@ -use crate::app::states::PerkDecks; -use clap::ValueEnum; -use std::fmt::Display; +use crate::app::states::{GameMode, PerkDecks}; #[derive(Debug, Clone, PartialEq)] pub struct SettingsState { - pub id: usize, - pub name: &'static str, - pub selected_setting: usize, - pub show_popup: bool, - pub selected_setting_new_value: String, - pub error_message: String, - pub options: Vec, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct SettingsOption { - pub name: &'static str, - pub value: SettingsValue, -} - -#[derive(Debug, Clone, PartialEq)] -pub enum SettingsValue { - U8(u8), - F32(f32), - U16(u16), - Text(String), - GameMode(GameMode), - PerkDeck(PerkDecks), -} - -impl Display for SettingsValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - SettingsValue::U8(v) => write!(f, "{}", v), - SettingsValue::F32(v) => write!(f, "{}", v), - SettingsValue::U16(v) => write!(f, "{}", v), - SettingsValue::Text(v) => write!(f, "{}", v), - SettingsValue::GameMode(v) => write!(f, "{}", v), - SettingsValue::PerkDeck(v) => write!(f, "{}", v), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)] -pub enum GameMode { - LastManStanding, - FrontLines, -} - -impl Display for GameMode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - GameMode::FrontLines => write!(f, "Front Lines"), - GameMode::LastManStanding => write!(f, "Last Man Standing"), - } - } + pub username: String, + pub game_mode: GameMode, + pub map_width: u8, + pub map_height: u8, + pub perk_deck: PerkDecks, + pub starting_wood: u16, + pub starting_iron: u16, + pub supply_limit: u8, + pub xp_modifier: f32, + pub skill_points_limit: u16, } diff --git a/src/app/states/skirmish.rs b/src/app/states/skirmish.rs index 0ddbffa..c63905a 100644 --- a/src/app/states/skirmish.rs +++ b/src/app/states/skirmish.rs @@ -1,5 +1,13 @@ +use clap::ValueEnum; + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct SkirmishState { pub id: usize, pub name: &'static str, } + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)] +pub enum GameMode { + LastManStanding, + FrontLines, +} diff --git a/src/app/view.rs b/src/app/view.rs index 2506604..262b8c1 100644 --- a/src/app/view.rs +++ b/src/app/view.rs @@ -1,6 +1,6 @@ use crate::app::{ App, - views::{default_view, main_menu_view, settings_view}, + views::{default_view, main_menu_view, skirmish_view}, }; use clap::ValueEnum; use ratatui::{buffer::Buffer, layout::Rect, widgets::Widget}; @@ -11,7 +11,6 @@ pub enum View { Skirmish, PerkDecks, SkillsConfig, - Settings, } impl Widget for &App { @@ -21,7 +20,7 @@ impl Widget for &App { { match self.view { View::MainMenu => main_menu_view(self, area, buf), - View::Settings => settings_view(self, area, buf), + View::Skirmish => skirmish_view(self, area, buf), _ => default_view(area, buf), } } diff --git a/src/app/views/mod.rs b/src/app/views/mod.rs index 0b2fc93..e5f3eb2 100644 --- a/src/app/views/mod.rs +++ b/src/app/views/mod.rs @@ -1,7 +1,7 @@ pub mod default; pub mod main_menu; -pub mod settings; +pub mod skirmish; pub use default::default_view; pub use main_menu::main_menu_view; -pub use settings::settings_view; +pub use skirmish::skirmish_view; diff --git a/src/app/views/settings.rs b/src/app/views/settings.rs deleted file mode 100644 index 20bd536..0000000 --- a/src/app/views/settings.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::app::{App, keybindings::Action, widgets::KeybindingsWidget}; -use ratatui::{ - buffer::Buffer, - layout::{Alignment, Constraint, Layout, Rect}, - style::{Style, Stylize}, - text::Line, - widgets::{Block, Borders, Padding, Paragraph, Widget, Wrap}, -}; - -pub fn settings_view(app: &App, area: Rect, buf: &mut Buffer) { - let vertical_layout: Layout = Layout::vertical([ - Constraint::Length(4), - Constraint::Fill(1), - Constraint::Length(5), - ]); - - let [title_area, main_area, keybindings_area] = vertical_layout.areas(area); - - { - Paragraph::new("War in tunnels") - .alignment(Alignment::Left) - .yellow() - .block( - Block::new() - .gray() - .borders(Borders::LEFT | Borders::TOP | Borders::RIGHT) - .padding(Padding::new(5, 1, 1, 1)), - ) - .render(title_area, buf); - - let lines: Vec> = app - .states - .settings - .options - .iter() - .enumerate() - .map(|(i, o)| { - if i == app.states.settings.selected_setting { - Line::from_iter([ - "> ".cyan(), - o.name.yellow(), - ": ".gray(), - o.value.to_string().light_green(), - ]) - } else { - Line::from(format!(" {}: {}", o.name, o.value)).white() - } - }) - .collect(); - - let settings_block: Block<'_> = Block::new() - .borders(Borders::LEFT | Borders::TOP | Borders::RIGHT) - .padding(Padding::new(1, 1, 1, 1)) - .title(Line::from_iter([ - "[ ".gray(), - "Settings".magenta(), - " ]".gray(), - ])) - .gray(); - - let settings_area: Rect = settings_block.inner(main_area); - - settings_block.render(main_area, buf); - - Paragraph::new(lines).alignment(Alignment::Center).render( - settings_area.centered_vertically(Constraint::Ratio(1, 2)), - buf, - ); - - let popup_text: Vec> = Vec::from_iter([ - app.states - .settings - .selected_setting_new_value - .clone() - .into(), - app.states.settings.error_message.clone().into(), - ]); - - if app.states.settings.show_popup { - Paragraph::new(popup_text) - .wrap(Wrap { trim: true }) - .style(Style::default()) - .block( - Block::new() - .title("Insert new value") - .title_style(Style::default().yellow()) - .borders(Borders::ALL) - .border_style(Style::default().gray()) - .padding(Padding { - left: 1, - right: 1, - top: 1, - bottom: 1, - }), - ) - .render( - Rect { - x: 2, - y: main_area.height - 1, - width: main_area.width - 3, - height: if app.states.settings.error_message.is_empty() { - 5 - } else { - 6 - }, - }, - buf, - ); - } - } - - { - let actions: Vec = vec![ - Action::Up, - Action::Down, - Action::Quit, - Action::Quit2, - Action::Esc, - Action::Space, - Action::Enter, - Action::Backspace, - Action::WildCard('_'), - ]; - - KeybindingsWidget::new(actions).render(keybindings_area, buf); - } -} diff --git a/src/app/views/skirmish.rs b/src/app/views/skirmish.rs new file mode 100644 index 0000000..d15aeaa --- /dev/null +++ b/src/app/views/skirmish.rs @@ -0,0 +1,89 @@ +use crate::app::{App, keybindings::Action, widgets::KeybindingsWidget}; +use ratatui::{ + buffer::Buffer, + layout::{Alignment, Constraint, Layout, Margin, Rect}, + style::Stylize, + text::Line, + widgets::{Block, Borders, Padding, Paragraph, Widget}, +}; + +pub fn skirmish_view(app: &App, area: Rect, buf: &mut Buffer) { + let vertical_layout: Layout = Layout::vertical([ + Constraint::Length(4), + Constraint::Fill(1), + Constraint::Length(4), + ]); + + let [title_area, main_area, keybindings_area] = vertical_layout.areas(area); + + { + let lines: Vec> = Vec::from_iter([ + Line::raw("War in Tunnels").yellow(), + Line::from_iter([ + format!("Wood: {} (+{}) | ", app.states.settings.starting_wood, 5), + format!("Iron: {} (+{}) | ", app.states.settings.starting_iron, 1), + format!( + "Supply Limit: {}/{} | ", + 10, app.states.settings.supply_limit + ), + format!( + "Skills points: {} ({}/{}) | ", + 1, 20, app.states.settings.skill_points_limit + ), + format!("Perk Deck: {}/9", 5), + ]), + ]); + + Paragraph::new(lines) + .alignment(Alignment::Left) + .block( + Block::new() + .gray() + .padding(Padding { + left: 1, + right: 1, + top: 0, + bottom: 1, + }) + .borders(Borders::LEFT | Borders::TOP | Borders::RIGHT), + ) + .render(title_area, buf); + } + + { + let board_block: Block = Block::new() + .gray() + .title(Line::from_iter([ + "[ ".gray(), + "Skirmish".magenta(), + " - ".gray(), + "Map".green(), + " ]".gray(), + ])) + .borders(Borders::LEFT | Borders::TOP | Borders::RIGHT); + + let board_area: Rect = board_block.inner(main_area); + board_block.render(main_area, buf); + + let inner_board_area: Rect = board_area.inner(Margin { + horizontal: 1, + vertical: 1, + }); + + let map_width: u16 = inner_board_area.width / (app.states.settings.map_width as u16); + let map_height: u16 = inner_board_area.height / (app.states.settings.map_height as u16); + + Paragraph::new(format!( + "x = {}, y = {}, mw = {}, mh = {}", + inner_board_area.width, inner_board_area.height, map_width, map_height + )) + .block(Block::default()) + .render(inner_board_area, buf); + } + + { + let actions: Vec = vec![Action::Quit, Action::Quit2, Action::Esc]; + + KeybindingsWidget::new(actions).render(keybindings_area, buf); + } +} diff --git a/src/cli.rs b/src/cli.rs index f96653e..ff47306 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -45,7 +45,7 @@ pub struct Cli { long, help = "Map height", value_name = "Positive integer [11; 50]", - default_value = "25" + default_value = "21" )] pub map_height: u8, @@ -64,7 +64,7 @@ pub struct Cli { value_name = "Positive integer", default_value = "50" )] - pub starting_wood: u8, + pub starting_wood: u16, #[arg( long, @@ -72,7 +72,7 @@ pub struct Cli { value_name = "Positive integer", default_value = "25" )] - pub starting_iron: u8, + pub starting_iron: u16, #[arg( long,