# Untergrund: `investigate_affair` Wie die anderen Underground-Tasks: Zeile in `falukant_data.underground` mit `result IS NULL`, nach ≥1 Tag verarbeitet der `UndergroundWorker`. ## Typ in der Datenbank In `falukant_type.underground` einen Eintrag mit **`tr = 'investigate_affair'`** und Backend-Logik, die den Auftrag anlegt. ## Semantik (Spec: Liebschaften & Untergrund) | Feld | Bedeutung | |------|-----------| | `performer_id` | Charakter-ID des Ausspionierenden | | `victim_id` | Charakter-ID des Opfers (mit Liebschaft) | | `parameters` (JSON) | `goal`: `"expose"` (Standard) oder `"blackmail"`; optional `relationship_id` (int): feste Liebschaft — sonst **höchster `discoveryScore`** unter allen aktiven `lover`-Beziehungen | ### `discoveryScore` (Auswahl der Ziel-Liebschaft) Gewichtung u. a.: `visibility`, `discretion`, `acknowledged`, Kinder (hidden/public, Deckel +20), Altersstufen, Haushalt/Diener (Leak-Bonus, Deckel +15), mehrere aktive Liebschaften, `status_fit`. ### Erfolg - `successChance = clamp(20 + discoveryScore * 0.55, 5, 95)` (Prozent) - Wurf 0–100: `roll ≤ successChance * 0.55` → voller Erfolg; `roll ≤ successChance` → Teilerfolg; sonst Fehlschlag ### `goal = expose` Voller/Teilerfolg: Sichtbarkeit und Diskretion des Ziel-`relationship_state` werden angepasst, Ruf des **Opfers** (`victim_id`) sinkt. Ab `visibility ≥ 60` nach Anpassung: **Sofort-Skandalprüfung** mit WebSocket (`falukant_family_scandal_hint`, `falukantUpdateFamily` mit `reason: scandal`, `falukantUpdateStatus`). ### `goal = blackmail` Voller/Teilerfolg: geringere Sichtbarkeits-/Diskretions-Effekte als bei `expose`; **`blackmailAmount`** aus Basisformel (Ruf, Sichtbarkeit, Stand, Kinder) × `outcomeFactor` (1.0 / 0.55). ### Fehlschlag `status: failed`, `outcome: failure`, `discoveries: null`, Hinweis `no proof` — keine DB-Änderungen an Liebschaft/Ruf. ## Ergebnis-JSON (`result`) Mindestens: `status`, `outcome`, `discoveries` (Pflichtfelder laut Spec), `visibilityDelta`, `reputationDelta`, optional `blackmailAmount`, `discoveryScore`, `successChance`, `roll`, `tier`, `notes`. ## WebSocket - Nach jedem Job: **`underground_processed`** (wie bisher). - Bei ausgelöstem **Skandal** (nur `expose` mit ausreichender Sichtbarkeit und bestandenem Wurf): wie oben. ## Idempotenz Weiterhin nur Zeilen mit **`result IS NULL`**; nach Verarbeitung wird `result` gesetzt (Daemon fasst den Auftrag nicht erneut an).