use crate::{ DResult, models::item::Item, models::consent::{Consent, ConsentType, ConsentStatus}, static_content::npc::npc_by_code, message_handler::user_commands::drop::consider_expire_job_for_item, }; use mockall_double::double; #[double] use crate::db::DBTrans; pub mod comms; pub mod combat; pub mod skills; pub mod capacity; pub mod effect; fn check_one_consent(consent: &Consent, action: &str, target: &Item) -> bool { if let Some((loctype, loccode)) = target.location.split_once("/") { if !consent.only_in.is_empty() { if loctype != "room" || !consent.only_in.iter().any(|v| v == loccode) { return false; } } if !consent.allow_private && loctype != "room" { return false; } } else { if !consent.only_in.is_empty() || !consent.allow_private { return false; } } if let Some(fight_consent) = consent.fight_consent.as_ref() { if fight_consent.status == ConsentStatus::PendingAdd { return false; } if !fight_consent.allow_pick && action == "pick" { return false; } } true } pub async fn check_consent(trans: &DBTrans, action: &str, consent_type: &ConsentType, by: &Item, target: &Item) -> DResult { // Consent is only a factor on actions by players towards other players or npcs. if by.item_type != "player" || (target.item_type != "player" && target.item_type != "npc") { return Ok(true); } if target.item_type == "npc" { return Ok(match npc_by_code().get(target.item_code.as_str()) { None => false, Some(npc) => npc.player_consents.contains(consent_type) }); } if target.item_code == by.item_code { return Ok(true) } trans.delete_expired_user_consent().await?; if let Some(consent) = trans.find_user_consent_by_parties_type( &target.item_code, &by.item_code, consent_type).await? { if check_one_consent(&consent, action, &target) { return Ok(true); } } trans.delete_expired_corp_consent().await?; if let Some(consent) = trans.find_corp_consent_by_user_parties_type( &target.item_code, &by.item_code, consent_type).await? { if check_one_consent(&consent, action, &target) { return Ok(true); } } Ok(false) } pub async fn destroy_container(trans: &DBTrans, container: &Item) -> DResult<()> { trans.delete_item(&container.item_type, &container.item_code).await?; for item in trans.find_items_by_location( &container.refstr() ).await?.into_iter() { let mut item_mut = (*item).clone(); // We only update this to support consider_expire_job - it gets updated in bulk // by transfer_all_possession below. item_mut.location = container.location.clone(); match capacity::check_item_capacity(trans, &container.location, item_mut.weight).await? { capacity::CapacityLevel::OverBurdened | capacity::CapacityLevel::AboveItemLimit => trans.delete_item(&item_mut.item_type, &item_mut.item_code).await?, _ => consider_expire_job_for_item(trans, &item_mut).await? } } trans.transfer_all_possessions_code( &container.refstr(), &container.location).await?; Ok(()) }