Gargoyle crash bugs

From DoomWiki.org

The "crash" feature of the gargoyle when it dies in Heretic, whereby it enters a special falling state until it hits the ground and then explodes into gibs on contact, is subject to several bugs which can cause interesting behaviors.

Mechanics[edit]

The crashstate was added to the mobjinfo_t structure by Raven Software to allow the gargoyle's special falling behavior. Special-case code in the function P_ZMovement will place it into this state when it is detected as having hit the ground. The normal death frame of a gargoyle always depicts it in a pose of falling through the air. It is the crashstate which transforms it into a pile of gibs and spawns additional gib objects.

No gibs[edit]

If the gargoyle is already touching the ground before the game makes the first check for impact, but after the gargoyle has already entered its deathstate, then the crash will never occur as the P_ZMovement function will never be invoked for the object at all. This will cause the gargoyle to remain solid and affected by gravity while holding its falling pose. This most commonly occurs if the gargoyle is perfectly level with a floor behind it and is pushed back onto the floor by the damage that kills it, resulting in no Z momentum. A common place to observe this is in E1M7: The Crypts, just beyond the yellow key door.

Multiple gibs[edit]

If the gargoyle crosses multiple sectors while dying, such as by sliding down a set of stairs, it may enter its crashstate repeatedly, becoming a fountain of gibs in the process. This happens due to interaction between the functions P_ZMovement and A_ImpExplode; neither function checks if a gargoyle is already in its crashstate, so when it hits each floor, it satisfies the conditions for the crash animation to occur.

Floating dead gargoyle[edit]

If the gargoyle suffers an "extreme" death (gibbing by normal standards), it enters a different frame (the xdeathstate) the same way as other monsters, but still utilizes the same crash logic. However, Raven wanted the gargoyle to appear to fly much further away from the player when this occurs, to reflect the power of the attack that killed it, so they temporarily assign the gargoyle the MF_NOGRAVITY bit flag to cause it to temporarily float in the air. This flag is assigned by the A_ImpXDeath1 action function and removed several frames later in the A_ImpXDeath2 action function, via the following state sequence:

   {SPR_IMPX, 18, 5, A_ImpXDeath1, S_IMP_XDIE2, 0, 0}, // S_IMP_XDIE1
   {SPR_IMPX, 19, 5, NULL, S_IMP_XDIE3, 0, 0}, // S_IMP_XDIE2
   {SPR_IMPX, 20, 5, NULL, S_IMP_XDIE4, 0, 0}, // S_IMP_XDIE3
   {SPR_IMPX, 21, 5, A_ImpXDeath2, S_IMP_XDIE5, 0, 0}, // S_IMP_XDIE4
   {SPR_IMPX, 22, 5, NULL, S_IMP_XDIE5, 0, 0}, // S_IMP_XDIE5

When A_ImpXDeath2 is invoked, it will check if the monster has touched the floor, and if so, it will then set it into its crashstate. There is a logical error in this setup, however: it is possible for the logic in P_ZMovement to set the gargoyle to its crashstate as usual between these two frames, and when this occurs, the S_IMP_XDIE4 frame is never entered by the monster at all. This results in the gibbed gargoyle keeping the no-gravity bit flag - it will remain floating in the air forever. This occurs if the gargoyle dies in the air but crosses a raised ledge at its exact height during the 15 tics between the two action function calls. This means that gibbing a gargoyle near a window frame is the easiest way to cause it.

Fixes[edit]

These bugs are fixed by some Heretic source ports:

The problem of no gibbing is addressed by adding a special-case check for objects with crash animations already being in contact with a floor when they die; they will be set into that state immediately instead of assuming that they will necessarily acquire Z momentum at some later point in execution.

The problem of gibbing multiple times must be addressed by adding some type of tracking to the actor. In both Eternity and ZDoom this is accomplished with an internal bit flag which records the "has crashed" state for that object. An object attempting to crash again will not repeat the animation if this bit is set.

The problem of a floating gibbed gargoyle is fixed simply by always removing the no-gravity bit flag in the A_ImpExplode routine as well, so that it will be removed regardless of how a gargoyle enters the crash animation.