#[double] use crate::db::DBTrans; use crate::{ message_handler::user_commands::{drop::consider_expire_job_for_item, user_error, UResult}, models::item::Item, models::{ consent::{Consent, ConsentStatus, ConsentType}, item::ItemSpecialData, }, static_content::{ dynzone::{dynzone_by_type, DynzoneType}, npc::npc_by_code, room::room_map_by_code, }, DResult, }; use mockall_double::double; pub mod capacity; pub mod charging; pub mod combat; pub mod comms; pub mod display; pub mod effect; pub mod room_effects; pub mod sharing; pub mod skills; pub mod spawn; pub mod tempbuff; pub mod urges; pub 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_ref_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(()) } pub fn require_power(item: &Item) -> UResult<()> { let result = match item.item_type.as_str() { "room" => room_map_by_code() .get(item.item_code.as_str()) .map(|r| r.has_power) .unwrap_or(false), "dynroom" => match &item.special_data { Some(ItemSpecialData::DynroomData { dynzone_code, dynroom_code, }) => DynzoneType::from_str(dynzone_code.as_str()) .and_then(|dzt| dynzone_by_type().get(&dzt)) .and_then(|dz| dz.dyn_rooms.get(dynroom_code.as_str())) .map(|dr| dr.has_power) .unwrap_or(false), _ => false, }, _ => false, }; if !result { user_error("That would require power, and it looks like wireless power distribution is not available here.".to_owned())?; } Ok(()) }