fix: archetypes origin_pool + faction_origin_override + lore corrections
- archetypes.json: origin -> origin_pool (liste), faction_origin_override (CDA->initie_confrerie, grand_krewe->goule) - passeur_bayou: faction ecumeurs -> grand_krewe (lore: les bayous sont leur territoire) - messager_faction: location_hints liste réelle (plus 'toutes zones sûres' non parsable) - fugitif: chased_by_faction_pool ajouté pour narration LLM - pillard_errant, scavenger, chasseur_primes, passeur: goule ajouté à origin_pool - pnj_factory.spawn_from_archetype: résolution origin depuis faction_origin_override puis origin_pool - character_creator._ROLE_TO_ORIGIN: lieutenant/chef_faction/chasseur_primes enrichis avec goule
This commit is contained in:
+45
-22
@@ -1,13 +1,17 @@
|
|||||||
{
|
{
|
||||||
"_comment": "Bibliothèque d'archétypes PNJ. Le LLM pioche ici pour instancier un PNJ de passage (tier 3) ou nommé (tier 2). Chaque archétype définit le template — le LLM choisit le nom, la faction et la localisation.",
|
"_comment": "Bibliothèque d'archétypes PNJ. origin_pool = liste d'origines possibles. faction_origin_override = si la faction choisie correspond, l'origine est forcée (lore). Le LLM choisit nom, faction, localisation.",
|
||||||
|
|
||||||
"garde_faction": {
|
"garde_faction": {
|
||||||
"role": "garde",
|
"role": "garde",
|
||||||
"origin": "survivant",
|
"origin_pool": ["survivant", "habitant_abri", "initie_confrerie", "goule"],
|
||||||
|
"faction_origin_override": {
|
||||||
|
"cda": "initie_confrerie",
|
||||||
|
"grand_krewe": "goule"
|
||||||
|
},
|
||||||
"tier": 3,
|
"tier": 3,
|
||||||
"description": "Garde d'une faction, posté à un point stratégique",
|
"description": "Garde d'une faction, posté à un point stratégique",
|
||||||
"faction_pool": ["union", "cda", "syndicat_capitole", "regie", "dynaste_oak"],
|
"faction_pool": ["union", "cda", "syndicat_capitole", "regie", "dynaste_oak", "grand_krewe"],
|
||||||
"location_hints": ["zone contrôlée par la faction d'appartenance"],
|
"location_hints": ["nola_cbd", "independance", "baton_rouge", "la_paroisse", "oak_plantation"],
|
||||||
"caps_range": [50, 250],
|
"caps_range": [50, 250],
|
||||||
"personality_traits": ["loyal", "méfiant envers étrangers", "obéit aux ordres"],
|
"personality_traits": ["loyal", "méfiant envers étrangers", "obéit aux ordres"],
|
||||||
"motivations": ["protéger son territoire", "nourrir sa famille", "progresser dans la hiérarchie"],
|
"motivations": ["protéger son territoire", "nourrir sa famille", "progresser dans la hiérarchie"],
|
||||||
@@ -16,7 +20,8 @@
|
|||||||
|
|
||||||
"vendeur_ambulant": {
|
"vendeur_ambulant": {
|
||||||
"role": "marchand",
|
"role": "marchand",
|
||||||
"origin": "survivant",
|
"origin_pool": ["survivant", "habitant_abri", "goule"],
|
||||||
|
"faction_origin_override": {},
|
||||||
"tier": 3,
|
"tier": 3,
|
||||||
"description": "Marchand itinérant qui circule entre les zones sûres",
|
"description": "Marchand itinérant qui circule entre les zones sûres",
|
||||||
"faction_pool": [null, "consortium", "regie"],
|
"faction_pool": [null, "consortium", "regie"],
|
||||||
@@ -29,7 +34,8 @@
|
|||||||
|
|
||||||
"habitant_nola": {
|
"habitant_nola": {
|
||||||
"role": "survivant_generique",
|
"role": "survivant_generique",
|
||||||
"origin": "survivant",
|
"origin_pool": ["survivant", "habitant_abri"],
|
||||||
|
"faction_origin_override": {},
|
||||||
"tier": 3,
|
"tier": 3,
|
||||||
"description": "Habitant ordinaire du Vieux Carré ou d'Indépendance",
|
"description": "Habitant ordinaire du Vieux Carré ou d'Indépendance",
|
||||||
"faction_pool": [null, "union", "regie"],
|
"faction_pool": [null, "union", "regie"],
|
||||||
@@ -42,7 +48,8 @@
|
|||||||
|
|
||||||
"pillard_errant": {
|
"pillard_errant": {
|
||||||
"role": "pillard",
|
"role": "pillard",
|
||||||
"origin": "survivant",
|
"origin_pool": ["survivant", "goule"],
|
||||||
|
"faction_origin_override": {},
|
||||||
"tier": 3,
|
"tier": 3,
|
||||||
"description": "Pillard solitaire ou en petite bande, sans base fixe",
|
"description": "Pillard solitaire ou en petite bande, sans base fixe",
|
||||||
"faction_pool": ["ecumeurs", null],
|
"faction_pool": ["ecumeurs", null],
|
||||||
@@ -55,11 +62,14 @@
|
|||||||
|
|
||||||
"passeur_bayou": {
|
"passeur_bayou": {
|
||||||
"role": "passeur",
|
"role": "passeur",
|
||||||
"origin": "survivant",
|
"origin_pool": ["survivant", "goule"],
|
||||||
|
"faction_origin_override": {
|
||||||
|
"grand_krewe": "goule"
|
||||||
|
},
|
||||||
"tier": 3,
|
"tier": 3,
|
||||||
"description": "Guide qui connaît les routes secrètes à travers les bayous",
|
"description": "Guide qui connaît les routes secrètes à travers les bayous — souvent une goule très ancienne",
|
||||||
"faction_pool": [null, "ecumeurs"],
|
"faction_pool": [null, "grand_krewe"],
|
||||||
"location_hints": ["pearl_river", "donaldsonville", "oak_plantation"],
|
"location_hints": ["pearl_river", "donaldsonville", "la_paroisse", "nola_fleuve"],
|
||||||
"caps_range": [100, 600],
|
"caps_range": [100, 600],
|
||||||
"personality_traits": ["taciturne", "fiable si payé", "indépendant", "survivaliste"],
|
"personality_traits": ["taciturne", "fiable si payé", "indépendant", "survivaliste"],
|
||||||
"motivations": ["caps", "indépendance totale", "connaître les secrets des factions"],
|
"motivations": ["caps", "indépendance totale", "connaître les secrets des factions"],
|
||||||
@@ -68,7 +78,8 @@
|
|||||||
|
|
||||||
"chasseur_primes": {
|
"chasseur_primes": {
|
||||||
"role": "chasseur_primes",
|
"role": "chasseur_primes",
|
||||||
"origin": "survivant",
|
"origin_pool": ["survivant", "goule", "habitant_abri"],
|
||||||
|
"faction_origin_override": {},
|
||||||
"tier": 3,
|
"tier": 3,
|
||||||
"description": "Mercenaire qui traite les contrats d'élimination ou de capture",
|
"description": "Mercenaire qui traite les contrats d'élimination ou de capture",
|
||||||
"faction_pool": [null, "syndicat_capitole"],
|
"faction_pool": [null, "syndicat_capitole"],
|
||||||
@@ -81,7 +92,8 @@
|
|||||||
|
|
||||||
"scavenger_freelance": {
|
"scavenger_freelance": {
|
||||||
"role": "scavenger",
|
"role": "scavenger",
|
||||||
"origin": "survivant",
|
"origin_pool": ["survivant", "goule"],
|
||||||
|
"faction_origin_override": {},
|
||||||
"tier": 3,
|
"tier": 3,
|
||||||
"description": "Récupérateur de ferraille et de technologie pré-guerre",
|
"description": "Récupérateur de ferraille et de technologie pré-guerre",
|
||||||
"faction_pool": [null],
|
"faction_pool": [null],
|
||||||
@@ -94,7 +106,8 @@
|
|||||||
|
|
||||||
"medecin_freelance": {
|
"medecin_freelance": {
|
||||||
"role": "docteur",
|
"role": "docteur",
|
||||||
"origin": "habitant_abri",
|
"origin_pool": ["habitant_abri", "survivant", "goule"],
|
||||||
|
"faction_origin_override": {},
|
||||||
"tier": 3,
|
"tier": 3,
|
||||||
"description": "Médecin indépendant qui soigne sans question contre paiement",
|
"description": "Médecin indépendant qui soigne sans question contre paiement",
|
||||||
"faction_pool": [null, "union", "consortium"],
|
"faction_pool": [null, "union", "consortium"],
|
||||||
@@ -107,11 +120,12 @@
|
|||||||
|
|
||||||
"messager_faction": {
|
"messager_faction": {
|
||||||
"role": "passeur",
|
"role": "passeur",
|
||||||
"origin": "survivant",
|
"origin_pool": ["survivant", "habitant_abri"],
|
||||||
|
"faction_origin_override": {},
|
||||||
"tier": 3,
|
"tier": 3,
|
||||||
"description": "Courrier entre factions, transporte messages et petits colis",
|
"description": "Courrier entre factions, transporte messages et petits colis",
|
||||||
"faction_pool": ["union", "consortium", "regie", "syndicat_capitole"],
|
"faction_pool": ["union", "consortium", "regie", "syndicat_capitole"],
|
||||||
"location_hints": ["toutes zones sûres"],
|
"location_hints": ["independance", "laplace", "nola_vieux_carre", "baton_rouge", "nola_cbd"],
|
||||||
"caps_range": [50, 300],
|
"caps_range": [50, 300],
|
||||||
"personality_traits": ["discret", "rapide", "mémorise sans noter", "refuse de lire les messages"],
|
"personality_traits": ["discret", "rapide", "mémorise sans noter", "refuse de lire les messages"],
|
||||||
"motivations": ["caps par livraison", "rester neutre", "éviter d'être intercepté"],
|
"motivations": ["caps par livraison", "rester neutre", "éviter d'être intercepté"],
|
||||||
@@ -120,11 +134,13 @@
|
|||||||
|
|
||||||
"fugitif": {
|
"fugitif": {
|
||||||
"role": "survivant_generique",
|
"role": "survivant_generique",
|
||||||
"origin": "survivant",
|
"origin_pool": ["survivant", "habitant_abri", "goule"],
|
||||||
|
"faction_origin_override": {},
|
||||||
"tier": 3,
|
"tier": 3,
|
||||||
"description": "Quelqu'un qui fuit une faction — esclave évadé, déserteur, criminel",
|
"description": "Quelqu'un qui fuit une faction — esclave évadé, déserteur, criminel, témoin gênant",
|
||||||
"faction_pool": [null],
|
"faction_pool": [null],
|
||||||
"location_hints": ["pearl_river", "nola_cbd", "donaldsonville"],
|
"chased_by_faction_pool": ["union", "cda", "syndicat_capitole", "regie", "dynaste_oak", "ecumeurs"],
|
||||||
|
"location_hints": ["pearl_river", "nola_cbd", "donaldsonville", "la_paroisse"],
|
||||||
"caps_range": [0, 50],
|
"caps_range": [0, 50],
|
||||||
"personality_traits": ["terrorisé", "méfiant extrême", "désespéré", "potentiellement dangereux"],
|
"personality_traits": ["terrorisé", "méfiant extrême", "désespéré", "potentiellement dangereux"],
|
||||||
"motivations": ["ne pas être retrouvé", "atteindre une zone sûre", "survivre une journée de plus"],
|
"motivations": ["ne pas être retrouvé", "atteindre une zone sûre", "survivre une journée de plus"],
|
||||||
@@ -133,7 +149,10 @@
|
|||||||
|
|
||||||
"technicien_freelance": {
|
"technicien_freelance": {
|
||||||
"role": "technicien",
|
"role": "technicien",
|
||||||
"origin": "initie_confrerie",
|
"origin_pool": ["initie_confrerie", "habitant_abri", "survivant"],
|
||||||
|
"faction_origin_override": {
|
||||||
|
"cda": "initie_confrerie"
|
||||||
|
},
|
||||||
"tier": 3,
|
"tier": 3,
|
||||||
"description": "Ingénieur indépendant qui répare armes, générateurs et pip-boys",
|
"description": "Ingénieur indépendant qui répare armes, générateurs et pip-boys",
|
||||||
"faction_pool": [null, "consortium"],
|
"faction_pool": [null, "consortium"],
|
||||||
@@ -146,11 +165,15 @@
|
|||||||
|
|
||||||
"lieutenant_faction": {
|
"lieutenant_faction": {
|
||||||
"role": "lieutenant",
|
"role": "lieutenant",
|
||||||
"origin": "survivant",
|
"origin_pool": ["survivant", "habitant_abri", "initie_confrerie", "goule"],
|
||||||
|
"faction_origin_override": {
|
||||||
|
"cda": "initie_confrerie",
|
||||||
|
"grand_krewe": "goule"
|
||||||
|
},
|
||||||
"tier": 2,
|
"tier": 2,
|
||||||
"description": "Officier de rang intermédiaire, bras droit opérationnel d'un chef",
|
"description": "Officier de rang intermédiaire, bras droit opérationnel d'un chef",
|
||||||
"faction_pool": ["union", "cda", "syndicat_capitole", "regie", "dynaste_oak", "ecumeurs", "consortium", "grand_krewe"],
|
"faction_pool": ["union", "cda", "syndicat_capitole", "regie", "dynaste_oak", "ecumeurs", "consortium", "grand_krewe"],
|
||||||
"location_hints": ["QG ou zone clé de la faction"],
|
"location_hints": ["independance", "baton_rouge", "nola_vieux_carre", "la_paroisse", "oak_plantation", "pearl_river", "laplace", "nola_cbd"],
|
||||||
"caps_range": [200, 800],
|
"caps_range": [200, 800],
|
||||||
"personality_traits": ["ambitieux", "dévoué à la faction", "respecté des gardes", "jaloux du boss"],
|
"personality_traits": ["ambitieux", "dévoué à la faction", "respecté des gardes", "jaloux du boss"],
|
||||||
"motivations": ["monter en grade", "protéger la faction", "accumuler des ressources personnelles"],
|
"motivations": ["monter en grade", "protéger la faction", "accumuler des ressources personnelles"],
|
||||||
|
|||||||
@@ -203,11 +203,11 @@ _ROLE_TO_ORIGIN: dict[str, list[str]] = {
|
|||||||
"docteur": ["survivant", "habitant_abri"],
|
"docteur": ["survivant", "habitant_abri"],
|
||||||
"technicien": ["initie_confrerie", "habitant_abri", "survivant"],
|
"technicien": ["initie_confrerie", "habitant_abri", "survivant"],
|
||||||
"raider_boss": ["survivant", "super_mutant"],
|
"raider_boss": ["survivant", "super_mutant"],
|
||||||
"lieutenant": ["survivant", "habitant_abri"],
|
"lieutenant": ["survivant", "habitant_abri", "initie_confrerie", "goule"],
|
||||||
"chasseur_primes": ["survivant"],
|
"chasseur_primes": ["survivant", "goule", "habitant_abri"],
|
||||||
"passeur": ["survivant", "goule"],
|
"passeur": ["survivant", "goule"],
|
||||||
"scavenger": ["survivant", "goule"],
|
"scavenger": ["survivant", "goule"],
|
||||||
"chef_faction": ["survivant", "habitant_abri"],
|
"chef_faction": ["survivant", "habitant_abri", "goule"],
|
||||||
"survivant_generique": ["survivant", "habitant_abri"],
|
"survivant_generique": ["survivant", "habitant_abri"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -123,13 +123,26 @@ def spawn_from_archetype(
|
|||||||
rng = random.Random(seed)
|
rng = random.Random(seed)
|
||||||
|
|
||||||
role = arch["role"]
|
role = arch["role"]
|
||||||
origin = arch.get("origin", "survivant")
|
|
||||||
tier = tier_override if tier_override is not None else arch.get("tier", 3)
|
tier = tier_override if tier_override is not None else arch.get("tier", 3)
|
||||||
|
|
||||||
if faction_slug is None:
|
if faction_slug is None:
|
||||||
pool = [f for f in arch.get("faction_pool", [None])]
|
pool = arch.get("faction_pool", [None])
|
||||||
faction_slug = rng.choice(pool)
|
faction_slug = rng.choice(pool)
|
||||||
|
|
||||||
|
# Résolution de l'origine : faction_origin_override prime sur origin_pool
|
||||||
|
origin_override = arch.get("faction_origin_override", {})
|
||||||
|
if faction_slug and faction_slug in origin_override:
|
||||||
|
origin = origin_override[faction_slug]
|
||||||
|
elif "origin_pool" in arch:
|
||||||
|
origin = rng.choice(arch["origin_pool"])
|
||||||
|
else:
|
||||||
|
origin = arch.get("origin", "survivant")
|
||||||
|
|
||||||
|
# Métadonnées narratives supplémentaires (ex: fugitif → chased_by)
|
||||||
|
chased_by = None
|
||||||
|
if "chased_by_faction_pool" in arch:
|
||||||
|
chased_by = rng.choice(arch["chased_by_faction_pool"])
|
||||||
|
|
||||||
char = cc.generate_character(
|
char = cc.generate_character(
|
||||||
session_id = session_id,
|
session_id = session_id,
|
||||||
role = role,
|
role = role,
|
||||||
@@ -148,6 +161,8 @@ def spawn_from_archetype(
|
|||||||
items = equip_character(char["id"], equip_role, session_id, seed=seed)
|
items = equip_character(char["id"], equip_role, session_id, seed=seed)
|
||||||
|
|
||||||
char["items_equipped"] = items
|
char["items_equipped"] = items
|
||||||
|
if chased_by:
|
||||||
|
char["chased_by_faction"] = chased_by
|
||||||
return char
|
return char
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user