Files
war-in-tunnels/src/cli.rs
T
GarandPLG 7541db79d8 Refactor App to use unified AppChannels for events
App now receives an AppChannels struct; AppEvent enum removed.

Event handling, tick generation, and audio communication are now
performed through dedicated channels.
2026-05-03 22:27:08 +02:00

208 lines
5.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use crate::{
app::{
states::{
PerkDecks,
skirmish_states::{GameMode, ZoomLevel},
},
threads::Soundtrack,
view::View,
},
logs::init_logger,
};
use clap::{Error, Parser, error::ErrorKind, value_parser};
use std::num::ParseFloatError;
/// Holds all configurable options that can be passed via the command line.
///
/// Each field corresponds to a CLI flag (e.g. `--view`, `--username`, …).
/// The `clap` attributes describe the flag name, help text, default value,
/// and any validation constraints. The struct derives `Parser` so that
/// `Cli::parse()` can be called directly to obtain a populated instance.
#[derive(Parser, Debug, Clone)]
#[command(version, about = "War in Tunnels", long_about = "War in Tunnels")]
pub struct Cli {
/// The initial view/window to display.
#[arg(
long,
help = "Default window",
value_name = "...",
default_value_t = View::MainMenu,
value_enum
)]
pub view: View,
/// Player name shown in the UI.
#[arg(
long,
help = "Username",
value_name = "String",
default_value = "Player"
)]
pub username: String,
/// Game mode selection.
#[arg(
long,
help = "Game mode",
value_name = "...",
default_value_t = GameMode::LastManStanding,
value_enum
)]
pub game_mode: GameMode,
/// Width of the generated map (36100 tiles).
#[arg(
long,
help = "Map width",
value_name = "Positive integer [36; 108]",
default_value = "42",
value_parser = value_parser!(u8).range(36..=108)
)]
pub map_width: u8,
/// Height of the generated map (1150 tiles).
#[arg(
long,
help = "Map height",
value_name = "Positive integer [11; 39]",
default_value = "11",
value_parser = value_parser!(u8).range(11..=39)
)]
pub map_height: u8,
/// Zoom level used for the UI.
#[arg(
long,
help = "Zoom level",
value_name = "...",
default_value_t = ZoomLevel::Default,
value_enum
)]
pub zoom_level: ZoomLevel,
/// Which perk deck to use.
#[arg(
long,
help = "Perk Deck",
value_name = "...",
default_value_t = PerkDecks::Silesian,
value_enum
)]
pub perk_deck: PerkDecks,
/// Starting amount of wood (1150).
#[arg(
long,
help = "Starting wood",
value_name = "Positive integer [1; 150]",
default_value = "50",
value_parser = value_parser!(u16).range(1..=150)
)]
pub starting_wood: u16,
/// Starting amount of iron (1150).
#[arg(
long,
help = "Starting iron",
value_name = "Positive integer [1; 150]",
default_value = "25",
value_parser = value_parser!(u16).range(1..=150)
)]
pub starting_iron: u16,
/// Maximum amount of units (49149).
#[arg(
long,
help = "Supply limit",
value_name = "Positive integer [49; 149]",
default_value = "99",
value_parser = value_parser!(u8).range(49..=149)
)]
pub supply_limit: u8,
/// Modifier applied to experience points (0.52.0).
#[arg(
long,
help = "XP modifier",
value_name = "Float [0.5; 2.0]",
default_value = "1.0",
value_parser = parse_xp
)]
pub xp_modifier: f32,
/// Upper bound for skill points that can be earned (90690).
#[arg(
long,
help = "Skill points limit",
value_name = "Positive integer [90; 690]",
default_value = "120",
value_parser = value_parser!(u16).range(90..=690)
)]
pub skill_points_limit: u16,
/// Which soundtrack to play (default: default)
#[arg(
long,
help = "Soundtrack",
value_name = "...",
default_value_t = Soundtrack::Default,
value_enum
)]
pub sound_track: Soundtrack,
/// Mute soundtrack (default: disabled).
#[arg(
long,
help = "Mute soundtrack (default: disabled)",
default_value_t = false
)]
pub mute: bool,
/// Enable logging to a file (default: disabled).
#[arg(
long,
help = "Enable logging to file (default: disabled)",
default_value_t = false
)]
pub log: bool,
}
/// Parses the command line arguments and returns a fully populated `Cli`
/// instance. This function simply forwards to `Cli::parse()`, which
/// handles argument validation and displays helpful error messages if
/// the user supplies invalid input.
pub fn get_args() -> Cli {
let args: Cli = Cli::parse();
if args.log {
init_logger();
}
args
}
/// Parses a string into a floatingpoint XP modifier and validates that it
/// lies within the inclusive range `0.5..=2.0`.
///
/// The function is used as a custom `value_parser` for the `--xp-modifier`
/// flag. On failure it returns a `clap::Error` with `ErrorKind::InvalidValue`,
/// allowing `clap` to present a clear error message to the user.
///
/// # Errors
///
/// * Returns an error if the string cannot be parsed as `f32`.
/// * Returns an error if the parsed value is outside the allowed range.
fn parse_xp(s: &str) -> Result<f32, Error> {
let v: f32 = s
.parse()
.map_err(|e: ParseFloatError| Error::raw(ErrorKind::InvalidValue, e.to_string()))?;
if (0.5..=2.0).contains(&v) {
Ok(v)
} else {
Err(Error::raw(
ErrorKind::InvalidValue,
format!("Value {} is out of range 0.5..=2.0", v),
))
}
}