Compare commits
No commits in common. "d584340f010e67919de8be2fffde17ffd9f20cdb" and "81a9ec0c50468cd6cdd4192323b6303bf7dd32d6" have entirely different histories.
d584340f01
...
81a9ec0c50
18 changed files with 216 additions and 1153 deletions
1136
Cargo.lock
generated
1136
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -2,7 +2,7 @@
|
||||||
members = ["cli", "discord"]
|
members = ["cli", "discord"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.11.0"
|
version = "0.10.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
repository = "https://2ndbeam.ru/git/2ndbeam/squad-quest"
|
repository = "https://2ndbeam.ru/git/2ndbeam/squad-quest"
|
||||||
homepage = "https://2ndbeam.ru/git/2ndbeam/squad-quest"
|
homepage = "https://2ndbeam.ru/git/2ndbeam/squad-quest"
|
||||||
|
|
|
||||||
|
|
@ -9,5 +9,5 @@ license.workspace = true
|
||||||
chrono = "0.4.42"
|
chrono = "0.4.42"
|
||||||
clap = { version = "4.5.53", features = ["derive"] }
|
clap = { version = "4.5.53", features = ["derive"] }
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
squad-quest = { version = "0.11.0", path = ".." }
|
squad-quest = { version = "0.10.0", path = ".." }
|
||||||
toml = "0.9.8"
|
toml = "0.9.8"
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,6 @@ pub enum MapCommands {
|
||||||
Delete(MapDeleteArgs),
|
Delete(MapDeleteArgs),
|
||||||
/// Update room data
|
/// Update room data
|
||||||
Update(MapUpdateArgs),
|
Update(MapUpdateArgs),
|
||||||
/// Get room implementation data
|
|
||||||
Data(MapDataArgs),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
|
|
@ -57,9 +55,3 @@ pub struct MapUpdateArgs {
|
||||||
#[arg(short,long)]
|
#[arg(short,long)]
|
||||||
pub value: Option<u32>,
|
pub value: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
|
||||||
pub struct MapDataArgs {
|
|
||||||
/// Room ID
|
|
||||||
pub id: u16,
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -147,8 +147,7 @@ fn main() {
|
||||||
answer: args.answer.clone(),
|
answer: args.answer.clone(),
|
||||||
public: args.public,
|
public: args.public,
|
||||||
available_on: args.available.clone(),
|
available_on: args.available.clone(),
|
||||||
deadline: args.deadline.clone(),
|
deadline: args.deadline.clone()
|
||||||
..Default::default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
do_and_log(quest.save(path), !cli.quiet, format!("Created quest #{}.", quest.id));
|
do_and_log(quest.save(path), !cli.quiet, format!("Created quest #{}.", quest.id));
|
||||||
|
|
@ -170,8 +169,7 @@ fn main() {
|
||||||
answer: args.answer.clone().unwrap_or(quest.answer.clone()),
|
answer: args.answer.clone().unwrap_or(quest.answer.clone()),
|
||||||
public: args.public.unwrap_or(quest.public),
|
public: args.public.unwrap_or(quest.public),
|
||||||
available_on: args.available.clone().or(quest.available_on.clone()),
|
available_on: args.available.clone().or(quest.available_on.clone()),
|
||||||
deadline: args.deadline.clone().or(quest.deadline.clone()),
|
deadline: args.deadline.clone().or(quest.deadline.clone())
|
||||||
..Default::default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
do_and_log(quest.save(path), !cli.quiet, format!("Updated quest #{}.", quest.id));
|
do_and_log(quest.save(path), !cli.quiet, format!("Updated quest #{}.", quest.id));
|
||||||
|
|
@ -447,15 +445,6 @@ fn main() {
|
||||||
let connected = if connect { "Connected" } else { "Disconnected" };
|
let connected = if connect { "Connected" } else { "Disconnected" };
|
||||||
do_and_log(map_save(map, map_path), !cli.quiet, format!("{connected} rooms #{} <-> #{}.", args.first, args.second));
|
do_and_log(map_save(map, map_path), !cli.quiet, format!("{connected} rooms #{} <-> #{}.", args.first, args.second));
|
||||||
},
|
},
|
||||||
MapCommands::Data(args) => {
|
|
||||||
if let Some(room) = map.room.iter().find(|r| r.id == args.id) {
|
|
||||||
if let Some(data) = &room.data {
|
|
||||||
for (key, value) in data {
|
|
||||||
println!("{key} = {value}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,7 @@ chrono = "0.4.42"
|
||||||
clap = { version = "4.5.53", features = ["derive"] }
|
clap = { version = "4.5.53", features = ["derive"] }
|
||||||
dotenvy = "0.15.7"
|
dotenvy = "0.15.7"
|
||||||
poise = "0.6.1"
|
poise = "0.6.1"
|
||||||
rocket = { version = "0.5.1", features = ["json"] }
|
|
||||||
serde = "1.0.228"
|
serde = "1.0.228"
|
||||||
serde_json = "1.0.146"
|
squad-quest = { version = "0.10.0", path = ".." }
|
||||||
squad-quest = { version = "0.11.0", path = ".." }
|
|
||||||
tokio = { version = "1.48.0", features = ["rt-multi-thread"] }
|
tokio = { version = "1.48.0", features = ["rt-multi-thread"] }
|
||||||
toml = "0.9.8"
|
toml = "0.9.8"
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
[default]
|
|
||||||
address = "127.0.0.1" # should be local only because frontend runs on the same machine
|
|
||||||
port = 2526
|
|
||||||
log_level = "critical"
|
|
||||||
|
|
||||||
[default.shutdown]
|
|
||||||
ctrlc = false
|
|
||||||
|
|
||||||
|
|
@ -1,24 +1,12 @@
|
||||||
use std::collections::HashMap;
|
use poise::serenity_prelude::UserId;
|
||||||
|
|
||||||
use poise::serenity_prelude::{User, UserId};
|
|
||||||
use squad_quest::{account::Account, config::Config, map::Map};
|
use squad_quest::{account::Account, config::Config, map::Map};
|
||||||
|
|
||||||
pub fn fetch_or_init_account(conf: &Config, id: String, user: Option<&User>) -> Account {
|
pub fn fetch_or_init_account(conf: &Config, id: String) -> Account {
|
||||||
let accounts = conf.load_accounts();
|
let accounts = conf.load_accounts();
|
||||||
let mut data: HashMap<String, String> = HashMap::new();
|
|
||||||
|
|
||||||
if let Some(user) = user {
|
|
||||||
let avatar = user.avatar_url().unwrap_or("null".to_string());
|
|
||||||
let name = user.display_name().to_string();
|
|
||||||
data.insert("avatar".to_string(), avatar);
|
|
||||||
data.insert("name".to_string(), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
match accounts.iter().find(|a| a.id == id) {
|
match accounts.iter().find(|a| a.id == id) {
|
||||||
Some(a) => a.clone(),
|
Some(a) => a.clone(),
|
||||||
None => Account {
|
None => Account {
|
||||||
id,
|
id,
|
||||||
data: Some(data),
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,119 +0,0 @@
|
||||||
use rocket::{Build, Response, Rocket, State, http::{Header, hyper::header::ACCESS_CONTROL_ALLOW_ORIGIN}, response::Responder, serde::json::Json};
|
|
||||||
use serde::Serialize;
|
|
||||||
use squad_quest::{SquadObject, account::Account, config::Config, map::{Map, Room}};
|
|
||||||
|
|
||||||
struct RocketData {
|
|
||||||
pub config: Config,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct UserData {
|
|
||||||
pub id: String,
|
|
||||||
pub avatar: String,
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct RoomData {
|
|
||||||
pub id: u16,
|
|
||||||
pub value: u32,
|
|
||||||
pub name: String,
|
|
||||||
pub description: String,
|
|
||||||
pub x: f32,
|
|
||||||
pub y: f32,
|
|
||||||
pub w: f32,
|
|
||||||
pub h: f32,
|
|
||||||
pub markers: Vec<UserData>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RoomDataResponse {
|
|
||||||
pub data: Vec<RoomData>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Vec<RoomData>> for RoomDataResponse {
|
|
||||||
fn from(value: Vec<RoomData>) -> Self {
|
|
||||||
Self {
|
|
||||||
data: value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'r> Responder<'r, 'static> for RoomDataResponse {
|
|
||||||
fn respond_to(self, request: &'r rocket::Request<'_>) -> rocket::response::Result<'static> {
|
|
||||||
Response::build_from(Json(&self.data).respond_to(request)?)
|
|
||||||
.header(Header::new(ACCESS_CONTROL_ALLOW_ORIGIN.as_str(), "http://localhost:5173"))
|
|
||||||
.ok()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&Room> for RoomData {
|
|
||||||
fn from(value: &Room) -> Self {
|
|
||||||
let data = value.data.clone().unwrap_or_default();
|
|
||||||
let keys = [ "x", "y", "w", "h" ];
|
|
||||||
let mut values = [ 0f32, 0f32, 0f32, 0f32 ];
|
|
||||||
let mut counter = 0usize;
|
|
||||||
for key in keys {
|
|
||||||
values[counter] = data.get(key).map_or(0f32, |v| v.parse::<f32>().unwrap_or_default());
|
|
||||||
counter += 1;
|
|
||||||
}
|
|
||||||
RoomData {
|
|
||||||
id: value.id,
|
|
||||||
value: value.value,
|
|
||||||
name: value.name.clone(),
|
|
||||||
description: value.description.clone().unwrap_or(String::new()),
|
|
||||||
x: values[0],
|
|
||||||
y: values[1],
|
|
||||||
w: values[2],
|
|
||||||
h: values[3],
|
|
||||||
markers: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn acc_filt_map(account: &Account, room_id: u16) -> Option<UserData> {
|
|
||||||
if account.location == room_id {
|
|
||||||
let data = account.data.clone().unwrap_or_default();
|
|
||||||
let keys = [ "avatar", "name" ];
|
|
||||||
let empty = String::new();
|
|
||||||
let mut values = [ &String::new(), &String::new() ];
|
|
||||||
let mut counter = 0usize;
|
|
||||||
for key in keys {
|
|
||||||
values[counter] = data.get(key).unwrap_or(&empty);
|
|
||||||
counter += 1;
|
|
||||||
}
|
|
||||||
Some(UserData {
|
|
||||||
id: account.id.clone(),
|
|
||||||
avatar: values[0].clone(),
|
|
||||||
name: values[1].clone(),
|
|
||||||
})
|
|
||||||
} else { None }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/")]
|
|
||||||
fn index(rd: &State<RocketData>) -> RoomDataResponse {
|
|
||||||
let map_path = rd.config.full_map_path();
|
|
||||||
let Ok(map) = Map::load(map_path) else {
|
|
||||||
return Vec::new().into();
|
|
||||||
};
|
|
||||||
let accounts = rd.config.load_accounts();
|
|
||||||
|
|
||||||
let rooms_vec: Vec<RoomData> = map.room.iter()
|
|
||||||
.map(|r| {
|
|
||||||
let mut rd = RoomData::from(r);
|
|
||||||
let markers = accounts.iter()
|
|
||||||
.filter_map(|a| acc_filt_map(a, r.id))
|
|
||||||
.collect::<Vec<UserData>>();
|
|
||||||
rd.markers = markers;
|
|
||||||
rd
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
rooms_vec.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rocket(config: Config) -> Rocket<Build> {
|
|
||||||
rocket::build()
|
|
||||||
.mount("/", routes![index])
|
|
||||||
.manage(RocketData{config})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -142,8 +142,7 @@ pub async fn give(
|
||||||
let mut accounts = config.load_accounts();
|
let mut accounts = config.load_accounts();
|
||||||
|
|
||||||
let user_id = format!("{}", ctx.author().id.get());
|
let user_id = format!("{}", ctx.author().id.get());
|
||||||
|
let mut user_account = fetch_or_init_account(config, user_id);
|
||||||
let mut user_account = fetch_or_init_account(config, user_id, Some(ctx.author()));
|
|
||||||
|
|
||||||
let who_id = format!("{}", who.id.get());
|
let who_id = format!("{}", who.id.get());
|
||||||
let Some(other_account) = accounts.iter_mut().find(|a| a.id == who_id ) else {
|
let Some(other_account) = accounts.iter_mut().find(|a| a.id == who_id ) else {
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ pub async fn answer(
|
||||||
#[description_localized("ru", "Вложение к ответу на квест")]
|
#[description_localized("ru", "Вложение к ответу на квест")]
|
||||||
file3: Option<Attachment>,
|
file3: Option<Attachment>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut account = fetch_or_init_account(&ctx.data().config, ctx.author().id.to_string(), Some(ctx.author()));
|
let mut account = fetch_or_init_account(&ctx.data().config, ctx.author().id.to_string());
|
||||||
|
|
||||||
if let Some(_) = account.quests_completed.iter().find(|qid| **qid == quest_id) {
|
if let Some(_) = account.quests_completed.iter().find(|qid| **qid == quest_id) {
|
||||||
return Err(Error::QuestIsCompleted(quest_id));
|
return Err(Error::QuestIsCompleted(quest_id));
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ pub async fn unlock(
|
||||||
};
|
};
|
||||||
|
|
||||||
let acc_id = format!("{}", ctx.author().id.get());
|
let acc_id = format!("{}", ctx.author().id.get());
|
||||||
let mut account = fetch_or_init_account(conf, acc_id, Some(ctx.author()));
|
let mut account = fetch_or_init_account(conf, acc_id);
|
||||||
|
|
||||||
if account.balance < room.value {
|
if account.balance < room.value {
|
||||||
return Err(Error::InsufficientFunds(room.value));
|
return Err(Error::InsufficientFunds(room.value));
|
||||||
|
|
@ -68,7 +68,7 @@ pub async fn r#move(
|
||||||
let conf = &ctx.data().config;
|
let conf = &ctx.data().config;
|
||||||
|
|
||||||
let acc_id = format!("{}", ctx.author().id.get());
|
let acc_id = format!("{}", ctx.author().id.get());
|
||||||
let mut account = fetch_or_init_account(conf, acc_id, Some(ctx.author()));
|
let mut account = fetch_or_init_account(conf, acc_id);
|
||||||
|
|
||||||
if let None = account.rooms_unlocked.iter().find(|rid| **rid == id) {
|
if let None = account.rooms_unlocked.iter().find(|rid| **rid == id) {
|
||||||
return Err(Error::CannotReach(id));
|
return Err(Error::CannotReach(id));
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
#[macro_use] extern crate rocket;
|
|
||||||
|
|
||||||
use std::{sync::{Arc, Mutex}};
|
use std::{sync::{Arc, Mutex}};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
@ -7,9 +5,8 @@ use dotenvy::dotenv;
|
||||||
use poise::serenity_prelude as serenity;
|
use poise::serenity_prelude as serenity;
|
||||||
use squad_quest::config::Config;
|
use squad_quest::config::Config;
|
||||||
|
|
||||||
use crate::{commands::{error_handler, print_error_recursively}, config::{ConfigImpl, DiscordConfig}, error::Error, strings::Strings};
|
use crate::{commands::error_handler, config::{ConfigImpl, DiscordConfig}, error::Error, strings::Strings};
|
||||||
|
|
||||||
mod api;
|
|
||||||
mod commands;
|
mod commands;
|
||||||
mod cli;
|
mod cli;
|
||||||
mod config;
|
mod config;
|
||||||
|
|
@ -68,14 +65,6 @@ async fn main() {
|
||||||
let token = std::env::var(DISCORD_TOKEN).expect("missing DISCORD_TOKEN");
|
let token = std::env::var(DISCORD_TOKEN).expect("missing DISCORD_TOKEN");
|
||||||
let intents = serenity::GatewayIntents::non_privileged();
|
let intents = serenity::GatewayIntents::non_privileged();
|
||||||
|
|
||||||
let conf1 = config.clone();
|
|
||||||
tokio::spawn(async {
|
|
||||||
if let Err(error) = api::rocket(conf1).launch().await {
|
|
||||||
eprintln!("ERROR ON API LAUNCH");
|
|
||||||
print_error_recursively(&error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let framework = poise::Framework::builder()
|
let framework = poise::Framework::builder()
|
||||||
.options(poise::FrameworkOptions {
|
.options(poise::FrameworkOptions {
|
||||||
on_error: |err| Box::pin(error_handler(err)),
|
on_error: |err| Box::pin(error_handler(err)),
|
||||||
|
|
@ -98,8 +87,6 @@ async fn main() {
|
||||||
.setup(|_ctx, _ready, _framework| {
|
.setup(|_ctx, _ready, _framework| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
//poise::builtins::register_globally(ctx, &framework.options().commands).await?;
|
//poise::builtins::register_globally(ctx, &framework.options().commands).await?;
|
||||||
|
|
||||||
|
|
||||||
Ok(Data {
|
Ok(Data {
|
||||||
config,
|
config,
|
||||||
discord: Arc::new(Mutex::new(discord)),
|
discord: Arc::new(Mutex::new(discord)),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//! User accounts
|
//! User accounts
|
||||||
|
|
||||||
use std::{collections::HashMap, fs, io::Write, path::PathBuf};
|
use std::{fs, io::Write, path::PathBuf};
|
||||||
|
|
||||||
use serde::{ Serialize, Deserialize };
|
use serde::{ Serialize, Deserialize };
|
||||||
|
|
||||||
|
|
@ -29,9 +29,6 @@ pub struct Account {
|
||||||
|
|
||||||
/// Vec of rooms unlocked by this user
|
/// Vec of rooms unlocked by this user
|
||||||
pub rooms_unlocked: Vec<u16>,
|
pub rooms_unlocked: Vec<u16>,
|
||||||
|
|
||||||
/// Additional implementation-defined data
|
|
||||||
pub data: Option<HashMap<String, String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Account {
|
impl Default for Account {
|
||||||
|
|
@ -42,7 +39,6 @@ impl Default for Account {
|
||||||
location: u16::default(),
|
location: u16::default(),
|
||||||
quests_completed: Vec::new(),
|
quests_completed: Vec::new(),
|
||||||
rooms_unlocked: Vec::new(),
|
rooms_unlocked: Vec::new(),
|
||||||
data: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use crate::{SquadObject, account::Account, error::Error, quest::Quest};
|
use crate::{SquadObject, account::Account, error::Error, quest::Quest};
|
||||||
|
|
||||||
/// Struct for containing paths to other (de-)serializable things
|
/// Struct for containing paths to other (de-)serializable things
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
/// Path to config directory
|
/// Path to config directory
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//! Map, a.k.a. a graph of rooms
|
//! Map, a.k.a. a graph of rooms
|
||||||
|
|
||||||
use std::{collections::HashMap, fs, io::Write, path::PathBuf};
|
use std::{fs, io::Write, path::PathBuf};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
@ -11,7 +11,7 @@ use crate::{SquadObject, account::Account, error::{Error, MapError}};
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct Map {
|
pub struct Map {
|
||||||
/// Rooms go here
|
/// Rooms go here
|
||||||
pub room: Vec<Room>,
|
pub room: Vec<Room>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Map {
|
impl Default for Map {
|
||||||
|
|
@ -131,8 +131,6 @@ pub struct Room {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// Room description
|
/// Room description
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
/// Additional implementation-based data
|
|
||||||
pub data: Option<HashMap<String, String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_name() -> String {
|
fn default_name() -> String {
|
||||||
|
|
@ -147,7 +145,6 @@ impl Default for Room {
|
||||||
value: u32::default(),
|
value: u32::default(),
|
||||||
name: default_name(),
|
name: default_name(),
|
||||||
description: None,
|
description: None,
|
||||||
data: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//! Text-based quests and user solutions for them
|
//! Text-based quests and user solutions for them
|
||||||
|
|
||||||
use std::{collections::HashMap, fs, io::Write, path::PathBuf};
|
use std::{fs, io::Write, path::PathBuf};
|
||||||
|
|
||||||
use serde::{ Serialize, Deserialize };
|
use serde::{ Serialize, Deserialize };
|
||||||
use crate::{SquadObject, account::Account, error::{Error, QuestError}};
|
use crate::{SquadObject, account::Account, error::{Error, QuestError}};
|
||||||
|
|
@ -66,10 +66,7 @@ pub struct Quest {
|
||||||
pub available_on: Option<Date>,
|
pub available_on: Option<Date>,
|
||||||
|
|
||||||
/// When quest expires
|
/// When quest expires
|
||||||
pub deadline: Option<Date>,
|
pub deadline: Option<Date>
|
||||||
|
|
||||||
/// Additional implementation-defined data
|
|
||||||
pub data: Option<HashMap<String, String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Quest {
|
impl Default for Quest {
|
||||||
|
|
@ -83,8 +80,7 @@ impl Default for Quest {
|
||||||
answer: default_answer(),
|
answer: default_answer(),
|
||||||
public: false,
|
public: false,
|
||||||
available_on: None,
|
available_on: None,
|
||||||
deadline: None,
|
deadline: None
|
||||||
data: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,7 @@ fn quest_one() {
|
||||||
answer: "Accept the answer if it has no attachments and an empty comment".to_owned(),
|
answer: "Accept the answer if it has no attachments and an empty comment".to_owned(),
|
||||||
public: false,
|
public: false,
|
||||||
available_on: None,
|
available_on: None,
|
||||||
deadline: None,
|
deadline: None
|
||||||
..Default::default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(*quest, expected);
|
assert_eq!(*quest, expected);
|
||||||
|
|
@ -74,8 +73,7 @@ fn account_test() {
|
||||||
balance: 150,
|
balance: 150,
|
||||||
location: 0,
|
location: 0,
|
||||||
quests_completed: vec![0],
|
quests_completed: vec![0],
|
||||||
rooms_unlocked: Vec::new(),
|
rooms_unlocked: Vec::new()
|
||||||
..Default::default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let accounts = config.load_accounts();
|
let accounts = config.load_accounts();
|
||||||
|
|
@ -94,7 +92,6 @@ fn load_map() {
|
||||||
value: 0,
|
value: 0,
|
||||||
name: "Entrance".to_string(),
|
name: "Entrance".to_string(),
|
||||||
description: Some("Enter the dungeon".to_string()),
|
description: Some("Enter the dungeon".to_string()),
|
||||||
..Default::default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let room1 = Room {
|
let room1 = Room {
|
||||||
|
|
@ -103,7 +100,6 @@ fn load_map() {
|
||||||
value: 100,
|
value: 100,
|
||||||
name: "Kitchen hall".to_string(),
|
name: "Kitchen hall".to_string(),
|
||||||
description: None,
|
description: None,
|
||||||
..Default::default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let room2 = Room {
|
let room2 = Room {
|
||||||
|
|
@ -112,7 +108,6 @@ fn load_map() {
|
||||||
value: 250,
|
value: 250,
|
||||||
name: "Room".to_string(),
|
name: "Room".to_string(),
|
||||||
description: Some("Simple room with no furniture".to_string()),
|
description: Some("Simple room with no furniture".to_string()),
|
||||||
..Default::default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let room3 = Room {
|
let room3 = Room {
|
||||||
|
|
@ -121,7 +116,6 @@ fn load_map() {
|
||||||
value: 175,
|
value: 175,
|
||||||
name: "Kitchen".to_string(),
|
name: "Kitchen".to_string(),
|
||||||
description: Some("Knives are stored here".to_string()),
|
description: Some("Knives are stored here".to_string()),
|
||||||
..Default::default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let expected = Map {
|
let expected = Map {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue