Split most room data to YAML for faster compile times.

This commit is contained in:
Condorra 2023-10-08 16:34:55 +11:00
parent 925deba57e
commit 807a9612fd
34 changed files with 3219 additions and 4679 deletions

10
Cargo.lock generated
View File

@ -80,17 +80,26 @@ name = "ansi"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ansi_macro", "ansi_macro",
"nom",
] ]
[[package]] [[package]]
name = "ansi_macro" name = "ansi_macro"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ansi_markup",
"nom", "nom",
"quote", "quote",
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "ansi_markup"
version = "0.1.0"
dependencies = [
"nom",
]
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.7.4" version = "0.7.4"
@ -221,6 +230,7 @@ name = "blastmud_game"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ansi", "ansi",
"ansi_markup",
"async-recursion", "async-recursion",
"async-trait", "async-trait",
"base64 0.20.0", "base64 0.20.0",

View File

@ -4,6 +4,7 @@ members = [
"blastmud_listener", "blastmud_listener",
"blastmud_interfaces", "blastmud_interfaces",
"blastmud_game", "blastmud_game",
"ansi_markup",
"ansi_macro", "ansi_macro",
"ansi", "ansi",
] ]

View File

@ -5,3 +5,4 @@ edition = "2021"
[dependencies] [dependencies]
ansi_macro = { path = "../ansi_macro" } ansi_macro = { path = "../ansi_macro" }
nom = "7.1.1"

View File

@ -10,3 +10,4 @@ proc-macro = true
nom = "7.1.1" nom = "7.1.1"
quote = "1.0.23" quote = "1.0.23"
syn = "1.0.107" syn = "1.0.107"
ansi_markup = { path = "../ansi_markup" }

View File

@ -1,72 +1,16 @@
use nom::{ use ansi_markup::parse_ansi_markup;
branch::alt,
bytes::complete::{tag, take_till, take_till1},
combinator::eof,
error::Error,
multi::fold_many0,
sequence::{pair, tuple},
Err, Parser,
};
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::ToTokens; use quote::ToTokens;
use syn::{parse_macro_input, Lit}; use syn::{parse_macro_input, Lit};
enum AnsiFrag<'l> {
Lit(&'l str),
Special(&'l str),
}
use AnsiFrag::Special;
#[proc_macro] #[proc_macro]
pub fn ansi(input: TokenStream) -> TokenStream { pub fn ansi(input: TokenStream) -> TokenStream {
let raw = match parse_macro_input!(input as Lit) { let raw = match parse_macro_input!(input as Lit) {
Lit::Str(lit_str) => lit_str.value(), Lit::Str(lit_str) => lit_str.value(),
_ => panic!("Expected a string literal"), _ => panic!("Expected a string literal"),
}; };
fn parser(i: &str) -> Result<String, Err<Error<&str>>> {
pair(
fold_many0(
alt((
take_till1(|c| c == '<').map(AnsiFrag::Lit),
tuple((tag("<"), take_till(|c| c == '>'), tag(">")))
.map(|t| AnsiFrag::Special(t.1)),
)),
|| "".to_owned(),
|a, r| {
a + match r {
AnsiFrag::Lit(s) => &s,
Special(s) if s == "reset" => "\x1b[0m",
Special(s) if s == "bold" => "\x1b[1m",
Special(s) if s == "under" => "\x1b[4m",
Special(s) if s == "strike" => "\x1b[9m",
Special(s) if s == "nounder" => "\x1b[24m",
Special(s) if s == "black" => "\x1b[30m",
Special(s) if s == "red" => "\x1b[31m",
Special(s) if s == "green" => "\x1b[32m",
Special(s) if s == "yellow" => "\x1b[33m",
Special(s) if s == "blue" => "\x1b[34m",
Special(s) if s == "magenta" => "\x1b[35m",
Special(s) if s == "cyan" => "\x1b[36m",
Special(s) if s == "white" => "\x1b[37m",
Special(s) if s == "bgblack" => "\x1b[40m",
Special(s) if s == "bgred" => "\x1b[41m",
Special(s) if s == "bggreen" => "\x1b[42m",
Special(s) if s == "bgyellow" => "\x1b[43m",
Special(s) if s == "bgblue" => "\x1b[44m",
Special(s) if s == "bgmagenta" => "\x1b[45m",
Special(s) if s == "bgcyan" => "\x1b[46m",
Special(s) if s == "bgwhite" => "\x1b[47m",
Special(s) if s == "lt" => "<",
Special(r) => panic!("Unknown ansi type {}", r),
}
},
),
eof,
)(i)
.map(|(_, (r, _))| r)
}
TokenStream::from( TokenStream::from(
parser(&raw) parse_ansi_markup(&raw)
.unwrap_or_else(|e| panic!("Bad ansi literal: {}", e)) .unwrap_or_else(|e| panic!("Bad ansi literal: {}", e))
.into_token_stream(), .into_token_stream(),
) )

7
ansi_markup/Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[package]
name = "ansi_markup"
version = "0.1.0"
edition = "2021"
[dependencies]
nom = "7.1.1"

62
ansi_markup/src/lib.rs Normal file
View File

@ -0,0 +1,62 @@
use nom::{
branch::alt,
bytes::complete::{tag, take_till, take_till1},
combinator::eof,
error::Error,
multi::fold_many0,
sequence::{pair, tuple},
Err, Parser,
};
enum AnsiFrag<'l> {
Lit(&'l str),
Special(&'l str),
}
use AnsiFrag::Special;
pub fn parse_ansi_markup(i: &str) -> Result<String, Err<Error<&str>>> {
pair(
fold_many0(
alt((
take_till1(|c| c == '<').map(AnsiFrag::Lit),
tuple((tag("<"), take_till(|c| c == '>'), tag(">")))
.map(|t| AnsiFrag::Special(t.1)),
)),
|| "".to_owned(),
|a, r| {
a + match r {
AnsiFrag::Lit(s) => &s,
Special(s) if s == "reset" => "\x1b[0m",
Special(s) if s == "bold" => "\x1b[1m",
Special(s) if s == "under" => "\x1b[4m",
Special(s) if s == "strike" => "\x1b[9m",
Special(s) if s == "nounder" => "\x1b[24m",
Special(s) if s == "black" => "\x1b[30m",
Special(s) if s == "red" => "\x1b[31m",
Special(s) if s == "green" => "\x1b[32m",
Special(s) if s == "yellow" => "\x1b[33m",
Special(s) if s == "blue" => "\x1b[34m",
Special(s) if s == "magenta" => "\x1b[35m",
Special(s) if s == "cyan" => "\x1b[36m",
Special(s) if s == "white" => "\x1b[37m",
Special(s) if s == "bgblack" => "\x1b[40m",
Special(s) if s == "bgred" => "\x1b[41m",
Special(s) if s == "bggreen" => "\x1b[42m",
Special(s) if s == "bgyellow" => "\x1b[43m",
Special(s) if s == "bgblue" => "\x1b[44m",
Special(s) if s == "bgmagenta" => "\x1b[45m",
Special(s) if s == "bgcyan" => "\x1b[46m",
Special(s) if s == "bgwhite" => "\x1b[47m",
Special(s) if s == "lt" => "<",
Special(r) => panic!("Unknown ansi type {}", r),
}
},
),
eof,
)(i)
.map(|(_, (r, _))| r)
}
pub fn parse_ansi_markup_escape(i: &str) -> Result<String, Err<Error<&str>>> {
parse_ansi_markup(i).map(|o| o.replace('\x1b', "\\e"))
}

View File

@ -9,6 +9,7 @@ edition = "2021"
base64 = "0.20.0" base64 = "0.20.0"
blastmud_interfaces = { path = "../blastmud_interfaces" } blastmud_interfaces = { path = "../blastmud_interfaces" }
ansi = { path = "../ansi" } ansi = { path = "../ansi" }
ansi_markup = { path = "../ansi_markup" }
deadpool = "0.9.5" deadpool = "0.9.5"
deadpool-postgres = { version = "0.10.3", features = ["serde"] } deadpool-postgres = { version = "0.10.3", features = ["serde"] }
futures = "0.3.25" futures = "0.3.25"
@ -44,3 +45,11 @@ mockall_double = "0.3.0"
[dev-dependencies] [dev-dependencies]
tokio-test = "0.4.2" tokio-test = "0.4.2"
[features]
default = []
# Export data to YAML files in /tmp on startup
yamldump = []
[profile.dev]
lto = false

View File

@ -7,6 +7,9 @@ use std::error::Error;
use std::fs; use std::fs;
use tokio::signal::unix::{signal, SignalKind}; use tokio::signal::unix::{signal, SignalKind};
#[cfg(feature = "yamldump")]
use static_content::dumper::dump_static_content;
mod av; mod av;
mod db; mod db;
mod language; mod language;
@ -44,6 +47,10 @@ async fn main() -> DResult<()> {
error!("Couldn't verify age-verification.yml - this is not a complete game. Check README.md: {}", e); error!("Couldn't verify age-verification.yml - this is not a complete game. Check README.md: {}", e);
Err(e) Err(e)
})?; })?;
#[cfg(feature = "yamldump")]
dump_static_content()?;
let config = read_latest_config()?; let config = read_latest_config()?;
let pool = DBPool::start(&config.database_conn_string)?; let pool = DBPool::start(&config.database_conn_string)?;

View File

@ -407,7 +407,7 @@ pub async fn describe_room(
contents: &str, contents: &str,
) -> UResult<()> { ) -> UResult<()> {
let zone = room::zone_details() let zone = room::zone_details()
.get(room.zone) .get(room.zone.as_str())
.map(|z| z.display) .map(|z| z.display)
.unwrap_or("Outside of time"); .unwrap_or("Outside of time");
ctx.trans ctx.trans
@ -694,7 +694,7 @@ pub async fn direction_to_item(
.ok_or_else(|| UserError("There is nothing in that direction".to_owned()))?; .ok_or_else(|| UserError("There is nothing in that direction".to_owned()))?;
let new_room = room::resolve_exit(room, exit) let new_room = room::resolve_exit(room, exit)
.ok_or_else(|| UserError("Can't find that room".to_owned()))?; .ok_or_else(|| UserError("Can't find that room".to_owned()))?;
Ok(trans.find_item_by_type_code("room", new_room.code).await?) Ok(trans.find_item_by_type_code("room", &new_room.code).await?)
} }
pub struct Verb; pub struct Verb;

View File

@ -25,16 +25,16 @@ pub fn render_map(room: &room::Room, width: usize, height: usize) -> String {
buf.push_str(ansi!("<bgblue><red>()<reset>")) buf.push_str(ansi!("<bgblue><red>()<reset>"))
} else { } else {
buf.push_str( buf.push_str(
room::room_map_by_zloc() &room::room_map_by_zloc()
.get(&(&room.zone, &room::GridCoords { x, y, z: my_loc.z })) .get(&(&room.zone, &room::GridCoords { x, y, z: my_loc.z }))
.map(|r| { .map(|r| {
if room.zone == r.zone { if room.zone == r.zone {
r.short r.short.as_str()
} else { } else {
r.secondary_zones r.secondary_zones
.iter() .iter()
.find(|sz| sz.zone == room.zone) .find(|sz| sz.zone == room.zone)
.map(|sz| sz.short) .map(|sz| sz.short.as_str())
.expect("Secondary zone missing") .expect("Secondary zone missing")
} }
}) })
@ -129,10 +129,10 @@ pub fn render_lmap(
let code_capt_opt = coord_room.map(|r| { let code_capt_opt = coord_room.map(|r| {
if room.zone == r.zone { if room.zone == r.zone {
( (
r.short, r.short.as_str(),
if r.should_caption { if r.should_caption {
Some(( Some((
r.name, r.name.as_str(),
((my_loc.x as i64 - r.grid_coords.x).abs() ((my_loc.x as i64 - r.grid_coords.x).abs()
+ (my_loc.y as i64 - r.grid_coords.y).abs()) + (my_loc.y as i64 - r.grid_coords.y).abs())
as usize, as usize,
@ -147,10 +147,10 @@ pub fn render_lmap(
.find(|sz| sz.zone == room.zone) .find(|sz| sz.zone == room.zone)
.map(|sz| { .map(|sz| {
( (
sz.short, sz.short.as_str(),
sz.caption.map(|c| { sz.caption.as_ref().map(|c| {
( (
c, c.as_str(),
((my_loc.x as i64 - r.grid_coords.x).abs() ((my_loc.x as i64 - r.grid_coords.x).abs()
+ (my_loc.y as i64 - r.grid_coords.y).abs()) + (my_loc.y as i64 - r.grid_coords.y).abs())
as usize, as usize,
@ -165,10 +165,10 @@ pub fn render_lmap(
None => buf.push_str(" "), None => buf.push_str(" "),
Some((code, capt_opt)) => { Some((code, capt_opt)) => {
if let Some((capt, closeness)) = capt_opt { if let Some((capt, closeness)) = capt_opt {
captions_needed.push((closeness, code, capt)); captions_needed.push((closeness, &code, &capt));
} }
buf.push('['); buf.push('[');
buf.push_str(code); buf.push_str(&code);
buf.push(']'); buf.push(']');
} }
} }

View File

@ -301,7 +301,7 @@ pub async fn handle_fall(trans: &DBTrans, faller: &mut Item, fall_dist: u64) ->
MaterialType::WaterSurface | MaterialType::Underwater => { MaterialType::WaterSurface | MaterialType::Underwater => {
return Ok("lands with a splash".to_owned()); return Ok("lands with a splash".to_owned());
} }
MaterialType::Soft { damage_modifier } => damage_modifier, MaterialType::Soft { damage_modifier } => damage_modifier as f64 / 100.0,
MaterialType::Normal => 1.0, MaterialType::Normal => 1.0,
}, },
}, },

View File

@ -329,7 +329,7 @@ impl UserVerb for Verb {
"Rent must be followed by the specific thing you want to rent: {}", "Rent must be followed by the specific thing you want to rent: {}",
room.rentable_dynzone room.rentable_dynzone
.iter() .iter()
.map(|ri| ri.rent_what) .map(|ri| ri.rent_what.as_str())
.join(", ") .join(", ")
))?, ))?,
Some(v) => v, Some(v) => v,

View File

@ -53,7 +53,7 @@ impl UserVerb for Verb {
"Vacate must be followed by the specific thing you want to vacate: {}", "Vacate must be followed by the specific thing you want to vacate: {}",
room.rentable_dynzone room.rentable_dynzone
.iter() .iter()
.map(|ri| ri.rent_what) .map(|ri| ri.rent_what.as_str())
.join(", ") .join(", ")
))?, ))?,
Some(v) => v, Some(v) => v,

View File

@ -8,7 +8,9 @@ use crate::{
}, },
regular_tasks::{TaskHandler, TaskRunContext}, regular_tasks::{TaskHandler, TaskRunContext},
services::Item, services::Item,
static_content::{possession_type::PossessionType, room::room_list, StaticTask}, static_content::{
possession_type::PossessionType, room::room_list, scavtable::scavtable_map, StaticTask,
},
DResult, DResult,
}; };
use async_recursion::async_recursion; use async_recursion::async_recursion;
@ -172,8 +174,12 @@ pub async fn refresh_all_spawn_points(trans: &DBTrans) -> DResult<()> {
// Also all scav spawns... // Also all scav spawns...
trans.clean_scavhidden().await?; trans.clean_scavhidden().await?;
let empty_vec = vec![];
for room in room_list().iter() { for room in room_list().iter() {
for scav in &room.scavtable { for scav in scavtable_map()
.get(&room.scavtable)
.unwrap_or_else(|| &empty_vec)
{
if thread_rng().gen_bool(scav.p_present) { if thread_rng().gen_bool(scav.p_present) {
let difflevel = { let difflevel = {
let mut rng = thread_rng(); let mut rng = thread_rng();

View File

@ -8,12 +8,15 @@ use log::info;
use room::refresh_room_exits; use room::refresh_room_exits;
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
#[cfg(feature = "yamldump")]
pub mod dumper;
pub mod dynzone; pub mod dynzone;
pub mod fixed_item; pub mod fixed_item;
pub mod journals; pub mod journals;
pub mod npc; pub mod npc;
pub mod possession_type; pub mod possession_type;
pub mod room; pub mod room;
pub mod scavtable;
pub mod species; pub mod species;
pub struct StaticItem { pub struct StaticItem {

View File

@ -0,0 +1,64 @@
use crate::DResult;
use super::room::{room_list, Exit, ExitType, Room, SimpleExit, SimpleRoom};
use serde_yaml::to_writer;
use std::fs::File;
fn exit_to_simple_exit(exit: &Exit) -> Option<SimpleExit> {
match exit.exit_type {
ExitType::Free => {}
_ => return None,
}
Some(SimpleExit {
direction: exit.direction.clone(),
target: exit.target.clone(),
exit_climb: exit.exit_climb.clone(),
})
}
fn room_to_simpleroom(room: &Room) -> Option<SimpleRoom<()>> {
if room.enter_trigger.is_some() {
return None;
}
let mut simple_exits = vec![];
for ex in &room.exits {
match exit_to_simple_exit(&ex) {
None => return None,
Some(simp_ex) => simple_exits.push(simp_ex),
}
}
Some(SimpleRoom {
zone: room.zone.clone(),
secondary_zones: room.secondary_zones.clone(),
code: room.code.clone(),
name: room.name.clone(),
short: room.short.clone(),
grid_coords: room.grid_coords.clone(),
description: room.description.clone(),
description_less_explicit: room.description_less_explicit.clone(),
exits: simple_exits,
should_caption: room.should_caption.clone(),
repel_npc: room.repel_npc.clone(),
item_flags: room.item_flags.clone(),
stock_list: room.stock_list.clone(),
rentable_dynzone: room.rentable_dynzone.clone(),
material_type: room.material_type.clone(),
has_power: room.has_power.clone(),
door_states: room.door_states.clone(),
wristpad_hack_allowed: room.wristpad_hack_allowed.clone(),
journal: room.journal.clone(),
scavtable: room.scavtable.clone(),
extra: (),
})
}
pub fn dump_static_content() -> DResult<()> {
let rooms: Vec<SimpleRoom<()>> = room_list()
.iter()
.filter_map(|r| room_to_simpleroom(r))
.collect();
let mut file = File::create("/tmp/rooms.yaml")?;
to_writer(&mut file, &rooms)?;
Ok(())
}

View File

@ -11,12 +11,13 @@ use crate::{
}; };
use mockall_double::double; use mockall_double::double;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;
mod cokmurl_apartment; mod cokmurl_apartment;
mod murl_deluxe_corporate; mod murl_deluxe_corporate;
#[derive(Eq, Clone, PartialEq, Ord, PartialOrd, Debug)] #[derive(Eq, Clone, PartialEq, Ord, PartialOrd, Debug, Serialize, Deserialize)]
pub enum DynzoneType { pub enum DynzoneType {
CokMurlApartment, CokMurlApartment,
MurlDeluxeCorporate, MurlDeluxeCorporate,

View File

@ -6,27 +6,29 @@ use crate::{
}; };
use ansi::ansi; use ansi::ansi;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;
#[derive(Serialize, Deserialize)]
pub struct FixedItem { pub struct FixedItem {
pub code: &'static str, pub code: String,
pub name: &'static str, pub name: String,
pub description: &'static str, pub description: String,
pub description_less_explicit: Option<&'static str>, pub description_less_explicit: Option<String>,
pub location: &'static str, pub location: String,
pub proper_noun: bool, pub proper_noun: bool,
pub aliases: Vec<&'static str>, pub aliases: Vec<String>,
pub action_type: LocationActionType, pub action_type: LocationActionType,
} }
impl Default for FixedItem { impl Default for FixedItem {
fn default() -> Self { fn default() -> Self {
Self { Self {
code: "default", code: "default".to_owned(),
name: "default", name: "default".to_owned(),
description: "A thingy", description: "A thingy".to_owned(),
description_less_explicit: None, description_less_explicit: None,
location: "unset", location: "unset".to_owned(),
proper_noun: true, proper_noun: true,
aliases: vec![], aliases: vec![],
action_type: LocationActionType::Normal, action_type: LocationActionType::Normal,
@ -39,8 +41,8 @@ fn fixed_item_list() -> &'static Vec<FixedItem> {
FIXED_ITEM_LIST.get_or_init(|| { FIXED_ITEM_LIST.get_or_init(|| {
vec![ vec![
FixedItem { FixedItem {
code: "repro_xv_updates_red_poster", code: "repro_xv_updates_red_poster".to_owned(),
name: ansi!("red poster"), name: ansi!("red poster").to_owned(),
description: "A larger faded poster with a thick red border. It says:\n\ description: "A larger faded poster with a thick red border. It says:\n\
\t\"Dear newly memory wiped citizen! Welcome to Melbs! A lot \ \t\"Dear newly memory wiped citizen! Welcome to Melbs! A lot \
has changed since the memories your implant is based on were \ has changed since the memories your implant is based on were \
@ -52,27 +54,27 @@ fn fixed_item_list() -> &'static Vec<FixedItem> {
Melbs as the King. I have gotten all the fallout out from the inner city, \ Melbs as the King. I have gotten all the fallout out from the inner city, \
and I have a robot police force to keep you safe from the worst baddies, \ and I have a robot police force to keep you safe from the worst baddies, \
but be warned - there still are some dangers near by, and the world \ but be warned - there still are some dangers near by, and the world \
further out, outside my realm, is a dangerous and radioactive place.\"", further out, outside my realm, is a dangerous and radioactive place.\"".to_owned(),
description_less_explicit: None, description_less_explicit: None,
location: "room/repro_xv_updates", location: "room/repro_xv_updates".to_owned(),
proper_noun: false, proper_noun: false,
aliases: vec!["poster"], aliases: vec!["poster".to_owned()],
..Default::default() ..Default::default()
}, },
FixedItem { FixedItem {
code: "melbs_king_st_spring_fed_fountain", code: "melbs_king_st_spring_fed_fountain".to_owned(),
name: "spring fed fountain", name: "spring fed fountain".to_owned(),
description: ansi!("A stainless steel fountain, clearly old, but in surprisingly good \ description: ansi!("A stainless steel fountain, clearly old, but in surprisingly good \
condition. A discoloured bronze plaque attached to it proudly declares \ condition. A discoloured bronze plaque attached to it proudly declares \
that it is fed by a natural spring underneath it. It was designed so that \ that it is fed by a natural spring underneath it. It was designed so that \
unused water runs off it into a dog bowl - presumably in a time long past when \ unused water runs off it into a dog bowl - presumably in a time long past when \
dogs were friendly companions and not the menace they are today. It smells \ dogs were friendly companions and not the menace they are today. It smells \
faintly of iron. [Try <bold>drink from fountain<reset> or, if you have a suitable \ faintly of iron. [Try <bold>drink from fountain<reset> or, if you have a suitable \
container, <bold>fill<reset> container <bold>from fountain<reset>]."), container, <bold>fill<reset> container <bold>from fountain<reset>].").to_owned(),
description_less_explicit: None, description_less_explicit: None,
location: "room/melbs_kingst_40", location: "room/melbs_kingst_40".to_owned(),
proper_noun: false, proper_noun: false,
aliases: vec!["fountain"], aliases: vec!["fountain".to_owned()],
..Default::default() ..Default::default()
}, },
].into_iter().chain(computer_museum::fixed_items().into_iter()).collect() ].into_iter().chain(computer_museum::fixed_items().into_iter()).collect()
@ -101,16 +103,16 @@ pub fn fixed_item_properties() -> &'static BTreeMap<&'static str, PossessionData
pub fn static_items() -> Box<dyn Iterator<Item = StaticItem>> { pub fn static_items() -> Box<dyn Iterator<Item = StaticItem>> {
Box::new(fixed_item_list().iter().map(|r| StaticItem { Box::new(fixed_item_list().iter().map(|r| StaticItem {
item_code: r.code, item_code: &r.code,
initial_item: Box::new(|| Item { initial_item: Box::new(|| Item {
item_code: r.code.to_owned(), item_code: r.code.clone(),
item_type: "fixed_item".to_owned(), item_type: "fixed_item".to_owned(),
display: r.name.to_owned(), display: r.name.clone(),
details: Some(r.description.to_owned()), details: Some(r.description.clone()),
details_less_explicit: r.description_less_explicit.map(|d| d.to_owned()), details_less_explicit: r.description_less_explicit.as_ref().map(|d| d.clone()),
location: r.location.to_owned(), location: r.location.clone(),
is_static: true, is_static: true,
aliases: r.aliases.iter().map(|s| (*s).to_owned()).collect(), aliases: r.aliases.iter().map(|s| (*s).clone()).collect(),
pronouns: Pronouns { pronouns: Pronouns {
is_proper: r.proper_noun, is_proper: r.proper_noun,
..Pronouns::default_inanimate() ..Pronouns::default_inanimate()

View File

@ -462,7 +462,9 @@ impl TaskHandler for NPCWanderTaskHandler {
} }
let ex_iter = room.exits.iter().filter(|ex| { let ex_iter = room.exits.iter().filter(|ex| {
resolve_exit(room, ex) resolve_exit(room, ex)
.map(|new_room| npc.wander_zones.contains(&new_room.zone) && !new_room.repel_npc) .map(|new_room| {
npc.wander_zones.contains(&new_room.zone.as_str()) && !new_room.repel_npc
})
.unwrap_or(false) .unwrap_or(false)
}); });
let dir_opt = ex_iter let dir_opt = ex_iter

View File

@ -1,16 +1,20 @@
use super::{journals::award_journal_if_needed, possession_type::PossessionType, StaticItem}; use super::{
journals::award_journal_if_needed, possession_type::PossessionType, scavtable::ScavtableType,
StaticItem,
};
#[double] #[double]
use crate::db::DBTrans; use crate::db::DBTrans;
use crate::{ use crate::{
message_handler::user_commands::UResult, message_handler::user_commands::UResult,
models::{ models::{
item::{DoorState, Item, ItemFlag, Scavtype}, item::{DoorState, Item, ItemFlag},
journal::JournalType, journal::JournalType,
user::WristpadHack, user::WristpadHack,
}, },
regular_tasks::queued_command::QueuedCommandContext, regular_tasks::queued_command::QueuedCommandContext,
DResult, DResult,
}; };
use ansi_markup::parse_ansi_markup;
use async_trait::async_trait; use async_trait::async_trait;
use mockall_double::double; use mockall_double::double;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
@ -21,7 +25,7 @@ mod chonkers;
mod cok_murl; mod cok_murl;
pub mod computer_museum; pub mod computer_museum;
pub mod general_hospital; pub mod general_hospital;
mod melbs; pub mod melbs;
mod repro_xv; mod repro_xv;
mod special; mod special;
@ -77,7 +81,7 @@ pub fn zone_details() -> &'static BTreeMap<&'static str, Zone> {
}) })
} }
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)] #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug, Serialize, Deserialize)]
pub struct GridCoords { pub struct GridCoords {
pub x: i64, pub x: i64,
pub y: i64, pub y: i64,
@ -256,12 +260,13 @@ impl Direction {
} }
} }
#[derive(Eq, Ord, Debug, PartialEq, PartialOrd, Clone)] #[derive(Eq, Ord, Debug, PartialEq, PartialOrd, Clone, Serialize, Deserialize)]
pub enum ExitTarget { pub enum ExitTarget {
UseGPS, UseGPS,
Custom(&'static str), Custom(String),
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct ExitClimb { pub struct ExitClimb {
// Negative if it is down. // Negative if it is down.
pub height: i64, pub height: i64,
@ -286,13 +291,44 @@ impl Default for Exit {
} }
} }
pub struct SecondaryZoneRecord { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub zone: &'static str, #[serde(default)]
pub short: &'static str, pub struct SimpleExit {
pub grid_coords: GridCoords, pub direction: Direction,
pub caption: Option<&'static str>, pub target: ExitTarget,
pub exit_climb: Option<ExitClimb>,
} }
impl Default for SimpleExit {
fn default() -> Self {
Self {
direction: Direction::NORTH,
target: ExitTarget::UseGPS,
exit_climb: None,
}
}
}
impl Into<Exit> for SimpleExit {
fn into(self: SimpleExit) -> Exit {
Exit {
direction: self.direction,
target: self.target,
exit_type: ExitType::Free,
exit_climb: self.exit_climb,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct SecondaryZoneRecord {
pub zone: String,
pub short: String,
pub grid_coords: GridCoords,
pub caption: Option<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct RoomStock { pub struct RoomStock {
pub possession_type: PossessionType, pub possession_type: PossessionType,
pub list_price: u64, pub list_price: u64,
@ -309,13 +345,15 @@ impl Default for RoomStock {
} }
} }
#[derive(Serialize, Deserialize, Clone)]
pub enum RentSuiteType { pub enum RentSuiteType {
Residential, Residential,
Commercial, Commercial,
} }
#[derive(Serialize, Deserialize, Clone)]
pub struct RentInfo { pub struct RentInfo {
pub rent_what: &'static str, pub rent_what: String,
pub suite_type: RentSuiteType, pub suite_type: RentSuiteType,
pub dynzone: super::dynzone::DynzoneType, pub dynzone: super::dynzone::DynzoneType,
pub daily_price: u64, pub daily_price: u64,
@ -323,11 +361,12 @@ pub struct RentInfo {
} }
#[allow(unused)] #[allow(unused)]
#[derive(Serialize, Deserialize, Clone)]
pub enum MaterialType { pub enum MaterialType {
Normal, Normal,
WaterSurface, WaterSurface,
Underwater, Underwater,
Soft { damage_modifier: f64 }, Soft { damage_modifier: u64 },
} }
#[async_trait] #[async_trait]
@ -335,24 +374,16 @@ pub trait RoomEnterTrigger {
async fn handle_enter(self: &Self, ctx: &mut QueuedCommandContext, room: &Room) -> UResult<()>; async fn handle_enter(self: &Self, ctx: &mut QueuedCommandContext, room: &Room) -> UResult<()>;
} }
pub struct Scavinfo {
pub possession_type: PossessionType,
pub p_present: f64, // probability it is there.
pub difficulty_mean: f64,
pub difficulty_stdev: f64,
pub scavtype: Scavtype,
}
pub struct Room { pub struct Room {
pub zone: &'static str, pub zone: String,
// Other zones where it can be seen on the map and accessed. // Other zones where it can be seen on the map and accessed.
pub secondary_zones: Vec<SecondaryZoneRecord>, pub secondary_zones: Vec<SecondaryZoneRecord>,
pub code: &'static str, pub code: String,
pub name: &'static str, pub name: String,
pub short: &'static str, pub short: String,
pub grid_coords: GridCoords, pub grid_coords: GridCoords,
pub description: &'static str, pub description: String,
pub description_less_explicit: Option<&'static str>, pub description_less_explicit: Option<String>,
pub exits: Vec<Exit>, pub exits: Vec<Exit>,
pub should_caption: bool, pub should_caption: bool,
pub repel_npc: bool, pub repel_npc: bool,
@ -367,19 +398,19 @@ pub struct Room {
pub wristpad_hack_allowed: Option<WristpadHack>, pub wristpad_hack_allowed: Option<WristpadHack>,
pub journal: Option<JournalType>, pub journal: Option<JournalType>,
pub enter_trigger: Option<&'static (dyn RoomEnterTrigger + Sync + Send)>, pub enter_trigger: Option<&'static (dyn RoomEnterTrigger + Sync + Send)>,
pub scavtable: Vec<Scavinfo>, pub scavtable: ScavtableType,
} }
impl Default for Room { impl Default for Room {
fn default() -> Self { fn default() -> Self {
Self { Self {
zone: "default", zone: "default".to_owned(),
secondary_zones: vec![], secondary_zones: vec![],
code: "default", code: "default".to_owned(),
name: "default", name: "default".to_owned(),
short: "DF", short: "DF".to_owned(),
grid_coords: GridCoords { x: 0, y: 0, z: 0 }, grid_coords: GridCoords { x: 0, y: 0, z: 0 },
description: "default", description: "default".to_owned(),
description_less_explicit: None, description_less_explicit: None,
exits: vec![], exits: vec![],
should_caption: true, should_caption: true,
@ -393,7 +424,101 @@ impl Default for Room {
wristpad_hack_allowed: None, wristpad_hack_allowed: None,
journal: None, journal: None,
enter_trigger: None, enter_trigger: None,
scavtable: vec![], scavtable: ScavtableType::Nothing,
}
}
}
#[derive(Serialize, Deserialize)]
#[serde(default)]
pub struct SimpleRoom<T> {
pub zone: String,
// Other zones where it can be seen on the map and accessed.
pub secondary_zones: Vec<SecondaryZoneRecord>,
pub code: String,
pub name: String,
pub short: String,
pub grid_coords: GridCoords,
pub description: String,
pub description_less_explicit: Option<String>,
pub exits: Vec<SimpleExit>,
pub should_caption: bool,
pub repel_npc: bool,
pub item_flags: Vec<ItemFlag>,
// Empty means not a shop.
pub stock_list: Vec<RoomStock>,
// What can be rented here...
pub rentable_dynzone: Vec<RentInfo>,
pub material_type: MaterialType,
pub has_power: bool,
pub door_states: Option<BTreeMap<Direction, DoorState>>,
pub wristpad_hack_allowed: Option<WristpadHack>,
pub journal: Option<JournalType>,
pub scavtable: ScavtableType,
pub extra: T,
}
impl<T> Into<Room> for SimpleRoom<T> {
fn into(self: SimpleRoom<T>) -> Room {
Room {
zone: parse_ansi_markup(&self.zone).unwrap(),
secondary_zones: self
.secondary_zones
.into_iter()
.map(|sz| SecondaryZoneRecord {
zone: sz.zone,
short: parse_ansi_markup(&sz.short).unwrap(),
grid_coords: sz.grid_coords,
caption: sz.caption,
})
.collect(),
code: self.code,
name: parse_ansi_markup(&self.name).unwrap(),
short: parse_ansi_markup(&self.short).unwrap(),
grid_coords: self.grid_coords,
description: parse_ansi_markup(&self.description).unwrap(),
description_less_explicit: self.description_less_explicit,
exits: self.exits.into_iter().map(|e| e.into()).collect(),
should_caption: self.should_caption,
repel_npc: self.repel_npc,
item_flags: self.item_flags,
stock_list: self.stock_list,
rentable_dynzone: self.rentable_dynzone,
material_type: self.material_type,
has_power: self.has_power,
door_states: self.door_states,
wristpad_hack_allowed: self.wristpad_hack_allowed,
journal: self.journal,
enter_trigger: None,
scavtable: self.scavtable,
}
}
}
impl<'a, T: Default> Default for SimpleRoom<T> {
fn default() -> Self {
Self {
zone: "default".to_owned(),
secondary_zones: vec![],
code: "default".to_owned(),
name: "default".to_owned(),
short: "DF".to_owned(),
grid_coords: GridCoords { x: 0, y: 0, z: 0 },
description: "default".to_owned(),
description_less_explicit: None,
exits: vec![],
should_caption: true,
repel_npc: false,
item_flags: vec![],
stock_list: vec![],
rentable_dynzone: vec![],
material_type: MaterialType::Normal,
has_power: false,
door_states: None,
wristpad_hack_allowed: None,
journal: None,
scavtable: ScavtableType::Nothing,
extra: Default::default(),
} }
} }
} }
@ -414,7 +539,8 @@ pub fn room_list() -> &'static Vec<Room> {
static STATIC_ROOM_MAP_BY_CODE: OnceCell<BTreeMap<&'static str, &'static Room>> = OnceCell::new(); static STATIC_ROOM_MAP_BY_CODE: OnceCell<BTreeMap<&'static str, &'static Room>> = OnceCell::new();
pub fn room_map_by_code() -> &'static BTreeMap<&'static str, &'static Room> { pub fn room_map_by_code() -> &'static BTreeMap<&'static str, &'static Room> {
STATIC_ROOM_MAP_BY_CODE.get_or_init(|| room_list().iter().map(|r| (r.code, r)).collect()) STATIC_ROOM_MAP_BY_CODE
.get_or_init(|| room_list().iter().map(|r| (r.code.as_str(), r)).collect())
} }
static STATIC_ROOM_MAP_BY_ZLOC: OnceCell< static STATIC_ROOM_MAP_BY_ZLOC: OnceCell<
@ -424,11 +550,11 @@ pub fn room_map_by_zloc() -> &'static BTreeMap<(&'static str, &'static GridCoord
STATIC_ROOM_MAP_BY_ZLOC.get_or_init(|| { STATIC_ROOM_MAP_BY_ZLOC.get_or_init(|| {
room_list() room_list()
.iter() .iter()
.map(|r| ((r.zone, &r.grid_coords), r)) .map(|r| ((r.zone.as_str(), &r.grid_coords), r))
.chain(room_list().iter().flat_map(|r| { .chain(room_list().iter().flat_map(|r| {
r.secondary_zones r.secondary_zones
.iter() .iter()
.map(|sz| ((sz.zone, &sz.grid_coords), r)) .map(|sz| ((sz.zone.as_str(), &sz.grid_coords), r))
.collect::<Vec<((&'static str, &'static GridCoords), &'static Room)>>() .collect::<Vec<((&'static str, &'static GridCoords), &'static Room)>>()
})) }))
.collect() .collect()
@ -437,13 +563,13 @@ pub fn room_map_by_zloc() -> &'static BTreeMap<(&'static str, &'static GridCoord
pub fn room_static_items() -> Box<dyn Iterator<Item = StaticItem>> { pub fn room_static_items() -> Box<dyn Iterator<Item = StaticItem>> {
Box::new(room_list().iter().map(|r| StaticItem { Box::new(room_list().iter().map(|r| StaticItem {
item_code: r.code, item_code: &r.code,
initial_item: Box::new(|| Item { initial_item: Box::new(|| Item {
item_code: r.code.to_owned(), item_code: r.code.to_owned(),
item_type: "room".to_owned(), item_type: "room".to_owned(),
display: r.name.to_owned(), display: r.name.to_owned(),
details: Some(r.description.to_owned()), details: Some(r.description.to_owned()),
details_less_explicit: r.description_less_explicit.map(|d| d.to_owned()), details_less_explicit: r.description_less_explicit.as_ref().map(|d| d.to_owned()),
location: format!("zone/{}", r.zone), location: format!("zone/{}", r.zone),
is_static: true, is_static: true,
flags: r.item_flags.clone(), flags: r.item_flags.clone(),
@ -456,7 +582,7 @@ pub fn room_static_items() -> Box<dyn Iterator<Item = StaticItem>> {
pub fn resolve_exit(room: &Room, exit: &Exit) -> Option<&'static Room> { pub fn resolve_exit(room: &Room, exit: &Exit) -> Option<&'static Room> {
match exit.target { match exit.target {
ExitTarget::Custom(t) => t.split_once("/").and_then(|(t, c)| { ExitTarget::Custom(ref t) => t.split_once("/").and_then(|(t, c)| {
if t != "room" { if t != "room" {
None None
} else { } else {
@ -464,7 +590,7 @@ pub fn resolve_exit(room: &Room, exit: &Exit) -> Option<&'static Room> {
} }
}), }),
ExitTarget::UseGPS => room_map_by_zloc() ExitTarget::UseGPS => room_map_by_zloc()
.get(&(room.zone, &room.grid_coords.apply(&exit.direction))) .get(&(&room.zone, &room.grid_coords.apply(&exit.direction)))
.map(|r| *r), .map(|r| *r),
} }
} }
@ -552,13 +678,14 @@ pub async fn check_for_enter_action(ctx: &mut QueuedCommandContext<'_>) -> UResu
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::super::scavtable::scavtable_map;
use super::*; use super::*;
use itertools::Itertools; use itertools::Itertools;
#[test] #[test]
fn room_zones_should_exist() { fn room_zones_should_exist() {
for room in room_list() { for room in room_list() {
zone_details().get(room.zone).expect(&format!( zone_details().get(room.zone.as_str()).expect(&format!(
"zone {} for room {} should exist", "zone {} for room {} should exist",
room.zone, room.code room.zone, room.code
)); ));
@ -570,7 +697,10 @@ mod test {
assert_eq!( assert_eq!(
room_list() room_list()
.iter() .iter()
.map(|r| (r.code, ansi::strip_special_characters(r.short))) .map(|r| (
r.code.as_str(),
ansi::strip_special_characters(r.short.as_str())
))
.filter(|(_c, s)| s.len() != 2) .filter(|(_c, s)| s.len() != 2)
.collect::<Vec<(&'static str, String)>>(), .collect::<Vec<(&'static str, String)>>(),
vec![] vec![]
@ -595,10 +725,10 @@ mod test {
.sort_unstable_by(|a, b| a.grid_coords.cmp(&b.grid_coords).then(a.zone.cmp(&b.zone))); .sort_unstable_by(|a, b| a.grid_coords.cmp(&b.grid_coords).then(a.zone.cmp(&b.zone)));
let dups: Vec<Vec<(&'static str, &GridCoords, &'static str)>> = roomlist let dups: Vec<Vec<(&'static str, &GridCoords, &'static str)>> = roomlist
.iter() .iter()
.group_by(|x| (&x.grid_coords, x.zone)) .group_by(|x| (&x.grid_coords, x.zone.as_str()))
.into_iter() .into_iter()
.map(|((coord, zone), rg)| { .map(|((coord, zone), rg)| {
rg.map(|r| (r.name, coord, zone)) rg.map(|r| (r.name.as_str(), coord, zone))
.collect::<Vec<(&str, &GridCoords, &str)>>() .collect::<Vec<(&str, &GridCoords, &str)>>()
}) })
.filter(|x| x.len() > 1) .filter(|x| x.len() > 1)
@ -633,4 +763,16 @@ mod test {
); );
} }
} }
#[test]
fn rooms_reference_valid_scavtables() {
let bad_scav_rooms: Vec<String> = room_list()
.iter()
.filter_map(|r| match scavtable_map().get(&r.scavtable) {
Some(_) => None,
None => Some(r.code.clone()),
})
.collect::<Vec<String>>();
assert_eq!(bad_scav_rooms, Vec::<String>::new());
}
} }

View File

@ -1,86 +1,10 @@
use super::{ use super::{Room, SimpleRoom};
Direction, Exit, ExitClimb, ExitTarget, GridCoords, MaterialType, Room, SecondaryZoneRecord, use serde_yaml::from_str as from_yaml_str;
};
use ansi::ansi;
pub fn room_list() -> Vec<Room> { pub fn room_list() -> Vec<Room> {
vec!( from_yaml_str::<Vec<SimpleRoom<()>>>(include_str!("chonkers.yaml"))
Room { .unwrap()
zone: "chonkers", .into_iter()
secondary_zones: vec!( .map(|r| r.into())
SecondaryZoneRecord { .collect()
zone: "melbs",
short: ansi!("<bgyellow><blue>CG<reset>"),
grid_coords: GridCoords { x: 8, y: 2, z: 0 },
caption: Some("Chonker's Gym")
}
),
code: "chonkers_strength_hall",
name: "Strength Hall",
short: ansi!("<bgblack><white>SH<reset>"),
description: ansi!("The first of several adjoined rooms making up Chonker's Gym, this space seems to be focused on strength training, and it exudes energy, filled with the invigorating scent of sweat and determination. The proprietor, Chonkers, stands at the center, a fitness enthusiast with a chiseled physique. Mirrors line the walls, reflecting the efforts of gym-goers as they push their limits. The atmosphere is charged with determination and camaraderie, accompanied by the rhythmic beat of energetic music. To the north, you notice a climbing wall towering over another room"),
description_less_explicit: None,
grid_coords: GridCoords { x: 0, y: 0, z: 0 },
exits: vec!(
Exit {
direction: Direction::SOUTH,
target: ExitTarget::Custom("room/melbs_bourkest_160"),
..Default::default()
},
Exit {
direction: Direction::NORTH,
..Default::default()
},
),
should_caption: true,
..Default::default()
},
Room {
zone: "chonkers",
code: "chonkers_endurance_hall",
name: "Endurance Hall",
short: ansi!("<bgblack><white>EH<reset>"),
description: ansi!("A room that appears to be dedicated to endurance training. This space exudes a sense of purpose, with its focus on building stamina and resilience. At the northern edge of the room stands a towering climbing wall, inviting enthusiasts to conquer its challenging heights. The walls are adorned with motivational posters, inspiring climbers to push beyond their limits and embrace the thrill of conquering obstacles. Surrounding the climbing wall, a variety of endurance-focused machines beckon, ready to test and strengthen the resolve of those who dare to challenge themselves. The air hums with the sounds of exertion and determination, creating an atmosphere charged with the energy of individuals striving to improve their endurance and surpass their previous achievements"),
description_less_explicit: None,
grid_coords: GridCoords { x: 0, y: -1, z: 0 },
exits: vec!(
Exit {
direction: Direction::SOUTH,
..Default::default()
},
Exit {
direction: Direction::UP,
exit_climb: Some(ExitClimb {
height: 5,
difficulty: 11
}),
..Default::default()
},
),
material_type: MaterialType::Soft { damage_modifier: 0.5 },
should_caption: true,
..Default::default()
},
Room {
zone: "chonkers",
code: "chonkers_climbing_top",
name: "Top of the Climbing Wall",
short: ansi!("<bgblack><white>CW<reset>"),
description: ansi!("Congratulations, you made it to the top! It is quite snug up here in a little alcove at the top of the wall, but the view from the top of the wall is amazing; you have a 180 degree view of buff men and women pumping iron and keeping themselves fit"),
description_less_explicit: None,
grid_coords: GridCoords { x: 0, y: -1, z: 1 },
exits: vec!(
Exit {
direction: Direction::DOWN,
exit_climb: Some(ExitClimb {
height: -5,
difficulty: 11
}),
..Default::default()
},
),
material_type: MaterialType::Soft { damage_modifier: 0.5 },
should_caption: true,
..Default::default()
},
)
} }

View File

@ -0,0 +1,52 @@
- zone: chonkers
secondary_zones:
- zone: melbs
short: <bgyellow><blue>CG<reset>
grid_coords:
x: 8
y: 2
z: 0
caption: Chonker's Gym
code: chonkers_strength_hall
name: Strength Hall
short: <bgblack><white>SH<reset>
grid_coords:
x: 0
y: 0
z: 0
description: The first of several adjoined rooms making up Chonker's Gym, this space seems to be focused on strength training, and it exudes energy, filled with the invigorating scent of sweat and determination. The proprietor, Chonkers, stands at the center, a fitness enthusiast with a chiseled physique. Mirrors line the walls, reflecting the efforts of gym-goers as they push their limits. The atmosphere is charged with determination and camaraderie, accompanied by the rhythmic beat of energetic music. To the north, you notice a climbing wall towering over another room
exits:
- direction: south
target: !Custom room/melbs_bourkest_160
- direction: north
- zone: chonkers
code: chonkers_endurance_hall
name: Endurance Hall
short: <bgblack><white>EH<reset>
grid_coords:
x: 0
y: -1
z: 0
description: A room that appears to be dedicated to endurance training. This space exudes a sense of purpose, with its focus on building stamina and resilience. At the northern edge of the room stands a towering climbing wall, inviting enthusiasts to conquer its challenging heights. The walls are adorned with motivational posters, inspiring climbers to push beyond their limits and embrace the thrill of conquering obstacles. Surrounding the climbing wall, a variety of endurance-focused machines beckon, ready to test and strengthen the resolve of those who dare to challenge themselves. The air hums with the sounds of exertion and determination, creating an atmosphere charged with the energy of individuals striving to improve their endurance and surpass their previous achievements
exits:
- direction: south
- direction: up
exit_climb:
height: 5
difficulty: 11
material_type: !Soft
damage_modifier: 50
- zone: chonkers
code: chonkers_climbing_top
name: Top of the Climbing Wall
short: <bgblack><white>CW<reset>
grid_coords:
x: 0
y: -1
z: 1
description: Congratulations, you made it to the top! It is quite snug up here in a little alcove at the top of the wall, but the view from the top of the wall is amazing; you have a 180 degree view of buff men and women pumping iron and keeping themselves fit
exits:
- direction: down
exit_climb:
height: -5
difficulty: 11

View File

@ -1,120 +1,10 @@
use super::{ use super::{Room, SimpleRoom};
Direction, Exit, ExitTarget, GridCoords, RentInfo, RentSuiteType, Room, SecondaryZoneRecord, use serde_yaml::from_str as from_yaml_str;
};
use crate::static_content::dynzone::DynzoneType;
use ansi::ansi;
pub fn room_list() -> Vec<Room> {
vec!(
// Residential
Room {
zone: "cok_murl",
secondary_zones: vec!(
SecondaryZoneRecord {
zone: "melbs",
short: ansi!("<bgyellow><black>CK<reset>"),
grid_coords: GridCoords { x: 2, y: 5, z: 0 },
caption: Some("Condos on King")
}
),
code: "cok_lobby",
name: "Residential Lobby",
short: ansi!("<bgyellow><black>RE<reset>"),
description: ansi!("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"),
description_less_explicit: None,
grid_coords: GridCoords { x: 0, y: 0, z: 0 },
exits: vec!(
Exit {
direction: Direction::WEST,
target: ExitTarget::Custom("room/melbs_kingst_80"),
..Default::default()
},
Exit {
direction: Direction::EAST,
..Default::default()
},
),
should_caption: true,
rentable_dynzone: vec!(RentInfo {
rent_what: "studio",
suite_type: RentSuiteType::Residential,
dynzone: DynzoneType::CokMurlApartment,
daily_price: 20,
setup_fee: 40,
}),
..Default::default()
},
// Commercial pub fn room_list() -> Vec<Room> {
Room { from_yaml_str::<Vec<SimpleRoom<()>>>(include_str!("cok_murl.yaml"))
zone: "cok_murl", .unwrap()
code: "murl_lobby", .into_iter()
name: "Murlison Suites Commercial Lobby", .map(|r| r.into())
short: ansi!("<bgyellow><black>ML<reset>"), .collect()
description: ansi!(
"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\""
),
description_less_explicit: None,
grid_coords: GridCoords { x: 1, y: 0, z: 0 },
rentable_dynzone: vec!(RentInfo {
rent_what: "deluxe",
suite_type: RentSuiteType::Commercial,
dynzone: DynzoneType::MurlDeluxeCorporate,
daily_price: 200,
setup_fee: 400,
}),
exits: vec!(
Exit {
direction: Direction::WEST,
..Default::default()
},
Exit {
direction: Direction::NORTH,
..Default::default()
},
Exit {
direction: Direction::SOUTH,
..Default::default()
}
),
should_caption: true,
..Default::default()
},
Room {
zone: "cok_murl",
code: "murl_gf_lift",
name: "Commercial Lifts",
short: ansi!("<bgyellow><black>LI<reset>"),
description: "A set of lifts leading up to various floors",
description_less_explicit: None,
grid_coords: GridCoords { x: 1, y: -1, z: 0 },
exits: vec!(
Exit {
direction: Direction::SOUTH,
..Default::default()
},
),
should_caption: true,
..Default::default()
},
Room {
zone: "cok_murl",
code: "murl_gf_stair",
name: "Commercial Stairs",
short: ansi!("<bgyellow><black>>><reset>"),
description: "A set of stairs leading up to various floors",
description_less_explicit: None,
grid_coords: GridCoords { x: 1, y: 1, z: 0 },
exits: vec!(
Exit {
direction: Direction::NORTH,
..Default::default()
},
),
should_caption: true,
..Default::default()
},
)
} }

View File

@ -0,0 +1,45 @@
- zone: cok_murl
secondary_zones:
- zone: melbs
short: "<bgyellow><black>CK<reset>"
grid_coords:
x: 2
y: 5
z: 0
caption: Condos on King
code: cok_lobby
name: Residential Lobby
short: "<bgyellow><black>RE<reset>"
grid_coords:
x: 0
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"
exits:
- direction: west
target: !Custom room/melbs_kingst_80
- direction: east
rentable_dynzone:
- rent_what: studio
suite_type: Residential
dynzone: CokMurlApartment
daily_price: 20
setup_fee: 40
- zone: cok_murl
code: murl_lobby
name: Murlison Suites Commercial Lobby
short: "<bgyellow><black>ML<reset>"
grid_coords:
x: 1
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\""
exits:
- direction: west
- direction: south
rentable_dynzone:
- rent_what: deluxe
suite_type: Commercial
dynzone: MurlDeluxeCorporate
daily_price: 200
setup_fee: 400

View File

@ -1,208 +1,31 @@
use crate::{ use crate::{
models::{ models::item::LocationActionType,
item::{DoorState, LocationActionType},
journal::JournalType,
user::WristpadHack,
},
static_content::{ static_content::{
fixed_item::FixedItem, fixed_item::FixedItem,
possession_type::{possession_data, PossessionData, PossessionType}, possession_type::{possession_data, PossessionData, PossessionType},
}, },
}; };
use super::{Direction, Exit, ExitTarget, GridCoords, Room, SecondaryZoneRecord}; use super::{Direction, Room, SimpleRoom};
use ansi::ansi; use serde_yaml::from_str as from_yaml_str;
pub fn room_list() -> Vec<Room> { pub fn room_list() -> Vec<Room> {
vec!( from_yaml_str::<Vec<SimpleRoom<()>>>(include_str!("computer_museum.yaml"))
Room { .unwrap()
zone: "computer_museum", .into_iter()
secondary_zones: vec!( .map(|r| r.into())
SecondaryZoneRecord { .collect()
zone: "melbs",
short: ansi!("<bgyellow><blue>CM<reset>"),
grid_coords: GridCoords { x: 2, y: -3, z: 0 },
caption: Some("Computer Museum")
}
),
code: "computer_museum_lobby",
name: "Lobby",
short: ansi!("<bgblack><white><lt>=<reset>"),
description: ansi!("A large room, full of glass cases containing computer equipment from various eras, from ancient dusty looking machines, to miniturised modern equipment. Some of the computer equipment is even powered up, showing scrolling text and various demonstration images. A dusty staircase, above which is hung a faded sign saying <red>'Danger, robots in use, do not enter'<reset>, leads down"),
description_less_explicit: None,
grid_coords: GridCoords { x: 0, y: 0, z: 0 },
exits: vec!(
Exit {
direction: Direction::WEST,
target: ExitTarget::Custom("room/melbs_kingst_20"),
..Default::default()
},
Exit {
direction: Direction::DOWN,
..Default::default()
},
),
should_caption: true,
..Default::default()
},
Room {
zone: "computer_museum",
secondary_zones: vec![],
code: "computer_museum_club_stairwell",
name: "Stairwell",
short: ansi!("<bgblack><yellow>>=<reset>"),
description: ansi!("This appears to be the start of a long corridor. Floor, walls, and ceiling are all made of concrete. A plain concrete staircase leads up. Painted on the floor to the east is a red line adorned with the text <red>DANGER ROBOTS DO NOT CROSS<reset>. The corridor echoes with screams of torment and the sound of metal cutting into flesh. You can just make out a door at the east end of the corridor"),
description_less_explicit: None,
grid_coords: GridCoords { x: 0, y: 0, z: -1 },
exits: vec!(
Exit {
direction: Direction::UP,
..Default::default()
},
Exit {
direction: Direction::EAST,
..Default::default()
},
),
repel_npc: true,
should_caption: true,
..Default::default()
},
Room {
zone: "computer_museum",
secondary_zones: vec![],
code: "computer_museum_hw_1",
name: "Corridor Segment 1",
short: ansi!("<bgblack><yellow>==<reset>"),
description: ansi!("This appears to be part of a long corridor. Floor, walls, and ceiling are all made of concrete. Painted on the ground to the west is the text <red>DANGER ROBOTS DO NOT CROSS<reset>. The corridor continues to the east. To the east, you see some kind of marking on the concrete wall. The corridor echoes with screams of torment and the sound of metal cutting into flesh. You can make out a door at the east end of the corridor, with some kind of electronic screen on it. A plaque on the wall tells you this is Corridor Segment 1"),
description_less_explicit: None,
grid_coords: GridCoords { x: 1, y: 0, z: -1 },
exits: vec!(
Exit {
direction: Direction::WEST,
..Default::default()
},
Exit {
direction: Direction::EAST,
..Default::default()
},
),
should_caption: false,
..Default::default()
},
Room {
zone: "computer_museum",
secondary_zones: vec![],
code: "computer_museum_hw_2",
name: "Corridor Segment 2",
short: ansi!("<bgblack><yellow>==<reset>"),
description: ansi!("This appears to be part of a long corridor. Floor, walls, and ceiling are all made of concrete. The corridor continues to the east and west. The corridor echoes with screams of torment and the sound of metal cutting into flesh. A stain, apparently done in blood, says in scrawled, panicked looking writing: <yellow><bgblack>Beware Robots! Discs to third tower<reset>. You can see a door at the east end of the corridor, with some kind of electronic screen on it, showing some kind of towers. A plaque on the wall tells you this is Corridor Segment 2"),
description_less_explicit: None,
grid_coords: GridCoords { x: 2, y: 0, z: -1 },
exits: vec!(
Exit {
direction: Direction::WEST,
..Default::default()
},
Exit {
direction: Direction::EAST,
..Default::default()
},
),
should_caption: false,
..Default::default()
},
Room {
zone: "computer_museum",
secondary_zones: vec![],
code: "computer_museum_hw_3",
name: "Corridor Segment 3",
short: ansi!("<bgblack><yellow>==<reset>"),
description: ansi!("This appears to be part of a long corridor. Floor, walls, and ceiling are all made of concrete. Painted on the ground to the west is the text <red>DANGER ROBOTS DO NOT CROSS<reset>. The corridor continues to the east and west. To the west, you see some kind of marking on the concrete wall. The corridor echoes with screams of torment and the sound of metal cutting into flesh. You can make out a door at the east end of the corridor, with some kind of electronic screen on it, showing some kind of towers. A plaque on the wall tells you this is Corridor Segment 3"),
description_less_explicit: None,
grid_coords: GridCoords { x: 3, y: 0, z: -1 },
exits: vec!(
Exit {
direction: Direction::WEST,
..Default::default()
},
Exit {
direction: Direction::EAST,
..Default::default()
},
),
should_caption: false,
..Default::default()
},
Room {
zone: "computer_museum",
secondary_zones: vec![],
code: "computer_museum_club_door",
name: "Doorwell",
short: ansi!("<bgblack><yellow>/\\<reset>"),
description: ansi!("This appears to be a security zone protecting access to a door to the north. A long corridor stretches to the west. The corridor echoes with screams of torment and the sound of metal cutting into flesh.\n\
Mounted on the door is a large screen, labelled as \"Doorbot\", showing \
primative ASCII art of some towers, \
with with some kind of electronic screen on it, showing some kind of towers with \
coloured discs stacked on them.\n\
[Hint: try <bold>-doorbot move from 1 to 2<reset> to ask Doorbot \
to move the top disc from tower 1 to tower 2]\n\
The discs are arranged as follows:\n"),
description_less_explicit: None,
grid_coords: GridCoords { x: 4, y: 0, z: -1 },
exits: vec!(
Exit {
direction: Direction::NORTH,
..Default::default()
},
Exit {
direction: Direction::WEST,
..Default::default()
},
),
should_caption: true,
..Default::default()
},
Room {
zone: "computer_museum",
secondary_zones: vec![],
code: "computer_museum_hackers_club",
name: "Hackers' Club",
short: ansi!("<bgblack><green>HC<reset>"),
description: ansi!("A room full of beeping and whirring equipment. One shiny stainless steel piece of equipment really catches your eye. It has a large plaque on it saying: Wristpad hacking unit - intelligence upgrade program. [You realise you can hack your wristpad here, if you have a free wristpad hack slot, to make yourself a superdork; it will increase your brains by 3, but decrease your cool by 1. To do it, type <bold>hack superdork<reset>]"),
description_less_explicit: None,
grid_coords: GridCoords { x: 4, y: -1, z: -1 },
exits: vec!(
Exit {
direction: Direction::SOUTH,
..Default::default()
},
),
door_states: Some(vec![
(
Direction::SOUTH,
DoorState {
open: false,
description: "a very heavy-duty looking solid steel door, with black and yellow warning stripes painted on the surface, and an LCD-style screen afixed to the middle a bit over a metre up".to_owned()
}
)
].into_iter().collect()),
should_caption: true,
journal: Some(JournalType::JoinedHackerClub),
wristpad_hack_allowed: Some(WristpadHack::Superdork),
..Default::default()
},
)
} }
pub fn fixed_items() -> Vec<FixedItem> { pub fn fixed_items() -> Vec<FixedItem> {
vec![FixedItem { vec![FixedItem {
code: "computer_museum_club_door_lock", code: "computer_museum_club_door_lock".to_owned(),
name: ansi!("basic keyed lock"), name: "basic keyed lock".to_owned(),
description: ansi!("A basic lock that looks like it needs a key to open"), description: "A basic lock that looks like it needs a key to open".to_owned(),
description_less_explicit: None, description_less_explicit: None,
location: "room/computer_museum_hackers_club", location: "room/computer_museum_hackers_club".to_owned(),
proper_noun: false, proper_noun: false,
aliases: vec!["lock"], aliases: vec!["lock".to_owned()],
action_type: LocationActionType::InstalledOnDoorAsLock(Direction::SOUTH), action_type: LocationActionType::InstalledOnDoorAsLock(Direction::SOUTH),
..Default::default() ..Default::default()
}] }]

View File

@ -0,0 +1,107 @@
- zone: computer_museum
secondary_zones:
- zone: melbs
short: <bgyellow><blue>CM<reset>
grid_coords:
x: 2
y: -3
z: 0
caption: Computer Museum
code: computer_museum_lobby
name: Lobby
short: <bgblack><white><lt>=<reset>
grid_coords:
x: 0
y: 0
z: 0
description: A large room, full of glass cases containing computer equipment from various eras, from ancient dusty looking machines, to miniturised modern equipment. Some of the computer equipment is even powered up, showing scrolling text and various demonstration images. A dusty staircase, above which is hung a faded sign saying <red>'Danger, robots in use, do not enter'<reset>, leads down
exits:
- direction: west
target: !Custom room/melbs_kingst_20
- direction: down
extra: null
- zone: computer_museum
code: computer_museum_club_stairwell
name: Stairwell
short: <bgblack><yellow>>=<reset>
grid_coords:
x: 0
y: 0
z: -1
description: This appears to be the start of a long corridor. Floor, walls, and ceiling are all made of concrete. A plain concrete staircase leads up. Painted on the floor to the east is a red line adorned with the text <red>DANGER ROBOTS DO NOT CROSS<reset>. The corridor echoes with screams of torment and the sound of metal cutting into flesh. You can just make out a door at the east end of the corridor
exits:
- direction: up
- direction: east
repel_npc: true
- zone: computer_museum
code: computer_museum_hw_1
name: Corridor Segment 1
short: <bgblack><yellow>==<reset>
grid_coords:
x: 1
y: 0
z: -1
description: This appears to be part of a long corridor. Floor, walls, and ceiling are all made of concrete. Painted on the ground to the west is the text <red>DANGER ROBOTS DO NOT CROSS<reset>. The corridor continues to the east. To the east, you see some kind of marking on the concrete wall. The corridor echoes with screams of torment and the sound of metal cutting into flesh. You can make out a door at the east end of the corridor, with some kind of electronic screen on it. A plaque on the wall tells you this is Corridor Segment 1
exits:
- direction: west
- direction: east
should_caption: false
- zone: computer_museum
code: computer_museum_hw_2
name: Corridor Segment 2
short: <bgblack><yellow>==<reset>
grid_coords:
x: 2
y: 0
z: -1
description: 'This appears to be part of a long corridor. Floor, walls, and ceiling are all made of concrete. The corridor continues to the east and west. The corridor echoes with screams of torment and the sound of metal cutting into flesh. A stain, apparently done in blood, says in scrawled, panicked looking writing: <yellow><bgblack>Beware Robots! Discs to third tower<reset>. You can see a door at the east end of the corridor, with some kind of electronic screen on it, showing some kind of towers. A plaque on the wall tells you this is Corridor Segment 2'
exits:
- direction: west
- direction: east
should_caption: false
- zone: computer_museum
code: computer_museum_hw_3
name: Corridor Segment 3
short: <bgblack><yellow>==<reset>
grid_coords:
x: 3
y: 0
z: -1
description: This appears to be part of a long corridor. Floor, walls, and ceiling are all made of concrete. Painted on the ground to the west is the text <red>DANGER ROBOTS DO NOT CROSS<reset>. The corridor continues to the east and west. To the west, you see some kind of marking on the concrete wall. The corridor echoes with screams of torment and the sound of metal cutting into flesh. You can make out a door at the east end of the corridor, with some kind of electronic screen on it, showing some kind of towers. A plaque on the wall tells you this is Corridor Segment 3
exits:
- direction: west
- direction: east
should_caption: false
- zone: computer_museum
code: computer_museum_club_door
name: Doorwell
short: <bgblack><yellow>/\<reset>
grid_coords:
x: 4
y: 0
z: -1
description: |
This appears to be a security zone protecting access to a door to the north. A long corridor stretches to the west. The corridor echoes with screams of torment and the sound of metal cutting into flesh.
Mounted on the door is a large screen, labelled as "Doorbot".to_owned(), showing primative ASCII art of some towers, with with some kind of electronic screen on it, showing some kind of towers with coloured discs stacked on them.
[Hint: try <bold>-doorbot move from 1 to 2<reset> to ask Doorbot to move the top disc from tower 1 to tower 2]
The discs are arranged as follows:
exits:
- direction: north
- direction: west
- zone: computer_museum
code: computer_museum_hackers_club
name: Hackers' Club
short: <bgblack><green>HC<reset>
grid_coords:
x: 4
y: -1
z: -1
description: 'A room full of beeping and whirring equipment. One shiny stainless steel piece of equipment really catches your eye. It has a large plaque on it saying: Wristpad hacking unit - intelligence upgrade program. [You realise you can hack your wristpad here, if you have a free wristpad hack slot, to make yourself a superdork; it will increase your brains by 3, but decrease your cool by 1. To do it, type <bold>hack superdork<reset>]'
exits:
- direction: south
door_states:
south:
open: false
description: a very heavy-duty looking solid steel door, with black and yellow warning stripes painted on the surface, and an LCD-style screen afixed to the middle a bit over a metre up
wristpad_hack_allowed: Superdork
journal: JoinedHackerClub

View File

@ -178,31 +178,31 @@ pub static SEE_PATIENT_TASK: &'static (dyn TaskHandler + Sync + Send) = &SeePati
pub fn room_list() -> Vec<Room> { pub fn room_list() -> Vec<Room> {
vec!( vec!(
Room { Room {
zone: "general_hospital", zone: "general_hospital".to_owned(),
secondary_zones: vec!( secondary_zones: vec!(
SecondaryZoneRecord { SecondaryZoneRecord {
zone: "melbs", zone: "melbs".to_owned(),
short: ansi!("<bgwhite><red>++<reset>"), short: ansi!("<bgwhite><red>++<reset>").to_owned(),
grid_coords: GridCoords { x: 2, y: 10, z: 0 }, grid_coords: GridCoords { x: 2, y: 10, z: 0 },
caption: Some("General Hospital") caption: Some("General Hospital".to_owned())
} }
), ),
code: "general_hospital_waiting_room", code: "general_hospital_waiting_room".to_owned(),
name: "Emergency Waiting Room", name: "Emergency Waiting Room".to_owned(),
short: ansi!("<bgwhite><red>WR<reset>"), short: ansi!("<bgwhite><red>WR<reset>").to_owned(),
description: ansi!("A room apparently designed for patients to wait to seen by doctors. \ description: ansi!("A room apparently designed for patients to wait to seen by doctors. \
Heavy-duty grey linoleum lines the floors, and even the tops of the walls, \ Heavy-duty grey linoleum lines the floors, and even the tops of the walls, \
while stainless steel metal strips cover the bottom of the walls. A line on \ while stainless steel metal strips cover the bottom of the walls. A line on \
floor reserves an area of the floor for sick patients to be rushed past on \ floor reserves an area of the floor for sick patients to be rushed past on \
stretchers. It smells strongly of phenolic cleaners. At the front of the room \ stretchers. It smells strongly of phenolic cleaners. At the front of the room \
a triage nurse assures everyone coming in they will be assessed by doctors \ a triage nurse assures everyone coming in they will be assessed by doctors \
a minute after arriving. Doctors pace the floor treating patients"), a minute after arriving. Doctors pace the floor treating patients").to_owned(),
description_less_explicit: None, description_less_explicit: None,
grid_coords: GridCoords { x: 0, y: 0, z: 0 }, grid_coords: GridCoords { x: 0, y: 0, z: 0 },
exits: vec!( exits: vec!(
Exit { Exit {
direction: Direction::WEST, direction: Direction::WEST,
target: ExitTarget::Custom("room/melbs_kingst_120"), target: ExitTarget::Custom("room/melbs_kingst_120".to_owned()),
..Default::default() ..Default::default()
}, },
), ),

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,10 +5,10 @@ use ansi::ansi;
pub fn room_list() -> Vec<Room> { pub fn room_list() -> Vec<Room> {
vec!( vec!(
Room { Room {
zone: "repro_xv", zone: "repro_xv".to_owned(),
code: "repro_xv_chargen", code: "repro_xv_chargen".to_owned(),
name: ansi!("Choice Room"), name: ansi!("Choice Room").to_owned(),
short: ansi!("<bgwhite><green>CR<reset>"), short: ansi!("<bgwhite><green>CR<reset>").to_owned(),
description: ansi!( description: ansi!(
"A room brightly lit in unnaturally white light, covered in sparkling \ "A room brightly lit in unnaturally white light, covered in sparkling \
white tiles from floor to ceiling. A loudspeaker plays a message on \ white tiles from floor to ceiling. A loudspeaker plays a message on \
@ -21,7 +21,7 @@ pub fn room_list() -> Vec<Room> {
wipe your brain again to change them. Talk to Statbot to spend your \ wipe your brain again to change them. Talk to Statbot to spend your \
14 points and create your body.\"<reset>\n\ 14 points and create your body.\"<reset>\n\
[Try <bold>-statbot hi<reset>, to send hi to statbot - the - means \ [Try <bold>-statbot hi<reset>, to send hi to statbot - the - means \
to whisper to a particular person in the room]"), to whisper to a particular person in the room]").to_owned(),
grid_coords: GridCoords { x: 0, y: 0, z: -1 }, grid_coords: GridCoords { x: 0, y: 0, z: -1 },
exits: vec!(Exit { exits: vec!(Exit {
direction: Direction::EAST, direction: Direction::EAST,
@ -33,15 +33,15 @@ pub fn room_list() -> Vec<Room> {
..Default::default() ..Default::default()
}, },
Room { Room {
zone: "repro_xv", zone: "repro_xv".to_owned(),
code: "repro_xv_updates", code: "repro_xv_updates".to_owned(),
name: ansi!("Update Centre"), name: ansi!("Update Centre").to_owned(),
short: ansi!("<bgwhite><green>UC<reset>"), short: ansi!("<bgwhite><green>UC<reset>").to_owned(),
description: ansi!( description: ansi!(
"A room covered in posters, evidently meant to help newly wiped individuals \ "A room covered in posters, evidently meant to help newly wiped individuals \
get up to speed on what has happened in the world since their memory implant was \ get up to speed on what has happened in the world since their memory implant was \
created. A one-way opens to the east - you have a feeling that once you go through, \ created. A one-way opens to the east - you have a feeling that once you go through, \
there will be no coming back in here. <bold>[Hint: Try reading the posters here.]<reset>"), there will be no coming back in here. <bold>[Hint: Try reading the posters here.]<reset>").to_owned(),
grid_coords: GridCoords { x: 1, y: 0, z: -1 }, grid_coords: GridCoords { x: 1, y: 0, z: -1 },
exits: vec!(Exit { exits: vec!(Exit {
direction: Direction::EAST, direction: Direction::EAST,
@ -51,17 +51,17 @@ pub fn room_list() -> Vec<Room> {
..Default::default() ..Default::default()
}, },
Room { Room {
zone: "repro_xv", zone: "repro_xv".to_owned(),
secondary_zones: vec!(), secondary_zones: vec!(),
code: "repro_xv_respawn", code: "repro_xv_respawn".to_owned(),
name: ansi!("Body Factory"), name: ansi!("Body Factory").to_owned(),
short: ansi!("<bgmagenta><white>BF<reset>"), short: ansi!("<bgmagenta><white>BF<reset>").to_owned(),
description: ansi!( description: ansi!(
"A room filled with glass vats full of clear fluids, with bodies of \ "A room filled with glass vats full of clear fluids, with bodies of \
various stages of development floating in them. It smells like bleach. \ various stages of development floating in them. It smells like bleach. \
Being here makes you realise you aren't exactly alive right now... you \ Being here makes you realise you aren't exactly alive right now... you \
have no body. But you sense you could go <bold>up<reset> and attach \ have no body. But you sense you could go <bold>up<reset> and attach \
your memories to a body matching your current stats"), your memories to a body matching your current stats").to_owned(),
grid_coords: GridCoords { x: 2, y: 0, z: -1 }, grid_coords: GridCoords { x: 2, y: 0, z: -1 },
exits: vec!(Exit { exits: vec!(Exit {
direction: Direction::UP, direction: Direction::UP,
@ -71,16 +71,16 @@ pub fn room_list() -> Vec<Room> {
..Default::default() ..Default::default()
}, },
Room { Room {
zone: "repro_xv", zone: "repro_xv".to_owned(),
secondary_zones: vec!(SecondaryZoneRecord { secondary_zones: vec!(SecondaryZoneRecord {
zone: "melbs", zone: "melbs".to_owned(),
short: ansi!("<bgmagenta><white>RL<reset>"), short: ansi!("<bgmagenta><white>RL<reset>").to_owned(),
grid_coords: GridCoords { x: 2, y: 1, z: 0 }, grid_coords: GridCoords { x: 2, y: 1, z: 0 },
caption: Some("ReproLabs") caption: Some("ReproLabs".to_owned())
}), }),
code: "repro_xv_lobby", code: "repro_xv_lobby".to_owned(),
name: "Lobby", name: "Lobby".to_owned(),
short: "<=", short: "<=".to_owned(),
description: ansi!( description: ansi!(
"An entrance for an establishment called ReproLabs XV. \ "An entrance for an establishment called ReproLabs XV. \
It looks like they make bodies and attach peoples memories to \ It looks like they make bodies and attach peoples memories to \
@ -88,12 +88,12 @@ pub fn room_list() -> Vec<Room> {
unattended reception desk, with chrome-plated letters reading \ unattended reception desk, with chrome-plated letters reading \
ReproLabs XV stuck to the wall behind it. A pipe down to into the ground \ ReproLabs XV stuck to the wall behind it. A pipe down to into the ground \
opens up here, but the airflow is so strong, it looks like it is out \ opens up here, but the airflow is so strong, it looks like it is out \
only - it seems to be how newly re-cloned bodies get back into the world"), only - it seems to be how newly re-cloned bodies get back into the world").to_owned(),
grid_coords: GridCoords { x: 2, y: 0, z: 0 }, grid_coords: GridCoords { x: 2, y: 0, z: 0 },
exits: vec!( exits: vec!(
Exit { Exit {
direction: Direction::WEST, direction: Direction::WEST,
target: ExitTarget::Custom("room/melbs_kingst_50"), target: ExitTarget::Custom("room/melbs_kingst_50".to_owned()),
..Default::default() ..Default::default()
}), }),
should_caption: true, should_caption: true,

View File

@ -1,152 +1,10 @@
use super::{GridCoords, Room}; use super::{Room, SimpleRoom};
use ansi::ansi; use serde_yaml::from_str as from_yaml_str;
// None of these are reachable except when the game or an admin puts something there.
pub fn room_list() -> Vec<Room> { pub fn room_list() -> Vec<Room> {
let holding_desc: &'static str = "The inside of a small pen or cage, with thick steel bars, suitable for holding an animal - or a person - securely, with no chance of escape. It is dimly lit and smells like urine, and is very cramped and indignifying. It looks like the only way out would be with the help of whoever locked you in here. [OOC: consider emailing staff@blastmud.org to discuss your situation]"; from_yaml_str::<Vec<SimpleRoom<()>>>(include_str!("special.yaml"))
vec![ .unwrap()
Room { .into_iter()
zone: "special", .map(|r| r.into())
code: "valhalla", .collect()
name: "Valhalla",
short: ansi!("<bgyellow><black>VH<reset>"),
description: "Where the valiant dead NPCs go to wait recloning",
description_less_explicit: None,
grid_coords: GridCoords { x: 0, y: 0, z: 0 },
exits: vec![],
..Default::default()
},
Room {
zone: "special",
code: "holding0",
name: "Holding Pen #0",
short: ansi!("<bgblack><red>H0<reset>"),
description: holding_desc,
description_less_explicit: None,
grid_coords: GridCoords { x: 0, y: 0, z: -1 },
exits: vec![],
..Default::default()
},
Room {
zone: "special",
code: "holding1",
name: "Holding Pen #1",
short: ansi!("<bgblack><red>H1<reset>"),
description: holding_desc,
description_less_explicit: None,
grid_coords: GridCoords { x: 1, y: 0, z: -1 },
exits: vec![],
..Default::default()
},
Room {
zone: "special",
code: "holding2",
name: "Holding Pen #2",
short: ansi!("<bgblack><red>H2<reset>"),
description: holding_desc,
description_less_explicit: None,
grid_coords: GridCoords { x: 2, y: 0, z: -1 },
exits: vec![],
..Default::default()
},
Room {
zone: "special",
code: "holding3",
name: "Holding Pen #3",
short: ansi!("<bgblack><red>H3<reset>"),
description: holding_desc,
description_less_explicit: None,
grid_coords: GridCoords { x: 3, y: 0, z: -1 },
exits: vec![],
..Default::default()
},
Room {
zone: "special",
code: "holding4",
name: "Holding Pen #4",
short: ansi!("<bgblack><red>H4<reset>"),
description: holding_desc,
description_less_explicit: None,
grid_coords: GridCoords { x: 0, y: 1, z: -1 },
exits: vec![],
..Default::default()
},
Room {
zone: "special",
code: "holding5",
name: "Holding Pen #5",
short: ansi!("<bgblack><red>H5<reset>"),
description: holding_desc,
description_less_explicit: None,
grid_coords: GridCoords { x: 1, y: 1, z: -1 },
exits: vec![],
..Default::default()
},
Room {
zone: "special",
code: "holding6",
name: "Holding Pen #6",
short: ansi!("<bgblack><red>H6<reset>"),
description: holding_desc,
description_less_explicit: None,
grid_coords: GridCoords { x: 2, y: 1, z: -1 },
exits: vec![],
..Default::default()
},
Room {
zone: "special",
code: "holding7",
name: "Holding Pen #7",
short: ansi!("<bgblack><red>H7<reset>"),
description: holding_desc,
description_less_explicit: None,
grid_coords: GridCoords { x: 3, y: 1, z: -1 },
exits: vec![],
..Default::default()
},
Room {
zone: "special",
code: "holding8",
name: "Holding Pen #8",
short: ansi!("<bgblack><red>H8<reset>"),
description: holding_desc,
description_less_explicit: None,
grid_coords: GridCoords { x: 0, y: 2, z: -1 },
exits: vec![],
..Default::default()
},
Room {
zone: "special",
code: "holding9",
name: "Holding Pen #9",
short: ansi!("<bgblack><red>H9<reset>"),
description: holding_desc,
description_less_explicit: None,
grid_coords: GridCoords { x: 1, y: 2, z: -1 },
exits: vec![],
..Default::default()
},
Room {
zone: "special",
code: "holdinga",
name: "Holding Pen A",
short: ansi!("<bgblack><red>HA<reset>"),
description: holding_desc,
description_less_explicit: None,
grid_coords: GridCoords { x: 2, y: 2, z: -1 },
exits: vec![],
..Default::default()
},
Room {
zone: "special",
code: "holdingb",
name: "Holding Pen B",
short: ansi!("<bgblack><red>HB<reset>"),
description: holding_desc,
description_less_explicit: None,
grid_coords: GridCoords { x: 3, y: 2, z: -1 },
exits: vec![],
..Default::default()
},
]
} }

View File

@ -0,0 +1,130 @@
- zone: special
code: valhalla
name: Valhalla
short: "<bgyellow><black>VH<reset>"
grid_coords:
x: 0
y: 0
z: 0
description: Where the valiant dead NPCs go to wait recloning
exits: []
- zone: special
code: holding0
name: 'Holding Pen #0'
short: "<bgblack><red>H0<reset>"
grid_coords:
x: 0
y: 0
z: -1
description: 'The inside of a small pen or cage, with thick steel bars, suitable for holding an animal - or a person - securely, with no chance of escape. It is dimly lit and smells like urine, and is very cramped and indignifying. It looks like the only way out would be with the help of whoever locked you in here. [OOC: consider emailing staff@blastmud.org to discuss your situation]'
exits: []
- zone: special
code: holding1
name: 'Holding Pen #1'
short: "<bgblack><red>H1<reset>"
grid_coords:
x: 1
y: 0
z: -1
description: 'The inside of a small pen or cage, with thick steel bars, suitable for holding an animal - or a person - securely, with no chance of escape. It is dimly lit and smells like urine, and is very cramped and indignifying. It looks like the only way out would be with the help of whoever locked you in here. [OOC: consider emailing staff@blastmud.org to discuss your situation]'
exits: []
- zone: special
code: holding2
name: 'Holding Pen #2'
short: "<bgblack><red>H2<reset>"
grid_coords:
x: 2
y: 0
z: -1
description: 'The inside of a small pen or cage, with thick steel bars, suitable for holding an animal - or a person - securely, with no chance of escape. It is dimly lit and smells like urine, and is very cramped and indignifying. It looks like the only way out would be with the help of whoever locked you in here. [OOC: consider emailing staff@blastmud.org to discuss your situation]'
exits: []
- zone: special
code: holding3
name: 'Holding Pen #3'
short: "<bgblack><red>H3<reset>"
grid_coords:
x: 3
y: 0
z: -1
description: 'The inside of a small pen or cage, with thick steel bars, suitable for holding an animal - or a person - securely, with no chance of escape. It is dimly lit and smells like urine, and is very cramped and indignifying. It looks like the only way out would be with the help of whoever locked you in here. [OOC: consider emailing staff@blastmud.org to discuss your situation]'
exits: []
- zone: special
code: holding4
name: 'Holding Pen #4'
short: "<bgblack><red>H4<reset>"
grid_coords:
x: 0
y: 1
z: -1
description: 'The inside of a small pen or cage, with thick steel bars, suitable for holding an animal - or a person - securely, with no chance of escape. It is dimly lit and smells like urine, and is very cramped and indignifying. It looks like the only way out would be with the help of whoever locked you in here. [OOC: consider emailing staff@blastmud.org to discuss your situation]'
exits: []
- zone: special
code: holding5
name: 'Holding Pen #5'
short: "<bgblack><red>H5<reset>"
grid_coords:
x: 1
y: 1
z: -1
description: 'The inside of a small pen or cage, with thick steel bars, suitable for holding an animal - or a person - securely, with no chance of escape. It is dimly lit and smells like urine, and is very cramped and indignifying. It looks like the only way out would be with the help of whoever locked you in here. [OOC: consider emailing staff@blastmud.org to discuss your situation]'
exits: []
- zone: special
code: holding6
name: 'Holding Pen #6'
short: "<bgblack><red>H6<reset>"
grid_coords:
x: 2
y: 1
z: -1
description: 'The inside of a small pen or cage, with thick steel bars, suitable for holding an animal - or a person - securely, with no chance of escape. It is dimly lit and smells like urine, and is very cramped and indignifying. It looks like the only way out would be with the help of whoever locked you in here. [OOC: consider emailing staff@blastmud.org to discuss your situation]'
exits: []
- zone: special
code: holding7
name: 'Holding Pen #7'
short: "<bgblack><red>H7<reset>"
grid_coords:
x: 3
y: 1
z: -1
description: 'The inside of a small pen or cage, with thick steel bars, suitable for holding an animal - or a person - securely, with no chance of escape. It is dimly lit and smells like urine, and is very cramped and indignifying. It looks like the only way out would be with the help of whoever locked you in here. [OOC: consider emailing staff@blastmud.org to discuss your situation]'
exits: []
- zone: special
code: holding8
name: 'Holding Pen #8'
short: "<bgblack><red>H8<reset>"
grid_coords:
x: 0
y: 2
z: -1
description: 'The inside of a small pen or cage, with thick steel bars, suitable for holding an animal - or a person - securely, with no chance of escape. It is dimly lit and smells like urine, and is very cramped and indignifying. It looks like the only way out would be with the help of whoever locked you in here. [OOC: consider emailing staff@blastmud.org to discuss your situation]'
exits: []
- zone: special
code: holding9
name: 'Holding Pen #9'
short: "<bgblack><red>H9<reset>"
grid_coords:
x: 1
y: 2
z: -1
description: 'The inside of a small pen or cage, with thick steel bars, suitable for holding an animal - or a person - securely, with no chance of escape. It is dimly lit and smells like urine, and is very cramped and indignifying. It looks like the only way out would be with the help of whoever locked you in here. [OOC: consider emailing staff@blastmud.org to discuss your situation]'
exits: []
- zone: special
code: holdinga
name: Holding Pen A
short: "<bgblack><red>HA<reset>"
grid_coords:
x: 2
y: 2
z: -1
description: 'The inside of a small pen or cage, with thick steel bars, suitable for holding an animal - or a person - securely, with no chance of escape. It is dimly lit and smells like urine, and is very cramped and indignifying. It looks like the only way out would be with the help of whoever locked you in here. [OOC: consider emailing staff@blastmud.org to discuss your situation]'
exits: []
- zone: special
code: holdingb
name: Holding Pen B
short: "<bgblack><red>HB<reset>"
grid_coords:
x: 3
y: 2
z: -1
description: 'The inside of a small pen or cage, with thick steel bars, suitable for holding an animal - or a person - securely, with no chance of escape. It is dimly lit and smells like urine, and is very cramped and indignifying. It looks like the only way out would be with the help of whoever locked you in here. [OOC: consider emailing staff@blastmud.org to discuss your situation]'
exits: []

View File

@ -0,0 +1,33 @@
use crate::models::item::Scavtype;
use super::{possession_type::PossessionType, room::melbs::street_scavtable};
use std::collections::BTreeMap;
use once_cell::sync::OnceCell;
use serde::{Deserialize, Serialize};
pub struct Scavinfo {
pub possession_type: PossessionType,
pub p_present: f64, // probability it is there.
pub difficulty_mean: f64,
pub difficulty_stdev: f64,
pub scavtype: Scavtype,
}
#[derive(Serialize, Deserialize, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
pub enum ScavtableType {
Nothing,
CityStreet,
}
pub fn scavtable_map() -> &'static BTreeMap<ScavtableType, Vec<Scavinfo>> {
static MAP: OnceCell<BTreeMap<ScavtableType, Vec<Scavinfo>>> = OnceCell::new();
MAP.get_or_init(|| {
vec![
(ScavtableType::Nothing, vec![]),
(ScavtableType::CityStreet, street_scavtable()),
]
.into_iter()
.collect()
})
}