Duke3D: Ordering Issue with PROJECTILE_RPG_IMPACT and DAMAGESPRITE events
The following block of code is present in actors.cpp
, inside the function ACTOR_STATIC void Proj_MoveCustom(int const spriteNum)
, starting at line 3109:
A_DamageObject(otherSprite, spriteNum);
...
if (pProj->workslike & PROJECTILE_RPG_IMPACT)
{
actor[otherSprite].owner = pSprite->owner;
actor[otherSprite].picnum = pSprite->picnum;
if (pProj->workslike & PROJECTILE_RPG_IMPACT_DAMAGE)
actor[otherSprite].extra += pProj->extra;
A_DoProjectileEffects(spriteNum, &davect, 0);
if (!(pProj->workslike & PROJECTILE_FORCEIMPACT))
{
A_DeleteSprite(spriteNum);
return;
}
}
Note that in the following: actor[otherSprite].owner == htowner
, actor[otherSprite].picnum == htpicnum
and actor[otherSprite].extra == htextra
.
Notice that A_DamageObject()
handles projectile damage and calls both EVENT_DAMAGESPRITE
as well as EVENT_POSTDAMAGESPRITE
respectively at the start and the end of the function. The former event is supposed to be executed before the damage is added to the htextra
struct member (and also, before htowner
and htpicnum
are set), while the latter event is supposed to be executed after these members have been updated.
The above block of code however is executed for any custom projectile that has the PROJECTILE_RPG_IMPACT
flag, and breaks the assumptions made for EVENT_POSTDAMAGESPRITE
. Namely, the htowner
as well as htpicnum
members are updated a second time, thus preventing them from being changed inside EVENT_POSTDAMAGESPRITE
, and if the flag PROJECTILE_RPG_IMPACT_DAMAGE
is also given, then the damage is incremented after the event, meaning that EVENT_POSTDAMAGESPRITE
does not have access to the full damage the projectile does to the enemy.
As a result, this block of code bypasses any changes made to the overall damage in EVENT_DAMAGESPRITE
. For example, if we tried to code different damage resistances for certain enemy types, PROJECTILE_RPG_IMPACT_DAMAGE
would bypass this resistance and apply the full damage, regardless of what is done in the CON code.
However, if we were to reorder this code such that A_DamageObject()
is executed only after the PROJECTILE_RPG_IMPACT
block, then we break the assumption about EVENT_DAMAGESPRITE
instead, as some damage has already been added to htextra
.