297 lines
8.9 KiB
Rust
297 lines
8.9 KiB
Rust
use serde_derive::{Deserialize, Serialize};
|
|
use std::fmt;
|
|
use std::path::PathBuf;
|
|
use std::slice::Iter;
|
|
use std::cmp::Ordering;
|
|
|
|
#[derive(Default)]
|
|
pub struct CommandManager {
|
|
pub launcher: Option<PathBuf>,
|
|
pub iwad: Option<PathBuf>,
|
|
pub pwads: Vec<PathBuf>,
|
|
pub warp: String,
|
|
pub difficulty: Option<Difficulty>,
|
|
pub fast_monsters: bool,
|
|
pub respawning_monsters: bool,
|
|
pub command_string: String,
|
|
}
|
|
|
|
pub enum CommandErrors {
|
|
NoLauncher,
|
|
NoIwad,
|
|
}
|
|
|
|
impl CommandManager {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
launcher: None,
|
|
iwad: None,
|
|
pwads: Vec::new(),
|
|
warp: "".to_string(),
|
|
difficulty: None,
|
|
fast_monsters: false,
|
|
respawning_monsters: false,
|
|
command_string: "".to_string(),
|
|
}
|
|
}
|
|
pub fn remove_iwad(&mut self) {
|
|
self.iwad = None;
|
|
let _ = self.generate_command_str();
|
|
}
|
|
pub fn add_iwad(&mut self, iwad: &WadInfo) {
|
|
self.iwad = Some(iwad.path.clone());
|
|
let _ = self.generate_command_str();
|
|
}
|
|
pub fn add_pwads(&mut self, pwads: &Vec<&WadInfo>) {
|
|
self.pwads = Vec::new();
|
|
for pwad in pwads {
|
|
self.pwads.push(pwad.path.clone());
|
|
}
|
|
let _ = self.generate_command_str();
|
|
}
|
|
pub fn add_launcher(&mut self, launcher: &LauncherInfo) {
|
|
self.launcher = Some(launcher.path.clone());
|
|
let _ = self.generate_command_str();
|
|
}
|
|
pub fn remove_launcher(&mut self) {
|
|
self.launcher = None;
|
|
let _ = self.generate_command_str();
|
|
}
|
|
pub fn generate_command(&self) -> Result<(String, Vec<String>), CommandErrors> {
|
|
let launcher = if let Some(launcher) = &self.launcher {
|
|
launcher
|
|
} else {
|
|
return Err(CommandErrors::NoLauncher);
|
|
};
|
|
let iwad = if let Some(iwad) = &self.iwad {
|
|
iwad
|
|
} else {
|
|
return Err(CommandErrors::NoIwad);
|
|
};
|
|
let mut command = vec!["-iwad".to_string(), iwad.clone().into_os_string().into_string().unwrap()];
|
|
for pwad in &self.pwads {
|
|
command.push("-file".to_string());
|
|
command.push(pwad.clone().into_os_string().into_string().unwrap());
|
|
}
|
|
if let Some(d) = self.difficulty {
|
|
command.push("-skill".to_string());
|
|
command.push(d.flag_number().to_string());
|
|
}
|
|
if !self.warp.is_empty() {
|
|
command.push("-warp".to_string());
|
|
command.push(self.warp.to_string());
|
|
}
|
|
if self.respawning_monsters {
|
|
command.push("-respawn".to_string());
|
|
}
|
|
if self.fast_monsters {
|
|
command.push("-fast".to_string());
|
|
}
|
|
Ok((launcher.to_str().unwrap().to_string(), command))
|
|
}
|
|
pub fn generate_command_str(&mut self) -> Result<(), CommandErrors> {
|
|
match self.generate_command() {
|
|
Err(e) => {
|
|
self.command_string = "plz add ".to_string();
|
|
match e {
|
|
CommandErrors::NoIwad => self.command_string.push_str("an iwad"),
|
|
CommandErrors::NoLauncher => self.command_string.push_str("a launcher"),
|
|
}
|
|
},
|
|
Ok((launcher, rest)) => {
|
|
let mut command = "".to_string();
|
|
// Feels like a bit of a hack, but it works I think
|
|
command.push_str(&format!(" '{}'", launcher));
|
|
for c in rest {
|
|
command.push_str(&format!(" '{}'", c));
|
|
}
|
|
self.command_string = command;
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct WadInfo {
|
|
pub path: PathBuf,
|
|
pub name: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct LauncherInfo {
|
|
pub path: PathBuf,
|
|
pub name: String,
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct MultiManager<T> {
|
|
pub selectable: Vec<T>,
|
|
pub current_selected: Vec<usize>,
|
|
}
|
|
|
|
impl<T: Clone> MultiManager<T> {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
selectable: Vec::new(),
|
|
current_selected: Vec::new(),
|
|
}
|
|
}
|
|
pub fn add(&mut self, item: &T) {
|
|
self.selectable.push(item.clone());
|
|
}
|
|
pub fn get(&self, index: usize) -> Option<(&T, bool)> {
|
|
if index > self.selectable.len() {
|
|
None
|
|
} else {
|
|
Some((
|
|
self.selectable.get(index).unwrap(),
|
|
self.current_selected.contains(&index),
|
|
))
|
|
}
|
|
}
|
|
pub fn get_current(&self) -> Vec<&T> {
|
|
let mut current_selected_items = Vec::new();
|
|
for item in &self.current_selected {
|
|
assert!(item < &self.selectable.len());
|
|
current_selected_items.push(self.selectable.get(*item).unwrap());
|
|
}
|
|
current_selected_items
|
|
}
|
|
pub fn set_current(&mut self, index: usize) {
|
|
assert!(index < self.selectable.len());
|
|
self.current_selected.push(index);
|
|
}
|
|
pub fn remove_current(&mut self, index: usize) {
|
|
assert!(index < self.current_selected.len());
|
|
self.current_selected.remove(index);
|
|
}
|
|
pub fn remove_selectable(&mut self, index: usize) {
|
|
assert!(index < self.selectable.len());
|
|
self.selectable.remove(index);
|
|
let mut new_selected: Vec<usize> = Vec::new();
|
|
for s in &self.current_selected {
|
|
match s.cmp(&index) {
|
|
Ordering::Equal => continue,
|
|
Ordering::Less => new_selected.push(*s),
|
|
Ordering::Greater => new_selected.push(s - 1),
|
|
}
|
|
}
|
|
self.current_selected = new_selected;
|
|
}
|
|
pub fn is_currently_selected(self, index: usize) -> bool {
|
|
self.current_selected.contains(&index)
|
|
}
|
|
pub fn iter_selectable_with_pos_and_selected(
|
|
&mut self,
|
|
) -> impl Iterator<Item = (&mut T, usize, bool)> + '_ {
|
|
self.selectable
|
|
.iter_mut()
|
|
.enumerate()
|
|
.map(|(i, l)| (l, i, self.current_selected.contains(&i)))
|
|
}
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct SingleManager<T> {
|
|
pub selectable: Vec<T>,
|
|
pub current_selected: Option<usize>,
|
|
}
|
|
|
|
impl<T: Clone> SingleManager<T> {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
selectable: Vec::new(),
|
|
current_selected: None,
|
|
}
|
|
}
|
|
pub fn add(&mut self, item: &T) {
|
|
self.selectable.push(item.clone());
|
|
}
|
|
pub fn get(&self, index: usize) -> Option<(&T, bool)> {
|
|
if index > self.selectable.len() {
|
|
None
|
|
} else {
|
|
Some((
|
|
self.selectable.get(index).unwrap(),
|
|
index == self.current_selected.unwrap_or(std::usize::MAX),
|
|
))
|
|
}
|
|
}
|
|
pub fn get_current(&self) -> Option<&T> {
|
|
match self.current_selected {
|
|
None => None,
|
|
Some(pos) => Some(self.selectable.get(pos).unwrap()),
|
|
}
|
|
}
|
|
pub fn set_current(&mut self, index: usize) {
|
|
assert!(index < self.selectable.len());
|
|
self.current_selected = Some(index);
|
|
}
|
|
pub fn remove_current(&mut self) {
|
|
self.current_selected = None;
|
|
}
|
|
pub fn remove_selectable(&mut self, index: usize) {
|
|
assert!(index < self.selectable.len());
|
|
self.selectable.remove(index);
|
|
if self.current_selected.is_some() && index == self.current_selected.unwrap() {
|
|
self.current_selected = None;
|
|
}
|
|
}
|
|
pub fn iter_selectable_with_pos_and_selected(
|
|
&mut self,
|
|
) -> impl Iterator<Item = (&mut T, usize, bool)> + '_ {
|
|
self.selectable
|
|
.iter_mut()
|
|
.enumerate()
|
|
.map(|(i, l)| (l, i, i == self.current_selected.unwrap_or(std::usize::MAX)))
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq, Clone, Copy)]
|
|
pub enum Difficulty {
|
|
None,
|
|
Baby,
|
|
Easy,
|
|
Medium,
|
|
Hard,
|
|
Nightmare,
|
|
}
|
|
|
|
impl fmt::Display for Difficulty {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match *self {
|
|
Difficulty::Baby => write!(f, "I'm too young to die"),
|
|
Difficulty::Easy => write!(f, "Hey, not too rough"),
|
|
Difficulty::Medium => write!(f, "Hurt me plenty"),
|
|
Difficulty::Hard => write!(f, "Ultra-Violence"),
|
|
Difficulty::Nightmare => write!(f, "Nightmare!"),
|
|
Difficulty::None => write!(f, "None"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Difficulty {
|
|
pub fn iterator() -> Iter<'static, Difficulty> {
|
|
static DIFFICULTIES: [Difficulty; 6] = [
|
|
Difficulty::None,
|
|
Difficulty::Baby,
|
|
Difficulty::Easy,
|
|
Difficulty::Medium,
|
|
Difficulty::Hard,
|
|
Difficulty::Nightmare,
|
|
];
|
|
DIFFICULTIES.iter()
|
|
}
|
|
pub fn flag_number(&self) -> &str {
|
|
match self {
|
|
Difficulty::None => "0",
|
|
Difficulty::Baby => "1",
|
|
Difficulty::Easy => "2",
|
|
Difficulty::Medium => "3",
|
|
Difficulty::Hard => "4",
|
|
Difficulty::Nightmare => "5",
|
|
}
|
|
}
|
|
}
|