dashboard/app.py:
load_sim_config() retourne None (pas {}) quand le fichier est absent
— {} est falsy en Python, masquait le formulaire même quand la config
était chargeable mais vide. None est explicitement distinguable.
load_all_modes() charge toujours depuis sim_001.json (référence 5 modes)
— sim_002 n'a qu'un seul mode dans son bloc 'modes', le tableau comparatif
était vide pour S2.
{% if cfg is not none %} dans le template au lieu de {% if cfg %}
Message d'avertissement sous le bouton save : prise en compte au prochain jour
Message d'erreur précis si fichier introuvable (path + hint mount Docker)
/params/save: vérification if cfg is None
run.py:
Hot-reload config à chaque tick==0 (frontière de jour) :
cfg.load(config_path, session_id=SESSION_ID)
effective_mode mis à jour depuis la config rechargée
tick_sleep recalculé (TICK_SLEEP_SEC env var prime toujours)
→ Changer mode/drain/encounter via dashboard prend effet le jour suivant
sans redémarrer le process
encounter_tables.json:
safe_zones: [independance, nola_vieux_carre, baton_rouge, laplace]
Zone safe: zone_type=safe, tier_weights sans lambda/group (actif+boss seulement)
raid_chance: probabilité séparée par zone (0.4-0.8%) indépendante du roll normal
entity_pools.raid_faction: commando éclaireur + milice faction hostile
urban_trade_roles: rôles autorisés à faire du commerce en ville
orientation_reactions: ajout réaction 'trade' pour marchands/doc/tech/passeur/scavenger
outcomes.trade: success (+caps, stress-1) / failed (aucun effet)
encounter.py:
_is_safe_zone(): vérifie si zone est dans safe_zones
should_trigger_raid(): roll séparé par zone pour déclencher un raid
generate_entity_trade(): cherche un PNJ compatible dans la même zone pour échange
generate_entity_raid(): génère un commando de faction ennemie avec contexte faction
_trade_roll(): jet CHA+LCK pour conclure une vente, caps_gain 10-60
resolve_encounter(): branche 'trade' → caps gagnés si succès
process_encounters_tick():
- Roll de raid une fois par zone sûre (pas par PNJ)
- PNJ en zone raidée → encounter_raid, skip encounter normal ce tick
- Zone safe + rôle commerçant → priorité generate_entity_trade sur actif
- Fallback boss en zone safe → None (pas de lambda)
Logique résultante:
Pearl River (dangerous): alligators, goules, raiders → inchangé
Independance (safe): un marchand croise un autre PNJ → vente possible
Raid rare sur independance: commando Union/Ecumeurs → combat ou fuite
Bêtes en ville: impossible
combat_engine.py: weapon_props = weapon.get('properties') or {} if weapon else {}
La ligne n'avait pas le guard 'if weapon else' contrairement aux deux lignes précédentes,
crash AttributeError quand un PNJ attaque sans arme équipée.
init_pnj.py: SESSION_ID = int(os.getenv('SESSION_ID', 1))
Était hardcodé à 1, empêchait l'init des PNJ de la session 2.