• 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.

Guard Posts v1.3 [GUI] - AI System

Foreword

Installation

Instructions

Trigger

Credits

Bugs

Changelogs


This system allows a unit to guard a certain place or point and attacks any entruders that goes within the guarded perimeter.

- Be sure to check the 'Automatically create unknown variables while pasting trigger data' via File>>>Preferences>>>General tab
- Copy the Unit Indexer to your map (or any Unit Indexer will do)
- Copy the Guard Post folder to your map, be sure to check the ''

First, set certain variables;
GP_GuardingUnit = The unit you want to be guarding
GP_GuardWhere = The point where the unit is guarding
GP_Perimeter = Guard units will attack any enemy that is in range
GP_FacingAngle = This is optional, when unit has no work he will face that angle
GP_EngageWhileTraveling = Also optional, default is false, it engages anemy units while going to the place he guards

Then at the last, run the;
  • Trigger - Run Guard Post Form <gen> (ignoring conditions)
Like this;
  • All Units
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
        • Loop - Actions
          • -------- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --------
          • -------- Sets the Guard unit --------
          • -------- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --------
          • Set GP_GuardingUnit = (Picked unit)
          • -------- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --------
          • -------- Sets the location point of where the unit will guard --------
          • -------- You do not need to remove the location coz it will be removed from the system automatically --------
          • -------- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --------
          • Set GP_GuardWhere = (Position of (Picked unit))
          • -------- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --------
          • -------- Sets the range perimeter from the location where the unit is guarding --------
          • -------- If an enemy unit is in range, he will engage --------
          • -------- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --------
          • Set GP_Perimeter = 1000.00
          • -------- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --------
          • -------- Facing angle and Engage while traveling are optional --------
          • -------- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --------
          • Set GP_FacingAngle = 30.00
          • Set GP_EngageWhileTraveling = True
          • -------- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --------
          • -------- Store the guard unit to the system --------
          • -------- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --------
          • Trigger - Run Guard Post Form <gen> (ignoring conditions)
      • -------- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --------
      • -------- If you want to remove the unit from the system, just do this --------
      • -------- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --------
      • Set GP_GuardingUnit = Mountain King 0010 <gen>
      • Trigger - Run Guard Post Remove <gen> (ignoring conditions)
For more info, check the Demo and Instructions folder

  • Guard Post Setup
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- All settings here are default and recommended --------
      • -------- ======================================= --------
      • -------- The minimum perimeter of the location where the unit is guarding --------
      • -------- ======================================= --------
      • Set GP_MinimumPerimeter = 200.00
      • -------- ======================================= --------
      • -------- If the unit doesnt have orders or no more enemies around, it will go back to it's guarding post --------
      • -------- Calculation is 1x3 since the Movement is every 3 seconds --------
      • -------- ======================================= --------
      • Set GP_MinimumDelayBackToBase = 1
  • Guard Post Form
    • Events
    • Conditions
    • Actions
      • -------- ======================================= --------
      • -------- Take note that if you cause an error message, the location variable will leak --------
      • -------- ======================================= --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • GP_GuardingUnit Equal to No unit
        • Then - Actions
          • Game - Display to (All players) the text: Guard Post Error: C...
          • Skip remaining actions
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • GP_Perimeter Less than GP_MinimumPerimeter
            • Then - Actions
              • Game - Display to (All players) the text: (Guard Post Error: + (Minimum Perimeter should be + (String(GP_MinimumPerimeter))))
              • Skip remaining actions
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (GP_GuardingUnit is in GP_GuardingGroup) Equal to True
                • Then - Actions
                  • Game - Display to (All players) the text: (Guard Post Error: + ((Name of GP_GuardingUnit) + is already added as a guard, remove it first))
                  • Skip remaining actions
                • Else - Actions
      • AI - Ignore GP_GuardingUnit's guard position
      • Set GP_UI = (Custom value of GP_GuardingUnit)
      • Set GP_U[GP_UI] = GP_GuardingUnit
      • Set GP_Per[GP_UI] = GP_Perimeter
      • Set GP_Fac[GP_UI] = GP_FacingAngle
      • Set GP_BackToBase[GP_UI] = GP_MinimumDelayBackToBase
      • Set GP_Back[GP_UI] = GP_MinimumDelayBackToBase
      • Set GP_Engage[GP_UI] = GP_EngageWhileTraveling
      • Set GP_EngageWhileTraveling = False
      • Unit - Order GP_GuardingUnit to Attack-Move To GP_GuardWhere
      • Custom script: set udg_GP_X[udg_GP_UI] = GetLocationX(udg_GP_GuardWhere)
      • Custom script: set udg_GP_Y[udg_GP_UI] = GetLocationY(udg_GP_GuardWhere)
      • Custom script: call RemoveLocation(udg_GP_GuardWhere)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • GP_Index Equal to 0
        • Then - Actions
          • Trigger - Turn on Guard Post Movements <gen>
        • Else - Actions
      • Set GP_Index = (GP_Index + 1)
      • Unit Group - Add GP_U[GP_UI] to GP_GuardingGroup
  • Guard Post Movements
    • Events
      • Time - Every 3.00 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in GP_GuardingGroup and do (Actions)
        • Loop - Actions
          • Custom script: local unit first
          • Custom script: local real xGuard
          • Custom script: local real yGuard
          • Set GP_UI = (Custom value of (Picked unit))
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (GP_U[GP_UI] is alive) Equal to True
            • Then - Actions
              • Custom script: set xGuard = GetUnitX(udg_GP_U[udg_GP_UI])
              • Custom script: set yGuard = GetUnitY(udg_GP_U[udg_GP_UI])
              • Custom script: set udg_GP_Distance = (udg_GP_X[udg_GP_UI] - xGuard)*(udg_GP_X[udg_GP_UI] - xGuard)+(udg_GP_Y[udg_GP_UI] - yGuard*(udg_GP_Y[udg_GP_UI] - yGuard))
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • GP_Distance Greater than or equal to (GP_Per[GP_UI] x GP_Per[GP_UI])
                • Then - Actions
                  • -------- ======================================= --------
                  • -------- Engage enemies while going to base if the condition is true --------
                  • -------- Or just moves to the base if away from perimeter --------
                  • -------- ======================================= --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • GP_Engage[GP_UI] Equal to True
                    • Then - Actions
                      • Custom script: call IssuePointOrderById(udg_GP_U[udg_GP_UI], 851983, udg_GP_X[udg_GP_UI], udg_GP_Y[udg_GP_UI])
                    • Else - Actions
                      • Custom script: call IssuePointOrderById(udg_GP_U[udg_GP_UI], 851986, udg_GP_X[udg_GP_UI], udg_GP_Y[udg_GP_UI])
                • Else - Actions
                  • -------- ======================================= --------
                  • -------- Searches for enemy units within the perimeter --------
                  • -------- ======================================= --------
                  • Custom script: call GroupEnumUnitsInRange(udg_GP_TempGroup, udg_GP_X[udg_GP_UI], udg_GP_Y[udg_GP_UI], udg_GP_Per[udg_GP_UI], null)
                  • Custom script: loop
                  • Custom script: set first = FirstOfGroup(udg_GP_TempGroup)
                  • Custom script: exitwhen first==null
                  • Custom script: if not IsUnitType(first, UNIT_TYPE_DEAD) and IsUnitEnemy(udg_GP_U[udg_GP_UI], GetOwningPlayer(first)) then
                  • Custom script: call IssuePointOrderById(udg_GP_U[udg_GP_UI], 851983, GetUnitX(first), GetUnitY(first))
                  • Custom script: endif
                  • Custom script: call GroupRemoveUnit(udg_GP_TempGroup, first)
                  • Custom script: endloop
                  • -------- ======================================= --------
                  • -------- Setting unit's facing angle if no order is available --------
                  • -------- ======================================= --------
                  • Custom script: if GetUnitCurrentOrder(udg_GP_U[udg_GP_UI])==0 then
                  • Custom script: call SetUnitFacing(udg_GP_U[udg_GP_UI], udg_GP_Fac[udg_GP_UI])
                  • -------- ======================================= --------
                  • -------- Back to base, recycles every XXX seconds if order is 0 --------
                  • -------- ======================================= --------
                  • Set GP_BackToBase[GP_UI] = (GP_BackToBase[GP_UI] - GP_Back[GP_UI])
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • GP_BackToBase[GP_UI] Equal to 0
                    • Then - Actions
                      • Set GP_BackToBase[GP_UI] = GP_Back[GP_UI]
                      • Custom script: call IssuePointOrderById(udg_GP_U[udg_GP_UI], 851983, udg_GP_X[udg_GP_UI], udg_GP_Y[udg_GP_UI])
                    • Else - Actions
                  • Custom script: endif
            • Else - Actions
              • Unit Group - Remove GP_U[GP_UI] from GP_GuardingGroup
              • Set GP_Index = (GP_Index - 1)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • GP_Index Equal to 0
                • Then - Actions
                  • Trigger - Turn off (This trigger)
                • Else - Actions
  • Guard Post Remove
    • Events
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (GP_GuardingUnit is in GP_GuardingGroup) Equal to True
        • Then - Actions
          • Unit Group - Remove GP_GuardingUnit from GP_GuardingGroup
          • Set GP_Index = (GP_Index - 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • GP_Index Equal to 0
            • Then - Actions
              • Game - Display to (All players) the text: adasdadadOFF
              • Trigger - Turn off Guard Post Movements <gen>
            • Else - Actions
        • Else - Actions
          • Game - Display to (All players) the text: (Guard Post Error: + ((Name of GP_GuardingUnit) + is not recognized to be removed from system.))

Bribe for his [thread=197329]UnitIndexer[/thread]

-

v 1.3
- All jass codes are converted to GUI
- Simple constant guarding of location is applied



Keywords:
guard, ai, post, unit, indexer, aos, diablo, rpg, unit, defend, attack, bribe, search, destroy
Contents

Guard Post (Map)

Reviews
Guard Posts v1.3 | Reviewed by Maker | 23rd Jul 2013 Approved This is a useful system Don't make units face angle, if they are already approximately facing the angle. It makes them twitch Remove the asdaf debug...

Moderator

M

Moderator


Guard Posts v1.3 | Reviewed by Maker | 23rd Jul 2013
Approved


126248-albums6177-picture66521.png


  • This is a useful system
126248-albums6177-picture66523.png


  • Don't make units face angle, if they are already
    approximately facing the angle. It makes them twitch
  • Remove the asdaf debug message from Guard Post Remove
    • AI - Ignore GP_GuardingUnit's guard position
    doesn't work on heroes
[tr]


10th Nov 2011
Bribe: "GPostLooper1" and "GPostLooper2" should "return nothing". I am not even sure how it compiles the way you have them return false.

This should use FirstOfGroup loops not filters, no need for the filters, just use "null".

The public API should be more readable, like "GuardPostSetUnit". Your internal codes can have the less readable prefix "GPost" but having it more clear for the users also helps distinguish their presence.
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
You really should post the function in JASS and explain all their parameters as no one will get your example right now (GUIers) and especially not demo 2 as it uses coordinates which GUIers don't use. Please change the demo 2 using a location instead and just use GetLocationX/Y in the function call.

A bit more down here:

-if distance > udg_GPostReturnOffset

Skip the squareroot and just set udg_GPostReturnOffset^2 instead.

-I know that GUIers don't mess with the hp but still IsUnitType(whichunit, UNIT_TYPE_DEAD) is safer than the GetWidgetLife check (or you can use both, Bribe will complain about it either way so ;) )

-Instead of "not IsUnitEnemy" use IsUnitAllie (or how it's spelled)

-Why do you use a trigger and attach a timer event to it + conditions? Just use two timers instead.

Anyway I like the idea of the system although using this with lots of units will make every 3 second lagg when it re-orders the units and lots of orders equal to lagg.
 
Level 17
Joined
Mar 17, 2009
Messages
1,350
okay this should most probably lead to an argument, but there are two schools regarding to this:
JASS:
function GPostGetDistance takes real x1, real y1, real x2, real y2 returns real
    return SquareRoot((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
endfunction

could be:
JASS:
function GPostGetDistance takes real x1, real y1, real x2, real y2 returns real
    local real x = x2-x1
    local real y = y2-y1

    return SquareRoot(x*x + y*y)
endfunction

as to my own opinion, the second method is better since ur calculating each of the 2 differences only once... some people however argue that creating the locals would be basically cancelling the effect of time gained by reducing the calculations..
 
@Mags
I've created a vJASS for this as an inpiration from my EngageSystem but decided to post this version instead.

@baassee
You really should post the function in JASS and explain all their parameters as no one will get your example right now (GUIers) and especially not demo 2 as it uses coordinates which GUIers don't use. Please change the demo 2 using a location instead and just use GetLocationX/Y in the function call.

I'm not really good in explaining things but I'll try harder next time ;)...
I'm just gonna make an optional location as well...

- if distance > udg_GPostReturnOffset

Skip the squareroot and just set udg_GPostReturnOffset^2 instead.

>>>pls explain further on how to achieve this without using squareroot?...<<< NVM

-I know that GUIers don't mess with the hp but still IsUnitType(whichunit, UNIT_TYPE_DEAD) is safer than the GetWidgetLife check (or you can use both, Bribe will complain about it either way so ;) )

-Instead of "not IsUnitEnemy" use IsUnitAllie (or how it's spelled)

Yeah Bribe is a perfectionist, lol!, sorry bribe :)...

-Why do you use a trigger and attach a timer event to it + conditions? Just use two timers instead.

hehe, no comment, I'll just change it next...I thought It'd be easier...

Anyway I like the idea of the system although using this with lots of units will make every 3 second lagg when it re-orders the units and lots of orders equal to lagg.

Next I'll just add a condition on WHEN the unit will move/follow...


In all thank you guys...


EDIT:
@Deuterium
Thanks...I did that to reduce lines not knowing which is better, however if the 2nd method is better, then I'll edit that...
 
Last edited:
All the GetWidgetLife(u) < 0.405 should have been replaced with:
JASS:
if not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0 then
    // unit is alive
endif
You can use statement about as function, so instead of using 'if' everytime just call the function which returns boolean depending if unit is alive or not:
JASS:
function GPostIsAlive takes unit u returns boolean
    return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) !=0
endfunction
To omit convertion string into order use ById function types:
JASS:
call IssueTargetOrder(u, "attack", target)
// ->>
call IssueTargetOrderById(u, 851983, target)

call IssuePointOrder(u, "smart", x, y)
// ->>
call IssuePointOrderById(u, 851971, x, y)

Deuterium mentioned about Square root will make calculation faster although:
- square root seems to be one of slower functions. To get rid of it you can:

  • Set GPostReturnOffset = 200.00
  • // user sets stuff, and on the bottom:
  • Set GPostReturnOffset = GPostReturnOffset x GPostReturnOffset
Now in script:
- remove GPostGetDistance() function.
- in GPostReturn remove 'distance' local and do
JASS:
if (udg_GPostX[i] - x) * (udg_GPostX[i] - x) + (udg_GPostX[i] - y) * (udg_GPostX[i] - y) > udg_GPostReturnOffset then
    // is out of range
endif
GPostPeriodic() needs similar healing, but in this case locals x1, y2 and waste of memory. You are using those only once anyways:
JASS:
local real x1
local real y1
set x1 = x + 200 * Cos(angle)
set y1 = y + 200 * Sin(angle)
call IssuePointOrder(u, "smart", x1, y1)

// ->>
call IssuePointOrder(u, "smart", x + 200 * Cos(angle), y + 200 * Sin(angle))
Function GPostFindEnemy() - I really feel like declaring two locals + calling GetFilterUnit() is slower than calling GetFilterUnit() two times:
JASS:
function GPostFindEnemy takes nothing returns boolean
    local unit u = GetFilterUnit()
    local boolean b = GetWidgetLife(u) > 0.405 and IsUnitEnemy(u, GetOwningPlayer(udg_GPostTempUnit))       
    set u = null
    return b
endfunction

// ->>
function GPostFindEnemy takes nothing returns boolean
    return GPostIsAlive(GetFilterUnit()) and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(udg_GPostTempUnit))       
endfunction

Interval within call TriggerRegisterTimerEvent(udg_GPostTrigP, 3.0, true) (for both triggers) should be constant function at the top.
Additionaly: you might consider raplacing time-events with timers.
 
Last edited:
tnx spin but most of the one you mentioned except the "IsUnitType(u, UNIT_TYPE_DEAD)" and the last one, damn...your fast :)...in the next update Ima apply all of it although Im not sure about this...
JASS:
if (udg_GPostX[i] - x) * (udg_GPostX[i] - x) + (udg_GPostX[i] - y) * (udg_GPostX[i] - y) > udg_GPostReturnOffset then
    // is out of range
endif

coz Im planning to put it in a separate function rather than inside the main code itself...
 
JASS:
function GPostGetDistance takes real x1, real y1, real x2, real y2 returns real
    local real x = x2-x1
    local real y = y2-y1

    return SquareRoot(x*x + y*y)
endfunction

->

JASS:
function GPostGetDistance takes real x1, real y1, real x2, real y2 returns real
    return SquareRoot((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1))
endfunction

This way, it inlines and you can avoid creating 2 locals and the huge overhead of a function call.
 
@mckill2009 I haven't read baassee post, sorry :p baassee <3

And no, you are mistaken:
JASS:
function GPostFindEnemy takes nothing returns boolean
    local unit u = GetFilterUnit()
    local boolean b = GetWidgetLife(u) > 0.405 and IsUnitEnemy(u, GetOwningPlayer(udg_GPostTempUnit))       
    set u = null
    return b
endfunction

// Should be:
function GPostIsAlive takes unit u returns boolean
    return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0
endfunction

function GPostFindEnemy takes nothing returns boolean
    local unit u = GetFilterUnit()
    local boolean b = GPostIsAlive(u) > 0.405 and IsUnitEnemy(u, GetOwningPlayer(udg_GPostTempUnit))       
    set u = null
    return b
endfunction


// And my idea is a bit faster:
function GPostIsAlive takes unit u returns boolean
    return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0
endfunction

function GPostFindEnemy takes nothing returns boolean
    return GPostIsAlive(GetFilterUnit()) and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(udg_GPostTempUnit))       
endfunction
GetWidgetLife() isn't accurate, you must ensure if unit is truly dead.
Why GPostIsAlive() function usage? In case you are checking if unit is alive many times. Function seems to be more handy that writing everything manually.



@Maggy, you nob ;S You can omit the square root, read my post.
 
Last edited:
dude, UNIT_TYPE_DEAD is fine, but Im not talking about it but the GetFilterUnit() which is suppose to be stored in a local, like...
JASS:
function GPostFindEnemy takes nothing returns boolean
    local unit u = GetFilterUnit()
    local boolean b = GPostIsAlive(u) and IsUnitEnemy(u, GetOwningPlayer(udg_GPostTempUnit))       
    set u = null
    return b
endfunction

BTW you really cant do this >>> GetUnitTypeId(u) coz it will error that integer, it should be...
JASS:
function GPostIsAlive takes unit u1, unit u2 returns boolean
    return not IsUnitType(u1, UNIT_TYPE_DEAD) and u1!=u2 and not IsUnitEnemy(u1, GetOwningPlayer(u2))
endfunction
 
Last edited:
Level 22
Joined
Nov 14, 2008
Messages
3,256
GetWidgetLife is accurate as long as people don't play with SetUnitState/SetWidgetLife (and actually I have no idea if OE heal ability plays with SetUnitState either so maybe it's not that accurate but still, I haven't had any problems with it).

And it will not inline anyway, not without JH (and this is supposed to be used with the vanilla editor?).

BTW you really cant do this >>> GetUnitTypeId(u) coz it will error that integer, it should be...

It's because Spinn forgot that it returns an integer in the last post. Should be

GetUnitTypeId(u) != null (or 0, dunno which one that is the correct one)

EDIT:

And the local is not needed as it's merely two function calls for the filtering unit. If people use JH it will inline without the local but with the local it will not. That's what they're talking about.
 
@mckill209 I had just forgotten about '!=0'. Post edited. If unit-type id is equal to 0 unit doesn't exist or it's decay time is over.

I guess we all want to be as accurate as possible, so I recommend using compasiron mentioned above my me. And again, my solution is faster than yours.
Two GetFilterUnit() >>> GetFilterUnit() plus two locals.
 

sentrywiz

S

sentrywiz

This reminds me of search the maze algorhytms, but much complex and better looking for the eyes. Love it anyway, even though I understand jack-sh1t from jass.
 
Maker said:
Don't make units face angle, if they are already
approximately facing the angle. It makes them twitch
I cant seem to fix this coz GetUnitFacing seems bugged...

Maker said:
Remove the asdaf debug message from Guard Post Remove
Opps, I forgot :D...

Maker said:
AI - Ignore GP_GuardingUnit's guard position
doesn't work on heroes
I know, also peon types or workers, maybe I just make a condition to filter out those units...
 
Top