Phase 2 war die vier Monate wo aus einem technischen Fundament ein spielbares Spiel wurde. Das klingt nach einem geraden Weg. War es nicht. Es war ein Durchwursteln mit gelegentlichen Hochpunkten, vielen Momenten wo nichts funktionierte, und einem November der sich angefuehlt hat wie eine Gegengerade in einem langen Rennen.
August war ich nicht weg. Waehrend andere Urlaub machten hab ich zu Hause gesessen und programmiert. Das war keine Entbehrung — das war genau das was ich wollte. Zuhause, Counter-Strike abends, tagsrueber Code. Kein Reisestress, kein Termindruck. Ich bin in diesem Sommer mehr vorangekommen als in jedem anderen Monat, weil kein einziger Tag verloren gegangen ist. Die Match Engine entstand in diesen Augustwochen.
Die Match Engine — das Herzstück und zwei Wochen Kalibrierung
Das Grundprinzip der Match Engine war frueh klar: 90 Minuten werden Minute fuer Minute simuliert. Jede Minute berechnet das System Ballbesitz, Druckphasen, Chancenkreation und Expected Goals (xG). Tore entstehen wenn ein xG-Wert einen Zufallsschwellenwert ueberschreitet. Der Zufallswert ist seeded und damit deterministisch — dasselbe Spiel mit denselben Inputs ergibt immer dasselbe Ergebnis. Das ist technisch wichtig: Es bedeutet dass man ein Spiel jederzeit reproduzieren kann, ohne jeden Zwischenzustand speichern zu muessen.
Die Kalibrierung hat zwei Wochen gedauert. Nicht weil das Grundprinzip schwierig gewesen waere, sondern weil ich echte statistische Zielwerte hatte: Durchschnittlich 2,7 Tore pro Spiel (Premier League Langzeitschnitt), 55% Heimsiegquote, das staerkere Team gewinnt in circa 68% der Begegnungen. Diese Werte kommen nicht von selbst. Jeder Tuning-Parameter hat Auswirkungen auf alle anderen. Ich hab Tausende von Testsaisons laufen lassen, Statistiken automatisch ausgewertet und Parameter angepasst.
Die finalen Werte: HomeAdvantageStrength 32.0 als Basiswert fuer den Heimvorteil, ShotBaseProbability 0.092 als Wahrscheinlichkeit dass aus einer Druckphase ein Schussversuch entsteht, FormSigma zwischen 0.04 und 0.14 je nach Spieler-Formkonstanz-Attribut fuer die Gauss-Verteilung der Tagesform. Dazu ein Energie-Decay der ab Minute 60 greift: Spieler werden in der zweiten Haelfte schwaecher, aber nicht linear — die Kurve haengt vom Ausdauer-Attribut ab. Ein Big-Game-Faktor fuer Pokalfinale und Entscheidungsspiele. Zusammen ergibt das ein System das sich nach echtem Fussball anfuehlt.
Spielplan-Generator und das Doppelrunden-Problem
Einen korrekten Doppelrunden-Spielplan zu generieren ist mathematisch nicht schwer — aber es gibt Randbedingungen die alle gleichzeitig erfuellt sein muessen: Jede Mannschaft spielt gegen jede andere genau zweimal, einmal heim und einmal auswaerts. Das Heimrecht muss ueber die Saison ausgeglichen sein. Keine Mannschaft darf mehr als zwei Heimspiele hintereinander haben. Die Abstands-Verteilung soll moeglichst gleichmaessig sein — kein Verein hat drei Wochen Pause und dann vier Spiele in zehn Tagen.
Ich hab den Generator zweimal umgebaut bis er in allen Faellen korrekt war. Die erste Version hatte einen subtilen Fehler bei ungeraden Vereinszahlen. Die zweite war korrekt aber zu langsam. Die dritte Version ist korrekt und erzeugt einen 34-Spieltage-Plan fuer 18 Mannschaften in unter einer Millisekunde. Der Pokal benutzt eine separate Auslosung die Ligazugehoerigkeit beruecksichtigt — kleinere Vereine treffen in fruehen Runden auf andere kleine Vereine, die grossen kommen spaeter ins Turnier.
September — der Sprint
September war der intensivste Einzelmonat des ganzen Projekts bis dahin. Vier Wochen, vier grosse Systeme.
Transfer-Screen mit Watchlist und Kompatibilitaets-Scoring. Das System berechnet nicht nur ob ein Spieler gut ist, sondern ob er in die eigene Taktik, auf die Altersstruktur des Kaders und ins Budget passt. Nicht “dieser Spieler hat 17 in Technik” sondern “dieser Spieler loest das konkrete Problem deiner Mannschaft”. Das erfordert dass das System weiss was das Problem ist — fehlende Taktische Intelligenz im Mittelfeld, zu geringe Ausdauer in der Abwehr, kein Freistoss-Spezialist. Das Scoring macht das transparent ohne den Spieler zu bevormunden.
Finanzsystem mit getrenntem Transfer- und Gehaltsbudget. Dynamische Stadioneinnahmen die von Vereinsreputation und Ergebnistrend abhaengen — ein Verein der drei Spiele in Folge verliert kriegt weniger Zuschauer, weniger Einnahmen, mehr Vorstandsdruck. Gehaltsstruktur mit Bonusklauseln (Meisterschaft, Pokalfinale, Torgrenzen). Eine Saisonprognose die zeigt wohin man finanziell steuert wenn man weiter so wirtschaftet.
Verletzungssystem mit drei Schweregraden: Leicht (1–3 Spieltage), Mittel (4–12 Spieltage), Schwer (13–30 Spieltage). Das Risiko haengt vom Verletzungsanfaelligkeit-Attribut, dem aktuellen Energielevel und der Spielintensitaet ab. Spieler mit 90 Minuten auf dem Ruecken und niedrigem Energielevel sind signifikant gefaehrdeter als frische Einwechselspieler — das schafft echte Rotations-Anreize die sich im Spielplan niederschlagen muessen.
Speichersystem mit mehreren Slots und automatischer Sicherung nach jedem Spieltag. Die Implementierung muss atomisch sein: Der Spielstand wird zuerst in eine temporaere Datei geschrieben und erst dann zur echten Slot-Datei umbenannt. Niemals ein halbgeschriebener Spielstand der beim naechsten Laden nicht gelesen werden kann.
Oktober — die kleinen Schlachten
Oktober war kein Monat mit einem grossen Feature. Es war ein Monat mit zwanzig kleinen Problemen die alle geloest werden mussten bevor das Spiel sich nach einem echten Spiel anfuehlte.
Der Post-Match-Analyse-Screen: xG-Verlauf ueber die 90 Minuten als Kurve. Tagesform beider Mannschaften. Energie-Kurven im Spielverlauf. Spieler-Einzelwertungen mit kurzem erklaerenden Text. Der Screen soll sich anfuehlen wie der Blick eines Trainers auf die Statistiken nach dem Abpfiff — nicht wie eine Datenbankabfrage.
Aufloesung-Profile fuer HD (1920×1080), WQHD (2560×1440) und 4K (3840×2160). ImGui mit absoluten Pixel-Koordinaten bedeutet dass jeder Abstand, jede Font-Groesse, jeder Component-Offset von der Aufloesung abhaengt. Ich hab ein LayoutResolver-System entwickelt das alle Masse von der Referenzaufloesung 2560×1440 auf die aktive skaliert — mit Ausnahme-Regeln fuer Dinge die nicht linear skalierbar sind. Spaeter wurde das zum vollstaendigen Design-System ausgebaut.
Das Chemie-System: Spieler die regelmaessig zusammen spielen entwickeln Verbindungen die ihre gemeinsame Leistung leicht verbessern. Das Designproblem: Wie verhindert man dass es zu einem simplen “kaufe moeglichst viele Spieler aus demselben Land”-Mechanismus wird? Loesung: Gemeinsame Spielzeit wird fuenfmal staerker gewichtet als Nationalitaet. Zwei Spieler die seit drei Saisons zusammen spielen haben mehr Chemie als zwei frische Neuzugaenge derselben Nation. Das macht Chemie zu einer Langzeitinvestition und belohnt Kaderkontinuitaet statt Shopping-Tourismus.
November — Audio, zwei Wochen Hoelle, und das ImGui-Styling
Audio. Ich hatte geschaetzt dass die Integration drei Tage dauert. Es wurden zwei Wochen.
Das Problem war nicht Audio an sich — das Problem war die Architektur. ImGui mit OpenGL in einem eigenen Render-Loop hat keinen natuerlichen Platz fuer Audio. In einer Game-Engine gibt es einen Game-Loop der jedes Frame Audio-Events verarbeitet. Ich habe keinen Game-Loop. Ich habe einen Render-Loop der Frames zeichnet. Ich musste NAudio einbinden, einen eigenen Audio-Thread aufbauen der unabhaengig vom Render-Loop laeuft, eine Thread-sichere Ereignis-Queue implementieren ueber die Spielereignisse (Tor, Abpfiff, Karte) an den Audio-Thread kommuniziert werden, und dabei sicherstellen dass Audio-Events nicht mit dem Rendering interferieren.
Der erste Test nach einer Woche: Crowd-Loop beim Spielstart. Er spielte — aber nicht synchron. Manchmal dreifach gleichzeitig weil der Loop-Trigger mehrfach ausgeloest wurde. Manchmal gar nicht weil der Thread noch nicht bereit war. Drei Tage nur fuer den Crowd-Loop. Dann Tor-Jubel: Korrekt, aber mit variablem Delay je nach CPU-Last. Nochmal drei Tage. Am Ende: Audio-Events werden mit Timestamp in die Queue geschrieben, der Audio-Thread verarbeitet sie in Order und puffert Loops mit Fade-In und Fade-Out. Kein Doppel-Trigger, kein unvorhersehbares Delay.
Das .tepk-Format (TaktikManager Extension Pack) kam gleichzeitig: Ein ZIP-Archiv mit manifest.json und Audio-Dateien. Vereinshymnen, eigene Crowd-Sounds, Kommentatoren-Clips — alles modbar von Anfang an und nicht als Nachgedanke spaeter.
Im November hab ich auch das ImGui-Styling systematisch angegangen. Ich hatte monatelang mit “funktioniert aber sieht nicht gut aus” gelebt. Jetzt: Farbpalette definiert mit sechs Hauptfarben in je drei Helligkeitsstufen, einem Akzent-Ton und zwei Warn-Toenen. Abstaende vereinheitlicht als vier Spacing-Tokens (XS/S/M/L). Hover-Zustaende fuer alle interaktiven Elemente. Typografie-Hierarchie mit drei Font-Groessen und zwei Weights. Jeder Pixel von Hand. Ich bin kein Designer. Aber es ist das Beste das ich alleine hinbekomme, und es ist sichtbar besser als vorher.
Ende November: Phase 2 abgeschlossen. Match Engine mit xG und deterministischem Seed, Kalibrierung auf reale Fussball-Statistiken, Spielplan-Generator fuer Liga und Pokal, Verletzungssystem, Speichersystem, Chemie-System, Finanzsystem, Transfer-Screen mit Kompatibilitaets-Scoring, Audio mit eigenem Thread und .tepk-Support, Post-Match-Analyse, drei Manager-Modi, HD/WQHD/4K-Profile. In Mai hatte ich ein schwarzes Fenster. In November hatte ich ein spielbares Spiel. Phase 3 beginnt. Die Tiefe kommt.