Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
Linguica

3 vanilla modding tricks I haven't seen elsewhere

Recommended Posts

Now that Selfie Doom is one for the ages, I want to document three tricks it used that, to the best of my knowledge, haven't been used in any other vanilla project.

  1. Non-repeating tall sprites in vanilla

    It's fairly well known that Doom sprites can't be taller than 128 pixels without screwing up. More specifically, the (vanilla) Doom engine's core rendering loop can only draw 128 pixels vertically at a time before starting to repeat. This was added because the same routine is used for drawing wall textures, and the game standardized on 128-pixel-high wall textures that would tile vertically.

    However, the Doom picture format actually supports graphics up to 254 pixels high, due to the specialized way they are stored. What this means is that while a single vertical column of pixels in a sprite can be 254 pixels tall, it would have to be split up into two separate "posts" as the engine calls them, each of 127ish pixels high, and have these two posts be placed one directly after the other with no gap.

    The trick is that no Doom graphics utilities that I am aware of will recognize this situation and automatically split up columns into multiple posts. In this old thread I ask about this issue, in what now was obviously a cover for my Selfie Doom work. I also found a workaround: purposely add in a transparent pixel in the middle of the tall sprite, and then export and manually hex edit the raw lump data to change the offset of the second post in each column. (This is actually less work than it sounds like.)

  2. Enforced HUD weapon alignment

    For ages, DeHackEd patches had two curious values for each entry in the frame table known only as "Unknown 1" and "Unknown 2." These were never used in the game and nobody really understood what they did, so they were pretty much ignored. After the source release it was clear from reading the code that these two values, more properly called "misc1" and "misc2", were supposed to be used to allow the engine to directly set the x- and y- offsets of a HUD weapon sprite.

    I'm not sure how useful that generally is, which maybe explains why it was never used, but there is one way in which it can be useful: to make a screen-covering HUD weapon sprite be aligned properly. By setting the misc1 and misc2 values on all the "viewfinder" graphics, I made sure they didn't bob around or freeze in a misaligned position.

    One small wrinkle is that the code is only called if the x-value is nonzero. This was a slight problem since I actually wanted the x- and y-offsets to both be zero, so the corner of the image would be aligned with the corner of the screen. I had to get around this by purposely misaligning the sprite's offsets by one on both the x and y axes, and then re-aligning them by +1 in the DeHackEd file.

  3. Randomized HUD graphic

    This one is really obscure and not terribly useful for anything except a gimmick, which, hey, turns out I was making. While almost everything involved in the HUD weapon graphics is totally deterministic, there is exactly one randomized thing: the firing frame of the plasma rifle randomly (using P_Random and not M_Random, for some bizarre reason, but which means that the selfie face is preserved in demos, something I exploited in the 4-player built demo) chooses between the two firing frame graphics. This means that combined with the other tricks, you can make it that when you fire a plasma rifle shot, it randomly displays one of two images, say for example a smiling doomguy or a shocked ouchface doomguy.

    This, by the way, is why the selfie stick in Selfie Doom replaces the BFG. Because I *had* to use the plasma rifle's shot for the randomizing effect, that meant I had to edit the plasma shot itself to be nonexistent. Since I was losing an energy weapon, I figured I would rather lose the BFG than the plasma rifle, so I edited the plasma rifle to actually fire BFG shots that were edited to look and act like plasma shots instead. If you look closely at the plasma rifle in Selfie Doom while firing it, you will notice the firing frames are no longer randomized, and jitter back and forth between the two frames in the same way every time. I actually saw one comment about Selfie Doom pointing out that firing the plasma rifle mysteriously "looked better" and "more random" or something, which ironically was the complete opposite of reality.

    This hack is also part of the reason why I ended up adding a separate DECORATE implementation in the final release, since some ZDoom-based ports would internally recognize the "plasma shots" as really being BFG shots, and would apply the BFG scorch decal when they hit a wall.

Share this post


Link to post
Linguica said:

I actually saw one comment about Selfie Doom pointing out that firing the plasma rifle mysteriously "looked better" and "more random" or something, which ironically was the complete opposite of reality.


Human perception of randomness is generally wrong.

Share this post


Link to post
Linguica said:

However, the Doom picture format actually supports graphics up to 254 pixels high, due to the specialized way they are stored.


Hmm, I would have though that you could have had around 382 pixels tall if you start a third post of 128 pixels at offset 254. Or have I misunderstood the format?

Share this post


Link to post

Thanks for posting this. When I played with selfie doom, I was really scratching my head about how you did the randomized HUD graphic. I had no idea that the plasma gun frames were chosen randomly. Very cool.

Share this post


Link to post
Linguica said:

Enforced HUD weapon alignment

This is super okay. I was under the impression that this code wasn't actually present or didn't work, and the values were nothing more than cruft. Now I can make it so the weapons are centered when firing.

Linguica said:

One small wrinkle is that the code is only called if the x-value is nonzero.

For both weapons I tried this on, the values of 1 and 32 were perfect and didn't require realigning the sprites themselves. I'm under the impression that X=1 is treated as the default value that resets the weapon to its default X position.

It's all a little counter-intuitive. Why Y=32 turned out to be perfect for the default Y position - I have no idea. It's literally the first value I tried after my initial thought about how this works proved to be wrong.

Linguica said:

The trick is that no Doom graphics utilities that I am aware of will recognize this situation and automatically split up columns into multiple posts.

And it's a real shame, since you can't even make a decent shotgun replacement without pixel columns taller than 128:

http://i.imgur.com/iet7f78.png

Which sorta kinda proves that splitting tall posts is the "canonical" way of saving Doom graphics - official IWADs have tall sprites and they work fine.

Share this post


Link to post
jeff-d said:

Hmm, I would have though that you could have had around 382 pixels tall if you start a third post of 128 pixels at offset 254. Or have I misunderstood the format?

Probably, but the third post has to be continuous. 254 is the tallest for an arbitrarily transparent graphic.

Da Werecat said:

Which sorta kinda proves that splitting tall posts is the "canonical" way of saving Doom graphics - official IWADs have tall sprites and they work fine.

...you know, this never even occurred to me. I went and extracted the SHGTC0 lump and looked at it in a hex editor, and sure enough, the long columns have a post of 128 pixels and then a second post of however many left over.

So for 22 years now, all third-party Doom graphics utilities have lacked a function that id's own utility apparently had built-in, nice.

Share this post


Link to post

The weapon offset forcer is awesome! Initially I thought it merely offsets the sprite like you'd do in the lump, but it turns out you don't need ZDoom to have properly-centred weapons! How did id not use this? It always bugged me when guns were off-centre.

Share this post


Link to post
Linguica said:

Probably, but the third post has to be continuous. 254 is the tallest for an arbitrarily transparent graphic.
...you know, this never even occurred to me. I went and extracted the SHGTC0 lump and looked at it in a hex editor, and sure enough, the long columns have a post of 128 pixels and then a second post of however many left over.

So for 22 years now, all third-party Doom graphics utilities have lacked a function that id's own utility apparently had built-in, nice.

In fact, if you examine the TNT: Evilution graphics, they differ from the Doom graphics, in that they are built the same way. In other words, TNT reprocessed the Doom IWAD graphics to make Evilution. At least for the weapon sprites. Maybe they had their own lump utilities?

Share this post


Link to post
kb1 said:

In fact, if you examine the TNT: Evilution graphics, they differ from the Doom graphics, in that they are built the same way.

I don't understand what this is supposed to mean. They are different in that they are the same?

Share this post


Link to post
Linguica said:

So for 22 years now, all third-party Doom graphics utilities have lacked a function that id's own utility apparently had built-in, nice.

The best is that people have come up with a different way to generate tall patches...

kb1 said:

In fact, if you examine the TNT: Evilution graphics, they differ from the Doom graphics, in that they are built the same way. In other words, TNT reprocessed the Doom IWAD graphics to make Evilution. At least for the weapon sprites. Maybe they had their own lump utilities?


They used DEUTEX (you can still see the _DEUTEX_ lump it left). It's also responsible for downsampling the 22khz sounds down to 11khz.

Share this post


Link to post
Linguica said:

I don't understand what this is supposed to mean. They are different in that they are the same?

Run a hash on the same lump from both WADs, like CRC-32 or MD5 - they are different. Further investigation reveals that the posts are built differently (no idea which is which right now).

Share this post


Link to post

The Doom picture format has possibly-random junk bytes strewn through it that are ignored, so it's not hard to imagine that the same image imported twice would have a different hash. Deutex does not support splitting up columns longer than 128 pixels into multiple posts though, so I don't know how TNT would have built the IWAD from scratch and not had the shotgun graphic repeat. (Deutex does, however, support importing nontransparent graphics more than 254 pixels tall by splitting them into multiple posts automatically, so hooray I guess.)

Share this post


Link to post

Looking more closely, let's see.

I exported SHTGC0 from doom.wad and tnt.wad and compared them.

Here's some code from the doom.wad lump:

FF 00 80
FF is the end of the previous column, then the new column's post starts at 00 and is 80 long (128 in decimal).
Here's the same place in TNT:
FF 00 97
So the previous column ends, the new one starts, and... is 151 long in decimal?? Wait a second...



UHHH???

Share this post


Link to post

This is the best discovery ever. I dunno if it cheapens or strengthens what the Batman Doom guys did. Maybe they discovered this all those years ago?

Share this post


Link to post

Great, never going to be able to unseen that :). I'm not sure Doom will ever run out of surprises at this point.

Share this post


Link to post
Linguica said:

Looking more closely, let's see.

I exported SHTGC0 from doom.wad and tnt.wad and compared them.

Here's some code from the doom.wad lump:

FF 00 80
FF is the end of the previous column, then the new column's post starts at 00 and is 80 long (128 in decimal).
Here's the same place in TNT:
FF 00 97
So the previous column ends, the new one starts, and... is 151 long in decimal?? Wait a second...

http://i.imgur.com/Qa22ddJl.png

UHHH???

I'm sure you realize that one of those end bytes is a junk byte in Doom posts, right? I believe it's an artifact of going from bytes to small ints in the transition from Alpha to release. They actually did this a couple of times, before settling on the final format. That extra byte threw me off for a long time, because I couldn't tell which was valid. The again, it's kinda overkill to have both run length and an end marker, huh?

Share this post


Link to post
kb1 said:

I'm sure you realize that one of those end bytes is a junk byte in Doom posts, right? I believe it's an artifact of going from bytes to small ints in the transition from Alpha to release. They actually did this a couple of times, before settling on the final format. That extra byte threw me off for a long time, because I couldn't tell which was valid. The again, it's kinda overkill to have both run length and an end marker, huh?

Look at the screenshot from Evilution more closely.

Share this post


Link to post

In case the rest of you missed it (I did), the shotgun overruns - look at the bottom left and you can see the end of the barrel repeated. But I had to load up Doom 1 and TNT in side-by-side DOSbox windows to spot it.

Share this post


Link to post

Ha, what a bizarre discovery, Lingu! It's easy to spot in Chocolate Doom with this deh, even easier with fullscreen HUD:

Spoiler

Patch File for DeHackEd v3.0
# Created with WhackEd4 1.0.4
# Note: Use the pound sign ('#') to start comment lines.

Doom version = 19
Patch format = 6


Frame 26
Duration = 35

All the ports I tried (except Chocolate Doom ofc) have fixed the 128 limit.

Share this post


Link to post

Excellent discoveries, just wanted to say that. Especially the manual weapon offsets, those would come in handy for various modding purposes.

Share this post


Link to post

Right now I can see two applications:

1. Centering the weapon during the attack.
2. Implementing duplicate-based smooth animations or weapon-jerking elegantly (i.e. without actually duplicating data).

WeaponReady overrides the offsets while the weapon is idle, so no way to remove bobbing completely.

The original purpose seems to be a little bit of both: to reposition the weapon without duplicating the sprites. IIRC, alpha versions demonstrate that. Apparently, when the idea of raising some weapons during their shooting sequences was abandoned, the developers stopped using the values altogether. Another guess is that the weapon freezing in whatever position the bobbing code left it was an oversight rather than the intended consequence.

Share this post


Link to post
Da Werecat said:

Right now I can see two applications:

1. Centering the weapon during the attack.
2. Implementing duplicate-based smooth animations or weapon-jerking elegantly (i.e. without actually duplicating data).

3. Instant weapon changes by pushing the weapon down during "Lower" frame and pushing it up during "Raise" frame.

Da Werecat said:

WeaponReady overrides the offsets while the weapon is idle, so no way to remove bobbing completely.

Maybe there is a way. You could make the weapon idle animation alternating between 2 states: The first state with "WeaponReady" codepointer and with duration 0, and the second state with NULL codepointer, with duration 1 and with the desired DEHACKED offsets.

Share this post


Link to post
Linguica said:

However, the Doom picture format actually supports graphics up to 254 pixels high, due to the specialized way they are stored. What this means is that while a single vertical column of pixels in a sprite can be 254 pixels tall, it would have to be split up into two separate "posts" as the engine calls them, each of 126ish pixels high, and have these two posts be placed one directly after the other with no gap.

The trick is that no Doom graphics utilities that I am aware of will recognize this situation and automatically split up columns into multiple posts. In this old thread I ask about this issue, in what now was obviously a cover for my Selfie Doom work. I also found a workaround: purposely add in a transparent pixel in the middle of the tall sprite, and then export and manually hex edit the raw lump data to change the offset of the second post in each column. (This is actually less work than it sounds like.)

Great sleuthing work! Now that you've described the problem, how likely is it to get fixed? As far as I can tell, the most active fork of deutex is this one -- any enthusiastic programmers feel up to the task of submitting a patch?

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×