From 5d3c8bc0aa251d63eec23b69f8dcc81fdf7bea3d Mon Sep 17 00:00:00 2001 From: Shagnor Date: Sun, 15 Jan 2023 17:30:23 +1100 Subject: [PATCH] Allow attacks to be started. --- Cargo.lock | 12 + blastmud_game/Cargo.toml | 1 + blastmud_game/src/db.rs | 3 +- blastmud_game/src/language.rs | 20 + .../src/message_handler/user_commands.rs | 8 + .../message_handler/user_commands/attack.rs | 105 ++++ .../src/message_handler/user_commands/look.rs | 19 +- .../src/message_handler/user_commands/say.rs | 4 +- blastmud_game/src/models/item.rs | 65 +- blastmud_game/src/static_content/npc.rs | 7 +- .../src/static_content/npc/melbs_dog.rs | 554 +++--------------- scripts/npc-chargen/gennpc-dog.hs | 10 +- 12 files changed, 294 insertions(+), 514 deletions(-) create mode 100644 blastmud_game/src/message_handler/user_commands/attack.rs diff --git a/Cargo.lock b/Cargo.lock index e84eeb22..334f969b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,6 +48,17 @@ dependencies = [ "syn", ] +[[package]] +name = "async-recursion" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cda8f4bcc10624c4e85bc66b3f452cca98cfa5ca002dc83a16aad2367641bea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-trait" version = "0.1.60" @@ -111,6 +122,7 @@ name = "blastmud_game" version = "0.1.0" dependencies = [ "ansi", + "async-recursion", "async-trait", "base64 0.20.0", "bcrypt", diff --git a/blastmud_game/Cargo.toml b/blastmud_game/Cargo.toml index e6bd7801..07e38e6b 100644 --- a/blastmud_game/Cargo.toml +++ b/blastmud_game/Cargo.toml @@ -35,3 +35,4 @@ validator = "0.16.0" itertools = "0.10.5" once_cell = "1.16.0" rand = "0.8.5" +async-recursion = "1.0.0" diff --git a/blastmud_game/src/db.rs b/blastmud_game/src/db.rs index c543745f..05025dc2 100644 --- a/blastmud_game/src/db.rs +++ b/blastmud_game/src/db.rs @@ -285,7 +285,8 @@ impl DBTrans { // Only copy more permanent fields, others are supposed to change over time and shouldn't // be reset on restart. for to_copy in ["display", "display_less_explicit", "details", "details_less_explicit", - "total_xp", "total_stats", "total_skills", "pronouns", "flags"] { + "total_xp", "total_stats", "total_skills", "pronouns", "flags", + "sex", "is_challenge_attack_only"] { det_ex = format!("jsonb_set({}, '{{{}}}', ${})", det_ex, to_copy, var_id); params.push(obj_map.get(to_copy).unwrap_or(&Value::Null)); var_id += 1; diff --git a/blastmud_game/src/language.rs b/blastmud_game/src/language.rs index 2770ffb1..3db2ee0a 100644 --- a/blastmud_game/src/language.rs +++ b/blastmud_game/src/language.rs @@ -53,6 +53,14 @@ pub fn pluralise(input: &str) -> String { input.to_owned() + "s" } +pub fn caps_first(inp: &str) -> String { + if inp.is_empty() { + "".to_string() + } else { + inp[0..1].to_uppercase() + &inp[1..] + } +} + #[cfg(test)] mod test { #[test] @@ -76,4 +84,16 @@ mod test { assert_eq!(super::pluralise(word), plural); } } + + #[test] + fn caps_first_works() { + for (inp, outp) in vec!( + ("", ""), + ("cat", "Cat"), + ("Cat", "Cat"), + ("hello world", "Hello world"), + ) { + assert_eq!(super::caps_first(inp), outp); + } + } } diff --git a/blastmud_game/src/message_handler/user_commands.rs b/blastmud_game/src/message_handler/user_commands.rs index fe5c9f84..c0d5fe54 100644 --- a/blastmud_game/src/message_handler/user_commands.rs +++ b/blastmud_game/src/message_handler/user_commands.rs @@ -10,6 +10,7 @@ use once_cell::sync::OnceCell; use std::sync::Arc; mod agree; +pub mod attack; mod describe; mod help; mod ignore; @@ -96,13 +97,20 @@ static REGISTERED_COMMANDS: UserVerbRegistry = phf_map! { "down" => movement::VERB, // Other commands (alphabetical except aliases grouped): + "attack" => attack::VERB, + "kill" => attack::VERB, + "k" => attack::VERB, + "describe" => describe::VERB, "l" => look::VERB, "look" => look::VERB, "read" => look::VERB, + "lmap" => map::VERB, + "\'" => say::VERB, "say" => say::VERB, + "-" => whisper::VERB, "whisper" => whisper::VERB, "tell" => whisper::VERB, diff --git a/blastmud_game/src/message_handler/user_commands/attack.rs b/blastmud_game/src/message_handler/user_commands/attack.rs new file mode 100644 index 00000000..ce21fae1 --- /dev/null +++ b/blastmud_game/src/message_handler/user_commands/attack.rs @@ -0,0 +1,105 @@ +use super::{VerbContext, UserVerb, UserVerbRef, UResult, user_error, + get_player_item_or_fail, search_item_for_user}; +use async_trait::async_trait; +use ansi::ansi; +use crate::services::broadcast_to_room; +use crate::db::{DBTrans, ItemSearchParams}; +use crate::models::{item::{Item, LocationActionType, Subattack}}; +use async_recursion::async_recursion; + +#[async_recursion] +async fn start_attack(trans: &DBTrans, by_whom: &Item, to_whom: &Item) -> UResult<()> { + let mut msg_exp = String::new(); + let mut msg_nonexp = String::new(); + let mut verb: String = "attacks".to_string(); + match by_whom.action_type { + LocationActionType::Sitting | LocationActionType::Reclining => { + msg_exp.push_str(&format!(ansi!("{} stands up.\n"), &by_whom.display)); + msg_nonexp.push_str(&format!(ansi!("{} stands up.\n"), + by_whom.display_less_explicit.as_ref().unwrap_or(&by_whom.display))); + }, + LocationActionType::Attacking(_) => { + match by_whom.active_combat.as_ref().and_then(|ac| ac.attacking.as_ref().and_then(|s| s.split_once("/"))) { + Some((cur_type, cur_code)) if cur_type == to_whom.item_type && cur_code == to_whom.item_code => + user_error(format!("You're already attacking {}!", to_whom.pronouns.object))?, + Some((cur_type, cur_code)) => { + if let Some(cur_item_arc) = trans.find_item_by_type_code(cur_type, cur_code).await? { + let mut cur_item = (*cur_item_arc).clone(); + if let Some(ac) = cur_item.active_combat.as_mut() { + let old_attacker = format!("{}/{}", by_whom.item_type, by_whom.item_code); + ac.attacked_by.retain(|v| v != &old_attacker); + trans.save_item_model(&cur_item).await?; + } + } + } + _ => {} + } + verb = "refocuses ".to_string() + &by_whom.pronouns.possessive + " attacks on"; + }, + _ => {} + } + msg_exp.push_str(&format!( + ansi!("{} {} {}.\n"), + &by_whom.display_for_sentence(true, 1, true), + verb, + &to_whom.display_for_sentence(true, 1, false)) + ); + msg_nonexp.push_str(&format!( + ansi!("{} {} {}.\n"), + &by_whom.display_for_sentence(false, 1, true), + verb, + &to_whom.display_for_sentence(false, 1, false)) + ); + broadcast_to_room(trans, &by_whom.location, None, &msg_exp, Some(msg_nonexp.as_str())).await?; + + let mut by_whom_for_update = by_whom.clone(); + by_whom_for_update.active_combat.get_or_insert_with(|| Default::default()).attacking = + Some(format!("{}/{}", + &to_whom.item_type, &to_whom.item_code)); + by_whom_for_update.action_type = LocationActionType::Attacking(Subattack::Normal); + let mut to_whom_for_update = to_whom.clone(); + to_whom_for_update.active_combat.get_or_insert_with(|| Default::default()).attacked_by.push( + format!("{}/{}", + &by_whom.item_type, &by_whom.item_code) + ); + + trans.save_item_model(&by_whom_for_update).await?; + trans.save_item_model(&to_whom_for_update).await?; + // Auto-counterattack if victim isn't busy. + if to_whom_for_update.active_combat.as_ref().and_then(|ac| ac.attacking.as_ref()) == None { + start_attack(trans, &to_whom_for_update, &by_whom_for_update).await?; + } + + Ok(()) +} + +pub struct Verb; +#[async_trait] +impl UserVerb for Verb { + async fn handle(self: &Self, ctx: &mut VerbContext, _verb: &str, remaining: &str) -> UResult<()> { + let player_item = get_player_item_or_fail(ctx).await?; + let attack_whom = search_item_for_user(ctx, &ItemSearchParams { + include_loc_contents: true, + ..ItemSearchParams::base(&player_item, remaining) + }).await?; + + match attack_whom.item_type.as_str() { + "npc" => {} + "player" => {}, + _ => user_error("Only characters (players / NPCs) accept whispers".to_string())? + } + + if attack_whom.item_code == player_item.item_code && attack_whom.item_type == player_item.item_type { + user_error("That's you, silly!".to_string())? + } + + if attack_whom.is_challenge_attack_only { + // Add challenge check here. + user_error(ansi!("Your wristpad vibrates and blocks you from doing that. You get a feeling that while the empire might be gone, the system to stop subjects with working wristpads from fighting each unless they have an accepted challenge very much functional. [Try help challenge]").to_string())? + } + + start_attack(&ctx.trans, &player_item, &attack_whom).await + } +} +static VERB_INT: Verb = Verb; +pub static VERB: UserVerbRef = &VERB_INT as UserVerbRef; diff --git a/blastmud_game/src/message_handler/user_commands/look.rs b/blastmud_game/src/message_handler/user_commands/look.rs index 5682147e..97e42050 100644 --- a/blastmud_game/src/message_handler/user_commands/look.rs +++ b/blastmud_game/src/message_handler/user_commands/look.rs @@ -7,7 +7,6 @@ use crate::models::{item::{Item, LocationActionType, Subattack, ItemFlag}}; use crate::static_content::room::{self, Direction}; use itertools::Itertools; use std::sync::Arc; -use crate::language::pluralise; pub fn render_map(room: &room::Room, width: usize, height: usize) -> String { let mut buf = String::new(); @@ -43,7 +42,7 @@ pub async fn describe_normal_item(ctx: &VerbContext<'_>, item: &Item) -> UResult ctx.trans.queue_for_session( ctx.session, Some(&format!("{}\n{}\n", - item.display_for_session(&ctx.session_dat), + &item.display_for_session(&ctx.session_dat), item.details_for_session(&ctx.session_dat).unwrap_or("") )) ).await?; @@ -85,7 +84,7 @@ async fn list_item_contents<'l>(ctx: &'l VerbContext<'_>, item: &'l Item) -> URe let all_groups: Vec>> = items .iter() - .group_by(|i| &i.display) + .group_by(|i| i.display_for_sentence(true, 1, false)) .into_iter() .map(|(_, g)|g.collect::>>()) .collect::>>>(); @@ -94,16 +93,8 @@ async fn list_item_contents<'l>(ctx: &'l VerbContext<'_>, item: &'l Item) -> URe let head = &group_items[0]; let is_creature = head.item_type == "player" || head.item_type.starts_with("npc"); buf.push(' '); - if group_items.len() > 1 { - buf.push_str(&format!("{} ", group_items.len())) - } else if !head.pronouns.is_proper { - buf.push_str("A "); - } - let mut disp = head.display_for_session(&ctx.session_dat).to_owned(); - if group_items.len() > 1 { - disp = pluralise(&disp); - } - buf.push_str(&disp); + buf.push_str(&head.display_for_sentence(!ctx.session_dat.less_explicit_mode, + group_items.len(), true)); buf.push_str(if group_items.len() > 1 { " are " } else { " is "}); match head.action_type { LocationActionType::Sitting => buf.push_str("sitting "), @@ -129,7 +120,7 @@ async fn list_item_contents<'l>(ctx: &'l VerbContext<'_>, item: &'l Item) -> URe match ctx.trans.find_item_by_type_code(ttype, tcode).await? { None => buf.push_str("someone"), Some(it) => buf.push_str( - it.display_for_session(&ctx.session_dat) + &it.display_for_session(&ctx.session_dat) ) } } diff --git a/blastmud_game/src/message_handler/user_commands/say.rs b/blastmud_game/src/message_handler/user_commands/say.rs index c61e488b..6a746d4c 100644 --- a/blastmud_game/src/message_handler/user_commands/say.rs +++ b/blastmud_game/src/message_handler/user_commands/say.rs @@ -26,12 +26,12 @@ pub async fn say_to_room<'l>( } let msg_exp = format!( ansi!("{} says: \"{}\"\n"), - from_item.display, + from_item.display_for_sentence(true, 1, true), say_what ); let msg_lessexp = format!( ansi!("{} says: \"{}\"\n"), - from_item.display_less_explicit.as_ref().unwrap_or(&from_item.display), + from_item.display_for_sentence(false, 1, true), say_what ); diff --git a/blastmud_game/src/models/item.rs b/blastmud_game/src/models/item.rs index fdf41833..7b4a7f12 100644 --- a/blastmud_game/src/models/item.rs +++ b/blastmud_game/src/models/item.rs @@ -1,5 +1,6 @@ use serde::{Serialize, Deserialize}; use std::collections::BTreeMap; +use crate::language; use super::{user::{SkillType, StatType}, session::Session}; #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] @@ -97,7 +98,7 @@ pub enum LocationActionType { Reclining, Worn, // Clothing etc... Wielded, - Attacking(Subattack), + Attacking(Subattack) } #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] @@ -112,6 +113,22 @@ pub enum ItemFlag { NoSeeContents } +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] +#[serde(default)] +pub struct ActiveCombat { + pub attacking: Option, + pub attacked_by: Vec +} + +impl Default for ActiveCombat { + fn default() -> Self { + Self { + attacking: None, + attacked_by: vec!() + } + } +} + #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] #[serde(default)] pub struct Item { @@ -125,7 +142,9 @@ pub struct Item { pub action_type: LocationActionType, pub presence_target: Option, // e.g. what are they sitting on. pub is_static: bool, - + pub is_dead: bool, + pub is_challenge_attack_only: bool, + pub total_xp: u64, pub total_stats: BTreeMap, pub total_skills: BTreeMap, @@ -133,12 +152,41 @@ pub struct Item { pub pronouns: Pronouns, pub flags: Vec, pub sex: Option, + pub active_combat: Option, } impl Item { - pub fn display_for_session<'l>(self: &'l Self, session: &Session) -> &'l str { - session.explicit_if_allowed(&self.display, - self.display_less_explicit.as_ref().map(String::as_str)) + pub fn display_for_sentence(&self, explicit_ok: bool, pluralise: usize, caps: bool) -> String { + let mut buf = String::new(); + if self.is_dead { + if pluralise > 1 { + buf.push_str("the bodies of "); + } else { + buf.push_str("the body of "); + } + } + if !self.pronouns.is_proper && pluralise == 1 { + buf.push_str("a "); + } + if pluralise > 1 { + buf.push_str(&format!("{} ", pluralise)); + } + let singular = if explicit_ok { &self.display } else { + self.display_less_explicit.as_ref().unwrap_or(&self.display) }; + if pluralise > 1 { + buf.push_str(&language::pluralise(singular)); + } else { + buf.push_str(singular); + } + + if caps { + language::caps_first(&buf) + } else { + buf + } + } + pub fn display_for_session<'l>(self: &'l Self, session: &Session) -> String { + self.display_for_sentence(!session.less_explicit_mode, 1, false) } pub fn details_for_session<'l>(self: &'l Self, session: &Session) -> Option<&'l str>{ @@ -154,7 +202,7 @@ impl Item { impl Default for Item { fn default() -> Self { - Item { + Self { item_code: "unset".to_owned(), item_type: "unset".to_owned(), display: "Item".to_owned(), @@ -165,13 +213,16 @@ impl Default for Item { action_type: LocationActionType::Normal, presence_target: None, is_static: false, + is_dead: false, + is_challenge_attack_only: true, total_xp: 0, total_stats: BTreeMap::new(), total_skills: BTreeMap::new(), temporary_buffs: Vec::new(), pronouns: Pronouns::default_inanimate(), flags: vec!(), - sex: None + sex: None, + active_combat: Some(Default::default()), } } } diff --git a/blastmud_game/src/static_content/npc.rs b/blastmud_game/src/static_content/npc.rs index f39fbe93..d3c750fb 100644 --- a/blastmud_game/src/static_content/npc.rs +++ b/blastmud_game/src/static_content/npc.rs @@ -52,7 +52,8 @@ pub struct NPC { pub description: &'static str, pub spawn_location: &'static str, pub message_handler: Option<&'static (dyn NPCMessageHandler + Sync + Send)>, - pub says: Vec + pub says: Vec, + pub attackable: bool } impl Default for NPC { @@ -64,7 +65,8 @@ impl Default for NPC { description: "default", spawn_location: "default", message_handler: None, - says: vec!() + says: vec!(), + attackable: false } } } @@ -121,6 +123,7 @@ pub fn npc_static_items() -> Box> { location: c.spawn_location.to_owned(), is_static: true, pronouns: c.pronouns.clone(), + is_challenge_attack_only: !c.attackable, ..Item::default() }) })) diff --git a/blastmud_game/src/static_content/npc/melbs_dog.rs b/blastmud_game/src/static_content/npc/melbs_dog.rs index 1698d1b0..dd1eb337 100644 --- a/blastmud_game/src/static_content/npc/melbs_dog.rs +++ b/blastmud_game/src/static_content/npc/melbs_dog.rs @@ -1,487 +1,81 @@ use super::NPC; use crate::models::item::Pronouns; +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() }, + attackable: true, + description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", + spawn_location: concat!("room/", $spawn), + ..Default::default() + } + } +} + pub fn npc_list() -> Vec { vec!( - NPC { - code: "melbs_dog_1", - name: "feral black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_elizabethst_collinsst", - ..Default::default() - }, - NPC { - code: "melbs_dog_2", - name: "howling black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_collinsst_100", - ..Default::default() - }, - NPC { - code: "melbs_dog_3", - name: "ferocious white dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_elizabethst_lonsdalest", - ..Default::default() - }, - NPC { - code: "melbs_dog_4", - name: "mangy grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_collinsst_160", - ..Default::default() - }, - NPC { - code: "melbs_dog_5", - name: "howling grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_lonsdalest_100", - ..Default::default() - }, - NPC { - code: "melbs_dog_6", - name: "reeking black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_lonsdalest_120", - ..Default::default() - }, - NPC { - code: "melbs_dog_7", - name: "growling grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_williamsst_20", - ..Default::default() - }, - NPC { - code: "melbs_dog_8", - name: "mangy black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_bourkest_120", - ..Default::default() - }, - NPC { - code: "melbs_dog_9", - name: "howling black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_collinsst_100", - ..Default::default() - }, - NPC { - code: "melbs_dog_10", - name: "howling brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_flindersst_130", - ..Default::default() - }, - NPC { - code: "melbs_dog_11", - name: "ferocious black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_flindersst_100", - ..Default::default() - }, - NPC { - code: "melbs_dog_12", - name: "mangy grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_elizabethst_90", - ..Default::default() - }, - NPC { - code: "melbs_dog_13", - name: "reeking light brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_lonsdalest_140", - ..Default::default() - }, - NPC { - code: "melbs_dog_14", - name: "smelly black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_queenst_20", - ..Default::default() - }, - NPC { - code: "melbs_dog_15", - name: "growling light brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_elizabethst_10", - ..Default::default() - }, - NPC { - code: "melbs_dog_16", - name: "howling brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_swanstonst_flindersst", - ..Default::default() - }, - NPC { - code: "melbs_dog_17", - name: "feral brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_kingst_latrobest", - ..Default::default() - }, - NPC { - code: "melbs_dog_18", - name: "smelly grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_kingst_40", - ..Default::default() - }, - NPC { - code: "melbs_dog_19", - name: "feral black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_elizabethst_60", - ..Default::default() - }, - NPC { - code: "melbs_dog_20", - name: "smelly white dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_swanstonst_120", - ..Default::default() - }, - NPC { - code: "melbs_dog_21", - name: "growling white dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_elizabethst_90", - ..Default::default() - }, - NPC { - code: "melbs_dog_22", - name: "feral light brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_lonsdalest_150", - ..Default::default() - }, - NPC { - code: "melbs_dog_23", - name: "mangy grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_lonsdalest_150", - ..Default::default() - }, - NPC { - code: "melbs_dog_24", - name: "reeking grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_elizabethst_100", - ..Default::default() - }, - NPC { - code: "melbs_dog_25", - name: "smelly grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_bourkest_180", - ..Default::default() - }, - NPC { - code: "melbs_dog_26", - name: "growling light brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_queenst_100", - ..Default::default() - }, - NPC { - code: "melbs_dog_27", - name: "feral light brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_queenst_10", - ..Default::default() - }, - NPC { - code: "melbs_dog_28", - name: "feral grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_lonsdalest_160", - ..Default::default() - }, - NPC { - code: "melbs_dog_29", - name: "reeking brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_bourkest_110", - ..Default::default() - }, - NPC { - code: "melbs_dog_30", - name: "howling grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_queenst_80", - ..Default::default() - }, - NPC { - code: "melbs_dog_31", - name: "howling brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_bourkest_160", - ..Default::default() - }, - NPC { - code: "melbs_dog_32", - name: "feral black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_swanstonst_collinsst", - ..Default::default() - }, - NPC { - code: "melbs_dog_33", - name: "reeking brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_kingst_flinderst", - ..Default::default() - }, - NPC { - code: "melbs_dog_34", - name: "reeking white dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_elizabethst_100", - ..Default::default() - }, - NPC { - code: "melbs_dog_35", - name: "growling light brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_queenst_110", - ..Default::default() - }, - NPC { - code: "melbs_dog_36", - name: "reeking black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_williamsst_90", - ..Default::default() - }, - NPC { - code: "melbs_dog_37", - name: "growling black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_latrobesst_200", - ..Default::default() - }, - NPC { - code: "melbs_dog_38", - name: "feral black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_queenst_90", - ..Default::default() - }, - NPC { - code: "melbs_dog_39", - name: "mangy black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_queenst_40", - ..Default::default() - }, - NPC { - code: "melbs_dog_40", - name: "growling white dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_williamsst_40", - ..Default::default() - }, - NPC { - code: "melbs_dog_41", - name: "reeking grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_queenst_latrobest", - ..Default::default() - }, - NPC { - code: "melbs_dog_42", - name: "mangy grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_flindersst_210", - ..Default::default() - }, - NPC { - code: "melbs_dog_43", - name: "ferocious brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_kingst_latrobest", - ..Default::default() - }, - NPC { - code: "melbs_dog_44", - name: "ferocious light brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_collinsst_120", - ..Default::default() - }, - NPC { - code: "melbs_dog_45", - name: "ferocious light brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_swanstonst_lonsdalest", - ..Default::default() - }, - NPC { - code: "melbs_dog_46", - name: "smelly grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_williamsst_30", - ..Default::default() - }, - NPC { - code: "melbs_dog_47", - name: "growling grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_lonsdalest_100", - ..Default::default() - }, - NPC { - code: "melbs_dog_48", - name: "ferocious brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_latrobest_210", - ..Default::default() - }, - NPC { - code: "melbs_dog_49", - name: "reeking brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_latrobest_140", - ..Default::default() - }, - NPC { - code: "melbs_dog_50", - name: "howling grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_swanstonst_110", - ..Default::default() - }, - NPC { - code: "melbs_dog_51", - name: "howling black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_elizabethst_flindersst", - ..Default::default() - }, - NPC { - code: "melbs_dog_52", - name: "growling light brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_flindersst_120", - ..Default::default() - }, - NPC { - code: "melbs_dog_53", - name: "ferocious black dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_queenst_110", - ..Default::default() - }, - NPC { - code: "melbs_dog_54", - name: "growling grey dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_flindersst_210", - ..Default::default() - }, - NPC { - code: "melbs_dog_55", - name: "reeking brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_williamsst_60", - ..Default::default() - }, - NPC { - code: "melbs_dog_56", - name: "ferocious white dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_queenst_lonsdalest", - ..Default::default() - }, - NPC { - code: "melbs_dog_57", - name: "smelly brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_swanstonst_lonsdalest", - ..Default::default() - }, - NPC { - code: "melbs_dog_58", - name: "mangy white dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_williamsst_bourkest", - ..Default::default() - }, - NPC { - code: "melbs_dog_59", - name: "mangy brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_latrobest_170", - ..Default::default() - }, - NPC { - code: "melbs_dog_60", - name: "growling brown dog", - pronouns: Pronouns { is_proper: false, ..Pronouns::default_inanimate() }, - description: "A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.", - spawn_location: "room/melbs_williamsst_110", - ..Default::default() - }, + 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"), ) } diff --git a/scripts/npc-chargen/gennpc-dog.hs b/scripts/npc-chargen/gennpc-dog.hs index 5bb9f5fd..0b5c949f 100644 --- a/scripts/npc-chargen/gennpc-dog.hs +++ b/scripts/npc-chargen/gennpc-dog.hs @@ -156,14 +156,8 @@ rooms = [ character :: Int -> T.Text -> T.Text -> T.Text character id adjective room = - " NPC {\n\ - \ code: \"melbs_dog_" <> (T.pack $ show id) <> "\",\n\ - \ name: \"" <> adjective <> " dog\",\n\ - \ proper_noun: false,\n\ - \ description: \"A malnourished looking dog. Its skeleton is visible through its thin and patchy fur. It smells terrible, and certainly doesn't look tame.\",\n\ - \ spawn_location: \"room/" <> room <> "\",\n\ - \ ..Default::default()\n\ - \ },\n" + " dog!(\"" <> (T.pack $ show id) <> "\", \"" <> adjective <> + "\", \"" <> room <> "\"),\n" chooseFromList :: [a] -> IO a chooseFromList l = (l!!) <$> randomRIO (0, length l - 1)