• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

unit spawning for AI

Status
Not open for further replies.

311

311

Level 4
Joined
May 12, 2019
Messages
73
How would I go about making a trigger that spawns units randomly.

Example
Event: every random# between 1 and 10 seconds (this part is easy)

Action
Spawn a random unit with cost that is equal to the # chosen


so for example lets say the # was 4 because it triggered at 4 seconds, it would spawn unit that I made cost 4gold
(there will be multiple units that cost the same amount also)



Hopefully I am explaining it clearly
basically every 1 to 10 seconds I want an event to happen and however many seconds the trigger decided to go off, it would take that duration lets say 5 seconds, it would then spawn a random unit that I deemed worth 5 points
 
Level 45
Joined
Feb 27, 2007
Messages
5,578
(this part is easy)
Surprisingly not so. If you put "random number between X and Y" in the periodic event it will only choose that random number one time (at map init) and keep re-using that same interval (because of how the timer that runs the event was started). You will instead have to start a one-shot timer each time with the appropriate random duration. As for how to place a random unit of the appropriate cost, this is a great opportunity to use another criminally under-used type: unitpools. The relevant functions are below:
JASS:
native CreateUnitPool           takes nothing returns unitpool
native DestroyUnitPool          takes unitpool whichPool returns nothing
native UnitPoolAddUnitType      takes unitpool whichPool, integer unitId, real weight returns nothing
native UnitPoolRemoveUnitType   takes unitpool whichPool, integer unitId returns nothing
native PlaceRandomUnit          takes unitpool whichPool, player forWhichPlayer, real x, real y, real facing returns unit
You will need to create an array of unitpools where randpool[1] are the units that cost 1 gold, randpool[2] are the units that cost 2 gold, etc.. Add the appropriate unit types to each pool on map init, then use PlaceRandomUnit() on the right pool to get the random unit. Since these unitpools don't 'exist' in GUI you will have to interface with them through some custom scripts, but that can be made easier by a generous use of variables.
JASS:
//put this in a blank trigger or your map's custom script section
globals
  unitpool array RandPool
endglobals
  • Events
    • Time - Elapsed game-time is 0.50 seconds
  • Conditions
  • Actions
    • Custom script: local unitpool UP
    • Countdown Timer - Start SpawnTimer as a one-shot timer that will expire in TIME_TO_WAIT_UNTIL_FIRST_SPAWN seconds
    • Set SpawnNumber = STARTING_SPAWN_NUMBER //a unit from this group will be spawned first
    • -------- below human units are in the 1st pool --------
    • Set MaxSpawn = (MaxSpawn + 1)
    • Custom script: set UP = CreateUnitPool()
    • Custom script: set RandPool[udg_MaxSpawn] = UP
    • Set UType = Footman //a unit type variable
    • Custom script: call UnitPoolAddUnitType(UP, udg_UType, 1.0) //the last argument is a weight value, leave it at 1 and all units are equally likely; a higher weight for any given type makes that type more likely, a lower weight makes that type less likely
    • Set UType = Rifleman
    • Custom script: call UnitPoolAddUnitType(UP, udg_UType, 1.0)
    • Set UType = Knight
    • Custom script: call UnitPoolAddUnitType(UP, udg_UType, 1.0)
    • -------- below orc units are in the 2nd pool --------
    • Set MaxSpawn = (MaxSpawn + 1)
    • Custom script: set UP = CreateUnitPool()
    • Custom script: set RandPool[udg_MaxSpawn] = UP
    • Set UType = Grunt
    • Custom script: call UnitPoolAddUnitType(UP, udg_UType, 1.0)
    • Set UType = Troll Headhunter
    • Custom script: call UnitPoolAddUnitType(UP, udg_UType, 1.0)
    • Set UType = Raider
    • Custom script: call UnitPoolAddUnitType(UP, udg_UType, 1.0)
    • -------- below Undead units are in the 3rdpool --------
    • Set MaxSpawn = (MaxSpawn + 1)
    • Custom script: set UP = CreateUnitPool()
    • Custom script: set RandPool[udg_MaxSpawn] = UP
    • Set UType = Ghoul
    • Custom script: call UnitPoolAddUnitType(UP, udg_UType, 1.0)
    • Set UType = Arachnid
    • Custom script: call UnitPoolAddUnitType(UP, udg_UType, 1.0)
    • Set UType = Abomination
    • Custom script: call UnitPoolAddUnitType(UP, udg_UType, 1.0)
    • -------- continue as necessary for all different pools --------
  • Events
    • Countdown Timer - SpawnTimer expires
  • Conditions
  • Actions
    • -------- Here SpawnNumber will tell us what to spawn --------
    • -------- we will save the spawned unit into the variable UnitVar, which you must create in the variable editor --------
    • Set TPoint = (Center of SpawnRegion <gen>)
    • Set TPlayer = Neutral Hostile //or whatever player should own the spawned unit
    • Set FacingAng = (Default building facing) //what angle should the spawned unit face
    • Custom script: set udg_UnitVar = PlaceRandomUnit(RandPool[udg_SpawnNumber], udg_TPlayer, GetLocationX(udg_TPoint), GetLocationY(udg_TPoint), udg_FacingAng)
    • Unit - Order UnitVar to Attack-move to... //or whatever
    • -------- Note that you cannot use "last created unit here" as that variable is not set by the PlaceRandomUnit call --------
    • -------- --------
    • Set SpawnNumber = Random integer number between 1 and MaxSpawn
    • Countdown Timer - Start SpawnTimer as a one-shot timer that will expire in Real(SpawnNumber) seconds
 
Level 20
Joined
Feb 23, 2014
Messages
1,265
Silly me, I haven't noticed that you want multiple units with the same "cost". In that case just ignore my idea and do what @Pyrogasm said.

---

Step 1) Assign your unit types to a proper array like this:

  • Actions
    • Set UnitTypeArray[1] = <Unit Type 1>
    • Set UnitTypeArray[2] = <Unit Type 2>
    • Set UnitTypeArray[3] = <Unit Type 3>
    • Set UnitTypeArray[4] = <Unit Type 4>
    • ...
    • Set UnitTypeArray[X] = <Unit Type X>
Step 2) Use a trigger like this to spawn the units:

  • Events
    • Time - TimerVariable expires
  • Conditions
  • Actions
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Execution count of (This trigger)) Greater than or equal to 2
      • Then - Actions
        • Set TempLoc = <point where you want to spawn the unit>
        • Unit - Create 1 UnitTypeArray[IntegerVariable] for <Player> at TempLoc facing <facing>
        • Custom script: call RemoveLocation(udg_TempLoc)
      • Else - Actions
    • Set IntegerVariable = (Random integer number between 1 and X)
    • Countdown Timer - Start TimerVariable as a One-shot timer that will expire in (Real(IntegerVariable)) seconds
Some notes:
- You have to run this trigger the first time from some other trigger, after that it will reset automatically
- Alternatively you can just move the unit creation action from the if/then/else block to the start of this trigger and remove the if/then/else block entirely - in this case, you can start this triggger by simply starting the timer by including these 2 actions in another trigger:

  • Set IntegerVariable = (Random integer number between 1 and X)
  • Countdown Timer - Start TimerVariable as a One-shot timer that will expire in (Real(IntegerVariable)) seconds
 
Last edited:

311

311

Level 4
Joined
May 12, 2019
Messages
73
wow I thought it be a simple trigger lol............I don't understand it at all, so hopefully copy/paste works because if not I will have no idea what to edit to fix it

Is there any type of OR function?
like if variable equal to 3 then do this OR this OR this?
because then the trigger should be easy and I wouldn't need custom script or stuff I don't understand
 
Last edited:

311

311

Level 4
Joined
May 12, 2019
Messages
73
I think I got it :)

I only did a small version to test, but it seems to work, might be the sloppy way but as far as I know its doing what I want, I'll find out when I actually have it in the map with lots of units
I just create a timer, then set a integer variable = to the original start time(this gives me how many seconds the timer was)

then when the timer expires I create a unit based off that variable and will just have to do a bunch of IF statements
if variable = to 1, then create one gold cost 1 unit(random # between 1 and how ever many units cost 1 gold) else do if variable = to 2, then create gold cost 2 units(raodm# between 1 and howmany many units in goldcost2 array.

then of course at map init. I set the variables such as
Goldcost 1 unit(1) = knight
Goldcost 1 unit(2)= footman
.
.
.
goldcost 2 unit(1)= abom
.
.
.
and so on

View attachment 331212
 
Level 45
Joined
Feb 27, 2007
Messages
5,578
I don't understand it at all
What is unclear? I gave an explanation of what you are doing, and you can read each line (literally speak the text of the line out loud if you need to) to understand what that line is supposed to do. If you clarify your confusion others can elaborate, but just saying you don't understand isn't helpful.
hopefully copy/paste works
You can copy the text of the custom script lines, yes, but not other trigger lines.
if not I will have no idea what to edit to fix it
This is the point where you post the error dialog you're getting or the map itself or the triggers in your map and describe what the issue you are having is, then we can help you understand what to change.
Is there any type of OR function?
like if variable equal to 3 then do this OR this OR this?
No, there is not. JASS doesn't even have switch/case so what you did with the big if-block is the most straightforward way to do it. Just note the if blocks don't have to be nested:
  • -------- this is not necessary: --------
  • If (All conditions are true) then do (Then actions) else do (Else actions)
    • If - Conditions
    • Then - Actions
    • Else - Actions
      • If (All conditions are true) then do (Then actions) else do (Else actions)
        • If - Conditions
        • Then - Actions
        • Else - Actions
          • If (All conditions are true) then do (Then actions) else do (Else actions)
            • If - Conditions
            • Then - Actions
            • Else - Actions
  • -------- --------
  • -------- it's fine just to do this: --------
  • If (All conditions are true) then do (Then actions) else do (Else actions)
    • If - Conditions
    • Then - Actions
    • Else - Actions
  • If (All conditions are true) then do (Then actions) else do (Else actions)
    • If - Conditions
    • Then - Actions
    • Else - Actions
  • If (All conditions are true) then do (Then actions) else do (Else actions)
    • If - Conditions
    • Then - Actions
    • Else - Actions
The only real improvement to the method you've done is to use a single 2d array instead of multiple arrays. Since JASS does not natively have 2D arrays you must instead 'fake' it using the following formula: var[A][B] = var[A*MAX_B + B] where MAX_B is the highest (or greater than the highest) B value for any A. For simplicity you can set MAX_B to something much higher than you'll ever use, like 100, and be sure that it will work fine.
  • Set MAX_B = 100
  • Set A = 0
  • -------- --------
  • Set A = (A + 1) //units that cost 1 gold
  • Set B = 0
  • -------- --------
  • Set B = (B+1)
  • Set SpawnUnit[(A x MAX_B) + B] = Footman
  • Set B = (B+1)
  • Set SpawnUnit[(A x MAX_B) + B] = Rifleman
  • Set B = (B+1)
  • Set SpawnUnit[(A x MAX_B) + B] = Knight
  • -------- --------
  • Set SpawnUnitCount[A] = B //how many units of cost 1 are there?
  • -------- --------
  • Set A = (A + 1) //units that cost 2 gold
  • Set B = 0
  • -------- --------
  • Set B = (B+1)
  • Set SpawnUnit[(A x MAX_B) + B] = Grunt
  • Set B = (B+1)
  • Set SpawnUnit[(A x MAX_B) + B] = Troll Headhunter
  • Set B = (B+1)
  • Set SpawnUnit[(A x MAX_B) + B] = Raider
  • Set B = (B+1)
  • Set SpawnUnit[(A x MAX_B) + B] = Tauren //one extra unit
  • -------- --------
  • Set SpawnUnitCount[A] = B //how many units of cost 2 are there?
  • -------- --------
  • Set A = (A + 1) //units that cost 3 gold
  • Set B = 0
  • -------- --------
  • Set B = (B+1)
  • Set SpawnUnit[(A x MAX_B) + B] = Ghoul
  • Set B = (B+1)
  • Set SpawnUnit[(A x MAX_B) + B] = Arachnid
  • Set B = (B+1)
  • Set SpawnUnit[(A x MAX_B) + B] = Abomination
  • -------- --------
  • Set SpawnUnitCount[A] = B //how many units of cost 3 are there?
The output of the above trigger is:
SpawnUnitCount[1] = 3
SpawnUnit[101] = Footman
SpawnUnit[102] = Rifleman
SpawnUnit[103] = Knight
SpawnUnitCount[2] = 4
SpawnUnit[201] = Grunt
SpawnUnit[202] = Troll Headhunter
SpawnUnit[203] = Raider
SpawnUnit[204] = Tauren //note this one has 4 units in it
SpawnUnitCount[3] = 3
SpawnUnit[301] = Ghoul
SpawnUnit[302] = Arachnid
SpawnUnit[303] = Abomination

Now to spawn the right unit, you will have to use SpawnNumber (from trigger 2 posts above) and a random int between 1 and SpawnCount[SpawnNumber] to calculate the appropriate index. You will ultimately do this:
  • -------- Presuming SpawnNumber is set when the timer is started --------
  • Set RandomSpawnType = SpawnUnit[(SpawnNumber x MAX_B) + (Random integer between 1 and SpawnCount[SpawnNumber])]
  • Unit - Create 1 RandomSpawnType for...
 
Status
Not open for further replies.
Top