Open doors automatically on movement.
This commit is contained in:
parent
131512fbf6
commit
62f5457d3a
@ -1,11 +1,16 @@
|
|||||||
use super::{VerbContext, UserVerb, UserVerbRef, UResult, UserError, user_error,
|
use super::{
|
||||||
get_player_item_or_fail, search_item_for_user};
|
VerbContext, UserVerb, UserVerbRef, UResult, UserError, user_error,
|
||||||
|
get_player_item_or_fail, search_item_for_user,
|
||||||
|
map::{render_map, render_map_dyn},
|
||||||
|
open::{is_door_in_direction, DoorSituation},
|
||||||
|
};
|
||||||
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::{
|
use crate::{
|
||||||
db::ItemSearchParams,
|
db::ItemSearchParams,
|
||||||
models::{item::{
|
models::{item::{
|
||||||
Item, LocationActionType, Subattack, ItemFlag, ItemSpecialData
|
Item, LocationActionType, Subattack, ItemFlag, ItemSpecialData,
|
||||||
|
DoorState
|
||||||
}},
|
}},
|
||||||
static_content::{
|
static_content::{
|
||||||
room::{self, Direction},
|
room::{self, Direction},
|
||||||
@ -15,7 +20,6 @@ use crate::{
|
|||||||
language,
|
language,
|
||||||
services::combat::max_health,
|
services::combat::max_health,
|
||||||
};
|
};
|
||||||
use super::map::{render_map, render_map_dyn};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use mockall_double::double;
|
use mockall_double::double;
|
||||||
@ -176,6 +180,32 @@ pub async fn describe_dynroom(ctx: &VerbContext<'_>,
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn describe_door(
|
||||||
|
ctx: &VerbContext<'_>,
|
||||||
|
room_item: &Item,
|
||||||
|
state: &DoorState,
|
||||||
|
direction: &Direction,
|
||||||
|
) -> UResult<()> {
|
||||||
|
let mut msg = format!("That exit is blocked by {}.",
|
||||||
|
&state.description);
|
||||||
|
if let Some(lock) = ctx.trans.find_by_action_and_location(
|
||||||
|
&room_item.refstr(),
|
||||||
|
&LocationActionType::InstalledOnDoorAsLock((*direction).clone())).await?
|
||||||
|
{
|
||||||
|
let lock_desc = lock.display_for_session(&ctx.session_dat);
|
||||||
|
msg.push_str(&format!(" The door is locked with {} {}",
|
||||||
|
&language::indefinite_article(&lock_desc),
|
||||||
|
&lock_desc
|
||||||
|
));
|
||||||
|
}
|
||||||
|
msg.push('\n');
|
||||||
|
ctx.trans.queue_for_session(
|
||||||
|
ctx.session,
|
||||||
|
Some(&msg)).await?;
|
||||||
|
Ok(())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
async fn list_room_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());
|
||||||
@ -321,6 +351,19 @@ impl UserVerb for Verb {
|
|||||||
ctx.trans.find_item_by_type_code(heretype, herecode).await?
|
ctx.trans.find_item_by_type_code(heretype, herecode).await?
|
||||||
.ok_or_else(|| UserError("Sorry, that no longer exists".to_owned()))?
|
.ok_or_else(|| UserError("Sorry, that no longer exists".to_owned()))?
|
||||||
} else if let Some(dir) = Direction::parse(&rem_trim) {
|
} else if let Some(dir) = Direction::parse(&rem_trim) {
|
||||||
|
match is_door_in_direction(&ctx.trans, &dir, &player_item).await? {
|
||||||
|
DoorSituation::NoDoor |
|
||||||
|
DoorSituation::DoorOutOfRoom { state: DoorState { open: true, .. }, .. } |
|
||||||
|
DoorSituation::DoorIntoRoom { state: DoorState { open: true, .. }, .. } => {},
|
||||||
|
DoorSituation::DoorIntoRoom { state, room_with_door, .. } => {
|
||||||
|
if let Some(rev_dir) = dir.reverse() {
|
||||||
|
return describe_door(ctx, &room_with_door, &state, &rev_dir).await;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
DoorSituation::DoorOutOfRoom { state, room_with_door, .. } => {
|
||||||
|
return describe_door(ctx, &room_with_door, &state, &dir).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
direction_to_item(&ctx.trans, use_location, &dir).await?
|
direction_to_item(&ctx.trans, use_location, &dir).await?
|
||||||
.ok_or_else(|| UserError("There's nothing in that direction".to_owned()))?
|
.ok_or_else(|| UserError("There's nothing in that direction".to_owned()))?
|
||||||
} else if rem_trim == "me" || rem_trim == "self" {
|
} else if rem_trim == "me" || rem_trim == "self" {
|
||||||
|
@ -2,6 +2,7 @@ use super::{
|
|||||||
VerbContext, UserVerb, UserVerbRef, UResult, UserError, user_error,
|
VerbContext, UserVerb, UserVerbRef, UResult, UserError, user_error,
|
||||||
get_player_item_or_fail,
|
get_player_item_or_fail,
|
||||||
look,
|
look,
|
||||||
|
open::{DoorSituation, is_door_in_direction, attempt_open_immediate},
|
||||||
};
|
};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -20,7 +21,8 @@ use crate::{
|
|||||||
Item,
|
Item,
|
||||||
ItemSpecialData,
|
ItemSpecialData,
|
||||||
SkillType,
|
SkillType,
|
||||||
LocationActionType
|
LocationActionType,
|
||||||
|
DoorState,
|
||||||
},
|
},
|
||||||
services::{
|
services::{
|
||||||
comms::broadcast_to_room,
|
comms::broadcast_to_room,
|
||||||
@ -139,7 +141,9 @@ pub async fn attempt_move_immediate(
|
|||||||
trans: &DBTrans,
|
trans: &DBTrans,
|
||||||
orig_mover: &Item,
|
orig_mover: &Item,
|
||||||
direction: &Direction,
|
direction: &Direction,
|
||||||
mut player_ctx: Option<&mut VerbContext<'_>>
|
// player_ctx should only be Some if called from queue_handler finish_command
|
||||||
|
// for the orig_mover's queue, because might re-queue a move command.
|
||||||
|
mut player_ctx: &mut Option<&mut VerbContext<'_>>
|
||||||
) -> UResult<()> {
|
) -> UResult<()> {
|
||||||
let use_location = if orig_mover.is_dead {
|
let use_location = if orig_mover.is_dead {
|
||||||
if orig_mover.item_type != "player" {
|
if orig_mover.item_type != "player" {
|
||||||
@ -150,6 +154,27 @@ pub async fn attempt_move_immediate(
|
|||||||
&orig_mover.location
|
&orig_mover.location
|
||||||
};
|
};
|
||||||
|
|
||||||
|
match is_door_in_direction(trans, direction, orig_mover).await? {
|
||||||
|
DoorSituation::NoDoor |
|
||||||
|
DoorSituation::DoorIntoRoom { state: DoorState { open: true, .. }, .. } |
|
||||||
|
DoorSituation::DoorOutOfRoom { state: DoorState { open: true, .. }, .. } => {},
|
||||||
|
_ => {
|
||||||
|
attempt_open_immediate(trans, player_ctx, orig_mover, direction).await?;
|
||||||
|
match player_ctx.as_mut() {
|
||||||
|
None => {
|
||||||
|
// NPCs etc... open and move in one step, but can't unlock.
|
||||||
|
},
|
||||||
|
Some(actual_player_ctx) => {
|
||||||
|
// Players take an extra step. So tell them to come back.
|
||||||
|
actual_player_ctx.session_dat.queue.push_front(
|
||||||
|
QueueCommand::Movement { direction: direction.clone() }
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut mover = (*orig_mover).clone();
|
let mut mover = (*orig_mover).clone();
|
||||||
let (new_loc, new_loc_item) = move_to_where(trans, use_location, direction, &mut mover, &mut player_ctx).await?;
|
let (new_loc, new_loc_item) = move_to_where(trans, use_location, direction, &mut mover, &mut player_ctx).await?;
|
||||||
|
|
||||||
@ -253,7 +278,7 @@ impl QueueCommandHandler for QueueHandler {
|
|||||||
_ => user_error("Unexpected command".to_owned())?
|
_ => user_error("Unexpected command".to_owned())?
|
||||||
};
|
};
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
attempt_move_immediate(ctx.trans, &player_item, direction, Some(ctx)).await?;
|
attempt_move_immediate(ctx.trans, &player_item, direction, &mut Some(ctx)).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ use crate::{
|
|||||||
possession_type::possession_data,
|
possession_type::possession_data,
|
||||||
},
|
},
|
||||||
models::{
|
models::{
|
||||||
item::{Item, LocationActionType},
|
item::{Item, LocationActionType, DoorState},
|
||||||
task::{Task, TaskMeta, TaskDetails}
|
task::{Task, TaskMeta, TaskDetails}
|
||||||
},
|
},
|
||||||
services::comms::broadcast_to_room,
|
services::comms::broadcast_to_room,
|
||||||
@ -28,6 +28,8 @@ use crate::{
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time;
|
use std::time;
|
||||||
use chrono::{self, Utc};
|
use chrono::{self, Utc};
|
||||||
|
use mockall_double::double;
|
||||||
|
#[double] use crate::db::DBTrans;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -37,7 +39,6 @@ pub static SWING_SHUT_HANDLER: &'static (dyn TaskHandler + Sync + Send) = &Swing
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl TaskHandler for SwingShutHandler {
|
impl TaskHandler for SwingShutHandler {
|
||||||
async fn do_task(&self, ctx: &mut TaskRunContext) -> DResult<Option<time::Duration>> {
|
async fn do_task(&self, ctx: &mut TaskRunContext) -> DResult<Option<time::Duration>> {
|
||||||
info!("Starting swing shut");
|
|
||||||
let (room_str, direction) = match &ctx.task.details {
|
let (room_str, direction) = match &ctx.task.details {
|
||||||
TaskDetails::SwingShut { room_item, direction } => (room_item, direction),
|
TaskDetails::SwingShut { room_item, direction } => (room_item, direction),
|
||||||
_ => { return Ok(None); }
|
_ => { return Ok(None); }
|
||||||
@ -69,27 +70,118 @@ impl TaskHandler for SwingShutHandler {
|
|||||||
broadcast_to_room(&ctx.trans, &other_room.refstr(), None, &msg, Some(&msg)).await?;
|
broadcast_to_room(&ctx.trans, &other_room.refstr(), None, &msg, Some(&msg)).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Finishing swing shut");
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn attempt_open_immediate(trans: &DBTrans, ctx_opt: &mut Option<&mut VerbContext<'_>>,
|
||||||
|
who: &Item, direction: &Direction) -> UResult<()> {
|
||||||
|
if who.is_dead {
|
||||||
|
user_error("Your ethereal hands don't seem to be able to move the door.".to_owned())?;
|
||||||
|
}
|
||||||
|
let (room_1, dir_in_room, room_2) = match is_door_in_direction(trans, &direction, &who).await? {
|
||||||
|
DoorSituation::NoDoor => user_error("There is no door to open.".to_owned())?,
|
||||||
|
DoorSituation::DoorIntoRoom { state: DoorState { open: true, .. }, .. } |
|
||||||
|
DoorSituation::DoorOutOfRoom { state: DoorState { open: true, .. }, .. } =>
|
||||||
|
user_error("The door is already open.".to_owned())?,
|
||||||
|
DoorSituation::DoorIntoRoom { room_with_door, current_room, .. } => {
|
||||||
|
let entering_room_loc = room_with_door.refstr();
|
||||||
|
if let Some(revdir) = direction.reverse() {
|
||||||
|
if let Some(lock) = trans.find_by_action_and_location(
|
||||||
|
&entering_room_loc,
|
||||||
|
&LocationActionType::InstalledOnDoorAsLock(revdir.clone())).await?
|
||||||
|
{
|
||||||
|
if let Some(ctx) = ctx_opt {
|
||||||
|
if let Some(lockcheck) = lock.possession_type.as_ref()
|
||||||
|
.and_then(|pt| possession_data().get(pt))
|
||||||
|
.and_then(|pd| pd.lockcheck_handler) {
|
||||||
|
lockcheck.cmd(ctx, &who, &lock).await?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// NPCs don't unlock doors.
|
||||||
|
user_error("Can't get through locked doors".to_owned())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 = true;
|
||||||
|
info!("Set door_map");
|
||||||
|
} else {
|
||||||
|
info!("door_map missing direction");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info!("door_map None");
|
||||||
|
}
|
||||||
|
info!("Saving door map");
|
||||||
|
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 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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(
|
||||||
|
&trans,
|
||||||
|
loc,
|
||||||
|
None,
|
||||||
|
&format!("{} opens the door to the {}.\n",
|
||||||
|
&who.display_for_sentence(true, 1, true),
|
||||||
|
dir
|
||||||
|
),
|
||||||
|
Some(
|
||||||
|
&format!("{} opens the door to the {}.\n",
|
||||||
|
&who.display_for_sentence(false, 1, true),
|
||||||
|
dir
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
trans.upsert_task(&Task {
|
||||||
|
meta: TaskMeta {
|
||||||
|
task_code: format!("{}/{}", &room_1.refstr(), &direction.describe()),
|
||||||
|
next_scheduled: Utc::now() + chrono::Duration::seconds(120),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
details: TaskDetails::SwingShut {
|
||||||
|
room_item: room_1.refstr(),
|
||||||
|
direction: dir_in_room.clone()
|
||||||
|
}
|
||||||
|
}).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub struct QueueHandler;
|
pub struct QueueHandler;
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl QueueCommandHandler for QueueHandler {
|
impl QueueCommandHandler for QueueHandler {
|
||||||
async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
async fn start_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
||||||
-> UResult<time::Duration> {
|
-> UResult<time::Duration> {
|
||||||
info!("Starting open start_command");
|
|
||||||
let direction = match command {
|
let direction = match command {
|
||||||
QueueCommand::OpenDoor { direction } => direction,
|
QueueCommand::OpenDoor { direction } => direction,
|
||||||
_ => user_error("Unexpected command".to_owned())?
|
_ => user_error("Unexpected command".to_owned())?
|
||||||
};
|
};
|
||||||
info!("Direction good");
|
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
info!("Got player");
|
match is_door_in_direction(&ctx.trans, &direction, &player_item).await? {
|
||||||
match is_door_in_direction(ctx, &direction, &player_item).await? {
|
|
||||||
DoorSituation::NoDoor => user_error("There is no door to open.".to_owned())?,
|
DoorSituation::NoDoor => user_error("There is no door to open.".to_owned())?,
|
||||||
DoorSituation::DoorIntoRoom { is_open: true, .. } | DoorSituation::DoorOutOfRoom { is_open: true, .. } =>
|
DoorSituation::DoorIntoRoom { state: DoorState { open: true, .. }, .. } |
|
||||||
|
DoorSituation::DoorOutOfRoom { state: DoorState { open: true, .. }, .. } =>
|
||||||
user_error("The door is already open.".to_owned())?,
|
user_error("The door is already open.".to_owned())?,
|
||||||
DoorSituation::DoorIntoRoom { room_with_door: entering_room, .. } => {
|
DoorSituation::DoorIntoRoom { room_with_door: entering_room, .. } => {
|
||||||
let entering_room_loc = entering_room.refstr();
|
let entering_room_loc = entering_room.refstr();
|
||||||
@ -109,118 +201,42 @@ impl QueueCommandHandler for QueueHandler {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Clean exit open start_command");
|
|
||||||
Ok(time::Duration::from_secs(1))
|
Ok(time::Duration::from_secs(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
async fn finish_command(&self, ctx: &mut VerbContext<'_>, command: &QueueCommand)
|
||||||
-> UResult<()> {
|
-> UResult<()> {
|
||||||
info!("Starting open finish_command");
|
|
||||||
let direction = match command {
|
let direction = match command {
|
||||||
QueueCommand::OpenDoor { direction } => direction,
|
QueueCommand::OpenDoor { direction } => direction,
|
||||||
_ => user_error("Unexpected command".to_owned())?
|
_ => user_error("Unexpected command".to_owned())?
|
||||||
};
|
};
|
||||||
let player_item = get_player_item_or_fail(ctx).await?;
|
let player_item = get_player_item_or_fail(ctx).await?;
|
||||||
let (room_1, dir_in_room, room_2) = match is_door_in_direction(ctx, &direction, &player_item).await? {
|
attempt_open_immediate(&ctx.trans, &mut Some(ctx), &player_item, &direction).await?;
|
||||||
DoorSituation::NoDoor => user_error("There is no door to open.".to_owned())?,
|
|
||||||
DoorSituation::DoorIntoRoom { is_open: true, .. } |
|
|
||||||
DoorSituation::DoorOutOfRoom { is_open: true, .. } =>
|
|
||||||
user_error("The door is already open.".to_owned())?,
|
|
||||||
DoorSituation::DoorIntoRoom { room_with_door, current_room, .. } => {
|
|
||||||
let entering_room_loc = room_with_door.refstr();
|
|
||||||
if let Some(revdir) = direction.reverse() {
|
|
||||||
if let Some(lock) = ctx.trans.find_by_action_and_location(
|
|
||||||
&entering_room_loc,
|
|
||||||
&LocationActionType::InstalledOnDoorAsLock(revdir.clone())).await?
|
|
||||||
{
|
|
||||||
if let Some(lockcheck) = lock.possession_type.as_ref()
|
|
||||||
.and_then(|pt| possession_data().get(pt))
|
|
||||||
.and_then(|pd| pd.lockcheck_handler) {
|
|
||||||
lockcheck.cmd(ctx, &player_item, &lock).await?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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!("{} opens the door to the {}.\n",
|
|
||||||
&player_item.display_for_sentence(true, 1, true),
|
|
||||||
dir
|
|
||||||
),
|
|
||||||
Some(
|
|
||||||
&format!("{} opens the door to the {}.\n",
|
|
||||||
&player_item.display_for_sentence(false, 1, true),
|
|
||||||
dir
|
|
||||||
)
|
|
||||||
)
|
|
||||||
).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.trans.upsert_task(&Task {
|
|
||||||
meta: TaskMeta {
|
|
||||||
task_code: format!("{}/{}", &room_1.refstr(), &direction.describe()),
|
|
||||||
next_scheduled: Utc::now() + chrono::Duration::seconds(120),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
details: TaskDetails::SwingShut {
|
|
||||||
room_item: room_1.refstr(),
|
|
||||||
direction: dir_in_room.clone()
|
|
||||||
}
|
|
||||||
}).await?;
|
|
||||||
|
|
||||||
info!("Clean exit open finish_command");
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum DoorSituation {
|
pub enum DoorSituation {
|
||||||
NoDoor,
|
NoDoor,
|
||||||
DoorIntoRoom { is_open: bool, room_with_door: Arc<Item>, current_room: Arc<Item> }, // Can be locked etc...
|
DoorIntoRoom { state: DoorState, room_with_door: Arc<Item>, current_room: Arc<Item> }, // Can be locked etc...
|
||||||
DoorOutOfRoom { is_open: bool, room_with_door: Arc<Item>, new_room: Arc<Item> } // No lockable.
|
DoorOutOfRoom { state: DoorState, room_with_door: Arc<Item>, new_room: Arc<Item> } // No lockable.
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn is_door_in_direction(ctx: &mut VerbContext<'_>, direction: &Direction, player_item: &Item) ->
|
pub async fn is_door_in_direction(trans: &DBTrans, direction: &Direction, player_item: &Item) ->
|
||||||
UResult<DoorSituation> {
|
UResult<DoorSituation> {
|
||||||
let (loc_type_t, loc_type_c) = player_item.location.split_once("/")
|
let (loc_type_t, loc_type_c) = player_item.location.split_once("/")
|
||||||
.ok_or_else(|| UserError("Invalid location".to_owned()))?;
|
.ok_or_else(|| UserError("Invalid location".to_owned()))?;
|
||||||
let cur_loc_item = ctx.trans.find_item_by_type_code(loc_type_t, loc_type_c).await?
|
let cur_loc_item = trans.find_item_by_type_code(loc_type_t, loc_type_c).await?
|
||||||
.ok_or_else(|| UserError("Can't find your current location anymore.".to_owned()))?;
|
.ok_or_else(|| UserError("Can't find your current location anymore.".to_owned()))?;
|
||||||
let new_loc_item = direction_to_item(ctx.trans, &player_item.location, direction).await?
|
let new_loc_item = direction_to_item(trans, &player_item.location, direction).await?
|
||||||
.ok_or_else(|| UserError("That exit doesn't really seem to go anywhere!".to_owned()))?;
|
.ok_or_else(|| UserError("That exit doesn't really seem to go anywhere!".to_owned()))?;
|
||||||
if let Some(door_state) =
|
if let Some(door_state) =
|
||||||
cur_loc_item.door_states.as_ref()
|
cur_loc_item.door_states.as_ref()
|
||||||
.and_then(|v| v.get(direction)) {
|
.and_then(|v| v.get(direction)) {
|
||||||
return Ok(DoorSituation::DoorOutOfRoom {
|
return Ok(DoorSituation::DoorOutOfRoom {
|
||||||
is_open: door_state.open,
|
state: door_state.clone(),
|
||||||
room_with_door: cur_loc_item,
|
room_with_door: cur_loc_item,
|
||||||
new_room: new_loc_item
|
new_room: new_loc_item
|
||||||
});
|
});
|
||||||
@ -230,7 +246,7 @@ pub async fn is_door_in_direction(ctx: &mut VerbContext<'_>, direction: &Directi
|
|||||||
.and_then(|v| direction.reverse().as_ref()
|
.and_then(|v| direction.reverse().as_ref()
|
||||||
.and_then(|rev| v.get(rev).map(|door| door.clone()))) {
|
.and_then(|rev| v.get(rev).map(|door| door.clone()))) {
|
||||||
return Ok(DoorSituation::DoorIntoRoom {
|
return Ok(DoorSituation::DoorIntoRoom {
|
||||||
is_open: door_state.open,
|
state: door_state.clone(),
|
||||||
room_with_door: new_loc_item,
|
room_with_door: new_loc_item,
|
||||||
current_room: cur_loc_item
|
current_room: cur_loc_item
|
||||||
});
|
});
|
||||||
@ -245,9 +261,7 @@ 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, remaining: &str) -> UResult<()> {
|
||||||
let dir = Direction::parse(remaining)
|
let dir = Direction::parse(remaining)
|
||||||
.ok_or_else(|| UserError("Unknown direction".to_owned()))?;
|
.ok_or_else(|| UserError("Unknown direction".to_owned()))?;
|
||||||
info!("Queueing open");
|
|
||||||
queue_command(ctx, &QueueCommand::OpenDoor { direction: dir.clone() }).await?;
|
queue_command(ctx, &QueueCommand::OpenDoor { direction: dir.clone() }).await?;
|
||||||
info!("Returning from open handler");
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,8 +310,19 @@ pub struct DynamicEntrance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct DoorState {
|
pub struct DoorState {
|
||||||
pub open: bool,
|
pub open: bool,
|
||||||
|
pub description: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DoorState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
open: false,
|
||||||
|
description: "a solid looking wooden door".to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)]
|
||||||
|
@ -100,9 +100,10 @@ impl Dynzone {
|
|||||||
owner: Some(owner.clone()),
|
owner: Some(owner.clone()),
|
||||||
door_states: Some(room.exits.iter()
|
door_states: Some(room.exits.iter()
|
||||||
.filter_map(|ex|
|
.filter_map(|ex|
|
||||||
if ex.exit_type == ExitType::Doored {
|
if let ExitType::Doored { description } = ex.exit_type {
|
||||||
Some((ex.direction.clone(), DoorState {
|
Some((ex.direction.clone(), DoorState {
|
||||||
open: false
|
open: false,
|
||||||
|
description: description.to_owned()
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -133,7 +134,7 @@ impl Default for Dynzone {
|
|||||||
#[derive(Eq, Clone, PartialEq, Ord, PartialOrd)]
|
#[derive(Eq, Clone, PartialEq, Ord, PartialOrd)]
|
||||||
pub enum ExitType {
|
pub enum ExitType {
|
||||||
Doorless,
|
Doorless,
|
||||||
Doored,
|
Doored { description: &'static str },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, Ord, Debug, PartialEq, PartialOrd, Clone)]
|
#[derive(Eq, Ord, Debug, PartialEq, PartialOrd, Clone)]
|
||||||
|
@ -49,7 +49,7 @@ pub fn zone() -> Dynzone {
|
|||||||
Exit {
|
Exit {
|
||||||
direction: Direction::WEST,
|
direction: Direction::WEST,
|
||||||
target: ExitTarget::Intrazone { subcode: "doorstep" },
|
target: ExitTarget::Intrazone { subcode: "doorstep" },
|
||||||
exit_type: ExitType::Doored
|
exit_type: ExitType::Doored { description: "a reasonably sturdy looking fire-rated solid core beige painted door" }
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
grid_coords: GridCoords { x: 1, y: 0, z: 0 },
|
grid_coords: GridCoords { x: 1, y: 0, z: 0 },
|
||||||
|
@ -354,7 +354,7 @@ impl TaskHandler for NPCWanderTaskHandler {
|
|||||||
);
|
);
|
||||||
let dir_opt = ex_iter.choose(&mut thread_rng()).map(|ex| ex.direction.clone()).clone();
|
let dir_opt = ex_iter.choose(&mut thread_rng()).map(|ex| ex.direction.clone()).clone();
|
||||||
if let Some(dir) = dir_opt {
|
if let Some(dir) = dir_opt {
|
||||||
match attempt_move_immediate(ctx.trans, &item, &dir, None).await {
|
match attempt_move_immediate(ctx.trans, &item, &dir, &mut None).await {
|
||||||
Ok(()) | Err(CommandHandlingError::UserError(_)) => {},
|
Ok(()) | Err(CommandHandlingError::UserError(_)) => {},
|
||||||
Err(CommandHandlingError::SystemError(e)) => Err(e)?
|
Err(CommandHandlingError::SystemError(e)) => Err(e)?
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user