Beginning of light mechanic implementation
This commit is contained in:
parent
760598e3a1
commit
28654a5130
@ -73,6 +73,12 @@ pub struct LocationStats {
|
||||
pub total_weight: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectRef {
|
||||
pub item_type: String,
|
||||
pub item_code: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(test, allow(dead_code))]
|
||||
impl DBPool {
|
||||
pub async fn record_listener_ping(self: &DBPool, listener: Uuid) -> DResult<()> {
|
||||
@ -401,6 +407,7 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[deny(dead_code)]
|
||||
pub async fn find_by_username<'a>(self: &'a Self, username: &'a str) -> DResult<Option<User>> {
|
||||
if let Some(details_json) = self
|
||||
.pg_trans()?
|
||||
@ -1906,6 +1913,68 @@ impl DBTrans {
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn is_illuminated(
|
||||
&self,
|
||||
player: &Item,
|
||||
location: &Item,
|
||||
consider_adjacent: &Vec<ObjectRef>,
|
||||
) -> DResult<bool> {
|
||||
if !location.flags.contains(&ItemFlag::DarkPlace) {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
let player_ref = player.refstr();
|
||||
let loc_ref = location.refstr();
|
||||
let adjacent_json = serde_json::to_value(consider_adjacent)?;
|
||||
Ok(self
|
||||
.pg_trans()?
|
||||
.query_one(
|
||||
&format!("WITH
|
||||
player_lights AS (
|
||||
SELECT 1 FROM items WHERE details->>'location' = $1 AND
|
||||
details->'flags' @> '\"{}\"'
|
||||
),
|
||||
location_direct_lights AS (
|
||||
SELECT 1 FROM items WHERE details->>'location' = $2 AND
|
||||
details->'flags' @> '\"IlluminatesRoom\"'
|
||||
),
|
||||
location_players AS (
|
||||
SELECT * FROM items WHERE details->>'location' = $2 AND details->>'item_type' = 'player'
|
||||
),
|
||||
location_player_lights AS (
|
||||
SELECT 1 FROM items i JOIN location_players p ON i.details->>'location' = CONCAT(p.details->>'item_type', '/', p.details->>'item_code') WHERE i.details->'flags' @> '\"IlluminatesRoom\"'
|
||||
),
|
||||
adjacent AS (
|
||||
SELECT value->>'item_type' AS item_type, value->>'item_code' AS item_code FROM jsonb_array_elements($3 :: JSONB)
|
||||
),
|
||||
adjacent_direct_lights AS (
|
||||
SELECT 1 FROM items i JOIN adjacent a ON i.details->>'item_type' = a.item_type AND i.details->>'item_code' = a.item_code
|
||||
WHERE i.details->'flags' @> '\"IlluminatesAdjacentRoom\"'
|
||||
),
|
||||
adjacent_players AS (
|
||||
SELECT i.* FROM items i JOIN adjacent a ON i.details->>'location' = CONCAT(a.item_type, '/', a.item_code)
|
||||
),
|
||||
adjacent_player_lights AS (
|
||||
SELECT 1 FROM items i JOIN adjacent_players p ON i.details->>'location' = CONCAT(p.details->>'item_type', '/', p.details->>'item_code')
|
||||
WHERE i.details->'flags' @> '\"IlluminatesAdjacentRoom\"'
|
||||
),
|
||||
relevant_lights AS (
|
||||
SELECT * FROM player_lights UNION ALL
|
||||
SELECT * FROM location_direct_lights UNION ALL
|
||||
SELECT * FROM location_player_lights UNION ALL
|
||||
SELECT * FROM adjacent_direct_lights UNION ALL
|
||||
SELECT * FROM adjacent_player_lights
|
||||
)
|
||||
SELECT EXISTS(SELECT 1 FROM relevant_lights);",
|
||||
if player.location == loc_ref { "IlluminatesRoomForPlayer" } else { "IlluminatesAdjacentRoomForPlayer"}
|
||||
),
|
||||
&[&player_ref,
|
||||
&loc_ref,
|
||||
&adjacent_json],
|
||||
)
|
||||
.await?.get(0))
|
||||
}
|
||||
|
||||
pub async fn commit(mut self: Self) -> DResult<()> {
|
||||
let trans_opt = self.with_trans_mut(|t| std::mem::replace(t, None));
|
||||
if let Some(trans) = trans_opt {
|
||||
|
@ -7,7 +7,7 @@ use super::{
|
||||
#[double]
|
||||
use crate::db::DBTrans;
|
||||
use crate::{
|
||||
db::ItemSearchParams,
|
||||
db::{ItemSearchParams, ObjectRef},
|
||||
language,
|
||||
models::{
|
||||
effect::EffectType,
|
||||
@ -376,8 +376,31 @@ fn exits_for_dyn(dynroom: &dynzone::Dynroom) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn is_room_illuminated(
|
||||
ctx: &VerbContext<'_>,
|
||||
player_item: &Item,
|
||||
location: &Item,
|
||||
room: &room::Room,
|
||||
) -> UResult<bool> {
|
||||
let consider_exits: Vec<ObjectRef> = room
|
||||
.exits
|
||||
.iter()
|
||||
.filter_map(|ex| room::resolve_exit(room, ex))
|
||||
// Do we want to consider skipping exits behind closed doors?
|
||||
.map(|r| ObjectRef {
|
||||
item_type: "room".to_owned(),
|
||||
item_code: r.code.to_owned(),
|
||||
})
|
||||
.collect();
|
||||
Ok(ctx
|
||||
.trans
|
||||
.is_illuminated(player_item, location, &consider_exits)
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn describe_room(
|
||||
ctx: &VerbContext<'_>,
|
||||
player_item: &Item,
|
||||
item: &Item,
|
||||
room: &room::Room,
|
||||
contents: &str,
|
||||
@ -386,10 +409,8 @@ pub async fn describe_room(
|
||||
.get(room.zone.as_str())
|
||||
.map(|z| z.display)
|
||||
.unwrap_or("Outside of time");
|
||||
ctx.trans
|
||||
.queue_for_session(
|
||||
ctx.session,
|
||||
Some(&flow_around(
|
||||
let illum = is_room_illuminated(ctx, player_item, item, room).await?;
|
||||
let desc = flow_around(
|
||||
&render_map(room, 5, 5),
|
||||
10,
|
||||
ansi!("<reset> "),
|
||||
@ -409,7 +430,15 @@ pub async fn describe_room(
|
||||
|row| if row >= 5 { 80 } else { 68 },
|
||||
),
|
||||
68,
|
||||
)),
|
||||
);
|
||||
ctx.trans
|
||||
.queue_for_session(
|
||||
ctx.session,
|
||||
Some(if illum {
|
||||
&desc
|
||||
} else {
|
||||
"It's too dark to see much.\n"
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
@ -768,7 +797,14 @@ impl UserVerb for Verb {
|
||||
let room = room::room_map_by_code()
|
||||
.get(item.item_code.as_str())
|
||||
.ok_or_else(|| UserError("Sorry, that room no longer exists".to_owned()))?;
|
||||
describe_room(ctx, &item, &room, &list_room_contents(ctx, &item).await?).await?;
|
||||
describe_room(
|
||||
ctx,
|
||||
&player_item,
|
||||
&item,
|
||||
&room,
|
||||
&list_room_contents(ctx, &item).await?,
|
||||
)
|
||||
.await?;
|
||||
} else if item.item_type == "dynroom" {
|
||||
let (dynzone, dynroom) = match &item.special_data {
|
||||
Some(ItemSpecialData::DynroomData {
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::{
|
||||
get_player_item_or_fail, user_error, UResult, UserError, UserVerb, UserVerbRef, VerbContext,
|
||||
get_player_item_or_fail, look::is_room_illuminated, user_error, UResult, UserError, UserVerb,
|
||||
UserVerbRef, VerbContext,
|
||||
};
|
||||
use crate::{
|
||||
models::item::{Item, ItemSpecialData},
|
||||
@ -541,6 +542,9 @@ impl UserVerb for Verb {
|
||||
let room = room::room_map_by_code()
|
||||
.get(room_item.item_code.as_str())
|
||||
.ok_or_else(|| UserError("Sorry, that room no longer exists".to_owned()))?;
|
||||
if !is_room_illuminated(ctx, &player_item, &room_item, room).await? {
|
||||
user_error("It's too dark here to make out the map.".to_owned())?;
|
||||
}
|
||||
map_type.map_room(ctx, &room).await?;
|
||||
} else if room_item.item_type == "dynroom" {
|
||||
let (dynzone, dynroom) = match &room_item.special_data {
|
||||
|
@ -325,6 +325,11 @@ pub enum ItemFlag {
|
||||
NoSeeContents,
|
||||
DroppedItemsDontExpire,
|
||||
PrivatePlace,
|
||||
DarkPlace,
|
||||
IlluminatesRoom,
|
||||
IlluminatesRoomForPlayer,
|
||||
IlluminatesAdjacentRoom,
|
||||
IlluminatesAdjacentRoomForPlayer,
|
||||
Hireable,
|
||||
NPCsDontAttack,
|
||||
CanLoad,
|
||||
|
@ -26,6 +26,7 @@ mod cok_murl;
|
||||
pub mod computer_museum;
|
||||
pub mod general_hospital;
|
||||
pub mod melbs;
|
||||
pub mod melbs_sewers;
|
||||
mod repro_xv;
|
||||
mod special;
|
||||
|
||||
@ -74,6 +75,11 @@ pub fn zone_details() -> &'static BTreeMap<&'static str, Zone> {
|
||||
display: "General Hospital",
|
||||
outdoors: false,
|
||||
},
|
||||
Zone {
|
||||
code: "melbs_sewers",
|
||||
display: "Melbs Sewers",
|
||||
outdoors: false,
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.map(|x| (x.code, x))
|
||||
@ -528,6 +534,7 @@ pub fn room_list() -> &'static Vec<Room> {
|
||||
rooms.append(&mut special::room_list());
|
||||
rooms.append(&mut computer_museum::room_list());
|
||||
rooms.append(&mut general_hospital::room_list());
|
||||
rooms.append(&mut melbs_sewers::room_list());
|
||||
rooms.into_iter().collect()
|
||||
})
|
||||
}
|
||||
@ -769,4 +776,21 @@ mod test {
|
||||
.collect::<Vec<String>>();
|
||||
assert_eq!(bad_scav_rooms, Vec::<String>::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exits_resolve() {
|
||||
let rl = room_list();
|
||||
let unresolved_exits: Vec<String> = rl
|
||||
.iter()
|
||||
.flat_map(|r: &'static Room| {
|
||||
let r2: &'static Room = r;
|
||||
r.exits.iter().map(move |ex| (r2, ex))
|
||||
})
|
||||
.filter_map(|(r, ex)| match resolve_exit(r, ex) {
|
||||
Some(_) => None,
|
||||
None => Some(format!("{} {}", r.code, &ex.direction.describe())),
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
assert_eq!(unresolved_exits, Vec::<String>::new());
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,6 @@
|
||||
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\""
|
||||
exits:
|
||||
- direction: west
|
||||
- direction: south
|
||||
rentable_dynzone:
|
||||
- rent_what: deluxe
|
||||
suite_type: Commercial
|
||||
|
@ -10,6 +10,8 @@
|
||||
exits:
|
||||
- direction: south
|
||||
- direction: east
|
||||
- direction: down
|
||||
target: !Custom room/melbs_sewers_1a
|
||||
should_caption: false
|
||||
scavtable: CityStreet
|
||||
- zone: melbs
|
||||
@ -808,7 +810,6 @@
|
||||
z: 0
|
||||
description: A road that looks to have been a major tram thoroughfare before the collapse. Cracks line the filthy concrete footpaths and rusted tram tracks, and weeds poke out from holes in the concrete
|
||||
exits:
|
||||
- direction: west
|
||||
- direction: south
|
||||
should_caption: false
|
||||
scavtable: CityStreet
|
||||
|
24
blastmud_game/src/static_content/room/melbs_sewers.rs
Normal file
24
blastmud_game/src/static_content/room/melbs_sewers.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use super::{Room, SimpleRoom};
|
||||
use crate::{
|
||||
models::item::Scavtype,
|
||||
static_content::{possession_type::PossessionType, scavtable::Scavinfo},
|
||||
};
|
||||
use serde_yaml::from_str as from_yaml_str;
|
||||
|
||||
pub fn sewer_scavtable() -> Vec<Scavinfo> {
|
||||
vec![Scavinfo {
|
||||
possession_type: PossessionType::RustySpike,
|
||||
p_present: 1.0,
|
||||
difficulty_mean: 7.0,
|
||||
difficulty_stdev: 1.0,
|
||||
scavtype: Scavtype::Scavenge,
|
||||
}]
|
||||
}
|
||||
|
||||
pub fn room_list() -> Vec<Room> {
|
||||
from_yaml_str::<Vec<SimpleRoom<()>>>(include_str!("melbs_sewers.yaml"))
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|r| r.into())
|
||||
.collect()
|
||||
}
|
16
blastmud_game/src/static_content/room/melbs_sewers.yaml
Normal file
16
blastmud_game/src/static_content/room/melbs_sewers.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
- zone: melbs_sewers
|
||||
code: melbs_sewers_1a
|
||||
name: Dank narrow sewerpipe
|
||||
short: <yellow>==<reset>
|
||||
grid_coords:
|
||||
x: 1
|
||||
y: -5
|
||||
z: -1
|
||||
description: A relatively narrow sewer pipe, featuring a ladder up to an access hole in a street. It smells like sewage in here. Foul smelling gloop, presumably sewage, flows along the bottom of the pipe. This sewer is a veritable ecosystem of its own; every now and then, you feel something living brush against you
|
||||
exits:
|
||||
- direction: up
|
||||
target: !Custom room/melbs_kingst_latrobest
|
||||
should_caption: false
|
||||
scavtable: CitySewer
|
||||
item_flags:
|
||||
- !DarkPlace
|
@ -1,4 +1,4 @@
|
||||
use crate::models::item::Scavtype;
|
||||
use crate::{models::item::Scavtype, static_content::room::melbs_sewers::sewer_scavtable};
|
||||
|
||||
use super::{possession_type::PossessionType, room::melbs::street_scavtable};
|
||||
use std::collections::BTreeMap;
|
||||
@ -18,6 +18,7 @@ pub struct Scavinfo {
|
||||
pub enum ScavtableType {
|
||||
Nothing,
|
||||
CityStreet,
|
||||
CitySewer,
|
||||
}
|
||||
|
||||
pub fn scavtable_map() -> &'static BTreeMap<ScavtableType, Vec<Scavinfo>> {
|
||||
@ -26,6 +27,7 @@ pub fn scavtable_map() -> &'static BTreeMap<ScavtableType, Vec<Scavinfo>> {
|
||||
vec![
|
||||
(ScavtableType::Nothing, vec![]),
|
||||
(ScavtableType::CityStreet, street_scavtable()),
|
||||
(ScavtableType::CitySewer, sewer_scavtable()),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
|
Loading…
Reference in New Issue
Block a user