forked from blasthavers/blastmud
326 lines
12 KiB
Rust
326 lines
12 KiB
Rust
use super::{
|
|
get_player_item_or_fail, parsing::parse_count, search_item_for_user, search_items_for_user,
|
|
user_error, ItemSearchParams, UResult, UserError, UserVerb, UserVerbRef, VerbContext,
|
|
};
|
|
use crate::{
|
|
models::item::{ItemFlag, LocationActionType},
|
|
regular_tasks::queued_command::{
|
|
queue_command, QueueCommand, QueueCommandHandler, QueuedCommandContext,
|
|
},
|
|
services::{
|
|
capacity::{check_item_capacity, recalculate_container_weight, CapacityLevel},
|
|
comms::broadcast_to_room,
|
|
},
|
|
static_content::possession_type::possession_data,
|
|
};
|
|
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 put it in, but your ghostly hands slip through it uselessly".to_owned(),
|
|
)?;
|
|
}
|
|
let (container_code, item_code) = match ctx.command {
|
|
QueueCommand::Put {
|
|
container_possession_id,
|
|
target_possession_id,
|
|
} => (container_possession_id, target_possession_id),
|
|
_ => user_error("Expected Put command".to_owned())?,
|
|
};
|
|
|
|
let container = ctx
|
|
.trans
|
|
.find_item_by_type_code("possession", &container_code)
|
|
.await?
|
|
.ok_or_else(|| UserError("Item to put in not found".to_owned()))?;
|
|
if container.location != ctx.item.location && container.location != ctx.item.refstr() {
|
|
user_error(format!(
|
|
"You try to put something in {} but realise {} is no longer there",
|
|
container.display_for_sentence(ctx.explicit().await?, 1, false),
|
|
container.display_for_sentence(ctx.explicit().await?, 1, false),
|
|
))?
|
|
}
|
|
let item = ctx
|
|
.trans
|
|
.find_item_by_type_code("possession", &item_code)
|
|
.await?
|
|
.ok_or_else(|| UserError("Item to place not found".to_owned()))?;
|
|
if item.location != ctx.item.refstr() {
|
|
user_error(format!(
|
|
"You try to put {} in {}, but realise you no longer have it",
|
|
item.display_for_sentence(ctx.explicit().await?, 1, false),
|
|
container.display_for_sentence(ctx.explicit().await?, 1, false),
|
|
))?
|
|
}
|
|
let msg_exp = format!(
|
|
"{} fumbles around trying to put {} in {}.\n",
|
|
&ctx.item.display_for_sentence(true, 1, true),
|
|
&item.display_for_sentence(true, 1, false),
|
|
&container.display_for_sentence(true, 1, false)
|
|
);
|
|
let msg_nonexp = format!(
|
|
"{} fumbles around trying to put {} in {}.\n",
|
|
&ctx.item.display_for_sentence(false, 1, true),
|
|
&item.display_for_sentence(false, 1, false),
|
|
&container.display_for_sentence(false, 1, false)
|
|
);
|
|
broadcast_to_room(
|
|
ctx.trans,
|
|
&ctx.item.location,
|
|
None,
|
|
&msg_exp,
|
|
Some(&msg_nonexp),
|
|
)
|
|
.await?;
|
|
Ok(time::Duration::from_secs(1))
|
|
}
|
|
|
|
#[allow(unreachable_patterns)]
|
|
async fn finish_command(&self, ctx: &mut QueuedCommandContext<'_>) -> UResult<()> {
|
|
if ctx.item.death_data.is_some() {
|
|
user_error(
|
|
"You try to put it in, but your ghostly hands slip through it uselessly".to_owned(),
|
|
)?;
|
|
}
|
|
let (container_code, item_code) = match ctx.command {
|
|
QueueCommand::Put {
|
|
container_possession_id,
|
|
target_possession_id,
|
|
} => (container_possession_id, target_possession_id),
|
|
_ => user_error("Expected Put command".to_owned())?,
|
|
};
|
|
|
|
let is_explicit = ctx.explicit().await?;
|
|
let container = ctx
|
|
.trans
|
|
.find_item_by_type_code("possession", &container_code)
|
|
.await?
|
|
.ok_or_else(|| UserError("Item to put in not found".to_owned()))?;
|
|
if container.location != ctx.item.location && container.location != ctx.item.refstr() {
|
|
user_error(format!(
|
|
"You try to put something in {} but realise {} is no longer there",
|
|
container.display_for_sentence(is_explicit, 1, false),
|
|
container.display_for_sentence(is_explicit, 1, false),
|
|
))?
|
|
}
|
|
let item = ctx
|
|
.trans
|
|
.find_item_by_type_code("possession", &item_code)
|
|
.await?
|
|
.ok_or_else(|| UserError("Item to place not found".to_owned()))?;
|
|
if item.location != ctx.item.refstr() {
|
|
user_error(format!(
|
|
"You try to put {} in {}, but realise you no longer have it",
|
|
item.display_for_sentence(is_explicit, 1, false),
|
|
container.display_for_sentence(is_explicit, 1, false),
|
|
))?
|
|
}
|
|
|
|
let container_data = container
|
|
.possession_type
|
|
.as_ref()
|
|
.and_then(|pt| {
|
|
possession_data()
|
|
.get(pt)
|
|
.and_then(|pd| pd.container_data.as_ref())
|
|
})
|
|
.ok_or_else(|| {
|
|
UserError(format!(
|
|
"You try to put {} in {}, but can't find out a way to get anything in it",
|
|
item.display_for_sentence(is_explicit, 1, false),
|
|
container.display_for_sentence(is_explicit, 1, false),
|
|
))
|
|
})?;
|
|
container_data.checker.check_place(&container, &item)?;
|
|
|
|
let msg_exp = format!(
|
|
"{} puts {} in {}.\n",
|
|
&ctx.item.display_for_sentence(true, 1, true),
|
|
&item.display_for_sentence(true, 1, false),
|
|
&container.display_for_sentence(true, 1, false)
|
|
);
|
|
let msg_nonexp = format!(
|
|
"{} puts {} in {}.\n",
|
|
&ctx.item.display_for_sentence(false, 1, true),
|
|
&item.display_for_sentence(false, 1, false),
|
|
&container.display_for_sentence(false, 1, false)
|
|
);
|
|
broadcast_to_room(
|
|
ctx.trans,
|
|
&ctx.item.location,
|
|
None,
|
|
&msg_exp,
|
|
Some(&msg_nonexp),
|
|
)
|
|
.await?;
|
|
|
|
let possession_data = match item
|
|
.possession_type
|
|
.as_ref()
|
|
.and_then(|pt| possession_data().get(&pt))
|
|
{
|
|
None => {
|
|
user_error("That item no longer exists in the game so can't be handled".to_owned())?
|
|
}
|
|
Some(pd) => pd,
|
|
};
|
|
|
|
match check_item_capacity(ctx.trans, &container, possession_data.weight).await? {
|
|
CapacityLevel::AboveItemLimit => user_error(format!(
|
|
"{} just can't hold that many things!",
|
|
container.display_for_sentence(is_explicit, 1, true),
|
|
))?,
|
|
CapacityLevel::OverBurdened => user_error(format!(
|
|
"{} You can't place {} because it is too heavy!",
|
|
if is_explicit { "Fuck!" } else { "Rats!" },
|
|
&ctx.item.display_for_sentence(is_explicit, 1, false)
|
|
))?,
|
|
_ => (),
|
|
}
|
|
|
|
let mut item_mut = (*item).clone();
|
|
item_mut.location = container.refstr();
|
|
item_mut.action_type = LocationActionType::Normal;
|
|
ctx.trans.save_item_model(&item_mut).await?;
|
|
|
|
recalculate_container_weight(&ctx.trans, &container).await?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub struct Verb;
|
|
#[async_trait]
|
|
impl UserVerb for Verb {
|
|
async fn handle(
|
|
self: &Self,
|
|
ctx: &mut VerbContext,
|
|
_verb: &str,
|
|
mut remaining: &str,
|
|
) -> UResult<()> {
|
|
let player_item = get_player_item_or_fail(ctx).await?;
|
|
|
|
let mut get_limit = Some(1);
|
|
if remaining == "all" || remaining.starts_with("all ") {
|
|
remaining = remaining[3..].trim();
|
|
get_limit = None;
|
|
} else if let (Some(n), remaining2) = parse_count(remaining) {
|
|
get_limit = Some(n);
|
|
remaining = remaining2;
|
|
}
|
|
|
|
let (into_what, for_what) = match remaining.split_once(" in ") {
|
|
None => {
|
|
user_error(ansi!("Try <bold>put<reset> item <bold>in<reset> container").to_owned())?
|
|
}
|
|
Some((item_str_raw, container_str_raw)) => {
|
|
let container = search_item_for_user(
|
|
ctx,
|
|
&ItemSearchParams {
|
|
include_loc_contents: true,
|
|
include_contents: true,
|
|
item_type_only: Some("possession"),
|
|
..ItemSearchParams::base(&player_item, container_str_raw.trim())
|
|
},
|
|
)
|
|
.await?;
|
|
(container, item_str_raw.trim())
|
|
}
|
|
};
|
|
|
|
let targets = search_items_for_user(
|
|
ctx,
|
|
&ItemSearchParams {
|
|
include_contents: true,
|
|
item_type_only: Some("possession"),
|
|
limit: get_limit.unwrap_or(100),
|
|
..ItemSearchParams::base(&player_item, for_what)
|
|
},
|
|
)
|
|
.await?;
|
|
if player_item.death_data.is_some() {
|
|
user_error(
|
|
"You try to put it in, but your ghostly hands slip through it uselessly".to_owned(),
|
|
)?;
|
|
}
|
|
|
|
let mut did_anything: bool = false;
|
|
let mut player_item_mut = (*player_item).clone();
|
|
for target in targets
|
|
.iter()
|
|
.filter(|t| t.action_type.is_visible_in_look())
|
|
{
|
|
if target.item_type == into_what.item_type && target.item_code == into_what.item_code {
|
|
user_error(
|
|
"You briefly ponder whether something can contain itself, but it blows your mind and you give up.".to_owned()
|
|
)?;
|
|
}
|
|
if target.item_type != "possession" {
|
|
user_error("You can't put that in something!".to_owned())?;
|
|
}
|
|
|
|
did_anything = true;
|
|
|
|
if into_what.flags.contains(&ItemFlag::Bench) && target.flags.contains(&ItemFlag::Book)
|
|
{
|
|
let pages = ctx.trans.find_items_by_location(&target.refstr()).await?;
|
|
if !pages.is_empty() {
|
|
ctx.trans
|
|
.queue_for_session(&ctx.session,
|
|
Some(
|
|
&format!("For ease of later use, you decide to rip the pages out of {} before placing them in {}.\n",
|
|
&target.display_for_session(&ctx.session_dat),
|
|
&into_what.display_for_session(&ctx.session_dat)),
|
|
)
|
|
).await?;
|
|
for page in pages {
|
|
queue_command(
|
|
ctx,
|
|
&mut player_item_mut,
|
|
&QueueCommand::GetFromContainer {
|
|
from_possession_id: target.item_code.clone(),
|
|
get_possession_id: page.item_code.clone(),
|
|
},
|
|
)
|
|
.await?;
|
|
queue_command(
|
|
ctx,
|
|
&mut player_item_mut,
|
|
&QueueCommand::Put {
|
|
container_possession_id: into_what.item_code.clone(),
|
|
target_possession_id: page.item_code.clone(),
|
|
},
|
|
)
|
|
.await?;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
queue_command(
|
|
ctx,
|
|
&mut player_item_mut,
|
|
&QueueCommand::Put {
|
|
container_possession_id: into_what.item_code.clone(),
|
|
target_possession_id: target.item_code.clone(),
|
|
},
|
|
)
|
|
.await?;
|
|
}
|
|
if !did_anything {
|
|
user_error("I didn't find anything matching.".to_owned())?;
|
|
} else {
|
|
ctx.trans.save_item_model(&player_item_mut).await?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
static VERB_INT: Verb = Verb;
|
|
pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef;
|