Retro Game Internals: Contra Random Enemies

Random Enemy Spawns

In addition to the enemies that are specifically set up to spawn at certain places in a level, there are also enemies that appear somewhat randomly. These enemies are the running soldiers that are spawned every so often at the edges of the screen as you play through the game. The system that manages these randomly spawned enemies is surprisingly complex given the seemingly simple job it has to do. You can see in the image below the enemies we’re talking about in this post. All of the running soldiers on this screen have been randomly spawned while the player was standing still.

rand_spawn

The heart of the random spawning system is a timer that counts down from some initial value to zero over and over. Each time it reaches zero, there is a chance for an enemy to spawn. Each level has a certain interval that the timer uses and some levels disable random enemy spawns by specifying an interval of zero (the base levels and the final level for example.) There are 2 modifications that are applied on top of the default interval specified by the level to arrive at the final interval that will be used . First, the interval is reduced by roughly 20% for each time that you’ve finished the game. This means that after the game kicks you back to the first level after you beat it, the random enemies spawn more frequently, and even more so if you play all the way through again and again. The other factor that reduces the timer interval is which gun you currently have. Guns are classified according to how good the game considers them to be with P being the worst, F being better, M and L sharing the next best rating and S (of course) being the best. The random spawn timer’s interval will be reduced by about 3% for each rating point (0-3) that your current gun has. The image above is from a 4th play through of the game while the player has the spread gun – the screen shot doesn’t do justice to the amount of guys constantly running onto the screen.

The rate at which the timer counts down is also variable depending on whether or not the screen is currently scrolling forward. If the countdown rate were 1.0 when you are standing still, it would be 0.75 when you are running forward. This has the effect of generating fewer random spawns while you’re moving.  I guess the developers wanted to compensate for the fact that you’ll also be running into the non-randomly spawned enemies while scrolling.

When the timer reaches zero, there is a chance for spawning to happen. Which side of the screen the enemy will come from is usually completely random. The one specific exception is when you are in the first level, and you are in your first play through of the game, and there have been fewer than 30 enemies randomly spawned on the current screen, then the enemies will always spawn on the right side of the screen. This makes it a little easier for brand new players who are just starting out. The Y position for the new enemy to spawn at is chosen in 1 of 3 different ways depending on how many frames have gone by since the game started. One quarter of the time the game looks for a platform to spawn on starting at the top of the screen and searching down. One quarter of the time it starts at the bottom of the screen and searches up. The other half of the time, the game tries to use a random player’s current Y position as the starting Y position for an upward search. There is actually a bug in this logic however that causes the search to start at the very top of the screen half of the time if there is only 1 player alive in the game. This bug doesn’t really harm anything though since the only effect might be that a randomly spawned enemy appears on a lower part of the screen than it should have.

Once a candidate position to spawn an enemy at is found, there are a few more checks to see if spawning should happen. If the candidate position is too close to the top or bottom of the screen then the spawn is rejected (unless you’re in the waterfall level where spawns are allowed to be close to the top of the screen.) If you’re on the very first screen of any level, then the spawn is rejected. Another hard coded test is if you’re on the last few screens of the snowfield level, then spawns from the left side of the screen are always rejected. This test kicks in when you get to the very last snowy platform of the level with the trees at the bottom, bombs being tossed out at you and the 1 guy shooting the stationary gun at you. Why such a specific test is in the game is anyone’s guess. Maybe one of the developers thought it was too hard to deal with so many threats at once (although almost the exact same situation happens at the very beginning of the level and spawns from the left are allowed there.)

One other hard coded test is there to make things a little easier on your first time through the game. If there have been fewer than 30 randomly spawned enemies on the current screen, and you are on your first play through, and a player is standing too close to the side of the screen that an enemy is about to spawn from, then the spawn is rejected. This prevents cheap deaths from enemies randomly spawning right on top of you.

If all of these tests have passed, there is still one more thing that needs to be checked before an enemy can actually spawn. Every single screen in the game has a unique value associated with it that controls various aspects of the randomly spawned enemies on that screen. One thing that an individual screen can control is an extra chance that any given spawn will be rejected. Screens can either always allow spawns, always reject spawns, randomly reject spawns 50% of the time, or randomly reject spawns 75% of the time. If this final test passes then it’s finally time to spawn something.

There are 2 different kinds of spawns that can happen once the game decides that it wants to spawn something. If you are not in the waterfall level, and the screen is currently scrolling, then you have a 25% chance to spawn a group of 3 running soldiers. These soldiers are always configured to never shoot bullets at you. In what might be another bug or might have been on purpose, the game uses what is effectively uninitialized memory to configure the behavior of each of the soldiers with respect to what they do when they hit the edge of the platform that they’re running on (whether they always jump off or if they’re allowed to turn around.) If this was a bug instead of just trying to get random looking behavior then it is again a pretty minor one.

The other kind of spawn that you get if the conditions for the first kind aren’t met is a single running soldier that gets configured slightly differently. In this case, the normal random number generator is used to randomly configure the jumping behavior of the soldier. These soldiers are also assigned a shooting behavior based on another screen specific value. The idea behind this process was that each screen selects one of a small number of pre-made groups of behaviors with each group having a different mix of non-shooting, high shooting and low shooting behaviors. Then, the specific shooting behavior of each soldier that is spawned is picked at random from within the group that the screen selects. However, there is another bug in the game where one specific screen in the hangar level specifies the 8th behavior group when only 7 behavior groups exist. This causes the game to assign soldiers on that screen a garbage behavior value (the actual value comes from part of the pointers to the screen enemy lists that we’ve talked about before) resulting in various non-fatal side effects that mostly result in the soldiers instantly turning around and running off the screen.

Up Next

Who knew spawning some random enemies was so complicated? The next post will cover the final piece of the enemy spawning puzzle which is how enemies work in the “base” levels of the game. As always, feedback is welcome @allan_blomquist or comment below.

(Prev – This is part 3 of a 7 part series – Next)

3 Responses to “Retro Game Internals: Contra Random Enemies”

  1. puggsoy says:

    Interesting as always! Deciding shooting behaviour based on the screen’s random rejection value seems a bit of a strange way to do it, but I suppose it saves space.
    Also, I haven’t played Contra, but even so it’s nice to know that the developers were thoughtful enough to modify the spawning depending on your experience and weapon.

    • Allan Blomquist says:

      The bits that are used to randomly reject spawns and the bits that are used to configure shooting behavior are all packed into the same byte of data, but logically they are 2 distinct values. I’ve updated the text to better express the logic instead of the implementation. Thanks for pointing that out!

  2. Horrorgoose says:

    Hello Tomorrow Corporation,

    Can I make a Video about little Inferno for youtube?
    It will be in german and I will show the little Inferno song there.

    Horrorgoose

Leave a Reply