jmtd → log → Deterministic Doom
What happens if you remove randomness from Doom?
For some reason, recently I have been thinking about Doom. This evening I was wanting to explore some behaviour in an old version of Doom and to do so, I hex-edited the binary and replaced the random number lookup table with static values.
Rather than consume system randomness, Doom has a fixed 256-value random number table from which numbers are pulled by aspects of the game logic. By replacing the whole table with a constant value, you essentially make the game entirely deterministic.
What does it play like? I tried two values, 0x00
and 0xFF
. With
either value, the screen "melt" effect that is used at the end of
levels is replaced with a level vertical wipe: the randomness was
used to offset each column. Monsters do not make different death
noises at different times; only one is played for each category of
monster. The bullet-based (hitscan) weapons have no spread at all:
the shotgun becomes like a sniper rifle, and the chain-gun is
likewise always true. You'd think this would make the super-shotgun
a pretty lethal weapon, but it seems to have been nerfed: the
spread pattern is integral to its function.
With 0x00
, monsters never make their idle noises (breathing etc.)
On the other hand, with 0xFF
, they always do: so often, that each
sample collides with the previous one, and you just get a sort-of
monster drone. This is quite overwhelming with even a small pack of
monsters.
With 0xFF
, any strobing sectors (flickering lights etc.), are
static. However, with 0x00
, they strobe like crazy.
With 0x00
, monsters seem to choose to attack much more frequently than
usual. Damage seems to be worst-case. The most damaging floor type
("super hellslime"/20%) can hurt you even if you are wearing a radiation
suit: There was a very low chance of it hurting whilst wearing the
suit (~2.6%)
each time the game checked; this is rounded up to 100%.
Various other aspects of the game become weird. A monster may always choose to use a ranged attack, regardless of how close you are. They might give up pursuing you. I've seen them walk aimlessly in circles if they are obstructed by another thing. The chance of monster in-fighting is never, or a certainty. The player is either mute, or cries in pain whenever he's hurt.
If you want to try this yourself, the easiest way is to hack the m_random.c
file in the source, but you can hex-edit a binary. Look for a 256-byte sequence
beginning beginning ['0x0', '0x8', '0x6d', '0xdc', '0xde', '0xf1']
and ending
['0x78', '0xa3', '0xec', '0xf9']
.
Comments
Even after ~20 years of playing, I'm still learning about the game's physics/quirks thanks to "white papers" and great write-ups like this!
id-Software/DOOM/blob/master/linuxdoom-1.10/m_random.c#L31
@anonymous: I've thought about it but not done it yet. There's also the question of whether you clamp to a byte or not: doing other would need more refactoring elsewhere.
There are some numbers entirely missing from the current table, and corresponding duplicates.
I wonder how interesting the game would be if, instead of using rand(), one used a counter;
Would the game be interesting if the counter followed a sawtooth pattern (increasing or decreasing,) mountain (up, then down,) sinus (range from 00 to ff.)
Would it be more interesting if the counter was displayed (so one would learn where the most powerful periods / most dangerous periods were and use them to gain advantage) or if it was NOT displayed (so one would need to learn based on the sounds made.)
If the range is interesting enough between 0 and 59 (decimal) the system clock could be used. If 0 to 59 were not a wide enough range, up to 4x the second counter could be used. Or the minute counter...
I'm unsure if the results will be worth persuing, and unfortunately I don't have the time to see - but I'd be interested if someone else did. (I may just use the ideas in another game.)