There are great football manager games out there. Especially for the German market: Anstoss shaped a generation. Football Manager remains the gold standard to this day. But that's not what this is about.
Instead, at some point, I became fascinated by the question of how far I could go myself. With my experience as a player and a developer, using Python as a tool and leveraging today's technical possibilities. Not as a clone and not as a "better version" of something else, but as its own project.
The project currently carries the working title Joni Fussballmanager. The game is still under development and is currently running on my machine.
The first moment that changed everything
In every project, there is that one moment where you stop just building an architecture and start actually playing something. For Joni Fussballmanager, that was the evening when, following a penalty, the first ticker entry appeared on the screen.
45+2' → SUBSTITUTION: Player A for Player B (Home Team)
47' → YELLOW CARD: Defender (Home Team) – Foul
56' → GOAL! Center Forward (Home Team) – Shot into the near corner – 1:0
For over an hour, I had been working on event distribution, rewiring the match engine, and fixing timing bugs. And then, numbers ran through a formula, the attributes of two players were compared, a probability was drawn—and a goal appeared in the ticker. Not as debug output, but as an event that actually mattered in the game.
Even so, for me, that was just an intermediate step. The first versions still ran in the terminal, almost like the late 80s or early 90s. The fact that it eventually became a game with a complete graphical user interface was a true milestone for me personally.
Why Python for a football manager game?
The obvious answer would probably be "Godot" or "Unity." But quite honestly: that would exceed my skill set. For a side project, it would simply be too large and too complex, and I probably wouldn't be able to pull it off in that form. Furthermore, for me, a manager game isn't a real-time or action game, but essentially a data-driven application with a complex interface, a lot of state logic, and a multitude of rules. There is no need to render images at 60 fps here. It doesn't require a physics engine or shaders.
What a football manager needs instead: a good UI library, clean data storage, and clearly structured domain logic. That is exactly where PyQt6 shines. SQLite is more than sufficient for such a project. And Python allows me to develop quickly, refactor things, and keep the logic readable.
What has been confirmed in practice: the codebase is large, but manageable. New features emerge without endless build chains. Debugging remains manageable. The game runs cross-platform.
A look behind the scenes: The following sections provide insight into how the game works and its technical structure.
The Two-Database System: Football and your career
Perhaps the most important architectural decision in the entire project—and one that you don't directly see while playing, but which influences practically everything.
master.db is read-only. It contains several national and international leagues and other competitions. It also includes clubs, players, stadiums, formation rules, and historical legends. This file is never modified.
Every save game has its own SQLite file. This contains league tables, transfers, finances, player form, results, and the archive of your own career.
What this means in practice: the game can be restarted at any time without corrupting the base data. Multiple save games can run in parallel. And if you want to delete a save game, you just delete one single file. The core data remains untouched.
This also brings clarity to the code: queries against master.db are always read-only, while queries against the save game file are allowed to write. An accidental UPDATE on the base data is practically impossible.
The Match Engine: Minutes, probabilities, and that one penalty
This is technically the most demanding part of the project. And at the same time, the one that is the most fun.
A match runs on a tick-based system: 90 simulated minutes, and in every minute, it is recalculated what happens. Events such as shots, goals, fouls, cards, injuries, or corners have probabilities that depend on player attributes. The formation plays a role too. Tactical instructions shift the weights. A good striker in the right system gets more chances to finish. A team with a high pressing value disrupts the opponent's buildup more effectively.
The result is a live ticker. Events appear line by line, similar to a live ticker on a smartphone—except here, you are the manager who set the lineup.
In parallel, all other matches of the matchday continue to run. On the right side of the window, the live table builds up in real-time. If a competitor scores, my position worsens. If I am leading and the pursuer only draws, my lead grows.
The Matchday View: Drag, drop, your layout
A feature that I underestimated for a long time—and one that massively changed the feel of the game.
The Matchday View was rebuilt from a simple QWidget to a QMainWindow to utilize Qt's native docking system. This means: all panels surrounding the ticker are their own dock widgets. Lineup, statistics, parallel matches, live table, match info—everything can be freely positioned via drag & drop. Each window can be collapsed individually, and the layout is saved automatically.
If you don't want to see the lineup, you collapse it. If you always want the live table in the top right, you just drag it there once—and the next time you open it, everything is back in its place.
This might sound like a small technical convenience feature. But it isn't. Once you have set up your own Matchday layout, you quickly realize that the game adapts to the player—not the other way around.
The Lifeblood of the Club: Financial System
No financial system, no real football manager. Period. The financial system in Joni Fussballmanager covers the most important income and expenses. TV money flows in depending on the league position. Gate receipts depend on stadium capacity and sporting attractiveness. Sponsorship deals must be negotiated. Transfers cost transfer fees and impact the wage budget. The youth academy, scouting, and amateur departments incur ongoing costs.
Since the last major update, there is an Investment Budget System. During onboarding at the start of a career, you decide how much should flow into specific areas each year: youth academy, amateur sector, scouting, talent development. These amounts are not deducted as a one-time fee, but are automatically accounted for week by week. This creates a much more realistic cash flow. AI clubs operate with plausible standard investments based on their wage budget and reputation.
The result: financial pressure is palpable. If you spend too much, you will have no transfer budget left later. If you invest in the youth, you don't see the effect immediately, but often only in later seasons.
The Legend System: Cards in the cabinet
Every club has historical legends—famous club legends from different eras and leagues. Instead of simply inserting them as fixed special players, the Legend System has its own mechanic: collectible cards.
Packs are unlocked throughout the career. Upon opening them, you receive legend cards in various rarity levels. If you are unlucky but keep collecting persistently, a pity system ensures you eventually get rare cards. If you possess enough tokens, you can specifically craft cards. Legends can then be added to the squad—but deliberately only within a limited framework per season, so that the team doesn't become completely overpowered.
AI-controlled clubs and the Press Service
All clubs not controlled by the player act independently. This affects not only the match simulation but also the transfer market: AI clubs have their own budgets, their own preferences, and independently make offers for players on the transfer list.
This is exactly what makes the market feel alive. Something is happening, even when you aren't doing anything. After every matchday, another AI element is added: the Press Service. Match reports are generated locally via Ollama, meaning without a cloud API. The course of play, key moments, and the result serve as context from which the model formulates a short match report.
Over a season, this creates your own archive: fictional press reports about the course, highlights, and setbacks of your own career. The 3:1 victory against a major rival that opens up a title race. The unexpected defeat that suddenly brings a different mood to the report. It's not a core system—but it's one that gives the game significantly more atmosphere.
Players age. Players become legends.
A feature that I originally intended for later project phases—but which was built too early because it was simply too important.
With Anstoss 3, I was always a little sad when a magnificent player ended their career. I didn't want that feeling to simply vanish in my own manager. Deserving players should be given a special place and not just quietly disappear from the system.
Players age over the seasons. From a certain age, performance levels slowly decline, attributes deteriorate, and eventually, retirement comes. If a player meets certain criteria—many appearances, important goals, titles with a club—they are classified as a club legend after their career ends.
This has no immediate gameplay impact. But when a player retires and the game honors this departure as a true club moment, it does something to the overall picture. It gives the career more weight.
What I have learned
The balance in the transfer market was harder than I initially thought. If the AI acts too aggressively, the market quickly becomes frustrating. If it is too cautious, too little happens. In the end, no theory helps; only playing, observing, and fine-tuning repeatedly.
A clear separation of domain logic and UI pays off even in games. Especially with a manager featuring many systems, it makes a huge difference whether new functions emerge within clean game logic or end up directly in widget classes. This separation keeps the code testable, understandable, and extensible.
What is happening right now
The game is playable, but it is still quite a long way from a truly finished state. So far, I haven't managed to implement a full season transition. I repeatedly encounter bugs, inconsistencies, and things I need to re-test.
This is also because I am the developer and the tester in one person. The game has grown steadily over time, and many systems had to be built in relatively early because it would have been significantly more complex to integrate such profound features cleanly later on. And of course, I am no magician like the developers of the great football manager classics, who built magnificent games on technically much more limited hardware before the turn of the millennium.
Precisely because of this, a large part of the work consists not just of building new things, but also of checking, refining, and re-testing. That is how this project continues to grow, step by step.
I hope that I don't run out of stamina and that the project doesn't fizzle out in the end. Far too many hours, weeks, and months have already been poured into it.