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

[Solved] Priority for healing-type spells targeting (Custom Logic)

Level 13
Joined
Feb 5, 2018
Messages
567
Hello,

I would like to have all healing spells e.g Holy Light, Rejuvenation, Healing Wave, etc to have target priority in the unit group iteration.

It would be best if we could have the targering prio:

1) First priority is to target melee (frontline) units. /// if no melee units are present then switch to prio 2
2) Target the most "wounded" unit on your team.
?(3) Maybe target self if the caster is "in combat", taking damage from an enemy or taken X amount of damage in Y time. This could be the second highest priority if it's not too hard to produce.

So the first prio would be to target a melee unit with least life remaining. Currently im just using a get random unit from unit group with life less than unit max hp. And to the reason I would like to have this is that my current project will be mostly played front-to-back style with some small nuances. The player units are given to an ai player and all units will cast their spells when they have reached their maxium mana.

I had some attempts on this, but unfortunately it was a failure. Below is the normal trigger that just finds one target randomly without any priority.

  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • (Unit-type of DamageEventSource) Equal to Priest
    • Then - Actions
      • Set VariableSet PriestHealerPoint = (Position of DamageEventSource)
      • Set VariableSet PriestHealGroup = (Units within 900.00 of PriestHealerPoint.)
      • Unit Group - Pick every unit in PriestHealGroup and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) is alive) Equal to True
              • ((Picked unit) belongs to an ally of (Owner of DamageEventSource).) Equal to True
              • ((Picked unit) is A structure) Equal to False
              • ((Picked unit) is Mechanical) Equal to False
              • (Life of (Picked unit)) Less than (Max life of (Picked unit))
            • Then - Actions
              • -------- Filter Only --------
            • Else - Actions
              • Unit Group - Remove (Picked unit) from PriestHealGroup.
      • Unit Group - Pick every unit in (Random 1 units from PriestHealGroup) and do (Actions)
        • Loop - Actions
          • Set VariableSet PriestHealTarget = (Picked unit)
          • Unit - Order DamageEventSource to Human Paladin - Holy Light PriestHealTarget
      • Custom script: call DestroyGroup(udg_PriestHealGroup)
      • Custom script: call RemoveLocation(udg_PriestHealerPoint)
    • Else - Actions
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
So this section of your trigger is incorrect and leaks a Unit Group:
  • Unit Group - Pick every unit in (Random 1 units from PriestHealGroup) and do (Actions)
    • Loop - Actions
      • Set VariableSet PriestHealTarget = (Picked unit)
      • Unit - Order DamageEventSource to Human Paladin - Holy Light PriestHealTarget
You would simply want to get a random unit from the group:
  • Set VariableSet PriestHealTarget = (Random unit from PriestHealGroup)
  • Unit - Order DamageEventSource to Human Paladin - Holy Light PriestHealTarget

But that setup still doesn't do everything you want. Here's how you can incorporate #1 and #2:
  • Actions
    • -------- Get nearby allied units and put them into a group --------
    • Set PriestHealerPoint = (Position of DamageEventSource)
    • Set PriestHealGroup = (Units within 900.00 range of PriestHealerPoint matching (Matching unit is alive) Equal to True and (Matching unit is an ally) Equal to True
    • -------- Get the unit with the least amount of hp from this group --------
    • Set LeastUnit = No unit
    • Set LeastMeleeUnit = No unit
    • Set LeastHP = 999999.00
    • Unit Group - Pick every unit in PriestHealGroup and do (Actions)
      • Loop - Actions
        • Set CurrentHP = (Percentage life of (Picked unit))
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • CurrentHP Less than LeastHP
          • Then - Actions
            • Set LeastHP = CurrentHP
            • Set LeastUnit = (Picked unit)
            • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • (LeastUnit is a Melee attacker) Equal to True
              • Then - Actions
                • Set LeastMeleeUnit = LeastUnit
              • Else - Actions
          • Else - Actions
    • -------- From this point on you can have the melee unit with the least hp and any unit with the least hp (can be the same) --------
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • LeastMeleeUnit Not equal to No unit
      • Then - Actions
        • Unit - Order DamageEventSource to Human Paladin - Holy Light LeastMeleeUnit
      • Else - Actions
        • Unit - Order DamageEventSource to Human Paladin - Holy Light LeastUnit
This will prioritize the most wounded melee unit and if no melee units are found it'll instead try to prioritize the most wounded ranged unit. Note that I'm using Percentage Life here since that's a better representation of missing life than flat life values (a 200/200 HP unit would appear more wounded than a 300/500 HP unit if we relied on flat values).

If you wanted to find the greatest HP unit you would simply reverse the logic. That means LeastHP would be set to 0 and you would check if CurrentHP is Greater than LeastHP. Note that this method can be applied to anything that involves comparing Integers/Reals. For example, this could be used to determine the closest/furthest unit by comparing their Distance values from a static Point.

Then to include #3, it's not that difficult to track how much damage a unit has taken recently, for example in the last 4 seconds:
  • Events
    • Game - DamageEvent becomes Equal to 1.00
  • Conditions
  • Actions
    • Custom script: local integer cv = GetUnitUserData( udg_DamageEventTarget )
    • Custom script: local real dmg = udg_DamageEventAmount
    • Custom script: set udg_Damage_Taken_Recently[cv] = udg_Damage_Taken_Recently[cv] + dmg
    • Wait 4.00 game-time seconds
    • Custom script: set udg_Damage_Taken_Recently[cv] = RMaxBJ((udg_Damage_Taken_Recently[cv] - (dmg + 0.01)), 0.00)
This new trigger relies on a Unit Indexer to make it MUI (works for any number of units at the same time) and you would need to create a Real array variable called Damage_Taken_Recently. You could add a Condition to make it only run for your Priest, but it may be useful to track this for all Units. So as long as this variable is > 0.00 you will know that the unit has been damaged recently. This tells you that it's "in combat", plus the exact value helps you determine how severe the damage has been.

You could then incorporate this into the Priest trigger like so:
  • Actions
    • -------- First try to heal yourself if it seems urgent --------
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • Damage_Taken_Recently[(Custom value of DamageEventSource)] Greater than or equal to 400.00
      • Then - Actions
        • Unit - Order DamageEventSource to Human Paladin - Holy Light DamageEventSource
        • Skip remaining actions
      • Else - Actions
    • -------- --------
    • -------- Otherwise, get nearby allied units and put them into a group --------
    • Set PriestHealerPoint = (Position of DamageEventSource)
    • Set PriestHealGroup = (Units within 900.00 range of PriestHealerPoint matching (Matching unit is alive) Equal to True and (Matching unit is an ally) Equal to True
    • -------- Get the unit with the least amount of hp from this group --------
    • Set LeastUnit = No unit
    • Set LeastMeleeUnit = No unit
    • Set LeastHP = 999999.00
    • Unit Group - Pick every unit in PriestHealGroup and do (Actions)
      • Loop - Actions
        • Set CurrentHP = (Percentage life of (Picked unit))
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • CurrentHP Less than LeastHP
          • Then - Actions
            • Set LeastHP = CurrentHP
            • Set LeastUnit = (Picked unit)
            • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • (LeastUnit is a Melee attacker) Equal to True
              • Then - Actions
                • Set LeastMeleeUnit = LeastUnit
              • Else - Actions
          • Else - Actions
    • -------- From this point on you can have the melee unit with the least hp and any unit with the least hp (can be the same) --------
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • LeastMeleeUnit Not equal to No unit
      • Then - Actions
        • Unit - Order DamageEventSource to Human Paladin - Holy Light LeastMeleeUnit
      • Else - Actions
        • Unit - Order DamageEventSource to Human Paladin - Holy Light LeastUnit
Remember to clean up the PriestHealerPoint and PriestHealGroup memory leaks at the very end.
 
Last edited:
Level 13
Joined
Feb 5, 2018
Messages
567
This new trigger relies on a Unit Indexer to make it MUI (works for any number of units at the same time) and you would need to create a Real array variable called Damage_Taken_Recently.
Ofcourse. I have been using this all the time in my projects.
So this section of your trigger is incorrect and leaks a Unit Group:
  • unitgroup.gif
    Unit Group - Pick every unit in (Random 1 units from PriestHealGroup) and do (Actions)
    • joinbottomminus.gif
      actions.gif
      Loop - Actions
      • empty.gif
        join.gif
        set.gif
        Set VariableSet PriestHealTarget = (Picked unit)
      • empty.gif
        joinbottom.gif
        unit.gif
        Unit - Order DamageEventSource to Human Paladin - Holy Light PriestHealTarget
Woops. I am pretty this is what I have used for years :D


I tested your triggers in practice with 50 units and hundreds of damage events and triggers firing at the same time and worked without any issues. Thank you Uncle :) you are the boss!
 
Top