diff --git a/blastmud_game/src/db.rs b/blastmud_game/src/db.rs index 32ffcf7..eccf74e 100644 --- a/blastmud_game/src/db.rs +++ b/blastmud_game/src/db.rs @@ -590,8 +590,10 @@ impl DBTrans { } if search.include_active_players { ctes.push("active_players AS (\ - SELECT details, ('[]'::JSONB) AS aliases FROM items WHERE details->>'item_type' = 'player' \ - AND current_session IS NOT NULL \ + SELECT i.details, ('[]'::JSONB) AS aliases FROM items i \ + JOIN users u ON u.username = i.details->>'item_code' \ + WHERE i.details->>'item_type' = 'player' \ + AND u.current_session IS NOT NULL \ )".to_owned()); include_tables.push("SELECT details, aliases FROM active_players"); } diff --git a/blastmud_game/src/message_handler/user_commands.rs b/blastmud_game/src/message_handler/user_commands.rs index 5a3417e..e13bec7 100644 --- a/blastmud_game/src/message_handler/user_commands.rs +++ b/blastmud_game/src/message_handler/user_commands.rs @@ -26,6 +26,7 @@ mod login; mod look; mod map; pub mod movement; +mod page; pub mod parsing; mod quit; mod register; @@ -125,6 +126,13 @@ static REGISTERED_COMMANDS: UserVerbRegistry = phf_map! { "list" => list::VERB, "lmap" => map::VERB, + "p" => page::VERB, + "page" => page::VERB, + "pg" => page::VERB, + "rep" => page::VERB, + "repl" => page::VERB, + "reply" => page::VERB, + "\'" => say::VERB, "say" => say::VERB, diff --git a/blastmud_game/src/message_handler/user_commands/page.rs b/blastmud_game/src/message_handler/user_commands/page.rs new file mode 100644 index 0000000..048f526 --- /dev/null +++ b/blastmud_game/src/message_handler/user_commands/page.rs @@ -0,0 +1,82 @@ +use super::{VerbContext, UserVerb, UserVerbRef, UResult, + ItemSearchParams, user_error, + get_player_item_or_fail, is_likely_explicit, + search_item_for_user, + parsing::parse_to_space}; +use async_trait::async_trait; +use ansi::{ignore_special_characters, ansi}; + +pub struct Verb; +#[async_trait] +impl UserVerb for Verb { + async fn handle(self: &Self, ctx: &mut VerbContext, verb: &str, remaining: &str) -> UResult<()> { + let (to_whom_name, say_what_raw) = if verb.starts_with("r") { + let last_page_from = match ctx.user_dat.as_ref().and_then(|u| u.last_page_from.as_ref()) { + None => user_error("No one has paged you, so you can't reply.".to_owned())?, + Some(m) => (*m).clone() + }; + (last_page_from, remaining) + } else { + let (to_whom, say_what) = parse_to_space(remaining); + (to_whom.to_owned(), say_what) + }; + let say_what = ignore_special_characters(&say_what_raw); + if say_what == "" { + user_error("You need to provide a message to send.".to_owned())?; + } + let player_item = get_player_item_or_fail(ctx).await?; + if player_item.is_dead { + user_error("Shush, the dead can't talk!".to_string())?; + } + let to_whom = search_item_for_user(ctx, &ItemSearchParams { + include_active_players: true, + limit: 1, + ..ItemSearchParams::base(&player_item, &to_whom_name) + }).await?; + + match to_whom.item_type.as_str() { + "player" => {}, + _ => user_error("Only players accept pages".to_string())? + } + + ctx.trans.queue_for_session(ctx.session, Some(&format!( + ansi!("You page {} on your wristpad: \"{}\"\n"), + to_whom.display_for_session(&ctx.session_dat), + say_what + ))).await?; + + if player_item == to_whom { + return Ok(()); + } + + match to_whom.item_type.as_str() { + "player" => { + match ctx.trans.find_session_for_player(&to_whom.item_code).await? { + None => user_error("That character is asleep.".to_string())?, + Some((other_session, other_session_dets)) => { + if other_session_dets.less_explicit_mode && is_likely_explicit(&say_what) { + user_error("That player is on a client that doesn't allow explicit \ + content, and your message looked explicit, so it wasn't sent." + .to_owned())? + } else { + if let Some(mut user) = ctx.trans.find_by_username(&to_whom.item_code).await? { + user.last_page_from = Some(player_item.item_code.clone()); + ctx.trans.save_user_model(&user).await?; + } + ctx.trans.queue_for_session(&other_session, Some(&format!( + ansi!("Your wristpad beeps with page from {}: \"{}\"\n"), + player_item.display_for_session(&ctx.session_dat), + say_what + ))).await?; + } + } + } + }, + _ => {} + } + + Ok(()) + } +} +static VERB_INT: Verb = Verb; +pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef; diff --git a/blastmud_game/src/models/user.rs b/blastmud_game/src/models/user.rs index 70eabaf..a7c01e5 100644 --- a/blastmud_game/src/models/user.rs +++ b/blastmud_game/src/models/user.rs @@ -35,6 +35,7 @@ pub struct User { pub raw_skills: BTreeMap, pub raw_stats: BTreeMap, pub last_skill_improve: BTreeMap>, + pub last_page_from: Option, pub credits: u64, // Reminder: Consider backwards compatibility when updating this. } @@ -77,6 +78,7 @@ impl Default for User { raw_skills: BTreeMap::new(), raw_stats: BTreeMap::new(), last_skill_improve: BTreeMap::new(), + last_page_from: None, credits: 500 } } diff --git a/blastmud_game/src/static_content/fixed_item.rs b/blastmud_game/src/static_content/fixed_item.rs index 35b0352..40bc902 100644 --- a/blastmud_game/src/static_content/fixed_item.rs +++ b/blastmud_game/src/static_content/fixed_item.rs @@ -10,7 +10,8 @@ pub struct FixedItem { pub description: &'static str, pub description_less_explicit: Option<&'static str>, pub location: &'static str, - pub proper_noun: bool + pub proper_noun: bool, + pub aliases: Vec<&'static str> } fn fixed_item_list() -> &'static Vec { @@ -34,7 +35,8 @@ fn fixed_item_list() -> &'static Vec { further out, outside my realm, is a dangerous and radioactive place.\"", description_less_explicit: None, location: "room/repro_xv_updates", - proper_noun: false + proper_noun: false, + aliases: vec!("poster") } )) } @@ -50,6 +52,7 @@ pub fn static_items() -> Box> { details_less_explicit: r.description_less_explicit.map(|d|d.to_owned()), location: r.location.to_owned(), is_static: true, + aliases: r.aliases.iter().map(|s| (*s).to_owned()).collect(), pronouns: Pronouns { is_proper: r.proper_noun, ..Pronouns::default_inanimate()