ZScript virtual functions

From ZDoom Wiki
Jump to: navigation, search
Note: This feature is for ZScript only.

Virtual functions in ZScript are functions designed for inheritance purposes, which allow for child classes to override them with their own version. This grants the ability to also call the super function which will execute everything in the predecessor class's function.

Class ActA : Actor
{
    int a;
    virtual void MyVirtualFunction()
    {
        // Do some stuff here.
        a++;
    }
}

This class will perform a++ and b++, with b++ going first.

Class ActB : ActA
{
    int b;
    override void MyVirtualFunction()
    {
        b++;
        Super.MyVirtualFunction();
    }
}

Note: Through chaining actors via inheritance, it's possible to execute every version down to the base actor, if they're set up to call the super function. The following example demonstrates the variables 'c', then 'b', and finally 'a' being incremented in that order.

Class ActC : ActB
{
    int c;
    override void MyVirtualFunction()
    {
        c++;
        Super.MyVirtualFunction();
    }
}

Internal Functions

Some of ZDoom's classes have several functions available for overriding if desired.

Note: Avoid calling the following virtual functions directly. These may produce unintended side effects or behaviors.


Thinker

  • void Tick()
Called every tic, 35 times a second. As the name implies, this is what makes an entity 'tick', or operate on its own.
WARNING: On PlayerPawn actors, serious problems can happen if voodoo dolls are present and the Tick function is overridden without proper handling. The following code below prevents this from happening and should be applied to the very beginning of the Tick function before anything else.
if (!player || !player.mo || player.mo != self)
{
	Super.Tick();
	return;
}
  • void PostBeginPlay()
Called after BeginPlay and before the very first tic is played. This is done before the very first Spawn/Use/Pickup/etc state is ever reached, useful for performing one-time setups like giving local variables a value, without worrying about a monster being dormant at the start and going to Deactivate instead of Spawn.
  • void ChangeStatNum(int stat)
(Verification needed)

Actor

  • void BeginPlay()
Called just after the actor is created. Note this is before any of the default properties are established.
  • void Activate(actor activator)
Called upon an actor that, for monsters, will remove the DORMANT flag and enable them. Overriding this can allow special behaviors to occur on actors not affected by dormancy.
  • activator - the actor responsible for activating this actor.
  • void Deactivate(actor activator)
The opposite of Activate.
  • activator - the actor responsible for deactivating this actor.
  • int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags = 0, double angle = 0) (New from 2.4.0)
Called by the actor whenever it takes damage.
  • inflictor - The actor pointer dealing the damage. Missiles are used here, with their owners being the source.
  • source - The actor pointer which claims responsibility for the damage, responsible for causing infighting.
  • damage - The amount of damage to deal out.
  • mod - The 'means of death', or the damagetype.
  • flags - Default is 0. Flags can be combined using the '|' symbol (without quotes):
  • DMG_NO_ARMOR - Ignores armor protection.
  • DMG_INFLICTOR_IS_PUFF - Used by bullet and rail attacks to clarify if the puff is the inflictor (with this flag) or the source (without).
  • DMG_THRUSTLESS - Doesn't thrust the actor. DMG_USEANGLE flag is ignored as a result.
  • DMG_FORCED - Ignores all damage negation flags/properties such as NODAMAGE and goes straight to reducing their health. Players with the NODAMAGE flag, god2 or buddha2 cheats are immune due to potential abuse.
  • DMG_NO_FACTOR - Ignores damagefactors.
  • DMG_PLAYERATTACK - (Need more info)
  • DMG_FOILINVUL - Behaves just like the FOILINVUL actor flag -- bypasses the INVULNERABLE flag.
  • DMG_FOILBUDDHA - Behaves just like the FOILBUDDHA actor flag -- bypasses the BUDDHA flag.
  • DMG_NO_PROTECT - Bypasses PowerProtection powerups.
  • DMG_USEANGLE - The function will use the angle parameter instead of thrusting the actor in the direction away from the inflictor (or source if no inflictor).
  • angle - Default is 0. Sets the absolute angle for thrusting enemies from the damage if DMG_USEANGLE is used.
  • void DoSpecialDamage(Actor target, int damage, name damagetype)
Applies poison for old-style poison damage, but otherwise does nothing else. Used in P_DamageMobj. PoisonBolt uses this to modify its damage amount to instant kill (health of target + 10) if the target is not a boss, 50 otherwise.
  • target - The actor to check.
  • damage - The damage intended to be dealt by this actor.
  • damagetype - The name of the type to apply.
  • void TakeSpecialDamage(Actor inflictor, Actor source, int damage, Name damagetype)
Called during damage processing. This occurs after damagefactors and PowerProtection are taken into account. This is bypassed by telefrag damage amount (1 million+) unless LAXTELEFRAGDMG is used. This function is also only called if the actor can actually take that damage and have their health lowered by it.
  • inflictor - The actor dealing the actual damage.
  • source - The actor to 'blame' for the damage, for infighting. Missiles set this to their owners (target pointers).
  • damage - The amount of damage to process.
  • damagetype - The name of the type applied to it.
  • void Die(Actor source, Actor inflictor, int dmgflags = 0)
Called when an actor is supposed to die.
  • dmgflags - Only used for obituaries, passed in by P_DamageMobj.
  • bool Slam(Actor victim)
Called when an actor is blasted away and hits another.
  • void Touch(Actor toucher)
Called when one actor touches another. This generally only works on inventory items and a few Strife enemies, the "toucher" being the thing moving in to it that has the appropriate flag (Verification needed). For a more flexible version, consider using CanCollideWith (see below).
  • bool SpecialBlastHandling (Actor source, double strength)
Called when an actor is to be reflected by a disc of repulsion. Returns true to continue normal blast processing.
See the examples for how MageStaffFX2 utilizes this function.
  • int SpecialMissileHit (Actor victim)
Called when a missile impacts an actor. Returning 1 tells the missile to keep going instead of exploding, while -1 signifies the missile to die.
See the example section below on how MageStaffFX2 utilizes this functionality to pass through some actors.
  • bool CanCollideWith (Actor other, bool passive)
Called upon two actors based on which is doing the colliding. See the examples section on how this can be used.
  • other - The actor to be checked against.
  • passive - Used depending on which actor is performing the move. This is false if the call is coming from the actor performing a move into another actor's blocking radius and height, and true if the other way around.
NOTE: This will only be called if regular actor blocking is not bypassed entirely with the use of flags like THRUACTORS or an object lacking SOLID while not having BLOCKEDBYSOLIDACTORS, etc. This function is also before item pickup checking and can be used to create specialized pickup attempts if needed. If both actors return true, they are capable of colliding and will block each other. Otherwise, if either one returns false, both actors will disable collisions for both actors.
Called when an actor is draining health from another actor. By default, the function returns the amount of health being drained.
  • victim - the actor whose health is being drained.
  • damage - the amount of health being drained.
  • dmgtype - the damage type of the attack which the victim received.
Note that since currently only players can drain health, thanks to PowerDrain, the function is only useful to be overridden in a player's actor definition.
class ExamplePlayer : DoomPlayer
{
    override int OnDrain (Actor victim, int damage, Name dmgtype)
    {
        // If the victim is a boss, i.e has the BOSS flag, cut the drained health by half.
        if(victim.bBoss)
        {
            damage /= 2;
        }

        // If the damage type of the attack is ice, boost the drained health by 50%.
        if(dmgtype == 'Ice')
        {
            damage = int(damage * 1.5);
        }

        return damage;
    }
}
  • void OnDestroy()
Called when an actor is about to be removed from the game. This could be used for actor maintenance, such as removal of children actors which would otherwise stop functioning without the master, or special effects that may be associated with that actor in particular.
  • bool Used (Actor user)
Called when someone 'uses' the actor, but only if they do NOT have the USESPECIAL flag. Default result returns false.
  • user - The actor 'using' the caller.

Inventory

  • bool Use (bool pickup);
Returns true if the item is used, false otherwise.
  • color GetBlend ();
Returns the color of the specified blend for the powerup effect.
  • bool HandlePickup(Inventory item);
(Verification needed) Returns true if item could be picked up
  • Inventory CreateCopy(Actor other);
(Verification needed)
  • Inventory CreateTossable();
(Verification needed)
  • bool SpecialDropAction (Actor dropper);
(Verification needed)
  • String PickupMessage();
Returns the pickup message string.
  • bool ShouldStay();
(Verification needed)
  • void DoEffect();
A replacement function for Tick() which is used when an inventory item is active and performing, especially in powerups. This should be used instead of Tick() when said powerups are active on an actor.
  • void PlayPickupSound(Actor user);
Causes user to play the pickup sound defined on it.
  • void AttachToOwner(Actor user);
(Verification needed)
  • void DetachFromOwner();
(Verification needed)
  • double GetSpeedFactor() { return 1; }
(Verification needed) Returns 1 by default.
  • bool GetNoTeleportFreeze() { return false; }
(Verification needed) Returns false by default.

RandomSpawner

(New from 2.4.0)

  • void PostSpawn(Actor spawned)
Called after spawning the actor spawned for allowing further modification of the actor. This is useful for ensuring things like TID, flags (i.e. DORMANT for randomizer mods), etc) are transferred over before the spawned actor can even think for the first time.
  • spawned - The pointer to the actor created. All changes done to the actor are after the spawned actor's BeginPlay, but before PostBeginPlay to allow maximum compatibility with mods that make extensive use of TID checking.

Examples

The following demonstrates how SpecialMissileHit works on MageStaffFX2.

override int SpecialMissileHit (Actor victim)
{
	if (victim != target && !victim.player && !victim.bBoss)
	{
		victim.DamageMobj (self, target, 10, 'Fire');
		return 1;	// Keep going
	}
	return -1;
}

The following demonstrates how SpecialBlastHandling is performed with the Disc of Repulsion.

override bool SpecialBlastHandling (Actor source, double strength)
{
    // Reflect to originator
    tracer = target;	
    target = source;
    return true;
}

The following demonstrates how CanCollideWith can be used:

//--------------------------------------------------------------------------
// Disable collisions on some actors.
//--------------------------------------------------------------------------

override bool CanCollideWith(Actor other, bool passive)
{
    // Non-passive means the one moving into the other is performing the checks.
    if (!passive)
    {
        if (!other)		
            return false;
	
        // Pass through dead things. There is a difference between this and CORPSE.
        if (other.bKILLED)
            return false;
		
        // Solid obstacles must block.
        if (other.bSOLID && !other.bNONSHOOTABLE && !other.bSHOOTABLE)
            return true;
		
        if (other.bSHOOTABLE && (other.bFLOAT || other.bNOGRAVITY))
            return false;

        // Walk over 'em if they're small enough.
        if (other.Height <= 75 && other.Radius <= 60)
            return false;

        // Pass through different species of select types.
        if (other.GetSpecies() == 'CommonInfected')
            return false;
    }
    // We don't really care about others making the check.
    return true;
}

See also