ZScript virtual functions

From ZDoom Wiki
Jump to navigation Jump to 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.

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

Class ActB : ActA
    int b;
    override void 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()

Internal Functions

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

Some of these govern fairly basic actor functionality and may produce unintended side effects or behaviours if overridden. Please test thoroughly whenever you override these (or call them in some unusual place, e.g., CanCollideWith() in some custom missile impact code), and if you don't know exactly what a virtual does you might want to call super.<nameofvirtualfunction>() in your override until you've had time to check the GZDoom source code to figure out what (if anything) it does by default.


  • void ChangeStatNum(int stat)
(Need more info)
  • 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.
WARNING: Due to quirks in the Doom weapon/inventory code (a state change directly calls the function attached to the state instead of queuing it), there is no guarantee that PostBeginPlay runs before any state. Timing-critical operations should not rely on this assumption, and would be better deferred for a few tics into the weapon/inventory's existence.
  • 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)


  • 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 BeginPlay()
Called just after the actor is created. Note this is before any of the default properties are established.
  • 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.
WARNING: This function assumes, without providing any feedback in the event it is not so, that the caller and the "other" are the same before and after the call. Do not destroy, damage or perform any complex alterations of either actor within this call, as doing so may cause deyncs and memory leaks.
  • int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags = 0, double angle = 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 defensive damagefactors on the actor receiving damage in general.
  • 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_NO_ENHANCE - Bypasses PowerDamage 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).
  • DMG_EXPLOSION - Designates the damage as an explosion (splash) damage. This does not make the function perform an explosion attack. If that is what is desired, use A_Explode, instead.
  • angle - Default is 0. Sets the absolute angle for thrusting enemies from the damage if DMG_USEANGLE is used.
  • void Deactivate(actor activator)
The opposite of Activate.
  • activator - the actor responsible for deactivating this actor.
  • 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.
  • 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.
  • int OnDrain (Actor victim, int damage, Name dmgtype)
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.
            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 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.
  • bool Slam(Actor victim)
Called when an actor that has the SKULLFLY touches another. Normally called by Lost Souls, Maulotaurs and monsters pushed away by Discs of Repulsion.
  • 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.
  • int 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 Touch(Actor toucher)
Called when an actor with the SPECIAL flag gets touched by another. Normally only used by Inventory and SpectralMonster.
  • toucher - The actor touching the caller.
  • bool Used (Actor user)
  • string GetObituary (Actor victim, Actor inflictor, Name mod, bool playerattack)
  • clearscope int GetMaxHealth (bool withupgrades = false) const


  • void AttachToOwner(Actor user);
(Verification needed) Makes the item part of user's inventory. Includes when you pick it up off the ground, when it's given by the give command or A_GiveInventory, or when you spawn with it as a startitem. Is not called when you pick up or otherwise receive more of an item you already have; if you need something to work then as well, you may consider using CustomInventory pickup states.
  • Inventory CreateCopy(Actor other);
(Verification needed) Creates a copy of the item to attach to an owner on pickup.
  • Inventory CreateTossable(int amount);
(Verification needed) Spawns the item when it is tossed from inventory.
  • void DetachFromOwner();
(Verification needed) Called anytime the item is fully removed from owner's inventory, whether by being tossed, destroyed or taken away entirely. Is not called when only some of the total amount is being dropped or removed (i.e., the inventory actor itself is remaining on the owner afterwards tracking the reduced amount).
  • void DoEffect();
A Tick()-like function that is called every tic that an inventory item is attached to an owner, e.g., in powerups. This should be used instead of Tick() when you only need certain actions to be taken while an owner is holding the item.
WARNING: RNG calls inside DoEffect() are handled differently than on a regular actor and can cause a desync in netgames. Use an identifier (e.g., random[myrando](0,100)) and test this in a netgame before relying on a random number inside a DoEffect() override.
  • color GetBlend ();
Returns the color of the specified blend for the powerup effect.
  • bool GetNoTeleportFreeze() { return false; }
(Need more info) Returns false by default.
  • double GetSpeedFactor() { return 1; }
(Need more info) Returns 1 by default.
  • bool HandlePickup(Inventory item);
(Verification needed) Returns true if item could be picked up
  • void OwnerDied () {}
Called upon the owner's death.
  • String PickupMessage();
Returns the pickup message string.
  • void PlayPickupSound(Actor user);
Causes user to play the pickup sound defined on it.
  • bool ShouldStay();
(Need more info)
  • bool SpecialDropAction (Actor dropper);
(Need more info)
  • bool Use (bool pickup);
Returns true if the item is used, false otherwise.
  • void AbsorbDamage (int damage, Name damageType, out int newdamage)
  • void ModifyDamage (int damage, Name damageType, out int newdamage, bool passive, Actor inflictor = null, Actor source = null, int flags = 0)
  • void OnDrop (Actor dropper)


  • 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.
  • virtual Name ChooseSpawn()
Determines the actor to spawn, returning its class name to the calling function to be spawned. If the returned name is None, nothing is spawned, and if it is Unknown, an instance of the Unknown class is spawned, indicating an error.


These can all be found in wadsrc/static/zscript/shared/player.txt.
WARNING: Be very careful about directly overriding some virtual player functions like HandleMovement(), MovePlayer(), CheckJump(), CheckCrouch() and similar. They occur in PlayerThink() before some other checks such that, if you make any significant changes in those virtuals, they interfere with or are ignored by those subsequent checks in a way that can cause a desync. Unless you really know what you're doing or you're completely replacing everything it may be advisable to put your effects somewhere else.
The Play* functions play certain playerpawn states.
  • void PlayAttacking()
  • void PlayAttacking2()
This is the one with the muzzle flash.
  • void PlayIdle()
  • void PlayRunning()
  • bool CanCrouch()
  • void CheckAirSupply()
  • void CheckCheats()
  • void CheckCrouch()
  • void CheckDegeneration()
  • void CheckFOV()
  • bool CheckFrozen()
  • void CheckJump()
  • void CheckMoveUpDown()
  • void CheckPitch()
  • void CheckPoison()
  • void CheckUndoMorph()
  • void CheckWeaponChange()
  • void CrouchMove(int direction)
Handles moving up and down to and from crouched.
  • void DeathThink()
  • void FireWeapon()
  • void FireWeaponAlt()
  • void HandleMovement()
  • void MovePlayer()
  • void MorphPlayerThink()
  • void OnRespawn()
  • void PlayerThink()
  • void TickPSprites()


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