forked from blasthavers/blastmud
Add drop command, and show inventory on look.
This commit is contained in:
parent
25cfda033b
commit
d5314c981e
@ -14,6 +14,7 @@ use std::sync::Arc;
|
|||||||
mod agree;
|
mod agree;
|
||||||
pub mod attack;
|
pub mod attack;
|
||||||
mod buy;
|
mod buy;
|
||||||
|
pub mod drop;
|
||||||
pub mod get;
|
pub mod get;
|
||||||
mod describe;
|
mod describe;
|
||||||
mod help;
|
mod help;
|
||||||
@ -107,6 +108,7 @@ static REGISTERED_COMMANDS: UserVerbRegistry = phf_map! {
|
|||||||
// Other commands (alphabetical except aliases grouped):
|
// Other commands (alphabetical except aliases grouped):
|
||||||
"attack" => attack::VERB,
|
"attack" => attack::VERB,
|
||||||
"buy" => buy::VERB,
|
"buy" => buy::VERB,
|
||||||
|
"drop" => drop::VERB,
|
||||||
"get" => get::VERB,
|
"get" => get::VERB,
|
||||||
"inventory" => inventory::VERB,
|
"inventory" => inventory::VERB,
|
||||||
"inv" => inventory::VERB,
|
"inv" => inventory::VERB,
|
||||||
|
133
blastmud_game/src/message_handler/user_commands/drop.rs
Normal file
133
blastmud_game/src/message_handler/user_commands/drop.rs
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
use super::{
|
||||||
|
VerbContext,
|
||||||
|
UserVerb,
|
||||||
|
UserVerbRef,
|
||||||
|
UResult,
|
||||||
|
ItemSearchParams,
|
||||||
|
user_error,
|
||||||
|
get_player_item_or_fail,
|
||||||
|
search_item_for_user,
|
||||||
|
};
|
||||||
|
use crate::{
|
||||||
|
static_content::possession_type::possession_data,
|
||||||
|
regular_tasks::queued_command::{
|
||||||
|
QueueCommandHandler,
|
||||||
|
QueueCommand,
|
||||||
|
queue_command
|
||||||
|
},
|
||||||
|
services::{
|
||||||
|
broadcast_to_room,
|
||||||
|
capacity::{
|
||||||
|
check_item_capacity,
|
||||||
|
CapacityLevel,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
models::item::LocationActionType,
|
||||||
|
};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use std::time;
|
||||||
|
|
||||||
|
pub struct QueueHandler;
|
||||||
|
#[async_trait]
|
||||||
|
impl QueueCommandHandler for QueueHandler {
|
||||||
|
async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
||||||
|
-> UResult<time::Duration> {
|
||||||
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
|
if player_item.is_dead {
|
||||||
|
user_error("You try to drop it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
|
}
|
||||||
|
let item_id = match command {
|
||||||
|
QueueCommand::Drop { possession_id } => possession_id,
|
||||||
|
_ => user_error("Unexpected command".to_owned())?
|
||||||
|
};
|
||||||
|
let item = match ctx.trans.find_item_by_type_code("possession", &item_id).await? {
|
||||||
|
None => user_error("Item not found".to_owned())?,
|
||||||
|
Some(it) => it
|
||||||
|
};
|
||||||
|
if item.location != format!("{}/{}", &player_item.item_type, &player_item.item_code) {
|
||||||
|
user_error(
|
||||||
|
format!("You try to drop {} but realise you no longer have it",
|
||||||
|
item.display_for_sentence(!ctx.session_dat.less_explicit_mode, 1, false)
|
||||||
|
)
|
||||||
|
)?
|
||||||
|
}
|
||||||
|
let msg_exp = format!("{} prepares to drop {}\n",
|
||||||
|
&player_item.display_for_sentence(true, 1, true),
|
||||||
|
&item.display_for_sentence(true, 1, false));
|
||||||
|
let msg_nonexp = format!("{} prepares to drop {}\n",
|
||||||
|
&player_item.display_for_sentence(false, 1, true),
|
||||||
|
&item.display_for_sentence(false, 1, false));
|
||||||
|
broadcast_to_room(ctx.trans, &player_item.location, None, &msg_exp, Some(&msg_nonexp)).await?;
|
||||||
|
Ok(time::Duration::from_secs(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
||||||
|
-> UResult<()> {
|
||||||
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
|
if player_item.is_dead {
|
||||||
|
user_error("You try to get it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
|
}
|
||||||
|
let item_id = match command {
|
||||||
|
QueueCommand::Drop { possession_id } => possession_id,
|
||||||
|
_ => user_error("Unexpected command".to_owned())?
|
||||||
|
};
|
||||||
|
let item = match ctx.trans.find_item_by_type_code("possession", &item_id).await? {
|
||||||
|
None => user_error("Item not found".to_owned())?,
|
||||||
|
Some(it) => it
|
||||||
|
};
|
||||||
|
if item.location != format!("{}/{}", &player_item.item_type, &player_item.item_code) {
|
||||||
|
user_error(format!("You try to drop {} but realise you no longer have it!",
|
||||||
|
&item.display_for_sentence(!ctx.session_dat.less_explicit_mode, 1, false)))?
|
||||||
|
}
|
||||||
|
|
||||||
|
let possession_data = match item.possession_type.as_ref().and_then(|pt| possession_data().get(&pt)) {
|
||||||
|
None => user_error("That item no longer exists in the game so can't be handled".to_owned())?,
|
||||||
|
Some(pd) => pd
|
||||||
|
};
|
||||||
|
|
||||||
|
match check_item_capacity(ctx.trans, &player_item.location, possession_data.weight).await? {
|
||||||
|
CapacityLevel::AboveItemLimit => user_error(
|
||||||
|
format!("You can't drop {}, because it is so cluttered here there is no where to put it!",
|
||||||
|
&item.display_for_sentence(!ctx.session_dat.less_explicit_mode, 1, false)
|
||||||
|
),
|
||||||
|
)?,
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
let msg_exp = format!("{} drops {}\n",
|
||||||
|
&player_item.display_for_sentence(true, 1, true),
|
||||||
|
&item.display_for_sentence(true, 1, false));
|
||||||
|
let msg_nonexp = format!("{} drops {}\n",
|
||||||
|
&player_item.display_for_sentence(false, 1, true),
|
||||||
|
&item.display_for_sentence(false, 1, false));
|
||||||
|
broadcast_to_room(ctx.trans, &player_item.location, None, &msg_exp, Some(&msg_nonexp)).await?;
|
||||||
|
let mut item_mut = (*item).clone();
|
||||||
|
item_mut.location = player_item.location.clone();
|
||||||
|
item_mut.action_type = LocationActionType::Normal;
|
||||||
|
ctx.trans.save_item_model(&item_mut).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Verb;
|
||||||
|
#[async_trait]
|
||||||
|
impl UserVerb for Verb {
|
||||||
|
async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, remaining: &str) -> UResult<()> {
|
||||||
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
|
let target = search_item_for_user(ctx, &ItemSearchParams {
|
||||||
|
include_contents: true,
|
||||||
|
..ItemSearchParams::base(&player_item, &remaining)
|
||||||
|
}).await?;
|
||||||
|
if player_item.is_dead {
|
||||||
|
user_error("You try to drop it, but your ghostly hands slip through it uselessly".to_owned())?;
|
||||||
|
}
|
||||||
|
if target.item_type != "possession" {
|
||||||
|
user_error("You can't drop that!".to_owned())?;
|
||||||
|
}
|
||||||
|
queue_command(ctx, &QueueCommand::Drop { possession_id: target.item_code.clone() }).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static VERB_INT: Verb = Verb;
|
||||||
|
pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef;
|
@ -2,9 +2,12 @@ use super::{VerbContext, UserVerb, UserVerbRef, UResult, UserError, user_error,
|
|||||||
get_player_item_or_fail, search_item_for_user};
|
get_player_item_or_fail, search_item_for_user};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use ansi::{ansi, flow_around, word_wrap};
|
use ansi::{ansi, flow_around, word_wrap};
|
||||||
use crate::db::ItemSearchParams;
|
use crate::{
|
||||||
use crate::models::{item::{Item, LocationActionType, Subattack, ItemFlag}};
|
db::ItemSearchParams,
|
||||||
use crate::static_content::room::{self, Direction};
|
models::{item::{Item, LocationActionType, Subattack, ItemFlag}},
|
||||||
|
static_content::room::{self, Direction},
|
||||||
|
language,
|
||||||
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -39,11 +42,45 @@ pub fn render_map(room: &room::Room, width: usize, height: usize) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn describe_normal_item(ctx: &VerbContext<'_>, item: &Item) -> UResult<()> {
|
pub async fn describe_normal_item(ctx: &VerbContext<'_>, item: &Item) -> UResult<()> {
|
||||||
|
let mut contents_desc = String::new();
|
||||||
|
|
||||||
|
let mut items = ctx.trans.find_items_by_location(&format!("{}/{}",
|
||||||
|
item.item_type, item.item_code)).await?;
|
||||||
|
items.sort_unstable_by(|it1, it2| (&it1.display).cmp(&it2.display));
|
||||||
|
|
||||||
|
let all_groups: Vec<Vec<&Arc<Item>>> = items
|
||||||
|
.iter()
|
||||||
|
.group_by(|i| i.display_for_sentence(true, 1, false))
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, g)|g.collect::<Vec<&Arc<Item>>>())
|
||||||
|
.collect::<Vec<Vec<&Arc<Item>>>>();
|
||||||
|
|
||||||
|
if all_groups.len() > 0 {
|
||||||
|
contents_desc.push_str(&(language::caps_first(&item.pronouns.subject)));
|
||||||
|
if item.item_type == "player" || item.item_type == "npc" {
|
||||||
|
contents_desc.push_str("'s carrying ");
|
||||||
|
} else {
|
||||||
|
contents_desc.push_str(" contains ");
|
||||||
|
}
|
||||||
|
let mut phrases = Vec::<String>::new();
|
||||||
|
for group_items in all_groups {
|
||||||
|
let head = &group_items[0];
|
||||||
|
let mut details = head.display_for_sentence(!ctx.session_dat.less_explicit_mode,
|
||||||
|
group_items.len(), false);
|
||||||
|
if head.action_type == LocationActionType::Wielded {
|
||||||
|
details.push_str(" (wielded)");
|
||||||
|
}
|
||||||
|
phrases.push(details);
|
||||||
|
}
|
||||||
|
let phrases_str: Vec<&str> = phrases.iter().map(|p| p.as_str()).collect();
|
||||||
|
contents_desc.push_str(&(language::join_words(&phrases_str) + ".\n"));
|
||||||
|
}
|
||||||
ctx.trans.queue_for_session(
|
ctx.trans.queue_for_session(
|
||||||
ctx.session,
|
ctx.session,
|
||||||
Some(&format!("{}\n{}\n",
|
Some(&format!("{}\n{}\n{}",
|
||||||
&item.display_for_session(&ctx.session_dat),
|
&item.display_for_session(&ctx.session_dat),
|
||||||
item.details_for_session(&ctx.session_dat).unwrap_or("")
|
item.details_for_session(&ctx.session_dat).unwrap_or(""),
|
||||||
|
contents_desc,
|
||||||
))
|
))
|
||||||
).await?;
|
).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -73,7 +110,7 @@ pub async fn describe_room(ctx: &VerbContext<'_>, item: &Item,
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn list_item_contents<'l>(ctx: &'l VerbContext<'_>, item: &'l Item) -> UResult<String> {
|
async fn list_room_contents<'l>(ctx: &'l VerbContext<'_>, item: &'l Item) -> UResult<String> {
|
||||||
if item.flags.contains(&ItemFlag::NoSeeContents) {
|
if item.flags.contains(&ItemFlag::NoSeeContents) {
|
||||||
return Ok(" It is too foggy to see who or what else is here.".to_owned());
|
return Ok(" It is too foggy to see who or what else is here.".to_owned());
|
||||||
}
|
}
|
||||||
@ -192,7 +229,7 @@ impl UserVerb for Verb {
|
|||||||
let room =
|
let room =
|
||||||
room::room_map_by_code().get(item.item_code.as_str())
|
room::room_map_by_code().get(item.item_code.as_str())
|
||||||
.ok_or_else(|| UserError("Sorry, that room no longer exists".to_owned()))?;
|
.ok_or_else(|| UserError("Sorry, that room no longer exists".to_owned()))?;
|
||||||
describe_room(ctx, &item, &room, &list_item_contents(ctx, &item).await?).await?;
|
describe_room(ctx, &item, &room, &list_room_contents(ctx, &item).await?).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,10 @@ use crate::message_handler::user_commands::{
|
|||||||
VerbContext,
|
VerbContext,
|
||||||
CommandHandlingError,
|
CommandHandlingError,
|
||||||
UResult,
|
UResult,
|
||||||
|
get,
|
||||||
|
drop,
|
||||||
movement,
|
movement,
|
||||||
wield,
|
wield,
|
||||||
get,
|
|
||||||
user_error,
|
user_error,
|
||||||
get_user_or_fail
|
get_user_or_fail
|
||||||
};
|
};
|
||||||
@ -28,6 +29,7 @@ pub enum QueueCommand {
|
|||||||
Movement { direction: Direction },
|
Movement { direction: Direction },
|
||||||
Wield { possession_id: String },
|
Wield { possession_id: String },
|
||||||
Get { possession_id: String },
|
Get { possession_id: String },
|
||||||
|
Drop { possession_id: String },
|
||||||
}
|
}
|
||||||
impl QueueCommand {
|
impl QueueCommand {
|
||||||
pub fn name(&self) -> &'static str {
|
pub fn name(&self) -> &'static str {
|
||||||
@ -36,6 +38,7 @@ impl QueueCommand {
|
|||||||
Movement {..} => "Movement",
|
Movement {..} => "Movement",
|
||||||
Wield {..} => "Wield",
|
Wield {..} => "Wield",
|
||||||
Get {..} => "Get",
|
Get {..} => "Get",
|
||||||
|
Drop {..} => "Drop",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,9 +53,10 @@ fn queue_command_registry() -> &'static BTreeMap<&'static str, &'static (dyn Que
|
|||||||
static REGISTRY: OnceCell<BTreeMap<&'static str, &'static (dyn QueueCommandHandler + Sync + Send)>> =
|
static REGISTRY: OnceCell<BTreeMap<&'static str, &'static (dyn QueueCommandHandler + Sync + Send)>> =
|
||||||
OnceCell::new();
|
OnceCell::new();
|
||||||
REGISTRY.get_or_init(|| vec!(
|
REGISTRY.get_or_init(|| vec!(
|
||||||
|
("Drop", &drop::QueueHandler as &(dyn QueueCommandHandler + Sync + Send)),
|
||||||
|
("Get", &get::QueueHandler as &(dyn QueueCommandHandler + Sync + Send)),
|
||||||
("Movement", &movement::QueueHandler as &(dyn QueueCommandHandler + Sync + Send)),
|
("Movement", &movement::QueueHandler as &(dyn QueueCommandHandler + Sync + Send)),
|
||||||
("Wield", &wield::QueueHandler as &(dyn QueueCommandHandler + Sync + Send)),
|
("Wield", &wield::QueueHandler as &(dyn QueueCommandHandler + Sync + Send)),
|
||||||
("Get", &get::QueueHandler as &(dyn QueueCommandHandler + Sync + Send)),
|
|
||||||
).into_iter().collect())
|
).into_iter().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user