feat: systeme tiers PNJ 0-3 + equipment by role + archetype factory

migration_003: tier/archetype_key, boss exclus sim, equipement distinctif
equipment_by_role.json: loadouts par role (armes/armure/consommables)
archetypes.json: 11 archetypes tier3 + lieutenant tier2
pnj_factory.py: spawn_from_archetype, equip_character, spawn_batch
character_creator.py: nouveaux roles + tier + archetype_key dans INSERT
init_pnj.py: 10 PNJ tier1 + 8 lieutenants tier2 par faction
db.py: get_characters(min_tier=1) exclut boss, get_all_characters pour seeds
tick.py: seeds tous tiers, survival/actions tier>=1 seulement

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Corback
2026-06-16 01:04:01 +02:00
parent c422d62f10
commit 873106d5cb
8 changed files with 895 additions and 44 deletions
+88 -30
View File
@@ -1,5 +1,6 @@
"""
Script one-shot : crée 10 PNJ de test en DB pour la pré-sim 3 jours pacifique.
Script one-shot : crée les PNJ tier 1 (actifs sim) et tier 2 (PNJ+ nommés).
Les boss tier 0 sont créés via fixtures.sql + migration_003.
Lance avec : python init_pnj.py
"""
@@ -7,48 +8,105 @@ import sys, os
sys.path.insert(0, os.path.dirname(__file__))
import character_creator as cc
import pnj_factory as factory
import db
SESSION_ID = 1
PNJ_SPECS = [
# ---------------------------------------------------------------------------
# Tier 1 — ACTIFS SIM (15 PNJ, boucle survival + actions complète)
# ---------------------------------------------------------------------------
TIER1_SPECS = [
# (role, origin, name, faction, location)
("garde", "survivant", "Thibodaux 'Gator'", "union", "nola_cbd"),
("garde", "initie_confrerie","Fontenot 'Ironhide'", "cda", "nola_cbd"),
("marchand", "habitant_abri", "LaFleur 'Vieux'", "consortium", "nola_vieux_carre"),
("marchand", "survivant", "Broussard 'Fil-de-Fer'", "regie", "nola_vieux_carre"),
("eclaireur", "goule", "Mouton 'Marécage'", None, "pearl_river"),
("eclaireur", "survivant", "Trahan 'Mudcat'", "union", "pearl_river"),
("docteur", "habitant_abri", "Hébert 'Tripette'", "union", "nola_cbd"),
("technicien", "initie_confrerie","Landry 'Rouille'", "consortium", "baton_rouge"),
("pillard", "survivant", "Arceneaux 'Crapaud'", "ecumeurs", "pearl_river"),
("survivant_generique","survivant", "Guidry 'Gris-Gris'", None, "nola_vieux_carre"),
("garde", "survivant", "Thibodaux 'Gator'", "union", "nola_cbd"),
("garde", "initie_confrerie","Fontenot 'Ironhide'", "cda", "nola_cbd"),
("marchand", "habitant_abri", "LaFleur 'Vieux'", "consortium", "nola_vieux_carre"),
("marchand", "survivant", "Broussard 'Fil-de-Fer'", "regie", "nola_vieux_carre"),
("eclaireur", "goule", "Mouton 'Marécage'", None, "pearl_river"),
("eclaireur", "survivant", "Trahan 'Mudcat'", "union", "pearl_river"),
("docteur", "habitant_abri", "Hébert 'Tripette'", "union", "nola_cbd"),
("technicien", "initie_confrerie","Landry 'Rouille'", "consortium", "baton_rouge"),
("pillard", "survivant", "Arceneaux 'Crapaud'", "ecumeurs", "pearl_river"),
("survivant_generique","survivant", "Guidry 'Gris-Gris'", None, "nola_vieux_carre"),
]
# ---------------------------------------------------------------------------
# Tier 2 — PNJ+ (personnages nommés secondaires, 1-2 par faction majeure)
# ---------------------------------------------------------------------------
TIER2_SPECS = [
# (archetype, name, faction, location, seed)
("lieutenant_faction", "Jean-Baptiste 'Fer' Caillouet", "union", "independance", 2001),
("lieutenant_faction", "Ramon 'Cobra' Villaverde", "syndicat_capitole", "baton_rouge", 2002),
("lieutenant_faction", "Lila 'Plomb' Moreau", "cda", "nola_fleuve", 2003),
("lieutenant_faction", "Zuzu 'Os-Blanc' Delacourt", "grand_krewe", "la_paroisse", 2004),
("lieutenant_faction", "Thérèse 'Circuit' Nguyen", "consortium", "laplace", 2005),
("lieutenant_faction", "Edmond 'Sèche' Bautista", "regie", "nola_vieux_carre",2006),
("lieutenant_faction", "Calhoun 'Fouet' Arceneaux", "dynaste_oak", "oak_plantation", 2007),
("lieutenant_faction", "Roscoe 'Requiem' Fontenot", "ecumeurs", "pearl_river", 2008),
]
def equip_tier1(char_id: int, role: str):
"""Équipe un PNJ tier 1 selon son rôle via pnj_factory."""
items = factory.equip_character(char_id, role, SESSION_ID)
return items
def main():
print(f"=== Création de {len(PNJ_SPECS)} PNJ — Session {SESSION_ID} ===\n")
created = []
for i, (role, origin, name, faction, location) in enumerate(PNJ_SPECS, 1):
print(f"=== Initialisation PNJ — Session {SESSION_ID} ===\n")
# --- Tier 1 ---
print(f"--- Tier 1 : {len(TIER1_SPECS)} PNJ actifs ---\n")
tier1_created = []
for i, (role, origin, name, faction, location) in enumerate(TIER1_SPECS, 1):
char = cc.generate_character(
session_id=SESSION_ID,
role=role,
origin=origin,
name=name,
faction_slug=faction,
location_slug=location,
character_type="pnj_sim",
seed=1000 + i,
save_to_db=True,
session_id = SESSION_ID,
role = role,
origin = origin,
name = name,
faction_slug = faction,
location_slug = location,
character_type = "pnj_sim",
seed = 1000 + i,
save_to_db = True,
tier = 1,
)
created.append(char)
items = equip_tier1(char["id"], role)
tier1_created.append(char)
print(cc.format_sheet(char))
print()
print(f" Équipement : {', '.join(items) or ''}\n")
print(f"{len(created)} PNJ insérés en DB (session {SESSION_ID})")
# --- Tier 2 ---
print(f"\n--- Tier 2 : {len(TIER2_SPECS)} PNJ+ nommés ---\n")
tier2_created = []
for archetype, name, faction, location, seed in TIER2_SPECS:
char = factory.spawn_from_archetype(
archetype_key = archetype,
session_id = SESSION_ID,
name = name,
faction_slug = faction,
location_slug = location,
seed = seed,
tier_override = 2,
)
tier2_created.append(char)
print(f" [TIER2] {name:<40} {faction or 'sans faction':<20} @ {location}")
print(f" Équipement : {', '.join(char.get('items_equipped', []))}\n")
# --- Résumé ---
total = len(tier1_created) + len(tier2_created)
all_chars = db.get_characters(SESSION_ID)
print(f"\n{total} PNJ créés ({len(tier1_created)} tier1 + {len(tier2_created)} tier2)")
print(f" DB total (all tiers) : {len(all_chars)} PNJ vivants en session {SESSION_ID}")
by_tier = {}
for c in all_chars:
t = c.get("tier", 1)
by_tier[t] = by_tier.get(t, 0) + 1
for t in sorted(by_tier):
labels = {0: "BOSS", 1: "ACTIFS SIM", 2: "PNJ+", 3: "PASSAGE"}
print(f" Tier {t} ({labels.get(t,'?')}) : {by_tier[t]} PNJ")
# Vérification rapide
chars = db.get_characters(SESSION_ID)
print(f" DB confirme : {len(chars)} PNJ vivants en session {SESSION_ID}")
if __name__ == "__main__":
main()