# Falukant: Geplante Schwangerschaft & Geburt – Daemon- und Datenbankkonzept Dieses Dokument beschreibt das **vereinheitlichte Konzept** für Schwangerschaft, die der **externe Daemon** (`UserCharacterWorker`, C++) verarbeiten soll, sowie die **Datenbank** und die **Abgrenzung zur bestehenden Zufallslogik**. Ziel ist, dass gesetzte Termine (`pregnancy_due_at`) und der gewählte Vater (`pregnancy_father_character_id`) – u. a. aus dem Admin-Tool – **tatsächlich zu Geburten führen**, ohne dass nur die Node-API „Geburt erzwingen“ funktioniert. --- ## 1. Ist-Zustand (Problem) ### 1.1 Datenbank (bereits vorhanden) Auf `falukant_data."character"` existieren (siehe `backend/sql/add_character_pregnancy.sql`): | Spalte | Typ | Bedeutung | |--------|-----|-----------| | `pregnancy_due_at` | `TIMESTAMPTZ` NULL | Erwarteter Geburtstermin | | `pregnancy_father_character_id` | `INTEGER` NULL, FK auf `character(id)` | Vater-Charakter | Die **Node-Backend**-Logik (Admin, `falukantService`) **liest und schreibt** diese Felder. ### 1.2 Daemon – aktuelles Verhalten In `src/usercharacterworker.cpp` / `src/usercharacterworker.h`: - `processPregnancies()` führt **`QUERY_GET_PREGNANCY_CANDIDATES`** aus. - Diese Query: - bezieht sich **nur** auf Ehen (`falukant_type.relationship.tr = 'married'`), - nutzt **keine** `pregnancy_*`-Spalten, - modelliert Geburten **per Zufallsprozess** (altersabhängige Wahrscheinlichkeit), - setzt implizit **`character1_id` = Vater** und **`character2_id` = Mutter** (fest verdrahtet, ohne Geschlechts- oder Rollenprüfung). **Folge:** Wer im Spiel oder per Admin als „schwanger“ mit Termin und Vater gespeichert wird, **wird vom Daemon nicht erkannt**. Geburten aus diesem Konzept passieren nur, wenn sie **manuell** per Node (z. B. Admin „Geburt erzwingen“) ausgelöst werden. **Zusätzlich:** `QUERY_AUTOBATISM` setzt nur `child_relation.name_set` nach einigen Tagen – hat **nichts** mit Schwangerschafts-Spalten zu tun. --- ## 2. Soll-Konzept (Zwei parallele Wege, eine klare Priorität) ### 2.1 Weg A – **Geplante Schwangerschaft** (DB-gesteuert, neu für den Daemon) **Auslöser:** `pregnancy_due_at` ist gesetzt und der Zeitpunkt ist **fällig**. **Regeln (Vorschlag):** 1. **Eine** Mutter ist immer der Datensatz in `character`, auf dem `pregnancy_due_at` und die Schwangerschaft „liegen“. 2. **Vater:** `pregnancy_father_character_id` - Wenn gesetzt: muss ein existierender Charakter sein, **nicht** `mother.id`. - Wenn `NULL`: Policy festlegen (siehe Abschnitt 8). 3. **Fälligkeit:** z. B. `date_trunc('day', pregnancy_due_at AT TIME ZONE 'Europe/Berlin') <= current_date` (oder einheitlich **UTC** – wichtig ist **eine** Definition im Team). 4. Nach erfolgreicher Geburt: **`pregnancy_due_at` und `pregnancy_father_character_id` auf NULL** setzen (Schwangerschaft beendet). Dieser Weg entspricht dem, was Admin und Spieler erwarten, wenn ein **Termin** existiert. ### 2.2 Weg B – **Legacy: Zufallsgeburten bei Ehe** (bestehende Query) Die Query `QUERY_GET_PREGNANCY_CANDIDATES` modelliert **„natürliche“** Zufallsgeburten ohne `pregnancy_*`-Felder. **Entscheidung für die Umsetzung:** - **Option B1:** Weg B **abschalten** oder stark reduzieren, wenn Weg A das offizielle Modell ist. - **Option B2:** Weg B **beibehalten** für Atmosphäre, aber **nur**, wenn **keine** aktive geplante Schwangerschaft auf den betroffenen Charakteren existiert (doppelte Geburten vermeiden). - **Option B3:** Weg B nur noch **Simulation**, bis Spiel-Logik „Konzeption“ explizit setzt (größerer Umbau). **Empfehlung:** Mindestens **B2** oder **B1**, damit keine zwei Geburten pro Tag für dieselbe Ehe aus unterschiedlichen Regeln entstehen. --- ## 3. Datenbank – Erweiterungen (Vorschlag) Die Minimalvariante kommt **ohne** neue Spalten aus (nur Daemon-Logik). Für Robustheit und spätere Features sind **optionale** Erweiterungen sinnvoll: ### 3.1 Pflicht (kein Schema-Zwang, aber empfohlen) - **Index** für den Daemon-Tick, z. B.: ```sql CREATE INDEX IF NOT EXISTS idx_character_pregnancy_due ON falukant_data."character" (pregnancy_due_at) WHERE pregnancy_due_at IS NOT NULL; ``` ### 3.2 Optional – Metadaten | Spalte | Typ | Zweck | |--------|-----|--------| | `pregnancy_source` | `TEXT` oder `ENUM` | z. B. `admin`, `gameplay`, `npc` – für Logging und Regeln | | `pregnancy_conception_at` | `TIMESTAMPTZ` | optional, für Anzeige/Quests | | `pregnancy_birth_context` | `TEXT` | `marriage` | `lover` – für korrekten `child_relation.birth_context` ohne Heuristik | Wenn `pregnancy_birth_context` **nicht** eingeführt wird, leitet der Daemon den Kontext aus der **Beziehung** zwischen Mutter und Vater ab (verheiratet → `marriage`, Liebhaber → `lover`, sonst Default `marriage` oder Policy). ### 3.3 `child_relation` – Parität mit Node Das Sequelize-Modell erwartet u. a. `father_name`, `mother_name`, `legitimacy`, `birth_context`, `public_known`. Die **Daemon-INSERT**-Query (`QUERY_INSERT_CHILD_RELATION`) muss mit der **realen DB** übereinstimmen (Pflichtfelder, Defaults). Falls nötig: - INSERT um **Namen** (aus Vordefiniert-Tabellen) und **legitimacy / birth_context / public_known** erweitern, - oder DB-Defaults / Trigger ergänzen, - **gleiche Semantik** wie `adminForceFalukantBirth` in `adminService.js` anstreben. --- ## 4. Daemon – Umsetzung (technisch) ### 4.1 Neue SQL-Query: „fällige geplante Geburten“ **Skizze (logisch):** - SELECT Mutter-`character` `c` mit: - `c.pregnancy_due_at IS NOT NULL` - `c.pregnancy_due_at` fällig (siehe Zeitzone) - JOIN Vater `c_father` auf `c.pregnancy_father_character_id = c_father.id` **wenn** Vater Pflicht ist - Pro Zeile: `father_cid`, `mother_cid`, `region_id`, `title_of_nobility` (vom passenden Elternteil), `last_name`, `father_uid`, `mother_uid` analog zur bestehenden Schleife. **Wichtig:** Vater/Mutter **nicht** aus `relationship.character1/2` ableiten, sondern aus **expliziten IDs** (`pregnancy_father_character_id` + Zeilen-ID der Mutter). ### 4.2 Ablauf in `processPregnancies()` 1. `QUERY_AUTOBATISM` wie bisher (optional, Reihenfolge beachten). 2. **Neu:** Transaktion oder feste Reihenfolge: - Kandidaten für **geplante Geburt** laden - **pro Kandidat:** Kind einfügen (`QUERY_INSERT_CHILD` oder gemeinsame Funktion), `child_relation` einfügen, **Schwangerschaft** auf der Mutter **leeren** - Benachrichtigungen (`children_update`, `falukantUpdateStatus`) wie bei bestehender Schleife 3. **Legacy-Query** nur ausführen, wenn nach Absprache (Option B1–B3). **Idempotenz:** Pro Tick darf dieselbe schwangere Zeile **nicht** zweimal gebären. Am sichersten: **UPDATE … RETURNING** oder **DELETE** der Schwangerschaftsdaten in derselben Transaktion wie das Kind. ### 4.3 Geschlecht der Eltern Optional: Plausibilitätsprüfung (`gender` Mutter/Vater) – kann im ersten Schritt weggelassen werden, sollte aber langfristig mit dem Spielregelwerk übereinstimmen. --- ## 5. Backend (Node) – Abstimmung - **Zeitzonen:** `pregnancy_due_at` wird in JS als `Date` gesetzt; Daemon muss **dieselbe** Fälligkeitsdefinition nutzen wie die UI („heute“ = 0 Tage). - **WebSocket:** Nach Daemon-Geburt dieselben Events wie bei Admin-Geburt, damit Clients die Familie aktualisieren. --- ## 6. Frontend - Hinweis in der Familien-Ansicht: „Geburt erfolgt automatisch am Termin“ (wenn Daemon aktiv), sonst „nur nach Admin-Aktion“ – je nach Rollout. --- ## 7. Test-Checkliste - [ ] Admin: Schwangerschaft mit Termin **heute** und Vater – nach Daemon-Lauf: Kind existiert, Schwangerschaft weg. - [ ] Kein Vater (`NULL`) – definiertes Verhalten (Fehler loggen / überspringen / NPC-Vater – **Policy**). - [ ] Doppel-Tick: keine doppelte Geburt. - [ ] Legacy-Zufallsgeburt: keine Kollision mit aktivem `pregnancy_due_at` auf derselben Mutter. - [ ] `child_relation` und `character`-Kind konsistent mit Node-Admin-Geburt. --- ## 8. Offene Policy-Fragen (bitte vor Implementierung festlegen) 1. **Vater `NULL`:** Geburt abbrechen, stillen Vater aus Beziehung erraten, oder festen Platzhalter? 2. **Legacy-Query:** komplett entfernen oder nur noch unter Bedingungen? 3. **Zeitzone** für „Termin ist heute“: Server-UTC, Europe/Berlin, oder Nutzer-TZ? 4. **Liebschaftsgeburten:** nur über `pregnancy_*` + `birth_context`/`pregnancy_birth_context`, nie über reine Ehe-Query? --- ## 9. Referenzdateien im Repo | Bereich | Datei | |---------|--------| | Daemon | `src/usercharacterworker.cpp` (`processPregnancies`) | | SQL-Strings | `src/usercharacterworker.h` (`QUERY_GET_PREGNANCY_CANDIDATES`, `QUERY_INSERT_CHILD`, `QUERY_INSERT_CHILD_RELATION`) | | DB-Spalten Schwangerschaft | `backend/sql/add_character_pregnancy.sql` | | Modell Character | `backend/models/falukant/data/character.js` | | Admin / Geburt Node | `backend/services/adminService.js` (`adminForceFalukantPregnancy`, `adminForceFalukantBirth`) | | Familie API | `backend/services/falukantService.js` (`_getCharacterPregnancyOptional`, `getFamily`) | --- *Stand: technische Analyse des Repos; zur Abstimmung mit Game-Design und Deployment des Daemons.*