From 0577697059bf98b55a7cf0622abc958725f28faf Mon Sep 17 00:00:00 2001 From: GarandPLG Date: Tue, 17 Mar 2026 14:28:46 +0100 Subject: [PATCH] Replace settings module with skirmish mode Removed the settings UI and its keybinding logic, added a skirmish view and corresponding keybindings, simplified the SettingsState to hold skirmish configuration, updated module exports, and changed the CLI default map height from 25 to 21. Also fixed the main menu selection limit. --- src/app/keybind.rs | 4 +- src/app/keybindings/main_menu.rs | 4 +- src/app/keybindings/mod.rs | 4 +- src/app/keybindings/settings.rs | 105 ------------------------- src/app/keybindings/skirmish.rs | 16 ++++ src/app/state.rs | 63 +++------------ src/app/states/mod.rs | 4 +- src/app/states/settings.rs | 65 +++------------- src/app/states/skirmish.rs | 8 ++ src/app/view.rs | 5 +- src/app/views/mod.rs | 4 +- src/app/views/settings.rs | 127 ------------------------------- src/app/views/skirmish.rs | 89 ++++++++++++++++++++++ src/cli.rs | 6 +- 14 files changed, 149 insertions(+), 355 deletions(-) delete mode 100644 src/app/keybindings/settings.rs create mode 100644 src/app/keybindings/skirmish.rs delete mode 100644 src/app/views/settings.rs create mode 100644 src/app/views/skirmish.rs 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,