Search In
• More options...
Find results that contain...
Find results in...

# Theory about 'barrel explosions which do no damage' bug

## Recommended Posts

This one. I've always figured that the bug happens when you're standing very slightly behind the line and Doom incorrectly treats the line as solid for some reason, shielding you from the blast. But now I've suddenly realised what that reason must be. When checking LOS across 2-sided lines with height differences, Doom calculates the angles from thing to the highest floor and lowest ceiling, to see if they completely obstruct the line of sight. It just occurred to me that this angle is stored as rise/run (like all vertical angles in Doom), and is bound to become inaccurate or even overflow if the run is extremely small.

p_sight.c, P_CrossSubsector()

```frac = P_InterceptVector2 (&strace, &divl);

if (front->floorheight != back->floorheight)
{
slope = FixedDiv (openbottom - sightzstart , frac);
if (slope > bottomslope)
bottomslope = slope;
}

if (front->ceilingheight != back->ceilingheight)
{
slope = FixedDiv (opentop - sightzstart , frac);
if (slope < topslope)
topslope = slope;
}

if (topslope <= bottomslope)
return false;		// stop
```
I see two things that might be going wrong here. Either FixedDiv() overflows when the divisor is very small (in the released source it checks for this condition, but maybe it didn't in the original executables?), or P_InterceptVector2() is inaccurate at small distances. Am I onto something here? Or worse, has someone already figured this out ages ago and not put the information on the wiki?

I did my usual Poor Man's Debugging (i.e. putting in a bunch of fprintfs) and got the following:
```frac = -38
after interceptvector2:
topslope = -2064384
bottomslope = 2147483647
topslope <= bottomslope
END EXPLODE CHECK
```
Does bottomslope look familiar? Right, it's INT_MAX. So clearly something is hitting a wall. And looks like frac is relatively miniscule at -38 (which corresponds to something like -0.0006 in non fixed point representation) so FixedDiv is blowing up.

So why is frac so small? P_InterceptVector2() is doing... some sort... of vector comparison, and ends up with a tiny numerator, so that's why. But I can't say WHY-why since I don't really understand how P_InterceptVector2() works. I assume it just returns a fraction of how far along one line the intersection point with the other line is, which would explain why it's so small here (and negative, which seems like it shouldn't happen?), but I don't know what mathematical formula it's derived from or anything. The denominator part looks similar to the denominator in the equation to find the intersection of two lines, but that's to find the actual point, not a fraction along one of them...

So yeah, long story short, Doom's math code is once again shitting a brick when dealing with infinitesimal distances. Fixed point strikes again!

e: thinking about it a little more, I think the sign change is really the important part in this case (frac being -38 instead of, like, 38) but it's still fixed point related.

Figures that they manage to replace a buggy but fixable sight checking algorightm (see Doom 1.2, Heretic) and replace it with one that's not only considerably less performant but also exhibits its own strange bugs.

Also, kind of weirdly, the code to check if the explosion does damage to the player checks a line from the player's (simulated as 3/4 height up) eyeball to the barrel, instead of just from the barrel to the player like you'd think. This means that if, for instance, a door has just started opening and a barrel just behind the door explodes, like so:

The barrel won't hurt the player because the player's can't actually see any part of the barrel, even though there is obviously a clear path between them.

Linguica said:

Does bottomslope look familiar? Right, it's INT_MAX. So clearly something is hitting a wall. And looks like frac is relatively miniscule at -38 (which corresponds to something like -0.0006 in non fixed point representation) so FixedDiv is blowing up.

Yup. It looks like FixedDiv() is supposed to return INT_MAX if an overflow would occur and the numbers have the same sign (and INT_MIN if they don't). This is reasonable and in fact would probably avert the bug completely but for one small detail.

Linguica said:

So why is frac so small? P_InterceptVector2() is doing... some sort... of vector comparison, and ends up with a tiny numerator, so that's why. But I can't say WHY-why since I don't really understand how P_InterceptVector2() works. I assume it just returns a fraction of how far along one line the intersection point with the other line is, which would explain why it's so small here (and negative, which seems like it shouldn't happen?), but I don't know what mathematical formula it's derived from or anything. The denominator part looks similar to the denominator in the equation to find the intersection of two lines, but that's to find the actual point, not a fraction along one of them...

My understanding (based on the context in which the function appears, not the function itself) is that it's supposed to calculate the absolute distance (in fracunits) between the start of the line and the intersection point. I agree it shouldn't be negative, and this negativity is likely the direct cause of the bug.

It would be more revealing to see the coordinates of the divlines in question, and how they compare with the map's linedefs and segs. We all know segs don't always line up exactly with their linedefs, so perhaps P_InterceptVector2() is working perfectly, but it's working from bad coordinates that place the player slightly in front of the line rather than behind it.

Yeah, but that's because checking sight in this situation is a fundamentally wrong way to do this, not a bug. The sight check works precisely as advertised.

Foxpup said:

It would be more revealing to see the coordinates of the divlines in question, and how they compare with the map's linedefs and segs. We all know segs don't always line up exactly with their linedefs, so perhaps P_InterceptVector2() is working perfectly, but it's working from bad coordinates that place the player slightly in front of the line rather than behind it.

P_CrossSubsector() is looping through all the segs associated with a subsector, so that wouldn't be it.

I notice that P_InterceptVector2() is also does stuff like "v1->dy>>8" which I assume is in an attempt to keep the FixedMul from overflowing. But doing whatever>>8 is done nowhere else in the source that I know of except for some of this intercept stuff (FRACBITS stuff is >>16, and FixedDiv does something with a >>14). I'm sure that doesn't help precision.

Linguica said:

P_CrossSubsector() is looping through all the segs associated with a subsector, so that wouldn't be it.

Oops, you're right.

Linguica said:

I notice that P_InterceptVector2() is also does stuff like "v1->dy>>8" which I assume is in an attempt to keep the FixedMul from overflowing. But doing whatever>>8 is done nowhere else in the source that I know of except for some of this intercept stuff (FRACBITS stuff is >>16, and FixedDiv does something with a >>14). I'm sure that doesn't help precision.

It doesn't help precision at all. I think it's safe to say that this imprecision is indeed the cause of the bug. Now who's going to distil the relevant details from this thread and throw them on the wiki?

Linguica said:

Poor Man's Debugging

Laugh at it not, for sometimes (on certain embedded systems, mostly), there's no other way of debugging. And you might not even have a device screen to directly output those fprintf's to.

As for the bug having to do with slopes....well, I kinda expected that. After all, what's the difference between a wall and a very steep slope?

However, sometimes the bug occurs even with no height difference at all.

Maes said:

However, sometimes the bug occurs even with no height difference at all.

LMPs or it didn't happen. The slope is only ever checked when a height difference occurs, and the only other things that can stop blast damage are solid walls, being out of range, being unshootable, being a cyber- or spiderdemon, or a faulty blockmap or reject table. The last one is probably the most likely - Graf Zahl was right about sight checking being the wrong tool for the job.

I've once seen a barrel explode into confetti

@Foxpop: I thought it was well-known that barrels do no damage if the explosion occurs right on a blockmap's boundary, or with the player hugging a wall? The same mechanism also allows negating Archvile splash damage in some situations.

Maes said:

I thought it was well-known that barrels do no damage if the explosion occurs right on a blockmap's boundary, or with the player hugging a wall?

But what's happening here?

BaronOfStuff said:

But what's happening here?

Does that level have a weird reject map maybe?

I've noticed on av20 fairly early in the level that there's a place where if I get up close to punch an arch-vile it will only do 20 damage. Is this related?

xit-vono said:

I've noticed on av20 fairly early in the level that there's a place where if I get up close to punch an arch-vile it will only do 20 damage. Is this related?

Are you saying the archvile only does 20 damage to you, or that you only do 20 damage to it? Because the former one, yeah it's probably related, but the latter sounds bizarre.

Linguica said:

The barrel won't hurt the player because the player's can't actually see any part of the barrel, even though there is obviously a clear path between them.

This one seems pretty explainable as a courtesy to the player; in the rare circumstances where a barrel explodes as a player opens a door to an area they haven't been in ( presumably due to the area being connected to a place the player has already visited, and there's some infighting going on ) performing normal calculations could mean that the player would die seemingly at random and for no reason; on the other hand, preventing the barrel from dealing damage until it's actually visible to the player makes the window of opportunity for that to happen far smaller.

It's basically a way, even if not elegant, to minimize cheap deaths.

Maes said:

@Foxpop: I thought it was well-known that barrels do no damage if the explosion occurs right on a blockmap's boundary, or with the player hugging a wall? The same mechanism also allows negating Archvile splash damage in some situations.

It can't be that well-known, because I know almost everything that's well-known about Doom as well as several things that aren't, and I've never seen or even heard of this. Or is this "well-known" in the sense that it's well-known that berserk only lasts while the screen is red?

I did throw in blockmap failures as one of potential causes, but merely being on a block boundary isn't a failure. That only causes problems working out if something overlaps a thing's radius, which explosions don't care about. I don't see what could possibly be going on here, and can't see without an actual example.

Foxpup said:

It can't be that well-known, because I know almost everything that's well-known about Doom as well as several things that aren't, and I've never seen or even heard of this. Or is this "well-known" in the sense that it's well-known that berserk only lasts while the screen is red?

It's well-known in the sense that it is on the wiki.
The berserk comment reminds me of a certain developer whose port implemented exactly that "well-known" aspect of the berserk and even went as far as to argue here on DW that his implementation was the correct behavior since that's how he remembered it from the beginning.

Never_Again said:

It's well-known in the sense that it is on the wiki.

Where? Are we even talking about the same bug?

I can't find any of the bugs mentioned by Maes on the linked wiki page. Either Never_Again was thinking about the title bug of this thread instead of the ones mentioned by Maes, or the bug pages are obscured by unobvious names.

*shrug* I vaguely remember some arcane technical discussions in Source Ports long time ago, which focused specifically on how Archvile blast damage can be sometimes negated if the player is positioned in certain spots/in certain ways, and that it somehow applied to barrels, as well.

Seeing that barrels, rockets and archviles blasts all share the same (?) action mechanism, it would seem strange that they have different behaviors (though explosion height might explain why we never heard of e.g. rockets that do no damage).

Yeah, the weaker archvile blast is definitely a thing, but I also can't remember what thread it was in or the exact circumstances (something like standing against a wall or pillar so that the blast only deals 20 damage like xit said).

^How funny, I actually witnessed this in BTSX last night, but only noticed it while sifting through the video today, and I had literally no explanation for it because the arch-vile was targeting a chaingunner, AND double damage was on: there was no way it could have survived.

TimeOfDeath said:

Yeah, the weaker archvile blast is definitely a thing, but I also can't remember what thread it was in or the exact circumstances (something like standing against a wall or pillar so that the blast only deals 20 damage like xit said).

Al of u guise r fucken scrublords coz u dont even kno pro doom monster strats how lame.

^I've learnt about the AV blast bug exactly from this video back in 2011 (or 12). I almost brought it up in my previous post, although I didn't remember anymore how the video was called. :)

just search for agitating skeleton and you're guaranteed to never forget how to find the video anymore.

Yes, I meant the title bug of this thread. I thought Maes was talking about this bug, but on repeat readings it seems like he mixed up it and the blockmap bug. The "player hugging a wall" bit slipped by me then (expectation bias at work), it is certainly not something I ever heard of before and screams "citation needed". ;) It's quite possible that he knows the subject than the three of us put together and all these phenomena have the same underlying mechanism, but some explanation is order.

Well, I'm very surprised I've never heard of this before, but now that I've seen it, it's obvious what the cause is. The source of an arch-vile explosion is 24 units in front of the player, which, if the player is facing a moderately high platform, puts it below the floor, and the line's lower surface is high enough to block the line of sight. Nothing to do with the blockmap, and not applicable to explosions from other sources. (One might expect facing a one-sided wall to work just as well, but it doesn't because the other side of the wall is often the same subsector, in which case the wall is never checked.)

This is totally unrelated to the bug under discussion, but should go on the wiki anyway (on the arch-vile page; dunno if it deserves its own page).

Foxpup said:

One might expect facing a one-sided wall to work just as well

The blast is centered in between the player and the archvile, so it is impossible for the blast to be on the other side of a 1S line, because that would mean the archvile was also on the other side of the 1S line, and so the blast wouldn't happen because LOS is blocked.