In addition to these, take a look at the ZDoom forums project thread for some more development news.


Blood and gibs

If you've played Brutal Doom, you've probably noticed that it contains a certain amount of blood and gore. This is reflected in the PK3 contents, where actors to support this are spread throughout BLOOD.TXT, BLOODSPLASH.TXT, DEAD.TXT, GORE!!!.TXT, GORE2.TXT, GORE3.TXT and many others - and that's before taking into account the decals and the models to simulate floor decals. These text files variously describe classes with names like MuchBlood2, BloodTr255 and XDeathHalfImpUpperPart32. Faced with this, I began experimenting by looking at one of the sergeant's death sequences and using the SUMMON command in-game to look at the spawned classes individually - but having got a vague idea of what about three of the classes were doing from that, I basically chose to throw the entire collection out and build it up again from scratch.

The amount of detail in the original gore library is... insane, for want of a better term - there's a vast collection of distinct organs and microgiblets that are spawned depending on the monster and the manner of violent death, all inheriting from each other in arcane patterns that I wasn't able to identify. As a side effect of the complexity, it's been overlooked that many of the spawned classes are missing some of their sprites, meaning that some don't have the intended effect at all. On the grounds that a player is never going to notice 99% of the detail unless they're wandering around with a clipboard taking inventory of the individual pieces like a crime scene doctor, I opted to greatly simplify the entire system using only a few of the giant collection of body parts available.

The BDLite hierarchy has been pared down to just four families and looks like this - you can see them all in context on the ZDoc page.

I'll explain the smaller ones first and then move on to the main hierarchy.

BdBleed contains the actors spawned when monsters are hurt, replacing Doom's original Blood object - these are invisible classes that spawn a variety of the effects below. They're defined in the BloodType of a monster, which has three variations - Blood, BloodSplatter and AxeBlood. Those last two are used mostly by Heretic/Hexen when a weapon uses the BLOODSPLATTER or AXEBLOOD flag - BDLite just uses the same blood type for the first two, but uses BleedSaw for the AxeBlood replacement when using the chainsaw to produce a stronger blood effect.

BdBloodHitEffect is a class spawned by BdBleed, a splash of blood to show impact.

BdBloodSpot are the actors that use models to simulate decals on the floor. There are just four variations - blue, red and whether the spot is small or a spreading pool. The spreading pool was used quite a lot in Brutal Doom, but I've limited it more here and it's usually only used for melting/plasma deaths.

BdBlood is the base class for the actual effects, and for this one I haven't included the subclasses beyond the first layer - each of them has a couple of variations below for blue blood or being drawn slightly larger. This is a point where I would really have liked the opportunity to pass parameters into actors when they're created - I considered abusing the Angle property or something for this but quickly decided that that would make things needlessly confusing. Its immediate subclasses are:

BdFlyingBlood - A drop of flying blood to be sprayed out from an enemy using A_FireProjectile. They leave blood spots behind when they land.

BdFlyingBloodTrail - These are small actors that hang in the air behind flying blood and body parts, giving more 'weight' to their appearance. They can also be used as projectiles if you want small splashes.

BdBloodDrop - A lot like BdFlyingBlood but much smaller, for shorter-range blood effects.

BdBloodDropTrail - As above, the equivalent of BdFlyingBloodTrail

BdBloodLump - Mini-gibs which splat to the ground and stay there - otherwise similar to BdFlyingBlood.

BdBloodSpawner* - These classes act as shortcuts for spawning a lot of different actors to represent large splashes, typically used when a monster dies in a particularly violent way. There are different size variations for the human enemies all the way up to the bosses, spawning more blood as you go up. Usually for a death sequence, this is the class you want to spawn, with additional effects added as you choose.

BdGib - Is a bit more involved. These represent the individual flying body parts that Brutal Doom was so fascinated by, though in a more manageable form. In the original code, all of these were spread out everywhere and had various undetectable differences between them - now, they're all consolidated in one dedicated file under one parent class. There are still about 60 variations, making this the biggest subset of the blood actors.

All gibs are simple objects that spin through the air (using the actor roll property with the +ROLLSPRITE flag), leaving blood trails behind them, and land on the ground where they check if the Janitor CVAR ("bd_janitor") is on.

The janitor is set under "Gibs Fade" in the Display Options menu. It works by having each subclass gib actor briefly display its own "lying around" frame (for example, a leg on the ground or half a ribcage), and then jumping into the parent BdGib "Lying" state which will look at the CVar. It uses the "----" pseudo-sprite (which I didn't know existed until midway through this project!) to preserve the appearance of the gib after calling this label, and depending on whether the CVar was set or not, will either stay in that sprite indefinitely or fade after a while.

The vast bulk of all of this is handled in the BdGib base class, which sets a random rotation speed and then leaves the subclass to handle its own display and flight before it lands.

The base class for gibs looks like this:

BdGib class
ACTOR BdGib : BdBlood { var int user_rotationspeed; Radius 8 Height 8 Speed 10 Gravity 0.6 Mass 4 Decal BrutalBloodSplat BounceFactor 0.01 +DOOMBOUNCE +MOVEWITHSECTOR +ROLLSPRITE +ROLLCENTER -RANDOMIZE States { Spawn: TNT1 A 0 A_SpawnItem("BdBloodSpot",0,0,0,1) TNT1 A 0 A_SetUserVar("user_rotationspeed", random(30, 50)) TNT1 A 0 A_SetUserVar("user_rotationspeed", user_rotationspeed * ((random(0,1)*2)-1)) //Randomly -1 or 1! TNT1 A 0 A_Jump(256, "Fly") Lying: "----" A 1 A_JumpIf(GetCVar("bd_janitor") == 1, "Expiring") //If the janitor cvar is on, skip the infinite frame and go away after a random time instead "----" A -1 Expiring: "----" A random(60, 600) TNT1 A 0 A_SpawnItemEx("CoolAndNewFlameTrailsLong", 0, 0, 0, 0, 0, 0) Stop } }

This is standard behaviour for all gibs - all each individual one has to do is implement its own Fly and Death labels (Death being called when it lands on the ground). Here's one for the imp's arm.

BdGibImpArm class
ACTOR BdGibImpArm : BdGib { States { Fly: HND4 A 4 A_SpawnProjectile("BdFlyingBloodTrailStrong", 0, 0, random (0, 360), 2, random (0, 360)) TNT1 A 0 A_SetRoll(roll + user_rotationspeed) Loop Death: TNT1 A 0 A_SpawnItem("BdBloodSpot",0,0,0,1) TNT1 AAA 0 A_CustomMissile ("BdFlyingBloodSmall", 0, 0, random (0, 360), CMF_AIMDIRECTION, random (0, 160)) TNT1 A 0 A_SetRoll(0) HND4 A 1 Goto Lying } }

A Fly label that leaves some type of blood trail as it moves, a Death state that spawns a blood spot and optionally some extra splats then hands things over to the parent Lying label, and that's really it - they're simple to implement for new monsters if you need ones that look unique.