Allow cutting parts from corpses.
This commit is contained in:
parent
936fcc6dde
commit
d8b0b6bed5
@ -569,11 +569,11 @@ impl DBTrans {
|
||||
dead_only = true;
|
||||
}
|
||||
if dead_only {
|
||||
extra_where.push_str(" AND COALESCE(CAST(details->>'is_dead' AS boolean), false) = true");
|
||||
extra_where.push_str(" AND COALESCE(details->>'death_data' IS NOT NULL, false) = true");
|
||||
} else if search.dead_first {
|
||||
extra_order.push_str(" COALESCE(CAST(details->>'is_dead' AS boolean), false) DESC,");
|
||||
extra_order.push_str(" COALESCE(details->>'death_data' IS NOT NULL, false) DESC,");
|
||||
} else {
|
||||
extra_order.push_str(" COALESCE(CAST(details->>'is_dead' AS boolean), false) ASC,");
|
||||
extra_order.push_str(" COALESCE(details->>'death_data' IS NOT NULL, false) ASC,");
|
||||
}
|
||||
|
||||
let query_wildcard = query.replace("\\", "\\\\")
|
||||
|
@ -18,6 +18,7 @@ mod buy;
|
||||
mod c;
|
||||
pub mod close;
|
||||
pub mod corp;
|
||||
mod cut;
|
||||
pub mod drop;
|
||||
pub mod get;
|
||||
mod describe;
|
||||
@ -130,6 +131,7 @@ static REGISTERED_COMMANDS: UserVerbRegistry = phf_map! {
|
||||
"c" => c::VERB,
|
||||
"close" => close::VERB,
|
||||
"corp" => corp::VERB,
|
||||
"cut" => cut::VERB,
|
||||
"drop" => drop::VERB,
|
||||
"get" => get::VERB,
|
||||
"install" => install::VERB,
|
||||
|
119
blastmud_game/src/message_handler/user_commands/cut.rs
Normal file
119
blastmud_game/src/message_handler/user_commands/cut.rs
Normal file
@ -0,0 +1,119 @@
|
||||
use super::{VerbContext, UserVerb, UserVerbRef, UResult, UserError,
|
||||
get_player_item_or_fail, user_error, search_item_for_user};
|
||||
use async_trait::async_trait;
|
||||
use crate::{
|
||||
models::{
|
||||
item::{Item, DeathData, SkillType},
|
||||
},
|
||||
db::ItemSearchParams,
|
||||
static_content::possession_type::possession_data,
|
||||
language::join_words,
|
||||
services::{
|
||||
destroy_container,
|
||||
skills::skill_check_and_grind, comms::broadcast_to_room,
|
||||
capacity::{CapacityLevel, check_item_capacity}},
|
||||
};
|
||||
use ansi::ansi;
|
||||
|
||||
pub struct Verb;
|
||||
#[async_trait]
|
||||
impl UserVerb for Verb {
|
||||
async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, remaining: &str) -> UResult<()> {
|
||||
let (what_raw, corpse_raw) = match remaining.split_once(" from ") {
|
||||
None => user_error(ansi!("Usage: <bold>cut<reset> thing <bold>from<reset> corpse").to_owned())?,
|
||||
Some(v) => v
|
||||
};
|
||||
|
||||
let player_item = get_player_item_or_fail(ctx).await?;
|
||||
|
||||
let corpse = search_item_for_user(ctx, &ItemSearchParams {
|
||||
include_loc_contents: true,
|
||||
dead_first: true,
|
||||
..ItemSearchParams::base(&player_item, corpse_raw.trim())
|
||||
}).await?;
|
||||
|
||||
let what_norm = what_raw.trim().to_lowercase();
|
||||
let possession_type = match corpse.death_data.as_ref() {
|
||||
None => user_error(format!("You can't do that while {} is still alive!", corpse.pronouns.subject))?,
|
||||
Some(DeathData { parts_remaining, ..}) =>
|
||||
parts_remaining.iter().find(
|
||||
|pt| possession_data().get(pt)
|
||||
.map(|pd| pd.display.to_lowercase() == what_norm ||
|
||||
pd.aliases.iter().any(|a| a.to_lowercase() == what_norm))
|
||||
== Some(true)).ok_or_else(
|
||||
|| UserError(format!("Parts you can cut: {}",
|
||||
&join_words(&parts_remaining.iter().filter_map(|pt| possession_data().get(pt))
|
||||
.map(|pd| pd.display).collect::<Vec<&'static str>>())
|
||||
)))?
|
||||
};
|
||||
|
||||
let possession_data = possession_data().get(possession_type)
|
||||
.ok_or_else(|| UserError("That part doesn't exist anymore".to_owned()))?;
|
||||
|
||||
let mut corpse_mut = (*corpse).clone();
|
||||
match corpse_mut.death_data.as_mut() {
|
||||
None => {},
|
||||
Some(dd) => {
|
||||
dd.parts_remaining =
|
||||
dd
|
||||
.parts_remaining
|
||||
.iter().take_while(|pt| pt != &possession_type)
|
||||
.chain(dd.parts_remaining.iter().skip_while(|pt| pt != &possession_type).skip(1))
|
||||
.map(|pt| (*pt).clone())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
match check_item_capacity(&ctx.trans, &player_item.refstr(), possession_data.weight).await? {
|
||||
CapacityLevel::AboveItemLimit | CapacityLevel::OverBurdened =>
|
||||
user_error("You have too much stuff to take that on!".to_owned())?,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if corpse_mut.death_data.as_ref().map(|dd| dd.parts_remaining.is_empty()) == Some(true) {
|
||||
destroy_container(&ctx.trans, &corpse_mut).await?;
|
||||
} else {
|
||||
ctx.trans.save_item_model(&corpse_mut).await?;
|
||||
}
|
||||
|
||||
let mut player_item_mut = (*player_item).clone();
|
||||
if skill_check_and_grind(&ctx.trans, &mut player_item_mut, &SkillType::Craft, 10.0).await? < 0.0 {
|
||||
broadcast_to_room(&ctx.trans, &player_item.location, None,
|
||||
&format!("{} tries to cut the {} from {}, but only leaves a mutilated mess.\n",
|
||||
&player_item.display_for_sentence(true, 1, true),
|
||||
possession_data.display,
|
||||
corpse.display_for_sentence(true, 1, false)
|
||||
),
|
||||
Some(&format!("{} tries to cut the {} from {}, but only leaves a mutilated mess.\n",
|
||||
&player_item.display_for_sentence(true, 1, true),
|
||||
possession_data.display,
|
||||
corpse.display_for_sentence(true, 1, false)
|
||||
))
|
||||
).await?;
|
||||
} else {
|
||||
let mut new_item: Item = (*possession_type).clone().into();
|
||||
new_item.item_code = format!("{}", ctx.trans.alloc_item_code().await?);
|
||||
new_item.location = player_item.refstr();
|
||||
ctx.trans.save_item_model(&new_item).await?;
|
||||
|
||||
broadcast_to_room(&ctx.trans, &player_item.location, None,
|
||||
&format!("{} expertly cuts the {} from {}.\n",
|
||||
&player_item.display_for_sentence(true, 1, true),
|
||||
possession_data.display,
|
||||
corpse.display_for_sentence(true, 1, false)
|
||||
),
|
||||
Some(&format!("{} expertly cuts the {} from {}.\n",
|
||||
&player_item.display_for_sentence(true, 1, true),
|
||||
possession_data.display,
|
||||
corpse.display_for_sentence(true, 1, false)
|
||||
))
|
||||
).await?;
|
||||
}
|
||||
|
||||
ctx.trans.save_item_model(&player_item_mut).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
static VERB_INT: Verb = Verb;
|
||||
pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef;
|
@ -3,6 +3,7 @@ use crate::{
|
||||
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;
|
||||
@ -78,3 +79,25 @@ pub async fn check_consent(trans: &DBTrans, action: &str,
|
||||
|
||||
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(())
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ use crate::{
|
||||
comms::broadcast_to_room,
|
||||
skills::skill_check_and_grind,
|
||||
skills::skill_check_only,
|
||||
destroy_container,
|
||||
},
|
||||
models::{
|
||||
item::{Item, LocationActionType, Subattack, SkillType, DeathData},
|
||||
@ -13,7 +14,7 @@ use crate::{
|
||||
npc::npc_by_code,
|
||||
species::species_info_map,
|
||||
},
|
||||
message_handler::user_commands::{user_error, UResult, drop::consider_expire_job_for_item},
|
||||
message_handler::user_commands::{user_error, UResult},
|
||||
regular_tasks::{TaskRunContext, TaskHandler},
|
||||
DResult,
|
||||
};
|
||||
@ -506,23 +507,12 @@ impl TaskHandler for RotCorpseTaskHandler {
|
||||
None => { return Ok(None) }
|
||||
Some(r) => r
|
||||
};
|
||||
ctx.trans.delete_item("corpse", &corpse_code).await?;
|
||||
destroy_container(ctx.trans, &corpse).await?;
|
||||
|
||||
let msg_exp = format!("{} rots away to nothing.\n",
|
||||
corpse.display_for_sentence(true, 1, true));
|
||||
let msg_nonexp = format!("{} rots away to nothing.\n",
|
||||
corpse.display_for_sentence(false, 1, true));
|
||||
|
||||
for item in ctx.trans.find_items_by_location(
|
||||
&format!("{}/{}", &corpse.item_type, &corpse.item_code)).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 = corpse.location.clone();
|
||||
consider_expire_job_for_item(ctx.trans, &item_mut).await?;
|
||||
}
|
||||
ctx.trans.transfer_all_possessions_code(
|
||||
&format!("{}/{}", &corpse.item_type, &corpse.item_code),
|
||||
&corpse.location).await?;
|
||||
broadcast_to_room(ctx.trans, &corpse.location, None, &msg_exp, Some(&msg_nonexp)).await?;
|
||||
Ok(None)
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ use super::PossessionData;
|
||||
pub fn skin_data() -> PossessionData {
|
||||
PossessionData {
|
||||
display: "animal skin",
|
||||
aliases: vec!("skin"),
|
||||
details: "The skin of an animal of some kind. It looks like you could make something out of this",
|
||||
weight: 100,
|
||||
..Default::default()
|
||||
@ -20,7 +21,7 @@ pub fn steak_data() -> PossessionData {
|
||||
|
||||
pub fn severed_head_data() -> PossessionData {
|
||||
PossessionData {
|
||||
display: "steak",
|
||||
display: "severed head",
|
||||
details: "A head that has been chopped clean from the body",
|
||||
weight: 250,
|
||||
..Default::default()
|
||||
|
Loading…
Reference in New Issue
Block a user