How the Car Limit in Need for Speed: High Stakes Was Expanded
For a long time, one of the most annoying limitations of Need for Speed: High Stakes was its car limit.
The game allowed roughly fifty drivable cars. One slot was effectively reserved for the Knockout Truck, which could not simply be replaced with a regular custom car.
At first glance, this looked like a fundamental limitation.
It was reasonable to assume that the entire game engine had been designed around roughly 50 cars and that significantly increasing this number would require reworking a huge part of the game.
The investigation showed that the situation was much more interesting.
The Limit Wasn't Quite as Fundamental as It Seemed
The game itself can find and load a list of car files without a hard limit of 50 entries. The problems begin later.
Inside NFS4 there are several tables containing information about loaded cars, their names, colors, availability, and other parameters. Many of these tables were designed for 50 cars.
This created a rather interesting situation. The game could discover an additional car, but after that it simply had no prepared space for it. Even the 51st car could cause the game to access data beyond the bounds of those tables and crash.
That was actually good news. The limitation was primarily caused by the sizes of internal structures rather than by some fundamental limitation of the engine itself.
Traffic, police cars, and the helicopter are also handled separately. They did not have to be moved into the new space for regular cars. So expanding the custom car list does not take slots away from traffic or police cars (well, at least I hope so).
The First Steps Beyond 50 Cars
The first practical goal was not to jump straight to hundreds of cars, but simply to make the game reliably cross the old limit.
An intermediate version supporting 64 cars was created. The main tables were expanded, and the parts of the game that treated 49 or 50 as the maximum index were adapted to the new range.
This is where the most difficult part of the work began.
Running the game for real quickly showed that simply making the tables larger was not enough.
For example, after changing the way the car lists were built, the Knockout Truck unexpectedly became available for purchase.
In the original game it serves a special purpose and is not supposed to behave like a normal showroom car.
Trying to handle it as a purchasable car resulted in corrupted garage data and eventually caused the game to crash.
The original logic excluding serial 33 therefore had to be restored separately, while still allowing the game to continue processing cars located after it in the list.
A similar problem appeared in the showroom. It turned out that different parts of the interface use slightly different car lists. Fixing one list did not necessarily mean that the special car disappeared from every other screen.
Problems like these were gradually discovered during real game testing and fixed one by one.
The Garage Turned Out to Have Its Own Limit
The next major obstacle was the garage.
Even if the game could load more cars, the internal structures used by the garage menu were still designed for roughly 50 cars (51, to be more precise). So expanding only the model catalog was not enough.
The garage was expanded separately. Its current capacity is 512 entries. The data used for names, car ordering, colors, serial numbers, and menu items was expanded as well.
Although later I started thinking that having more than 50 cars in the garage probably isn't really necessary anyway :)
Interestingly, the save data format itself can potentially hold more records. At the moment, the practical limitation is the new 512-car capacity of the garage interface.
The Name Problem
Once the game had more than 50 cars, another feature of the original game became apparent. Although I already knew about it before, because for certain string ID ranges the game dynamically constructs strings instead of simply retrieving them from TEXT.ENG or the other translation files.
Car names were effectively tied to the old range as well.
Cars with indices above 49 appeared in the shop without proper names. The problem was not in the car files themselves, but in the mechanism the game uses to obtain car names.
The naming system was therefore expanded so that additional cars could use their actual names. At the same time, the model index had to be separated from the car's serial number. With the original set of cars, some of the game's old assumptions happened to work almost by accident, but with a large number of installed cars they were no longer reliable.
Serial Numbers Turned Out to Be More Complicated Than Model Indices
This became one of the most important problems in the entire expansion.
In the original game, car serial numbers were used in many places as a convenient way to find the corresponding model. With a small, predefined set of cars, that was sufficient.
With hundreds of custom cars, things become more complicated. Mods can contain duplicate serial numbers, zero values, and numbers that can no longer safely be treated as car indices.
Serial number handling was therefore substantially reworked. The current version stores data for 512 models and can detect zero or duplicate values, assigning available numbers in their place. The main change is that a serial number should no longer be implicitly treated as a model index.
This is especially important for the career, garage, shop, and other parts of the game where the same car can pass through several different systems.
The AI Had Its Own Limit Too
After expanding the regular car list, another hidden limitation was discovered. The game builds internal sets of cars for a race according to the restrictions specified for that race, and then uses those sets when selecting opponents and different car variants.
These structures were also designed for a relatively small number of cars.
In the current version they have been expanded to 512 models. The space used for the combined variant list has also been increased. This should make it possible to create mod setups where a single class contains far more cars than the developers of the original game ever expected.
However, this part still needs serious testing. It is necessary to test not just a few dozen cars, but deliberately place a very large number of them into a single class. A preliminary test with 200+ F50s seems to suggest that it works.
The Career Had a Separate Problem
Career mode turned out to be another place where the old assumptions about the number of cars did not become apparent immediately.
The game stores information about possible opponents in a fairly compact form. Once the catalog was expanded to hundreds of cars, the old method of representing a model index was no longer sufficient.
The format of the internal opponent list was expanded so that it can correctly represent model indices from 0 to 511. At the same time, the additional information describing the car variant and its characteristics had to be preserved.
At the code level, this problem has already been addressed. What remains is to test the boundary cases in the actual game, especially cars with indices around 255, 256, and 511, as well as large, completely filled opponent pools.
Car Colors and Resources
After the first successful tests with cars beyond the old limit, another set of problems appeared that no longer looked like simple limit overflows.
Additional cars could receive incorrect or gray colors. The reason was that the original game treated certain high indices as special models, such as traffic vehicles.
Installed drivable cars now go through the normal path for loading their models, textures, and colors regardless of whether they are near the beginning of the list or far beyond the original limit.
Several situations were also fixed where a corrupted or missing resource reference could crash the garage. Instead of blindly accessing invalid data, such cases are now handled more safely (whether they are handled correctly is another question...).
Engine Sound
The expansion also affected sound.
The engine sound banks themselves are still loaded from each individual car's car.viv. So adding hundreds of models does not mean that all of them have to use the same engine sound.
There are separate volume tables as well. These were also designed around the original set of cars and have now been expanded to 512 entries. The original cars retain the values from the game's original tables, while additional cars currently use fixed values: 100 for the player's car and 50 for AI cars. There is still something to think about here: should these values eventually be stored in car.viv, or is a fixed value good enough?
There is one known boundary case. Serial numbers 512 and above are outside this table and use a fallback value instead. So working with such serial numbers cannot yet be considered fully supported.
Will 512 Cars Affect Performance?
At first I had the impression that performance had dropped, and at one point I was also seeing visual artifacts in the 3D graphics.
It may have been related to one particular car, the "Mercedes SL30". After removing it, I haven't seen those artifacts again, but this still needs independent verification.
There was also another concern: could the game start scanning the entire car catalog every frame?
Checking the rendering path showed that this does not happen.
During a race, the engine processes only the list of cars actually participating in the current race. The complete catalog of installed models is not scanned again every frame. Most of the additional work associated with the larger catalog happens during loading and preparation.
That is a good result, although any final conclusions about performance will still require practical testing with large races.
From 49 to 512
At this point, the result already goes far beyond the original goal.
Instead of the original limit of roughly 49 drivable cars, the game now has infrastructure prepared for 512 models. The garage has been expanded to the same capacity. The model, name, and color tables have been reworked, along with serial number handling, AI car variant selection, career opponent pools, and engine volume tables.
Along the way, problems involving the shop, the Knockout Truck, incorrect serial numbers, empty names, colors, resource loading, and several causes of garage crashes were discovered and fixed. The known problems that appeared after crossing the old 50-car boundary now have corresponding fixes.
But there is an important distinction to make here.
The game has been prepared to work with a catalog of up to 512 models. That does not mean that a complete gameplay session with 512 actually installed cars has already been tested. In practice, I have only tested around 70 different real car mods plus about 250 copies of the Ferrari F50.
What Still Needs to Be Tested
The main remaining task is stress testing.
I need to build a car list that actually approaches the 512-model limit and take those cars through the normal lifecycle in the game. They need to appear correctly in the menus, be purchased, sold, saved, loaded, and used in races. Ideally, I would also like to complete an entire career with the expanded car list, since the way the AI selects cars for races is one of the areas I am still somewhat concerned about.
The additional cars and extreme serial number cases also need proper sound testing. Normal traffic, all police cars, Pursuit and High Stakes modes, and helicopter scenes need to be tested again as well. Although these models use separate spaces and do not consume any of the new 512 slots, some of the shared code has now been modified.
Another major area that needs testing is replays and multiplayer. I need to make sure that expanded car indices are handled correctly when saving replays and exchanging data over the network, and that races using additional cars can be restarted or continued normally.
For multiplayer, I already know about one limitation. The network protocol allocates only one byte for a car's serial number, which means a maximum value of 255. Anything above that will not work correctly.
Expanding the protocol should not be particularly difficult, and that is the next task needed to make the patch complete.
Comments
No comments yet.
Log in to leave a comment and rate. Log in