Difference between revisions of "Barrel suicide"

From DoomWiki.org

[checked revision][checked revision]
m (templated link for dwforums thread)
m (missed a space)
 
(11 intermediate revisions by 7 users not shown)
Line 4: Line 4:
  
 
If a monster manages to damage ''itself'' in a barrel explosion, it is the cause of its own injury. Doom v1.4 does not check for this special case (it is not a scenario that occurs frequently during normal play). As a result, monsters that injure themselves through a barrel explosion will retaliate ''against themselves''. Monsters such as [[cacodemon]]s, [[Baron of hell|barons of hell]] and [[imp]]s will "tear themselves apart" with their own [[melee]] attack. [[Former human]]s (or monsters without [[melee attack]]s) will "go crazy", firing ahead blindly, possibly causing monster infighting as a result.
 
If a monster manages to damage ''itself'' in a barrel explosion, it is the cause of its own injury. Doom v1.4 does not check for this special case (it is not a scenario that occurs frequently during normal play). As a result, monsters that injure themselves through a barrel explosion will retaliate ''against themselves''. Monsters such as [[cacodemon]]s, [[Baron of hell|barons of hell]] and [[imp]]s will "tear themselves apart" with their own [[melee]] attack. [[Former human]]s (or monsters without [[melee attack]]s) will "go crazy", firing ahead blindly, possibly causing monster infighting as a result.
 +
 +
The bug was retained in [[Heretic]] and [[Hexen]], which never patched it in an official release.  In Heretic, the exploding [[pod]] serves as a barrel analogue.  The Hexen variant requires somewhat more unusual circumstances to occur; the monster in question must have a fire-type projectile and incur splash damage from burning a destructible tree or bush.  Creatures that can meet these requirements include [[afrit]]s, both varieties of [[chaos serpent]], [[death wyvern]]s, [[Korax]], [[Menelkir]], and [[reiver]]s.
  
 
== Technical ==
 
== Technical ==
Line 24: Line 26:
 
This code is executed when an object is damaged by another object; this includes barrel explosions. The variable {{c|source}} is a reference to the object which caused the damage, while the variable {{c|target}} is a reference to the object on which damage is inflicted. When a barrel is destroyed, any affected enemies are injured with {{c|source}} equal to the player or enemy which caused the explosion.
 
This code is executed when an object is damaged by another object; this includes barrel explosions. The variable {{c|source}} is a reference to the object which caused the damage, while the variable {{c|target}} is a reference to the object on which damage is inflicted. When a barrel is destroyed, any affected enemies are injured with {{c|source}} equal to the player or enemy which caused the explosion.
  
The above code is supposed to cause monsters to retaliate against players which attack them. However, when a monster injures itself through a barrel explosion, both {{c|target}} and {{c|source}} will reference the monster. It is likely that the code in '''bold type''' was not present in version 1.4. As a result, the monster's target ({{c|target->target}}, the object it is currently chasing/attacking) is set to itself. The result is that it attacks itself.
+
The above code is supposed to cause monsters to retaliate against players which attack them. However, when a monster injures itself through a barrel explosion, both {{c|target}} and {{c|source}} will reference the monster. It is likely that the code in '''bold type''' was not present in versions 1.4 and earlier. As a result, the monster's target ({{c|target->target}}, the object it is currently chasing/attacking) is set to itself. The result is that it attacks itself.
  
 
== Bug ==
 
== Bug ==
Line 60: Line 62:
 
     }
 
     }
  
The first block will automatically destroy the damaged actor if it has no remaining hit points, the last block, detailed in the previous section of this article, switches the target. Note the {{c|return;}} instruction after {{c|P_KillMobj}} in the first block: this means that if the mobj is killed, it will ''not'' run the rest of the function, and will therefore not switch target. {{c|P_KillMobj()}} itself does not have target switching mechanism either. (As as aside, this code also show some actor class-specific hacks: a charging [[lost soul]] will not be placed in its pain state, and an [[arch-vile]] will never be targeted, making it immune to infighting).
+
The first block will automatically destroy the damaged actor if it has no remaining hit points, the last block, detailed in the previous section of this article, switches the target. Note the {{c|return;}} instruction after {{c|P_KillMobj}} in the first block: this means that if the mobj is killed, it will ''not'' run the rest of the function, and will therefore not switch target. {{c|P_KillMobj()}} itself does not have target switching mechanism either. (As an aside, this code also show some actor class-specific hacks: a charging [[lost soul]] will not be placed in its pain state, and an [[arch-vile]] will never be targeted, making it immune to infighting).
  
 
== External links ==
 
== External links ==
 
* [https://web.archive.org/web/20120914045151/http://rome.ro/lee_killough/memorabilia/index.shtml Demos on Lee Killough's webpage demonstrating barrel suicide] (archived)
 
* [https://web.archive.org/web/20120914045151/http://rome.ro/lee_killough/memorabilia/index.shtml Demos on Lee Killough's webpage demonstrating barrel suicide] (archived)
 +
* [https://classicdoom.com/v11bbugs.htm Doom v1.1 barrel-bug demo collection] by Ledmeister
 
* {{Dwforums|id=10323|title=Doom Oddities}} thread at the [[Doomworld forums]]
 
* {{Dwforums|id=10323|title=Doom Oddities}} thread at the [[Doomworld forums]]
  
 
[[Category:Errors and bugs]]
 
[[Category:Errors and bugs]]
 +
[[Category:Heretic errors and bugs]]
 
[[Category:Historical]]
 
[[Category:Historical]]
 
[[Category:Monsters]]
 
[[Category:Monsters]]
 
[[Category:Tactics]]
 
[[Category:Tactics]]
 
[[Category:Exploitable bugs and glitches]]
 
[[Category:Exploitable bugs and glitches]]

Latest revision as of 20:26, 26 September 2023

A cacodemon committing barrel suicide

Because of a bug in the implementation of monster infighting in Doom v1.4 and earlier, monsters will try to commit suicide by attacking themselves if they are injured when they destroy barrels.

A simple explanation for this behavior is as follows: when a barrel is damaged, the Doom engine tracks which player or monster caused this damage. When the barrel explodes, the source of the previous damage is then passed on to objects damaged by the explosion. Ideally, a monster hurt in a barrel explosion will then retaliate against the monster or player that caused the barrel to explode (an example of monster infighting, if the source is another monster). However, the damage sourcing is done after the check to see if the barrel isn't damaged enough to be destroyed (see below), therefore a barrel can be first hit by a monster, and then destroyed by another, and it is the first monster who will be targeted by any AI victim of the explosion. Furthermore, if a barrel is destroyed in a single hit, no one will be considered responsible.

If a monster manages to damage itself in a barrel explosion, it is the cause of its own injury. Doom v1.4 does not check for this special case (it is not a scenario that occurs frequently during normal play). As a result, monsters that injure themselves through a barrel explosion will retaliate against themselves. Monsters such as cacodemons, barons of hell and imps will "tear themselves apart" with their own melee attack. Former humans (or monsters without melee attacks) will "go crazy", firing ahead blindly, possibly causing monster infighting as a result.

The bug was retained in Heretic and Hexen, which never patched it in an official release. In Heretic, the exploding pod serves as a barrel analogue. The Hexen variant requires somewhat more unusual circumstances to occur; the monster in question must have a fire-type projectile and incur splash damage from burning a destructible tree or bush. Creatures that can meet these requirements include afrits, both varieties of chaos serpent, death wyverns, Korax, Menelkir, and reivers.

Technical[edit]

The likely cause of this can be seen in the Doom source code. In the P_DamageMobj function in p_inter.c is the following code:

if ( (!target->threshold || target->type == MT_VILE)
        && source && source != target
        && source->type != MT_VILE)
   {
       // if not intent on another player,
       // chase after this one
       target->target = source;
       target->threshold = BASETHRESHOLD;
       if (target->state == &states[target->info->spawnstate]
           && target->info->seestate != S_NULL)
           P_SetMobjState (target, target->info->seestate);
   }

This code is executed when an object is damaged by another object; this includes barrel explosions. The variable source is a reference to the object which caused the damage, while the variable target is a reference to the object on which damage is inflicted. When a barrel is destroyed, any affected enemies are injured with source equal to the player or enemy which caused the explosion.

The above code is supposed to cause monsters to retaliate against players which attack them. However, when a monster injures itself through a barrel explosion, both target and source will reference the monster. It is likely that the code in bold type was not present in versions 1.4 and earlier. As a result, the monster's target (target->target, the object it is currently chasing/attacking) is set to itself. The result is that it attacks itself.

Bug[edit]

The idea was presumably that barrels would "blame" the mobj directly responsible for their explosion. However, the P_DamageMobj function does not work in the proper order for this to actually happen. This excerpt shows the problem:

   // do the damage	
   target->health -= damage;	
   if (target->health <= 0)
   {
	P_KillMobj (source, target);
	return;
   }

   if ( (P_Random () < target->info->painchance)
	 && !(target->flags&MF_SKULLFLY) )
   {
	target->flags |= MF_JUSTHIT;	// fight back!
	
	P_SetMobjState (target, target->info->painstate);
   }
			
   target->reactiontime = 0;		// we're awake now...	

   if ( (!target->threshold || target->type == MT_VILE)
	 && source && source != target
	 && source->type != MT_VILE)
   {
	// if not intent on another player,
	// chase after this one
	target->target = source;
	target->threshold = BASETHRESHOLD;
	if (target->state == &states[target->info->spawnstate]
	    && target->info->seestate != S_NULL)
	    P_SetMobjState (target, target->info->seestate);
   }

The first block will automatically destroy the damaged actor if it has no remaining hit points, the last block, detailed in the previous section of this article, switches the target. Note the return; instruction after P_KillMobj in the first block: this means that if the mobj is killed, it will not run the rest of the function, and will therefore not switch target. P_KillMobj() itself does not have target switching mechanism either. (As an aside, this code also show some actor class-specific hacks: a charging lost soul will not be placed in its pain state, and an arch-vile will never be targeted, making it immune to infighting).

External links[edit]