NPC data to separate YAML

This commit is contained in:
Condorra 2023-10-09 21:38:12 +11:00
parent 16341e2c3e
commit e53949abf7
19 changed files with 990 additions and 880 deletions

594
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -9,5 +9,5 @@ proc-macro = true
[dependencies]
nom = "7.1.1"
quote = "1.0.23"
syn = "1.0.107"
syn = "2.0.38"
ansi_markup = { path = "../ansi_markup" }

View File

@ -6,16 +6,16 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
base64 = "0.20.0"
base64 = "0.21.4"
blastmud_interfaces = { path = "../blastmud_interfaces" }
ansi = { path = "../ansi" }
ansi_markup = { path = "../ansi_markup" }
deadpool = "0.9.5"
deadpool-postgres = { version = "0.10.3", features = ["serde"] }
deadpool = "0.10.0"
deadpool-postgres = { version = "0.11.0", features = ["serde"] }
futures = "0.3.25"
log = "0.4.17"
nix = "0.26.1"
ring = "0.16.20"
nix = { version = "0.27.1", features = ["process", "signal"] }
ring = "0.17.2"
serde = { version = "1.0.150", features = ["derive", "serde_derive"] }
serde_yaml = "0.9.14"
simple_logger = "4.0.0"
@ -29,22 +29,22 @@ serde_json = "1.0.91"
phf = { version = "0.11.1", features = ["macros"] }
async-trait = "0.1.60"
nom = "7.1.1"
ouroboros = "0.15.5"
ouroboros = "0.18.0"
chrono = { version = "0.4.23", features = ["serde"] }
bcrypt = "0.13.0"
bcrypt = "0.15.0"
validator = "0.16.0"
itertools = "0.10.5"
itertools = "0.11.0"
once_cell = "1.16.0"
rand = "0.8.5"
async-recursion = "1.0.0"
rand_distr = "0.4.3"
humantime = "2.1.0"
rust_decimal = "1.28.0"
mockall = "0.11.3"
mockall_double = "0.3.0"
[dev-dependencies]
tokio-test = "0.4.2"
mockall = "0.11.3"
[features]
default = []

View File

@ -1,5 +1,5 @@
use crate::DResult;
use base64;
use base64::{self, Engine};
use ring::signature;
use serde::Deserialize;
use std::error::Error;
@ -33,6 +33,9 @@ pub fn check() -> DResult<()> {
let sign_text = format!("cn={};{};serial={}", av.cn, av.assertion, av.serial);
let key: signature::UnparsedPublicKey<&[u8]> =
signature::UnparsedPublicKey::new(&signature::ECDSA_P256_SHA256_ASN1, &KEY_BYTES);
key.verify(&sign_text.as_bytes(), &base64::decode(av.sig)?)
.map_err(|_| Box::<dyn Error + Send + Sync>::from("Invalid age-verification.yml signature"))
key.verify(
&sign_text.as_bytes(),
&base64::engine::general_purpose::STANDARD_NO_PAD.decode(av.sig)?,
)
.map_err(|_| Box::<dyn Error + Send + Sync>::from("Invalid age-verification.yml signature"))
}

View File

@ -19,7 +19,7 @@ use std::sync::Arc;
mod agree;
mod allow;
pub mod attack;
mod attack;
mod butcher;
mod buy;
mod c;

View File

@ -2,6 +2,7 @@ use super::{user_error, UResult, UserVerb, UserVerbRef, VerbContext};
use crate::models::user::{User, UserTermData};
use ansi::ansi;
use async_trait::async_trait;
use base64::Engine;
use chrono::Utc;
pub struct Verb;
@ -54,10 +55,9 @@ fn terms<'a>(ctx: &'a VerbContext<'a>) -> UResult<&'a UserTermData> {
fn first_outstanding_agreement(ctx: &VerbContext) -> UResult<Option<(String, String)>> {
let existing_terms = &terms(ctx)?.accepted_terms;
for agreement in REQUIRED_AGREEMENTS {
let shortcode = base64::encode(ring::digest::digest(
&ring::digest::SHA256,
agreement.as_bytes(),
))[0..20]
let shortcode = base64::engine::general_purpose::STANDARD_NO_PAD.encode(
ring::digest::digest(&ring::digest::SHA256, agreement.as_bytes()),
)[0..20]
.to_owned();
match existing_terms.get(&shortcode) {
None => {

View File

@ -20,7 +20,7 @@ pub mod scavtable;
pub mod species;
pub struct StaticItem {
pub item_code: &'static str,
pub item_code: String,
pub initial_item: Box<dyn Fn() -> Item>,
pub extra_items_on_create: Box<dyn Fn(&Item) -> Box<dyn Iterator<Item = Item>>>,
}

View File

@ -103,7 +103,7 @@ pub fn fixed_item_properties() -> &'static BTreeMap<&'static str, PossessionData
pub fn static_items() -> Box<dyn Iterator<Item = StaticItem>> {
Box::new(fixed_item_list().iter().map(|r| StaticItem {
item_code: &r.code,
item_code: r.code.clone(),
initial_item: Box::new(|| Item {
item_code: r.code.clone(),
item_type: "fixed_item".to_owned(),

View File

@ -29,6 +29,7 @@ use log::info;
use mockall_double::double;
use once_cell::sync::OnceCell;
use rand::{prelude::*, thread_rng, Rng};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::time;
use uuid::Uuid;
@ -92,15 +93,33 @@ pub struct NPCSpawnPossession {
wear_layer: i64, // 0 is on top, higher under.
}
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Serialize, Deserialize)]
pub enum NPCPronounType {
Inanimate,
Neutral,
Male,
Female,
}
pub fn npc_pronoun_type_to_pronouns(t: &NPCPronounType) -> Pronouns {
use NPCPronounType::*;
match t {
Inanimate => Pronouns::default_inanimate(),
Neutral => Pronouns::default_animate(),
Male => Pronouns::default_male(),
Female => Pronouns::default_female(),
}
}
pub struct NPC {
pub code: &'static str,
pub name: &'static str,
pub code: String,
pub name: String,
pub pronouns: Pronouns,
pub description: &'static str,
pub spawn_location: &'static str,
pub description: String,
pub spawn_location: String,
pub spawn_possessions: Vec<NPCSpawnPossession>,
pub message_handler: Option<&'static (dyn NPCMessageHandler + Sync + Send)>,
pub aliases: Vec<&'static str>,
pub aliases: Vec<String>,
pub says: Vec<NPCSayInfo>,
pub aggression: u64, // 1-20 sets aggro time, >= 21 = instant aggro.
pub aggro_pc_only: bool,
@ -110,7 +129,7 @@ pub struct NPC {
pub total_skills: BTreeMap<SkillType, f64>,
pub total_stats: BTreeMap<StatType, f64>,
pub species: SpeciesType,
pub wander_zones: Vec<&'static str>,
pub wander_zones: Vec<String>,
pub kill_bonus: Option<KillBonus>,
pub player_consents: Vec<ConsentType>,
pub hire_data: Option<HireData>,
@ -121,11 +140,11 @@ pub struct NPC {
impl Default for NPC {
fn default() -> Self {
Self {
code: "DEFAULT",
name: "default",
code: "DEFAULT".to_owned(),
name: "default".to_owned(),
pronouns: Pronouns::default_animate(),
description: "default",
spawn_location: "default",
description: "default".to_owned(),
spawn_location: "default".to_owned(),
spawn_possessions: vec![],
message_handler: None,
aliases: vec![],
@ -160,11 +179,11 @@ pub fn npc_list() -> &'static Vec<NPC> {
static NPC_LIST: OnceCell<Vec<NPC>> = OnceCell::new();
NPC_LIST.get_or_init(|| {
let mut npcs = vec![NPC {
code: "repro_xv_chargen_statbot",
name: "Statbot",
code: "repro_xv_chargen_statbot".to_owned(),
name: "Statbot".to_owned(),
description:
"A silvery shiny metal mechanical being. It lets out a whirring sound as it moves.",
spawn_location: "room/repro_xv_chargen",
"A silvery shiny metal mechanical being. It lets out a whirring sound as it moves.".to_owned(),
spawn_location: "room/repro_xv_chargen".to_owned(),
message_handler: Some(&statbot::StatbotMessageHandler),
says: vec![],
..Default::default()
@ -179,7 +198,7 @@ pub fn npc_list() -> &'static Vec<NPC> {
pub fn npc_by_code() -> &'static BTreeMap<&'static str, &'static NPC> {
static NPC_CODE_MAP: OnceCell<BTreeMap<&'static str, &'static NPC>> = OnceCell::new();
NPC_CODE_MAP.get_or_init(|| npc_list().iter().map(|npc| (npc.code, npc)).collect())
NPC_CODE_MAP.get_or_init(|| npc_list().iter().map(|npc| (npc.code.as_str(), npc)).collect())
}
pub fn npc_say_info_by_npc_code_say_code(
@ -192,7 +211,7 @@ pub fn npc_say_info_by_npc_code_say_code(
.flat_map(|npc| {
npc.says
.iter()
.map(|says| ((npc.code, says.say_code), says))
.map(|says| ((npc.code.as_str(), says.say_code), says))
})
.collect()
})
@ -201,7 +220,7 @@ pub fn npc_say_info_by_npc_code_say_code(
pub fn npc_static_items() -> Box<dyn Iterator<Item = StaticItem>> {
Box::new(npc_list().iter().map(|c| {
StaticItem {
item_code: c.code,
item_code: c.code.clone(),
initial_item: Box::new(|| {
let mut flags: Vec<ItemFlag> = c.extra_flags.clone();
if c.hire_data.is_some() {
@ -463,7 +482,7 @@ impl TaskHandler for NPCWanderTaskHandler {
let ex_iter = room.exits.iter().filter(|ex| {
resolve_exit(room, ex)
.map(|new_room| {
npc.wander_zones.contains(&new_room.zone.as_str()) && !new_room.repel_npc
npc.wander_zones.contains(&new_room.zone) && !new_room.repel_npc
})
.unwrap_or(false)
});

View File

@ -11,7 +11,10 @@ use crate::{
regular_tasks::{TaskHandler, TaskRunContext},
services::comms::broadcast_to_room,
static_content::{
npc::KillBonus, possession_type::PossessionType, room::Direction, species::SpeciesType,
npc::{npc_pronoun_type_to_pronouns, KillBonus, NPCPronounType},
possession_type::PossessionType,
room::Direction,
species::SpeciesType,
},
DResult,
};
@ -26,6 +29,8 @@ use nom::{
combinator::{eof, opt},
sequence::{delimited, pair, preceded, terminated},
};
use serde::Deserialize;
use serde_yaml::from_str as from_yaml_str;
use std::time;
async fn reply(ctx: &VerbContext<'_>, msg: &str) -> DResult<()> {
@ -349,6 +354,21 @@ impl TaskHandler for ResetGameTaskHandler {
}
pub static RESET_GAME_HANDLER: &'static (dyn TaskHandler + Sync + Send) = &ResetGameTaskHandler;
#[derive(Deserialize)]
enum MuseumNPC {
Geek {
code: String,
adjectives: String,
spawn_loc: String,
pronouns: NPCPronounType,
},
Killbot {
code: String,
adjectives: String,
spawn_loc: String,
},
}
pub fn npc_list() -> Vec<NPC> {
use NPCSayType::FromFixedList;
let geek_stdsay = NPCSayInfo {
@ -373,56 +393,53 @@ pub fn npc_list() -> Vec<NPC> {
))
};
macro_rules! geek_gender_word {
(default_male) => {
"guy"
};
(default_female) => {
"gal"
};
}
macro_rules! geek {
($code: expr, $adj: expr, $spawn: expr, $pronouns: ident) => {
NPC {
code: concat!("computer_museum_geek_", $code),
name: concat!($adj, " geek"),
pronouns: Pronouns { is_proper: false, ..Pronouns::$pronouns() },
description: concat!("A geeky looking ", geek_gender_word!($pronouns), " with horn-rimmed glasses, and a button-down shirt. In the pocket is a pocket protector"),
spawn_location: concat!("room/computer_museum_", $spawn),
spawn_possessions: vec![
NPCSpawnPossession {
what: PossessionType::Shirt,
action_type: LocationActionType::Worn,
wear_layer: 0,
},
NPCSpawnPossession {
what: PossessionType::Jeans,
action_type: LocationActionType::Worn,
wear_layer: 0,
},
],
message_handler: None,
wander_zones: vec!("computer_museum"),
says: vec!(geek_stdsay.clone()),
player_consents: vec!(ConsentType::Medicine),
..Default::default()
}
fn geek_gender_word(pronouns: &NPCPronounType) -> &'static str {
match pronouns {
NPCPronounType::Male => "guy",
_ => "gal",
}
}
macro_rules! killbot {
($code: expr, $adj: expr, $spawn: expr) => {
let mut npcs: Vec<NPC> = from_yaml_str::<Vec<MuseumNPC>>(include_str!("computer_museum_npcs.yaml"))
.unwrap()
.into_iter()
.map(|npc| match npc {
MuseumNPC::Geek { code, adjectives, spawn_loc, pronouns } =>
NPC {
code: format!("computer_museum_geek_{}", &code),
name: format!("{} geek", &adjectives),
pronouns: Pronouns { is_proper: false, ..npc_pronoun_type_to_pronouns(&pronouns) },
description: format!("A geeky looking {} with horn-rimmed glasses, and a button-down shirt. In the pocket is a pocket protector", geek_gender_word(&pronouns)),
spawn_location: format!("room/computer_museum_{}", &spawn_loc),
spawn_possessions: vec![
NPCSpawnPossession {
what: PossessionType::Shirt,
action_type: LocationActionType::Worn,
wear_layer: 0,
},
NPCSpawnPossession {
what: PossessionType::Jeans,
action_type: LocationActionType::Worn,
wear_layer: 0,
},
],
message_handler: None,
wander_zones: vec!("computer_museum".to_owned()),
says: vec!(geek_stdsay.clone()),
player_consents: vec!(ConsentType::Medicine),
..Default::default()
},
MuseumNPC::Killbot { code, adjectives, spawn_loc } =>
NPC {
code: concat!("computer_museum_killbot_", $code),
name: concat!($adj, " Killbot"),
code: format!("computer_museum_killbot_{}", &code),
name: format!("{} Killbot", &adjectives),
species: SpeciesType::Robot,
pronouns: Pronouns {
is_proper: false,
..Pronouns::default_inanimate()
},
description: concat!("A mean looking robot, complete with a vicious spiked mace and powerful solonoids for smashing it hard into whatever unfortunate victim this bot targets"),
spawn_location: concat!("room/computer_museum_", $spawn),
description: "A mean looking robot, complete with a vicious spiked mace and powerful solonoids for smashing it hard into whatever unfortunate victim this bot targets".to_owned(),
spawn_location: format!("room/computer_museum_{}", &spawn_loc),
spawn_possessions: vec![],
aggression: 21,
aggro_pc_only: true,
@ -438,7 +455,7 @@ pub fn npc_list() -> Vec<NPC> {
.collect(),
intrinsic_weapon: Some(PossessionType::SpikedMace),
message_handler: None,
wander_zones: vec!["computer_museum"],
wander_zones: vec!["computer_museum".to_owned()],
kill_bonus: Some(KillBonus {
msg: "On your wristpad: Those robots have been the bane of our existence at the museum. Thanks for taking one out! Here's a small token of our gratitude.",
payment: 120,
@ -447,31 +464,23 @@ pub fn npc_list() -> Vec<NPC> {
player_consents: vec![ConsentType::Fight],
..Default::default()
}
};
}
vec![
geek!("1", "excited", "lobby", default_male),
geek!("2", "mesmerised", "lobby", default_female),
killbot!("3", "abhorrent", "hw_1"),
killbot!("4", "berserk", "hw_2"),
killbot!("5", "vicious", "hw_3"),
killbot!("6", "murderous", "club_door"),
NPC {
code: "computer_museum_doorbot",
name: "Doorbot",
spawn_location: "room/computer_museum_club_door",
description: ansi!(
"A flat panel screen on the door, with a microphone listening for \
commands directed at it, apparently hooked up to the door lock. \
[Hint: try <bold>-doorbot move from 1 to 2<reset> to ask Doorbot \
to move the top disc from tower 1 to tower 2]"
),
pronouns: Pronouns::default_inanimate(),
species: SpeciesType::Robot,
extra_flags: vec![ItemFlag::DontListInLook],
message_handler: Some(&DoorbotMsgHandler),
..Default::default()
},
]
}).collect();
npcs.push(NPC {
code: "computer_museum_doorbot".to_owned(),
name: "Doorbot".to_owned(),
spawn_location: "room/computer_museum_club_door".to_owned(),
description: ansi!(
"A flat panel screen on the door, with a microphone listening for \
commands directed at it, apparently hooked up to the door lock. \
[Hint: try <bold>-doorbot move from 1 to 2<reset> to ask Doorbot \
to move the top disc from tower 1 to tower 2]"
)
.to_owned(),
pronouns: Pronouns::default_inanimate(),
species: SpeciesType::Robot,
extra_flags: vec![ItemFlag::DontListInLook],
message_handler: Some(&DoorbotMsgHandler),
..Default::default()
});
npcs
}

View File

@ -0,0 +1,26 @@
- Geek:
code: "1"
adjectives: excited
spawn_loc: lobby
pronouns: Male
- Geek:
code: "2"
adjectives: mesmerised
spawn_loc: lobby
pronouns: Female
- Killbot:
code: "3"
adjectives: abhorrent
spawn_loc: hw_1
- Killbot:
code: "4"
adjectives: berserk
spawn_loc: hw_2
- Killbot:
code: "5"
adjectives: vicious
spawn_loc: hw_3
- Killbot:
code: "6"
adjectives: murderous
spawn_loc: club_door

View File

@ -1,11 +1,18 @@
use super::{NPCSayInfo, NPCSayType, NPCSpawnPossession, NPC};
use super::{NPCPronounType, NPCSayInfo, NPCSayType, NPCSpawnPossession, NPC};
use crate::{
models::{
consent::ConsentType,
item::{LocationActionType, Pronouns},
},
static_content::possession_type::PossessionType,
models::{consent::ConsentType, item::LocationActionType},
static_content::{npc::npc_pronoun_type_to_pronouns, possession_type::PossessionType},
};
use serde::Deserialize;
use serde_yaml::from_str as from_yaml_str;
#[derive(Deserialize)]
struct Citizen {
code: String,
name: String,
spawn_loc: String,
gender: NPCPronounType,
}
pub fn npc_list() -> Vec<NPC> {
use NPCSayType::FromFixedList;
@ -24,14 +31,16 @@ pub fn npc_list() -> Vec<NPC> {
))
};
macro_rules! citizen {
($code: expr, $name: expr, $spawn: expr, $pronouns: expr) => {
from_yaml_str::<Vec<Citizen>>(include_str!("melbs_citizen.yaml"))
.unwrap()
.into_iter()
.map(|c|
NPC {
code: concat!("melbs_citizen_", $code),
name: $name,
pronouns: $pronouns,
description: "A fairly ordinary looking citizen of Melbs, clearly weary from the harsh reality of post-apocalyptic life",
spawn_location: concat!("room/melbs_", $spawn),
code: format!("melbs_citizen_{}", &c.code),
name: c.name,
pronouns: npc_pronoun_type_to_pronouns(&c.gender),
description: "A fairly ordinary looking citizen of Melbs, clearly weary from the harsh reality of post-apocalyptic life".to_owned(),
spawn_location: format!("room/melbs_{}", &c.spawn_loc),
spawn_possessions: vec![
NPCSpawnPossession {
what: PossessionType::Shirt,
@ -45,349 +54,10 @@ pub fn npc_list() -> Vec<NPC> {
},
],
message_handler: None,
wander_zones: vec!("melbs"),
wander_zones: vec!("melbs".to_owned()),
says: vec!(melbs_citizen_stdsay.clone()),
player_consents: vec!(ConsentType::Medicine, ConsentType::Sex),
..Default::default()
}
}
}
vec![
citizen!(
"1",
"Matthew Thomas",
"kingst_latrobest",
Pronouns::default_male()
),
citizen!("2", "Matthew Perez", "kingst_20", Pronouns::default_male()),
citizen!(
"3",
"Kimberly Jackson",
"kingst_40",
Pronouns::default_female()
),
citizen!(
"4",
"Michael Sanchez",
"kingst_50",
Pronouns::default_male()
),
citizen!(
"5",
"Jessica Davis",
"kingst_bourkest",
Pronouns::default_female()
),
citizen!("6", "Robert Davis", "kingst_70", Pronouns::default_male()),
citizen!("7", "Paul Lewis", "kingst_90", Pronouns::default_male()),
citizen!(
"8",
"Andrew Moore",
"kingst_collinsst",
Pronouns::default_male()
),
citizen!(
"9",
"Betty Thomas",
"kingst_100",
Pronouns::default_female()
),
citizen!(
"10",
"Mary Robinson",
"kingst_110",
Pronouns::default_female()
),
citizen!(
"11",
"Lisa Lopez",
"kingst_flinderst",
Pronouns::default_female()
),
citizen!(
"12",
"Kimberly Martinez",
"flindersst_200",
Pronouns::default_female()
),
citizen!(
"13",
"Anthony Nguyen",
"flindersst_190",
Pronouns::default_male()
),
citizen!(
"14",
"Joshua Green",
"flindersst_180",
Pronouns::default_male()
),
citizen!(
"15",
"Emily Wright",
"flindersst_170",
Pronouns::default_female()
),
citizen!(
"16",
"Ashley Thomas",
"lonsdalest_130",
Pronouns::default_male()
),
citizen!(
"17",
"Jessica Miller",
"kingst_80",
Pronouns::default_female()
),
citizen!(
"18",
"Anthony Lopez",
"lonsdalest_140",
Pronouns::default_male()
),
citizen!(
"19",
"John Lopez",
"elizabethst_lonsdalest",
Pronouns::default_male()
),
citizen!(
"20",
"Thomas Garcia",
"williamsst_120",
Pronouns::default_male()
),
citizen!(
"21",
"Donna Thompson",
"elizabethst_60",
Pronouns::default_female()
),
citizen!(
"22",
"Matthew Davis",
"williamsst_100",
Pronouns::default_male()
),
citizen!(
"23",
"Steven Jones",
"swanstonst_120",
Pronouns::default_male()
),
citizen!(
"24",
"Linda Smith",
"swanstonst_lonsdalest",
Pronouns::default_male()
),
citizen!(
"25",
"Karen Rodriguez",
"bourkest_180",
Pronouns::default_female()
),
citizen!(
"26",
"Paul Scott",
"swanstonst_70",
Pronouns::default_male()
),
citizen!(
"27",
"Ashley Thomas",
"lonsdalest_130",
Pronouns::default_male()
),
citizen!(
"28",
"Sandra Scott",
"elizabethst_30",
Pronouns::default_female()
),
citizen!(
"29",
"Michael Rodriguez",
"swanstonst_70",
Pronouns::default_male()
),
citizen!(
"30",
"Donald Miller",
"elizabethst_30",
Pronouns::default_male()
),
citizen!(
"31",
"Charles Moore",
"lonsdalest_160",
Pronouns::default_male()
),
citizen!(
"32",
"Ashley Sanchez",
"kingst_100",
Pronouns::default_male()
),
citizen!(
"33",
"Margaret Lewis",
"flindersst_180",
Pronouns::default_female()
),
citizen!(
"34",
"Sandra Thompson",
"swanstonst_80",
Pronouns::default_female()
),
citizen!(
"35",
"Sandra King",
"lonsdalest_150",
Pronouns::default_female()
),
citizen!(
"36",
"Lisa Anderson",
"lonsdalest_210",
Pronouns::default_female()
),
citizen!(
"37",
"Kimberly Martin",
"kingst_80",
Pronouns::default_female()
),
citizen!(
"38",
"Susan Smith",
"latrobest_190",
Pronouns::default_female()
),
citizen!(
"39",
"Susan Martin",
"collinsst_150",
Pronouns::default_female()
),
citizen!(
"40",
"Linda Scott",
"williamsst_30",
Pronouns::default_female()
),
citizen!(
"41",
"Donald Miller",
"elizabethst_80",
Pronouns::default_male()
),
citizen!("42", "Mark Hill", "collinsst_120", Pronouns::default_male()),
citizen!(
"43",
"William Perez",
"queenst_90",
Pronouns::default_male()
),
citizen!(
"44",
"Donald Perez",
"queenst_lonsdalest",
Pronouns::default_male()
),
citizen!(
"45",
"Lisa Rodriguez",
"collinsst_100",
Pronouns::default_female()
),
citizen!(
"46",
"James Adams",
"latrobest_150",
Pronouns::default_male()
),
citizen!(
"47",
"James Moore",
"latrobest_130",
Pronouns::default_male()
),
citizen!(
"48",
"Joseph Martin",
"bourkest_150",
Pronouns::default_male()
),
citizen!("49", "Matthew Jones", "kingst_60", Pronouns::default_male()),
citizen!(
"50",
"Michael Sanchez",
"queenst_100",
Pronouns::default_male()
),
citizen!(
"51",
"Donna Torres",
"flindersst_150",
Pronouns::default_female()
),
citizen!(
"52",
"Barbara Garcia",
"swanstonst_50",
Pronouns::default_female()
),
citizen!(
"53",
"Daniel Miller",
"bourkest_110",
Pronouns::default_male()
),
citizen!(
"54",
"Robert Young",
"kingst_collinsst",
Pronouns::default_male()
),
citizen!(
"55",
"Donald Flores",
"swanstonst_40",
Pronouns::default_male()
),
citizen!(
"56",
"Charles Thomas",
"flindersst_110",
Pronouns::default_male()
),
citizen!(
"57",
"William Torres",
"swanstonst_60",
Pronouns::default_male()
),
citizen!(
"58",
"Barbara Gonzalez",
"collinsst_190",
Pronouns::default_female()
),
citizen!(
"59",
"Mary Smith",
"bourkest_180",
Pronouns::default_female()
),
citizen!(
"60",
"Michael John",
"williamsst_110",
Pronouns::default_male()
),
]
).collect()
}

View File

@ -0,0 +1,240 @@
- code: "1"
name: Matthew Thomas
spawn_loc: kingst_latrobest
gender: Male
- code: "2"
name: Matthew Perez
spawn_loc: kingst_20
gender: Male
- code: "3"
name: Kimberly Jackson
spawn_loc: kingst_40
gender: Female
- code: "4"
name: Michael Sanchez
spawn_loc: kingst_50
gender: Male
- code: "5"
name: Jessica Davis
spawn_loc: kingst_bourkest
gender: Female
- code: "6"
name: Robert Davis
spawn_loc: kingst_70
gender: Male
- code: "7"
name: Paul Lewis
spawn_loc: kingst_90
gender: Male
- code: "8"
name: Andrew Moore
spawn_loc: kingst_collinsst
gender: Male
- code: "9"
name: Betty Thomas
spawn_loc: kingst_100
gender: Female
- code: "10"
name: Mary Robinson
spawn_loc: kingst_110
gender: Female
- code: "11"
name: Lisa Lopez
spawn_loc: kingst_flinderst
gender: Female
- code: "12"
name: Kimberly Martinez
spawn_loc: flindersst_200
gender: Female
- code: "13"
name: Anthony Nguyen
spawn_loc: flindersst_190
gender: Male
- code: "14"
name: Joshua Green
spawn_loc: flindersst_180
gender: Male
- code: "15"
name: Emily Wright
spawn_loc: flindersst_170
gender: Female
- code: "16"
name: Ashley Thomas
spawn_loc: lonsdalest_130
gender: Male
- code: "17"
name: Jessica Miller
spawn_loc: kingst_80
gender: Female
- code: "18"
name: Anthony Lopez
spawn_loc: lonsdalest_140
gender: Male
- code: "19"
name: John Lopez
spawn_loc: elizabethst_lonsdalest
gender: Male
- code: "20"
name: Thomas Garcia
spawn_loc: williamsst_120
gender: Male
- code: "21"
name: Donna Thompson
spawn_loc: elizabethst_60
gender: Female
- code: "22"
name: Matthew Davis
spawn_loc: williamsst_100
gender: Male
- code: "23"
name: Steven Jones
spawn_loc: swanstonst_120
gender: Male
- code: "24"
name: Linda Smith
spawn_loc: swanstonst_lonsdalest
gender: Male
- code: "25"
name: Karen Rodriguez
spawn_loc: bourkest_180
gender: Female
- code: "26"
name: Paul Scott
spawn_loc: swanstonst_70
gender: Male
- code: "27"
name: Ashley Thomas
spawn_loc: lonsdalest_130
gender: Male
- code: "28"
name: Sandra Scott
spawn_loc: elizabethst_30
gender: Female
- code: "29"
name: Michael Rodriguez
spawn_loc: swanstonst_70
gender: Male
- code: "30"
name: Donald Miller
spawn_loc: elizabethst_30
gender: Male
- code: "31"
name: Charles Moore
spawn_loc: lonsdalest_160
gender: Male
- code: "32"
name: Ashley Sanchez
spawn_loc: kingst_100
gender: Male
- code: "33"
name: Margaret Lewis
spawn_loc: flindersst_180
gender: Female
- code: "34"
name: Sandra Thompson
spawn_loc: swanstonst_80
gender: Female
- code: "35"
name: Sandra King
spawn_loc: lonsdalest_150
gender: Female
- code: "36"
name: Lisa Anderson
spawn_loc: lonsdalest_210
gender: Female
- code: "37"
name: Kimberly Martin
spawn_loc: kingst_80
gender: Female
- code: "38"
name: Susan Smith
spawn_loc: latrobest_190
gender: Female
- code: "39"
name: Susan Martin
spawn_loc: collinsst_150
gender: Female
- code: "40"
name: Linda Scott
spawn_loc: williamsst_30
gender: Female
- code: "41"
name: Donald Miller
spawn_loc: elizabethst_80
gender: Male
- code: "42"
name: Mark Hill
spawn_loc: collinsst_120
gender: Male
- code: "43"
name: William Perez
spawn_loc: queenst_90
gender: Male
- code: "44"
name: Donald Perez
spawn_loc: queenst_lonsdalest
gender: Male
- code: "45"
name: Lisa Rodriguez
spawn_loc: collinsst_100
gender: Female
- code: "46"
name: James Adams
spawn_loc: latrobest_150
gender: Male
- code: "47"
name: James Moore
spawn_loc: latrobest_130
gender: Male
- code: "48"
name: Joseph Martin
spawn_loc: bourkest_150
gender: Male
- code: "49"
name: Matthew Jones
spawn_loc: kingst_60
gender: Male
- code: "50"
name: Michael Sanchez
spawn_loc: queenst_100
gender: Male
- code: "51"
name: Donna Torres
spawn_loc: flindersst_150
gender: Female
- code: "52"
name: Barbara Garcia
spawn_loc: swanstonst_50
gender: Female
- code: "53"
name: Daniel Miller
spawn_loc: bourkest_110
gender: Male
- code: "54"
name: Robert Young
spawn_loc: kingst_collinsst
gender: Male
- code: "55"
name: Donald Flores
spawn_loc: swanstonst_40
gender: Male
- code: "56"
name: Charles Thomas
spawn_loc: flindersst_110
gender: Male
- code: "57"
name: William Torres
spawn_loc: swanstonst_60
gender: Male
- code: "58"
name: Barbara Gonzalez
spawn_loc: collinsst_190
gender: Female
- code: "59"
name: Mary Smith
spawn_loc: bourkest_180
gender: Female
- code: "60"
name: Michael John
spawn_loc: williamsst_110
gender: Male

View File

@ -1,91 +1,38 @@
use super::{KillBonus, NPC};
use crate::models::{consent::ConsentType, item::Pronouns};
use crate::static_content::{possession_type::PossessionType, species::SpeciesType};
use serde::Deserialize;
use serde_yaml::from_str as from_yaml_str;
macro_rules! dog {
($code:expr, $adj:expr, $spawn: expr) => {
NPC {
code: concat!("melbs_dog_", $code),
name: concat!($adj, " dog"),
pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() },
aggression: 12,
wander_zones: vec!("melbs"),
description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.",
aliases: vec!("dog"),
spawn_location: concat!("room/", $spawn),
intrinsic_weapon: Some(PossessionType::Fangs),
species: SpeciesType::Dog,
kill_bonus: Some(KillBonus {
msg: "On your wristpad: Thank you for helping Melbs with animal control! Here's your fee.",
payment: 100,
}),
player_consents: vec!(ConsentType::Fight),
..Default::default()
}
}
#[derive(Deserialize)]
struct MelbsDog {
code: String,
adjectives: String,
spawn_room: String,
}
pub fn npc_list() -> Vec<NPC> {
vec![
dog!("1", "smelly black", "melbs_williamsst_80"),
dog!("2", "howling black", "melbs_swanstonst_100"),
dog!("3", "smelly black", "melbs_collinsst_160"),
dog!("4", "growling light brown", "melbs_kingst_40"),
dog!("5", "ferocious white", "melbs_swanstonst_110"),
dog!("6", "mangy grey", "melbs_kingst_30"),
dog!("7", "reeking light brown", "melbs_flindersst_210"),
dog!("8", "feral brown", "melbs_elizabethst_40"),
dog!("9", "reeking grey", "melbs_collinsst_190"),
dog!("10", "ferocious grey", "melbs_kingst_60"),
dog!("11", "howling brown", "melbs_collinsst_140"),
dog!("12", "feral black", "melbs_flindersst_160"),
dog!("13", "smelly grey", "melbs_queenst_80"),
dog!("14", "howling grey", "melbs_kingst_70"),
dog!("15", "smelly grey", "melbs_flindersst_110"),
dog!("16", "feral black", "melbs_queenst_latrobest"),
dog!("17", "howling grey", "melbs_swanstonst_110"),
dog!("18", "mangy grey", "melbs_swanstonst_80"),
dog!("19", "reeking light brown", "melbs_latrobest_180"),
dog!("20", "smelly white", "melbs_flindersst_130"),
dog!("21", "reeking grey", "melbs_flindersst_180"),
dog!("22", "growling brown", "melbs_williamsst_80"),
dog!("23", "howling black", "melbs_lonsdalest_100"),
dog!("24", "growling grey", "melbs_latrobest_140"),
dog!("25", "howling light brown", "melbs_queenst_30"),
dog!("26", "howling black", "melbs_latrobest_160"),
dog!("27", "howling grey", "melbs_collinsst_170"),
dog!("28", "growling brown", "melbs_elizabethst_latrobest"),
dog!("29", "mangy brown", "melbs_kingst_70"),
dog!("30", "growling black", "melbs_swanstonst_120"),
dog!("31", "reeking light brown", "melbs_latrobest_130"),
dog!("32", "howling white", "melbs_bourkest_160"),
dog!("33", "growling black", "melbs_elizabethst_50"),
dog!("34", "mangy black", "melbs_swanstonst_110"),
dog!("35", "ferocious grey", "melbs_collinsst_100"),
dog!("36", "mangy grey", "melbs_flindersst_100"),
dog!("37", "growling brown", "melbs_swanstonst_flindersst"),
dog!("38", "mangy light brown", "melbs_lonsdalest_200"),
dog!("39", "howling light brown", "melbs_flindersst_210"),
dog!("40", "mangy light brown", "melbs_queenst_flindersst"),
dog!("41", "reeking white", "melbs_collinsst_130"),
dog!("42", "growling light brown", "melbs_lonsdalest_130"),
dog!("43", "reeking light brown", "melbs_elizabethst_70"),
dog!("44", "mangy brown", "melbs_swanstonst_30"),
dog!("45", "growling light brown", "melbs_swanstonst_lonsdalest"),
dog!("46", "smelly brown", "melbs_queenst_lonsdalest"),
dog!("47", "growling white", "melbs_elizabethst_bourkest"),
dog!("48", "feral brown", "melbs_collinsst_140"),
dog!("49", "ferocious black", "melbs_lonsdalest_150"),
dog!("50", "mangy grey", "melbs_kingst_collinsst"),
dog!("51", "ferocious brown", "melbs_kingst_120"),
dog!("52", "growling white", "melbs_elizabethst_10"),
dog!("53", "ferocious white", "melbs_lonsdalest_190"),
dog!("54", "smelly grey", "melbs_kingst_collinsst"),
dog!("55", "reeking light brown", "melbs_elizabethst_90"),
dog!("56", "reeking grey", "melbs_swanstonst_20"),
dog!("57", "feral brown", "melbs_flindersst_180"),
dog!("58", "reeking brown", "melbs_bourkest_130"),
dog!("59", "mangy light brown", "melbs_queenst_50"),
dog!("60", "growling white", "melbs_kingst_110"),
]
from_yaml_str::<Vec<MelbsDog>>(include_str!("melbs_dog.yaml"))
.unwrap()
.into_iter()
.map(|d|
NPC {
code: format!("melbs_dog_{}", &d.code),
name: format!("{} dog", &d.adjectives),
pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() },
aggression: 12,
wander_zones: vec!("melbs".to_owned()),
description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.".to_owned(),
aliases: vec!("dog".to_owned()),
spawn_location: format!("room/{}", d.spawn_room),
intrinsic_weapon: Some(PossessionType::Fangs),
species: SpeciesType::Dog,
kill_bonus: Some(KillBonus {
msg: "On your wristpad: Thank you for helping Melbs with animal control! Here's your fee.",
payment: 100,
}),
player_consents: vec!(ConsentType::Fight),
..Default::default()
}
).collect()
}

View File

@ -0,0 +1,180 @@
- code: "1"
adjectives: smelly black
spawn_room: melbs_williamsst_80
- code: "2"
adjectives: howling black
spawn_room: melbs_swanstonst_100
- code: "3"
adjectives: smelly black
spawn_room: melbs_collinsst_160
- code: "4"
adjectives: growling light brown
spawn_room: melbs_kingst_40
- code: "5"
adjectives: ferocious white
spawn_room: melbs_swanstonst_110
- code: "6"
adjectives: mangy grey
spawn_room: melbs_kingst_30
- code: "7"
adjectives: reeking light brown
spawn_room: melbs_flindersst_210
- code: "8"
adjectives: feral brown
spawn_room: melbs_elizabethst_40
- code: "9"
adjectives: reeking grey
spawn_room: melbs_collinsst_190
- code: "10"
adjectives: ferocious grey
spawn_room: melbs_kingst_60
- code: "11"
adjectives: howling brown
spawn_room: melbs_collinsst_140
- code: "12"
adjectives: feral black
spawn_room: melbs_flindersst_160
- code: "13"
adjectives: smelly grey
spawn_room: melbs_queenst_80
- code: "14"
adjectives: howling grey
spawn_room: melbs_kingst_70
- code: "15"
adjectives: smelly grey
spawn_room: melbs_flindersst_110
- code: "16"
adjectives: feral black
spawn_room: melbs_queenst_latrobest
- code: "17"
adjectives: howling grey
spawn_room: melbs_swanstonst_110
- code: "18"
adjectives: mangy grey
spawn_room: melbs_swanstonst_80
- code: "19"
adjectives: reeking light brown
spawn_room: melbs_latrobest_180
- code: "20"
adjectives: smelly white
spawn_room: melbs_flindersst_130
- code: "21"
adjectives: reeking grey
spawn_room: melbs_flindersst_180
- code: "22"
adjectives: growling brown
spawn_room: melbs_williamsst_80
- code: "23"
adjectives: howling black
spawn_room: melbs_lonsdalest_100
- code: "24"
adjectives: growling grey
spawn_room: melbs_latrobest_140
- code: "25"
adjectives: howling light brown
spawn_room: melbs_queenst_30
- code: "26"
adjectives: howling black
spawn_room: melbs_latrobest_160
- code: "27"
adjectives: howling grey
spawn_room: melbs_collinsst_170
- code: "28"
adjectives: growling brown
spawn_room: melbs_elizabethst_latrobest
- code: "29"
adjectives: mangy brown
spawn_room: melbs_kingst_70
- code: "30"
adjectives: growling black
spawn_room: melbs_swanstonst_120
- code: "31"
adjectives: reeking light brown
spawn_room: melbs_latrobest_130
- code: "32"
adjectives: howling white
spawn_room: melbs_bourkest_160
- code: "33"
adjectives: growling black
spawn_room: melbs_elizabethst_50
- code: "34"
adjectives: mangy black
spawn_room: melbs_swanstonst_110
- code: "35"
adjectives: ferocious grey
spawn_room: melbs_collinsst_100
- code: "36"
adjectives: mangy grey
spawn_room: melbs_flindersst_100
- code: "37"
adjectives: growling brown
spawn_room: melbs_swanstonst_flindersst
- code: "38"
adjectives: mangy light brown
spawn_room: melbs_lonsdalest_200
- code: "39"
adjectives: howling light brown
spawn_room: melbs_flindersst_210
- code: "40"
adjectives: mangy light brown
spawn_room: melbs_queenst_flindersst
- code: "41"
adjectives: reeking white
spawn_room: melbs_collinsst_130
- code: "42"
adjectives: growling light brown
spawn_room: melbs_lonsdalest_130
- code: "43"
adjectives: reeking light brown
spawn_room: melbs_elizabethst_70
- code: "44"
adjectives: mangy brown
spawn_room: melbs_swanstonst_30
- code: "45"
adjectives: growling light brown
spawn_room: melbs_swanstonst_lonsdalest
- code: "46"
adjectives: smelly brown
spawn_room: melbs_queenst_lonsdalest
- code: "47"
adjectives: growling white
spawn_room: melbs_elizabethst_bourkest
- code: "48"
adjectives: feral brown
spawn_room: melbs_collinsst_140
- code: "49"
adjectives: ferocious black
spawn_room: melbs_lonsdalest_150
- code: "50"
adjectives: mangy grey
spawn_room: melbs_kingst_collinsst
- code: "51"
adjectives: ferocious brown
spawn_room: melbs_kingst_120
- code: "52"
adjectives: growling white
spawn_room: melbs_elizabethst_10
- code: "53"
adjectives: ferocious white
spawn_room: melbs_lonsdalest_190
- code: "54"
adjectives: smelly grey
spawn_room: melbs_kingst_collinsst
- code: "55"
adjectives: reeking light brown
spawn_room: melbs_elizabethst_90
- code: "56"
adjectives: reeking grey
spawn_room: melbs_swanstonst_20
- code: "57"
adjectives: feral brown
spawn_room: melbs_flindersst_180
- code: "58"
adjectives: reeking brown
spawn_room: melbs_bourkest_130
- code: "59"
adjectives: mangy light brown
spawn_room: melbs_queenst_50
- code: "60"
adjectives: growling white
spawn_room: melbs_kingst_110

View File

@ -14,9 +14,17 @@ use crate::{
use ansi::ansi;
use async_trait::async_trait;
use mockall_double::double;
use serde::Deserialize;
use serde_yaml::from_str as from_yaml_str;
struct RoboporterHandler;
#[derive(Deserialize)]
struct RoboporterDesc {
code: String,
spawn_room: String,
}
#[async_trait]
impl HireHandler for RoboporterHandler {
async fn hire_handler(
@ -77,7 +85,7 @@ impl HireHandler for RoboporterHandler {
let old_location = target.location.clone();
if let Some(return_to) = npc_by_code()
.get(target.item_code.as_str())
.map(|npc| npc.spawn_location)
.map(|npc| npc.spawn_location.as_str())
{
if return_to != &target.location {
target.location = return_to.to_owned();
@ -103,40 +111,28 @@ impl HireHandler for RoboporterHandler {
static ROBOPORTER_HANDLER: RoboporterHandler = RoboporterHandler;
macro_rules! roboporter {
($code:expr, $spawn: expr) => {
NPC {
code: concat!("roboporter_", $code),
name: concat!("Roboporter ", $code),
pronouns: Pronouns { is_proper: true, ..Pronouns::default_inanimate() },
description: "Standing at an imposing height of over 5 metres, and as wide as a truck, the Roboporter is a marvel of mechanical engineering. Its sturdy metallic frame is built for strength and endurance, with hydraulic joints that allow for precise movements. The body is covered in scuffs and scratches, evidence of its relentless hauling duties.\n\nEquipped with a plethora of massive storage compartments, the Roboporter was clearly designed to carry large and heavy loads with ease. Its reinforced chassis and powerful motors enable it to traverse all terrains, from rubble-strewn streets to treacherous wastelands. It seems to have hinges all over it so it can dynamically transform its shape to sqeeze through doors and haul cargo into indoor spaces too. The faint hum of its internal machinery is ever-present, a testament to its unwavering efficiency.\n\nThe Roboporter's front panel displays a digital interface, showcasing real-time diagnostics and its current operational status. A pair of bright LED lights function as its eyes, pulsating with a soft glow. It lacks any human-like features, emphasizing its purely functional design.\n\nDespite its lack of emotions, the Roboporter exudes an aura of dependability and reliability. It stands as a symbol of resilience in a world ravaged by chaos, ready to assist survivors in their quest for survival.",
aliases: vec!("roboporter"),
spawn_location: concat!("room/", $spawn),
intrinsic_weapon: Some(PossessionType::Fangs),
species: SpeciesType::Robot,
hire_data: Some(HireData {
handler: &ROBOPORTER_HANDLER,
frequency_secs: 600,
price: 100,
}),
extra_flags: vec![ItemFlag::CanLoad],
total_stats: vec![(StatType::Brawn, 20.0)].into_iter().collect(),
..Default::default()
}
}
}
pub fn npc_list() -> Vec<NPC> {
vec![
roboporter!("1", "melbs_roboporter_rentals"),
roboporter!("2", "melbs_roboporter_rentals"),
roboporter!("3", "melbs_roboporter_rentals"),
roboporter!("4", "melbs_roboporter_rentals"),
roboporter!("5", "melbs_roboporter_rentals"),
roboporter!("6", "melbs_roboporter_rentals"),
roboporter!("7", "melbs_roboporter_rentals"),
roboporter!("8", "melbs_roboporter_rentals"),
roboporter!("9", "melbs_roboporter_rentals"),
roboporter!("10", "melbs_roboporter_rentals"),
]
from_yaml_str::<Vec<RoboporterDesc>>(include_str!("roboporter.yaml"))
.unwrap()
.into_iter()
.map(|rp|
NPC {
code: format!("roboporter_{}", &rp.code),
name: format!("Roboporter {}", &rp.code),
pronouns: Pronouns { is_proper: true, ..Pronouns::default_inanimate() },
description: "Standing at an imposing height of over 5 metres, and as wide as a truck, the Roboporter is a marvel of mechanical engineering. Its sturdy metallic frame is built for strength and endurance, with hydraulic joints that allow for precise movements. The body is covered in scuffs and scratches, evidence of its relentless hauling duties.\n\nEquipped with a plethora of massive storage compartments, the Roboporter was clearly designed to carry large and heavy loads with ease. Its reinforced chassis and powerful motors enable it to traverse all terrains, from rubble-strewn streets to treacherous wastelands. It seems to have hinges all over it so it can dynamically transform its shape to sqeeze through doors and haul cargo into indoor spaces too. The faint hum of its internal machinery is ever-present, a testament to its unwavering efficiency.\n\nThe Roboporter's front panel displays a digital interface, showcasing real-time diagnostics and its current operational status. A pair of bright LED lights function as its eyes, pulsating with a soft glow. It lacks any human-like features, emphasizing its purely functional design.\n\nDespite its lack of emotions, the Roboporter exudes an aura of dependability and reliability. It stands as a symbol of resilience in a world ravaged by chaos, ready to assist survivors in their quest for survival.".to_owned(),
aliases: vec!("roboporter".to_owned()),
spawn_location: format!("room/{}", &rp.spawn_room),
intrinsic_weapon: Some(PossessionType::Fangs),
species: SpeciesType::Robot,
hire_data: Some(HireData {
handler: &ROBOPORTER_HANDLER,
frequency_secs: 600,
price: 100,
}),
extra_flags: vec![ItemFlag::CanLoad],
total_stats: vec![(StatType::Brawn, 20.0)].into_iter().collect(),
..Default::default()
}
).collect()
}

View File

@ -0,0 +1,20 @@
- code: "1"
spawn_room: melbs_roboporter_rentals
- code: "2"
spawn_room: melbs_roboporter_rentals
- code: "3"
spawn_room: melbs_roboporter_rentals
- code: "4"
spawn_room: melbs_roboporter_rentals
- code: "5"
spawn_room: melbs_roboporter_rentals
- code: "6"
spawn_room: melbs_roboporter_rentals
- code: "7"
spawn_room: melbs_roboporter_rentals
- code: "8"
spawn_room: melbs_roboporter_rentals
- code: "9"
spawn_room: melbs_roboporter_rentals
- code: "10"
spawn_room: melbs_roboporter_rentals

View File

@ -563,7 +563,7 @@ pub fn room_map_by_zloc() -> &'static BTreeMap<(&'static str, &'static GridCoord
pub fn room_static_items() -> Box<dyn Iterator<Item = StaticItem>> {
Box::new(room_list().iter().map(|r| StaticItem {
item_code: &r.code,
item_code: r.code.clone(),
initial_item: Box::new(|| Item {
item_code: r.code.to_owned(),
item_type: "room".to_owned(),

View File

@ -9,7 +9,7 @@ edition = "2021"
blastmud_interfaces = { path = "../blastmud_interfaces" }
futures = "0.3.25"
log = "0.4.17"
nix = "0.26.2"
nix = "0.27.1"
once_cell = "1.17.0"
rand = "0.8.5"
serde = { version = "1.0.149", features = ["derive", "serde_derive"] }