feat(citygen): flavor pack and theme table
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
158
crates/citygen/src/flavor.rs
Normal file
158
crates/citygen/src/flavor.rs
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
//! Flavor pack: names and signage glyphs, loaded from RON.
|
||||||
|
|
||||||
|
use crate::params::GenError;
|
||||||
|
use crate::world::{BuildingKind, Theme};
|
||||||
|
use rand::Rng;
|
||||||
|
use rand::seq::IndexedRandom;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
const DEFAULT_PACK: &str = include_str!("../../../flavor/names.ron");
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct NameParts {
|
||||||
|
pub prefixes: Vec<String>,
|
||||||
|
pub suffixes: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct CorpParts {
|
||||||
|
pub first: Vec<String>,
|
||||||
|
pub second: Vec<String>,
|
||||||
|
pub suffix: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct FlavorPack {
|
||||||
|
pub city: NameParts,
|
||||||
|
pub districts: Vec<(Theme, NameParts)>,
|
||||||
|
pub corp: CorpParts,
|
||||||
|
pub shops: Vec<(BuildingKind, Vec<String>)>,
|
||||||
|
pub landmarks: Vec<String>,
|
||||||
|
pub signage: Vec<char>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pick<'a>(rng: &mut impl Rng, items: &'a [String]) -> &'a str {
|
||||||
|
items.choose(rng).map(String::as_str).unwrap_or("")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn capitalize(s: &str) -> String {
|
||||||
|
let mut chars = s.chars();
|
||||||
|
match chars.next() {
|
||||||
|
Some(c) => c.to_uppercase().chain(chars).collect(),
|
||||||
|
None => String::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlavorPack {
|
||||||
|
/// Loads a named pack. Only `default` is built in.
|
||||||
|
pub fn load(name: &str) -> Result<FlavorPack, GenError> {
|
||||||
|
match name {
|
||||||
|
"default" => FlavorPack::parse(DEFAULT_PACK),
|
||||||
|
other => Err(GenError::Flavor(format!("unknown flavor pack `{other}`"))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(text: &str) -> Result<FlavorPack, GenError> {
|
||||||
|
let pack: FlavorPack = ron::from_str(text).map_err(|e| GenError::Flavor(e.to_string()))?;
|
||||||
|
if pack.signage.is_empty() || pack.city.prefixes.is_empty() || pack.city.suffixes.is_empty()
|
||||||
|
{
|
||||||
|
return Err(GenError::Flavor(
|
||||||
|
"flavor pack is missing required lists".into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(pack)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn city_name(&self, rng: &mut impl Rng) -> String {
|
||||||
|
format!(
|
||||||
|
"{}{}",
|
||||||
|
pick(rng, &self.city.prefixes),
|
||||||
|
pick(rng, &self.city.suffixes)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn district_name(&self, theme: Theme, rng: &mut impl Rng) -> String {
|
||||||
|
match self.districts.iter().find(|(t, _)| *t == theme) {
|
||||||
|
Some((_, parts)) => format!(
|
||||||
|
"{}{}",
|
||||||
|
pick(rng, &parts.prefixes),
|
||||||
|
pick(rng, &parts.suffixes)
|
||||||
|
),
|
||||||
|
None => format!("{} {}", theme.label(), rng.random_range(1..100)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn corp_name(&self, rng: &mut impl Rng) -> String {
|
||||||
|
let stem = format!(
|
||||||
|
"{}{}",
|
||||||
|
pick(rng, &self.corp.first),
|
||||||
|
pick(rng, &self.corp.second)
|
||||||
|
);
|
||||||
|
format!("{}{}", capitalize(&stem), pick(rng, &self.corp.suffix))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A two-syllable made-up word for shop names.
|
||||||
|
fn syllable_word(&self, rng: &mut impl Rng) -> String {
|
||||||
|
let stem = format!(
|
||||||
|
"{}{}",
|
||||||
|
pick(rng, &self.corp.first).to_lowercase(),
|
||||||
|
pick(rng, &self.corp.second)
|
||||||
|
);
|
||||||
|
capitalize(&stem)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shop_name(&self, kind: BuildingKind, rng: &mut impl Rng) -> Option<String> {
|
||||||
|
let (_, templates) = self.shops.iter().find(|(k, _)| *k == kind)?;
|
||||||
|
let template = pick(rng, templates);
|
||||||
|
let word = self.syllable_word(rng);
|
||||||
|
Some(template.replace("{syl}", &word))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn landmark_name(&self, corp: &str, district: &str, rng: &mut impl Rng) -> String {
|
||||||
|
pick(rng, &self.landmarks)
|
||||||
|
.replace("{corp}", corp)
|
||||||
|
.replace("{district}", district)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sign_glyph(&self, rng: &mut impl Rng) -> char {
|
||||||
|
*self.signage.choose(rng).unwrap_or(&'#')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::rng::stage_rng;
|
||||||
|
use crate::world::{BuildingKind, Theme};
|
||||||
|
|
||||||
|
fn unicode_single_width(c: char) -> bool {
|
||||||
|
let u = c as u32;
|
||||||
|
u >= 0x20
|
||||||
|
&& !(0x1100..=0x115F).contains(&u)
|
||||||
|
&& !(0x2E80..=0xA4CF).contains(&u)
|
||||||
|
&& !(0xAC00..=0xD7A3).contains(&u)
|
||||||
|
&& !(0xF900..=0xFAFF).contains(&u)
|
||||||
|
&& !(0xFE30..=0xFE4F).contains(&u)
|
||||||
|
&& !(0xFF00..=0xFF60).contains(&u)
|
||||||
|
&& !(0xFFE0..=0xFFE6).contains(&u)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_flavor_loads_and_names_are_deterministic() {
|
||||||
|
let f = FlavorPack::load("default").unwrap();
|
||||||
|
assert!(FlavorPack::load("nope").is_err());
|
||||||
|
let mut a = stage_rng(7, 9);
|
||||||
|
let mut b = stage_rng(7, 9);
|
||||||
|
assert_eq!(f.city_name(&mut a), f.city_name(&mut b));
|
||||||
|
for t in Theme::ALL {
|
||||||
|
assert!(!f.district_name(t, &mut a).is_empty());
|
||||||
|
}
|
||||||
|
assert!(f.shop_name(BuildingKind::NoodleBar, &mut a).is_some());
|
||||||
|
assert!(f.shop_name(BuildingKind::CorpTower, &mut a).is_none());
|
||||||
|
assert!(!f.corp_name(&mut a).is_empty());
|
||||||
|
assert!(f.landmark_name("Kirotek", "Apex Plaza", &mut a).len() > 5);
|
||||||
|
assert!(f.signage.iter().all(|c| unicode_single_width(*c)));
|
||||||
|
assert!(f.signage.len() >= 40);
|
||||||
|
let _ = f.sign_glyph(&mut a);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,22 @@
|
|||||||
//! World model and generator for the cyberpunk city.
|
//! World model and generator for the cyberpunk city.
|
||||||
|
|
||||||
|
pub mod flavor;
|
||||||
pub mod geom;
|
pub mod geom;
|
||||||
pub mod ids;
|
pub mod ids;
|
||||||
pub mod net;
|
pub mod net;
|
||||||
pub mod params;
|
pub mod params;
|
||||||
pub mod rng;
|
pub mod rng;
|
||||||
|
pub mod theme;
|
||||||
pub mod tile;
|
pub mod tile;
|
||||||
pub mod validate;
|
pub mod validate;
|
||||||
pub mod world;
|
pub mod world;
|
||||||
|
|
||||||
|
pub use flavor::FlavorPack;
|
||||||
pub use geom::{Dir, Grid, Pos, Rect, Size};
|
pub use geom::{Dir, Grid, Pos, Rect, Size};
|
||||||
pub use ids::*;
|
pub use ids::*;
|
||||||
pub use net::*;
|
pub use net::*;
|
||||||
pub use params::*;
|
pub use params::*;
|
||||||
|
pub use theme::*;
|
||||||
pub use tile::*;
|
pub use tile::*;
|
||||||
pub use validate::*;
|
pub use validate::*;
|
||||||
pub use world::*;
|
pub use world::*;
|
||||||
|
|||||||
271
crates/citygen/src/theme.rs
Normal file
271
crates/citygen/src/theme.rs
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
//! Static per-theme generation parameters.
|
||||||
|
|
||||||
|
use crate::tile::Hue;
|
||||||
|
use crate::world::{BuildingKind, HeightClass, Theme};
|
||||||
|
|
||||||
|
/// How a district carves its streets.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum StreetStyle {
|
||||||
|
Grid,
|
||||||
|
Organic,
|
||||||
|
Superblock,
|
||||||
|
Rows,
|
||||||
|
Shattered,
|
||||||
|
Strip,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tunables for one theme. Fractions are probabilities in 0..1.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ThemeSpec {
|
||||||
|
pub base_wealth: f32,
|
||||||
|
pub base_decay: f32,
|
||||||
|
pub street_style: StreetStyle,
|
||||||
|
/// Target block size (w, h).
|
||||||
|
pub block: (i32, i32),
|
||||||
|
/// Minimum lot size (w, h).
|
||||||
|
pub min_lot: (i32, i32),
|
||||||
|
pub mix: &'static [(BuildingKind, u32)],
|
||||||
|
pub tall: f32,
|
||||||
|
pub mid: f32,
|
||||||
|
pub basement: f32,
|
||||||
|
pub plaza: f32,
|
||||||
|
pub neon: f32,
|
||||||
|
pub holo: f32,
|
||||||
|
pub lamp_spacing: i32,
|
||||||
|
pub security: u8,
|
||||||
|
pub hues: &'static [Hue],
|
||||||
|
}
|
||||||
|
|
||||||
|
use BuildingKind as B;
|
||||||
|
|
||||||
|
static CORP_CORE: ThemeSpec = ThemeSpec {
|
||||||
|
base_wealth: 0.9,
|
||||||
|
base_decay: 0.1,
|
||||||
|
street_style: StreetStyle::Grid,
|
||||||
|
block: (24, 12),
|
||||||
|
min_lot: (10, 7),
|
||||||
|
mix: &[
|
||||||
|
(B::CorpTower, 5),
|
||||||
|
(B::Office, 4),
|
||||||
|
(B::Hotel, 1),
|
||||||
|
(B::Parking, 1),
|
||||||
|
],
|
||||||
|
tall: 0.7,
|
||||||
|
mid: 0.3,
|
||||||
|
basement: 0.6,
|
||||||
|
plaza: 0.25,
|
||||||
|
neon: 0.3,
|
||||||
|
holo: 0.5,
|
||||||
|
lamp_spacing: 8,
|
||||||
|
security: 200,
|
||||||
|
hues: &[Hue::Cyan, Hue::White, Hue::Blue],
|
||||||
|
};
|
||||||
|
static NIGHT_MARKET: ThemeSpec = ThemeSpec {
|
||||||
|
base_wealth: 0.4,
|
||||||
|
base_decay: 0.5,
|
||||||
|
street_style: StreetStyle::Organic,
|
||||||
|
block: (16, 9),
|
||||||
|
min_lot: (5, 4),
|
||||||
|
mix: &[
|
||||||
|
(B::Shop, 4),
|
||||||
|
(B::NoodleBar, 4),
|
||||||
|
(B::Bar, 2),
|
||||||
|
(B::Market, 2),
|
||||||
|
(B::Clinic, 1),
|
||||||
|
(B::Pawn, 1),
|
||||||
|
(B::Apartment, 2),
|
||||||
|
],
|
||||||
|
tall: 0.05,
|
||||||
|
mid: 0.3,
|
||||||
|
basement: 0.1,
|
||||||
|
plaza: 0.3,
|
||||||
|
neon: 0.8,
|
||||||
|
holo: 0.3,
|
||||||
|
lamp_spacing: 12,
|
||||||
|
security: 60,
|
||||||
|
hues: &[Hue::Magenta, Hue::Orange, Hue::Yellow],
|
||||||
|
};
|
||||||
|
static MEGABLOCKS: ThemeSpec = ThemeSpec {
|
||||||
|
base_wealth: 0.3,
|
||||||
|
base_decay: 0.6,
|
||||||
|
street_style: StreetStyle::Superblock,
|
||||||
|
block: (40, 20),
|
||||||
|
min_lot: (18, 10),
|
||||||
|
mix: &[(B::Megablock, 6), (B::Apartment, 3), (B::Shop, 1)],
|
||||||
|
tall: 0.9,
|
||||||
|
mid: 0.1,
|
||||||
|
basement: 0.5,
|
||||||
|
plaza: 0.1,
|
||||||
|
neon: 0.2,
|
||||||
|
holo: 0.2,
|
||||||
|
lamp_spacing: 10,
|
||||||
|
security: 110,
|
||||||
|
hues: &[Hue::Yellow, Hue::White, Hue::Orange],
|
||||||
|
};
|
||||||
|
static COMBAT_ZONE: ThemeSpec = ThemeSpec {
|
||||||
|
base_wealth: 0.1,
|
||||||
|
base_decay: 0.9,
|
||||||
|
street_style: StreetStyle::Shattered,
|
||||||
|
block: (16, 10),
|
||||||
|
min_lot: (5, 4),
|
||||||
|
mix: &[
|
||||||
|
(B::Apartment, 3),
|
||||||
|
(B::Shop, 2),
|
||||||
|
(B::Bar, 2),
|
||||||
|
(B::Pawn, 2),
|
||||||
|
(B::Clinic, 1),
|
||||||
|
(B::Garage, 1),
|
||||||
|
],
|
||||||
|
tall: 0.05,
|
||||||
|
mid: 0.2,
|
||||||
|
basement: 0.1,
|
||||||
|
plaza: 0.15,
|
||||||
|
neon: 0.3,
|
||||||
|
holo: 0.05,
|
||||||
|
lamp_spacing: 16,
|
||||||
|
security: 20,
|
||||||
|
hues: &[Hue::Red, Hue::Yellow, Hue::Orange],
|
||||||
|
};
|
||||||
|
static DOCKS: ThemeSpec = ThemeSpec {
|
||||||
|
base_wealth: 0.3,
|
||||||
|
base_decay: 0.6,
|
||||||
|
street_style: StreetStyle::Rows,
|
||||||
|
block: (30, 14),
|
||||||
|
min_lot: (12, 8),
|
||||||
|
mix: &[
|
||||||
|
(B::Warehouse, 6),
|
||||||
|
(B::Depot, 2),
|
||||||
|
(B::Bar, 1),
|
||||||
|
(B::Garage, 1),
|
||||||
|
],
|
||||||
|
tall: 0.0,
|
||||||
|
mid: 0.2,
|
||||||
|
basement: 0.2,
|
||||||
|
plaza: 0.1,
|
||||||
|
neon: 0.2,
|
||||||
|
holo: 0.05,
|
||||||
|
lamp_spacing: 14,
|
||||||
|
security: 70,
|
||||||
|
hues: &[Hue::Cyan, Hue::Green, Hue::Orange],
|
||||||
|
};
|
||||||
|
static INDUSTRIAL: ThemeSpec = ThemeSpec {
|
||||||
|
base_wealth: 0.25,
|
||||||
|
base_decay: 0.7,
|
||||||
|
street_style: StreetStyle::Rows,
|
||||||
|
block: (28, 14),
|
||||||
|
min_lot: (12, 8),
|
||||||
|
mix: &[
|
||||||
|
(B::Factory, 5),
|
||||||
|
(B::Warehouse, 3),
|
||||||
|
(B::Depot, 2),
|
||||||
|
(B::Garage, 1),
|
||||||
|
],
|
||||||
|
tall: 0.05,
|
||||||
|
mid: 0.3,
|
||||||
|
basement: 0.4,
|
||||||
|
plaza: 0.05,
|
||||||
|
neon: 0.15,
|
||||||
|
holo: 0.05,
|
||||||
|
lamp_spacing: 14,
|
||||||
|
security: 90,
|
||||||
|
hues: &[Hue::Yellow, Hue::Green, Hue::White],
|
||||||
|
};
|
||||||
|
static NEON_STRIP: ThemeSpec = ThemeSpec {
|
||||||
|
base_wealth: 0.6,
|
||||||
|
base_decay: 0.3,
|
||||||
|
street_style: StreetStyle::Strip,
|
||||||
|
block: (18, 10),
|
||||||
|
min_lot: (6, 4),
|
||||||
|
mix: &[
|
||||||
|
(B::Club, 4),
|
||||||
|
(B::Bar, 3),
|
||||||
|
(B::Arcade, 3),
|
||||||
|
(B::Hotel, 2),
|
||||||
|
(B::Shop, 1),
|
||||||
|
],
|
||||||
|
tall: 0.2,
|
||||||
|
mid: 0.5,
|
||||||
|
basement: 0.2,
|
||||||
|
plaza: 0.2,
|
||||||
|
neon: 0.95,
|
||||||
|
holo: 0.6,
|
||||||
|
lamp_spacing: 6,
|
||||||
|
security: 120,
|
||||||
|
hues: &[Hue::Pink, Hue::Blue, Hue::Magenta],
|
||||||
|
};
|
||||||
|
static OLD_TOWN: ThemeSpec = ThemeSpec {
|
||||||
|
base_wealth: 0.5,
|
||||||
|
base_decay: 0.4,
|
||||||
|
street_style: StreetStyle::Organic,
|
||||||
|
block: (14, 9),
|
||||||
|
min_lot: (5, 4),
|
||||||
|
mix: &[
|
||||||
|
(B::Apartment, 4),
|
||||||
|
(B::Shop, 2),
|
||||||
|
(B::Temple, 1),
|
||||||
|
(B::NoodleBar, 2),
|
||||||
|
(B::Bar, 1),
|
||||||
|
(B::Clinic, 1),
|
||||||
|
],
|
||||||
|
tall: 0.0,
|
||||||
|
mid: 0.25,
|
||||||
|
basement: 0.15,
|
||||||
|
plaza: 0.25,
|
||||||
|
neon: 0.4,
|
||||||
|
holo: 0.1,
|
||||||
|
lamp_spacing: 12,
|
||||||
|
security: 80,
|
||||||
|
hues: &[Hue::Orange, Hue::Green, Hue::White],
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Theme {
|
||||||
|
pub fn spec(self) -> &'static ThemeSpec {
|
||||||
|
match self {
|
||||||
|
Theme::CorpCore => &CORP_CORE,
|
||||||
|
Theme::NightMarket => &NIGHT_MARKET,
|
||||||
|
Theme::Megablocks => &MEGABLOCKS,
|
||||||
|
Theme::CombatZone => &COMBAT_ZONE,
|
||||||
|
Theme::Docks => &DOCKS,
|
||||||
|
Theme::Industrial => &INDUSTRIAL,
|
||||||
|
Theme::NeonStrip => &NEON_STRIP,
|
||||||
|
Theme::OldTown => &OLD_TOWN,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuildingKind {
|
||||||
|
/// Height classes this kind may take, preferred first.
|
||||||
|
pub fn height_classes(self) -> &'static [HeightClass] {
|
||||||
|
match self {
|
||||||
|
B::CorpTower | B::Megablock => &[HeightClass::Tall],
|
||||||
|
B::Office | B::Hotel => &[HeightClass::Mid, HeightClass::Tall],
|
||||||
|
B::Apartment => &[HeightClass::Mid, HeightClass::Low],
|
||||||
|
B::Factory | B::Parking => &[HeightClass::Low, HeightClass::Mid],
|
||||||
|
_ => &[HeightClass::Low],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::world::{BuildingKind, HeightClass, Theme};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn theme_mix_weights_nonzero() {
|
||||||
|
for t in Theme::ALL {
|
||||||
|
let s = t.spec();
|
||||||
|
assert!(s.mix.iter().map(|(_, w)| *w).sum::<u32>() > 0);
|
||||||
|
assert!(s.min_lot.0 >= 4 && s.min_lot.1 >= 3);
|
||||||
|
assert!(!s.hues.is_empty());
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
BuildingKind::CorpTower.height_classes(),
|
||||||
|
&[HeightClass::Tall]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
BuildingKind::Office.height_classes(),
|
||||||
|
&[HeightClass::Mid, HeightClass::Tall]
|
||||||
|
);
|
||||||
|
assert_eq!(BuildingKind::Shop.height_classes(), &[HeightClass::Low]);
|
||||||
|
}
|
||||||
|
}
|
||||||
65
flavor/names.ron
Normal file
65
flavor/names.ron
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// Default flavor pack: original names in the shared cyberpunk register.
|
||||||
|
// Swap this file (or add another and select it via GenParams.flavor) to retheme a city.
|
||||||
|
FlavorPack(
|
||||||
|
city: NameParts(
|
||||||
|
prefixes: ["Neo", "New", "Night", "Grey", "Ash", "Iron", "Hollow", "Saint", "Port", "North", "Low", "Vanta", "Chrome", "Static", "Ember"],
|
||||||
|
suffixes: ["haven", "port", "gate", "spire", "fall", "reach", "burg", "side", "mouth", "wick", "crest", "shore", "vale", "march", "field"],
|
||||||
|
),
|
||||||
|
districts: [
|
||||||
|
(CorpCore, NameParts(
|
||||||
|
prefixes: ["Apex", "Meridian", "Zenith", "Crown", "Axis", "Prime", "Nexus", "Vector", "Summit", "Core", "Helix", "Aurum"],
|
||||||
|
suffixes: [" Plaza", " Center", " Heights", " District", " Row", " Quarter", " Terrace", " Exchange", " Circle", " Mile", " Spire", " Square"],
|
||||||
|
)),
|
||||||
|
(NightMarket, NameParts(
|
||||||
|
prefixes: ["Kowloon", "Lantern", "Ginza", "Saigon", "Jade", "Paper", "Smoke", "Bazaar", "Spice", "Dragon", "Lotus", "Silk"],
|
||||||
|
suffixes: [" Market", " Alley", " Walk", " Ward", " Lanes", " Steps", " Street", " Yard", " Court", " Strip", " Row", " Block"],
|
||||||
|
)),
|
||||||
|
(Megablocks, NameParts(
|
||||||
|
prefixes: ["Block", "Stack", "Tower", "Unit", "Sector", "Hive", "Cell", "Slab", "Tier", "Bay", "Deck", "Quad"],
|
||||||
|
suffixes: [" 7", " 12", " 19", " 23", " 31", " 44", " 56", " 61", " 77", " 88", " 93", " 101"],
|
||||||
|
)),
|
||||||
|
(CombatZone, NameParts(
|
||||||
|
prefixes: ["Rust", "Scrap", "Cinder", "Dead", "Broken", "Razor", "Burnout", "Gravel", "Wreck", "Hollow", "Dust", "Scar"],
|
||||||
|
suffixes: [" Row", " Yards", " Flats", " End", " Hollow", " Cut", " Run", " Pit", " Zone", " Sprawl", " Line", " Reach"],
|
||||||
|
)),
|
||||||
|
(Docks, NameParts(
|
||||||
|
prefixes: ["Harbor", "Pier", "Tide", "Salt", "Anchor", "Cargo", "Quay", "Wharf", "Bilge", "Keel", "Gull", "Brine"],
|
||||||
|
suffixes: [" Point", " Docks", " Landing", " Basin", " Wharf", " Slip", " Reach", " Yard", " Front", " Bank", " Mole", " Strand"],
|
||||||
|
)),
|
||||||
|
(Industrial, NameParts(
|
||||||
|
prefixes: ["Furnace", "Foundry", "Reactor", "Kiln", "Crucible", "Smelter", "Turbine", "Boiler", "Coil", "Refinery", "Slag", "Pylon"],
|
||||||
|
suffixes: [" Works", " Yards", " Park", " Annex", " Fields", " Belt", " Grid", " Works", " Row", " Stacks", " Pit", " Sector"],
|
||||||
|
)),
|
||||||
|
(NeonStrip, NameParts(
|
||||||
|
prefixes: ["Neon", "Velvet", "Mirage", "Pulse", "Glitter", "Chrome", "Halo", "Afterglow", "Vapor", "Siren", "Candy", "Strobe"],
|
||||||
|
suffixes: [" Strip", " Boulevard", " Mile", " Drag", " Lane", " Avenue", " Parade", " Run", " Way", " Walk", " Row", " Line"],
|
||||||
|
)),
|
||||||
|
(OldTown, NameParts(
|
||||||
|
prefixes: ["Old", "Temple", "Cobble", "Lantern", "Ivy", "Chapel", "Mill", "Orchard", "Clock", "Tanner", "Weaver", "Bell"],
|
||||||
|
suffixes: [" Town", " Hill", " Quarter", " Close", " Lane", " Green", " Yard", " Gate", " Walk", " Cross", " Rise", " Row"],
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
corp: CorpParts(
|
||||||
|
first: ["Arasu", "Kiro", "Nov", "Hex", "Mira", "Tess", "Oro", "Vel", "Kai", "Zen", "Dai", "Sol", "Yuki", "Bran", "Ark", "Lum"],
|
||||||
|
second: ["tek", "dyne", "corp", "soft", "gen", "ware", "sys", "line", "med", "sec", "net", "bio", "form", "tron", "core", "flux"],
|
||||||
|
suffix: ["", " Industries", " Group", " Holdings", " Systems", " Biotech", " Dynamics", " Securities", " Logistics", " Media", " Capital", " Labs"],
|
||||||
|
),
|
||||||
|
shops: [
|
||||||
|
(NoodleBar, ["{syl} Noodles", "Ramen {syl}", "{syl} Kitchen", "Hot {syl}", "{syl} Bowl"]),
|
||||||
|
(Bar, ["The {syl}", "{syl} Lounge", "Bar {syl}", "{syl} & Static", "Dive {syl}"]),
|
||||||
|
(Club, ["Club {syl}", "{syl} Afterdark", "Velvet {syl}", "{syl} Pulse"]),
|
||||||
|
(Clinic, ["{syl} Ripperdoc", "Clinic {syl}", "{syl} Chrome", "Doc {syl}"]),
|
||||||
|
(Shop, ["{syl} Goods", "{syl} Mart", "24h {syl}", "{syl} Supply"]),
|
||||||
|
(Pawn, ["{syl} Pawn", "{syl} & Sons", "Cash {syl}"]),
|
||||||
|
(Arcade, ["{syl} Arcade", "Neon {syl}", "{syl} Braindance"]),
|
||||||
|
(Hotel, ["Hotel {syl}", "{syl} Capsule", "The {syl} Inn"]),
|
||||||
|
(Temple, ["{syl} Temple", "Shrine of {syl}", "{syl} Mission"]),
|
||||||
|
(Market, ["{syl} Market", "{syl} Bazaar"]),
|
||||||
|
(Garage, ["{syl} Motors", "{syl} Autoworks"]),
|
||||||
|
(Warehouse, ["{syl} Storage", "{syl} Freight"]),
|
||||||
|
(Factory, ["{syl} Fabrication", "{syl} Assembly"]),
|
||||||
|
(Depot, ["{syl} Depot", "{syl} Transit"]),
|
||||||
|
],
|
||||||
|
landmarks: ["{corp} Tower", "{district} Terminal", "The {district} Arcology", "{corp} Plaza", "Old {district} Station"],
|
||||||
|
signage: ['ヲ','ァ','ィ','ゥ','ェ','ォ','ャ','ュ','ョ','ッ','ー','ア','イ','ウ','エ','オ','カ','キ','ク','ケ','コ','サ','シ','ス','セ','ソ','タ','チ','ツ','テ','ト','ナ','ニ','ヌ','ネ','ノ','ハ','ヒ','フ','ヘ','ホ','マ','ミ','ム','メ','モ','ヤ','ユ','ヨ','ラ','リ','ル','レ','ロ','ワ','ン','Ж','Ф','Ц','Ш','Я','Δ','Σ','Ψ','Ω','¥','$','€','§','¤'],
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user