blastmud/blastmud_game/src/services.rs
2024-03-11 20:42:52 +11:00

161 lines
4.7 KiB
Rust

#[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 environment;
pub mod idlepark;
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<bool> {
// 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(())
}