Topic updated: 2022-05-05The first episode of my serie about retro-engineering on old 90's video games. Today let's talk about the famous Ultimate Soccer Manager 98.
The first episode of my series about retro-engineering on old 90's video games.
What it is exactly? It is trying to analyze the compiled code of old games (around 20 years old) in order to patch them (changing behaviors or correcting bugs) or to try to find traces of uncompleted features or even hidden ones!
There are also others important ideas behind this hobby...
Today let's talk about the famous Ultimate Soccer Manager 98.
USM98 was released in... 1998. It is the third episode of the USM series and the last one (I don't count the extension released in 1999).
The game put you in the role of a football (soccer) team coach or manager. You have to deal with a lot of aspects of the game like transferring payers, managing budget, communication and merchandising.
I got the second opus (the 96-97 one) on Christmas 1997 and spent countless hours on it, despite being frustrated by a lot of flaws. But when you were a twelve-years-old soccer fan with a lot of imagination (as any kid), this game was made for you. Then, when I played the demo of the 98 version in late 98, I was stunned. I finally bought it at the end of 1999. Since then, I play this game at least one time (I mean a full career) a year.
Like many of my old 90's games, I run it on my 2011 iMac (or my 2012 MacBook Pro), both with Intel processors. I run the game in VMware, itself running Windows 98. It works like a charm. You can also run it with the excellent PCem.
While playing this game for many years, I was still frustrated by some limitations or inaccuracies, like these ones:
For more details, a full list of these issues is here.
Being a software developer, the idea came to me the first time at the end of the 2000's. I thought "It would be so cool if I could have the source code to patch the game!". However, I didn't think about it that much. Then, in 2014, this idea came back, and for a few weeks it became an obsession. This is when I put down a list of all the things I would like to change in the game. I tried to imagine ways how I could work: I first contacted the lead developer of the game (who was kind to answer me) to get some thoughts, but it was not helping (at first, because the answer encouraged me to go further). I stopped thinking about it for a while, but the idea came back two years later, and this time I contacted the company owning the rights of the game (Activision-Blizzard) to ask if I could get the source code. The answer was no, as expected. Small parenthesis: if you have ever wondered why so few companies release the source code of old games, here are a few elements:
So, I was still in a dead-end. But this time, I was not discouraged, and I decided to make a side project of it. In late 2016, I was ready to spend time on it, without any idea of how to starts (it was the first time I was trying to do that), or whithout even any hope of success!
I looked for days on the Internet to look for tools to help me for retro-engineering. I selected two of them:
The last one was the core of the work. It is an interactive disassembler: instead of just converting the bytes to assembly language, it also generates call graphs, string inventories and more. I would say it help you to create a map of the battlefield.
Then, I decided to use the English version of the 98-99 version of the game (not the 98 one with the extension, I used the standalone one released in 1999). This is why:
Then I started to work. Things were clear on my mind: if I had a list of many things I would like to change, the first one was to be able to prevent to be fired in the game. For this, the string inventory of the game was of immediate help. I was so focused on this specific task that I didn't go through the whole list of strings, I went directly to the one displayed when your chairman fire you. This is what IDA shows after an analysis of the executable and you find what you are looking for:
Then, the brain work starts. In a few words, you have to look when this string is used and try to understand the logic of the code. Just a side note, when I started to work on it in 2016, it has been 12 years since the last time I worked on assembly language, when I was in first year of my IT studies. So, you can imagine how funny and hard it was for me to go back to that!
So, I spent a lot of hours to try to figure out what was the logic. And after reading a lot about the matter and trying to have some imagination, I found that there are four levels to workaround a given behavior in an application when you don't have the source code*:
*Note that it is how people with bad intentions work... I do it only on two decades old video games, only for education or patch purpose, never to bypass security or "crack" the game. If you do it on something new, that you just bought, with bad ideas, you expose yourself to serious legal issues!
I decided to work with the two first ones, not having the skills the use the last one while the third one was, I think, inappropriate. Changing values of the variables was easy and straightforward, but inversing some logical conditions needed to find a table of the main x86 Intel processors conditions. I found it here and was able to do some trials, like for instance replace a 74 instruction by its opposite, the 75.
So, in a few words, after a loooot of hours, I was however stuck: impossible to get what I wanted to do. In this situation, like in my work, the recommended way to proceed is to focus on other issues and come back to this one later. This is what I did. I spent again many and many hours and was able to get small first successes at first, and biggers after some times, able to change some behaviors on my list, then sharing the results of my discoveries with the members of the Facebook page dedicated to the game.
Those small and medium successes were a reward for the many dozens of hours spent on it, not to mention the interest showed by other players of this game. It encouraged me to continue, so far four important things on my list were missing:
While working - with success - on the third point mentioned on the previous list, I found this:
It doesn't need so much comment. I just would like to say that it was a great moment, because:
Enabling the access to this screen was quite easy, I just changed on logical behavior. However, I don't know how to "properly" enable if (if there is any way to do it).
Seeing how sharing my early work made some other players enthusiasts, I decided to continue to do it:
Seeing how people reacted for this old game was great and rewarding, we were hundreds to still play it. Some of these persons provided tutorials and content for the website. Some other joined the adventure and started to try to patch it too, this is how we got:
Despite all these huge achievements, one thing was still missing, you guess it, the fact that you cannot disable that you can be fired. I had to call for some help, and finally I paid a Lithuanian developer (thanks again) with great skills. Not only he found the solution but he also helped me a lot to understand how to assess some problems.
When I decided to develop the "Tweaker" (the small app to patch the game), I just thought to share it. Finally, remembering that we are not eternal and anything can happen, I also put the source code on Github. It is messy, has no quality gate or anything, is given "as is", but at least is documented and open-source.
In early 2018, as I was finalizing this stuff, I found out in the string panel of IDA some weird labels I had never see in the games, like the one referring to the French National division and the Italian C1 serie. One of the small disappointing aspect of the 98 version of USM is that it had less divisions than the previous version. For instance, on the French side, you could only play in the Division 1 and Division 2 levels while in the 96-97 version of USM you could also play in the third level named National. The discovery of these string may me wonder if at some point the presence of these divisions were planned but the deadline made that they were never incorporated, or because of some license negotiation issues.
Anyway, the good point to find these unused strings, is that I was able to rename some competitions. For instance, on the French and English championshios, or on the European cup's, names have changed since the release of the game. Finding unused strings helped me: by changing their content and modifying the memory calls I could rename some tournaments. It was previsouly impossible because the French and English divisions shared the same name in 1997, while no longer the case in 2018. Finding these string gave me more opporutunities: without that, renaming one would also rename the other!
While working on labels, I also added a feature to the tweaker allowing the user to rename some of them, for instance Sierratext could become SmartTV or Telephone could become iPhone, making them more "modern". This is what the tweaker looks like in its last version:
After a break from mid-2018 to early 2021, I started to work on this game again. I was no longer working on the patch, but on a texture editor. The first release was permit to export the addboards (the sponsors we used to see in 1997 are not always the same today) to a BMP file and then to be able to reimport them in the game after update. Thanks to the help of a member of the community who, years ago, had mapped the colors of the game and understood how adboards were stored, I just developed this import-export tool, and you can see my custom work on the below screenshot:
But then, I dug-up something I started in summer 2018 (in fact, it was where I stopped back then): I wanted to be able to edit some textures, and to be more accurate, to start with the pitch. This time, it took me countless hours to, without no more help than a hexadecimal editor and a lot of patience, to understand the compression mechanism and to add this feature to my import-export tools. I released this feature in mid-2021.
This time, the source code is clean and checked against a CI (linter and unit tests). It is available here.
I still have work to do, like now I would like to be able to edit the goals nets. I started to work it, but it need a lot of analysis and I stopped... until next time.