Allow plugging in to charge in powered locations

This commit is contained in:
Condorra 2024-01-17 22:48:42 +11:00
parent 15b96c1b50
commit 033cbf2273
8 changed files with 157 additions and 0 deletions

View File

@ -55,6 +55,7 @@ pub mod open;
mod page;
pub mod parsing;
pub mod pay;
pub mod plug;
mod pow;
pub mod put;
mod quit;
@ -198,6 +199,8 @@ static REGISTERED_COMMANDS: UserVerbRegistry = phf_map! {
"l" => look::VERB,
"look" => look::VERB,
"read" => look::VERB,
"examine" => look::VERB,
"ex" => look::VERB,
"feint" => feint::VERB,
"list" => list::VERB,
@ -221,6 +224,7 @@ static REGISTERED_COMMANDS: UserVerbRegistry = phf_map! {
"reply" => page::VERB,
"pay" => pay::VERB,
"plug" => plug::VERB,
"pow" => pow::VERB,
"power" => pow::VERB,

View File

@ -114,6 +114,7 @@ impl QueueCommandHandler for QueueHandler {
&item.display_for_sentence(1, false)
))?
}
ctx.trans.delete_task("ChargeItem", &item.refstr()).await?;
let msg = format!(
"{} picks up {}\n",

View File

@ -0,0 +1,143 @@
use crate::{
db::ItemSearchParams,
models::{
item::ItemSpecialData,
task::{Task, TaskDetails, TaskMeta},
},
services::comms::broadcast_to_room,
static_content::{
dynzone::{dynzone_by_type, DynzoneType},
possession_type::possession_data,
room::room_map_by_code,
},
DResult,
};
use super::{
get_player_item_or_fail, search_item_for_user, user_error, CommandHandlingError, UResult,
UserError, UserVerb, UserVerbRef, VerbContext,
};
#[double]
use crate::db::DBTrans;
use ansi::ansi;
use async_trait::async_trait;
use chrono::{Duration, Utc};
use mockall_double::double;
async fn place_has_power(trans: &DBTrans, place_type: &str, place_code: &str) -> DResult<bool> {
match place_type {
"room" => room_map_by_code()
.get(place_code)
.map(|r| Ok(r.has_power))
.unwrap_or(Ok(false)),
"dynroom" => trans
.find_item_by_type_code(place_type, place_code)
.await?
.and_then(|place| match place.special_data.as_ref() {
Some(ItemSpecialData::DynroomData {
dynzone_code,
dynroom_code,
}) => DynzoneType::from_str(&dynzone_code)
.and_then(|dzt| dynzone_by_type().get(&dzt))
.and_then(|dz| dz.dyn_rooms.get(dynroom_code.as_str()))
.map(|dr| Ok(dr.has_power)),
_ => None,
})
.unwrap_or(Ok(false)),
_ => Ok(false),
}
}
pub struct Verb;
#[async_trait]
impl UserVerb for Verb {
async fn handle(
self: &Self,
ctx: &mut VerbContext,
_verb: &str,
remaining: &str,
) -> UResult<()> {
let (word, remaining) = match remaining.split_once(" ") {
None => user_error(ansi!("Try <bold>plug in<reset> something").to_owned())?,
Some(v) => v,
};
if word.trim() != "in" {
user_error(ansi!("Try <bold>plug in<reset> something").to_owned())?;
}
let player_item = get_player_item_or_fail(ctx).await?;
if player_item.death_data.is_some() {
user_error("Plugging metal things in can make you dead, but being dead doesn't let you plug things in.".to_owned())?;
}
let remaining = remaining.trim();
let item = search_item_for_user(
ctx,
&ItemSearchParams {
limit: 1,
include_loc_contents: true,
item_type_only: Some("possession"),
..ItemSearchParams::base(&player_item, &remaining)
},
)
.await
.map_err(|e| match e {
CommandHandlingError::UserError(m) => CommandHandlingError::UserError(
m + " I only looked in the room - try dropping an item first.",
),
e => e,
})?;
let charge_data = match item
.possession_type
.as_ref()
.and_then(|pt| possession_data().get(pt))
.and_then(|pd| pd.charge_data.as_ref())
{
Some(v) if v.electric_recharge => v,
_ => user_error("You can't recharge that!".to_owned())?,
};
let (place_type, place_code) = player_item
.location
.split_once("/")
.ok_or_else(|| UserError("Bad location".to_owned()))?;
if !place_has_power(&ctx.trans, place_type, place_code).await? {
user_error("You can't find any power sockets to plug in to.".to_owned())?;
}
if item.charges >= charge_data.max_charges {
user_error("You realise it's already fully charged.".to_owned())?;
}
let refstr = item.refstr();
if ctx
.trans
.check_task_by_type_code("ChargeItem", &refstr)
.await?
{
user_error("It's already charging!".to_owned())?;
}
ctx.trans
.upsert_task(&Task {
meta: TaskMeta {
task_code: refstr.clone(),
next_scheduled: Utc::now() + Duration::minutes(1),
..Default::default()
},
details: TaskDetails::ChargeItem { item: refstr },
})
.await?;
broadcast_to_room(
&ctx.trans,
&player_item.location,
None,
&format!(
"{} plugs in {}.\n",
&player_item.display_for_sentence(1, true),
&item.display_for_sentence(1, false)
),
)
.await?;
Ok(())
}
}
static VERB_INT: Verb = Verb;
pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef;

View File

@ -155,6 +155,7 @@ pub struct ChargeData {
pub max_charges: u8,
pub charge_name_prefix: &'static str,
pub charge_name_suffix: &'static str,
pub electric_recharge: bool,
}
impl Default for ChargeData {
@ -163,6 +164,7 @@ impl Default for ChargeData {
max_charges: 1,
charge_name_prefix: "charge",
charge_name_suffix: "",
electric_recharge: false,
}
}
}

View File

@ -20,6 +20,7 @@ pub fn data() -> &'static Vec<(PossessionType, PossessionData)> {
max_charges: 20,
charge_name_prefix: "bite",
charge_name_suffix: "of food",
..Default::default()
}),
..Default::default()
}
@ -39,6 +40,7 @@ pub fn data() -> &'static Vec<(PossessionType, PossessionData)> {
max_charges: 20,
charge_name_prefix: "bite",
charge_name_suffix: "of food",
..Default::default()
}),
..Default::default()
}

View File

@ -175,6 +175,8 @@ pub fn data() -> &'static Vec<(PossessionType, PossessionData)> {
max_charges: 20,
charge_name_prefix: "bar",
charge_name_suffix: "of power",
electric_recharge: true,
..ChargeData::default()
}),
..Default::default()
})])

View File

@ -29,6 +29,7 @@ pub fn data() -> &'static Vec<(PossessionType, PossessionData)> {
max_charges: 20,
charge_name_prefix: "bite",
charge_name_suffix: "of food",
..Default::default()
}),
..Default::default()
}

View File

@ -15,6 +15,7 @@
y: 0
z: 0
description: "A sizeable lobby that looks like it is serves the dual purpose as the entrance to the residential condos and as a grand entrance to the linked Murlison Suites commercial building. It is tiled with sparkling clean bluestone tiles. Light green tinted tempered glass panels line the walls. You notice a set of sleek lifts, supervised by a friendly robot, and a passage to the attached Murlison commercial building to the east.\n\n\"Welcome to Condos on King!\", intones the bot, \"say <bold>in<reset> name\" with the name of the person you are here to see, and I'll guide you to their apartment. Or try <bold>rent studio<reset> to rent a studio apartment for $20 a day ($40 setup fee), and <bold>vacate studio<reset> to give notice to vacate"
has_power: true
exits:
- direction: west
target: !Custom room/melbs_kingst_80
@ -34,6 +35,7 @@
y: 0
z: 0
description: "A sleek reception that could have been the bridge of a 2000s era sci-fi spaceship. Linished metal plates are lit up by ambient blue LEDs, while stone tiles cover the floor. You see a white android, complete with elegant rounded corners and glowing blue eyes.\n\n\"Welcome to Murlison Suites - the best a business can rent\", purs the bot pleasantly. \"Just say <bold>in<reset> corpname\" and I'll guide you to the suite for that corp before you can blink! Or if you hold a corp and would like to rent the best suite money can buy for it, just say <bold>rent deluxe for<reset> corpname, and I'll set you up\""
has_power: true
exits:
- direction: west
rentable_dynzone: