Choose result of ThinkerIterator

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
Post Reply
User avatar
Apeirogon
Posts: 1605
Joined: Mon Jun 12, 2017 12:57 am

Choose result of ThinkerIterator

Post by Apeirogon »

How choose one randomly actor founded by ThinkerIterator?
I need find all child of current actor and then perform warp of master to one randomly chosen child, until something, player, dont stop it by killing it. Better say, save all founded actor and give to them some pointer available from any part of a mod.
How do I do so?
User avatar
Apeirogon
Posts: 1605
Joined: Mon Jun 12, 2017 12:57 am

Re: Choose result of ThinkerIterator

Post by Apeirogon »

Where all GLORIUS ZSCRIPT MASTER RACE?
Is it even possible?
User avatar
AFADoomer
Posts: 1324
Joined: Tue Jul 15, 2003 4:18 pm
Contact:

Re: Choose result of ThinkerIterator

Post by AFADoomer »

Untested code, but the function should essentially do what you want. Just don't call it too often, because too many calls of ThinkerIterator can slow down processing to a crawl...

Code: Select all

class MyActorThatWarpsToChildren : Actor
{
    States
    {
        ...
        Warp:
            UNKN A 1 A_DoRandomWarp();
            Goto See;
    }

    void A_DoRandomWarp()
    {
        Array<Actor> Children;

        ThinkerIterator ChildFinder = ThinkerIterator.Create("Actor", Thinker.STAT_DEFAULT);
        Actor mo;

        while (mo = Actor(ChildFinder.Next()))
        {
            if (mo.master == self)
            {
                Children.Push(mo);
            }
        }

        if (Children.Size < 1) { return; }

        Actor warptarget = Children[Random(0, Children.Size - 1)];

        if (warptarget)
        {
            Warp(warptarget);
        }
    }
} 
User avatar
Apeirogon
Posts: 1605
Joined: Mon Jun 12, 2017 12:57 am

Re: Choose result of ThinkerIterator

Post by Apeirogon »

So I cant save pointer to all found childen one time, and then just check if it alive!?
Or every Children%_number_% personifies its own actor?
User avatar
AFADoomer
Posts: 1324
Joined: Tue Jul 15, 2003 4:18 pm
Contact:

Re: Choose result of ThinkerIterator

Post by AFADoomer »

Here's a slightly modified version that lets you find all of the children once and then reference the array of pointers from then on:

Code: Select all

class MyActorThatWarpsToChildren : Actor
{
    Array<Actor> Children; // Array that is used to store pointers to all child actors

    States
    {
        ...
        SomeStateAfterChildrenSpawned:
            UNKN A 1 A_CollectChildren();
            Goto See;
        Warp:
            UNKN A 1 A_DoRandomWarp();
            Goto See;
    }

    void A_CollectChildren()
    {
        Children.Clear(); // Clear the Children array, in case this gets called more than once

        // Find all Actor thinkers
        ThinkerIterator ChildFinder = ThinkerIterator.Create("Actor", Thinker.STAT_DEFAULT); 
        Actor mo;

        // Loop through all of the actors...
        while (mo = Actor(ChildFinder.Next()))
        {
            // ...and find any actors that have this actor set as their master
            if (mo.master == self)
            {
                Children.Push(mo); // Push a pointer to the found actor into the Children array
            }
        }
    }

    void A_DoRandomWarp()
    {
        if (Children.Size < 1) { return; } // If there aren't any children, don't bother running the rest of the code

        int targetindex = Random(0, Children.Size - 1); // Pick a random index into the Children array

        if (Children[targetindex] && Children[targetindex].health > 0 ) // If the array index is a valid actor and the actor has health...
        {
            Warp(Children[targetindex]); // ...warp to the actor's location
        }
        else
        {
            Children.Delete(targetindex); // If it was dead or invalid, delete it from the Children array so we don't have to deal with it again
        }
    }
}  
Basically, when you tell the actor to call A_CollectChildren, the Children array will be populated with pointers to all actors that have this actor set as their master. There is no internal list of children maintained by the engine; every A_*DoSomethingto*Children function uses an iterator internally.

The A_DoRandomWarp function picks a random index in the array (so, a random pointer to a child), checks if the health is greater than 0, and warps to the actor's location... If it wasn't valid, the child pointer is deleted from the array.
User avatar
Apeirogon
Posts: 1605
Joined: Mon Jun 12, 2017 12:57 am

Re: Choose result of ThinkerIterator

Post by Apeirogon »

Thanks.
Looks like I need read chapter "using array in C++"...
User avatar
AFADoomer
Posts: 1324
Joined: Tue Jul 15, 2003 4:18 pm
Contact:

Re: Choose result of ThinkerIterator

Post by AFADoomer »

That'd probably be useful... There's a [wiki=Dynamic_arrays]wiki page[/wiki] with a pretty good breakdown of the various commands that you can use.

The very basics that are used here:
  • Declaration: Array<type> ArrayName; - "type" determines what the array is of... Can be any class/type (int, string, Thinker, ACtor, ZombieMan, etc.)
  • ArrayName[x] - access array member at index 'x'... So, 'ArrayName[3]' will give you the 4th member of the array (zero-based numbering, so 0 is the first).
  • ArrayName.Push(whatever) - adds 'whatever' to the end of the array
  • ArrayName.Delete(i) - deletes the pointer at index 'i' from the array
  • ArrayName.Size - returns how many values are in the array... Note that this is one off from the maximum index of the array due to the index numbers starting at 0, not 1
  • ArrayName.Clear() - deletes everything from the array
Post Reply

Return to “Scripting”