• 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.
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!
  • ✅ The POLL for Hive's Texturing Contest #34 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!
  • ✅ The POLL for Hive's Techtree Contest #20 is OPEN! Vote for the TOP 3 FACTIONS! 🔗Click here to cast your vote!

[Solved] Is this MPU/MUI or not?

Level 18
Joined
Jun 2, 2009
Messages
1,276
Some say this will gonna work most of the times. But as we know WE have serious problems with Wait function. But is it works for ANOTHER PLAYER?
I just want to set boolean false for x seconds, then make it true. Should i run timer for every time? Or is it going to work?

  • run tower range
    • Events
      • Unit - A unit Begins channeling an ability
    • Conditions
      • ((Triggering unit) belongs to an enemy of (Owner of (Target unit of ability being cast))) Equal to True
      • ((Target unit of ability being cast) is A Hero) Equal to True
      • ((Triggering unit) is in HerolarBotALL) Equal to True
      • fAI_run_tower2[(Player number of (Owner of (Triggering unit)))] Equal to False
    • Actions
      • Set TempPoint = (Position of (Target unit of ability being cast))
      • Set TempGroup = (Units within 800.00 of TempPoint matching ((((Matching unit) is in zug_TowersALL) Equal to True) and ((((Matching unit) belongs to an enemy of (Owner of (Triggering unit))) Equal to True) and (((Matching unit) is alive) Equal to True))))
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in TempGroup) Greater than 0
        • Then - Actions
          • Unit - Order (Triggering unit) to Move To (Center of PreviousTarget[(Player number of (Owner of (Triggering unit)))])
          • Set fAI_run_tower2[(Player number of (Owner of (Triggering unit)))] = True
        • Else - Actions
      • Custom script: call DestroyGroup(udg_TempGroup)
      • Custom script: call RemoveLocation(udg_TempPoint)
      • Wait 2.00 seconds
      • Set fAI_run_tower2[(Player number of (Owner of (Triggering unit)))] = False
Update: I have tested it on empty map and it works. The question is, what can cause issues in there? Not happened yet but what is the problem with Wait?
Every player have only one Heroes and why should i use timer if this one works?
 
Last edited:
This is player instanced and only the first unit per player can trigger these actions every 2 seconds.
If you want it to be MUI, then an easy approach would be to use shadowing, as explained here: local udg_
Players only have 1 Hero. In other words this is MPI but not MUI right? People was telling each other not to use Wait function for a reason. I do not remember why. This is why i wanted to ask. If this trigger works only 1 unit for specific player there is no problem.
 
If you cast the ability twice in a row then you'll create two instances of the trigger. Both instances have their own Wait which will expire after ~2 seconds.

These two instances both control the fAI_run_tower2 variable, so they're basically fighting over who gets to Set it to true/false. Without the Wait they wouldn't fight with one another because the first instance would finish all of it's Actions before the second instance even started running it's Actions.

However, this might not be possible in your map. It depends on the Cooldown of the ability and if you have things that Reset cooldowns. Tome of Retraining, Triggers, things like Refresher Orb in DotA come to mind. It'd probably be an extremely rare bug in those cases but it could happen.

Also, this leaks a Point:
  • Unit - Order (Triggering unit) to Move To (Center of PreviousTarget[(Player number of (Owner of (Triggering unit)))])
(Center of), (Position of), these are all signs of a Point leak.

When dealing with locations in the game world, unless you're directly referencing x/y/z coordinates, the game is going to create a Point there. If you don't store that Point in a variable and remove it afterwards, it's going to leak.
 
Last edited:
Still i do not understand what kind of conditions i can use this wait.

  • Events
    • Game - DamageModifierEvent becomes Equal to 1.00
  • Conditions
    • fAI_run_tower[(Player number of (Owner of (Picked unit)))] Equal to False
    • (DamageEventSource is A structure) Equal to True
    • (DamageEventTarget is in HerolarBotALL) Equal to True
  • Actions
    • Set fAI_run_tower[(Player number of (Owner of DamageEventTarget))] = True
    • Set DamageEventAmount = (DamageEventAmount - 100.00)
    • Set TempPoint = (Center of PreviousTarget[(Player number of (Owner of DamageEventTarget))])
    • Unit - Order HERO_AI[(Player number of (Owner of DamageEventTarget))] to Move To TempPoint
    • Wait 2.00 seconds
    • Set fAI_run_tower[(Player number of (Owner of DamageEventTarget))] = False
    • Custom script: call RemoveLocation(udg_TempPoint)
If hero takes damage from tower, it will return their previous order for 2 seconds.
But what happens if it will take secondary damage? It will restarts this trigger for specific player?
If yes: No problem. run_tower should turn True if it will not take damage from tower last 2 seconds.

Player 5 Hero takes damage from tower
Second 0
Second 1
Second 1.5 and takes damage again
Starts from
0
1
2 (false)


Is it true right? If yes, i can use it "IF PLAYER HAVE ONLY ONE UNIT"
Right?
 
In your trigger you Set "fAI_run_tower = True" immediately when the unit takes damage:
  • Actions
    • Set fAI_run_tower[(Player number of (Owner of DamageEventTarget))] = True
You also have a Condition that prevents the trigger from running while that variable is True:
  • Conditions
    • fAI_run_tower[(Player number of (Owner of (Picked unit)))] Equal to False
^ But I think you meant for this to say (Owner of DamageEventTarget) and not (Picked unit).

(Picked unit) will either get you "No unit" or it will get you the last unit you've "looped" over. In other words, it's not really meant to be used outside of a Unit Group loop and it has absolutely nothing to do with the Event.

You're also making some mistakes by referencing global variables after the Wait. That's rarely safe to do.

Here's a fixed trigger:
  • Events
    • Game - DamageModifierEvent becomes Equal to 1.00
  • Conditions
    • fAI_run_tower[(Player number of DamageEventTarget)] Equal to False
    • (DamageEventSource is A structure) Equal to True
    • (DamageEventTarget is in HerolarBotALL) Equal to True
  • Actions
    • Custom script: local integer pn = GetConvertedPlayerId(GetOwningPlayer(udg_DamageEventTarget))
    • Custom script: set udg_fAI_run_tower[pn] = true
    • Set DamageEventAmount = (DamageEventAmount - 100.00)
    • Set TempPoint = (Center of PreviousTarget[(Player number of (Owner of DamageEventTarget))])
    • Unit - Order HERO_AI[(Player number of (Owner of DamageEventTarget))] to Move To TempPoint
    • Custom script: call RemoveLocation(udg_TempPoint)
    • Wait 2.00 seconds
    • Custom script: set udg_fAI_run_tower[pn] = false
1) I changed (Picked unit) to DamageEventTarget.
2) I use a local variable "pn" to store the Player number of the DamageEventTarget. This is safe to use even after Waits.
3) I moved "call RemoveLocation" so that it happens before the Wait. Anything that can be dealt with immediately SHOULD be.
 
Last edited:
I was tought you we're using PN for the make it easy instead of setting player number owner of bla bla. Thank you again dear Uncle. I am going to delete my few timers and create them just like this. Because this trigger works only for one unit per hero. No need to MUI. Thank you.
 
Update: Why TriggeringUnit or GetTriggeringUnit not works?

Custom script: local integer pn = GetConvertedPlayerId(GetOwningPlayer(udg_TriggeringUnit))
Custom script: local integer pn = GetConvertedPlayerId(GetOwningPlayer(udg_GetTriggeringUnit))
 
(Triggering unit) is an Event Response that calls a function which gets you the Unit mentioned in the Event. This function is called GetTriggerUnit().

You only use udg_ in your Custom Script to reference global Variables that you've created:
1755432030272.png


So if you want to reference (Triggering unit) in Custom Script then you can do one of these two:

1) Use _udg with one of your own Variables:
  • Actions
    • Custom script: local integer pn
    • Set MyUnitVariable = (Triggering unit)
    • Custom script: set pn = GetConvertedPlayerId(GetOwningPlayer(udg_MyUnitVariable))
2) Use a Jass function directly:
  • Actions
    • Custom script: local integer pn = GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))
Here's some more functions that you can use in your Custom Script:

GetTriggerUnit() = (Triggering unit)
GetKillingUnit() = (Killing unit)
GetAttacker() = (Attacking unit)
GetSummonedUnit() = (Summoned unit)
GetSpellTargetUnit() = (Target unit of ability being cast)
GetOrderTargetUnit() = (Target unit of issued order)
 
Last edited:
Sorry for ask again because this is not turns to False somehow. But in the same time i am using this more than 1 place.

  • run tower range
    • Events
      • Unit - A unit Begins channeling an ability
    • Conditions
      • fAI_run_tower[(Player number of (Owner of (Triggering unit)))] Equal to False
      • ((Triggering unit) belongs to an enemy of (Owner of (Target unit of ability being cast))) Equal to True
      • ((Target unit of ability being cast) is A Hero) Equal to True
      • ((Triggering unit) is in HerolarBotALL) Equal to True
    • Actions
      • Custom script: local integer pn = GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))
      • Custom script: set udg_fAI_run_tower[pn] = true
      • Set TempPoint = (Position of (Triggering unit))
      • Set TempGroup = (Units within 800.00 of TempPoint matching ((((Matching unit) is in zug_TowersALL) Equal to True) and ((((Matching unit) belongs to an enemy of (Owner of (Triggering unit))) Equal to True) and (((Matching unit) is alive) Equal to True))))
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in TempGroup) Greater than 0
        • Then - Actions
          • Unit - Order (Triggering unit) to Move To (Center of PreviousTarget[(Player number of (Owner of (Triggering unit)))])
          • Set fAI_run_tower[(Player number of (Owner of (Triggering unit)))] = True
        • Else - Actions
      • Custom script: call DestroyGroup(udg_TempGroup)
      • Custom script: call RemoveLocation(udg_TempPoint)
      • Wait 2.00 seconds
      • Custom script: set udg_fAI_run_tower[pn] = false

  • run tower dmg2
    • Events
      • Game - DamageModifierEvent becomes Equal to 1.00
    • Conditions
      • fAI_run_tower[(Player number of (Owner of DamageEventTarget))] Equal to False
      • (DamageEventSource is A structure) Equal to True
      • (DamageEventTarget is in HerolarBotALL) Equal to True
    • Actions
      • Custom script: local integer pn = GetConvertedPlayerId(GetOwningPlayer(udg_DamageEventTarget))
      • Custom script: set udg_fAI_run_tower[pn] = true
      • Set DamageEventAmount = (DamageEventAmount - 100.00)
      • Set TempPoint = (Center of PreviousTarget[(Player number of (Owner of DamageEventTarget))])
      • Unit - Order HERO_AI[(Player number of (Owner of DamageEventTarget))] to Move To TempPoint
      • Custom script: call RemoveLocation(udg_TempPoint)
      • Wait 2.00 seconds
      • Custom script: set udg_fAI_run_tower[pn] = false
First can we verify that am i using this wait thing correct in there?
I can see this not turns false because i have a debug system. @Uncle
 
Your first trigger should probably work like this:
  • run tower range
    • Events
      • Unit - A unit Begins channeling an ability
    • Conditions
      • fAI_run_tower[(Player number of (Owner of (Triggering unit)))] Equal to False
      • ((Triggering unit) belongs to an enemy of (Owner of (Target unit of ability being cast))) Equal to True
      • ((Target unit of ability being cast) is A Hero) Equal to True
      • ((Triggering unit) is in HerolarBotALL) Equal to True
    • Actions
      • Custom script: local integer pn = GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))
      • Set TempPoint = (Position of (Triggering unit))
      • Set TempGroup = (Units within 800.00 of TempPoint matching ((((Matching unit) is in zug_TowersALL) Equal to True) and ((((Matching unit) belongs to an enemy of (Owner of (Triggering unit))) Equal to True) and (((Matching unit) is alive) Equal to True))))
      • Custom script: call RemoveLocation(udg_TempPoint)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in TempGroup) Greater than 0
        • Then - Actions
          • Custom script: set udg_fAI_run_tower[pn] = true
          • Custom script: call DestroyGroup(udg_TempGroup)
          • Set TempPoint = (Center of PreviousTarget[(Player number of (Owner of (Triggering unit)))])
          • Unit - Order (Triggering unit) to Move To TempPoint
          • Custom script: call RemoveLocation(udg_TempPoint)
          • Wait 2.00 seconds
          • Custom script: set udg_fAI_run_tower[pn] = false
        • Else - Actions
          • Custom script: call DestroyGroup(udg_TempGroup)

But you can debug by adding Text Messages to both triggers:
  • Custom script: set udg_fAI_run_tower[pn] = true
  • Custom script: call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "TRUE, pn: " + I2S(pn))
  • Custom script: set udg_fAI_run_tower[pn] = false
  • Custom script: call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "FALSE, pn: " + I2S(pn))
If that doesn't fix it, then either pn is the wrong Player Number or you're changing it somewhere else. You could also be reusing global variables a bit too much, overwriting them accidentally.
 
Last edited:
I was shared my system with people in here [General] - AI system by me. Specially for AoS/MOBA but still includes lot of bugs (i think) but still i have a serious problems with my own AI system. Always i am doing dozens of tests and if i cannot solve it, i am creating post about it.
Now this one is bit of complicated and i have recorded video about it. It is better than sharing all triggers.


Update: I did some changes after shared video.

  • DoNotFightWhenTowerAround
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • ((Attacked unit) belongs to an enemy of (Owner of (Attacking unit))) Equal to True
      • ((Attacked unit) is A Hero) Equal to True
      • ((Attacking unit) is in HerolarBotALL) Equal to True
    • Actions
      • Custom script: local integer pn2 = GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))
      • Set TempPoint = (Position of (Attacked unit))
      • Set TempGroup = (Units within 800.00 of TempPoint matching ((((Matching unit) is in zug_TowersALL) Equal to True) and ((((Matching unit) belongs to an enemy of (Owner of (Attacking unit))) Equal to True) and (((Matching unit) is alive) Equal to True))))
      • Custom script: call RemoveLocation(udg_TempPoint)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in TempGroup) Greater than 0
        • Then - Actions
          • Custom script: set udg_fAI_run_tower[pn2] = true
          • Set TempPoint = (Center of PreviousTarget[(Player number of (Owner of (Attacking unit)))])
          • Unit - Order (Triggering unit) to Move To TempPoint
          • Custom script: call RemoveLocation(udg_TempPoint)
          • Custom script: call DestroyGroup(udg_TempGroup)
          • Wait 2.00 seconds
          • Custom script: set udg_fAI_run_tower[pn2] = false
        • Else - Actions
      • Custom script: call DestroyGroup(udg_TempGroup)

  • run tower range
    • Events
      • Unit - A unit Begins channeling an ability
    • Conditions
      • fAI_run_tower[(Player number of (Owner of (Triggering unit)))] Equal to False
      • ((Triggering unit) belongs to an enemy of (Owner of (Target unit of ability being cast))) Equal to True
      • ((Target unit of ability being cast) is A Hero) Equal to True
      • ((Triggering unit) is in HerolarBotALL) Equal to True
    • Actions
      • Custom script: local integer pn2 = GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))
      • Set TempPoint = (Position of (Triggering unit))
      • Set TempGroup = (Units within 800.00 of TempPoint matching ((((Matching unit) is in zug_TowersALL) Equal to True) and ((((Matching unit) belongs to an enemy of (Owner of (Triggering unit))) Equal to True) and (((Matching unit) is alive) Equal to True))))
      • Custom script: call RemoveLocation(udg_TempPoint)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in TempGroup) Greater than 0
        • Then - Actions
          • Custom script: set udg_fAI_run_tower[pn2] = true
          • Custom script: call DestroyGroup(udg_TempGroup)
          • Set TempPoint = (Center of PreviousTarget[(Player number of (Owner of (Triggering unit)))])
          • Unit - Order (Triggering unit) to Move To TempPoint
          • Custom script: call RemoveLocation(udg_TempPoint)
          • Custom script: call DestroyGroup(udg_TempGroup)
          • Wait 2.00 seconds
          • Custom script: set udg_fAI_run_tower[pn2] = false
        • Else - Actions
      • Custom script: call DestroyGroup(udg_TempGroup)

  • run tower dmg2
    • Events
      • Game - DamageModifierEvent becomes Equal to 1.00
    • Conditions
      • fAI_run_tower[(Player number of (Owner of DamageEventTarget))] Equal to False
      • (DamageEventSource is A structure) Equal to True
      • (DamageEventTarget is in HerolarBotALL) Equal to True
    • Actions
      • Custom script: local integer pn2 = GetConvertedPlayerId(GetOwningPlayer(udg_DamageEventTarget))
      • Custom script: set udg_fAI_run_tower[pn2] = true
      • Set DamageEventAmount = (DamageEventAmount - 100.00)
      • Set TempPoint = (Center of PreviousTarget[(Player number of (Owner of DamageEventTarget))])
      • Unit - Order HERO_AI[(Player number of (Owner of DamageEventTarget))] to Move To TempPoint
      • Custom script: call RemoveLocation(udg_TempPoint)
      • Wait 2.00 seconds
      • Custom script: set udg_fAI_run_tower[pn2] = false

  • run creep
    • Events
      • Game - DamageModifierEvent becomes Equal to 1.00
    • Conditions
      • fAI_run_creep[(Player number of (Owner of DamageEventTarget))] Equal to False
      • (DamageEventTarget is in HerolarBotALL) Equal to True
      • (DamageEventTarget is in zUG_RegenALL) Equal to False
      • (Level of DamageEventTarget) Less than or equal to 21
      • Or - Any (Conditions) are true
        • Conditions
          • (DamageEventSource is in zUG_CreepsDevil) Equal to True
          • (DamageEventSource is in zUG_CreepsReaper) Equal to True
    • Actions
      • Custom script: local integer pn2 = GetConvertedPlayerId(GetOwningPlayer(udg_DamageEventTarget))
      • Custom script: set udg_fAI_run_creep[pn2] = true
      • Set TempPoint = ((Position of DamageEventTarget) offset by 375.00 towards ((Angle from (Position of DamageEventSource) to (Center of PreviousTarget[(Player number of (Owner of DamageEventTarget))])) - 0.00) degrees)
      • Unit - Order DamageEventTarget to Move To TempPoint
      • Custom script: call RemoveLocation (udg_TempPoint)
      • Wait 1.00 seconds
      • Custom script: set udg_fAI_run_creep[pn2] = false
 
Last edited:
Trigger1 is missing a Condition to prevent it from running more than once. You also put DestroyGroup in the wrong spot at the end:
  • DoNotFightWhenTowerAround
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • fAI_run_creep[(Player number of (Owner of (Attacked unit)))] Equal to False
      • ((Attacked unit) belongs to an enemy of (Owner of (Attacking unit))) Equal to True
      • ((Attacked unit) is A Hero) Equal to True
      • ((Attacking unit) is in HerolarBotALL) Equal to True
    • Actions
      • Custom script: local integer pn2 = GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))
      • Set TempPoint = (Position of (Attacked unit))
      • Set TempGroup = (Units within 800.00 of TempPoint matching ((((Matching unit) is in zug_TowersALL) Equal to True) and ((((Matching unit) belongs to an enemy of (Owner of (Attacking unit))) Equal to True) and (((Matching unit) is alive) Equal to True))))
      • Custom script: call RemoveLocation(udg_TempPoint)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in TempGroup) Greater than 0
        • Then - Actions
          • Custom script: set udg_fAI_run_tower[pn2] = true
          • Set TempPoint = (Center of PreviousTarget[(Player number of (Owner of (Attacked unit)))])
          • Unit - Order (Attacked unit) to Move To TempPoint
          • Custom script: call RemoveLocation(udg_TempPoint)
          • Custom script: call DestroyGroup(udg_TempGroup)
          • Wait 2.00 seconds
          • Custom script: set udg_fAI_run_tower[pn2] = false
        • Else - Actions
          • Custom script: call DestroyGroup(udg_TempGroup)
Then I would combine Trigger3 and Trigger4 into one trigger, otherwise they will fight with one another since they use the same Event:
  • RunFromTower
    • Events
      • Game - DamageModifierEvent becomes Equal to 1.00
    • Conditions
      • fAI_run_tower[(Player number of (Owner of DamageEventTarget))] Equal to False
      • (DamageEventTarget is in HerolarBotALL) Equal to True
    • Actions
      • Custom script: local integer pn2 = GetConvertedPlayerId(GetOwningPlayer(udg_DamageEventTarget))
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
        • (DamageEventSource is A structure) Equal to True
        • Then - Actions
          • -------- RUN FROM TOWER --------
          • Custom script: set udg_fAI_run_creep[pn2] = true
          • Set TempPoint = (Center of PreviousTarget[(Player number of (Owner of DamageEventTarget))])
          • Unit - Order DamageEventTarget to Move To TempPoint
          • Custom script: call RemoveLocation (udg_TempPoint)
          • Wait 2.00 seconds
          • Custom script: set udg_fAI_run_creep[pn2] = false
        • Else - Actions
          • -------- RUN FROM CREEPS --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
            • (DamageEventTarget is in zUG_RegenALL) Equal to False
            • (Level of DamageEventTarget) Less than or equal to 21
            • Or - Any (Conditions) are true
              • Conditions
              • (DamageEventSource is in zUG_CreepsDevil) Equal to True
              • (DamageEventSource is in zUG_CreepsReaper) Equal to True
            • Then - Actions
              • Custom script: set udg_fAI_run_creep[pn2] = true
              • Set TempPoint2 = (Position of DamageEventTarget)
              • Set TempPoint3 = (Center of PreviousTarget[(Player number of (Owner of DamageEventTarget))
              • Set TempPoint = (TempPoint2 offset by 375.00 towards ((Angle from TempPoint2 to TempPoint3)) degrees)
              • Unit - Order DamageEventTarget to Move To TempPoint
              • Custom script: call RemoveLocation (udg_TempPoint)
              • Custom script: call RemoveLocation (udg_TempPoint2)
              • Custom script: call RemoveLocation (udg_TempPoint3)
              • Wait 1.00 seconds
              • Custom script: set udg_fAI_run_creep[pn2] = false
            • Else - Actions
I also cleaned up some Point (location) memory leaks.
 
Last edited:
You are amazing as always. I have to close this one as solved (already did) and i will create new topic if i have more questions.
I was planning to combine triggers but first i was need to find problems. But i do not understand one thing. Why we are destroying tempgroup in Else but not bottom of the triggers? @Uncle

Update: Is there any problem with combined triggers? Are we checking bot run tower and run creep? Because tested it just now and still not turning false. But let me create net topic about that. Well organized new and fresh topic that everything explained better.
 
Last edited:
Back
Top