212 lines
7.1 KiB
Rust
212 lines
7.1 KiB
Rust
use super::{
|
|
get_player_item_or_fail, search_item_for_user, user_error, ItemSearchParams, UResult, UserVerb,
|
|
UserVerbRef, VerbContext,
|
|
};
|
|
use crate::{
|
|
models::item::LocationActionType,
|
|
regular_tasks::queued_command::{
|
|
queue_command_and_save, QueueCommand, QueueCommandHandler, QueuedCommandContext,
|
|
},
|
|
services::{comms::broadcast_to_room, urges::recalculate_urge_growth},
|
|
};
|
|
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 recline, but it turns out the dead can't even do that!".to_owned(),
|
|
)?;
|
|
}
|
|
let item_ref = match ctx.command {
|
|
QueueCommand::Recline { item } => item,
|
|
_ => user_error("Unexpected command".to_owned())?,
|
|
};
|
|
if ctx
|
|
.item
|
|
.active_combat
|
|
.as_ref()
|
|
.and_then(|ac| ac.attacking.as_ref())
|
|
.is_some()
|
|
{
|
|
user_error(
|
|
"Recline... while fighting? You can't figure out how to make it work".to_owned(),
|
|
)?
|
|
}
|
|
if ctx.item.active_climb.is_some() {
|
|
user_error(
|
|
"Recline... while climbing? You can't figure out how to make it work".to_owned(),
|
|
)?
|
|
}
|
|
match ctx.item.action_type {
|
|
LocationActionType::Reclining { .. } => {
|
|
user_error("You're already reclining.".to_owned())?
|
|
}
|
|
_ => {}
|
|
}
|
|
match item_ref {
|
|
None => {}
|
|
Some(item_ref) => {
|
|
let (item_type, item_code) = match item_ref.split_once("/") {
|
|
None => user_error("Invalid item ref in Reclining command".to_owned())?,
|
|
Some(v) => v,
|
|
};
|
|
match ctx
|
|
.trans
|
|
.find_item_by_type_code(&item_type, &item_code)
|
|
.await?
|
|
{
|
|
None => user_error("Item not found".to_owned())?,
|
|
Some(item) => {
|
|
if item.location != ctx.item.location {
|
|
user_error(format!(
|
|
"You try to reclining on {} but realise it's no longer here",
|
|
item.display_for_sentence(true, 1, false)
|
|
))?
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
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 recline, but it turns out the dead can't even do that!".to_owned(),
|
|
)?;
|
|
}
|
|
let item_ref = match ctx.command {
|
|
QueueCommand::Recline { item } => item,
|
|
_ => user_error("Unexpected command".to_owned())?,
|
|
};
|
|
if ctx
|
|
.item
|
|
.active_combat
|
|
.as_ref()
|
|
.and_then(|ac| ac.attacking.as_ref())
|
|
.is_some()
|
|
{
|
|
user_error(
|
|
"Recline... while fighting? You can't figure out how to make it work".to_owned(),
|
|
)?
|
|
}
|
|
if ctx.item.active_climb.is_some() {
|
|
user_error(
|
|
"Recline... while climbing? You can't figure out how to make it work".to_owned(),
|
|
)?
|
|
}
|
|
match ctx.item.action_type {
|
|
LocationActionType::Reclining { .. } => {
|
|
user_error("You're already reclining.".to_owned())?
|
|
}
|
|
_ => {}
|
|
}
|
|
let (item, desc) = match item_ref {
|
|
None => (None, "the floor".to_owned()),
|
|
Some(item_ref) => {
|
|
let (item_type, item_code) = match item_ref.split_once("/") {
|
|
None => user_error("Invalid item ref in Sit command".to_owned())?,
|
|
Some(v) => v,
|
|
};
|
|
match ctx
|
|
.trans
|
|
.find_item_by_type_code(&item_type, &item_code)
|
|
.await?
|
|
{
|
|
None => user_error("Item not found".to_owned())?,
|
|
Some(item) => {
|
|
if item.location != ctx.item.location {
|
|
user_error(format!(
|
|
"You try to recline on {} but realise it's no longer here",
|
|
item.display_for_sentence(true, 1, false)
|
|
))?
|
|
}
|
|
(
|
|
Some(item.clone()),
|
|
item.display_for_sentence(true, 1, false),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
};
|
|
let msg = format!(
|
|
"{} reclines on {}.\n",
|
|
&ctx.item.display_for_sentence(true, 1, true),
|
|
&desc
|
|
);
|
|
broadcast_to_room(ctx.trans, &ctx.item.location, None, &msg).await?;
|
|
|
|
ctx.item.action_type = LocationActionType::Reclining(item.map(|it| it.refstr()));
|
|
recalculate_urge_growth(&ctx.trans, &mut ctx.item).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?;
|
|
|
|
if remaining.starts_with("on ") {
|
|
remaining = remaining[3..].trim();
|
|
}
|
|
if remaining == "" {
|
|
remaining = "floor";
|
|
}
|
|
|
|
let target = if remaining == "here" || remaining == "ground" || remaining == "floor" {
|
|
None
|
|
} else {
|
|
Some(
|
|
search_item_for_user(
|
|
ctx,
|
|
&ItemSearchParams {
|
|
include_loc_contents: true,
|
|
..ItemSearchParams::base(&player_item, &remaining)
|
|
},
|
|
)
|
|
.await?,
|
|
)
|
|
};
|
|
|
|
if player_item.death_data.is_some() {
|
|
user_error(
|
|
"You try to recline, but it turns out the dead can't even do that!".to_owned(),
|
|
)?;
|
|
}
|
|
|
|
if let Some(target) = target.as_ref() {
|
|
if target
|
|
.static_data()
|
|
.and_then(|pd| pd.sit_data.as_ref())
|
|
.is_none()
|
|
{
|
|
user_error("You can't recline on that!".to_owned())?;
|
|
}
|
|
}
|
|
queue_command_and_save(
|
|
ctx,
|
|
&player_item,
|
|
&QueueCommand::Recline {
|
|
item: target.map(|t| t.refstr()),
|
|
},
|
|
)
|
|
.await?;
|
|
Ok(())
|
|
}
|
|
}
|
|
static VERB_INT: Verb = Verb;
|
|
pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef;
|