- Added new political powers and benefits functionalities, including reputation ticks, tax jurisdiction management, and appointment capabilities. - Introduced a new job for periodic reputation updates and created necessary database tables for tracking political benefits. - Enhanced the FalukantController and services to support new endpoints for managing political powers and appointments. - Updated localization files to reflect new features and improve user experience across multiple languages. - Modified the UI to display new political powers and benefits, ensuring accurate representation in the PoliticsView.
12 KiB
Falukant: Konzept — Daemon, Backend und UI für politische Amtsvorteile
Dieses Dokument beschreibt die noch nicht implementierten Teile zu den Amtsvorteilen (reputation_periodic, appoint_politicians, set_regional_tax, free_lover_slots, sowie optional guard_protection / court_immunity als Spielwirkung). Die Anzeige in der Politik-Übersicht existiert bereits; hier geht es um Ausführung, Persistenz und Bedienoberfläche.
1. Ausgangslage im Code
| Bereich | Stand |
|---|---|
| Predefine | falukant_predefine.political_office_benefit + Typen in falukant_type.political_office_benefit_type; JSON value pro Amt. |
| Auslesen / Anzeige | FalukantService.politicsBenefitEntriesFromRows, Frontend PoliticsView.vue. |
| Bereits mechanisch | daily_salary (beim Laden der Politik-Übersicht, last_political_daily_salary_on am FalukantUser); Steuerbefreiung in getCumulativeTaxPercentForCharacter (SQL mit exempt types). |
| Daemon (C++) | PoliticsWorker läuft täglich nach 03:00 (src/politics_worker.cpp): Wahlen, Nachbesetzung, Benachrichtigungen — kein Bezug zu den neuen JSON-Vorteilen. |
| Node-Daemon | backend/daemonServer.js ist ein WebSocket-Relay, kein Spiel-Ticker. |
| Steuern im Spiel | Regionen haben tax_percent; kumulativ über Eltern-Regionen; Verkaufsbuchung in falukantService (Steueranteil). |
Empfehlung zur Architektur: zeitkritische Batch-Jobs (täglich, idempotent) entweder im bestehenden C++-PoliticsWorker direkt nach den bestehenden Schritten ausführen oder einen kleinen Node-Cron-Job (z. B. node backend/jobs/politicalBenefitsTick.js + systemd timer), der Sequelize nutzt. C++ vermeidet doppelte DB-Logik; Node vermeidet C++-Deploy für reine Sequelize-Regeln. Für synchrone API-Aktionen (Steuern setzen, Ernennungen) ist ausschließlich das Node-Backend sinnvoll.
2. Zielbild pro Vorteilstyp
2.1 reputation_periodic (Ansehen alle x Tage)
Ziel: Charaktere mit aktivem Amt erhalten in einem festen Intervall gain Ansehenspunkte (oberhalb 0, Cap z. B. 100), höchstens einmal pro Intervall pro (Charakter × konkreter Benefit-Zeile).
Persistenz (neu):
- Tabelle z. B.
falukant_data.political_benefit_last_tickid,character_id,political_office_benefit_id(FK auf Predefine-Zeile),last_tick_at(timestamptz), optionalticks_count.- Unique
(character_id, political_office_benefit_id).
Logik:
- Alle
political_office-Zeilen mitcharacter_id IS NOT NULLladen (oder seit letztem Lauf geänderte). - Pro Zeile zugehörige
office_type_id→ allePoliticalOfficeBenefitmitbenefitDefinition.tr = 'reputation_periodic'. - Für jede Kombination:
last_tick_atlesen; wennnow - last_tick_at >= intervalDays(Kalendertage Spielzeit oder UTC-Echtzeit — festlegen; konsistent mitdaily_salaryist UTC-Datum einfacher), danncharacter.reputationerhöhen,last_tick_at = now, Eintrag ins Money-/Activity-Log optional (political_reputation_tick). - Mehrere Ämter: mehrere Benefit-Zeilen = mehrere mögliche Ticks (jede mit eigenem Intervall), so wie konfiguriert.
- Idempotenz: Pro Lauf nur ein Tick pro Unique-Key; Worker max. 1× täglich wie
PoliticsWorkerreicht, wenn Intervall ≥ 1 Tag; beiintervalDays < 1separaten Stunden-Job definieren (nicht empfohlen ohne Bedarf).
Daemon-Ort: neuer Schritt performPoliticalBenefitTicks() am Ende von PoliticsWorker::performDailyPoliticsTask() oder Node-Job 03:05 UTC.
Push: nach Tick falukantUpdateStatus an betroffene User (wie bei anderen Politics-Events).
2.2 free_lover_slots (kostenfreie Liebschaften / Mätressen)
Ziel: Die ersten N aktiven Liebschaften (Relationship-Typ lover + sichtbarer relationship_state, Rolle z. B. lover oder mistress_or_favorite) verursachen keinen monatlichen Unterhalt (monthly_base_cost effektiv 0 für diese Slots).
Kein eigener Daemon nötig — Anwendung beim bestehenden monatlichen Abrechnungslauf (C++ UserCharacterWorker oder Sequelize-Äquivalent), der relationship_state und Kosten verarbeitet.
Backend-Mechanik:
- Hilfsfunktion
getFreePoliticalLoverSlotCount(characterId)- Aktive
PoliticalOfficedes Charakters →office_type_id→ Summefree_lover_slots.countaus Benefits (max oder Summe — Spec-Empfehlung: Summe, Deckel optionalmaxTotalFreeSlots: 5in Config).
- Aktive
- Liebschaften nach Erstellungsdatum oder fester Priorität sortieren; die ersten
NerhalteneffectiveMonthlyCost = 0für diese Abrechnung. - Optional: Flag in
relationship_state.flags_json(political_free_slot: true) setzen/aktualisieren für Transparenz und UI — oder rein berechnet ohne Persistenz.
Fairness: Nur Charaktere, die Inhaber sind (nicht nur Kandidaten).
2.3 appoint_politicians (Ernennungsrecht)
Ziel: Amtsträger dürfen unter definierten Regeln andere Ämter in ihrer Zuständigkeit besetzen (NPC oder Spieler), ohne vollständige Wahl — oder: Sonderwahl / Nachrücker auslösen.
Varianten (Priorisierung empfohlen):
| Variante | Beschreibung | Aufwand |
|---|---|---|
| A — Nachbesetzung | Bei vakantem political_office in erlaubter Region: Appointer wählt einen Kandidaten aus Pool (nur Charaktere mit Titel/Alter wie bei Wahl); Server erstellt Eintrag political_office + Log. |
Mittel |
| B — Nur NPC | Appointer „ernennt“ nur NPCs (bestehende NPC-Erzeugung); kein PvP-Konflikt. | Geringer |
| C — Einladung | appointment_invite an Spieler; Annahme erstellt Amt. |
Höher |
Persistenz (neu):
falukant_data.political_appointmentid,appointer_character_id,target_character_id(nullable bei NPC),office_type_id,region_id,status(pending,accepted,rejected,expired,completed),created_at,expires_at,completed_office_id(nullable).
Regeln:
- Appointer muss aktuelles Amt haben, dessen Benefit
officeTrsdas Zielamt enthält. - Zielregion muss zur Kompetenz passen (z. B. gleiche Stadt/Grafschaft wie Appointer-Amt oder laut
scopeaus JSON erweitert). - Anti-Spam: Cooldown, max. offene Ernennungen pro Appointer.
Daemon: optional nur Ablauf (expired) einmal täglich im PoliticsWorker oder Node.
2.4 set_regional_tax (Steuersätze festlegen)
Ziel: Berechtigte setzen tax_percent (oder einen Aufschlag) für Regionen innerhalb ihrer Kompetenz (scope: local, shire, duchy, national).
Datenmodell:
- Option A (minimal): direkt
falukant_data.region.tax_percentändern + Audit-Tabelleregion_tax_history(region_id,old_value,new_value,setter_character_id,office_id,created_at). - Option B (flexibler):
region_political_tax_modifier(additiv), Basis bleibt inregion; effektive Steuer = Basis + Summe gültiger Modifier (mit TTL). Für „Rücknahme nach Amtsende“ einfacher.
Backend-Mechanik:
GET /api/falukant/politics/tax-jurisdiction— Regionen, für die der Charakter nach aktuellem Amt +set_regional_taxschreiben darf, inkl. aktuellem Wert und Grenzen.PUT /api/falukant/politics/region/:regionId/tax— Body{ percent }oder{ delta }; Server prüft:- Charakter hat passendes Amt;
- Region liegt in erlaubter Hierarchie (lokal = nur Amtsregion; shire = Teilbaum unter shire; …);
- Clamp min/max (global config, z. B. 0–25 %).
- Verkaufs-/Steuer-SQL unverändert nutzen, sofern weiterhin
tax_percentaufregionliegt (bei Option B SQL um Modifier erweitern).
Daemon: nicht nötig; bei Amtsende optional Modifier entfernen oder auf Historie zurücksetzen (täglicher Job oder Trigger auf political_office delete).
2.5 guard_protection / court_immunity (Spielwirkung)
Optional, später:
- guard_protection: Reduktion von Untergrund-Erfolgswahrscheinlichkeit gegen den Charakter oder geringerer
visibility-Anstieg bei Affären (wenn solche Formeln existieren). - court_immunity: Abschwächung bestimmter Rechts-/Straf-Events (sobald es dafür Services gibt).
Konkrete Zahlen als JSON in value (attackMitigationPercent, …). Daemon: nicht zwingend; eher bei Event-Auswertung abfragen.
3. Daemon — Gesamtüberblick
03:00 (bestehend) PoliticsWorker
├─ … Wahlen, Nachbesetzung, Notifications …
├─ NEU: politicalBenefitReputationTicks()
└─ NEU: politicalAppointmentExpiry() [optional]
Monatlich / bestehender Character-Tick
└─ relationship monthly cost ← berücksichtigt free_lover_slots
Idempotenz-Prinzip: Jeder Batch-Job nutzt klare Unique-Keys und Transaktionen; bei Crash-Wiederholung keine Doppel-Ticks (Reputation).
Observability: strukturierte Logs [PoliticalBenefits] characterId=… officeBenefitId=… action=reputation_tick.
4. Backend-API (Node) — Übersicht
| Endpoint | Zweck |
|---|---|
GET /api/falukant/politics/my-powers |
Für eingeloggten Charakter: Liste aktionabler Vorteile inkl. Parameter, nächster reputation-Tick (read-only aus political_benefit_last_tick), freie Liebschaft-Slots-Zahl. |
GET /api/falukant/politics/tax-jurisdiction |
Regionen + aktuelle Steuer + erlaubter Bereich. |
PUT /api/falukant/politics/region/:id/tax |
Steuer setzen (siehe oben). |
GET /api/falukant/politics/appointable-offices |
Vakante oder ernennbare Posten + erlaubte Ziel-officeTrs. |
POST /api/falukant/politics/appointments |
Ernennung anstoßen (Body: targetCharacterId, officeTypeId, regionId). |
POST /api/falukant/politics/appointments/:id/accept |
Optional für Ziel-Spieler. |
Service-Schicht: falukantPoliticalPowersService.js (oder Erweiterung falukantService) mit klaren Guards und Wiederverwendung der Benefit-Loader aus PoliticalOfficeBenefit.
Sicherheit: Alle Routen mit getFalukantUserByHashedId + Charakter-Inhaber-Check; keine Überschreibung fremder Regionen.
5. UI-Konzept (Vue)
5.1 Einstieg
- In Politik neuer Unter-Tab oder Sektion „Amtsbefugnisse“ (sichtbar nur, wenn
my-powersnicht leer). - Kurzinfo in „Aktuelle Position“: neben der Vorteilsliste ein Link „Befugnisse ausüben“.
5.2 Steuern (set_regional_tax)
- Ansicht: Tabelle Region (Name, Typ, aktueller Steuersatz, Slider oder Zahleneingabe).
- Validierung clientseitig spiegelt Server-Clamps.
- Speichern ruft
PUTauf; Erfolgstoast; ggf. Eintrag in lokaler Historie (letzte 5 Änderungen ausregion_tax_history).
5.3 Ernennungen (appoint_politicians)
- Schritt 1: Amt + Region wählen (nur erlaubte Kombinationen).
- Schritt 2: Ziel-Charakter suchen (Autocomplete über Community/Falukant-Suche) oder „NPC vorschlagen“ (Variante B).
- Schritt 3: Bestätigung, Anzeige der Regeln (Titel, Alter, Cooldown).
- Einladungs-Variante: Posteingang / Notification mit Annehmen/Ablehnen.
5.4 reputation_periodic / Meta
- Anzeige: „Nächster Ansehens-Bonus: in X Tagen“ aus
last_tick_at+intervalDays(nur lesend; Ausführung durch Daemon). - Optional: Eintrag im Tagebuch / Notification nach Tick.
5.5 free_lover_slots
- In Familie → Affären (oder Liebschaften): Badge „Amt: X Plätze ohne Unterhalt“; in der Kostenübersicht pro Beziehung Kennzeichnung „politisch freigestellt“.
- Kein eigener Daemon-Dialog nötig.
5.6 Internationalisierung
- Alle neuen Strings unter
falukant.politics.powers.*(de/en/es/ceb analog zubenefits).
6. Migrations-Reihenfolge (empfohlen)
political_benefit_last_tick(+ FKs, Indizes).region_tax_historyoder Modifier-Tabelle.political_appointment(+ Indizes aufstatus,appointer_character_id).- Daemon-/Job-Implementierung Reputation.
- API Steuern + UI.
- API Ernennungen + UI.
- Monatliche Kostenanpassung
free_lover_slots.
7. Offene Produktentscheidungen
- Echtzeit vs. Spielzeit für
intervalDays(aktuell Mischung möglich mitdaily_salaryauf UTC-Datum). - Summe vs. Maximum bei mehreren Ämtern für
free_lover_slots. - Ernennung: nur innerhalb der eigenen Region oder auch in Unterregionen?
- Steuer: darf derselbe Region mehrfach von verschiedenen Ämtern gesetzt werden? (Empfehlung: letzte schreibende Instanz mit höherer
scope-Priorität gewinnt, oder explizite Hierarchie-Regel.)
Dokumentstand: abgestimmt auf Repository mit C++-PoliticsWorker, Sequelize-Falukant-Backend und bestehenden political_office_benefit-Seeds.