ThinkerIterator

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


ThinkerIterator is an internal class in ZScript, inheriting from Object.

This class is used for searching through descendants of thinkers. A_GiveToChildren is one of the many functions which uses this.

Functions

Return Type Function Arguments (first to last) Use/Arguments
ThinkerIterator Create
  1. class<Object> type = "Actor",
  2. int statnum =
Thinker.MAX_STATNUM + 1

Initializes the iterator.

  • type - Serves as a filter. Specifying a classname here will only search for this type of class and descendants. Default is Actor.
  • statnum - Sets the specific statnum to be searched. The default is MAX_STATNUM+1, meaning the iterator will search through all of the statnums. If only actors or thinkers in the game simulation are desired, consider setting this to STAT_DEFAULT to save on time an efficiency where all actors are regularly stored, except for inventory. See Thinker for more information.

Note: this function is static and should be called off the class name, i.e. ThinkerIterator.Create(...).

Thinker Next
  1. bool exact = false

Cycles through the list of existing actors, filtered out by the Create() function.

  • exact - If true, disables ancestry checking. Note that ancestry checking is just like CheckClass.
void Reinit None Restarts the search.

Example

In this example, an iterator is used during a Tick override on a morphed actor to allow key gathering, despite -PICKUP being set on the player.

// Think of this as A_CheckProximity, but with less limitation.
// However, we have to invent all the checks in order to use it
// properly.

// So, create an iterator that searches for D4KeyBase-inheriting
// only.
ThinkerIterator KeyFinder = ThinkerIterator.Create("D4KeyBase");
Actor mo;
while (mo = D4KeyBase(KeyFinder.Next()))
{
    // Make sure it can be touched.
    double blockdist = radius + mo.radius;
    if (abs(pos.x - mo.pos.x) > blockdist || abs(pos.y - mo.pos.y) > blockdist)
    {    continue;    }
       				
    // So we're in range horizontally. What about vertically?
    if (pos.z + height < mo.pos.z || mo.pos.z + mo.height < pos.z)
    {    continue;   }
       
    // Execute any specials this thing had.				
    if (mo && mo.special)
    {
        A_CallSpecial(mo.special, mo.args[0], mo.args[1], mo.args[2], mo.args[3], mo.args[4]);
    }

    // Assemble the arrays only if we succeed. This first array
    // contains the actor's hard names.
    static const Class<Actor> KeyName[] =
    {
        "D4RedCard",
        "D4YellowCard",
        "D4BlueCard",
        "D4RedSkull",
        "D4YellowSkull",
        "D4BlueSkull"
    };
       
    // Contains the nice names for logging.
    static const String NiceKeyName[] =
    {
        "Red Card",
        "Yellow Card",
        "Blue Card",
        "Red Skull",
        "Yellow Skull",
        "Blue Skull"
    };

    // In the event someone decides to screw with the keys, check the base class.
    for (int index = 0; index < 6; index++)
    {
        if (mo.CheckClass(KeyName[index], DefPtr, true))
        {
            //Concatenate a string with .. (two periods)
            A_Log(NiceKeyName[index].." Found");
            break;
        }
    }
       
    // Grabs the actual key and gives it to the player. This would
    // be the same as if I had done A_GiveInventory(KeyName[Index])
    // inside the for loop and if block. However, if done above, it
    // wouldn't be safe as D4D mods could possibly modify them.
    // This ensures nothing is missed so long as they inherit from
    // D4KeyBase. The worst that will happen, they simply don't have
    // a pickup message attached. No big deal.
       
    Class<D4KeyBase> keypick = (Class<D4KeyBase>)(mo.GetClass());
    A_GiveInventory(keypick,1);
    mo.A_Remove(DefPtr,RMVF_EVERYTHING);
    
}

See Also