This commit is contained in:
AsmodeusRex 2022-10-26 19:36:24 -07:00
parent 23fd56b07e
commit 6475e46293
63 changed files with 10733 additions and 6833 deletions

8
generator/Cargo.toml Normal file
View file

@ -0,0 +1,8 @@
[package]
name = "generator"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

70
generator/src/main.rs Normal file
View file

@ -0,0 +1,70 @@
use std::fs::File;
use std::io::{self, Write};
mod parts;
mod racegroups;
mod surgery;
mod things;
use parts::*;
use racegroups::*;
use surgery::*;
use things::*;
fn write(path: &'static str, data: &String) -> io::Result<()> {
let mut f = File::create(format!("../Content/Base/Defs/{path}.xml"))?;
let s = format!("<?xml version=\"1.0\" encoding=\"utf-8\"?>
<!-- This is an automatically generated file. If you are the end user, this is safe to edit. If you are a contributor, please edit the source files instead. -->
<Defs>{data}</Defs>");
f.write_all(s.as_bytes())?;
Ok(())
}
fn main() {
let animal_parts = part_data_animals();
let mut animal_hediffs = String::new();
for part in &animal_parts {
animal_hediffs.push_str(&(construct_hediff(part, false) + "\n"));
}
let mut human_hediffs = String::new();
let human_parts = part_data_humans();
for part in &human_parts {
human_hediffs.push_str(&(construct_hediff(part, true) + "\n"));
}
let (breasts, breast_hediffs) = part_data_breasts();
let (parts, part_hediffs) = part_data_other();
let mut raceparts = String::new();
let mut thingdefs = String::new();
let mut surgeries = String::new();
for part in animal_parts.iter().chain(human_parts.iter()).chain(breasts.iter()).chain(parts.iter()) {
raceparts.push_str(&(construct_racepart(part) + "\n"));
thingdefs.push_str(&(construct_thingdef(part) + "\n"));
let surg = enumerate_surgeries(&part);
for surgery in surg {
surgeries.push_str(&(construct_surgery(&surgery) + "\n"));
}
}
let mut human_races = String::new();
for group in racegroup_data_humans() {
human_races.push_str(&construct_racegroup(&group));
}
let mut animal_races = String::new();
for group in racegroup_data_animals() {
animal_races.push_str(&construct_racegroup(&group));
}
write("HediffDefs/Hediffs_Animals", &animal_hediffs).unwrap();
write("HediffDefs/Hediffs_Humans", &human_hediffs).unwrap();
write("HediffDefs/Hediffs_Breasts", &breast_hediffs).unwrap();
write("HediffDefs/Hediffs_Misc", &part_hediffs).unwrap();
write("RaceSupport/Custom_Parts", &raceparts).unwrap();
write("ThingDefs/Items_BodyParts", &thingdefs).unwrap();
write("RecipeDefs/Recipes_Surgery", &surgeries).unwrap();
write("RaceSupport/Humanoids", &human_races).unwrap();
write("RaceSupport/Animals", &animal_races).unwrap();
}

593
generator/src/parts.rs Normal file
View file

@ -0,0 +1,593 @@
use std::collections::HashMap;
#[derive(Clone, Copy, Debug)]
pub enum PartType {
Anus,
Breasts,
Penis,
Vagina,
}
#[derive(Clone, Debug)]
pub struct Part {
pub part_type: PartType,
pub name: String,
pub label: String,
pub label_noun: String,
pub description: String,
// Known props:
// Penis:
// Girthy/Thin
// Long/Small
// Artificial
// Barbed
// Flared
// Glowing
// Humanlike
// Internal
// Knotted
// Multiple
// Prehensile
// Resizable
// Ridged
// Rigid
// Sheathed
// Solid
// STDImmune
// Tapered
//
// Hole:
// Loose/Tight
// Barbed
// Deep
// Glowing
// Resizable
// Ridged
// STDImmune
pub props: Vec<&'static str>,
}
impl Part {
fn standard(pre: &'static str, ty: PartType, species: &'static str, desc: &'static str, props: Vec<&'static str>) -> Option<Self> {
let mut name = species.to_owned() + match ty {
PartType::Anus => "Anus",
PartType::Breasts => return None,
PartType::Penis => "Penis",
PartType::Vagina => "Vagina",
};
if let Some(c) = name.get_mut(0..1) {
c.make_ascii_uppercase();
};
let label_type = match ty {
PartType::Anus => "anus",
PartType::Breasts => panic!(),
PartType::Penis => "penis",
PartType::Vagina => "vagina",
};
let label = format!("{species} {label_type}");
let label_noun = format!("{pre} {species} {label_type}");
Some(Self {
part_type: ty,
name: name,
label: label,
label_noun: label_noun,
description: desc.to_string(),
props: props
})
}
}
pub fn construct_racepart(part: &Part) -> String {
String::from(RACEPART_STRING).replace("{name}", &part.name)
}
pub fn construct_hediff(part: &Part, human: bool) -> String {
let mut s = String::from(HEDIFF_STRING);
let ty = match part.part_type {
PartType::Anus => "Anus",
PartType::Breasts => return "".to_string(),
PartType::Penis => "Penis",
PartType::Vagina => "Vagina",
};
let mut props = String::new();
for prop in &part.props {
props.push_str(&format!("\n\t\t\t\t\t<li>{prop}</li>"));
}
if human {
props.push_str(&format!("\n\t\t\t\t\t<li>Humanlike</li>"));
}
let replace = HashMap::from([
("{type}", ty),
("{name}", &part.name),
("{label}", &part.label),
("{label_noun}", &part.label_noun),
("{description}", &part.description),
("{props}", &props),
]);
for r in replace {
s = s.replace(r.0, r.1);
}
s
}
const HEDIFF_STRING: &'static str = "
<rjw.HediffDef_PartBase ParentName=\"NaturalPrivatePart{type}\">
<defName>{name}</defName>
<label>{label}</label>
<labelNoun>{label_noun}</labelNoun>
<description>{description}</description>
<descriptionHyperlinks>
<ThingDef>{name}</ThingDef>
</descriptionHyperlinks>
<spawnThingOnRemoved>{name}</spawnThingOnRemoved>
<modExtensions>
<li Class=\"rjw.PartProps\">
<props>{props}
</props>
</li>
</modExtensions>
</rjw.HediffDef_PartBase>";
const HEDIFF_STRING_EXT: &'static str = "
<rjw.HediffDef_PartBase ParentName=\"NaturalPrivatePart{type}\">
<defName>{name}</defName>
<label>{label}</label>
<labelNoun>{label_noun}</labelNoun>
<description>{description}</description>
<descriptionHyperlinks>
<ThingDef>{name}</ThingDef>
</descriptionHyperlinks>
<spawnThingOnRemoved>{name}</spawnThingOnRemoved>
{fields}<modExtensions>
<li Class=\"rjw.PartProps\">
<props>{props}
</props>
</li>
</modExtensions>
</rjw.HediffDef_PartBase>\n";
const HEDIFF_STRING_BREASTS: &'static str = "
<rjw.HediffDef_PartBase ParentName=\"{type}\">
<defName>{name}</defName>
<label>{label}</label>
<labelNoun>{label_noun}</labelNoun>
<description>{description}</description>
<descriptionHyperlinks>
<ThingDef>{name}</ThingDef>
</descriptionHyperlinks>
<spawnThingOnRemoved>{name}</spawnThingOnRemoved>
{fields}<modExtensions>
<li Class=\"rjw.PartProps\">
<props>{props}
</props>
</li>
</modExtensions>
</rjw.HediffDef_PartBase>\n";
const RACEPART_STRING: &'static str = "
<rjw.RacePartDef>
<defName>{name}</defName>
<hediffName>{name}</hediffName>
</rjw.RacePartDef>";
pub fn part_data_animals() -> Vec<Part> {
vec![
// Mammals
Part::standard("a", PartType::Penis, "bear",
"A small penis supported by a bone.",
vec!["Flared", "Small", "Rigid"]
).unwrap(),
Part::standard("a", PartType::Penis, "bovine",
"A rather long but thin penis with large testicles.",
vec!["Long", "Sheathed", "Thin"]
).unwrap(),
Part::standard("a", PartType::Vagina, "bovine",
"A rather thin and deep vagina, likely belonging to a large mammal.",
vec!["Tight", "Deep"]
).unwrap(),
Part::standard("a", PartType::Anus, "dog",
"A canine anus.",
vec![]
).unwrap(),
Part::standard("a", PartType::Penis, "dino",
"A large tapered penis that is slightly flattened at the top. It looks similar to a large tongue.",
vec!["Girthy", "Tapered", "Internal"]
).unwrap(),
Part::standard("an", PartType::Penis, "elephant",
"A large and flexible prehensile penis.",
vec!["Girthy", "Long", "Prehensile", "Sheathed"]
).unwrap(),
Part::standard("an", PartType::Vagina, "elephant",
"The deep vagina of a female elephant.",
vec!["Deep"]
).unwrap(),
Part::standard("an", PartType::Anus, "equine",
"An anus shaped like a doughnut.",
vec!["Loose"]
).unwrap(),
Part::standard("a", PartType::Anus, "feline",
"A feline anus.",
vec!["Tight"]
).unwrap(),
Part::standard("a", PartType::Penis, "monkey",
"A very thin, but otherwise humanoid-looking penis.",
vec!["Thin"]
).unwrap(),
Part::standard("a", PartType::Penis, "pig",
"A corkscrew shaped penis.",
vec!["Long", "Sheathed", "Thin"]
).unwrap(),
Part::standard("a", PartType::Vagina, "pig",
"The foldy vagina of a female pig.",
vec!["Tight"]
).unwrap(),
Part {
part_type: PartType::Vagina,
name: "MammalVagina".to_string(),
label: "mammal vagina".to_string(),
label_noun: "a mammalian vagina".to_string(),
description: "A generic vagina that probably belongs to some mammal.".to_string(),
props: vec![],
},
Part {
part_type: PartType::Anus,
name: "MammalAnus".to_string(),
label: "mammal anus".to_string(),
label_noun: "a mammalian anus".to_string(),
description: "A generic mammalian animal's anus.".to_string(),
props: vec![],
},
Part {
part_type: PartType::Anus,
name: "CervineAnus".to_string(),
label: "cervine anus".to_string(),
label_noun: "a deer anus".to_string(),
description: "A deer's anus.".to_string(),
props: vec![],
},
Part {
part_type: PartType::Vagina,
name: "HyenaVagina".to_string(),
label: "hyena pseudo-penis".to_string(),
label_noun: "a hyena pseudo-penis".to_string(),
description: "The clitoris of the female spotted hyena is enlarged into a pseudo-penis, through which the female urinates and reproduces. It can even get erect!".to_string(),
props: vec!["Barbed", "Deep"],
},
Part {
part_type: PartType::Penis,
name: "MarinePenis".to_string(),
label: "marine penis".to_string(),
label_noun: "a marine mammal penis".to_string(),
description: "A girthy, retractable penis that tapers to a point; it likely belongs to a seal, walrus, or hippo.".to_string(),
props: vec!["Girthy", "Internal", "Tapered"],
},
Part {
part_type: PartType::Vagina,
name: "MarineVagina".to_string(),
label: "marine vagina".to_string(),
label_noun: "a marine mammal vagina".to_string(),
description: "A slippery vagina.".to_string(),
props: vec!["Loose"],
},
// Non-Mammals
Part::standard("a", PartType::Penis, "cactoid",
"A rough plant-like penis, with thorns along the shaft.",
vec!["Barbed", "Ridged"]
).unwrap(),
Part::standard("a", PartType::Vagina, "cactoid",
"A rough plant-like vagina, with thorns lining the inner walls. The thorns grip male genitals during sex.",
vec!["Barbed", "Ridged"]
).unwrap(),
Part::standard("a", PartType::Anus, "cactoid",
"A rough plant-like anus. No thorns this time.",
vec!["Barbed", "Ridged"]
).unwrap(),
Part::standard("a", PartType::Penis, "turtle",
"A large penis with a huge flare at the tip.",
vec!["Flared", "Girthy", "Internal", "Long"]
).unwrap(),
Part {
part_type: PartType::Penis,
name: "Aedeagus".to_string(),
label: "aedeagus".to_string(),
label_noun: "an aedeagus".to_string(),
description: "The phallus of a male arthropod, for excreting a spermatophore to inseminate a female arthropod.".to_string(),
props: vec!["Rigid"],
},
Part {
part_type: PartType::Vagina,
name: "OviporeVagina".to_string(),
label: "ovipore".to_string(),
label_noun: "an ovipore".to_string(),
description: "A pore-like sexual organ of a female arthropod for receiving a spermatophore. Very loosely comparable to a vagina.".to_string(),
props: vec!["Rigid"],
},
Part {
part_type: PartType::Penis,
name: "AntherPenis".to_string(),
label: "anther".to_string(),
label_noun: "a flower's anther".to_string(),
description: "A flower's male reproductive organ. A long and thin filament, with a large pollen-producing head in the tip.".to_string(),
props: vec!["Long", "Thin"],
},
Part {
part_type: PartType::Vagina,
name: "PistilVagina".to_string(),
label: "pistil".to_string(),
label_noun: "a flower's pistil".to_string(),
description: "A flower's female reproductive organ. The sticky entrance is connected to the ovaries via a long tube-like structure.".to_string(),
props: vec![],
},
Part {
part_type: PartType::Penis,
name: "TentaclePenis".to_string(),
label: "tentacles".to_string(),
label_noun: "reproductive tentacles".to_string(),
description: "A mass of tentacle-like penises, capable of both restraining and pleasuring.".to_string(),
props: vec!["Long", "Multiple", "Prehensile"],
},
Part {
part_type: PartType::Penis,
name: "VinePenis".to_string(),
label: "vines".to_string(),
label_noun: "a mass of vines".to_string(),
description: "Genetically altered vines capable of reproduction.".to_string(),
props: vec!["Long", "Multiple", "Prehensile", "Thin"],
},
]
}
pub fn part_data_humans() -> Vec<Part> {
vec![
Part::standard("a", PartType::Penis, "necro",
"A disgusting, rotting penis that somehow still works.",
vec![]
).unwrap(),
Part::standard("a", PartType::Vagina, "necro",
"A disgusting, rotting vagina. Its insides are as cold as a grave.",
vec!["Loose"]
).unwrap(),
Part::standard("a", PartType::Anus, "necro",
"A disgusting, rotting anus. Its insides are as cold as a grave.",
vec!["Loose"]
).unwrap(),
Part::standard("an", PartType::Penis, "elf",
"A thinner and longer humanlike penis. Is that glitter?",
vec!["Long", "Thin"]
).unwrap(),
Part::standard("an", PartType::Vagina, "elf",
"A tighter humanlike vagina. Tastes like oranges.",
vec!["Tight"]
).unwrap(),
Part::standard("an", PartType::Anus, "elf",
"A tighter humanlike anus. Smells of flowers.",
vec!["Tight"]
).unwrap(),
Part::standard("a", PartType::Penis, "golem",
"A rough and jagged stone-like penis.",
vec!["Rigid", "Solid"]
).unwrap(),
Part::standard("an", PartType::Penis, "ghoul",
"A humanlike penis that glows slightly. It's very hot to the touch.",
vec!["Glowing"]
).unwrap(),
Part::standard("a", PartType::Vagina, "ghoul",
"A humanlike vagina that glows slightly. It is uncomfortably hot inside.",
vec!["Glowing"]
).unwrap(),
Part::standard("a", PartType::Anus, "ghoul",
"An anus that glows slightly. It is uncomfortably hot inside.",
vec!["Glowing"]
).unwrap(),
Part::standard("an", PartType::Penis, "orc",
"A girthy penis with a preputial ring, but otherwise similar to a humanoid penis.",
vec!["Girthy"]
).unwrap(),
Part::standard("an", PartType::Vagina, "orc",
"A loose humanlike vagina with very large lips.",
vec!["Loose"]
).unwrap(),
Part::standard("an", PartType::Anus, "orc",
"An anus that looks like a mix between an humanlike anus and an equine anus.",
vec!["Loose"]
).unwrap(),
Part {
part_type: PartType::Penis,
name: "TreePenis".to_string(),
label: "bark penis".to_string(),
label_noun: "a wooden penis".to_string(),
description: "A naturally grown wooden penis. The testicles are completely covered in hard, wooden bark, while the texture along the shaft is softer, leaving the tip uncovered.".to_string(),
props: vec!["Ridged", "Rigid"],
},
Part {
part_type: PartType::Vagina,
name: "TreeVagina".to_string(),
label: "bark vagina".to_string(),
label_noun: "a wooden vagina".to_string(),
description: "A naturally grown wooden vagina. While the outside looks like bark, the inside is soft.".to_string(),
props: vec!["Ridged", "Rigid"],
},
Part {
part_type: PartType::Anus,
name: "TreeAnus".to_string(),
label: "bark anus".to_string(),
label_noun: "a wooden anus".to_string(),
description: "A naturally grown wooden anus. While the outside looks like bark, the inside is soft.".to_string(),
props: vec!["Ridged", "Rigid"],
},
]
}
pub fn part_data_breasts() -> (Vec<Part>, String) {
let breasts = vec![
(Part {
part_type: PartType::Breasts,
name: "MammalBreasts".to_string(),
label: "mammal breasts".to_string(),
label_noun: "a pair of mammalian breasts".to_string(),
description: "A group of breasts/nipples that mammals use to suckle their young.".to_string(),
props: vec![],
}, "MammalBreastBase", None),
(Part {
part_type: PartType::Breasts,
name: "CatBreasts".to_string(),
label: "kitty titties".to_string(),
label_noun: "the kitty's titties".to_string(),
description: "It's the kitty's titties!".to_string(),
props: vec![],
}, "MammalBreastBase", None),
(Part {
part_type: PartType::Breasts,
name: "GhostBreasts".to_string(),
label: "immaterial breasts".to_string(),
label_noun: "a pair of immaterial breasts".to_string(),
description: "A translucent, almost intangible pair of breasts. Touching them sends chills down the spine.".to_string(),
props: vec!["Humanlike"],
}, "NaturalPrivatePartBreast", Some(
"<FluidType>Ecto</FluidType>\n\t\t"
)),
(Part {
part_type: PartType::Breasts,
name: "CactoidBreasts".to_string(),
label: "cactoid breasts".to_string(),
label_noun: "a pair of cactoid breasts".to_string(),
description: "A pair of rough plant-like breasts, with thorns all around them, and flower-like nipples.".to_string(),
props: vec![],
}, "NaturalPrivatePartBreast", None),
(Part {
part_type: PartType::Breasts,
name: "GhoulBreasts".to_string(),
label: "irradiated breasts".to_string(),
label_noun: "a pair of irradiated breasts".to_string(),
description: "A pair of humanlike breasts that glow slightly. They're very hot to the touch.".to_string(),
props: vec!["Humanlike"],
}, "NaturalPrivatePartBreast", None),
(Part {
part_type: PartType::Breasts,
name: "NecroBreasts".to_string(),
label: "decayed breasts".to_string(),
label_noun: "A pair of decayed breasts".to_string(),
description: "A disgusting, rotting pair of breasts.".to_string(),
props: vec!["Humanlike"],
}, "NaturalPrivatePartBreast", None),
(Part {
part_type: PartType::Breasts,
name: "OrcBreasts".to_string(),
label: "orc breasts".to_string(),
label_noun: "a pair of orc breasts".to_string(),
description: "A pair of humanlike breasts that sag greatly.".to_string(),
props: vec!["Humanlike"],
}, "NaturalPrivatePartBreast", None),
(Part {
part_type: PartType::Breasts,
name: "ScaleBreasts".to_string(),
label: "scaly breasts".to_string(),
label_noun: "a pair of scaly breasts".to_string(),
description: "A pair of scale-covered breasts, without nipples.".to_string(),
props: vec!["Humanlike"],
}, "NaturalPrivatePartBreast", None),
(Part {
part_type: PartType::Breasts,
name: "TreeBreasts".to_string(),
label: "bark breasts".to_string(),
label_noun: "a pair of wooden breasts".to_string(),
description: "A pair of naturally grown wooden breasts. Hard bark covers the entire outer portion, while leaving the nipples underneath exposed.".to_string(),
props: vec!["Humanlike", "Ridged", "Rigid"],
}, "NaturalPrivatePartBreast", None),
];
let mut hediffs = String::new();
for breast in &breasts {
let mut s = String::from(HEDIFF_STRING_BREASTS);
let mut props = String::new();
for prop in &breast.0.props {
props.push_str(&format!("\n\t\t\t\t\t<li>{prop}</li>"));
}
let fields = breast.2.unwrap_or("");
let replace = HashMap::from([
("{type}", breast.1),
("{name}", &breast.0.name),
("{label}", &breast.0.label),
("{label_noun}", &breast.0.label_noun),
("{description}", &breast.0.description),
("{fields}", &fields),
("{props}", &props),
]);
for r in replace {
s = s.replace(r.0, r.1);
}
hediffs.push_str(&s);
}
(breasts.into_iter().map(|x| x.0).collect(), hediffs)
}
pub fn part_data_other() -> (Vec<Part>, String) {
let parts = vec![
(Part {
part_type: PartType::Penis,
name: "GhostPenis".to_string(),
label: "immaterial penis".to_string(),
label_noun: "an immaterial penis".to_string(),
description: "A translucent, almost intangible penis. Touching it sends chills down the spine.".to_string(),
props: vec!["Humanlike"],
}, "<FluidType>Ecto</FluidType>\n\t\t".to_string() ),
(Part {
part_type: PartType::Vagina,
name: "GhostVagina".to_string(),
label: "immaterial vagina".to_string(),
label_noun: "an immaterial vagina".to_string(),
description: "A translucent, almost intangible vagina. Penetrating it sends chills down the spine.".to_string(),
props: vec!["Humanlike"],
}, "<FluidType>Ecto</FluidType>\n\t\t".to_string() ),
(Part {
part_type: PartType::Anus,
name: "GhostAnus".to_string(),
label: "immaterial anus".to_string(),
label_noun: "an immaterial anus".to_string(),
description: "A translucent, almost intangible anus. Penetrating it sends chills down the spine.".to_string(),
props: vec!["Humanlike"],
}, "<FluidType>Ecto</FluidType>\n\t\t".to_string() ),
(Part {
part_type: PartType::Vagina,
name: "DemonTentaclesF".to_string(),
label: "demon tentacle".to_string(),
label_noun: "a female demon tentacle".to_string(),
description: "A long and flexible tentacle, capable of laying eggs.".to_string(),
props: vec!["Long", "Prehensile"],
}, "<produceEggs>true</produceEggs>
<minEggTick>12000</minEggTick>
<maxEggTick>60000</maxEggTick>
<FluidType>GR_EldritchInsectJelly</FluidType>\n\t\t".to_string() ),
];
let mut hediffs = String::new();
for part in &parts {
let mut s = String::from(HEDIFF_STRING_EXT);
let ty = match part.0.part_type {
PartType::Anus => "Anus",
PartType::Breasts => panic!(),
PartType::Penis => "Penis",
PartType::Vagina => "Vagina",
};
let mut props = String::new();
for prop in &part.0.props {
props.push_str(&format!("\n\t\t\t\t\t<li>{prop}</li>"));
}
let replace = HashMap::from([
("{type}", ty),
("{name}", &part.0.name),
("{label}", &part.0.label),
("{label_noun}", &part.0.label_noun),
("{description}", &part.0.description),
("{fields}", &part.1),
("{props}", &props),
]);
for r in replace {
s = s.replace(r.0, r.1);
}
hediffs.push_str(&s);
}
(parts.into_iter().map(|x| x.0).collect(), hediffs)
}

1377
generator/src/racegroups.rs Normal file

File diff suppressed because it is too large Load diff

138
generator/src/surgery.rs Normal file
View file

@ -0,0 +1,138 @@
use std::collections::HashMap;
use crate::parts::{Part, PartType};
#[derive(Clone, Copy, Debug)]
struct Operation {
surgery_type: &'static str,
verbs: (&'static str, &'static str, &'static str),
}
#[derive(Clone, Debug)]
pub struct Surgery {
part: Part,
operation: Operation,
}
const SURGERY_STRING: &str = "
<RecipeDef ParentName=\"{type}\">
<defName>{type}{name}</defName>
<label>{verb.0} {label}</label>
<description>{verb.1} {label_noun}</description>
<jobString>{verb.2} {label_noun}</jobString>
<ingredients>
<li>
<filter>
<categories>
<li>Medicine</li>
</categories>
</filter>
<count>1</count>
</li>
<li>
<filter>
<thingDefs>
<li>{name}</li>
</thingDefs>
</filter>
<count>1</count>
</li>
</ingredients>
<fixedIngredientFilter>
<categories>
<li>Medicine</li>
</categories>
<thingDefs>
<li>{name}</li>
</thingDefs>
</fixedIngredientFilter>
<addsHediff>{name}</addsHediff>
</RecipeDef>";
const BREAST_SURGERIES: [Option<Operation>;3] = [
Some(Operation{
surgery_type: "MultiBreast",
verbs: ("add", "Adds", "Adding"),
}),
Some(Operation{
surgery_type: "BreastSurgery",
verbs: ("attach", "Attaches", "Attaching"),
}),
None
];
const PENIS_SURGERIES: [Option<Operation>;3] = [
Some(Operation{
surgery_type: "FutaMakingF",
verbs: ("add", "Adds", "Adding"),
}),
Some(Operation{
surgery_type: "MultiPenis",
verbs: ("add", "Adds", "Adding"),
}),
Some(Operation{
surgery_type: "SexReassignmentP",
verbs: ("attach", "Attaches", "Attaching"),
})
];
const VAGINA_SURGERIES: [Option<Operation>;3] = [
Some(Operation{
surgery_type: "FutaMakingM",
verbs: ("add", "Adds", "Adding"),
}),
Some(Operation{
surgery_type: "MultiVagina",
verbs: ("add", "Adds", "Adding"),
}),
Some(Operation{
surgery_type: "SexReassignmentV",
verbs: ("attach", "Attaches", "Attaching"),
})
];
const ANUS_SURGERIES: [Option<Operation>;3] = [
Some(Operation{
surgery_type: "MultiAnus",
verbs: ("add", "Adds", "Adding"),
}),
Some(Operation{
surgery_type: "AnalSurgery",
verbs: ("attach", "Attaches", "Attaching"),
}),
None
];
pub fn enumerate_surgeries<'a>(part: &Part) -> Vec<Surgery> {
// Every part should have 2-3 relevant surgeries
let surgeries = match part.part_type {
PartType::Anus => ANUS_SURGERIES,
PartType::Breasts => BREAST_SURGERIES,
PartType::Penis => PENIS_SURGERIES,
PartType::Vagina => VAGINA_SURGERIES,
};
surgeries.iter().filter(|x| x.is_some()).map(|operation|
Surgery {
part: part.clone(),
operation: operation.unwrap()
}
).collect()
}
pub fn construct_surgery(surgery: &Surgery) -> String {
let mut s = String::from(SURGERY_STRING);
let replace = HashMap::from([
("{type}", surgery.operation.surgery_type),
("{verb.0}", surgery.operation.verbs.0),
("{verb.1}", surgery.operation.verbs.1),
("{verb.2}", surgery.operation.verbs.2),
("{name}", &surgery.part.name),
("{label}", &surgery.part.label),
("{label_noun}", &surgery.part.label_noun),
]);
for r in replace {
s = s.replace(r.0, r.1);
}
s
}

77
generator/src/things.rs Normal file
View file

@ -0,0 +1,77 @@
use std::collections::HashMap;
use crate::parts::{Part, PartType};
const THINGDEF_STRING: &str = "
<ThingDef ParentName=\"rjw_BodyPartNaturalBase{type}\">
<defName>{name}</defName>
<label>{label}</label>
<description>{description}</description>
<statBases>
<MarketValue>{value}</MarketValue>
<Mass>{mass}</Mass>
</statBases>
</ThingDef>";
pub fn construct_thingdef(part: &Part) -> String {
let mut s = String::from(THINGDEF_STRING);
let ty = match part.part_type {
PartType::Anus => "Anus",
PartType::Breasts => "Breast",
PartType::Penis => "GenMale",
PartType::Vagina => "GenFemale",
};
let mass = match part.part_type {
PartType::Anus => 0.12,
PartType::Breasts => 0.5,
PartType::Penis => 0.16,
PartType::Vagina => 0.10,
};
let mut mass_mult = 1.;
for prop in &part.props {
match *prop {
// positive
"Long" => mass_mult += 0.5,
"Girthy" => mass_mult += 0.5,
"Deep" => mass_mult += 0.3,
"Knotted" => mass_mult += 0.1,
"Solid" => mass_mult += 1.,
"Multiple" => mass_mult += 0.2,
// negative
"Thin" => mass_mult -= 0.3,
"Small" => mass_mult -= 0.5,
_ => {}
}
}
let m = format!("{:.3}", mass * mass_mult);
let val = match part.name.as_str() {
// positive
"DinoPenis" => "300",
"DinoVagina" => "300",
"TentaclePenis" => "350",
// negative
"OviporeVagina" => "50",
"AedeagusPenis" => "50",
_ => "250",
};
let replace = HashMap::from([
("{type}", ty),
("{name}", &part.name),
("{label}", &part.label),
("{description}", &part.description),
("{value}", val),
("{mass}", &m),
]);
for r in replace {
s = s.replace(r.0, r.1);
}
s
}