initiative_core/world/place/building/religious/
shrine.rs

1use crate::utils::pluralize;
2use crate::world::place::PlaceData;
3use crate::world::{word, word::ListGenerator, Demographics};
4use rand::prelude::*;
5
6pub fn generate(place: &mut PlaceData, rng: &mut impl Rng, _demographics: &Demographics) {
7    place.name.replace_with(|_| name(rng));
8}
9
10fn name(rng: &mut impl Rng) -> String {
11    match rng.gen_range(0..10) {
12        0..=3 => format!("The {} {}", descriptor(rng), place(rng)),
13        4..=7 => format!("{} of {}", place(rng), deity(rng)),
14        8 => {
15            let (animal, s) = pluralize(word::animal(rng));
16            format!("Place Where the {}{} {}", animal, s, action(rng))
17        }
18        9 => {
19            let (animal, s) = pluralize(word::animal(rng));
20            format!("{} of the {} {}{}", place(rng), number(rng), animal, s)
21        }
22        _ => unreachable!(),
23    }
24}
25
26//place of worship can be a building or a natural feature
27fn place(rng: &mut impl Rng) -> &'static str {
28    match rng.gen_range(0..6) {
29        0..=2 => "Shrine",
30        3..=4 => building(rng),
31        5 => feature(rng),
32        _ => unreachable!(),
33    }
34}
35
36//commonly worshipped places
37fn building(rng: &mut impl Rng) -> &'static str {
38    ListGenerator(&[
39        "Altar", "Pagoda", "Gate", "Obelisk", "Pagoda", "Pillar", "Pillars",
40    ])
41    .gen(rng)
42}
43
44//less common places of worship, typically natural formations
45#[rustfmt::skip]
46fn feature(rng: &mut impl Rng) -> &'static str {
47    ListGenerator(&[
48        "Basin","Cavern","Grove","Pond","Pool","Menhir",
49        "Grotto","Cenote", "Tree", "Stones", "Cave"
50    ]).gen(rng)
51}
52
53//DESCRIPTOR can be an ADJECTIVE or an ACTION
54fn descriptor(rng: &mut impl Rng) -> String {
55    match rng.gen_range(0..3) {
56        0..=1 => word::adjective(rng).to_string(),
57        2 => gerund(action(rng)),
58        _ => unreachable!(),
59    }
60}
61
62//ACTION
63#[rustfmt::skip]
64fn action(rng: &mut impl Rng) -> String {
65    ListGenerator(&[
66        "Dance","Whisper","Shiver","Rot","Rise","Fall","Laugh","Travel","Creep",
67        "Sing","Fade","Glow","Shine","Stand","Weep","Drown","Howl","Smile","Hunt",
68        "Burn","Return","Dream","Wake","Slumber"
69    ]).gen(rng).to_string()
70}
71
72fn gerund(verb: String) -> String {
73    let last_char = verb.chars().last().unwrap();
74    let last_two_chars = &verb[verb.len() - 2..verb.len()];
75    if last_char == 'e' {
76        format!("{}ing", &verb[..verb.len() - 1])
77    } else if last_two_chars == "ot" {
78        format!("{}ting", &verb)
79    } else if last_two_chars == "el" {
80        format!("{}ling", &verb)
81    } else {
82        format!("{}ing", verb)
83    }
84}
85
86#[rustfmt::skip]
87fn number(rng: &mut impl Rng) -> &'static str {
88    ListGenerator(&[
89        "Two","Three","Four","Five","Six","Seven","Eight","Eight-and-a-Half","Nine",
90        "Twelve","Thirty-Six", "Forty","Seventy-Two","Nine-and-Twenty", "Ninety-Nine","Thousand","Thousand-Thousand"
91    ]).gen(rng)
92}
93
94//DEITY can be PERSON, ANIMAL, or DIVINE CONCEPT
95fn deity(rng: &mut impl Rng) -> String {
96    match rng.gen_range(0..10) {
97        0..=1 => format!("the {}", word::person(rng)),
98        2 => format!("the {} {}", descriptor(rng), word::person(rng)),
99        3..=4 => format!("the {}", word::animal(rng)),
100        5 => format!("the {} {}", descriptor(rng), word::animal(rng)),
101        6..=8 => concept(rng).to_string(),
102        9 => format!("{} {}", descriptor(rng), concept(rng)),
103        _ => unreachable!(),
104    }
105}
106
107//DIVINE CONCEPT are more abstract stuff that doesn't go well with "the" in front of it.
108#[rustfmt::skip]
109fn concept(rng: &mut impl Rng) -> &'static str {
110    ListGenerator(&[
111        "Love","Knowledge","Wisdom","Truth","Justice","Mercy","Protection","Healing","Strength","Courage",
112        "Fortune","Prosperity","Storms","Fire","Water","Earth","Air","Dreams","Music","Poetry","Dance",
113        "Ancestors","Transcendence","Anguish","Blight","Confessions","Connections","Courage","Decay",
114        "Lore","Silence","Triumph","Wisdom","Mending","Healing","Judgement","Forgiveness","Justice","Textiles", 
115    ]).gen(rng)
116}
117
118#[cfg(test)]
119mod test {
120    use super::*;
121
122    #[test]
123    fn name_test() {
124        let mut rng = SmallRng::seed_from_u64(0);
125
126        assert_eq!(
127            [
128                "Shrine of the Pelican",
129                "Place Where the Weasels Drown",
130                "The Gold Pillar",
131                "The Singing Cave",
132                "The Fading Basin",
133                "The Grey Gate",
134                "The Creeping Shrine",
135                "The Red Shrine",
136                "Pillar of the Five Camels",
137                "The Wasted Pagoda",
138                "Shrine of the Empress",
139                "The Singing Shrine",
140                "Place Where the Unicorns Weep",
141                "Gate of the Emperor",
142                "The Orange Tree",
143                "The Creeping Shrine",
144                "Gate of the Thirty-Six Rams",
145                "Shrine of the Wild Cat",
146                "The Wasted Altar",
147                "Shrine of Forgiveness"
148            ]
149            .iter()
150            .map(|s| s.to_string())
151            .collect::<Vec<_>>(),
152            (0..20).map(|_| name(&mut rng)).collect::<Vec<String>>(),
153        );
154    }
155}