- Joined
- Jul 14, 2014
- Messages
- 115
[Solved] How to keep track of the amount of each unit a player owns?
Like in the AI editor for example
Like in the AI editor for example
Last edited:
Number of units in (Units owned by (Player 1 (Red)))?
You will need to do this for each unit-type. But don't forget to make a variable for the group and use it when checking, then remove the leak.
Number of units in (Units owned by (Player 1 (Red)) matching (Unit-type of (Matching Unit) equal to Footman) and ((Matching Unit) is dead equal to false))
You will need to do this for each unit-type. But don't forget to make a variable for the group and use it when checking, then remove the leak.
Number of units in (Units owned by (Player 1 (Red)) matching (Unit-type of (Matching Unit) equal to Footman) and ((Matching Unit) is dead equal to false))
set id = GetUnitTypeId(pickedUnit)
set playerId = GetPlayerId(GetOwningPlayer(pickedUnit))
set count = LoadInteger(udg_countTable, playerId, id) + 1
call SaveInteger(udg_countTable, playerId, id, count)
This can get really expensive -> you'd select every unit in the map for every single unit type you have and see if they match that unit type and are owned by the chosen player. This could easily be thousands of iterations (10 unit types with 100 units on the map).
Don't forget that the group count function is O(n) as well (it loops over the whole group to count them).
A faster way would be to use a hashtable so you can directly increment the count in the bucket that matches the unit type ID for each player - looping over the units in the map just once.
Basically would look a little like this inside the loop:
JASS:set id = GetUnitTypeId(pickedUnit) set playerId = GetPlayerId(GetOwningPlayer(pickedUnit)) set count = LoadInteger(udg_countTable, playerId, id) + 1 call SaveInteger(udg_countTable, playerId, id, count)
Then you can use the player ID + unit type combo to determine the count of that unit type for that player.
Alternatively, you could store the count somewhere (might be doable with an array with some other setup, but just a hashtable is probably easier). Then check when the units enter the map, you increment the according count similar to the other method. You have to properly detect when units die, though - as well as change teams (if they do that), revive, etc. It's probably the fastest overall, but it would get ugly depending on what happens in your map.
So that means I would have to create and integer and set it to the amount of units? But how do I remove the leak. I know it's something like calludg_remove...?
|
Man that trigger must lag like a bi*ch. Picking every unit on the map every 0.1 seconds? There could be over 100 units on the map at a time! Why not do add the integer each time the unit enters the map instead? And remove when they die?
Man that trigger must lag like a bi*ch. Picking every unit on the map every 0.1 seconds? There could be over 100 units on the map at a time! Why not do add the integer each time the unit enters the map instead? And remove when they die?
|
Thank you all for your help. The map can easily have 150 - 200 units for each player. Legal Ease's method seems a little laggy for such an amount but I'll try it anyway. SAUS, I'm sorry for being such a retard, but you only type your ideas in text. I can't really fully understand without seeing a trigger. Sorry again
No worries. I just don't like working with GUI and, in my own map, I would copy-paste so much of the code that I am only writing maybe 30% of the lines of code manually. I can't do that when I'm on here because I go on here mostly when I'm not at home
This trigger will collect all the units into the unit group for their owner as they enter the map. You will need a unit group array variable (called playerUnits in my trigger) which will need to be size 13 (or maybe just 12, but going higher is safer).
Collect Units
Events
Unit - A unit enters <Playable map area>
Conditions
Actions
set tempUnit = Triggering Unit
set tempPlayer = Owner of (Triggering Unit)
set tempInt = Player number of (tempPlayer)
Unit Group - Add (tempUnit) to playerUnits[tempInt]
This trigger will clean the removed units out of the groups and also will update units that switched teams (by completely emptying the current set of groups and adding all the units). When you want to get the count of a unit, you will have to count the units in your trigger. Here is an example:
Refresh Groups
Events
Time - Every 60.00 seconds
Conditions
Actions
For each integer A do
Loop (Actions)
Unit Group - Empty playerUnits[(For loop integer A)]
set tempGroup = Units in <Playable map area>
Unit Group - Pick every unit in tempGroup and do
Actions
Unit Group - Add (picked unit) to playerUnits[Player number of (Owner of (Picked unit))]
Custom script: call DestroyGroup(udg_tempGroup)
This trigger will check every 30 seconds if player 1 has at least 100 footmen and will make them win if they do.
Example Use
Events
Time - Every 30.00 seconds
Conditions
Actions
set tempInt = 0
Unit Group - Pick every unit in playerUnits[1] and do
Actions
If (multiple actions)
Conditions
(Picked unit) is alive
(Picked unit) belongs to Player(1)
Unit type of (Picked unit) matches (Footman)
Then
set tempInt = tempInt + 1
Else
If (multiple actions)
Conditions
tempInt is greater than or equal to 100
Then
Game - End the game in victory for Player(1)
Else
These triggers are still not perfectly accurate. If a unit switches teams, they are not counted in the new team until the Refresh Groups trigger is run - you can increase how often the Refresh Groups trigger is run, but it will still have this problem (though it will be more rare). However, you can manually run it before counting if you really want to (there is a GUI action like Trigger - Run (Refresh Groups <gen>)). Just remember that you don't want to run this trigger too often because it loops over all the units in the entire map.
Hopefully these triggers are helpful. I think I did okay on the GUI syntax, but I wrote these by hand. They may not be exactly as they look in the editor.
EDIT:
Typos and hidden tags.
Summoning units is fine - they "enter playable map area" when they are summoned. Resurrection and animate dead spells are the problem there - the units are already in the map - they are just dead. They would not be re-added to the group. That is not a problem if you don't try to remove them in the first place, though.
You need to refresh the group every once in a while because a group can have "NULL" units in it (units that have died and fully decayed no longer exist, but the group still has that unit in it - it will just loop over it and fail checks like "is alive"). Without refreshing, looping over the group will take longer and longer as the game goes on.
Legal_Ease's version would count faster (when you go to use it) and would also be less code inside the trigger that needs to use the count, but it would also require that you make an array for each unit type you want to check (which might not be that many, anyway).
I don't know if you have anything that would break the counting, however, it means you cannot add one in later without doing some extra work. I don't know all the details of your map, so it is hard to say what is better.
If your map has no reanimation / unit stealing or giving, you should be okay to use Legal_Ease's method. I think it is overall a faster method, just less robust once you have those kinds of things added to your map.
If your map has no reanimation / unit stealing or giving, you should be okay to use Legal_Ease's method. I think it is overall a faster method, just less robust once you have those kinds of things added to your map.
Hashtables is probably the best solution. You could create a single system for all units that way.
That is only half the problem solved because what do you "add +1" or "-1" from? This is where hashtables work the best because you can use the unit type as the parent key.Why not just use a Unit Indexer and use the event of "unit gets indexed" to add +1, and then use "A unit dies" to -1?![]()
That is only half the problem solved because what do you "add +1" or "-1" from? This is where hashtables work the best because you can use the unit type as the parent key.
It also does not solve the problem of units which do not die. Such as trigger removed units or units which change ownership. You will either need to deal with such events separately (RemoveUnit extension, add triggers to catch Charm ability casts), not allow such events to occur (eg a nice stable classic TD game) or have some sort of error correction mechanism which chugs along quietly in the background.