Use correct indefinite article in possession descriptions.

This commit is contained in:
Condorra 2023-02-20 00:02:29 +11:00
parent 7d8c236f3f
commit b28ea26d8a
6 changed files with 103 additions and 9 deletions

View File

@ -234,7 +234,8 @@ pub struct ItemSearchParams<'l> {
pub include_contents: bool, pub include_contents: bool,
pub include_loc_contents: bool, pub include_loc_contents: bool,
pub include_active_players: bool, pub include_active_players: bool,
pub include_all_players: bool pub include_all_players: bool,
pub dead_first: bool,
} }
impl ItemSearchParams<'_> { impl ItemSearchParams<'_> {
@ -244,7 +245,8 @@ impl ItemSearchParams<'_> {
include_contents: false, include_contents: false,
include_loc_contents: false, include_loc_contents: false,
include_active_players: false, include_active_players: false,
include_all_players: false include_all_players: false,
dead_first: false,
} }
} }
} }

View File

@ -54,6 +54,60 @@ pub fn pluralise(input: &str) -> String {
input.to_owned() + "s" input.to_owned() + "s"
} }
pub fn indefinite_article(countable_word: &str) -> &'static str {
if countable_word.is_empty() {
return "";
}
let vowels = ["a", "e", "i", "o", "u"];
if !vowels.contains(&&countable_word[0..1]) {
if countable_word.starts_with("honor") || countable_word.starts_with("honour") ||
countable_word.starts_with("honest") || countable_word.starts_with("hour") ||
countable_word.starts_with("heir") {
return "an";
}
return "a";
}
if countable_word.starts_with("eu") || countable_word.starts_with("one") ||
countable_word.starts_with("once") {
return "a";
}
if countable_word.starts_with("e") {
if countable_word.starts_with("ewe") {
return "a";
}
return "an";
}
if countable_word.starts_with("u") {
if countable_word.len() < 3 {
return "an";
}
if countable_word.starts_with("uni") {
if countable_word.starts_with("unid") ||
countable_word.starts_with("unim") ||
countable_word.starts_with("unin") {
// unidentified, unimaginable, uninhabited etc...
return "an";
}
// Words like unilateral
return "a";
}
if countable_word.starts_with("unani") || countable_word.starts_with("ubiq") {
return "a";
}
if ["r", "s", "t"].contains(&&countable_word[1..2]) {
if vowels.contains(&&countable_word[2..3]) {
// All u[rst][aeiou] words, e.g. usury, need "a"
return "a";
}
return "an";
}
if countable_word.starts_with("ubiq") || countable_word.starts_with("uku") || countable_word.starts_with("ukr") {
return "a"
}
}
return "an";
}
pub fn caps_first(inp: &str) -> String { pub fn caps_first(inp: &str) -> String {
if inp.is_empty() { if inp.is_empty() {
"".to_string() "".to_string()
@ -102,6 +156,36 @@ mod test {
} }
} }
#[test]
fn indefinite_article_should_follow_english_rules() {
for (article, word) in vec!(
("a", "cat"),
("a", "human"),
("an", "apple"),
("an", "easter egg"),
("an", "indigo orb"),
("an", "orange"),
("an", "urchin"),
("an", "hour"),
("a", "once-in-a-lifetime opportunity"),
("a", "uranium-covered field"),
("a", "usurper to the throne"),
("a", "Ukrainian hero"),
("a", "universal truth"),
("an", "uninvited guest"),
("a", "unanimous decision"),
("a", "European getaway"),
("an", "utter disaster"),
("a", "uterus"),
("a", "user"),
("a", "ubiquitous hazard"),
("a", "unitary plan"),
) {
let result = super::indefinite_article(&word.to_lowercase());
assert_eq!(format!("{} {}", result, word), format!("{} {}", article, word));
}
}
#[test] #[test]
fn caps_first_works() { fn caps_first_works() {
for (inp, outp) in vec!( for (inp, outp) in vec!(

View File

@ -254,6 +254,7 @@ pub async fn search_item_for_user<'l>(ctx: &'l VerbContext<'l>, search: &'l Item
trans: &trans, trans: &trans,
session_dat: &mut session_dat, session_dat: &mut session_dat,
user_dat: &mut user_dat }; user_dat: &mut user_dat };
resolve_handler(&ctx, "less_explicit_mode"); assert_eq!(resolve_handler(&ctx, "less_explicit_mode").is_some(),
true);
} }
} }

View File

@ -3,6 +3,7 @@ use super::{VerbContext, UserVerb, UserVerbRef, UResult, user_error,
use crate::{ use crate::{
static_content::room, static_content::room,
static_content::possession_type::possession_data, static_content::possession_type::possession_data,
language
}; };
use async_trait::async_trait; use async_trait::async_trait;
use ansi::ansi; use ansi::ansi;
@ -38,7 +39,8 @@ impl UserVerb for Verb {
let display = if ctx.session_dat.less_explicit_mode { let display = if ctx.session_dat.less_explicit_mode {
possession_type.display_less_explicit.as_ref().unwrap_or(&possession_type.display) possession_type.display_less_explicit.as_ref().unwrap_or(&possession_type.display)
} else { &possession_type.display }; } else { &possession_type.display };
msg.push_str(&format!("| {:20} | {:15.2} |\n", display, &stock.list_price)) msg.push_str(&format!("| {:20} | {:15.2} |\n",
&language::caps_first(&display), &stock.list_price))
} }
} }
msg.push_str(ansi!("\nUse <bold>buy<reset> item to purchase something.\n")); msg.push_str(ansi!("\nUse <bold>buy<reset> item to purchase something.\n"));

View File

@ -314,14 +314,15 @@ impl Item {
buf.push_str("the body of "); buf.push_str("the body of ");
} }
} }
let singular = if explicit_ok { &self.display } else {
self.display_less_explicit.as_ref().unwrap_or(&self.display) };
if !self.pronouns.is_proper && pluralise == 1 { if !self.pronouns.is_proper && pluralise == 1 {
buf.push_str("a "); buf.push_str(language::indefinite_article(&singular));
buf.push(' ');
} }
if pluralise > 1 { if pluralise > 1 {
buf.push_str(&format!("{} ", pluralise)); 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 { if pluralise > 1 {
buf.push_str(&language::pluralise(singular)); buf.push_str(&language::pluralise(singular));
} else { } else {

View File

@ -1,6 +1,6 @@
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use crate::{ use crate::{
models::item::{SkillType, Item} models::item::{SkillType, Item, Pronouns}
}; };
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use std::collections::BTreeMap; use std::collections::BTreeMap;
@ -123,6 +123,10 @@ impl Into<Item> for PossessionType {
aliases: possession_dat.aliases.iter().map(|al| (*al).to_owned()).collect(), aliases: possession_dat.aliases.iter().map(|al| (*al).to_owned()).collect(),
health: possession_dat.max_health, health: possession_dat.max_health,
weight: possession_dat.weight, weight: possession_dat.weight,
pronouns: Pronouns {
is_proper: false,
..Pronouns::default_inanimate()
},
..Default::default() ..Default::default()
} }
} }
@ -191,7 +195,7 @@ pub fn possession_data() -> &'static BTreeMap<PossessionType, PossessionData> {
..Default::default() ..Default::default()
}), }),
(AntennaWhip, PossessionData { (AntennaWhip, PossessionData {
display: "Antenna whip", display: "antenna whip",
details: "A crudely fashioned whip made from a broken metal antenna. It looks a bit flimsy, but it \ details: "A crudely fashioned whip made from a broken metal antenna. It looks a bit flimsy, but it \
might do you until you get a better weapon!", might do you until you get a better weapon!",
aliases: vec!("whip"), aliases: vec!("whip"),