use super::{ VerbContext, UserVerb, UserVerbRef, UResult, UserError, user_error, get_player_item_or_fail, open::{is_door_in_direction, DoorSituation}, }; use crate::{ regular_tasks::{ queued_command::{ QueueCommandHandler, QueueCommand, queue_command }, }, static_content::{ room::Direction, }, models::{ item::DoorState, }, services::comms::broadcast_to_room, }; 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 { let direction = match command { QueueCommand::CloseDoor { direction } => direction, _ => user_error("Unexpected queued command".to_owned())? }; let player_item = get_player_item_or_fail(ctx).await?; match is_door_in_direction(&ctx.trans, &direction, &player_item).await? { DoorSituation::NoDoor => user_error("There is no door to close.".to_owned())?, DoorSituation::DoorIntoRoom { state: DoorState { open: false, .. }, .. } | DoorSituation::DoorOutOfRoom { state: DoorState { open: false, .. }, .. } => user_error("The door is already closed.".to_owned())?, _ => {} } Ok(time::Duration::from_secs(1)) } #[allow(unreachable_patterns)] async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand) -> UResult<()> { let direction = match command { QueueCommand::CloseDoor { direction } => direction, _ => user_error("Unexpected queued command".to_owned())? }; let player_item = get_player_item_or_fail(ctx).await?; let (room_1, dir_in_room, room_2) = match is_door_in_direction(&ctx.trans, &direction, &player_item).await? { DoorSituation::NoDoor => user_error("There is no door to close.".to_owned())?, DoorSituation::DoorIntoRoom { state: DoorState { open: false, .. }, .. } | DoorSituation::DoorOutOfRoom { state: DoorState { open: false, .. }, .. } => user_error("The door is already closed.".to_owned())?, DoorSituation::DoorIntoRoom { room_with_door, current_room, .. } => { if let Some(revdir) = direction.reverse() { let mut entering_room_mut = (*room_with_door).clone(); if let Some(door_map) = entering_room_mut.door_states.as_mut() { if let Some(door) = door_map.get_mut(&revdir) { (*door).open = false; } }; ctx.trans.save_item_model(&entering_room_mut).await?; (room_with_door, revdir, current_room) } else { user_error("There's no door possible there.".to_owned())? } }, DoorSituation::DoorOutOfRoom { room_with_door, new_room, .. } => { let mut entering_room_mut = (*room_with_door).clone(); if let Some(door_map) = entering_room_mut.door_states.as_mut() { if let Some(door) = door_map.get_mut(&direction) { (*door).open = false; } } ctx.trans.save_item_model(&entering_room_mut).await?; (room_with_door, direction.clone(), new_room) } }; for (loc, dir) in [(&room_1.refstr(), &dir_in_room.describe()), (&room_2.refstr(), &dir_in_room.reverse().map(|d| d.describe()) .unwrap_or_else(|| "outside".to_owned()))] { broadcast_to_room( &ctx.trans, loc, None, &format!("{} closes the door to the {}.\n", &player_item.display_for_sentence(true, 1, true), dir ), Some( &format!("{} closes the door to the {}.\n", &player_item.display_for_sentence(false, 1, true), dir ) ) ).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 dir = Direction::parse(remaining) .ok_or_else(|| UserError("Unknown direction".to_owned()))?; queue_command(ctx, &QueueCommand::CloseDoor { direction: dir.clone() }).await?; Ok(()) } } static VERB_INT: Verb = Verb; pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef;