Page 1 of 1

After death event handler without items

Posted: Sun Sep 26, 2021 12:40 pm
by zdusr
Hi!

Ever wanted to make script to handle corpse after it's death? To fade it out or do any other things? If you have you may have suggested to give that monster some kind of special item that does stuff that you want after the monster is dead. However I personally dont like the idea of creating dummy items as it kinda seems like some hack or workaround. And also to beginner modder like me giving item to monsters adds extra complexity. Keep in mind that zscript does not have delay or sleep functions so if you need these then you might still need to give monsters items but for simpler stuff this tutorial here seems to be easier solution.

So here is how you can do stuff with corpse after it's death without having to give them any item:
1) You you add all dead monsters to the list on the moment they die using WorldThingDied event.
2) You iterate that list later in WorldTick event

Check out zdoom wiki for more info about events: https://zdoom.org/wiki/Events_and_handlers

Now let's take a look at greater detail:

1) Create zscript.txt to include your zscript:

Code: Select all

version "4.5.0"
#include "Source/tutorial.zs"
2) Create mapinfo to make your events called by zdoom:

Code: Select all

gameinfo {
  AddEventHandlers = "ComboEventHandler"
}
3) Create source/tutorial.zs. Read comments in code for more explanation.

Code: Select all

// Tip: You can use zscript plugin for VS Code if you want syntax highlighting

// You also need the event 
// handler defined in MAPINFO for event handlers to work



// For more complex data structures we need either struct or class.
// Zscript does not allow you to create dynamic array of structs therefore we use
// class instead.
// In this class we have 2 fields actor and tick.
// We use field actor to remember our dead actor
// We use tick to remember when actor died
//   * remember 35 ticks is 1 second in game in case you want to time events later

Class DeathInfo : Object {
    Actor actor;
    int tick;
}

Class ComboEventHandler : EventHandler
{
    // Array where we keep dead monsters
    Array<DeathInfo> deadMonsters;
    // Integer to keep track of how many ticks have passed since game start
    int currentTick;


    // https://zdoom.org/wiki/Events_and_handlers
    // WorldThingDied gets called every time some actor dies 
    Override void WorldThingDied(WorldEvent e)
    {
        If(e.Thing && e.Thing.bIsMonster) // Make sure e.Thing actually exists
        {
           DeathInfo info = new("DeathInfo"); //Create new class instance.
           info.actor = e.Thing;
           info.tick = currentTick;
           deadMonsters.Push(info); // add to our list
        }
    }

    // WorldTick gets called at the beginning of each tick, 35 times per second. 
    // In this example we use it to delete dead monsters 1 second after their death.
    // You can also use it to make a fade out effect or what ever you wish.
    // Keep in mind that there is no sleep function in zscript and you need other workarounds.
    override void WorldTick(){
        // skip code executon if there is no elements.
        // Additionally you could add currentTick % 35 == 0 to run code inside
        // if statement only once every socond.
        // Depending on what mod you are doing you should consider what
        // performance optimizations you might need here.
        // Slaughtermaps can easily be 20k monsters so make sure your mod does not become a problem here.
        if(deadMonsters.Size() > 0) {

            // We want to remove deleted monsters from original list so we are using
            // This list to temporarily store elements that we did not choose to delete yet
            Array<DeathInfo> updatedDeadMonsters;

            for (int i = 0; i < deadMonsters.Size(); i++) {

                // require that monsters have  been dead for at least certain amount of time before
                // we start processing it. 
                // In this example we require that monster would be dead at least 1 second (35 tics).
                if(currentTick - deadMonsters[i].tick >= 35) {
                    if(deadMonsters[i].actor){
                        // Delete monster
                        deadMonsters[i].actor.A_Remove(0);
                    }
                }else {
                    // add back all those monsters that we did not delete this time yet.
                    updatedDeadMonsters.Push(deadMonsters[i]);
                }
            }
            Console.printf(" Tick: %d, num monsters dead %d", currentTick, deadMonsters.Size());

            // basically here we want to do deadMonsters = updatedDeadMonsters
            // but since zscript does not have assignment operator for dynamic arrays,
            // we need some workaround
            //
            // https://zdoom.org/wiki/Dynamic_arrays
            deadMonsters.Move(updatedDeadMonsters);
        }
        // keep track
        currentTick += 1;
    }

}