Skip to content

Feature/stuetzpunkt handel spieler - #41

Merged
SirTobyB merged 61 commits into
masterfrom
feature/stuetzpunkt-handel-spieler
Aug 15, 2026
Merged

Feature/stuetzpunkt handel spieler#41
SirTobyB merged 61 commits into
masterfrom
feature/stuetzpunkt-handel-spieler

Conversation

@SirTobyB

Copy link
Copy Markdown
Member

No description provided.

SirTobyB and others added 30 commits July 27, 2026 21:55
Das Push-Release erzeugte ein falsches Tag (3.19.0 statt 3.46.0), weil
der Workflow fuer Tag und Changelog-Link den Output assembly-version
(<AssemblyVersion> = 3.19.0) nutzte, waehrend das NuGet-Paket aus
<Version> = 3.46.0 gepackt wird.

- main.yml: Tag und Changelog-Link nutzen jetzt den Output "version"
  (entspricht <Version>, also der Paketversion).
- csproj: AssemblyVersion und FileVersion auf 3.46.0 an <Version>
  angeglichen (waren seit 3.19.0 nicht mehr mitgezogen worden).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
KaufangebotAbgeben unterstuetzt jetzt auch menschliche Besitzer: der
Betrag wird beim Anbieter reserviert und am Stuetzpunkt vermerkt
(AngebotVonSpielerID/AngebotPreis). Neue Stuetzpunkt.AngebotVorlegen
legt das Angebot dem Besitzer vor (Annahme: Besitzwechsel gegen Preis
+ Handelszertifikat Stufe 3; Ablehnung: Rueckerstattung). Manager:
VerarbeiteEingehendeKaufangebote + StehenKaufangeboteAn fuer den Aufruf
zu Zugbeginn.

Nebenbei behoben: NameBesitzer im Bestaetigungstext nutzte faelschlich
den aktiven Spieler statt den Stuetzpunkt-Besitzer.

Verifiziert per Konsolentest (Angebot reserviert, Annahme uebertraegt
und zahlt, Ablehnung erstattet zurueck).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Anbieter erhaelt zu Beginn seines naechsten Zuges eine eigene
Meldung, ob sein Kaufangebot angenommen (Besitzwechsel) oder abgelehnt
(Rueckerstattung) wurde. Neue spielstandskompatible, lazy
initialisierte HumSpieler.HandelsNachrichten und
SoeldnerRaeuberManager.ZeigeHandelsnachrichten; AngebotVorlegen reiht
die Meldung beim Anbieter ein.

Verifiziert per Konsolentest (Annahme- und Ablehnungs-Meldung kommen
an und werden nach Anzeige geleert).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…9.0)

Stuetzpunkt.ZumVerkaufAngeboten kennzeichnet einen zum Verkauf
angebotenen Stuetzpunkt. SoeldnerRaeuberManager.GeneriereKiKaufangebote
erzeugt zu Zugbeginn gelegentlich ein zufaelliges KI-Angebot (Preis um
den aktuellen Wert). AngebotVorlegen verarbeitet jetzt auch KI-Anbieter:
Annahme -> Besitzwechsel zur KI gegen Bezahlung (Flag zurueckgesetzt),
Ablehnung -> bleibt gelistet, keine Rueckerstattung. Zusaetzlich
SetzeZumVerkauf/IstZumVerkaufAngeboten sowie
StuetzpunktVerwaltenManager.ZumVerkaufAngeboten fuer die UI.

Verifiziert per Konsolentest (anbieten -> KI-Angebot -> Annahme
uebertraegt und zahlt; Ablehnung bleibt gelistet).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die in der Abrechnung an menschliche Zollburg-Besitzer ausgezahlten
Zoelle werden jetzt in HumSpieler.ZolleinnahmenGesammelt summiert
(ZahleZollAusUndSammle) und dem Spieler zu Zugbeginn ueber
SoeldnerRaeuberManager.ZeigeZolleinnahmen als Einnahme gemeldet,
danach zurueckgesetzt.

Verifiziert per Konsolentest (keine Meldung bei 0, Meldung + Reset bei
gesammelten Zoellen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neue Spieleinstellungen.KiAktivitaetProzent (1-100, Standard 50)
steuert die Aktivitaet der KI in den Militaerstuetzpunkten. Raeuberlager
und Zollburg leiten den Aktivitaetsfaktor direkt daraus ab (Prozent/50,
also 50% = Faktor 1.0 wie bisher); alte Spielstaende (0) werden wie 50%
behandelt. Die bisherige 3-Stufen-Auswertung (AggressivitaetKISpieler)
entfaellt in beiden Klassen.

Verifiziert: Lib-Build 0 Fehler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…52.0)

Stuetzpunkt.MoralBonusZahlen bezahlt vor dem Kampf einen einmaligen
Moral-Bonus (Kosten je Truppenstaerke, gespeichert in
MoralBonusBezahlt). MoralFuerKampf liefert die effektive Kampfmoral
(Truppenmoral + MoralBonusWert 15, auf 100 gedeckelt) und wird im
Kampfaufbau (Kampfberechnung) fuer die Angreifer genutzt. Der
KampfereignisseManager erstattet den Bonus bei Sieg zurueck (bzw.
ungenutzte Boni) und setzt ihn zurueck. Convenience am
StuetzpunktVerwaltenManager fuer die UI.

Verifiziert per Konsolentest (Boost-Math inkl. Deckelung, Bezahlen
mit/ohne Truppen, Doppel-Bezahlung abgelehnt).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auf Wunsch: Ein vor dem Kampf bezahlter Moral-Bonus wird mit dem Kampf
verbraucht und bei einem Sieg nicht mehr zurueckerstattet (zuvor
Rueckerstattung bei Sieg). Nur ein ungenutzter Bonus (ohne
stattgefundenen Kampf) wird weiterhin erstattet. Bestaetigungstext
angepasst (kein Rueckerstattungs-Versprechen mehr).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
….54.0)

TruppenAnheuern bezahlt jetzt den Werbe-Etat und reiht die Truppen in
Stuetzpunkt.GeworbeneTruppen ein, statt sie sofort per ErhoeheTruppen
einzustellen. GeworbeneTruppenEinstellen stellt sie zum Rundenende ein
(im KampfereignisseManager vor den Kaempfen, mit Meldung).
GetAnzahlTruppenInklGeworben liefert stationierte + angeworbene Truppen
fuer die Verwaltung. TruppenEntlassen storniert zunaechst noch nicht
eingetroffene Anwerbungen und erstattet den Werbe-Etat zurueck.
Kapazitaetspruefung inkl. angeworbener Truppen.

Verifiziert per Konsolentest (Anwerben queuet + zahlt, Anzeige
current+geworben, Stornierung erstattet zurueck, Rundenende stellt ein).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
KampfereignisseManager.ErmittleEreignisse erhaelt zwei Flags (aus dem
WinForms-Original frmKampfereignisse uebernommen): KI-Stuetzpunkt-
Aktionsmeldungen ausblenden und Kaempfe ohne menschliche Beteiligung
(Angreifer/Verteidiger/ueberfallene Karawane alle KI) unterdruecken.
Aktionen und Kaempfe werden weiterhin immer abgewickelt, nur die
Anzeige wird gefiltert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
"Truppen schicken" mit gegnerischem Stuetzpunkt als Ziel erzeugt zum
Rundenende einen Kampf (EnumKampfArt.StuetzpunktAngriff). Bei Sieg mit
vollstaendig ausgeloeschter Garnison und ueberlebenden Angreifern wird
der Stuetzpunkt eingenommen, sonst nur beschaedigt (-25 Zustand). KI
greift je nach Aktivitaet ebenfalls an. Angriffe erst 7 Jahre nach
Spielbeginn.

Fehlerbehebung: invertierte Bereichspruefung im ZielStuetzpunktID-Setter
verwarf zuvor jedes gueltige Ziel, sodass "Truppen schicken" nie ein Ziel
speichern konnte.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die KI-Zielauswahl (KiZufaelligesAngriffsziel) beruecksichtigt nur noch
Stuetzpunkte menschlicher Besitzer. Zusaetzlich ueberspringt
ErmittleStattfindendeKaempfe als Sicherung jeden Angriff, bei dem
Angreifer und Verteidiger beide KI sind (schuetzt auch alte Spielstaende).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ist der handelnde Spieler zollfrei (Privileg 23 bzw. 50%-Chance von
Privileg 31), erhalten nun auch die Zollburg-Besitzer keinen Zollanteil
mehr. Die Zollfreiheit wird vor der Auszahlung ermittelt und ueberspringt
die gesamte Zollberechnung, statt die Kosten erst nachtraeglich auf 0 zu
setzen (der Besitzer wurde zuvor trotzdem gutgeschrieben).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
KampfereignisseManager.ErmittleEreignisse entfernt die |-Marker um die
Spielernamen nicht mehr aus den Kampf-Zusammenfassungen. Die Marker sind
die Markup-Konvention der Lib und bleiben nun erhalten, damit die Ansicht
die Namen hervorheben kann (fett, menschliche Spieler dunkelrot - wie im
WinForms-Original).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die KI-Kandidatensuche in WahlAnlegen ignorierte nach 100 erfolglosen
Versuchen die Eignungspruefung komplett - dadurch konnten z. B. amtslose
Spieler fuer den Regenten kandidieren. Neu gibt es eine gelockerte
Zwischenstufe (CheckBewerbAmtGelockert): der starre 1-2-Stufen-Sprung
entfaellt, der Kandidat muss aber unterhalb des Zielamts liegen, und
Amtslose bleiben auf Einstiegsaemter (Stufe 1-2) beschraenkt. Erst als
allerletzte Reserve wird wie zuvor die Pruefung ignoriert, damit jede
Wahl garantiert zwei Kandidaten hat.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Menschliche Spieler koennen sich jetzt gleichzeitig fuer mehrere freie
Aemter bewerben. Massgeblich ist die Kandidatenliste der Wahl statt einer
einzelnen gespeicherten Teilnahme; WahlAnmeldungUmschalten schaltet je
Wahl unabhaengig um, GetBewerbungsangebote markiert alle Bewerbungen.

Bei der Auszaehlung sortiert GetWahlenMitMenschlicherBeteiligung nach
Amtsstufe absteigend (hoechstes Amt zuerst). Gewinnt der Spieler ein Amt,
zieht VergebeAmt ueber die neue SpielerAusAllenWahlenEntfernen alle
uebrigen Bewerbungen des Gewinners zurueck - er behaelt nur das hoechste
gewonnene Amt. Kerkerstrafe und Ausscheiden entfernen den Spieler
ebenfalls aus allen Wahlen. HatMenschlicheBeteiligung ist oeffentlich.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Issue #18, Schritt 1: Klagt ein menschlicher Spieler einen KI-Spieler an,
beruecksichtigen die KI-Richter jetzt die von seinen Spionen gesammelten
Beweise gegen den Angeklagten. StarteVerhandlung ermittelt die
Beweisstaerke aus den Spionage-Delikten des Klaegers (GetBeweise),
BerechneKiUrteil addiert sie zum Schuld-Faktor - mehr Beweise erhoehen
die Verurteilungswahrscheinlichkeit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Issue #18, Schritt 2 (Mischung): KI begehen zum Rundenende zufaellige
Delikte, deren Haeufigkeit mit der Bosheit steigt
(RundenEndeManager.FuehreKiStraftatenDurch); die Verbrechen werden je
Gesetz gespeichert und verblassen jaehrlich. Der Speicher begingVerbrechenX
wurde von HumSpieler in die Basisklasse Spieler gehoben (KI + Mensch
teilen ihn, additiv fuer kuenftige reale KI-Aktionen). StarteVerhandlung
nutzt fuer KI wie Mensch die tatsaechlich begangenen Delikte statt
Zufall; nach der Verhandlung sind sie gesuehnt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der in 3.63.0 in die Basisklasse Spieler gehobene Delikt-Speicher
_begingVerbrechenX war bei per Deserialisierung geladenen Spielern null
(der Konstruktor wird dabei umgangen), wodurch FuehreKiStraftatenDurch
zum Rundenende crashte und das Jahr stehenblieb. Zugriff jetzt null-sicher
per Lazy-Init.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ist der Spieler angeklagt, kann er eine Aussage waehlen (Leugnen,
empoert leugnen, Teilgestaendnis, Gestaendnis; GetAussageOptionen /
SetzeAussage). Gestaffelte Wirkung abhaengig von der Beweislage:
Gestaendnis erhoeht die Verurteilungsneigung, senkt aber die Strafe
(Straffaktor); Leugnen hilft nur bei schwacher Lage, empoertes Leugnen
schlaegt bei starker Lage ins Gegenteil um. BerechneKiUrteil nutzt den
Aussage-Bonus, WerteAus skaliert das Strafmass.
IstAngeklagterAktiverSpieler steuert die Anzeige im Client.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Jedes Beweisstueck (begangenes Delikt bzw. erspaehtes Delikt) wog bisher
nur 1 gegen die zufaellige Richter-Sympathie (20-80), sodass selbst bei
klarer Beweislage kaum verurteilt wurde. Jedes Beweisstueck wird nun mit
BeweisGewicht (10) gewichtet: echte Beweise fuehren im Schnitt zu ~80 %
zur Verurteilung, gestaffelt nach Anzahl (0->5%, 1->31%, 2->63%, 3->84%,
4+->95%+). Die Aussage-Boni des Angeklagten wurden auf denselben Massstab
angehoben, damit sie spuerbar bleiben (Gestaendnis fast sichere
Verurteilung bei milderer Strafe, Leugnen raeumt Falschanklage frei,
empoertes Leugnen schlaegt bei erdrueckender Lage ins Gegenteil um).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ist der aktive Spieler Partei, kann er vor dem Urteil die Richter
bestechen: als Angeklagter auf Freispruch, als Klaeger auf Verurteilung
(KannBestechen, GetRichterBestechungsOptionen, SetzeRichterBestechung).
Wirkung "ab Schwelle sicher": erreicht der auf einen Richter entfallende
Anteil dessen Schwelle (halbes Barvermoegen, mind. 3000), stimmt er
sicher im Sinne des Bestechers, darunter anteilig (BerechneKiUrteil).
Stufen sind auf das Barvermoegen begrenzt und werden sofort abgebucht;
WurdeBestochen/GetBestechungsOffenlegung legen vor dem Urteil offen, dass
Gelder geflossen sind. Der Zeugen-Topf (SetzeZeugenBestechung) ist
angelegt, bleibt aber wirkungslos bis zu den echten Zeugen (Schritt 5).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
In jeder Verhandlung sagen bis zu zwei KI-Zeugen (weder Partei noch
Richter) aus. Ob fuer oder gegen den Angeklagten ergibt sich aus dem
Verhaeltnis (naeher am Angeklagten -> fuer ihn, sonst dagegen);
ueberzeugend bei grossem Beziehungsunterschied, sonst schwach. Die
Aussagen fliessen als _zeugenBonus ins Urteil (BerechneKiUrteil). Der in
3.66.0 angelegte Zeugen-Topf wirkt nun: Bestechung zieht einen Zeugen
(ab Schwelle sicher) auf die Seite des Bestechers und laesst ihn
ueberzeugend auftreten. Neu: GetZeugenAnzahl, ErmittleZeugenAussagen
(nach der Bestechung), Klasse ZeugenAussage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Zeugen tragen zusaetzlich zu ihrer Einordnung einen gesprochenen Satz
vor, passend zu Richtung (fuer/gegen) und Ueberzeugungskraft
(ueberzeugend/zoegerlich). Pronomen und der/die Taeter(in) richten sich
nach dem Geschlecht des Angeklagten.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der JSON-Typ-Binder liess beim Laden nur "Conspiratio.Lib.*"-Typen zu und
wies die Kampf-Einheiten ab, die aus Kompatibilitaetsgruenden bewusst im
alten Namespace "Conspiratio.Kampf" verblieben sind (ZollSoeldner,
RaubRaeuber, ...). Dadurch war jeder Spielstand mit Stuetzpunkt-Einheiten
unladbar ("Error resolving type specified in JSON ...").

Der Binder loest Typen jetzt direkt in der Conspiratio.Lib-Assembly auf
(deckt den Kompatibilitaets-Namespace mit ab), nutzt die
Uebersetzungstabelle nur noch als Fallback fuer umbenannte Typen und
prueft weiterhin auf das "Conspiratio."-Praefix. Die Mapping-Tabelle
wurde zur gemeinsamen Nutzung durch beide Binder statisch gemacht.
Verifiziert gegen echte Spielstaende (test_godot_1606/1609).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Anklage- und Verteidigungsplaedoyer (GetAnklageplaedoyer,
GetVerteidigungsplaedoyer). Anklage: Ton nach Beweislast (haltlos ->
erdrueckend). Verteidigung: Ton nach Ansehen des Angeklagten; hohes
Ansehen zieht die Richter zudem etwas Richtung Freispruch
(_plaedoyerBonus in StarteVerhandlung, in BerechneKiUrteil: >=80 -6,
>=30 -3). Schliesst die Gerichtsverhandlung-Erweiterung (Issue #18) ab.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…3.68.1)

Das Rueckzahlungsjahr wurde als Restlaufzeit + aktuelles Jahr berechnet,
die Restlaufzeit aber nie heruntergezaehlt -> das Jahr wanderte jedes
Jahr mit (nach einem Schuldturm-Jahr sogar +2). Kredit bekommt ein festes
_rueckzahlungsjahr, das NimmKredit auf aktuelles Jahr + Laufzeit setzt;
GetOffeneKredite zeigt es an und schreibt alte Kredite (ohne festes Jahr)
beim ersten Oeffnen einmalig aus der Restlaufzeit fest. TilgeKredit setzt
es zurueck. Verifiziert per Konsolentest (Endjahr bleibt konstant).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neue Methode AemterManager.GetFreieAemterAnkuendigung() liefert die zu
Zugbeginn neu zu besetzenden Aemter des aktiven Spielers als fertigen
Ankuendigungstext (Amt + Ort je Zeile) bzw. null, wenn es keine fuer ihn
bewerbbaren freien Aemter gibt. Basiert auf GetBewerbungsangebote.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…) (3.70.0)

Neuer CheatManager fuer die komplexeren WinForms-Cheats: UebernehmeAmt
(nimmt einer KI das Amt ab, tauscht das alte Amt zu ihr), BaueHaus,
LasseVerklagen (Delikt + KI-Klaeger + drei Richter + Gerichtsverhandlung
fuers Folgejahr). Dazu Combobox-Daten (Stufen/Gebiete/Aemter/Staedte/
Haustypen). Verifiziert per Konsolentest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die in der Statistik angezeigten, aber nie befuellten Kennzahlen werden
jetzt waehrend des Spiels mitgezaehlt: verkaufte/eingekaufte Waren und
Gesamtumsatz, entrichtete Steuern und Zoelle, Amtseinkommen, hoechstes
Amt, Gesetzesverstoesse, Wahlteilnahmen/-siege, Anklagen, gezeugte Kinder
und Schuldturm-Aufenthalte. Alle Zaehler betreffen nur menschliche Spieler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SirTobyB and others added 28 commits August 3, 2026 19:53
Neue Methode KontrahentenManager.GetKontrahentDetails(spielerId) samt
Datenklasse KontrahentDetailInfo (Migration von KontrahentDetails):
Name, Titel, Alter, Amt immer; Vermoegen, Gesundheit, Beweislast
(per Spionage aufgedeckte Delikte) und Erhebungsstand nur bei laufender
Spionage gegen den Kontrahenten.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…Anzeige

Neues Modell Dynastiegeneration/AhnPerson + Ahnentafel-Liste am HumSpieler.
FamilieManager.FuehreTestamentAus haelt die aktuelle Generation (Oberhaupt,
Ehepartner, Kinder mit Jahren, Erbe) vor TestamentVollstrecken fest, sonst
gingen die Daten bei der Erbuebernahme verloren. AhnentafelManager liefert
alle Generationen (vergangene + lebende) fuer die Anzeige. PrivilegienManager
fuehrt die Ahnentafel als immer verfuegbaren Eintrag. Savegame-kompatibel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AhnPerson traegt jetzt den Titel. Oberhaupt und Ehepartner werden beim
Erbfall und fuer die lebende Generation mit ihrem gegenderten Titel
(GetTitelGegendert) erfasst; Kinder haben mangels Amt/Titel keinen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neuer GrabsteinManager.ErmittleGrabspruch(SpielerStatistik) schaetzt aus
der Pro-Spiel-Statistik den praegendsten Typ des verstorbenen Charakters
(Kriegsherr, Intrigant, Kaufmann, Kirchenmann, Staatsmann, Patriarch,
Gesetzloser) und liefert einen passenden kurzen Grabspruch; ohne klares
Profil einen allgemeinen. Vorbild "Die Fugger 2".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neuer MaetresseManager + HumSpieler.HatMaetresse. Ein verheirateter
Spieler mit genug Talern kann sich eine Maetresse nehmen: einmalige
Kosten, +Ansehen (dauerhaft), +verbleibende Jahre, geringere Chance auf
ehelichen Nachwuchs (FamilieManager.StehtGeburtAn), jaehrlicher Unterhalt
und Skandal-Risiko. PrivilegienManager fuehrt sie als synthetischen
Eintrag, solange keine Maetresse vorhanden ist. Vorbild "Die Fugger 2".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neue Methode SchreibstubeManager.TilgeUeberfaelligeKredite() tilgt am
Rundenende alle Kredite des aktiven Spielers, deren Rückzahlungsjahr
erreicht oder überschritten ist – notfalls rutscht das Vermögen dabei
ins Minus. Der Betrag wird dem Gläubiger gutgeschrieben, der Kredit-Slot
geleert, und pro getilgtem Kredit wird eine Hinweismeldung zurückgegeben
(mit gesondertem Hinweis, falls das Vermögen negativ wird). Fehlt bei
Altspielständen das Rückzahlungsjahr, wird es aus Dauer + aktuellem Jahr
nachgetragen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Über <DebugType>embedded</DebugType> werden die Debug-Symbole nun direkt
in die Assembly eingebettet - auch im Release. Dadurch enthalten
Stacktraces bei den Endnutzern Datei- und Zeilennummern, und die Symbole
reisen im NuGet-Paket mit. Grundlage für aussagekräftige Fehlerberichte.
Keine Code-Änderung, nur Build-Einstellung.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Optionale, bei der Spielerstellung wählbare Aufträge nach Vorbild von
"Die Fugger 2", unterteilt in leicht/mittel/schwer.

- EnumAuftrag + Spieleinstellungen.Auftrag (Standard KeinAuftrag =
  freies/endloses Spiel; savegame-sicher).
- AuftragManager: sieben Aufträge (Aufsteiger, Kleiner Wohlstand, Herr
  des Doms, Mäzen, Baumeister, Talerrennen, Kriegsherr) mit
  Fortschritts- und Erfüllungsprüfung sowie Fortschrittstext.
- HighscoreManager: lokale Bestenliste (highscores.json), sortiert nach
  Schnelligkeit (wenigste Spieljahre zuerst).
- HumSpieler: neue Zähler DomherrJahreInFolge und GestifteterBauwert;
  BauwerkStiftenManager.FuehreStiftungAus addiert den gestifteten Wert
  mit (für "Mäzen"). Alte Spielstände starten ohne Auftrag, Zähler 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Erweitert den AuftragManager um sechs Aufträge (jetzt 13 gesamt):
- leicht: Kaufmann (200.000 Taler Gesamtumsatz), Familienvater (3 Kinder)
- mittel: Wahlsieger (3 Wahlen gewinnen), Kriegsheld (10 Kämpfe gewinnen)
- schwer: Karawanenschreck (8 Karawanen überfallen),
  Meuchelmörder (3 erfolgreiche Anschläge)

Alle nutzen bereits geführte SpielerStatistik-Kennzahlen; kein neues
Tracking nötig. Die neuen EnumAuftrag-Werte sind ans Ende angehängt,
sodass bestehende Enum-Werte und damit alte Spielstände stabil bleiben.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nfassen

Alle Änderungen seit dem letzten echten GitHub-Release (3.46.0) stehen
jetzt gesammelt unter einer einzigen ## [Unreleased]-Überschrift (DE- und
EN-Stichpunkte), statt je Change einen eigenen datierten Versionsblock.
Künftige Changes werden nur noch dort angehängt; die csproj-Version darf
weiterhin erhöht werden. 3.46.0 und älter bleiben unverändert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GetFreieAemterFuerSpX schrieb die bewerbbaren Ämter in ein fest 50
Einträge großes Array, obwohl es bis zu 199 Wahlen geben kann. War ein
Spieler für mehr als 50 gleichzeitig offene Ämter bewerbbar (z. B. wenn
durch Todesfälle oder Sabotage viele Ämter auf einmal frei wurden), lief
das Array über (IndexOutOfRangeException).

Das Array wird nun auf die maximale Wahlenzahl dimensioniert;
GetAnzahlFreieAemterFuerSpX zählt robust bis zum ersten Leereintrag.
Behebt das alte 'gelegentlich viel zu hoher amtcounter, speziell wenn
sabotiert wird'-TODO. Mit 60 bewerbbaren Ämtern reproduziert und
verifiziert (vorher IndexOutOfRange, jetzt korrekt 60).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die Methode ZugNachrichtenManager.FuehreTodDesAktivenSpielersDurch wurde
nirgends aufgerufen (Lib, Godot, WinForms) und trug ein veraltetes TODO
zu Testament/Erbfolge – beides läuft längst über
FamilieManager.FuehreTestamentAus. Ersatzlos entfernt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Das Kellermeister-Privileg (Amt 23) zeigte bisher nur einen Text ohne
Wirkung. Jetzt:
- PrivVergifteterWein.PrivExecute öffnet die Personen-Karte im
  Zielauswahl-Modus 12 (sofern noch keine Vergiftung vorbereitet ist).
- KontrahentenManager.PersonWasMachen führt für Modus 12
  SW.Dynamisch.WeinVergiften aus (5.000 Taler, Ziel für dieses Jahr
  vormerken).
- AemterEbeneManager.GetTitel liefert die Kopfzeile "Wein vergiften in".

Auflösung (FuehreVergiftetenWeinDurch) und Erfolgschance waren bereits
vorhanden; die Ergebnismeldung grammatikalisch korrigiert
("... wieder, doch seine Gesundheit hat gelitten"). Mit Konsolentest
verifiziert (Zielvormerkung, Kosten, Doppelsperre, Auflösung, Reset).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GetUntergebene legte Untergebenen-Aemter/-Inhaber in zwei fest 7 Eintraege
grossen Arrays ab; ufinalID multipliziert je untergeordnetem Amt ueber
alle Staedte/Laender eines Gebiets. In der aktuellen Aemtertabelle passt
das gerade so (max. 6 Eintraege) - der Puffer ist aber nur einen Slot
gross, sodass ein zusaetzliches Unteramt oder eine 5. Stadt je Land eine
IndexOutOfRangeException ausloesen wuerde.

Arrays jetzt nach den Max-Konstanten dimensioniert (analog zum
Wahlen-Fix). Analytisch verifiziert: max. moegliche Fuelllaenge ueber
alle Aemter = 6, neue Groesse deutlich groesser; kein Regressions-Crash.
Gefunden bei einem gezielten Scan nach fest verdrahteten Array-Groessen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tipps[16] war doppelt belegt: der Kredit-Hinweis ueberschrieb den Tipp
"Verkaufserloes nimmt bei wiederholtem Verkauf ab", der dadurch nie
angezeigt wurde. Der Kredit-Hinweis liegt jetzt auf Index 30,
TippsMaxIndex entsprechend auf 30 erhoeht.

Verifiziert: MaxIndex 30, Tipp 16 = Verkaufserloes, Tipp 30 = Kredit,
keine leeren Tipps in 0..30.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neues Feature nach Vorbild "Die Fugger 2":
- FechtDuellManager: Fechtunterricht (steigende Kosten, hebt die
  Fechtfaehigkeit) und Duelle. Ein Amtstraeger kann wegen einer
  Beleidigung zum Duell gefordert werden (max. eines pro Zug). Der
  Sieger ergibt sich aus der Fechtfaehigkeit gegen eine aus der
  KI-Bosheit abgeleitete Gegnerstaerke plus Zufall. Der Verlierer
  verliert Gesundheit; unter 30 verliert er sein Amt (AmtVonXfreigeben,
  Neuwahl) - symmetrisch, auch der Spieler kann verlieren.
- HumSpieler: Fechtfaehigkeit, FechtstundenGenommen,
  DuellGefuehrtDiesesJahr (Reset in RundenManager.BeginneZug).
- PrivilegienManager: synthetische Eintraege 10002 (Fechtunterricht) und
  10003 (Duell). Personen-Karten-Modus 14 in KontrahentenManager und
  AemterEbeneManager.

Mit Konsolentest verifiziert: Preisstaffel, Skill, Duell-Voraussetzungen,
Sieg -> KI-Amtsverlust, Symmetrie (Spieler verliert -> eigenes Amt weg),
Once-per-year-Sperre. Alte Spielstaende starten mit Fechtfaehigkeit 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Beleidigung ist jetzt ein Ehrenhandel mit Entscheidung statt sofortigem
Duell:
- Beleidige(zielId): Der Beleidiger sinkt deutlich im Ansehen des Ziels
  (Beziehungsverlust bei KI). Der Beleidigte entscheidet ueber
  Satisfaktion (KI aus Bosheit, Mensch per Dialog).
- VerweigereSatisfaktion(id): Verzicht kostet den Verzichtenden Ansehen
  bei den Amtstraegern seiner Amtsstufe (Stadt/Land/Reich).
- PruefeKiBeleidigtSpieler(): Selten beleidigt eine KI den Spieler; die
  Chance haengt vor allem an der (feindseligsten) Beziehung zum Spieler
  und steigt erst unter "neutral" (50), Bosheit spielt eine kleine
  Rolle. Gedeckelt ~7-8 %, im Schnitt seltener als alle 15 Zuege.
- Duell "im Morgengrauen"; Mensch-gegen-Mensch vergleicht beide
  Fechtfaehigkeiten. Privileg-Label "Amtstraeger beleidigen".

Verifiziert: Beziehungsverlust -25, Ansehensverlust -15, Frequenz
(Bez.60->0%, 30->3.1%, 0->6.8%), Mensch-Duell 96%/6%.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die Chance, dass eine beleidigte KI Satisfaktion (ein Duell) verlangt,
steigt von 30 % + Bosheit/2 auf 50 % + Bosheit/2 (Bereich jetzt
50-100 %, vorher 30-80 %). Nur die Konstante KiSatisfaktionsBasis.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- PlayerSetupManager.ErstelleSpieler setzt das Alter der menschlichen
  Spieler passend zum Startjahr, sodass ihr Geburtsjahr 1580 ist (vorher
  blieb das Alter 0 -> Geburtsjahr = Startjahr).
- FechtDuellManager.GetBeleidigungsFrage nutzt "Er"/"Sie" je nach
  Geschlecht des Ziels statt fest "Er".

Verifiziert: Startjahr 1600 -> Alter 20, Geburtsjahr 1580; Frage
maennl./weibl. korrekt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Damit der Client ein Duell als eigene Szene inszenieren kann, gibt es eine
neue UI-Schnittstelle IDuellDialog (SW.UI.DuellDialog). Sie ist ein optionaler
Parameter von UIHelper.Initialisieren, sodass Clients ohne Inszenierung
unveraendert bleiben.

DuellErgebnis liefert zusaetzlich GegnerName und AmtName, damit der Client den
Ausgang selbst formulieren kann, statt die vorformulierte Meldung zu zerlegen.
Verlangt ein Beleidigter Satisfaktion, spielt KontrahentenManager das Duell
ueber den neuen Dialog aus; ist keiner registriert, bleibt es bei der
bisherigen Textmeldung.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ein Duell wird nicht mehr ausgewuerfelt, sondern als Schlagabtausch von
Beleidigungen gespielt (Vorbild "Monkey Island 1"). Der neue
WortgefechtManager fuehrt je Wortwechsel zwei Schritte: Der Angreifer waehlt
aus mindestens drei Beleidigungen, der Angegriffene muss unter mindestens
drei Kontern den passenden erkennen. Die falschen Antworten sind die Konter
anderer Beleidigungen und klingen darum absurd. Wer zuerst drei Wortwechsel
gewinnt, gewinnt das Duell; kein Spruchpaar wiederholt sich.

Gegen einen menschlichen Gegner waehlen beide Seiten selbst (Hot-Seat), gegen
die KI entscheidet beim Kontern ein Wuerfel, gewichtet mit der
Fechtfaehigkeit. Diese wirkt hybrid: gedeckelter Treffervorsprung plus
haeufiger sitzende eigene Beleidigungen. Die Gewichte sind so kalibriert,
dass perfektes Kontern gegen einen mittleren Gegner auch ganz ohne
Fechtunterricht rund 70 % der Duelle gewinnt, waehrend durchweg falsche
Konter selbst mit maximalem Unterricht nur rund 40 % gewinnen - Training
hilft spuerbar, ersetzt den Witz aber nicht.

Damit der Ausgang erst nach dem Gefecht feststeht, ist FechtDuellManager
aufgetrennt: BerechneSiegchance und WendeDuellAusgangAn sind oeffentlich,
FuehreDuellDurch (gewuerfeltes Duell) verhaelt sich unveraendert und bleibt
der Weg fuer Clients ohne Inszenierung. IDuellDialog bietet nun
SpieleWortgefecht und ZeigeAusgang.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die mit Spionen gesammelten Beweise lassen sich jetzt nutzen: Wer genug
Belastendes gegen einen Amtstraeger hat, kann ihn erpressen und einige Jahre
lang dessen Amtsprivilegien mitnutzen. Umsetzung nach dem Konzept von
PommBaer samt der Abstimmung im Issue.

Die Beweispunkte mussten nicht neu erfunden werden: AktiveSpionagen zaehlt
nicht Vorfaelle, sondern summiert die Beweismaechtigkeit (1-4 je Fund) - genau
die Groesse, die das Konzept meint. Noetig sind 3/5/7 Punkte je nach
Amtsebene. Die Erfolgsaussicht betraegt 75 % plus 4 % je ueberzaehligem
Punkt, minus 15 % je Titelstufe des Ziels ueber dem Erpresser (plus 3 % je
Stufe darunter), minus 5 % bei gleicher Religion; die drei Szenarien der
Konzept-Tabelle ergeben damit exakt 56/48/40 %.

Eine gelungene Erpressung wirkt 4/3/2 Jahre plus 0-3/0-2/0-1 Zufall (im
Issue gegenueber dem Konzept um ein Jahr gekuerzt) und verbraucht die
Beweise; eine misslungene laesst sie verfallen. Mehrere Erpressungen laufen
parallel und enden zum Jahreswechsel. Menschliche Opfer entscheiden selbst
(neue Schnittstelle IErpressungDialog) - wer ablehnt, laesst dem Erpresser
die Beweise fuer eine Anklage.

Fuer die Privilegien-Uebernahme genuegte eine neue Abfrage: Die gesamte
Amtsabhaengigkeit steckt in PrivilegienAktualisieren, die Privilegien selbst
wirken generisch. GetAmtsPrivilegien spiegelt diese Bedingungen; ein
Konsolentest vergleicht beide ueber alle Aemter, damit sie nicht
auseinanderlaufen. Der Erpresste verliert die aktiv nutzbaren
Amtsprivilegien und behaelt die passiven.

Erpressung ist selbst strafbar. Das neue Strafgesetz brauchte entgegen der
Befuerchtung keine Savegame-Migration: Die Gesetzestabelle hat 100 feste
Plaetze und ist nur duenn belegt, sodass Index 25 im Strafblock frei war -
Gericht und Jurist erfassen ihn ueber die vorhandenen Bereichsgrenzen von
selbst.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bislang gab es nur im Godot-Repo eine Anleitung; die Lib-spezifischen Regeln
mussten jedes Mal neu erlesen werden. Festgehalten sind vor allem die Dinge,
die man dem Code nicht ansieht:

- Sprachstand C# 7.3 (netstandard2.0 ohne LangVersion) als harte Grenze.
- Das Rezept, eine unveroeffentlichte Version fuer den Godot-Client sichtbar
  zu machen - inklusive des Schritts, der immer wieder vergessen wird: ohne
  Loeschen im NuGet-Cache baut Godot stillschweigend gegen den alten Stand.
- Savegame-Kompatibilitaet: Der ContractResolver erzeugt Objekte ohne
  Konstruktoraufruf, spaeter ergaenzte Felder kommen also als null bzw. zu
  kurzes Array an. Daraus folgt die Lazy-Init-Konvention.
- Domaenen-Fallstricke, die in dieser Sitzung Zeit gekostet haben: Amt und
  Gebiet gehoeren zusammen, die Gesetzestabelle hat 100 feste Plaetze und ist
  duenn belegt, Spionage-Beweise sind eine Punktsumme statt eines Zaehlers,
  und die Amtsabhaengigkeit der Privilegien steckt an genau einer Stelle.
- Testgewohnheiten: Zufallswerte fixieren, bei Wahrscheinlichkeiten auf Quoten
  statt Einzelfaelle pruefen, Refactorings gegen das Original vergleichen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die Spielregeln wurden bisher mit wegwerfbaren Konsolenskripten geprueft, die
nach jedem Feature geloescht wurden - die Zusicherungen waren damit jedes Mal
verloren. Sie leben nun als 36 Tests in Conspiratio.Lib.Tests weiter.

Verankert sind unter anderem: die drei Szenarien der Erpressungs-Konzepttabelle
als exakte Werte (56/48/40 %), Mindestbeweise und Wirkungsdauer je Amtsebene,
der Beweisverfall inklusive der PvP-Sonderregel, parallel laufende
Erpressungen, die Balance-Quoten des Wortgefechts, die Duellauswertung sowie
die Lazy-Init-Zugriffe, von denen die Ladbarkeit alter Spielstaende abhaengt.

Der wichtigste Test vergleicht GetAmtsPrivilegien mit PrivilegienAktualisieren
ueber alle Aemter. Diese Gleichwertigkeit war die Grundlage der
Privilegien-Uebernahme und ist nun gegen spaeteres Auseinanderlaufen
abgesichert.

Der gesamte Spielzustand liegt in statischen SW-Fassaden, deshalb laeuft die
Suite bewusst ohne Parallelitaet und jeder Test baut sich seine Spielwelt neu
auf. Zufallsabhaengige Groessen (KI-Bosheit) werden gepinnt, Wahrscheinliches
wird ueber Quoten statt Einzelfaelle geprueft.

Das Projekt ist nicht packbar und stoert die Pack- und Publish-Kette nicht;
beide Workflows fuehren die Tests jetzt aus, im Release-Workflow bewusst vor
dem Veroeffentlichen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Das Privileg blieb nach einem Amtswechsel sichtbar, wenn das neue Amt gar
keine Untergebenen hat: In PrivilegienAktualisieren deckte die Zuweisung nur
den Fall "Untergebene vorhanden" ab, sodass ein einmal gesetztes true aus
einem frueheren Amt stehen blieb. Ein Klick zeigte dann eine leere Liste.
Die Zuweisung erfasst jetzt beide Faelle.

Der zugehoerige Test sucht sich die passenden Aemter selbst - je eines mit und
ohne Untergebene - und bleibt damit gueltig, falls sich die Spieldaten
aendern. Dass er den Fehler wirklich fasst, wurde geprueft, indem die
Korrektur voruebergehend zurueckgenommen wurde: Dann schlaegt er fehl.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die READMEs (deutsch und englisch) bekommen einen Abschnitt "Tests": was es
gibt, wie man es startet, und die Erwartung, dass neue Features
ueblicherweise Tests mitbringen - inklusive der Abgrenzung, was keine
braucht (reine Textausgaben, blosses Weiterreichen an die Oberflaeche).

In der CLAUDE.md stand noch "There are no automated tests". Der Abschnitt ist
nun zweigeteilt: die Tests als Normalfall samt der Konventionen, von denen
die Suite abhaengt (keine Parallelitaet wegen des statischen SW-Zustands,
TestSpielwelt-Helfer, gepinnte Zufallswerte, Quoten statt Einzelfaelle), und
die Konsolen-Harness ausdruecklich als Werkzeug zum Umsehen statt zum
Behalten.

Neu festgehalten sind zwei Erkenntnisse: Bei einer Fehlerbehebung erst
nachsehen, dass der Test ohne die Korrektur fehlschlaegt. Und: Das
Veroeffentlichen auf nuget.org ist ein Nebeneffekt von master - solange etwas
auf einem Feature-Branch liegt, existiert die Version fuer andere und fuer
die CI nicht.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sturm, Flut, Brand, Erdbeben und Pest suchen die Staedte heim - selten, rund
alle vier bis fuenf Jahre, dann aber heftig.

Die Auswahl musste nicht erfunden werden: Jede Stadt traegt seit jeher je Art
eine Anfaelligkeit von 0-100 in den Spieldaten (Stadt.GetKatastrophen), die
bislang ungenutzt war. Art und Ort werden danach gewichtet ausgelost, und
eine Stadt mit 0 wird von dieser Art nie getroffen - Hafenstaedte ersaufen,
Bergstaedte beben. Eine Katastrophe trifft eine einzelne Stadt, alle
anfaelligen Staedte einer Grafschaft oder des ganzen Reichs.

Folgen je betroffener Stadt: 8-20 % der Einwohner (Pest doppelt), 1-2 Punkte
Reichtum und 20-40 % der Warenvorraete; die Knappheit hebt die Preise um 2-4
je Ware. Ein echtes Angebot/Nachfrage-System gibt es nicht - die Preise
schwanken sonst rein zufaellig und haengen nicht am Vorrat -, deshalb wirkt
die Katastrophe direkt auf Vorrat und Preis statt auf eine simulierte
Nachfrage.

Auch die Spieler trifft es in betroffenen Staedten: eingelagerte Waren im
selben Umfang, Wohnsitze verlieren 10-25 Prozentpunkte Zustand, und eine Pest
kostet Gesundheit, wenn man dort wohnt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…7.0)

SW.Statisch.SetRnd(int seed) setzt den Zufallsgenerator auf einen festen
Startwert. Rnd war bisher nur lesbar, sodass sich ein Spielverlauf nicht
wiederholen liess - ein fehlgeschlagener automatischer Durchlauf des
Godot-Clients war damit nicht nachstellbar.

Genau das hat sich sofort ausgezahlt: Mit festem Startwert war ein bis dahin
sporadischer Haenger reproduzierbar und als echter Fehler zu erkennen.
FuelleRestlicheAemter wuerfelte fuer jede angelegte Wahl blind einen der
KI-Plaetze als Gewinner aus. IstDieWahlVoll besagt aber nur, dass die Wahl
angelegt ist - nicht, dass sich jemand beworben hat. Traf der Wuerfel einen
leeren Platz (Kandidat 0), scheiterte VergebeAmt mit einer
NullReferenceException, die den gesamten Jahreswechsel abbrach und das Spiel
haengen liess. Gewaehlt wird jetzt nur unter den tatsaechlich vorhandenen
Bewerbern; gibt es keinen, bleibt das Amt unbesetzt und die Wahl steht im
naechsten Jahr erneut an.

Tests: TestSpielwelt.Starte nimmt einen optionalen Startwert, ZufallTests
sichern die Reproduzierbarkeit (gleiche Zahlenfolge und gleicher Spielaufbau),
AemterTests decken die Wahl ohne Bewerber und den einzelnen Bewerber ab.
51 Tests gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@SirTobyB
SirTobyB merged commit b7f8e59 into master Aug 15, 2026
1 check passed
@SirTobyB
SirTobyB deleted the feature/stuetzpunkt-handel-spieler branch August 15, 2026 14:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant