DevBlog #1: Random Fun
Published on October 21, 2024
Updated on October 24, 2024
Tags: System Shock 2, Game Design, Mod Development, DevBlog
Intro
After playing through System Shock 2 many times, I have become a little bored with the game. At this point, most of the encounters are predictable, and there are certain areas within some maps I don’t even bother visiting, because I know there’s nothing worthwhile there.
While the game is still quite fun on its own, I figured it would be nice to experience it again as if it was my first time - looking in every nook and cranny, being surprised by enemies around corners, being caught by ambushes, etc.
The First Version
Since the game is very moddable, I decided to try my hand at fixing this problem by creating a randomiser mod.
Initially, designing a mod like this seemed like it wouldn’t be particularly difficult. Many games already feature randomisation (including System Shock 2) through item tables. I started by writing a simple script to swap around all of the existing items in the map, including items in containers. This worked reasonably well, but also had some large problems. It also felt artificial, with many items being swapped in ways that weren’t immersive or that didn’t make sense within the context of the game world.
The Problems
Med/Sci is the first real map of System Shock 2. Your main objective is to gain access to the maintenance shaft, which requires finding a code. In order to find the code, you need to recharge a power-cell to gain access to the next map. Finally you need to come back to medsci1 to access the R&D section, where the code is located.
This introduces some problems for randomisation, because the Power Cell needs to be accessible before the R&D sector, and can’t appear in the final maintenance shaft section either, because access to these areas is restricted.
There were also a number of other issues:
- The player starts in the Cryogenics sector, which contains no enemies. It would be unbalanced to allow the player to find extra cyber modules, weapons, or other high-value goodies in this section before the main area of the map, so the items in the Cryogenics sector should be randomised amongst themselves only.
- System Shock 2 contains a lot of low value junk items - magazines, soda cans, mugs, etc. There’s also several items in the map which are trapped or difficult to access. For example, the Science sector contains a turret which must be destroyed or hacked in order to access the box of bullets behind it. If these bullets are randomised, it would be very disappointing for the player to find a mug there instead, so it’s important to distinguish between junk items and normal items. If new item locations are added, it’s also important to ensure something is always behind the turret.
- A Shotgun is available in the R&D sector. The R&D sector is normally accessed 10-20 minutes after the science sector. Finding this shotgun before R&D would overpower the player.
- Some containers (such as body bags) should only contain certain loot. Body Bags never contain anything other than nanites and hypos, so if we are randomising them, they should follow the same restrictions as the original game. Finding a shotgun or some cyber modules inside a body bag would feel very strange.
- There are various security crates scattered around the map. Some of these contain very valuable items, and having them available in the general item pool might cause some imbalance. Additionally, it’s important that they always contain valuable items rather than junk, and can’t contain quest items.
The Second Version
In order to resolve these problems, maps needed to be split into sections. For each section, an “object pool” was created, which contains a list of all the objects in that part of the map. Object pools were also created for other special collections of items, such as the security crates, keeping them separate from the other items located around the map and allowing them to be randmoised separately. Randomisers were updated to randomise objects within a collection of object pools, and could also be restricted to certain types of items, or even specific items.
By allowing randomisers to use specific object pools, the locations of items could be restricted to any part of the map.
After the changes, 6 Randomisers were created for the different areas of the level:
- A Randomiser was created for the Cryogenics sector, using the Cryogenics sector object pool. This swaps all the items around in the Cryogenics sector.
- A Randomiser was created for the Science Sector weapons, using the Science Sector object pool. This allows the weapons in the Science sector to only appear in the Science sector.
- A Randomiser was created for the R&D Sector weapons, using the R&D Sector object pool. This allows the weapons in the R&D sector (most importantly, the shotgun) to only appear in the R&D sector.
- A Randomiser was created for the Power Cell, using the Science Sector object pool. This restricts the Power Cell to only appear in the Science sector.
- A Randomiser was created for the general items in the map. This uses the object pools for the Science, R&D and Maintenance sectors. This randomises everything not handled by the other randomisers and allows them to appear anywhere within the map, except for the Cryogenics sector.
- A Randomiser was created for the High Security Crates within the map, which randomises items between the different crates only. This ensures a random distribution for high-security items, but prevents them from containing any of the standard items from the general map pool.
Additionally, a number of MetaProperties were created, which serve as flags telling randomisers what to do. These can then be attached to any object, controlling how they function as inputs or outputs for randomisers. Here are some examples of how they are used:
- The box of bullets behind the turret in the science sector had the
Object Randomiser - High Priority Output
metaproperty added. This ensures that something will always spawn in that particular location, and will always be something valuable, never a junk item. - It also had the
Object Randomiser - Secret
metaproperty added, which prevents plot related items (in this case, the power cell) from appearing in that location, as it would be unfair otherwise. - The Body Bags were given the
Object Randomiser - Hypo Output
metaproperty, which restricts them to only containing hypos.
A series of markers were also created and added to the object pools, serving as new potential locations for items to randomise to.
With these changes this implementation worked quite well and was able to solve most of the problems with item distribution throughout all of the levels within the game. With careful use of metaproperties to handle some special cases, the item distribution felt fresh and interesting with nothing feeling out of place, as if the developers had hand placed everything in new locations.
Further Improvements
The first version worked quite well, but there were a few more enhancements that were needed to really round-out the experience.
Firstly, support was added for randomising enemies. Unlike items, enemies are rolled on a table rather than being swapped around. This allows enemies from previous decks to appear even if they never appeared in the vanilla game (such as having grenade hybrids appear on the command deck) while still maintaining the overall enemy distribution and difficulty.
Bots, Turrets and regular enemies all needed to be swapped as groups, requiring 3 extra randomisers per map. Otherwise extremely large enemies such as Assault Bots might appear in more cramped spaces designed for smaller enemies.
Additionally, some new metaproperties were added. Object Randomiser - Ranged
Enemies Only
was created to specify which locations should only allow ranged
enemies - such as ledges, high areas, and behind barriers. Object Randomiser -
Patrol
was also created to allow some spawned enemies to walk around the map
automatically rather than standing in place. A series of metaproperties were
also created to allow enemies to be rolled together, spawning multiple of the
same enemy type. This was used for groups of turrets to ensure they are all the
same time, as well as certain ambushes or traps where it makes sense to be
attacked by multiples of the same enemy type.
Overall, the result was very effective. Ranged enemies generally appear in spots where it makes sense, such as high ledges, and most enemy encounters feel fresh and interesting.
Conclusion
Creating the Randomiser has been a very long but rewarding journey. While it ended up being significantly more complicated than anticipated, with a lot more edge cases that have needed to be accounted for, the result speaks for itself. It’s been a huge amount of work, but I feel like it has achieved it’s goal of recapturing the original feeling of playing the game for the first time. Making a randomiser that feels good to play is a lot more work than the simple version, but has also resulted in a significantly better experience overall.