Implement debtors prison features across the application: Enhance FalukantController to include debtors prison logic in various service methods. Update FalukantService to manage debtors prison state and integrate it into user data retrieval. Modify frontend components, including DashboardWidget, StatusBar, and BankView, to display debtors prison status and warnings. Add localization for debtors prison messages in English, German, and Spanish, ensuring clarity in user notifications and actions.

This commit is contained in:
Torsten Schulz (local)
2026-03-23 11:59:59 +01:00
parent f2343098d2
commit 9b88a98a20
19 changed files with 1643 additions and 102 deletions

View File

@@ -0,0 +1,447 @@
# Falukant: Schuldturm und Pfändung - Daemon-Spezifikation
Dieses Dokument beschreibt die Umsetzung des **Schuldturm-Systems** im externen Daemon.
Wichtig:
- Die projektseitigen DB-Felder, API-Erweiterungen, UI-Warnungen und Aktionssperren sind bereits umgesetzt.
- Der Daemon ist die führende Quelle für:
- Verzugstage
- Eintritt in den Schuldturm
- Pfändung und Verwertung
- soziale Folgen
- Freilassung
## 1. Bereits vorhandene Datenbasis
Bereits im Projekt vorhanden:
- `falukant_data.credit`
- `falukant_data.debtors_prism`
- `falukant_data.user_house`
- inkl. `household_tension_score`
- inkl. `household_tension_reasons_json`
- Familien-/Liebschaftsdaten in:
- `falukant_data.relationship`
- `falukant_data.relationship_state`
- `falukant_data.child_relation`
Bereits erweitert:
- `debtors_prism.status`
- `debtors_prism.entered_at`
- `debtors_prism.released_at`
- `debtors_prism.debt_at_entry`
- `debtors_prism.remaining_debt`
- `debtors_prism.days_overdue`
- `debtors_prism.reason`
- `debtors_prism.creditworthiness_penalty`
- `debtors_prism.next_forced_action`
- `debtors_prism.assets_seized_json`
- `debtors_prism.public_known`
Es sind für den Daemon derzeit keine weiteren DB-Änderungen nötig.
## 2. Grundregel
Ein Charakter kommt in den Schuldturm, wenn:
- mindestens ein aktiver Kredit offen ist
- fällige Kreditbedienung ausbleibt
- und `days_overdue >= 3`
Der Daemon prüft dies im Daily-Tick.
## 3. Zustände
`debtors_prism.status` verwendet mindestens:
- `delinquent`
- `imprisoned`
- `released`
Bedeutung:
- `delinquent`: Kreditverzug, aber noch nicht im Schuldturm
- `imprisoned`: im Schuldturm, Verwertung läuft
- `released`: historischer abgeschlossener Fall
## 4. Daily-Tick
Der Daily-Tick prüft pro Falukant-Nutzer:
1. aktive Kredite
2. verbleibende Schuld
3. geleistete Bedienung seit letztem Tick
4. neue Verzugstage
5. Schuldturm-Eintritt
6. laufende soziale Folgen
7. Verwertungsschritt
### 4.1 Verzugstage
Regel:
- wenn offene Schuld vorhanden und fällige Bedienung ausbleibt:
- `days_overdue += 1`
- wenn Kreditpflicht erfüllt wurde:
- `days_overdue = 0`
- falls nicht im Schuldturm
Wenn noch kein aktiver `debtors_prism`-Eintrag existiert:
- bei erstem Verzug `debtors_prism` anlegen mit
- `status = 'delinquent'`
- `days_overdue = 1`
- `remaining_debt = aktuelle offene Schuld`
- `next_forced_action = 'reminder'`
### 4.2 Warnstufen
Bei Verzug:
- Tag 1:
- `next_forced_action = 'reminder'`
- Event `falukantUpdateDebt` mit `reason: 'delinquency'`
- Tag 2:
- `next_forced_action = 'final_warning'`
- Event `falukantUpdateDebt` mit `reason: 'delinquency'`
- Tag 3:
- Schuldturm-Eintritt
Für Warnstufen senden:
- `falukantUpdateDebt`
- zusätzlich `falukantUpdateStatus`
## 5. Eintritt in den Schuldturm
Bei `days_overdue >= 3`:
- `status = 'imprisoned'`
- `entered_at = now()`
- `released_at = null`
- `debt_at_entry = aktuelle offene Schuld`
- `remaining_debt = aktuelle offene Schuld`
- `reason = 'credit_default'`
- `creditworthiness_penalty += 45`
- `next_forced_action = 'asset_seizure'`
- `public_known = true`
### 5.1 Sofortfolgen bei Eintritt
Einmalig anwenden:
- Reputation deutlich senken
- Empfehlung: `-12`
- `marriage_satisfaction` senken
- Empfehlung: `-10`
- `household_tension_score` erhöhen
- Empfehlung: `+15`
- `household_tension_reasons_json` um `debtorsPrison` ergänzen
Zusätzlich:
- aktive Liebhaber/Mätressen sichtbar destabilisieren
- mindestens `affection -= 4`
- Kreditaufnahme und aktive Falukant-Aktionen bleiben projektseitig bereits gesperrt
Bei Eintritt senden:
- `falukantUpdateDebt`
- `reason: 'debtors_prison_entered'`
- `falukantUpdateStatus`
- `falukantUpdateFamily`
- `reason: 'daily'`
- `falukantHouseUpdate`
- `falukantBranchUpdate`
## 6. Verwertung / Pfändung
Die Verwertung läuft nicht alles auf einmal, sondern schrittweise pro Tick.
Reihenfolge:
1. freies Geld
2. Fahrzeuge
3. Waren / Lagerbestände
4. Haus
5. Niederlassungen
Ziel:
- `remaining_debt` schrittweise senken
- Fortschritt im UI sichtbar machen
### 6.1 Geld
Wenn `falukant_user.money > 0`:
- direkt zur Schuld tilgen
- `remaining_debt -= eingezogener_betrag`
Events:
- `falukantUpdateDebt`
- `reason: 'asset_seizure'`
- `falukantUpdateStatus`
### 6.2 Fahrzeuge
Verkaufe zuerst:
- freie Fahrzeuge
- dann weniger wertvolle Typen
- keine Fahrzeuge in aktiven Transporten im selben Tick anfassen, falls technisch problematisch
Erlös:
- Empfehlung: `vehicle_type.cost * condition_factor * 0.55`
Zusätzlich in `assets_seized_json` protokollieren:
- Typ
- Anzahl
- Erlös
Events:
- `falukantUpdateDebt`
- `reason: 'vehicle_liquidation'`
- `falukantUpdateStatus`
### 6.3 Waren / Lager
Verwertbare Güter:
- Lagerbestände
- Inventar
- handelbare Waren
Erlös:
- Empfehlung: Marktwert mit Abschlag von `35% bis 50%`
Events:
- `falukantUpdateDebt`
- `reason: 'asset_seizure'`
- `falukantUpdateStatus`
- `falukantBranchUpdate`
### 6.4 Haus
Wenn Restschuld nach Geld/Fahrzeugen/Waren weiter hoch ist:
- Haus pfänden
- Spieler auf niedrigeres Haus oder Minimalhaus zurücksetzen
- Dienerschaft reduzieren
- `household_order` senken
Events:
- `falukantUpdateDebt`
- `reason: 'house_seizure'`
- `falukantHouseUpdate`
- `falukantUpdateStatus`
- `falukantUpdateFamily`
- `reason: 'daily'`
### 6.5 Niederlassungen
Wenn weiter nicht gedeckt:
- Niederlassungen schließen
- zuerst niedrige Stufe / niedriger Wert
- Hauptniederlassung nur als letzter Schritt
Events:
- `falukantUpdateDebt`
- `reason: 'branch_closure'`
- `falukantBranchUpdate`
- `falukantUpdateStatus`
## 7. Laufende soziale Folgen im Schuldturm
Solange `status = 'imprisoned'`:
- täglicher Reputationsmalus
- Empfehlung: `-2`
- zusätzliche `creditworthiness_penalty += 1` pro Tag
- `marriage_satisfaction -= 1`
- `household_tension_score += 2`
Wenn aktive Liebschaften bestehen:
- `affection -= 2`
- bei niedriger Zuneigung oder hoher Sichtbarkeit kann Beziehung enden
Empfohlene Absprungregel:
- wenn `affection <= 30` oder `months_underfunded >= 2`
- Chance auf Beziehungsende prüfen
- bei repräsentativen Beziehungen zusätzlich höhere Absprungchance, wenn `public_known = true`
Events bei sozialen Folgewirkungen:
- `falukantUpdateFamily`
- `reason: 'daily'`
- zusätzlich `falukantUpdateStatus`
## 8. Kreditwürdigkeit
Die UI rechnet bereits aus `creditworthiness_penalty` und Status einen sichtbaren Wert.
Der Daemon muss pflegen:
- `creditworthiness_penalty`
- `status`
- `days_overdue`
Empfehlung:
- Eintritt Schuldturm: `+45`
- pro weiterem Hafttag: `+1`
- Hauspfändung: zusätzlich `+10`
- Niederlassungsschließung: zusätzlich `+8`
## 9. Freilassung
Freilassung, wenn:
- keine relevante Restschuld mehr offen ist
oder
- ein definierter Restwert unterschritten wird, falls ihr einen Bagatellgrenzwert wollt
Dann:
- `status = 'released'`
- `released_at = now()`
- `next_forced_action = null`
- `days_overdue = 0`
- `remaining_debt = 0`
Events:
- `falukantUpdateDebt`
- `reason: 'debtors_prison_released'`
- `falukantUpdateStatus`
- `falukantUpdateFamily`
- `reason: 'daily'`
- `falukantHouseUpdate`
- `falukantBranchUpdate`
Keine automatische vollständige soziale Heilung:
- Reputation bleibt reduziert
- Kreditwürdigkeit bleibt reduziert
- Familie/Haus bleiben in Folgezuständen
## 10. Event-Kommunikation zur UI
Der Daemon sendet als Primärevent:
```json
{
"event": "falukantUpdateDebt",
"user_id": 123,
"reason": "delinquency"
}
```
Mögliche `reason`:
- `delinquency`
- `debtors_prison_entered`
- `asset_seizure`
- `vehicle_liquidation`
- `house_seizure`
- `branch_closure`
- `debtors_prison_released`
### 10.1 Begleitevents
Je nach Folge zusätzlich:
- `falukantUpdateStatus`
- `falukantHouseUpdate`
- `falukantBranchUpdate`
- `falukantUpdateFamily`
### 10.2 Empfohlene Minimalregeln
- `delinquency`:
- `falukantUpdateDebt`
- `falukantUpdateStatus`
- `debtors_prison_entered`:
- `falukantUpdateDebt`
- `falukantUpdateStatus`
- `falukantUpdateFamily`
- `falukantHouseUpdate`
- `falukantBranchUpdate`
- `asset_seizure`:
- `falukantUpdateDebt`
- `falukantUpdateStatus`
- optional `falukantBranchUpdate`
- `vehicle_liquidation`:
- `falukantUpdateDebt`
- `falukantUpdateStatus`
- `house_seizure`:
- `falukantUpdateDebt`
- `falukantUpdateStatus`
- `falukantHouseUpdate`
- `falukantUpdateFamily`
- `branch_closure`:
- `falukantUpdateDebt`
- `falukantUpdateStatus`
- `falukantBranchUpdate`
- `debtors_prison_released`:
- `falukantUpdateDebt`
- `falukantUpdateStatus`
- `falukantUpdateFamily`
- `falukantHouseUpdate`
- `falukantBranchUpdate`
## 11. Idempotenz
Der Worker muss idempotent arbeiten.
Wichtig:
- Eintritt in den Schuldturm nicht mehrfach für denselben aktiven Fall auslösen
- Verwertungsschritte nur einmal je Asset anwenden
- `released` nicht erneut freisetzen
Empfehlung:
- pro Tick Transaktion
- pro Nutzer eine klare Reihenfolge
- Änderungen in `assets_seized_json` protokollieren
## 12. Mindestumsetzung für Version 1
Pflicht:
1. Verzugstage pflegen
2. Eintritt nach 3 Tagen
3. Status und Penalty schreiben
4. Geld zuerst einziehen
5. danach Fahrzeuge
6. Events senden
Danach:
7. Hauspfändung
8. Niederlassungsschließung
9. volle Familienfolgen
## 13. Hinweis an den Daemon
Die projektseitigen Grundlagen sind bereits umgesetzt:
- `debtors_prism` ist erweitert
- Bank-/Haus-/Familien-/Übersichts-UI reagiert auf den Status
- aktive Falukant-Aktionen werden im Backend bereits gesperrt, sobald `inDebtorsPrison = true`
Der Daemon muss daher vor allem die Zustände und Folgen zuverlässig schreiben und die dokumentierten Events senden.

View File

@@ -1,8 +1,9 @@
# Falukant: UI-Anpassung WebSocket & Familie / Liebschaften
# Falukant: UI-Anpassung - WebSocket & Familie / Liebschaften
Dieses Dokument beschreibt die Nachrichten, die der externe Falukant-Daemon für Familien-, Ehe- und Liebschaftsänderungen sendet, damit die UI gezielt reagieren kann.
Dieses Dokument beschreibt die Nachrichten, die der externe Falukant-Daemon über den WebSocket-Broadcast sendet, damit die UI gezielt reagieren kann.
Transport:
- Alle Clients erhalten denselben Broadcast.
- Die UI muss nach `user_id` filtern und nur Events für die eingeloggte Session verarbeiten.
@@ -10,10 +11,13 @@ Transport:
| `event` | Pflichtfelder | Typische UI-Reaktion |
|---------|----------------|----------------------|
| `falukantUpdateFamily` | `user_id`, `reason` | Gezielter Refresh von Familie, Liebschaften und je nach `reason` auch Geld oder Ruf |
| `falukantUpdateStatus` | `user_id` | Allgemeiner Falukant-Status-/Spielstands-Refresh |
| `children_update` | `user_id` | Kinderliste und Familienansicht aktualisieren |
| `falukant_family_scandal_hint` | `relationship_id` | Optionaler Hinweis oder Logeintrag; kein `user_id` |
| `falukantUpdateFamily` | `user_id`, `reason` | Gezielter Refresh Familie/Liebe/Geld je nach `reason` |
| `falukantUpdateStatus` | `user_id` | Allgemeiner Status-/Spielstands-Refresh |
| `falukantUpdateProductionCertificate` | `user_id`, `reason`, `old_certificate`, `new_certificate` | Produkte / Produktions-UI / Zertifikat neu laden |
| `children_update` | `user_id` | Kinderliste / FamilyView aktualisieren |
| `falukant_family_scandal_hint` | `relationship_id` | Optionaler Toast oder Log; kein `user_id` |
| `falukantUpdateChurch` | `user_id`, `reason` | Kirchenämter, Bewerbungen, Ernennungen |
| `falukantUpdateDebt` | `user_id`, `reason` | Schuldturm, Verzug, Pfändung, Freilassung |
## 2. JSON-Payloads
@@ -28,14 +32,32 @@ Transport:
```
`reason` ist immer genau einer dieser festen Strings:
- `daily`
- `monthly`
- `lover_installment`
- `scandal`
- `lover_birth`
Es gibt keine weiteren `reason`-Werte.
### 2.2 `falukantUpdateChurch`
### 2.2 `falukantUpdateStatus`
```json
{
"event": "falukantUpdateChurch",
"user_id": 123,
"reason": "applications"
}
```
Mögliche `reason`:
- `applications`
- `npc_decision`
- `appointment`
- `vacancy_fill`
- `promotion`
### 2.3 `falukantUpdateStatus`
```json
{
@@ -44,9 +66,21 @@ Es gibt keine weiteren `reason`-Werte.
}
```
Dieses Event wird typischerweise direkt nach `falukantUpdateFamily` mit derselben `user_id` gesendet.
Dieses Event wird typischerweise direkt nach einem fachlichen Falukant-Event mit derselben `user_id` gesendet.
### 2.3 `children_update`
### 2.4 `falukantUpdateProductionCertificate`
```json
{
"event": "falukantUpdateProductionCertificate",
"user_id": 123,
"reason": "daily_recalculation",
"old_certificate": 2,
"new_certificate": 3
}
```
### 2.5 `children_update`
```json
{
@@ -56,10 +90,11 @@ Dieses Event wird typischerweise direkt nach `falukantUpdateFamily` mit derselbe
```
Dieses Event tritt bei Geburt aus einer Liebschaft auf, meist zusammen mit:
- `falukantUpdateFamily` mit `reason: "lover_birth"`
- `falukantUpdateStatus`
### 2.4 `falukant_family_scandal_hint`
### 2.6 `falukant_family_scandal_hint`
```json
{
@@ -69,56 +104,118 @@ Dieses Event tritt bei Geburt aus einer Liebschaft auf, meist zusammen mit:
```
Hinweis:
- Dieses Event enthält kein `user_id`.
- Die UI kann es ignorieren oder optional nur für Log-/Toast-Zwecke verwenden.
- Die eigentliche nutzerbezogene Aktualisierung läuft über `falukantUpdateFamily` mit `reason: "scandal"`.
### 2.7 `falukantUpdateDebt`
```json
{
"event": "falukantUpdateDebt",
"user_id": 123,
"reason": "debtors_prison_entered"
}
```
Mögliche `reason`:
- `delinquency`
- `debtors_prison_entered`
- `asset_seizure`
- `vehicle_liquidation`
- `house_seizure`
- `branch_closure`
- `debtors_prison_released`
## 3. Fachliche Bedeutung von `reason`
### `reason: "daily"`
### 3.1 `falukantUpdateFamily`
#### `reason: "daily"`
`daily` ist der Sammelgrund für tägliche Änderungen im Familien- und Liebschaftssystem.
Darunter fallen insbesondere:
- tägliche Drift und Änderung der Ehezufriedenheit
- `marriage_public_stability`
- `household_tension_score`
- Ehe-Buffs und temporäre Zähler wie Geschenk-, Fest- oder Haus-Effekte
- tägliche Liebschaftslogik für aktive Beziehungen
- Rufverlust bei zwei oder mehr sichtbaren Liebschaften
- Zufalls-Mali wie Gerücht oder Tadel
Wichtig:
- Es gibt kein separates Event für „nur Ehe-Buff“.
- Es gibt kein separates Event für „nur zwei sichtbare Liebschaften“.
- Es gibt kein separates Event für „nur Gerücht/Tadel“.
- Alles davon erscheint in der UI ausschließlich als `falukantUpdateFamily` mit `reason: "daily"`.
### `reason: "scandal"`
#### `reason: "monthly"`
`monthly` steht für monatliche Verarbeitung, insbesondere:
- Dienerschaftskosten
- laufende Kosten
- Unterversorgung
- Geldänderungen
#### `reason: "lover_installment"`
`lover_installment` steht für die 2-Stunden-Unterhaltsbelastung von Liebschaften.
Die UI sollte dafür mindestens:
- Geld neu laden
- Family-/Liebschaftsstatus neu laden
#### `reason: "scandal"`
`scandal` wird zusätzlich zu einem gelungenen Skandalwurf gesendet.
Typischer Ablauf:
- optional `falukant_family_scandal_hint`
- `falukantUpdateFamily` mit `reason: "scandal"`
- `falukantUpdateStatus`
Danach kann für denselben Nutzer am selben Tag zusätzlich noch `daily` folgen.
### `reason: "monthly"`
`monthly` steht für Monatsverarbeitung, insbesondere:
- laufende Kosten
- Unterversorgung
- Geldänderungen
### `reason: "lover_birth"`
#### `reason: "lover_birth"`
`lover_birth` signalisiert ein neues Kind aus einer Liebschaft.
Meist folgen zusammen:
- `falukantUpdateFamily` mit `reason: "lover_birth"`
- `children_update`
- `falukantUpdateStatus`
### 3.2 `falukantUpdateChurch`
- `applications`: Spieler ist kirchlicher Vorgesetzter; offene Bewerbungen warten
- `npc_decision`: NPC-Vorgesetzter hat entschieden
- `appointment`: automatische Annahme älterer Bewerbung
- `vacancy_fill`: Interimsbesetzung
- `promotion`: reserviert / zukünftig
### 3.3 `falukantUpdateProductionCertificate`
- `daily_recalculation`: Zertifikat nach täglicher Prüfung geändert
### 3.4 `falukantUpdateDebt`
- `delinquency`: Mahnstufe oder Verzug aktualisiert
- `debtors_prison_entered`: Eintritt in den Schuldturm
- `asset_seizure`: Geld, Waren oder sonstige Vermögenswerte eingezogen
- `vehicle_liquidation`: Fahrzeuge zwangsverkauft
- `house_seizure`: Haus gepfändet
- `branch_closure`: Niederlassung geschlossen
- `debtors_prison_released`: Freilassung
## 4. Empfohlene Handler-Logik
```text
@@ -131,10 +228,22 @@ onMessage(json):
refreshPlayerStatus()
return
case "falukantUpdateProductionCertificate":
refreshProductsAndProductionUi()
return
case "children_update":
refreshChildrenAndFamilyView()
return
case "falukantUpdateChurch":
refreshChurchContextByReason(json.reason)
return
case "falukantUpdateDebt":
refreshDebtAndAffectedViews(json.reason)
return
case "falukantUpdateFamily":
switch json.reason:
case "daily":
@@ -145,6 +254,10 @@ onMessage(json):
refreshMoney()
refreshFamilyAndRelationships()
break
case "lover_installment":
refreshMoney()
refreshFamilyAndRelationships()
break
case "scandal":
showScandalToastOptional()
refreshFamilyAndRelationships()
@@ -162,15 +275,23 @@ onMessage(json):
## 5. Deduplizierung
Am selben Tag kann ein Nutzer mehrere relevante Events erhalten, zum Beispiel:
Ein Nutzer kann kurz hintereinander mehrere relevante Events erhalten, zum Beispiel:
- `scandal`
- danach `daily`
- danach `falukantUpdateStatus`
oder:
- `falukantUpdateDebt`
- direkt danach `falukantUpdateStatus`
- zusätzlich `falukantUpdateFamily`
Die UI sollte deshalb:
- Refreshes bündeln oder entprellen
- idempotente Reloads verwenden
- nicht davon ausgehen, dass jeder fachliche Effekt einen eigenen `reason` hat
- nicht davon ausgehen, dass jeder fachliche Effekt einen eigenen Spezial-Eventpfad hat
## 6. Welche Daten sollten neu geladen werden?
@@ -178,15 +299,18 @@ Die UI sollte deshalb:
|-----------|--------------------|
| Jede `falukantUpdateFamily` | Family-/Relationship-Daten neu laden |
| `reason: "monthly"` | Family-Daten plus Geld/Status neu laden |
| `reason: "lover_installment"` | Geld plus Family-Daten neu laden |
| `reason: "daily"` | Family-Daten neu laden, bei Bedarf auch Ruf-/Statusdaten |
| `reason: "scandal"` | Family-Daten plus Ruf-/Statusdaten neu laden |
| `children_update` / `lover_birth` | Kinderdaten und FamilyView neu laden |
| `falukantUpdateChurch` | Kirchenämter, Bewerbungen, freie Positionen je nach `reason` |
| `falukantUpdateProductionCertificate` | User-Status, Zertifikat, Produkte, Produktions-UI |
| `falukantUpdateDebt` | Bank, Overview, House, Branch, ggf. Family |
## 7. Sonderfälle
| Fall | Verhalten |
|------|-----------|
| NPC ohne `user_id` | Keine nutzerbezogenen Family-Socket-Events |
| NPC ohne `user_id` | Keine nutzerbezogenen Socket-Events |
| Mehrere Events kurz hintereinander | Normal; UI sollte damit robust umgehen |
| Nur `falukantUpdateStatus` ohne Family-Event | Kann von anderen Falukant-Workern kommen |
| Nur `falukantUpdateStatus` ohne Fach-Event | Kann von anderen Falukant-Workern kommen |