180 lines
4.6 KiB
Rust
180 lines
4.6 KiB
Rust
//! Text-based quests and user solutions for them
|
|
|
|
pub mod error;
|
|
|
|
use std::{fs, io::Write, path::PathBuf};
|
|
|
|
use serde::{ Serialize, Deserialize };
|
|
use error::QuestError;
|
|
|
|
/// Difficulty of the quest
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
|
|
pub enum QuestDifficulty {
|
|
/// Easy quest
|
|
Easy,
|
|
/// Normal quest
|
|
Normal,
|
|
/// Hard quest
|
|
Hard,
|
|
/// Special case of hard quests. Also is a default value for enum
|
|
Secret
|
|
}
|
|
|
|
impl Default for QuestDifficulty {
|
|
fn default() -> Self {
|
|
QuestDifficulty::Secret
|
|
}
|
|
}
|
|
|
|
fn default_name() -> String {
|
|
"Slay the dragon".to_string()
|
|
}
|
|
|
|
fn default_description() -> String {
|
|
"Just do it in any way".to_string()
|
|
}
|
|
|
|
fn default_answer() -> String {
|
|
"Attachment should show that the dragon was slain".to_string()
|
|
}
|
|
|
|
/// Quest struct
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
|
#[serde(default)]
|
|
pub struct Quest {
|
|
/// Quest identifier
|
|
pub id: u16,
|
|
|
|
/// Difficulty of this quest
|
|
pub difficulty: QuestDifficulty,
|
|
|
|
/// Reward for the quest
|
|
pub reward: u32,
|
|
|
|
/// Visible quest name
|
|
pub name: String,
|
|
|
|
/// Visible quest description
|
|
pub description: String,
|
|
|
|
/// Quest answer, available for admins
|
|
pub answer: String,
|
|
}
|
|
|
|
impl Default for Quest {
|
|
fn default() -> Self {
|
|
Quest {
|
|
id: u16::default(),
|
|
difficulty: QuestDifficulty::default(),
|
|
reward: u32::default(),
|
|
name: default_name(),
|
|
description: default_description(),
|
|
answer: default_answer()
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Quest {
|
|
/// Parse quest TOML or return error
|
|
///
|
|
/// # Examples
|
|
/// ```rust
|
|
/// use squad_quest::quest::{Quest,error::QuestError};
|
|
/// # fn main() {
|
|
/// # let _ = wrapper();
|
|
/// # }
|
|
///
|
|
/// # fn wrapper() -> Result<(), QuestError> {
|
|
/// let path = "quests/0.toml".into();
|
|
///
|
|
/// let quest = Quest::load(path)?;
|
|
/// #
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
pub fn load(path: PathBuf) -> Result<Self, QuestError> {
|
|
match std::fs::read_to_string(path) {
|
|
Ok(string) => {
|
|
match toml::from_str::<Quest>(&string) {
|
|
Ok(quest) => Ok(quest),
|
|
Err(error) => Err(QuestError::TomlDeserializeError(error))
|
|
}
|
|
},
|
|
Err(error) => Err(QuestError::IoError(error))
|
|
}
|
|
}
|
|
|
|
/// Check if given file is a quest, then delete it or raise an error.
|
|
/// If file is not a quest, raises [QuestError::TomlDeserializeError]
|
|
///
|
|
/// # Examples
|
|
/// ```rust
|
|
/// use squad_quest::quest::{Quest,error::QuestError};
|
|
///
|
|
/// let path = "quests/0.toml".into();
|
|
///
|
|
/// if let Err(error) = Quest::delete(path) {
|
|
/// // handle the error
|
|
/// }
|
|
/// ```
|
|
pub fn delete(path: PathBuf) -> Result<(), QuestError> {
|
|
match Quest::load(path.clone()) {
|
|
Ok(_) => {
|
|
if let Err(error) = fs::remove_file(path) {
|
|
return Err(QuestError::IoError(error));
|
|
}
|
|
|
|
Ok(())
|
|
},
|
|
Err(error) => Err(error)
|
|
}
|
|
}
|
|
|
|
/// Save quest to given folder in TOML format.
|
|
/// File will be saved as `{id}.toml`.
|
|
/// If file exists, this method will override it.
|
|
///
|
|
/// # Examples
|
|
/// ```rust
|
|
/// # fn main() {
|
|
/// use squad_quest::quest::{Quest,error::QuestError};
|
|
/// use std::path::PathBuf;
|
|
///
|
|
/// let quest = Quest::default();
|
|
///
|
|
/// let path: PathBuf = "quests".into();
|
|
/// # let path2 = path.clone();
|
|
///
|
|
/// if let Err(error) = quest.save(path) {
|
|
/// // handle the error
|
|
/// }
|
|
/// # let filename = format!("{}.toml", quest.id);
|
|
/// # let _ = Quest::delete(path2.with_file_name(filename));
|
|
/// # }
|
|
/// ```
|
|
pub fn save(&self, path: PathBuf) -> Result<(), QuestError> {
|
|
let filename = format!("{}.toml", self.id);
|
|
let mut full_path = path;
|
|
full_path.push(filename);
|
|
|
|
let str = match toml::to_string_pretty(&self) {
|
|
Ok(string) => string,
|
|
Err(error) => {
|
|
return Err(QuestError::TomlSerializeError(error));
|
|
}
|
|
};
|
|
|
|
let mut file = match fs::File::create(full_path) {
|
|
Ok(f) => f,
|
|
Err(error) => {
|
|
return Err(QuestError::IoError(error));
|
|
}
|
|
};
|
|
|
|
if let Err(error) = file.write_all(str.as_bytes()) {
|
|
return Err(QuestError::IoError(error));
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|