Compare commits
No commits in common. "d8b0b6bed5d26c7bd5aa93318798187a56e91026" and "8102f2f7b03410f1a8ccc38bc493a88b0b41e946" have entirely different histories.
d8b0b6bed5
...
8102f2f7b0
@ -569,11 +569,11 @@ impl DBTrans {
|
|||||||
dead_only = true;
|
dead_only = true;
|
||||||
}
|
}
|
||||||
if dead_only {
|
if dead_only {
|
||||||
extra_where.push_str(" AND COALESCE(details->>'death_data' IS NOT NULL, false) = true");
|
extra_where.push_str(" AND COALESCE(CAST(details->>'is_dead' AS boolean), false) = true");
|
||||||
} else if search.dead_first {
|
} else if search.dead_first {
|
||||||
extra_order.push_str(" COALESCE(details->>'death_data' IS NOT NULL, false) DESC,");
|
extra_order.push_str(" COALESCE(CAST(details->>'is_dead' AS boolean), false) DESC,");
|
||||||
} else {
|
} else {
|
||||||
extra_order.push_str(" COALESCE(details->>'death_data' IS NOT NULL, false) ASC,");
|
extra_order.push_str(" COALESCE(CAST(details->>'is_dead' AS boolean), false) ASC,");
|
||||||
}
|
}
|
||||||
|
|
||||||
let query_wildcard = query.replace("\\", "\\\\")
|
let query_wildcard = query.replace("\\", "\\\\")
|
||||||
|
@ -18,7 +18,6 @@ mod buy;
|
|||||||
mod c;
|
mod c;
|
||||||
pub mod close;
|
pub mod close;
|
||||||
pub mod corp;
|
pub mod corp;
|
||||||
mod cut;
|
|
||||||
pub mod drop;
|
pub mod drop;
|
||||||
pub mod get;
|
pub mod get;
|
||||||
mod describe;
|
mod describe;
|
||||||
@ -131,7 +130,6 @@ static REGISTERED_COMMANDS: UserVerbRegistry = phf_map! {
|
|||||||
"c" => c::VERB,
|
"c" => c::VERB,
|
||||||
"close" => close::VERB,
|
"close" => close::VERB,
|
||||||
"corp" => corp::VERB,
|
"corp" => corp::VERB,
|
||||||
"cut" => cut::VERB,
|
|
||||||
"drop" => drop::VERB,
|
"drop" => drop::VERB,
|
||||||
"get" => get::VERB,
|
"get" => get::VERB,
|
||||||
"install" => install::VERB,
|
"install" => install::VERB,
|
||||||
|
@ -20,7 +20,7 @@ impl UserVerb for Verb {
|
|||||||
async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, remaining: &str) -> UResult<()> {
|
async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, remaining: &str) -> UResult<()> {
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
|
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("It doesn't really seem fair, but you realise you won't be able to attack anyone while you're dead!".to_string())?;
|
user_error("It doesn't really seem fair, but you realise you won't be able to attack anyone while you're dead!".to_string())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ impl UserVerb for Verb {
|
|||||||
user_error(ansi!("<blue>Your wristpad vibrates and blocks you from doing that.<reset> You get a feeling that while the empire might be gone, the system to stop subjects with working wristpads from fighting each unless they have an consented is very much functional. [Try <bold>help allow<reset>]").to_string())?
|
user_error(ansi!("<blue>Your wristpad vibrates and blocks you from doing that.<reset> You get a feeling that while the empire might be gone, the system to stop subjects with working wristpads from fighting each unless they have an consented is very much functional. [Try <bold>help allow<reset>]").to_string())?
|
||||||
}
|
}
|
||||||
|
|
||||||
if attack_whom.death_data.is_some() {
|
if attack_whom.is_dead {
|
||||||
user_error("There's no point attacking the dead!".to_string())?
|
user_error("There's no point attacking the dead!".to_string())?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ impl UserVerb for Verb {
|
|||||||
async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, remaining: &str) -> UResult<()> {
|
async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, remaining: &str) -> UResult<()> {
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
|
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("Nobody seems to listen when you try to buy... possibly because you're dead.".to_owned())?
|
user_error("Nobody seems to listen when you try to buy... possibly because you're dead.".to_owned())?
|
||||||
}
|
}
|
||||||
let (heretype, herecode) = player_item.location.split_once("/").unwrap_or(("room", "repro_xv_chargen"));
|
let (heretype, herecode) = player_item.location.split_once("/").unwrap_or(("room", "repro_xv_chargen"));
|
||||||
|
@ -1,119 +0,0 @@
|
|||||||
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;
|
|
@ -119,7 +119,7 @@ impl QueueCommandHandler for QueueHandler {
|
|||||||
async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
||||||
-> UResult<time::Duration> {
|
-> UResult<time::Duration> {
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("You try to drop it, but your ghostly hands slip through it uselessly".to_owned())?;
|
user_error("You try to drop it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
}
|
}
|
||||||
let item_id = match command {
|
let item_id = match command {
|
||||||
@ -151,7 +151,7 @@ impl QueueCommandHandler for QueueHandler {
|
|||||||
async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
||||||
-> UResult<()> {
|
-> UResult<()> {
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("You try to get it, but your ghostly hands slip through it uselessly".to_owned())?;
|
user_error("You try to get it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
}
|
}
|
||||||
let item_id = match command {
|
let item_id = match command {
|
||||||
@ -219,7 +219,7 @@ impl UserVerb for Verb {
|
|||||||
..ItemSearchParams::base(&player_item, &remaining)
|
..ItemSearchParams::base(&player_item, &remaining)
|
||||||
}).await?;
|
}).await?;
|
||||||
|
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("You try to drop it, but your ghostly hands slip through it uselessly".to_owned())?;
|
user_error("You try to drop it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ impl QueueCommandHandler for QueueHandler {
|
|||||||
async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
||||||
-> UResult<time::Duration> {
|
-> UResult<time::Duration> {
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("You try to get it, but your ghostly hands slip through it uselessly".to_owned())?;
|
user_error("You try to get it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
}
|
}
|
||||||
let item_id = match command {
|
let item_id = match command {
|
||||||
@ -66,7 +66,7 @@ impl QueueCommandHandler for QueueHandler {
|
|||||||
async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
||||||
-> UResult<()> {
|
-> UResult<()> {
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("You try to get it, but your ghostly hands slip through it uselessly".to_owned())?;
|
user_error("You try to get it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
}
|
}
|
||||||
let item_id = match command {
|
let item_id = match command {
|
||||||
@ -133,7 +133,7 @@ impl UserVerb for Verb {
|
|||||||
limit: get_limit.unwrap_or(100),
|
limit: get_limit.unwrap_or(100),
|
||||||
..ItemSearchParams::base(&player_item, &remaining)
|
..ItemSearchParams::base(&player_item, &remaining)
|
||||||
}).await?;
|
}).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("You try to get it, but your ghostly hands slip through it uselessly".to_owned())?;
|
user_error("You try to get it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ impl UserVerb for Verb {
|
|||||||
Some(v) => v
|
Some(v) => v
|
||||||
};
|
};
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("Apparently, you have to be alive to work as an installer.\
|
user_error("Apparently, you have to be alive to work as an installer.\
|
||||||
So discriminatory!".to_owned())?;
|
So discriminatory!".to_owned())?;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ pub struct Verb;
|
|||||||
impl UserVerb for Verb {
|
impl UserVerb for Verb {
|
||||||
async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, _remaining: &str) -> UResult<()> {
|
async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, _remaining: &str) -> UResult<()> {
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
ctx.trans.queue_for_session(ctx.session, Some("The dead don't really have an inventory.\n")).await?;
|
ctx.trans.queue_for_session(ctx.session, Some("The dead don't really have an inventory.\n")).await?;
|
||||||
}
|
}
|
||||||
let inv = ctx.trans.find_items_by_location(&format!("{}/{}",
|
let inv = ctx.trans.find_items_by_location(&format!("{}/{}",
|
||||||
|
@ -14,7 +14,7 @@ impl UserVerb for Verb {
|
|||||||
async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, _remaining: &str) -> UResult<()> {
|
async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, _remaining: &str) -> UResult<()> {
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
|
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("Nobody seems to offer you any prices... possibly because you're dead.".to_owned())?
|
user_error("Nobody seems to offer you any prices... possibly because you're dead.".to_owned())?
|
||||||
}
|
}
|
||||||
let (heretype, herecode) = player_item.location.split_once("/").unwrap_or(("room", "repro_xv_chargen"));
|
let (heretype, herecode) = player_item.location.split_once("/").unwrap_or(("room", "repro_xv_chargen"));
|
||||||
|
@ -233,7 +233,7 @@ async fn list_room_contents<'l>(ctx: &'l VerbContext<'_>, item: &'l Item) -> URe
|
|||||||
LocationActionType::Sitting => buf.push_str("sitting "),
|
LocationActionType::Sitting => buf.push_str("sitting "),
|
||||||
LocationActionType::Reclining => buf.push_str("reclining "),
|
LocationActionType::Reclining => buf.push_str("reclining "),
|
||||||
LocationActionType::Normal | LocationActionType::Attacking(_) if is_creature => {
|
LocationActionType::Normal | LocationActionType::Attacking(_) if is_creature => {
|
||||||
if head.death_data.is_some() {
|
if head.is_dead {
|
||||||
buf.push_str("lying ");
|
buf.push_str("lying ");
|
||||||
} else {
|
} else {
|
||||||
buf.push_str("standing ");
|
buf.push_str("standing ");
|
||||||
@ -343,7 +343,7 @@ impl UserVerb for Verb {
|
|||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
|
|
||||||
let rem_trim = remaining.trim().to_lowercase();
|
let rem_trim = remaining.trim().to_lowercase();
|
||||||
let use_location = if player_item.death_data.is_some() { "room/repro_xv_respawn" } else {
|
let use_location = if player_item.is_dead { "room/repro_xv_respawn" } else {
|
||||||
&player_item.location
|
&player_item.location
|
||||||
};
|
};
|
||||||
let (heretype, herecode) = use_location.split_once("/").unwrap_or(("room", "repro_xv_chargen"));
|
let (heretype, herecode) = use_location.split_once("/").unwrap_or(("room", "repro_xv_chargen"));
|
||||||
|
@ -393,7 +393,7 @@ impl MapType for GmapType {
|
|||||||
room: &room::Room) -> UResult<()> {
|
room: &room::Room) -> UResult<()> {
|
||||||
ctx.trans.queue_for_session(
|
ctx.trans.queue_for_session(
|
||||||
ctx.session,
|
ctx.session,
|
||||||
Some(&render_map(room, 32, 18))
|
Some(&render_map(room, 16, 9))
|
||||||
).await?;
|
).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ pub async fn attempt_move_immediate(
|
|||||||
// for the orig_mover's queue, because might re-queue a move command.
|
// for the orig_mover's queue, because might re-queue a move command.
|
||||||
mut player_ctx: &mut Option<&mut VerbContext<'_>>
|
mut player_ctx: &mut Option<&mut VerbContext<'_>>
|
||||||
) -> UResult<()> {
|
) -> UResult<()> {
|
||||||
let use_location = if orig_mover.death_data.is_some() {
|
let use_location = if orig_mover.is_dead {
|
||||||
if orig_mover.item_type != "player" {
|
if orig_mover.item_type != "player" {
|
||||||
user_error("Dead players don't move".to_owned())?;
|
user_error("Dead players don't move".to_owned())?;
|
||||||
}
|
}
|
||||||
@ -268,7 +268,7 @@ pub async fn attempt_move_immediate(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if mover.death_data.is_some() {
|
if mover.is_dead {
|
||||||
if !handle_resurrect(trans, &mut mover).await? {
|
if !handle_resurrect(trans, &mut mover).await? {
|
||||||
user_error("You couldn't be resurrected.".to_string())?;
|
user_error("You couldn't be resurrected.".to_string())?;
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ impl TaskHandler for SwingShutHandler {
|
|||||||
|
|
||||||
pub async fn attempt_open_immediate(trans: &DBTrans, ctx_opt: &mut Option<&mut VerbContext<'_>>,
|
pub async fn attempt_open_immediate(trans: &DBTrans, ctx_opt: &mut Option<&mut VerbContext<'_>>,
|
||||||
who: &Item, direction: &Direction) -> UResult<()> {
|
who: &Item, direction: &Direction) -> UResult<()> {
|
||||||
if who.death_data.is_some() {
|
if who.is_dead {
|
||||||
user_error("Your ethereal hands don't seem to be able to move the door.".to_owned())?;
|
user_error("Your ethereal hands don't seem to be able to move the door.".to_owned())?;
|
||||||
}
|
}
|
||||||
let (room_1, dir_in_room, room_2) = match is_door_in_direction(trans, &direction, &who).await? {
|
let (room_1, dir_in_room, room_2) = match is_door_in_direction(trans, &direction, &who).await? {
|
||||||
|
@ -25,7 +25,7 @@ impl UserVerb for Verb {
|
|||||||
user_error("You need to provide a message to send.".to_owned())?;
|
user_error("You need to provide a message to send.".to_owned())?;
|
||||||
}
|
}
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("Shush, the dead can't talk!".to_string())?;
|
user_error("Shush, the dead can't talk!".to_string())?;
|
||||||
}
|
}
|
||||||
let to_whom = search_item_for_user(ctx, &ItemSearchParams {
|
let to_whom = search_item_for_user(ctx, &ItemSearchParams {
|
||||||
|
@ -55,7 +55,7 @@ impl UserVerb for Verb {
|
|||||||
user_error("You need to provide a message to send.".to_owned())?;
|
user_error("You need to provide a message to send.".to_owned())?;
|
||||||
}
|
}
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("Shush, the dead can't talk!".to_string())?;
|
user_error("Shush, the dead can't talk!".to_string())?;
|
||||||
}
|
}
|
||||||
say_to_room(ctx.trans, &player_item, &player_item.location,
|
say_to_room(ctx.trans, &player_item, &player_item.location,
|
||||||
|
@ -21,7 +21,7 @@ impl UserVerb for Verb {
|
|||||||
Some(v) => v
|
Some(v) => v
|
||||||
};
|
};
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("Apparently, you have to be alive to work as an uninstaller. \
|
user_error("Apparently, you have to be alive to work as an uninstaller. \
|
||||||
So discriminatory!".to_owned())?;
|
So discriminatory!".to_owned())?;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ impl QueueCommandHandler for QueueHandler {
|
|||||||
async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
||||||
-> UResult<time::Duration> {
|
-> UResult<time::Duration> {
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("You try to use it, but your ghostly hands slip through it uselessly".to_owned())?;
|
user_error("You try to use it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
}
|
}
|
||||||
let (item_id, target_type_code) = match command {
|
let (item_id, target_type_code) = match command {
|
||||||
@ -122,7 +122,7 @@ impl QueueCommandHandler for QueueHandler {
|
|||||||
async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
||||||
-> UResult<()> {
|
-> UResult<()> {
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("You try to use it, but your ghostly hands slip through it uselessly".to_owned())?;
|
user_error("You try to use it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +260,7 @@ pub struct Verb;
|
|||||||
impl UserVerb for Verb {
|
impl UserVerb for Verb {
|
||||||
async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, remaining: &str) -> UResult<()> {
|
async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, remaining: &str) -> UResult<()> {
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("You try to use it, but your ghostly hands slip through it uselessly".to_owned())?;
|
user_error("You try to use it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ impl UserVerb for Verb {
|
|||||||
user_error("You need to provide a message to send.".to_owned())?;
|
user_error("You need to provide a message to send.".to_owned())?;
|
||||||
}
|
}
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("Shush, the dead can't talk!".to_string())?;
|
user_error("Shush, the dead can't talk!".to_string())?;
|
||||||
}
|
}
|
||||||
let to_whom = search_item_for_user(ctx, &ItemSearchParams {
|
let to_whom = search_item_for_user(ctx, &ItemSearchParams {
|
||||||
|
@ -33,7 +33,7 @@ impl QueueCommandHandler for QueueHandler {
|
|||||||
async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
||||||
-> UResult<time::Duration> {
|
-> UResult<time::Duration> {
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("You try to wield it, but your ghostly hands slip through it uselessly".to_owned())?;
|
user_error("You try to wield it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
}
|
}
|
||||||
let item_id = match command {
|
let item_id = match command {
|
||||||
@ -80,7 +80,7 @@ impl QueueCommandHandler for QueueHandler {
|
|||||||
async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
||||||
-> UResult<()> {
|
-> UResult<()> {
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("You try to wield it, but your ghostly hands slip through it uselessly".to_owned())?;
|
user_error("You try to wield it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
}
|
}
|
||||||
let item_id = match command {
|
let item_id = match command {
|
||||||
@ -118,7 +118,7 @@ impl UserVerb for Verb {
|
|||||||
limit: 1,
|
limit: 1,
|
||||||
..ItemSearchParams::base(&player_item, &remaining)
|
..ItemSearchParams::base(&player_item, &remaining)
|
||||||
}).await?;
|
}).await?;
|
||||||
if player_item.death_data.is_some() {
|
if player_item.is_dead {
|
||||||
user_error("You try to wield it, but your ghostly hands slip through it uselessly".to_owned())?;
|
user_error("You try to wield it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
}
|
}
|
||||||
if weapon.action_type == LocationActionType::Wielded {
|
if weapon.action_type == LocationActionType::Wielded {
|
||||||
|
@ -342,20 +342,6 @@ impl Default for DoorState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct DeathData {
|
|
||||||
pub parts_remaining: Vec<PossessionType>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for DeathData {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
parts_remaining: vec!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
@ -371,7 +357,7 @@ pub struct Item {
|
|||||||
pub action_type: LocationActionType,
|
pub action_type: LocationActionType,
|
||||||
pub presence_target: Option<String>, // e.g. what are they sitting on.
|
pub presence_target: Option<String>, // e.g. what are they sitting on.
|
||||||
pub is_static: bool,
|
pub is_static: bool,
|
||||||
pub death_data: Option<DeathData>,
|
pub is_dead: bool,
|
||||||
pub species: SpeciesType,
|
pub species: SpeciesType,
|
||||||
pub health: u64,
|
pub health: u64,
|
||||||
pub total_xp: u64,
|
pub total_xp: u64,
|
||||||
@ -387,13 +373,13 @@ pub struct Item {
|
|||||||
pub special_data: Option<ItemSpecialData>,
|
pub special_data: Option<ItemSpecialData>,
|
||||||
pub dynamic_entrance: Option<DynamicEntrance>,
|
pub dynamic_entrance: Option<DynamicEntrance>,
|
||||||
pub owner: Option<String>,
|
pub owner: Option<String>,
|
||||||
pub door_states: Option<BTreeMap<Direction, DoorState>>,
|
pub door_states: Option<BTreeMap<Direction, DoorState>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item {
|
impl Item {
|
||||||
pub fn display_for_sentence(&self, explicit_ok: bool, pluralise: usize, caps: bool) -> String {
|
pub fn display_for_sentence(&self, explicit_ok: bool, pluralise: usize, caps: bool) -> String {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
if self.death_data.is_some() {
|
if self.is_dead {
|
||||||
if pluralise > 1 {
|
if pluralise > 1 {
|
||||||
buf.push_str("the bodies of ");
|
buf.push_str("the bodies of ");
|
||||||
} else {
|
} else {
|
||||||
@ -455,7 +441,7 @@ impl Default for Item {
|
|||||||
action_type: LocationActionType::Normal,
|
action_type: LocationActionType::Normal,
|
||||||
presence_target: None,
|
presence_target: None,
|
||||||
is_static: false,
|
is_static: false,
|
||||||
death_data: None,
|
is_dead: false,
|
||||||
species: SpeciesType::Human,
|
species: SpeciesType::Human,
|
||||||
health: 24,
|
health: 24,
|
||||||
total_xp: 0,
|
total_xp: 0,
|
||||||
|
@ -3,7 +3,6 @@ use crate::{
|
|||||||
models::item::Item,
|
models::item::Item,
|
||||||
models::consent::{Consent, ConsentType, ConsentStatus},
|
models::consent::{Consent, ConsentType, ConsentStatus},
|
||||||
static_content::npc::npc_by_code,
|
static_content::npc::npc_by_code,
|
||||||
message_handler::user_commands::drop::consider_expire_job_for_item,
|
|
||||||
};
|
};
|
||||||
use mockall_double::double;
|
use mockall_double::double;
|
||||||
#[double] use crate::db::DBTrans;
|
#[double] use crate::db::DBTrans;
|
||||||
@ -79,25 +78,3 @@ pub async fn check_consent(trans: &DBTrans, action: &str,
|
|||||||
|
|
||||||
Ok(false)
|
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,18 +3,16 @@ use crate::{
|
|||||||
comms::broadcast_to_room,
|
comms::broadcast_to_room,
|
||||||
skills::skill_check_and_grind,
|
skills::skill_check_and_grind,
|
||||||
skills::skill_check_only,
|
skills::skill_check_only,
|
||||||
destroy_container,
|
|
||||||
},
|
},
|
||||||
models::{
|
models::{
|
||||||
item::{Item, LocationActionType, Subattack, SkillType, DeathData},
|
item::{Item, LocationActionType, Subattack, SkillType},
|
||||||
task::{Task, TaskMeta, TaskDetails},
|
task::{Task, TaskMeta, TaskDetails}
|
||||||
},
|
},
|
||||||
static_content::{
|
static_content::{
|
||||||
possession_type::{WeaponData, possession_data, fist},
|
possession_type::{WeaponData, possession_data, fist},
|
||||||
npc::npc_by_code,
|
npc::npc_by_code,
|
||||||
species::species_info_map,
|
|
||||||
},
|
},
|
||||||
message_handler::user_commands::{user_error, UResult},
|
message_handler::user_commands::{user_error, UResult, drop::consider_expire_job_for_item},
|
||||||
regular_tasks::{TaskRunContext, TaskHandler},
|
regular_tasks::{TaskRunContext, TaskHandler},
|
||||||
DResult,
|
DResult,
|
||||||
};
|
};
|
||||||
@ -50,7 +48,7 @@ impl TaskHandler for AttackTaskHandler {
|
|||||||
Some(item) => (*item).clone()
|
Some(item) => (*item).clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
if attacker_item.death_data.is_some() || victim_item.death_data.is_some() {
|
if attacker_item.is_dead || victim_item.is_dead {
|
||||||
return Ok(None)
|
return Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,11 +210,7 @@ pub async fn handle_death(trans: &DBTrans, whom: &mut Item) -> DResult<()> {
|
|||||||
);
|
);
|
||||||
broadcast_to_room(trans, &whom.location, None, &msg_exp, Some(&msg_nonexp)).await?;
|
broadcast_to_room(trans, &whom.location, None, &msg_exp, Some(&msg_nonexp)).await?;
|
||||||
|
|
||||||
whom.death_data = Some(DeathData {
|
whom.is_dead = true;
|
||||||
parts_remaining: species_info_map().get(&whom.species)
|
|
||||||
.map(|sp| sp.corpse_butchers_into.clone()).unwrap_or_else(|| vec!()),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
if let Some(ac) = &whom.active_combat {
|
if let Some(ac) = &whom.active_combat {
|
||||||
let at_str = ac.attacking.clone();
|
let at_str = ac.attacking.clone();
|
||||||
for attacker in ac.attacked_by.clone().iter() {
|
for attacker in ac.attacked_by.clone().iter() {
|
||||||
@ -256,7 +250,7 @@ pub async fn handle_death(trans: &DBTrans, whom: &mut Item) -> DResult<()> {
|
|||||||
|
|
||||||
pub async fn handle_resurrect(trans: &DBTrans, player: &mut Item) -> DResult<bool> {
|
pub async fn handle_resurrect(trans: &DBTrans, player: &mut Item) -> DResult<bool> {
|
||||||
corpsify_item(trans, &player).await?;
|
corpsify_item(trans, &player).await?;
|
||||||
player.death_data = None;
|
player.is_dead = false;
|
||||||
let lost_xp = (player.total_xp / 200).max(10).min(player.total_xp);
|
let lost_xp = (player.total_xp / 200).max(10).min(player.total_xp);
|
||||||
let (session, _) = match trans.find_session_for_player(&player.item_code).await? {
|
let (session, _) = match trans.find_session_for_player(&player.item_code).await? {
|
||||||
None => return Ok(false),
|
None => return Ok(false),
|
||||||
@ -482,13 +476,13 @@ impl TaskHandler for NPCRecloneTaskHandler {
|
|||||||
Some(r) => r
|
Some(r) => r
|
||||||
};
|
};
|
||||||
|
|
||||||
if npc_item.death_data.is_none() {
|
if !npc_item.is_dead {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
corpsify_item(ctx.trans, &npc_item).await?;
|
corpsify_item(ctx.trans, &npc_item).await?;
|
||||||
|
|
||||||
npc_item.death_data = None;
|
npc_item.is_dead = false;
|
||||||
npc_item.health = max_health(&npc_item);
|
npc_item.health = max_health(&npc_item);
|
||||||
npc_item.location = npc.spawn_location.to_owned();
|
npc_item.location = npc.spawn_location.to_owned();
|
||||||
ctx.trans.save_item_model(&npc_item).await?;
|
ctx.trans.save_item_model(&npc_item).await?;
|
||||||
@ -507,12 +501,23 @@ impl TaskHandler for RotCorpseTaskHandler {
|
|||||||
None => { return Ok(None) }
|
None => { return Ok(None) }
|
||||||
Some(r) => r
|
Some(r) => r
|
||||||
};
|
};
|
||||||
destroy_container(ctx.trans, &corpse).await?;
|
ctx.trans.delete_item("corpse", &corpse_code).await?;
|
||||||
|
|
||||||
let msg_exp = format!("{} rots away to nothing.\n",
|
let msg_exp = format!("{} rots away to nothing.\n",
|
||||||
corpse.display_for_sentence(true, 1, true));
|
corpse.display_for_sentence(true, 1, true));
|
||||||
let msg_nonexp = format!("{} rots away to nothing.\n",
|
let msg_nonexp = format!("{} rots away to nothing.\n",
|
||||||
corpse.display_for_sentence(false, 1, true));
|
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?;
|
broadcast_to_room(ctx.trans, &corpse.location, None, &msg_exp, Some(&msg_nonexp)).await?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use mockall_double::double;
|
|||||||
pub async fn broadcast_to_room(trans: &DBTrans, location: &str, from_item: Option<&Item>,
|
pub async fn broadcast_to_room(trans: &DBTrans, location: &str, from_item: Option<&Item>,
|
||||||
message_explicit_ok: &str, message_nonexplicit: Option<&str>) -> DResult<()> {
|
message_explicit_ok: &str, message_nonexplicit: Option<&str>) -> DResult<()> {
|
||||||
for item in trans.find_items_by_location(location).await? {
|
for item in trans.find_items_by_location(location).await? {
|
||||||
if item.item_type != "player" || item.death_data.is_some() {
|
if item.item_type != "player" || item.is_dead {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some((session, session_dat)) = trans.find_session_for_player(&item.item_code).await? {
|
if let Some((session, session_dat)) = trans.find_session_for_player(&item.item_code).await? {
|
||||||
|
@ -59,7 +59,7 @@ impl TaskHandler for DelayedHealthTaskHandler {
|
|||||||
}
|
}
|
||||||
Some(it) => it
|
Some(it) => it
|
||||||
};
|
};
|
||||||
if item.death_data.is_some() {
|
if item.is_dead {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
match item_effect_series.1.pop_front() {
|
match item_effect_series.1.pop_front() {
|
||||||
|
@ -270,7 +270,7 @@ impl TaskHandler for NPCSayTaskHandler {
|
|||||||
Some(r) => r
|
Some(r) => r
|
||||||
};
|
};
|
||||||
|
|
||||||
if npc_item.death_data.is_none() {
|
if npc_item.is_dead {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,7 +323,7 @@ impl TaskHandler for NPCWanderTaskHandler {
|
|||||||
},
|
},
|
||||||
Some(r) => r
|
Some(r) => r
|
||||||
};
|
};
|
||||||
if item.death_data.is_some() {
|
if item.is_dead {
|
||||||
return Ok(None)
|
return Ok(None)
|
||||||
}
|
}
|
||||||
let (ltype, lcode) = match item.location.split_once("/") {
|
let (ltype, lcode) = match item.location.split_once("/") {
|
||||||
@ -379,14 +379,14 @@ impl TaskHandler for NPCAggroTaskHandler {
|
|||||||
},
|
},
|
||||||
Some(r) => r
|
Some(r) => r
|
||||||
};
|
};
|
||||||
if item.death_data.is_some() || item.active_combat.as_ref().map(|ac| ac.attacking.is_some()).unwrap_or(false) {
|
if item.is_dead || item.active_combat.as_ref().map(|ac| ac.attacking.is_some()).unwrap_or(false) {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let items_loc = ctx.trans.find_items_by_location(&item.location).await?;
|
let items_loc = ctx.trans.find_items_by_location(&item.location).await?;
|
||||||
let vic_opt = items_loc
|
let vic_opt = items_loc
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|it| (it.item_type == "player" || it.item_type == "npc") &&
|
.filter(|it| (it.item_type == "player" || it.item_type == "npc") &&
|
||||||
it.death_data.is_none() && (it.item_type != item.item_type || it.item_code != item.item_code))
|
!it.is_dead && (it.item_type != item.item_type || it.item_code != item.item_code))
|
||||||
.choose(&mut thread_rng());
|
.choose(&mut thread_rng());
|
||||||
if let Some(victim) = vic_opt {
|
if let Some(victim) = vic_opt {
|
||||||
match start_attack(ctx.trans, &item, victim).await {
|
match start_attack(ctx.trans, &item, victim).await {
|
||||||
@ -418,13 +418,13 @@ impl TaskHandler for NPCRecloneTaskHandler {
|
|||||||
Some(r) => r
|
Some(r) => r
|
||||||
};
|
};
|
||||||
|
|
||||||
if npc_item.death_data.is_none() {
|
if !npc_item.is_dead {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
corpsify_item(ctx.trans, &npc_item).await?;
|
corpsify_item(ctx.trans, &npc_item).await?;
|
||||||
|
|
||||||
npc_item.death_data = None;
|
npc_item.is_dead = false;
|
||||||
npc_item.health = npc.max_health;
|
npc_item.health = npc.max_health;
|
||||||
npc_item.location = npc.spawn_location.to_owned();
|
npc_item.location = npc.spawn_location.to_owned();
|
||||||
ctx.trans.save_item_model(&npc_item).await?;
|
ctx.trans.save_item_model(&npc_item).await?;
|
||||||
|
@ -13,11 +13,9 @@ use async_trait::async_trait;
|
|||||||
|
|
||||||
mod fangs;
|
mod fangs;
|
||||||
mod antenna_whip;
|
mod antenna_whip;
|
||||||
mod blade;
|
|
||||||
mod trauma_kit;
|
mod trauma_kit;
|
||||||
mod corp_licence;
|
mod corp_licence;
|
||||||
mod lock;
|
mod lock;
|
||||||
mod meat;
|
|
||||||
|
|
||||||
pub type AttackMessageChoice = Vec<Box<dyn Fn(&Item, &Item, bool) -> String + 'static + Sync + Send>>;
|
pub type AttackMessageChoice = Vec<Box<dyn Fn(&Item, &Item, bool) -> String + 'static + Sync + Send>>;
|
||||||
pub type AttackMessageChoicePart = Vec<Box<dyn Fn(&Item, &Item, &BodyPart, bool) -> String + 'static + Sync + Send>>;
|
pub type AttackMessageChoicePart = Vec<Box<dyn Fn(&Item, &Item, &BodyPart, bool) -> String + 'static + Sync + Send>>;
|
||||||
@ -147,7 +145,6 @@ pub struct PossessionData {
|
|||||||
pub lockcheck_handler: Option<&'static (dyn ArglessHandler + Sync + Send)>,
|
pub lockcheck_handler: Option<&'static (dyn ArglessHandler + Sync + Send)>,
|
||||||
pub sign_handler: Option<&'static (dyn ArglessHandler + Sync + Send)>,
|
pub sign_handler: Option<&'static (dyn ArglessHandler + Sync + Send)>,
|
||||||
pub write_handler: Option<&'static (dyn WriteHandler + Sync + Send)>,
|
pub write_handler: Option<&'static (dyn WriteHandler + Sync + Send)>,
|
||||||
pub can_butcher: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PossessionData {
|
impl Default for PossessionData {
|
||||||
@ -168,7 +165,6 @@ impl Default for PossessionData {
|
|||||||
lockcheck_handler: None,
|
lockcheck_handler: None,
|
||||||
sign_handler: None,
|
sign_handler: None,
|
||||||
write_handler: None,
|
write_handler: None,
|
||||||
can_butcher: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,10 +203,6 @@ pub enum PossessionType {
|
|||||||
NewCorpLicence,
|
NewCorpLicence,
|
||||||
CertificateOfIncorporation,
|
CertificateOfIncorporation,
|
||||||
Scanlock,
|
Scanlock,
|
||||||
ButcherKnife,
|
|
||||||
Steak,
|
|
||||||
AnimalSkin,
|
|
||||||
SeveredHead,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Item> for PossessionType {
|
impl Into<Item> for PossessionType {
|
||||||
@ -274,15 +266,11 @@ pub fn possession_data() -> &'static BTreeMap<PossessionType, PossessionData> {
|
|||||||
vec!(
|
vec!(
|
||||||
(Fangs, fangs::data()),
|
(Fangs, fangs::data()),
|
||||||
(AntennaWhip, antenna_whip::data()),
|
(AntennaWhip, antenna_whip::data()),
|
||||||
(ButcherKnife, blade::butcher_data()),
|
|
||||||
(MediumTraumaKit, trauma_kit::medium_data()),
|
(MediumTraumaKit, trauma_kit::medium_data()),
|
||||||
(EmptyMedicalBox, trauma_kit::empty_data()),
|
(EmptyMedicalBox, trauma_kit::empty_data()),
|
||||||
(NewCorpLicence, corp_licence::data()),
|
(NewCorpLicence, corp_licence::data()),
|
||||||
(CertificateOfIncorporation, corp_licence::cert_data()),
|
(CertificateOfIncorporation, corp_licence::cert_data()),
|
||||||
(Scanlock, lock::scan()),
|
(Scanlock, lock::scan()),
|
||||||
(Steak, meat::steak_data()),
|
|
||||||
(AnimalSkin, meat::skin_data()),
|
|
||||||
(SeveredHead, meat::severed_head_data()),
|
|
||||||
).into_iter().collect()
|
).into_iter().collect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
use super::{PossessionData, WeaponData};
|
|
||||||
use crate::models::item::SkillType;
|
|
||||||
|
|
||||||
pub fn butcher_data() -> PossessionData {
|
|
||||||
PossessionData {
|
|
||||||
display: "butcher knife",
|
|
||||||
details: "A 30 cm long stainless steel blade, sharp on one edge with a pointy tip. It looks perfect for butchering things, and in a pinch you could probably fight with it too.",
|
|
||||||
aliases: vec!("butcher", "knife"),
|
|
||||||
weight: 250,
|
|
||||||
weapon_data: Some(WeaponData {
|
|
||||||
uses_skill: SkillType::Blades,
|
|
||||||
raw_min_to_learn: 0.0,
|
|
||||||
raw_max_to_learn: 2.0,
|
|
||||||
normal_attack_start_messages: vec!(
|
|
||||||
Box::new(|attacker, victim, exp|
|
|
||||||
format!("{} raises {} butcher knife menancingly, preparing to attack {}",
|
|
||||||
&attacker.display_for_sentence(exp, 1, true),
|
|
||||||
&attacker.pronouns.possessive,
|
|
||||||
&victim.display_for_sentence(exp, 1, false),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
normal_attack_success_messages: vec!(
|
|
||||||
Box::new(|attacker, victim, part, exp|
|
|
||||||
format!("{}'s butcher knife cuts into {}'s {}",
|
|
||||||
&attacker.display_for_sentence(exp, 1, true),
|
|
||||||
&victim.display_for_sentence(exp, 1, false),
|
|
||||||
&part.display(victim.sex.clone())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
normal_attack_mean_damage: 2.0,
|
|
||||||
normal_attack_stdev_damage: 2.0,
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn steak_data() -> PossessionData {
|
|
||||||
PossessionData {
|
|
||||||
display: "steak",
|
|
||||||
details: "A hunk of raw red meat, dripping with blood",
|
|
||||||
weight: 100,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn severed_head_data() -> PossessionData {
|
|
||||||
PossessionData {
|
|
||||||
display: "severed head",
|
|
||||||
details: "A head that has been chopped clean from the body",
|
|
||||||
weight: 250,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
@ -212,7 +212,7 @@ pub fn medium_data() -> PossessionData {
|
|||||||
task_ref: "bandage",
|
task_ref: "bandage",
|
||||||
errorf: Box::new(
|
errorf: Box::new(
|
||||||
|_item, target|
|
|_item, target|
|
||||||
if target.death_data.is_some() {
|
if target.is_dead {
|
||||||
Some(format!("It is too late, {}'s dead", target.pronouns.subject))
|
Some(format!("It is too late, {}'s dead", target.pronouns.subject))
|
||||||
} else if target.item_type != "player" && target.item_type != "npc" {
|
} else if target.item_type != "player" && target.item_type != "npc" {
|
||||||
Some("It only works on animals.".to_owned())
|
Some("It only works on animals.".to_owned())
|
||||||
|
@ -2527,11 +2527,6 @@ pub fn room_list() -> Vec<Room> {
|
|||||||
target: ExitTarget::UseGPS,
|
target: ExitTarget::UseGPS,
|
||||||
exit_type: ExitType::Free
|
exit_type: ExitType::Free
|
||||||
},
|
},
|
||||||
Exit {
|
|
||||||
direction: Direction::SOUTH,
|
|
||||||
target: ExitTarget::UseGPS,
|
|
||||||
exit_type: ExitType::Free
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
should_caption: false,
|
should_caption: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -2562,32 +2557,6 @@ pub fn room_list() -> Vec<Room> {
|
|||||||
should_caption: true,
|
should_caption: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Room {
|
|
||||||
zone: "melbs",
|
|
||||||
secondary_zones: vec!(),
|
|
||||||
code: "melbs_grande_outdoors",
|
|
||||||
name: "Grande Outdoors",
|
|
||||||
short: ansi!("<yellow>GO<reset>"),
|
|
||||||
description: "A shop that looks like it once helped people camp for fun, its clientele now days are probably more focused on just surviving! A weary looking woman with calloused, grease covered hands paces the shop floor, prepared to spring on you and hype up whatever merchandise you look at as the best thing ever",
|
|
||||||
description_less_explicit: None,
|
|
||||||
grid_coords: GridCoords { x: 3, y: 4, z: 0 },
|
|
||||||
exits: vec!(
|
|
||||||
Exit {
|
|
||||||
direction: Direction::NORTH,
|
|
||||||
target: ExitTarget::UseGPS,
|
|
||||||
exit_type: ExitType::Free
|
|
||||||
},
|
|
||||||
),
|
|
||||||
stock_list: vec!(
|
|
||||||
RoomStock {
|
|
||||||
possession_type: PossessionType::ButcherKnife,
|
|
||||||
list_price: 120,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
),
|
|
||||||
should_caption: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
Room {
|
Room {
|
||||||
zone: "melbs",
|
zone: "melbs",
|
||||||
secondary_zones: vec!(),
|
secondary_zones: vec!(),
|
||||||
|
@ -2,8 +2,7 @@ use once_cell::sync::OnceCell;
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use crate::{
|
use crate::{
|
||||||
models::item::Sex,
|
models::item::Sex
|
||||||
static_content::possession_type::PossessionType,
|
|
||||||
};
|
};
|
||||||
use rand::seq::IteratorRandom;
|
use rand::seq::IteratorRandom;
|
||||||
|
|
||||||
@ -58,8 +57,7 @@ impl BodyPart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct SpeciesInfo {
|
pub struct SpeciesInfo {
|
||||||
pub body_parts: Vec<BodyPart>,
|
body_parts: Vec<BodyPart>,
|
||||||
pub corpse_butchers_into: Vec<PossessionType>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -78,13 +76,7 @@ pub fn species_info_map() -> &'static BTreeMap<SpeciesType, SpeciesInfo> {
|
|||||||
BodyPart::Arms,
|
BodyPart::Arms,
|
||||||
BodyPart::Legs,
|
BodyPart::Legs,
|
||||||
BodyPart::Feet
|
BodyPart::Feet
|
||||||
),
|
)
|
||||||
corpse_butchers_into: vec!(
|
|
||||||
PossessionType::Steak,
|
|
||||||
PossessionType::Steak,
|
|
||||||
PossessionType::AnimalSkin,
|
|
||||||
PossessionType::SeveredHead,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
(SpeciesType::Dog,
|
(SpeciesType::Dog,
|
||||||
@ -97,12 +89,7 @@ pub fn species_info_map() -> &'static BTreeMap<SpeciesType, SpeciesInfo> {
|
|||||||
BodyPart::Groin,
|
BodyPart::Groin,
|
||||||
BodyPart::Legs,
|
BodyPart::Legs,
|
||||||
BodyPart::Feet
|
BodyPart::Feet
|
||||||
),
|
)
|
||||||
corpse_butchers_into: vec!(
|
|
||||||
PossessionType::Steak,
|
|
||||||
PossessionType::AnimalSkin,
|
|
||||||
PossessionType::SeveredHead,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
).into_iter().collect()
|
).into_iter().collect()
|
||||||
|
Loading…
Reference in New Issue
Block a user