Does the RealGibs Actor do anything any more?

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!
Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
Post Reply
User avatar
Enjay
 
 
Posts: 27377
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

Does the RealGibs Actor do anything any more?

Post by Enjay »

The RealGibs actor is supposed to be the small blood pool that appears when a dead body is crushed under a door. It shares a sprite (POL5A0) with the Gibs actor (EdNum 24) which is a map placeable decoration version of the blood pool.

In the past, when an enemy was crushed under a door, it would be replaced by the RealGibs actor. I think we are talking a really long time ago in earlier versions of ZDoom (no G) before DECORATE.

Anyway, I don't think this happens any more - so I just wanted to check that I am correct in my assumptions.


The base ACTOR class in ZScript has its own "GenericCrush" state sequence:

Code: Select all

	GenericCrush:
		POL5 A -1;
		Stop;
So, when a monster dies and gets crushed under a door, I *think* it just jumps to that state label and shows POL5A0 within its own (inherited) actor definition rather than spawning a RealGibs actor (unless, of course, the monster has its own crush state sequence - in which case that will be used instead).

I've tested this by defining a replacement for the RealGibs Actor:

Code: Select all

CLASS NJRealGibs : ACTOR replaces RealGibs
{
	Default
	{}
	
	States
	{
	Spawn:
		SOUL A -1;
		Stop;
	}
}
If I type summon realgibs at the console, as expected, an actor that looks like a non-animated soul sphere appears. This indicates that my replacer actor works.

If I then kill an enemy (Zombieman, DoomImp, whatever) under a door and allow the door to close on the fallen enemy, the POL5A0 sprite appears - indicating that there was no attempt to spawn the RealGibs actor.

So, am I right in saying that the RealGibs actor is effectively now just a relic of older ZDoom, that it probably never appears in game, and that all classes derived from ACTOR use the GenericCrush state sequence from the parent ACTOR class instead?

If so, I'm assuming that RealGibs is probably only kept around for potential compatibility reasons?


In saying all of the above, the line:

Code: Select all

PClassActor *i = PClass::FindActor("RealGibs");
exists in pmobj.cpp but I don't really know what that does - if it is even ever called any more.
ZzZombo
Posts: 332
Joined: Mon Jul 16, 2012 2:02 am

Re: Does the RealGibs Actor do anything any more?

Post by ZzZombo »

The conditions for placing the gibs actor are as follows:

* The actor is eligible for gibing at all (is not marked as `+DONTGIB`, etc).
* The actor doesn't have both `Crush` and `GenericCrush` states, or they all do not have sprites. This is simplified, because the code repeatedly sets the `state` variable to `NULL` based on various checks.
* The actor bleeds.
* The replacement gibs actor (which may be the original, if none are present) is defined and has sprites in the spawn state, which also has to be present.
* The replacement gibs actor successfully is placed in the level, passing all generic spawning checks of the engine.
User avatar
phantombeta
Posts: 2198
Joined: Thu May 02, 2013 1:27 am
Operating System Version (Optional): Windows 10
Graphics Processor: nVidia with Vulkan support
Location: Brazil

Re: Does the RealGibs Actor do anything any more?

Post by phantombeta »

It gets used if:
  • The actor is a player
  • The actor undefines the GenericCrush state label

    Code: Select all

    	GenericCrush:
    		stop;
    
  • The sprite used by the GenericCrush state isn't defined (The one defined in Actor uses POL5 A)
  • The actor has the ICECORPSE flag but doesn't have the NOBLOOD flag (this is a weird side effect- ice deaths set ICECORPSE and NOBLOOD, and the code seems to expect both together. Actors with only NOBLOOD just disappear, actors with NOBLOOD and ICECORPSE run special behaviour for the latter flag when crushed)
These were the only situations I could see where it's still used, but I could have missed one.
ZzZombo
Posts: 332
Joined: Mon Jul 16, 2012 2:02 am

Re: Does the RealGibs Actor do anything any more?

Post by ZzZombo »

This doesn't match the linked code. `GenericCrush` isn't used if `Crush` is defined and will never be used if the actor is a player or doesn't bleed. So assuming we have a corpse of a player, the next branch is only executed if the `Crush` state sequence is defined on the actor, effectively, and it is not frozen solid, leading to an early return after having made the actor unsolid and put into the state. Otherwise, if the actor bleeds, it may potentially spawn the separate gibs actor. So for the purposes of the question, whether the actor is a player or not is only relevant to the code path that deals with the `GenericCrush` state, so players with a `Crush` state will still not create the gibs actor, just like removing `GenericCrush` may still potentially work out to no gibs actor, and that's the major points I noted.
User avatar
phantombeta
Posts: 2198
Joined: Thu May 02, 2013 1:27 am
Operating System Version (Optional): Windows 10
Graphics Processor: nVidia with Vulkan support
Location: Brazil

Re: Does the RealGibs Actor do anything any more?

Post by phantombeta »

ZzZombo wrote: Fri Nov 21, 2025 5:07 am This doesn't match the linked code. `GenericCrush` isn't used if `Crush` is defined and will never be used if the actor is a player or doesn't bleed. So assuming we have a corpse of a player, the next branch is only executed if the `Crush` state sequence is defined on the actor, effectively, and it is not frozen solid, leading to an early return after having made the actor unsolid and put into the state. Otherwise, if the actor bleeds, it may potentially spawn the separate gibs actor. So for the purposes of the question, whether the actor is a player or not is only relevant to the code path that deals with the `GenericCrush` state, so players with a `Crush` state will still not create the gibs actor, just like removing `GenericCrush` may still potentially work out to no gibs actor, and that's the major points I noted.
None of what I said was incorrect, I tested it ingame, and those are the circumstances where RealGibs still gets spawned.
The question was if RealGibs is still used, and if so, when. I'm sure Enjay knows how the Crush state works already, so that didn't need to be outlined, and the information I gave assuming that is correct.

But since you seem to disagree, let's walk through the code together :wink:

Code: Select all

        // [Fetch the Crush state (will be null if it doesn't exist)]
        FState * state = actor->FindState(NAME_Crush);

        // [If we're in Heretic or Chex and there's no Crush state, we just change the corpse's size]
        // In Heretic and Chex Quest we don't change the actor's sprite, just its size.
        if (state == NULL && gameinfo.dontcrunchcorpses)
        {
            // [...]
            return false;
        }

        bool isgeneric = false;
        // ZDoom behavior differs from standard as crushed corpses cannot be raised.
        // The reason for the change was originally because of a problem with players,
        // see rh_log entry for February 21, 1999. Don't know if it is still relevant.
        // [If the Crush state is null, the corpse bleeds and is not a player]
        if (state == NULL                                   // Only use the default crushed state if:
            && !(actor->flags & MF_NOBLOOD)                     // 1. the monster bleeeds,
            && actor->player == NULL)                               // 3. and the thing isn't a player.
        {
            isgeneric = true;
            // [Fetch the GenericCrush state]
            state = actor->FindState(NAME_GenericCrush);

            // [If the GenericCrush state's sprite doesn't exist, consider it invalid and set the state to null]
            if (state != NULL && (sprites[state->sprite].numframes <= 0))
                state = NULL; // If one of these tests fails, do not use that state.
        }

        // [If the state isn't null AND we're not an ice corpse (i.e., Crush state didn't exist or not allowed AND GenericCrush didn't exist, or was invalid, or not allowed (non-bleeding or a player))]
        if (state != NULL && !(actor->flags & MF_ICECORPSE))
        {
            if (actor->flags4 & MF4_BOSSDEATH)
                // [BOSSDEATH handling]
            // [Set the corpse's size and set it to the selected crush state]
            return false;
        }

        if (!(actor->flags & MF_NOBLOOD))
        {
            if (actor->flags4 & MF4_BOSSDEATH)
                // [BOSSDEATH handling]

            PClassActor *i = PClass::FindActor("RealGibs");

            // [If RealGibs' class isn't null (which will always be the case unless you mess with gzdoom.pk3, this is just defensive programming)]
            if (i != NULL)
            {
                i = i->GetReplacement(actor->Level); // [Fetch the RealGibs' replacement, if any]

                // [If RealGibs OR its replacement either 1: have no Spawn state OR 2: its sprite doesn't exist, null the gibs class]
                const AActor *defaults = GetDefaultByType (i);
                if (defaults->SpawnState == NULL ||
                    sprites[defaults->SpawnState->sprite].numframes == 0)
                {
                    i = NULL;
                }
            }

            if (i == NULL) // [If the gibs class is null, just change the corpse's size]
            {
                // [...]
                return false;
            }

            // [Spawns RealGibs or its replacement]
        }

        if (actor->flags & MF_ICECORPSE)
            // [Special ICECORPSE behaviour]
        else if (actor->player)
            // [Special player behaviour]
        else
            // [Removes the corpse if it didn't enter a crush state or GenericCrush]

        return false;       // keep checking
ZzZombo
Posts: 332
Joined: Mon Jul 16, 2012 2:02 am

Re: Does the RealGibs Actor do anything any more?

Post by ZzZombo »

I have no desire to argue with anyone. I've read through your comments, and they do not align with the code, and I have no energy to correct them.
User avatar
Enjay
 
 
Posts: 27377
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

Re: Does the RealGibs Actor do anything any more?

Post by Enjay »

OK, thanks for the input. I didn't expect it to get heated though. :shock:

So, I guess the short answer is that, yes, the actor can be used under certain circumstances, but the exact nature of those circumstances is subject to debate. I'll do a few practical tests myself to see what I come up with when I get a chance.

I hadn't even considered the player actor being different to other actors.

[Edit: On a quick test, all I can do right now-
using my soulsphere RealGibs replacer:
The player definitely spawns a realgibs actor when crushed with no modification.
A zombieman with the GenericCrush state undefined (as per PhantomBeta's example) spawns a RealGibs actor when crushed (i.e. the soul sphere sprite appears), but, as previously reported, an unmodified Zombieman does not. ]
Post Reply

Return to “Scripting”