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 { if ctx.item.death_data.is_some() { user_error("You try to sit, but it turns out the dead can't even do that!".to_owned())?; } let item_ref = match ctx.command { QueueCommand::Sit { 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( "Sit... while fighting? You can't figure out how to make it work".to_owned(), )? } if ctx.item.active_climb.is_some() { user_error( "Sit... while climbing? You can't figure out how to make it work".to_owned(), )? } match ctx.item.action_type { LocationActionType::Sitting { .. } => user_error("You're already sitting.".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 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 sit on {} but realise it's no longer here", item.display_for_sentence(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 sit, but it turns out the dead can't even do that!".to_owned())?; } let item_ref = match ctx.command { QueueCommand::Sit { 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( "Sit... while fighting? You can't figure out how to make it work".to_owned(), )? } if ctx.item.active_climb.is_some() { user_error( "Sit... while climbing? You can't figure out how to make it work".to_owned(), )? } match ctx.item.action_type { LocationActionType::Sitting { .. } => user_error("You're already sitting.".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 sit on {} but realise it's no longer here", item.display_for_sentence(1, false) ))? } (Some(item.clone()), item.display_for_sentence(1, false)) } } } }; let msg = format!( "{} sits on {}.\n", &ctx.item.display_for_sentence(1, true), &desc ); broadcast_to_room(ctx.trans, &ctx.item.location, None, &msg).await?; ctx.item.action_type = LocationActionType::Sitting(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 sit, 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 sit on that!".to_owned())?; } } queue_command_and_save( ctx, &player_item, &QueueCommand::Sit { item: target.map(|t| t.refstr()), }, ) .await?; Ok(()) } } static VERB_INT: Verb = Verb; pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef;