Demon speed bug


Demon speed bug demonstration

The demon speed bug is an oversight in the interaction of the Nightmare! skill level (or -fast parameter) and the savegame loading code. It can result in extremely slow demons that seem frozen in place, or in extremely fast demons that will freeze the entire game.


The demon has the duration of its states (other than spawn/idle, death and resurrection sequence) halved in nightmare mode. This makes it all-around faster and more aggressive, since it will move and attack twice as often in the same duration.

This effect is obtained by overwriting the state table in memory, halving the duration of each concerned state when starting a nightmare game. When the player starts a new game while the game is already running, the code checks to see if it should change the demon's state duration by comparing the new game's skill level to the current game's skill level (which is stored in the gameskill variable). If the current game is Nightmare and the new game is not, the game doubles the state duration to slow the demons down; if the current game is not Nightmare and the new game is Nightmare, the game halves the state durations to speed the demons up.

The bug arises from the fact that when a savegame is loaded, the gameskill variable is overwritten with the value of the saved skill level before the check to see if the state lengths have to be changed is made. Therefore, when loading a nightmare savegame when in a non-nightmare game, the demons will not be sped up; conversely, when loading a non-nightmare savegame while in a nightmare game, the demons will not be slowed down.

Therefore, if a player saves the game while in nightmare mode, starts a new game in non-nightmare mode, and finally reloads the nightmare savegame, the engine will double the demon state durations when starting the new game, but it will neglect to halve them when the savegame is loaded. If the player repeats the process multiple times, the demon will be increasingly slowed down as starting a new game doubles the state durations again and again, while loading the savegame does not halve them. The geometrical growth of the state duration can result in a demon that is practically frozen in place: for example, doubling ten times is the same as multiplying by over a thousand (210 = 1024), resulting in a chase state lasting about a full minute instead of 2/35th of a second (2048/35 ≈ 58.51).

Conversely, it is possible by loading a normal save and starting a nightmare game repeatedly to continually halve the state durations, making demons faster and faster. Of particular interest is the chase state sequence (S_SARG_RUN1 to S_SARG_RUN8), where each of the individual states that comprise it lasts only two tics. After two halvings, their duration is reduced to zero, possibly resulting in an infinite loop as the whole sequence can be looped an infinite amount of times in a single tic. (This can happen if the demon is awake, but cannot reach the player; for example, because a door has not finished opening. Being unable to start attacking, it will continue to chase forever without any delay, freezing the game as it cannot process anything else.)


Several approaches can be used to prevent the bug. The simplest would be to change the save loading code so that it writes the loaded skill level in d_skill instead of gameskill, as happens when starting a new game from the menu. Boom instead decided to use an additional variable to keep track of whether the previous game was in nightmare mode. ZDoom prefers to halve each demon mobj's countdown for the next state in the relevant condition, achieving the same result without modifying the state table.