forked from blasthavers/blastmud
Improve get targeting with 'all' option.
This commit is contained in:
parent
ddd0f33cb5
commit
d4fd71d839
@ -235,6 +235,8 @@ pub struct ItemSearchParams<'l> {
|
|||||||
pub include_loc_contents: bool,
|
pub include_loc_contents: bool,
|
||||||
pub include_active_players: bool,
|
pub include_active_players: bool,
|
||||||
pub include_all_players: bool,
|
pub include_all_players: bool,
|
||||||
|
pub item_type_only: Option<&'l str>,
|
||||||
|
pub limit: u8,
|
||||||
pub dead_first: bool,
|
pub dead_first: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,6 +249,8 @@ impl ItemSearchParams<'_> {
|
|||||||
include_active_players: false,
|
include_active_players: false,
|
||||||
include_all_players: false,
|
include_all_players: false,
|
||||||
dead_first: false,
|
dead_first: false,
|
||||||
|
limit: 100,
|
||||||
|
item_type_only: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -521,8 +525,30 @@ impl DBTrans {
|
|||||||
let player_desig = format!("{}/{}", search.from_item.item_type,
|
let player_desig = format!("{}/{}", search.from_item.item_type,
|
||||||
search.from_item.item_code);
|
search.from_item.item_code);
|
||||||
|
|
||||||
let (offset, query) = parse_offset(search.query);
|
let (offset, mut query) = parse_offset(search.query);
|
||||||
let mut param_no: usize = 5;
|
let mut param_no: usize = 6;
|
||||||
|
let mut extra_order: String = String::new();
|
||||||
|
let mut extra_where: String = String::new();
|
||||||
|
|
||||||
|
let mut dead_only = false;
|
||||||
|
if query.starts_with("dead") {
|
||||||
|
query = query[4..].trim();
|
||||||
|
dead_only = true;
|
||||||
|
} else if query.starts_with("corpse of") {
|
||||||
|
query = query[9..].trim();
|
||||||
|
dead_only = true;
|
||||||
|
} else if query.starts_with("corpse") {
|
||||||
|
query = query[6..].trim();
|
||||||
|
dead_only = true;
|
||||||
|
}
|
||||||
|
if dead_only {
|
||||||
|
extra_where.push_str(" AND COALESCE(CAST(details->>'is_dead' AS boolean), false) = true");
|
||||||
|
} else if search.dead_first {
|
||||||
|
extra_order.push_str(" COALESCE(CAST(details->>'is_dead' AS boolean), false) DESC,");
|
||||||
|
} else {
|
||||||
|
extra_order.push_str(" COALESCE(CAST(details->>'is_dead' AS boolean), false) ASC,");
|
||||||
|
}
|
||||||
|
|
||||||
let query_wildcard = query.replace("\\", "\\\\")
|
let query_wildcard = query.replace("\\", "\\\\")
|
||||||
.replace("_", "\\_")
|
.replace("_", "\\_")
|
||||||
.replace("%", "")
|
.replace("%", "")
|
||||||
@ -530,11 +556,24 @@ impl DBTrans {
|
|||||||
let offset_sql = offset.map(|x| (if x >= 1 { x - 1 } else { x}) as i64).unwrap_or(0);
|
let offset_sql = offset.map(|x| (if x >= 1 { x - 1 } else { x}) as i64).unwrap_or(0);
|
||||||
let query_json = serde_json::to_value(query.to_lowercase())?;
|
let query_json = serde_json::to_value(query.to_lowercase())?;
|
||||||
let query_len = query.len() as i32;
|
let query_len = query.len() as i32;
|
||||||
|
let limit = search.limit as i64;
|
||||||
let mut params: Vec<&(dyn ToSql + Sync)> = vec!(
|
let mut params: Vec<&(dyn ToSql + Sync)> = vec!(
|
||||||
&query_wildcard,
|
&query_wildcard,
|
||||||
&offset_sql, &query_len, &query_json);
|
&offset_sql,
|
||||||
|
&query_len,
|
||||||
|
&query_json,
|
||||||
|
&limit
|
||||||
|
);
|
||||||
|
|
||||||
|
match search.item_type_only {
|
||||||
|
None => {}
|
||||||
|
Some(ref item_type) => {
|
||||||
|
extra_where.push_str(&format!(" AND details->>'item_type' = ${}", param_no));
|
||||||
|
param_no += 1;
|
||||||
|
params.push(item_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if search.include_contents {
|
if search.include_contents {
|
||||||
ctes.push(format!("contents AS (\
|
ctes.push(format!("contents AS (\
|
||||||
SELECT details, details->'aliases' AS aliases FROM items WHERE details->>'location' = ${}\
|
SELECT details, details->'aliases' AS aliases FROM items WHERE details->>'location' = ${}\
|
||||||
@ -567,14 +606,15 @@ impl DBTrans {
|
|||||||
ctes.push(format!("relevant_items AS ({})", include_tables.join(" UNION ")));
|
ctes.push(format!("relevant_items AS ({})", include_tables.join(" UNION ")));
|
||||||
|
|
||||||
let cte_str: String = ctes.join(", ");
|
let cte_str: String = ctes.join(", ");
|
||||||
|
|
||||||
Ok(Arc::new(self.pg_trans()?.query(
|
Ok(Arc::new(self.pg_trans()?.query(
|
||||||
&format!(
|
&format!(
|
||||||
"WITH {} SELECT details, aliases FROM relevant_items WHERE (lower(details->>'display') LIKE $1) \
|
"WITH {} SELECT details, aliases FROM relevant_items WHERE \
|
||||||
OR (lower(details ->>'display_less_explicit') LIKE $1) \
|
((lower(details->>'display') LIKE $1) \
|
||||||
OR aliases @> $4 \
|
OR (lower(details ->>'display_less_explicit') LIKE $1) \
|
||||||
ORDER BY ABS(length(details->>'display')-$3) ASC \
|
OR aliases @> $4) {} \
|
||||||
LIMIT 1 OFFSET $2", &cte_str),
|
ORDER BY {} ABS(length(details->>'display')-$3) ASC \
|
||||||
|
LIMIT $5 OFFSET $2", &cte_str, &extra_where, &extra_order),
|
||||||
¶ms
|
¶ms
|
||||||
).await?.into_iter()
|
).await?.into_iter()
|
||||||
.filter_map(|i| serde_json::from_value(i.get("details")).ok())
|
.filter_map(|i| serde_json::from_value(i.get("details")).ok())
|
||||||
|
@ -242,6 +242,14 @@ pub async fn search_item_for_user<'l>(ctx: &'l VerbContext<'l>, search: &'l Item
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn search_items_for_user<'l>(ctx: &'l VerbContext<'l>, search: &'l ItemSearchParams<'l>) ->
|
||||||
|
UResult<Vec<Arc<Item>>> {
|
||||||
|
Ok(match &ctx.trans.resolve_items_by_display_name_for_player(search).await?[..] {
|
||||||
|
[] => user_error("Sorry, I couldn't find anything matching.".to_owned())?,
|
||||||
|
v => v.into_iter().map(|it| it.clone()).collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)] mod test {
|
#[cfg(test)] mod test {
|
||||||
use crate::db::MockDBTrans;
|
use crate::db::MockDBTrans;
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ impl UserVerb for Verb {
|
|||||||
|
|
||||||
let attack_whom = search_item_for_user(ctx, &ItemSearchParams {
|
let attack_whom = search_item_for_user(ctx, &ItemSearchParams {
|
||||||
include_loc_contents: true,
|
include_loc_contents: true,
|
||||||
|
limit: 1,
|
||||||
..ItemSearchParams::base(&player_item, remaining)
|
..ItemSearchParams::base(&player_item, remaining)
|
||||||
}).await?;
|
}).await?;
|
||||||
|
|
||||||
|
@ -6,7 +6,8 @@ use super::{
|
|||||||
ItemSearchParams,
|
ItemSearchParams,
|
||||||
user_error,
|
user_error,
|
||||||
get_player_item_or_fail,
|
get_player_item_or_fail,
|
||||||
search_item_for_user,
|
search_items_for_user,
|
||||||
|
parsing::parse_count
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
static_content::possession_type::possession_data,
|
static_content::possession_type::possession_data,
|
||||||
@ -115,20 +116,32 @@ impl QueueCommandHandler for QueueHandler {
|
|||||||
pub struct Verb;
|
pub struct Verb;
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
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, mut remaining: &str) -> UResult<()> {
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
// TODO: Parse "get target from container" variant
|
// TODO: Parse "get target from container" variant
|
||||||
let target = search_item_for_user(ctx, &ItemSearchParams {
|
let mut get_limit = Some(1);
|
||||||
|
if remaining == "all" || remaining.starts_with("all ") {
|
||||||
|
remaining = remaining[3..].trim();
|
||||||
|
get_limit = None;
|
||||||
|
} else if let (Some(n), remaining2) = parse_count(remaining) {
|
||||||
|
get_limit = Some(n);
|
||||||
|
remaining = remaining2;
|
||||||
|
}
|
||||||
|
let targets = search_items_for_user(ctx, &ItemSearchParams {
|
||||||
include_loc_contents: true,
|
include_loc_contents: true,
|
||||||
|
item_type_only: Some("possession"),
|
||||||
|
limit: get_limit.unwrap_or(100),
|
||||||
..ItemSearchParams::base(&player_item, &remaining)
|
..ItemSearchParams::base(&player_item, &remaining)
|
||||||
}).await?;
|
}).await?;
|
||||||
if player_item.is_dead {
|
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())?;
|
||||||
}
|
}
|
||||||
if target.item_type != "possession" {
|
for target in targets {
|
||||||
user_error("You can't get that!".to_owned())?;
|
if target.item_type != "possession" {
|
||||||
|
user_error("You can't get that!".to_owned())?;
|
||||||
|
}
|
||||||
|
queue_command(ctx, &QueueCommand::Get { possession_id: target.item_code.clone() }).await?;
|
||||||
}
|
}
|
||||||
queue_command(ctx, &QueueCommand::Get { possession_id: target.item_code.clone() }).await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,6 +219,7 @@ impl UserVerb for Verb {
|
|||||||
&ItemSearchParams {
|
&ItemSearchParams {
|
||||||
include_contents: true,
|
include_contents: true,
|
||||||
include_loc_contents: true,
|
include_loc_contents: true,
|
||||||
|
limit: 1,
|
||||||
..ItemSearchParams::base(&player_item, &rem_trim)
|
..ItemSearchParams::base(&player_item, &rem_trim)
|
||||||
}
|
}
|
||||||
).await?
|
).await?
|
||||||
|
@ -45,6 +45,16 @@ pub fn parse_offset(input: &str) -> (Option<u8>, &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_count(input: &str) -> (Option<u8>, &str) {
|
||||||
|
fn parser(input: &str) -> IResult<&str, u8> {
|
||||||
|
terminated(u8, char(' '))(input)
|
||||||
|
}
|
||||||
|
match parser(input) {
|
||||||
|
Err(_) => (None, input),
|
||||||
|
Ok((rest, result)) => (Some(result), rest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_username(input: &str) -> Result<(&str, &str), &'static str> {
|
pub fn parse_username(input: &str) -> Result<(&str, &str), &'static str> {
|
||||||
const CATCHALL_ERROR: &'static str = "Must only contain alphanumeric characters or _";
|
const CATCHALL_ERROR: &'static str = "Must only contain alphanumeric characters or _";
|
||||||
fn parse_valid(input: &str) -> IResult<&str, (), VerboseError<&str>> {
|
fn parse_valid(input: &str) -> IResult<&str, (), VerboseError<&str>> {
|
||||||
|
@ -22,6 +22,7 @@ impl UserVerb for Verb {
|
|||||||
}
|
}
|
||||||
let to_whom = search_item_for_user(ctx, &ItemSearchParams {
|
let to_whom = search_item_for_user(ctx, &ItemSearchParams {
|
||||||
include_loc_contents: true,
|
include_loc_contents: true,
|
||||||
|
limit: 1,
|
||||||
..ItemSearchParams::base(&player_item, &to_whom_name)
|
..ItemSearchParams::base(&player_item, &to_whom_name)
|
||||||
}).await?;
|
}).await?;
|
||||||
|
|
||||||
|
@ -117,6 +117,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 weapon = search_item_for_user(ctx, &ItemSearchParams {
|
let weapon = search_item_for_user(ctx, &ItemSearchParams {
|
||||||
include_contents: true,
|
include_contents: true,
|
||||||
|
limit: 1,
|
||||||
..ItemSearchParams::base(&player_item, &remaining)
|
..ItemSearchParams::base(&player_item, &remaining)
|
||||||
}).await?;
|
}).await?;
|
||||||
if player_item.is_dead {
|
if player_item.is_dead {
|
||||||
|
Loading…
Reference in New Issue
Block a user