Using pointers in ZScript

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


Actor pointers (target, master and tracer) are available for every actor class, but more than that can be defined similarly to C++. They can be declared in the actor's states or globally to that actor.

Unlike DECORATE, there is no safety fallbacks when accessing pointers. If no pointer exists and an attempt to access a non-existant entity's property is performed, the game will end with a console message indicating where in the code it happens. It is important to check for an existing pointer before attempting to access it, which can be done by simply checking the name of the pointer, like below.

Class PointerImp : DoomImp
{
    int OtherHealth;
    Actor ptr; // Class-wide scope. Accessible from any part of this actor or other actors with proper casting.
    States
    {
    See:
        TROO AABBCCDD 3
        {
            Actor ptr2 = target; // State scoped pointer that will only exist here in this anonymous function.
            if (ptr2)            // Null pointer check. If it exists, this returns true. Otherwise, this will not be executed.
            {
                A_LogInt(ptr2.health); // Gets ptr2's health and logs it.
                if (ptr2.target)
                {
                    // Gets the target's target pointer, if it has one and if we have an existing target.
                    ptr = ptr2.target;

                    if (ptr) // Always check for existence.
                    {
                        OtherHealth = ptr.health;
                        A_LogInt(ptr.health);
                    }
                }
            }
            A_Chase();
        }
        Loop;
    }
}

Casting

ZScript pointers can be given specific class casts to allow access to that class's variables and functions, if they are declared in the class's scope.

"let" is an automatic class deduction type which will resolve a class dynamically, and declares a variable.

// The variable 'ptrimp' will be null if 'target' is not a PointerImp class.
let ptrimp = PointerImp(target);
if (ptrimp)
{
    // Now it's possible to get the class-specific variable, provided the scope is class-wide and not made in the states.
    A_LogInt(ptrimp.OtherHealth); 
}

Inventory

Inventory items require the use of invoker in order to change variables.

Class MyVarChanger : CustomInventory
{
    int myvar;
    States
    {
    Pickup:
        TNT1 A 0
        {
            invoker.myvar = 1; // Changes THIS actor's 'myvar' variable. Not the one doing the picking up!
        }
        Stop;
    }
}

Inventory items of any kind may also modify the owner's properties and/or vars. This is done by declaring a specific actor type. In the following example, the let keyword is used for redundancy reduction.

// An actor who possesses 'myvar'.
Class SpecMarine : DoomPlayer
{
    int myvar;
}

// Then, in a customized weapon or some inventory actor when owned:
Class MyVarChanger : CustomInventory
{
    States
    {
    Pickup:
        TNT1 A 0
        {
            let ownr = SpecMarine(invoker.owner); // Auto casts to the specified actor.
            if (ownr)                             // Make sure it exists.
            {
                ownr.myvar = 1;                   // Change the owner's manual.
            }
        }
        Stop;
    }
}


See also