Complete phase 47 romance pack on generic orientation and affinity hooks.

Vanilla catalogs stay without crushes; a content pack ships the overlay so later mods can reuse it.
This commit is contained in:
Leonid Pershin
2026-08-20 10:42:42 +03:00
parent cb869e4977
commit d2911c3daf
43 changed files with 1840 additions and 29 deletions
+28
View File
@@ -0,0 +1,28 @@
# Romance pack
A content pack, not a sample folder. Tick it in create. Vanilla schools stay without
orientation, crushes, pairs, or these topics.
`example` is the layout sample; this pack is the living one. Do not copy content into
`example`.
## Layout
```
romance/
pack.jsonc # version + requires: ["core"]
localizations/{ru,en}.jsonc
defs/orientations/ # OrientationDef + generator weights
defs/affinity/rules.jsonc # AffinityRulesDef singleton — numbers, not pack ids in code
defs/traits/traits.jsonc # crush-prone / jealous via TraitDef fields
defs/topics/romance.jsonc # topics that exist only with this pack
patches/topic-appearance.jsonc
README.md
```
Core already picks every `TopicDef` in the catalog for `Chat`. New topics join that pool;
`Chat` itself is not rewritten. The appearance topic gets a `romance` tag so crush-prone
people lean toward it — that is a patch, not a copy of core.
Without this pack the catalog has no `OrientationDef` and no `AffinityRulesDef`. The
generator then writes no orientation field, and the affinity overlay does not run.
@@ -0,0 +1,17 @@
{
"defName": "AffinityRules",
"sympathyThreshold": 50,
"pairThreshold": 70,
"pairBreakThreshold": 20,
"pairMinAge": 18,
"studentAgeDeltaYears": 2,
"studentAdjacentYear": true,
"excludeFamily": true,
"rebuffOpinionShift": -8,
"rolePairs": [
{ "from": "student", "to": "student", "sympathy": true, "pair": true },
{ "from": "student", "to": "staff", "sympathy": true, "pair": false },
{ "from": "staff", "to": "student", "sympathy": false, "pair": false },
{ "from": "staff", "to": "staff", "sympathy": true, "pair": true },
],
}
@@ -0,0 +1,18 @@
[
{
"defName": "Heterosexual",
"weight": 70,
"oppositeGender": true,
},
{
"defName": "Bisexual",
"weight": 20,
"sameGender": true,
"oppositeGender": true,
},
{
"defName": "Homosexual",
"weight": 10,
"sameGender": true,
},
]
@@ -0,0 +1,23 @@
[
{
"defName": "TopicCrush",
"tags": ["romance", "gossip"],
"roles": ["student"],
"age": { "min": 11, "max": 18 },
"opinionShift": 2,
},
{
"defName": "TopicCouple",
"tags": ["romance"],
"roles": ["student", "staff"],
"age": { "min": 18 },
"opinionShift": 3,
},
{
"defName": "TopicTease",
"tags": ["romance", "gossip"],
"roles": ["student"],
"age": { "min": 7, "max": 18 },
"opinionShift": 1,
},
]
@@ -0,0 +1,16 @@
[
{
"defName": "CrushProne",
"weight": 5,
"roles": ["student", "staff"],
"affinityThresholdOffset": -15,
"talkTagWeights": [{ "tag": "romance", "weight": 3 }],
},
{
"defName": "Jealous",
"weight": 4,
"roles": ["student", "staff"],
"age": { "min": 14 },
"affinityBreakOffset": 15,
},
]
@@ -0,0 +1,17 @@
{
"romance": "Romance",
"Heterosexual": "heterosexual",
"Bisexual": "bisexual",
"Homosexual": "homosexual",
"AffinityRules": "Affinity rules",
"CrushProne": "crush-prone",
"Jealous": "jealous",
"TopicCrush": "who likes whom",
"TopicCouple": "couples",
"TopicTease": "teasing",
"AffinityCrush": "a crush started",
"AffinityPair": "became a couple",
"AffinityPairBreak": "the couple split",
"AffinityTease": "teasing in class",
"AffinityRebuff": "turned down in talk",
}
@@ -0,0 +1,17 @@
{
"romance": "Романтика",
"Heterosexual": "гетеро",
"Bisexual": "би",
"Homosexual": "гомо",
"AffinityRules": "Правила симпатии",
"CrushProne": "влюбчивый",
"Jealous": "ревнивый",
"TopicCrush": "кто кому нравится",
"TopicCouple": "пары",
"TopicTease": "дразнилки",
"AffinityCrush": "появилась симпатия",
"AffinityPair": "стали парой",
"AffinityPairBreak": "пара распалась",
"AffinityTease": "дразнилки в классе",
"AffinityRebuff": "разговор-отказ",
}
@@ -0,0 +1,4 @@
{
"version": "1.0",
"requires": ["core"],
}
@@ -0,0 +1,6 @@
{
"target": "TopicAppearance",
"ops": [
{ "op": "add", "path": "/tags/-", "value": "romance" },
],
}