How to Grab and Count Enemy Units?

Started by Kernel64, March 08, 2010, 01:00:10 PM

Previous topic - Next topic

Kernel64

I've seen a code somewhere within the Zerg one that grabbed units and counted them. It was for the overseer I guess. There was also one that counted ground and air.

How do I grab all enemy units, then filter them out one by one:
zealots for zealots, stalkers, colossuses, etc.

Or is it better to just count each one by making grabs for each? I don't want to use the Count enemy units one, as that is good for the AI that has default vision off.

You guys have a function for this already? I'm focusing on studying actual build orders now, and I'll share them all as soon as I get something solid. All with counters and race specifics.




turdburgler

It's done in 6.1.

//--------------------------------------------------------------------------------------------------
//AIAirThreat(int player) by turdburgler            (REACTIVE)
//will return true if the AI knows of a significant air threat
//--------------------------------------------------------------------------------------------------

int AIAirThreat(int player)
{
    int a = 0;
    int totalAirUnits = 0;

    //loop players and check if they has mad air
    while(a != 4)
    {
        if(a != player)
        {
            totalAirUnits = totalAirUnits + AIKnownUnitCount(player, a, c_TU_Battlecruiser) * 3;
            totalAirUnits = totalAirUnits + AIKnownUnitCount(player, a, c_TU_Raven);
            totalAirUnits = totalAirUnits + AIKnownUnitCount(player, a, c_TU_Banshee);
            totalAirUnits = totalAirUnits + AIKnownUnitCount(player, a, c_PU_VoidRay) * 2;
            totalAirUnits = totalAirUnits + AIKnownUnitCount(player, a, c_PU_Carrier) * 4;
            totalAirUnits = totalAirUnits + AIKnownUnitCount(player, a, c_ZU_Mutalisk);
        }

        a = a + 1;
    }

    return totalAirUnits;
}

Kernel64

#2
That should do, I guess.

If there's more cooler ones, please post. I'll be making another post for the BOs and counters in a few. And also the logic I had been thinking of for the AI.

Edit:

Does Grab include structures currently under construction? How about AIKnownUnitCount?

Aeg1s

Quote from: Kernel64 on March 08, 2010, 01:44:13 PM
Does Grab include structures currently under construction? How about AIKnownUnitCount?


AIKnownUnitCount counts units under construction too; if you want something more specific use TechTreeUnitCount with one of the following flags:
const int c_techCountQueuedOnly         = 0;const int c_techCountQueuedOrBetter     = 1;const int c_techCountInProgressOnly     = 2;const int c_techCountInProgressOrBetter = 3;const int c_techCountCompleteOnly       = 4;const int c_techCountIncompleteOnly     = 5;

Kernel64

Cool.

I'm currently needing a function that returns the free available food supply with two conditions:

Now -- the number of free resource from hatch/lair/Hive + ovies already completed.
Soon -- Now + number of ovies in queue or already in production.

I'm using this to test a script that will only spawn lings when necessary, and depending on the number of what target it needs to counter and the counter value for ling vs that specific target in question.

Also, one question, will two while blocks run simultaneously?

Say,

while(A) {
   do(x)...
}
while(!B) {
   do(y)...
}

Will do(x) and do(y) run simultaneously?

hd

Quote from: Kernel64 on March 09, 2010, 05:37:47 AM
Cool.

I'm currently needing a function that returns the free available food supply with two conditions:

Now -- the number of free resource from hatch/lair/Hive + ovies already completed.
Soon -- Now + number of ovies in queue or already in production.

I'm using this to test a script that will only spawn lings when necessary, and depending on the number of what target it needs to counter and the counter value for ling vs that specific target in question.

Also, one question, will two while blocks run simultaneously?

Say,

while(A) {
   do(x)...
}
while(!B) {
   do(y)...
}

Will do(x) and do(y) run simultaneously?

No like that. It will run the code in the order it's typed. while(a) will run, finish then while(!b) will run.

You can however put

while(a) {
    while(!b) {
    }
}

Aeg1s

Quote from: Kernel64 on March 09, 2010, 05:37:47 AM
Cool.

I'm currently needing a function that returns the free available food supply with two conditions:




This is what I use to check supply:


    int used = PlayerGetPropertyInt(player, c_playerPropSuppliesUsed);
    int created = PlayerGetPropertyInt(player, c_playerPropSuppliesMade); //current supply


    // queued supply count:
    if (PlayerRace(player) == "Zerg") {
    created = TechTreeUnitCount(player, c_ZU_Overlord, c_techCountQueuedOrBetter) * 8 + TechTreeUnitCount(player, c_ZU_Overseer, c_techCountQueuedOrBetter) * 8;
        created += TechTreeUnitCount(player, c_ZB_Hatchery, c_techCountQueuedOrBetter) * 2 + TechTreeUnitCount(player, c_ZB_Lair, c_techCountQueuedOrBetter) * 2 + TechTreeUnitCount(player, c_ZB_Hive, c_techCountQueuedOrBetter) * 2;
    } else if (PlayerRace(player) == "Prot") {
    created = TechTreeUnitCount(player, c_PB_Pylon, c_techCountQueuedOrBetter) * 8 + TechTreeUnitCount(player, c_PB_Nexus, c_techCountQueuedOrBetter) * 10;
    } else if (PlayerRace(player) == "Terr") {
    created = TechTreeUnitCount(player, c_TB_SupplyDepot, c_techCountQueuedOrBetter) * 8 + TechTreeUnitCount(player, c_TB_CommandCenter, c_techCountQueuedOrBetter) * 11;
        created += TechTreeUnitCount(player, c_TB_OrbitalCommand, c_techCountQueuedOrBetter) * 11 + TechTreeUnitCount(player, c_TB_PlanetaryFortress, c_techCountQueuedOrBetter) * 11;
        created += TechTreeUnitCount(player, "SupplyDepotLowered", c_techCountQueuedOrBetter) * 8;
        // Alias doesn't seem to work right here...
    }



Quote
Also, one question, will two while blocks run simultaneously?

Say,

while(A) {
   do(x)...
}
while(!B) {
   do(y)...
}

Will do(x) and do(y) run simultaneously?


What do you mean simultaneously? What are you trying to do with the two loops?

Kernel64

#7
It's like this:

Quote
//begin: Bane Defense
    AISetStock( player, 1, c_ZB_Hatchery_Alias );
    AISetStock( player, 10, c_ZU_Drone );
    AISetStock( player, 2, c_ZU_Overlord );
    AISetStock( player, 1, c_ZB_SpawningPool );
    if ( AITechCount(player, c_ZB_SpawningPool, c_techCountQueuedOrBetter ) == 1 ) { //we've started pool
        AISetStock( player, 12, c_ZU_Drone );
        AISetStock( player, 1, c_ZB_Extractor );       
        AISetStock( player, 15, c_ZU_Drone );
    }
    if ( (AITechCount(player, c_ZU_Drone, c_techCountInProgressOrBetter ) >= 13) &&
         (AITechCount(player, c_ZU_Drone, c_techCountInProgressOrBetter ) <= 16) &&
         (AIHasRes (player, 150, 0) == true) )
    {
        AISetStock( player, 1, c_ZU_Queen );
        AISetStock( player, 3, c_ZU_Overlord );
        AISetStock( player, 12, c_ZU_Zergling );   
        AISetStock( player, 1, c_ZB_BanelingNest );       
        AISetStock( player, 16, c_ZU_Drone );
    }
    if ( (AITechCount(player, c_ZU_Zergling, c_techCountInProgressOrBetter ) >= 4) &&
         (AITechCount(player, c_ZU_Zergling, c_techCountInProgressOrBetter ) <= 12) &&
         (AIHasRes (player, 250, 0) == true) )
    {
        AIDefaultExpansion(player, c_ZB_Hatchery_Alias, 12000, 6000, c_expandDefault);   
    }
    if    ( (AITechCount(player, c_ZB_BanelingNest, c_techCountCompleteOnly ) == 1) ) {
        AISetStock( player, 6, c_ZU_Zergling );
        AISetStock( player, 8, c_ZU_Baneling );
    }
   
    if ( (AITechCount(player, c_ZB_Hatchery, c_techCountInProgressOrBetter ) == 2)  &&
        (AITechCount(player, c_ZU_Drone, c_techCountCompleteOnly ) <= 18) &&
        (AIGetTime() < 300)    )
    {
        AISetStock( player, 8, c_ZU_Zergling );   
        AISetStock( player, 8, c_ZU_Baneling );
        AISetStock( player, 10, c_ZU_Zergling );
    }

I wrote this without the funcs yet, which I believe you guys can do. Funcs that are conditional which will run in parallel.

From testing, the script should either choose to make banes immediately or lings, or skip them all together if the enemy had no zealots, right? That's where the while comes.

I want the AI to enter a while and stay there until a break is called. And once that while has been entered, a key will be set so the next while will not be true anymore.

Before each while, conditions tested and the script will parse multiple ifs repeatedly until a while condition is met. Once in a while, at some cases, a key will be set and break called so as to call the other while.

All this will loop over and over, just as a state does, and might even leave a state early and move to MidGndA or B. All depending on the conditions.

From the above example, we can later create a code that has one main, and two conditional states it will enter. This so called states are the ones in the while statement.

So for example, while the protoss player is maintaining a number of zealots, it will enter the while and keep TrainZerglings(UnitToCounter, Min, Max, PriorityKey).

So it's probably going to look like this:
returned 1 -- minimum is reached
returned 2 -- maximum is reached
returned 3 -- we cannot try min, we cannot try max, we're not needing this.

while (TrainZerglings("Zealot", 3, 7, 8 ) != 3) and some condition is true here) { //we are facing 1-7 zeals, and we've not trained zerglings 1x4 (minimum which returns 1) to zerglings 7x4 (max which returns 3)

     [do stuff here]
}

if (we have more than 6 lings complete and TrainZerglings(..) >= 1 and != 3 and some condition here is true) {
     while (TrainBanes("Zealot", 1, 3, 10) !=3)) {}
}

So, as you can see, the script should jump back and forth from each other and maintain a number of lings, then morph them to banelings, etc, until everything is satisfied.

Something like this. Haven't put a lot of thought yet in implementation, since I'm still trying to figure out the thinking process and loop holes of ZvP @ < 5:00 mins.

So far though, the above will most likely be needed should it make the AI more dynamic.

ShadowTiger

Im not exactly sure what you are trying to do, but if you want 2 whiles to run simultaneously, simply combine them. Just have 1 while and use if statements or a state variable to decide whether to build zerglings. A state variable is a boolean that says, if im done building zerglings, set build banelings = true. If build banelings = true, build banelings. If i dont need them anymore, set build banelings = false.

Does that make sense?

Kernel64

It does. My above post is really not refined nor exactly useful (sort of inductive). They're vague concepts still, as I'm yet trying to get a handle on the whats that gets swapped around within the first 5mins of the game.

Anyway, I'll post what I find.

hd

Quote from: Kernel64 on March 10, 2010, 03:24:07 AM
It does. My above post is really not refined nor exactly useful (sort of inductive). They're vague concepts still, as I'm yet trying to get a handle on the whats that gets swapped around within the first 5mins of the game.

Anyway, I'll post what I find.

The first 5 minutes of the game really isn't that big of a deal. It's pretty straight forward.

1.) Rush or no rush.
2.) Fast expand or no fast expand
3.) Harass or no harass.

That's all early game consists of. It's really hard to combine all three of those in a single game and to some extent, harassing and rush are almost hand in hand. Drops, nukes, pressure, map control, trapping someone inside their base, teching... those are all middle game.

Kernel64

Brilliant. I'm currently focusing on the AI in a defensive mode. It wants to tech to lair asap, and use minimal expenses on defense units, and will build them only when necessary. Once it get's lair, it starts two things:

want to 3rd expo, while harassing, and building up an offensive army.

Before, I get to that though, I'm working on the script for the early game, and give it priority shifting. I'm trying to write code, which I want to be as dynamic as possible, and can be reused later up in the tiers where multiple options, and more data are involved.

Astazha

@Kernel64


You may wish to be careful locking the code up in a while loop that doesn't complete until you've reached some build count.  I don't know if the execution of the AI is multi threaded, but if it isn't you'l be preventing CPU cycles from going to other code outside of your loop. 


Part of the beauty of a state engine is that it allows the code to run through once, check conditions to see if it's time to start doing something else, and then complete so that other functions can be called.  This will help with the modularity of your build, too.  It may also reduce CPU usage, depending on how the native function calls to the galaxy scripts are set up. 


You can accomplish the same thing by using IF statements and setting state variables.  If you do the while loop I'm curious to hear if if causes any trouble.  I don't know if the same thread is being used for these galaxy scripts and other unit functions like targeting logic or if they're being run separately.  That would be interesting to know.

Kernel64

True. After testing, while kind of makes the game into stop motion. Ifs work better.

Do you guys know how the galaxy files interact? where do we define global variables, which one gets executed, which ones are just libraries, etc.

Astazha

As far as I can tell a global declared anywhere is a global declared everywhere.  The includes bring in the code from another file just like if you pasted it there.  We need to make sure that the declaration of the global occurs before any references to it, but  other than that I don't think it matters, syntactically speaking.


It appears to me that everything in these galaxy files is just a function, and that Starcraft2 calls some of those functions directly.  I believe the actual main entry point is AIMeleeStart() in MeleeAI.galaxy.  There are some other callbacks to I believe - like AIGetScoutZerg() in Zerg.galaxy.  Changing this code will change how the native scouting features select which units to scout with when you set the scouting flags - even though the rest of the scouting logic is largely concealed from us.  That's how it looks to me anyway.


Neither can I find any reference in a .galaxy to AIMeleeZerg() or ZergInit() or their variants for the other races.  I'm left to assume that most of the functions within the Zerg.galaxy, Protoss.galaxy, and Terran.galaxy files are callbacks for the native functions. 


As far as I can see, anything with no references to it pretty much has to be either unused or a callback.


Not sure if there is a list anywhere