forked from blasthavers/blastmud
Implement scavenge command
This commit is contained in:
parent
64b96f48ab
commit
925deba57e
@ -3,7 +3,7 @@ use crate::message_handler::ListenerSession;
|
|||||||
use crate::models::{
|
use crate::models::{
|
||||||
consent::{Consent, ConsentType},
|
consent::{Consent, ConsentType},
|
||||||
corp::{Corp, CorpCommType, CorpId, CorpMembership},
|
corp::{Corp, CorpCommType, CorpId, CorpMembership},
|
||||||
item::{Item, ItemFlag, LocationActionType},
|
item::{Item, ItemFlag, LocationActionType, Scavtype},
|
||||||
session::Session,
|
session::Session,
|
||||||
task::{Task, TaskParse},
|
task::{Task, TaskParse},
|
||||||
user::User,
|
user::User,
|
||||||
@ -788,6 +788,29 @@ impl DBTrans {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn find_scavhidden_item_by_location<'a>(
|
||||||
|
self: &'a Self,
|
||||||
|
location: &'a str,
|
||||||
|
scavtype: &Scavtype,
|
||||||
|
max_difficulty: i64,
|
||||||
|
) -> DResult<Option<Item>> {
|
||||||
|
match self
|
||||||
|
.pg_trans()?
|
||||||
|
.query_opt(
|
||||||
|
"SELECT details FROM items WHERE details->>'location' = $1 AND \
|
||||||
|
details->'action_type'->'Scavhidden'->'scavtype' = $2::JSONB AND \
|
||||||
|
(details->'action_type'->'Scavhidden'->>'difficulty')::INT8 <= $3 \
|
||||||
|
ORDER BY details->>'display'
|
||||||
|
LIMIT 1",
|
||||||
|
&[&location, &serde_json::to_value(scavtype)?, &max_difficulty],
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
{
|
||||||
|
None => Ok(None),
|
||||||
|
Some(i) => Ok(Some(serde_json::from_value(i.get("details"))?)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn save_item_model(self: &Self, details: &Item) -> DResult<()> {
|
pub async fn save_item_model(self: &Self, details: &Item) -> DResult<()> {
|
||||||
self.pg_trans()?
|
self.pg_trans()?
|
||||||
.execute(
|
.execute(
|
||||||
@ -817,6 +840,17 @@ impl DBTrans {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn clean_scavhidden<'a>(self: &'a Self) -> DResult<()> {
|
||||||
|
self.pg_trans()?
|
||||||
|
.execute(
|
||||||
|
"DELETE FROM items WHERE \
|
||||||
|
details->'action_type'->'Scavhidden' IS NOT NULL",
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn find_session_for_player<'a>(
|
pub async fn find_session_for_player<'a>(
|
||||||
self: &'a Self,
|
self: &'a Self,
|
||||||
item_code: &'a str,
|
item_code: &'a str,
|
||||||
|
@ -64,6 +64,7 @@ pub mod rent;
|
|||||||
mod report;
|
mod report;
|
||||||
mod reset_spawns;
|
mod reset_spawns;
|
||||||
pub mod say;
|
pub mod say;
|
||||||
|
pub mod scavenge;
|
||||||
mod score;
|
mod score;
|
||||||
mod sign;
|
mod sign;
|
||||||
pub mod sit;
|
pub mod sit;
|
||||||
@ -225,6 +226,9 @@ static REGISTERED_COMMANDS: UserVerbRegistry = phf_map! {
|
|||||||
"\'" => say::VERB,
|
"\'" => say::VERB,
|
||||||
"say" => say::VERB,
|
"say" => say::VERB,
|
||||||
|
|
||||||
|
"scavenge" => scavenge::VERB,
|
||||||
|
"search" => scavenge::VERB,
|
||||||
|
|
||||||
"sc" => score::VERB,
|
"sc" => score::VERB,
|
||||||
"score" => score::VERB,
|
"score" => score::VERB,
|
||||||
|
|
||||||
|
147
blastmud_game/src/message_handler/user_commands/scavenge.rs
Normal file
147
blastmud_game/src/message_handler/user_commands/scavenge.rs
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
use super::{
|
||||||
|
drop::consider_expire_job_for_item, get_player_item_or_fail, user_error, UResult, UserVerb,
|
||||||
|
UserVerbRef, VerbContext,
|
||||||
|
};
|
||||||
|
use crate::{
|
||||||
|
models::item::{LocationActionType, Scavtype, SkillType},
|
||||||
|
regular_tasks::queued_command::{
|
||||||
|
queue_command_and_save, QueueCommand, QueueCommandHandler, QueuedCommandContext,
|
||||||
|
},
|
||||||
|
services::{
|
||||||
|
capacity::{check_item_capacity, CapacityLevel},
|
||||||
|
comms::broadcast_to_room,
|
||||||
|
skills::skill_check_and_grind,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use ansi::ansi;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use std::time;
|
||||||
|
|
||||||
|
pub struct QueueHandler;
|
||||||
|
#[async_trait]
|
||||||
|
impl QueueCommandHandler for QueueHandler {
|
||||||
|
async fn start_command(&self, ctx: &mut QueuedCommandContext<'_>) -> UResult<time::Duration> {
|
||||||
|
if ctx.item.death_data.is_some() {
|
||||||
|
user_error(
|
||||||
|
"You try to search the area, but you realise your ghost hands aren't good for searching".to_owned(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
broadcast_to_room(
|
||||||
|
&ctx.trans,
|
||||||
|
&ctx.item.location,
|
||||||
|
None,
|
||||||
|
&format!(
|
||||||
|
ansi!("<blue>{} starts methodically searching the area.<reset>\n"),
|
||||||
|
ctx.item.display_for_sentence(true, 1, true),
|
||||||
|
),
|
||||||
|
Some(&format!(
|
||||||
|
ansi!("<blue>{} starts methodically searching the area.<reset>\n"),
|
||||||
|
ctx.item.display_for_sentence(false, 1, true),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(time::Duration::from_secs(3))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
async fn finish_command(&self, ctx: &mut QueuedCommandContext<'_>) -> UResult<()> {
|
||||||
|
if ctx.item.death_data.is_some() {
|
||||||
|
user_error(
|
||||||
|
"You try to search the area, but you realise your ghost hands aren't good for searching".to_owned(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
let scav = ctx
|
||||||
|
.item
|
||||||
|
.total_skills
|
||||||
|
.get(&SkillType::Scavenge)
|
||||||
|
.unwrap_or(&0.0)
|
||||||
|
.clone();
|
||||||
|
let found_opt = ctx
|
||||||
|
.trans
|
||||||
|
.find_scavhidden_item_by_location(
|
||||||
|
&ctx.item.location,
|
||||||
|
&Scavtype::Scavenge,
|
||||||
|
(scav * 100.0).max(0.0) as i64,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let mut found = match found_opt {
|
||||||
|
None => user_error("You have a look, and you're pretty sure there's nothing to find here. [Try searching elsewhere, or come back later]".to_owned())?,
|
||||||
|
Some(v) => v,
|
||||||
|
};
|
||||||
|
let diff: f64 = (match found.action_type {
|
||||||
|
LocationActionType::Scavhidden { difficulty, .. } => difficulty,
|
||||||
|
_ => 800,
|
||||||
|
}) as f64
|
||||||
|
/ 100.0;
|
||||||
|
|
||||||
|
if skill_check_and_grind(&ctx.trans, &mut ctx.item, &SkillType::Scavenge, diff).await? < 0.0
|
||||||
|
{
|
||||||
|
// No crit fail for now, it is either yes or no.
|
||||||
|
match ctx.get_session().await? {
|
||||||
|
None => {},
|
||||||
|
Some((sess, _)) =>
|
||||||
|
ctx.trans.queue_for_session(&sess, Some("You give up searching, but you still have a feeling there is something here.\n")).await?
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
found.action_type = LocationActionType::Normal;
|
||||||
|
match check_item_capacity(&ctx.trans, &ctx.item, found.weight).await? {
|
||||||
|
CapacityLevel::OverBurdened | CapacityLevel::AboveItemLimit => {
|
||||||
|
consider_expire_job_for_item(&ctx.trans, &found).await?;
|
||||||
|
broadcast_to_room(
|
||||||
|
&ctx.trans,
|
||||||
|
&ctx.item.location,
|
||||||
|
None,
|
||||||
|
&format!("{} seems to have found {} - but can't carry it so drops it on the ground.\n",
|
||||||
|
ctx.item.display_for_sentence(true, 1, true),
|
||||||
|
found.display_for_sentence(true, 1, false),
|
||||||
|
),
|
||||||
|
Some(&format!(
|
||||||
|
"{} seems to have found {} - but can't carry it so drops it on the ground.\n",
|
||||||
|
ctx.item.display_for_sentence(false, 1, true),
|
||||||
|
found.display_for_sentence(false, 1, false),)),
|
||||||
|
).await?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
broadcast_to_room(
|
||||||
|
&ctx.trans,
|
||||||
|
&ctx.item.location,
|
||||||
|
None,
|
||||||
|
&format!(
|
||||||
|
"{} seems to have found {}.\n",
|
||||||
|
ctx.item.display_for_sentence(true, 1, true),
|
||||||
|
found.display_for_sentence(true, 1, false),
|
||||||
|
),
|
||||||
|
Some(&format!(
|
||||||
|
"{} seems to have found {}.\n",
|
||||||
|
ctx.item.display_for_sentence(false, 1, true),
|
||||||
|
found.display_for_sentence(false, 1, false),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
found.location = ctx.item.refstr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.trans.save_item_model(&found).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Verb;
|
||||||
|
#[async_trait]
|
||||||
|
impl UserVerb for Verb {
|
||||||
|
async fn handle(
|
||||||
|
self: &Self,
|
||||||
|
ctx: &mut VerbContext,
|
||||||
|
_verb: &str,
|
||||||
|
_remaining: &str,
|
||||||
|
) -> UResult<()> {
|
||||||
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
|
queue_command_and_save(ctx, &player_item, &QueueCommand::Scavenge).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static VERB_INT: Verb = Verb;
|
||||||
|
pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef;
|
@ -261,6 +261,11 @@ pub enum Subattack {
|
|||||||
Wrestling,
|
Wrestling,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
|
pub enum Scavtype {
|
||||||
|
Scavenge,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
pub enum LocationActionType {
|
pub enum LocationActionType {
|
||||||
Normal,
|
Normal,
|
||||||
@ -270,6 +275,7 @@ pub enum LocationActionType {
|
|||||||
Wielded,
|
Wielded,
|
||||||
Attacking(Subattack),
|
Attacking(Subattack),
|
||||||
InstalledOnDoorAsLock(Direction),
|
InstalledOnDoorAsLock(Direction),
|
||||||
|
Scavhidden { difficulty: u64, scavtype: Scavtype },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LocationActionType {
|
impl LocationActionType {
|
||||||
@ -277,6 +283,7 @@ impl LocationActionType {
|
|||||||
use LocationActionType::*;
|
use LocationActionType::*;
|
||||||
match self {
|
match self {
|
||||||
InstalledOnDoorAsLock(_) => false,
|
InstalledOnDoorAsLock(_) => false,
|
||||||
|
Scavhidden { .. } => false,
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,8 @@ use super::{TaskHandler, TaskRunContext};
|
|||||||
use crate::db::DBTrans;
|
use crate::db::DBTrans;
|
||||||
use crate::message_handler::user_commands::{
|
use crate::message_handler::user_commands::{
|
||||||
close, cut, drink, drop, eat, fill, get, improvise, make, movement, open, put, recline, remove,
|
close, cut, drink, drop, eat, fill, get, improvise, make, movement, open, put, recline, remove,
|
||||||
sit, stand, use_cmd, user_error, wear, wield, CommandHandlingError, UResult, VerbContext,
|
scavenge, sit, stand, use_cmd, user_error, wear, wield, CommandHandlingError, UResult,
|
||||||
|
VerbContext,
|
||||||
};
|
};
|
||||||
use crate::message_handler::ListenerSession;
|
use crate::message_handler::ListenerSession;
|
||||||
use crate::models::session::Session;
|
use crate::models::session::Session;
|
||||||
@ -102,6 +103,7 @@ pub enum QueueCommand {
|
|||||||
Remove {
|
Remove {
|
||||||
possession_id: String,
|
possession_id: String,
|
||||||
},
|
},
|
||||||
|
Scavenge,
|
||||||
Sit {
|
Sit {
|
||||||
item: Option<String>,
|
item: Option<String>,
|
||||||
},
|
},
|
||||||
@ -143,6 +145,7 @@ impl QueueCommand {
|
|||||||
Put { .. } => "Put",
|
Put { .. } => "Put",
|
||||||
Recline { .. } => "Recline",
|
Recline { .. } => "Recline",
|
||||||
Remove { .. } => "Remove",
|
Remove { .. } => "Remove",
|
||||||
|
Scavenge => "Scavenge",
|
||||||
Sit { .. } => "Sit",
|
Sit { .. } => "Sit",
|
||||||
Stand { .. } => "Stand",
|
Stand { .. } => "Stand",
|
||||||
Use { .. } => "Use",
|
Use { .. } => "Use",
|
||||||
@ -249,6 +252,10 @@ fn queue_command_registry(
|
|||||||
"Remove",
|
"Remove",
|
||||||
&remove::QueueHandler as &(dyn QueueCommandHandler + Sync + Send),
|
&remove::QueueHandler as &(dyn QueueCommandHandler + Sync + Send),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"Scavenge",
|
||||||
|
&scavenge::QueueHandler as &(dyn QueueCommandHandler + Sync + Send),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"Sit",
|
"Sit",
|
||||||
&sit::QueueHandler as &(dyn QueueCommandHandler + Sync + Send),
|
&sit::QueueHandler as &(dyn QueueCommandHandler + Sync + Send),
|
||||||
|
@ -3,12 +3,12 @@ use crate::db::DBTrans;
|
|||||||
use crate::{
|
use crate::{
|
||||||
message_handler::user_commands::rent::recursively_destroy_or_move_item,
|
message_handler::user_commands::rent::recursively_destroy_or_move_item,
|
||||||
models::{
|
models::{
|
||||||
item::{LiquidDetails, LiquidType},
|
item::{LiquidDetails, LiquidType, LocationActionType},
|
||||||
task::{Task, TaskDetails, TaskMeta, TaskRecurrence},
|
task::{Task, TaskDetails, TaskMeta, TaskRecurrence},
|
||||||
},
|
},
|
||||||
regular_tasks::{TaskHandler, TaskRunContext},
|
regular_tasks::{TaskHandler, TaskRunContext},
|
||||||
services::Item,
|
services::Item,
|
||||||
static_content::{possession_type::PossessionType, StaticTask},
|
static_content::{possession_type::PossessionType, room::room_list, StaticTask},
|
||||||
DResult,
|
DResult,
|
||||||
};
|
};
|
||||||
use async_recursion::async_recursion;
|
use async_recursion::async_recursion;
|
||||||
@ -17,6 +17,7 @@ use log::{info, warn};
|
|||||||
use mockall_double::double;
|
use mockall_double::double;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
|
use rand_distr::Distribution;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
@ -168,6 +169,31 @@ pub async fn refresh_all_spawn_points(trans: &DBTrans) -> DResult<()> {
|
|||||||
trans.save_item_model(&location_mut).await?;
|
trans.save_item_model(&location_mut).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also all scav spawns...
|
||||||
|
trans.clean_scavhidden().await?;
|
||||||
|
for room in room_list().iter() {
|
||||||
|
for scav in &room.scavtable {
|
||||||
|
if thread_rng().gen_bool(scav.p_present) {
|
||||||
|
let difflevel = {
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
(rand_distr::Normal::new(scav.difficulty_mean, scav.difficulty_stdev)?
|
||||||
|
.sample(&mut rng)
|
||||||
|
* 100.0)
|
||||||
|
.max(0.0) as u64
|
||||||
|
};
|
||||||
|
let mut item: Item = scav.possession_type.clone().into();
|
||||||
|
item.item_code = format!("{}", trans.alloc_item_code().await?);
|
||||||
|
item.location = format!("room/{}", room.code);
|
||||||
|
item.action_type = LocationActionType::Scavhidden {
|
||||||
|
difficulty: difflevel,
|
||||||
|
scavtype: scav.scavtype.clone(),
|
||||||
|
};
|
||||||
|
trans.save_item_model(&item).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ mod corp_licence;
|
|||||||
mod fangs;
|
mod fangs;
|
||||||
mod food;
|
mod food;
|
||||||
pub mod head_armour;
|
pub mod head_armour;
|
||||||
|
mod junk;
|
||||||
pub mod lock;
|
pub mod lock;
|
||||||
pub mod lower_armour;
|
pub mod lower_armour;
|
||||||
mod meat;
|
mod meat;
|
||||||
@ -442,6 +443,7 @@ pub enum PossessionType {
|
|||||||
Steak,
|
Steak,
|
||||||
AnimalSkin,
|
AnimalSkin,
|
||||||
SeveredHead,
|
SeveredHead,
|
||||||
|
RustySpike,
|
||||||
// Craft benches
|
// Craft benches
|
||||||
KitchenStove,
|
KitchenStove,
|
||||||
// Recipes
|
// Recipes
|
||||||
@ -532,6 +534,7 @@ pub fn possession_data() -> &'static BTreeMap<PossessionType, &'static Possessio
|
|||||||
.chain(lock::data().iter().map(|v| ((*v).0.clone(), &(*v).1)))
|
.chain(lock::data().iter().map(|v| ((*v).0.clone(), &(*v).1)))
|
||||||
.chain(meat::data().iter().map(|v| ((*v).0.clone(), &(*v).1)))
|
.chain(meat::data().iter().map(|v| ((*v).0.clone(), &(*v).1)))
|
||||||
.chain(food::data().iter().map(|v| ((*v).0.clone(), &(*v).1)))
|
.chain(food::data().iter().map(|v| ((*v).0.clone(), &(*v).1)))
|
||||||
|
.chain(junk::data().iter().map(|v| ((*v).0.clone(), &(*v).1)))
|
||||||
.chain(
|
.chain(
|
||||||
head_armour::data()
|
head_armour::data()
|
||||||
.iter()
|
.iter()
|
||||||
|
19
blastmud_game/src/static_content/possession_type/junk.rs
Normal file
19
blastmud_game/src/static_content/possession_type/junk.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use super::{PossessionData, PossessionType};
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
|
||||||
|
pub fn data() -> &'static Vec<(PossessionType, PossessionData)> {
|
||||||
|
static D: OnceCell<Vec<(PossessionType, PossessionData)>> = OnceCell::new();
|
||||||
|
&D.get_or_init(|| {
|
||||||
|
vec![(
|
||||||
|
PossessionType::RustySpike,
|
||||||
|
PossessionData {
|
||||||
|
display: "rusty metal spike",
|
||||||
|
aliases: vec!["spike"],
|
||||||
|
details:
|
||||||
|
"A sharp, rusty spike of metal. You might be able to make something with this, but it is otherwise useless",
|
||||||
|
weight: 250,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
})
|
||||||
|
}
|
@ -4,7 +4,7 @@ use crate::db::DBTrans;
|
|||||||
use crate::{
|
use crate::{
|
||||||
message_handler::user_commands::UResult,
|
message_handler::user_commands::UResult,
|
||||||
models::{
|
models::{
|
||||||
item::{DoorState, Item, ItemFlag},
|
item::{DoorState, Item, ItemFlag, Scavtype},
|
||||||
journal::JournalType,
|
journal::JournalType,
|
||||||
user::WristpadHack,
|
user::WristpadHack,
|
||||||
},
|
},
|
||||||
@ -335,6 +335,14 @@ pub trait RoomEnterTrigger {
|
|||||||
async fn handle_enter(self: &Self, ctx: &mut QueuedCommandContext, room: &Room) -> UResult<()>;
|
async fn handle_enter(self: &Self, ctx: &mut QueuedCommandContext, room: &Room) -> UResult<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Scavinfo {
|
||||||
|
pub possession_type: PossessionType,
|
||||||
|
pub p_present: f64, // probability it is there.
|
||||||
|
pub difficulty_mean: f64,
|
||||||
|
pub difficulty_stdev: f64,
|
||||||
|
pub scavtype: Scavtype,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Room {
|
pub struct Room {
|
||||||
pub zone: &'static str,
|
pub zone: &'static str,
|
||||||
// Other zones where it can be seen on the map and accessed.
|
// Other zones where it can be seen on the map and accessed.
|
||||||
@ -359,6 +367,7 @@ pub struct Room {
|
|||||||
pub wristpad_hack_allowed: Option<WristpadHack>,
|
pub wristpad_hack_allowed: Option<WristpadHack>,
|
||||||
pub journal: Option<JournalType>,
|
pub journal: Option<JournalType>,
|
||||||
pub enter_trigger: Option<&'static (dyn RoomEnterTrigger + Sync + Send)>,
|
pub enter_trigger: Option<&'static (dyn RoomEnterTrigger + Sync + Send)>,
|
||||||
|
pub scavtable: Vec<Scavinfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Room {
|
impl Default for Room {
|
||||||
@ -384,6 +393,7 @@ impl Default for Room {
|
|||||||
wristpad_hack_allowed: None,
|
wristpad_hack_allowed: None,
|
||||||
journal: None,
|
journal: None,
|
||||||
enter_trigger: None,
|
enter_trigger: None,
|
||||||
|
scavtable: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -555,6 +565,18 @@ mod test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn room_shorts_should_be_display_length_2() {
|
||||||
|
assert_eq!(
|
||||||
|
room_list()
|
||||||
|
.iter()
|
||||||
|
.map(|r| (r.code, ansi::strip_special_characters(r.short)))
|
||||||
|
.filter(|(_c, s)| s.len() != 2)
|
||||||
|
.collect::<Vec<(&'static str, String)>>(),
|
||||||
|
vec![]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn room_map_by_code_should_have_repro_xv_chargen() {
|
fn room_map_by_code_should_have_repro_xv_chargen() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user