use super::{ get_player_item_or_fail, parsing::parse_count, search_item_for_user, search_items_for_user, user_error, UResult, UserVerb, UserVerbRef, VerbContext, }; use crate::{ db::ItemSearchParams, models::item::{ItemFlag, ItemSpecialData}, services::{ capacity::{check_item_capacity, CapacityLevel}, comms::broadcast_to_room, }, }; use ansi::ansi; use async_trait::async_trait; pub struct Verb; #[async_trait] impl UserVerb for Verb { async fn handle( self: &Self, ctx: &mut VerbContext, verb: &str, remaining: &str, ) -> UResult<()> { let reverse: bool = verb == "unload"; let sep = if reverse { "from" } else { "onto" }; let (mut item_name, npc_name) = match remaining.split_once(sep) { None => user_error(format!( ansi!("I couldn't understand that. Try {} item {} npc"), verb, sep ))?, Some(v) => v, }; let player_item = get_player_item_or_fail(ctx).await?; let npc = search_item_for_user( ctx, &ItemSearchParams { include_loc_contents: true, ..ItemSearchParams::base(&player_item, npc_name.trim()) }, ) .await?; if !npc.flags.contains(&ItemFlag::CanLoad) { user_error(format!("You can't {} things {} that!", verb, sep))? } match npc.special_data.as_ref() { Some(ItemSpecialData::HireData { hired_by: Some(hired_by), }) if hired_by == &player_item.item_code => {} _ => user_error(format!( "{} doesn't seem to be letting you do that. Try hiring {} first!", npc.display_for_session(&ctx.session_dat), npc.pronouns.object ))?, } let mut item_limit = Some(1); if item_name == "all" || item_name.starts_with("all ") { item_name = item_name[3..].trim(); item_limit = None; } else if let (Some(n), remaining2) = parse_count(item_name) { item_limit = Some(n); item_name = remaining2; } let items = search_items_for_user( ctx, &ItemSearchParams { include_contents: reverse, include_loc_contents: !reverse, item_type_only: Some("possession"), limit: item_limit.unwrap_or(100), ..ItemSearchParams::base(&npc, item_name.trim()) }, ) .await?; for item in items { if reverse { match check_item_capacity(&ctx.trans, &player_item.location, item.weight).await? { CapacityLevel::AboveItemLimit => user_error( "There is not enough space here to unload another item.".to_owned(), )?, _ => {} } } else { match check_item_capacity(&ctx.trans, &npc.refstr(), item.weight).await? { CapacityLevel::AboveItemLimit | CapacityLevel::OverBurdened => { user_error("There is not enough capacity to load that item.".to_owned())? } _ => {} } } let mut item_mut = (*item).clone(); item_mut.location = if reverse { npc.location.clone() } else { npc.refstr() }; ctx.trans.save_item_model(&item_mut).await?; broadcast_to_room( &ctx.trans, &npc.location, None, &format!( "{} {}s {} {} {}\n", &npc.display_for_sentence(true, 1, true), verb, &item.display_for_sentence(true, 1, false), sep, &npc.pronouns.intensive ), Some(&format!( "{} {}s {} {} {}\n", &npc.display_for_sentence(false, 1, true), verb, &item.display_for_sentence(false, 1, false), sep, &npc.pronouns.intensive )), ) .await?; } Ok(()) } } static VERB_INT: Verb = Verb; pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef;