From cf2798a418d9d0f4e251f40611261d400320cf11 Mon Sep 17 00:00:00 2001 From: Shagnor Date: Thu, 29 Dec 2022 22:17:55 +1100 Subject: [PATCH] Expose more about contents of room. --- blastmud_game/src/db.rs | 10 +++ .../src/message_handler/user_commands/look.rs | 77 +++++++++++++++++-- blastmud_game/src/regular_tasks.rs | 46 ++++++----- blastmud_game/src/static_content/room.rs | 2 +- 4 files changed, 107 insertions(+), 28 deletions(-) diff --git a/blastmud_game/src/db.rs b/blastmud_game/src/db.rs index cc04d7db..e20916af 100644 --- a/blastmud_game/src/db.rs +++ b/blastmud_game/src/db.rs @@ -301,6 +301,16 @@ impl DBTrans { } Ok(None) } + + pub async fn find_items_by_location(self: &Self, location: &str) -> DResult> { + Ok(self.pg_trans()?.query( + "SELECT details FROM items WHERE details->>'location' = $1 \ + LIMIT 20", &[&location] + ).await?.into_iter() + .filter_map(|i| serde_json::from_value(i.get("details")).ok()) + .collect()) + + } pub async fn commit(mut self: Self) -> DResult<()> { let trans_opt = self.with_trans_mut(|t| std::mem::replace(t, None)); diff --git a/blastmud_game/src/message_handler/user_commands/look.rs b/blastmud_game/src/message_handler/user_commands/look.rs index 3bc3bbe5..776e4f6a 100644 --- a/blastmud_game/src/message_handler/user_commands/look.rs +++ b/blastmud_game/src/message_handler/user_commands/look.rs @@ -1,8 +1,9 @@ use super::{VerbContext, UserVerb, UserVerbRef, UResult, UserError, user_error, explicit_if_allowed}; use async_trait::async_trait; use ansi::{ansi, flow_around, word_wrap}; -use crate::models::{user::User, item::Item}; +use crate::models::{user::User, item::{Item, LocationActionType, Subattack}}; use crate::static_content::room::{self, Direction}; +use itertools::Itertools; pub fn get_user_or_fail<'l>(ctx: &'l VerbContext) -> UResult<&'l User> { ctx.user_dat.as_ref() @@ -62,20 +63,82 @@ fn exits_for(room: &room::Room) -> String { format!(ansi!("[ Exits: {} ]"), exit_text.join(" ")) } -pub async fn describe_room(ctx: &VerbContext<'_>, room: &room::Room) -> UResult<()> { +pub async fn describe_room(ctx: &VerbContext<'_>, room: &room::Room, contents: &str) -> UResult<()> { let zone = room::zone_details().get(room.zone).map(|z|z.display).unwrap_or("Outside of time"); ctx.trans.queue_for_session( ctx.session, Some(&flow_around(&render_map(room, 5, 5), 10, " ", - &word_wrap(&format!("{} ({})\n{}\n{}\n", room.name, zone, + &word_wrap(&format!("{} ({})\n{}.{}\n{}\n", room.name, zone, explicit_if_allowed(ctx, room.description, room.description_less_explicit), - exits_for(room)), + contents, exits_for(room)), |row| if row >= 5 { 80 } else { 68 }), 68)) ).await?; Ok(()) } +async fn list_item_contents<'l>(ctx: &'l VerbContext<'_>, item: &'l Item) -> UResult { + let mut buf = 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> = items + .iter() + .group_by(|i| &i.display) + .into_iter() + .map(|(_, g)|g.collect::>()) + .collect::>>(); + + for group_items in all_groups { + let head = &group_items[0]; + let is_creature = head.item_type == "player" || head.item_type.starts_with("npc"); + buf.push(' '); + if group_items.len() > 1 { + buf.push_str(&format!("{} ", group_items.len())) + } else if !is_creature { + buf.push_str("A "); + } + buf.push_str( + &explicit_if_allowed(ctx, + &head.display, + head.display_less_explicit.as_ref().map(|v|&**v))); + buf.push_str(" is "); + match head.action_type { + LocationActionType::Sitting => buf.push_str("sitting "), + LocationActionType::Reclining => buf.push_str("reclining "), + _ => {} + } + buf.push_str("here"); + if let LocationActionType::Attacking(subattack) = &head.action_type { + match subattack { + Subattack::Powerattacking => buf.push_str(", powerattacking "), + Subattack::Feinting => buf.push_str(", feinting "), + Subattack::Grabbing => buf.push_str(", grabbing "), + Subattack::Wrestling => buf.push_str(", wrestling "), + _ => buf.push_str(", attacking ") + } + match &head.presence_target { + None => buf.push_str("someone"), + Some(who) => match who.split_once("/") { + None => buf.push_str("someone"), + Some((ttype, tcode)) => + match ctx.trans.find_item_by_type_code(ttype, tcode).await? { + None => buf.push_str("someone"), + Some(it) => buf.push_str( + &explicit_if_allowed(ctx, + &it.display, + it.display_less_explicit.as_ref().map(|v|&**v)) + ) + } + } + } + } + buf.push('.'); + } + Ok(buf) +} + pub struct Verb; #[async_trait] impl UserVerb for Verb { @@ -107,14 +170,14 @@ impl UserVerb for Verb { } else { user_error("Sorry, I don't understand what you want to look at.".to_owned()) }?; + let item = ctx.trans.find_item_by_type_code(itype, icode).await? + .ok_or_else(|| UserError("Sorry, that no longer exists".to_owned()))?; if itype != "room" { - let item = ctx.trans.find_item_by_type_code(itype, icode).await? - .ok_or_else(|| UserError("Sorry, that no longer exists".to_owned()))?; describe_normal_item(ctx, &item).await?; } else { let room = room::room_map_by_code().get(icode).ok_or_else(|| UserError("Sorry, that room no longer exists".to_owned()))?; - describe_room(ctx, &room).await?; + describe_room(ctx, &room, &list_item_contents(ctx, &item).await?).await?; } Ok(()) } diff --git a/blastmud_game/src/regular_tasks.rs b/blastmud_game/src/regular_tasks.rs index 39452bc5..afee1f6b 100644 --- a/blastmud_game/src/regular_tasks.rs +++ b/blastmud_game/src/regular_tasks.rs @@ -27,29 +27,35 @@ fn start_session_cleanup_task(pool: db::DBPool) { } async fn process_sendqueue_once(pool: db::DBPool, listener_map: ListenerMap) -> DResult<()> { - for item in pool.get_from_sendqueue().await? { - match listener_map.lock().await.get(&item.session.listener).map(|l| l.clone()) { - None => {} - Some(listener_sender) => { - let (tx, rx) = oneshot::channel(); - listener_sender.send( - ListenerSend { - message: match item.message.clone() { - None => MessageToListener::DisconnectSession { - session: item.session.session.clone() + loop { + let q = pool.get_from_sendqueue().await?; + for item in &q { + match listener_map.lock().await.get(&item.session.listener).map(|l| l.clone()) { + None => {} + Some(listener_sender) => { + let (tx, rx) = oneshot::channel(); + listener_sender.send( + ListenerSend { + message: match item.message.clone() { + None => MessageToListener::DisconnectSession { + session: item.session.session.clone() + }, + Some(msg) => MessageToListener::SendToSession { + session: item.session.session.clone(), + msg: msg + } }, - Some(msg) => MessageToListener::SendToSession { - session: item.session.session.clone(), - msg: msg - } - }, - ack_notify: tx - } - ).await.unwrap_or(()); - rx.await.unwrap_or(()); - pool.delete_from_sendqueue(&item).await?; + ack_notify: tx + } + ).await.unwrap_or(()); + rx.await.unwrap_or(()); + pool.delete_from_sendqueue(&item).await?; + } } } + if q.len() <= 9 { + break; + } } Ok(()) } diff --git a/blastmud_game/src/static_content/room.rs b/blastmud_game/src/static_content/room.rs index c6bb11e3..95d3207f 100644 --- a/blastmud_game/src/static_content/room.rs +++ b/blastmud_game/src/static_content/room.rs @@ -144,7 +144,7 @@ pub fn room_list() -> &'static Vec { will impact who you end up being, and you would need to completely \ wipe your brain again to change them. Talk to Statbot to spend your \ 14 points and create your body.\"\n\ - [Try \"statbot hi, to send hi to statbot - the \" means \ + [Try -statbot hi, to send hi to statbot - the - means \ to whisper to a particular person in the room]"), description_less_explicit: None, grid_coords: GridCoords { x: 0, y: 0, z: 1 },