• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Spell] Disable any kind of health regeneration in a certain area

Status
Not open for further replies.
Level 5
Joined
Feb 18, 2016
Messages
96
Hello
Does somebody know a way to make all sources of healing (like lifesteals, spells, and even unit regeneration) in a certain area
I tried to do it by myself but it did not work

  • Anular
    • Events
      • Time - Every 0.5 seconds of game time
    • Conditions
    • Actions
      • Set Center = Tower <gen>
      • Set APOINTTEMP = (Position of Center)
      • Set Group = (Units within 400.00 of APOINTTEMP)
      • Custom script: call RemoveLocation (udg_APOINTTEMP)
      • Unit Group - Pick every unit in Group and do (Actions)
        • Loop - Actions
          • Set Real = (Life of (Picked unit))
          • Wait 0.45 seconds
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Life of (Picked unit)) Greater than Real
            • Then - Actions
              • Unit - Set life of (Picked unit) to Real
            • Else - Actions
      • Custom script: call DestroyGroup (udg_Group)
 
You would need to catch the units that are in the region first, (using a Unit Enters Region event), and include them in a group. You would also need to store their health at the time that they entered. This could be done with this:

Hashtable

Arrays


Initialization:
  • Events
    • - map initialization
  • Conditions -
  • Actions -
    • Hashtable - Create a hashtable
    • Set <hash_var> = (last created hashtable)
    • Custom script : set udg_Group = CreateGroup()
    • Comment - The custom script done above creates a group for us to use later on.
    • Comment - Do note that an uninitialized group variable would be useless when adding units to it directly.
Enter Trigger:
  • Events
    • - A unit enters (designated region)
  • Conditions -
  • Actions -
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Number of units in Group) equal to 0
      • Then - Actions
        • Trigger - Enable Anular <gen>
      • Else - Actions
    • Unit Group - Add (Triggering Unit) to udg_Group
    • Hashtable - Save (Life of (Triggering unit)) as (Key (Triggering unit)) of (0) in <hash_var>
    • Comment - This saves the data in the hashtable, which in this case is the life of the triggering unit.
    • Comment - To access the data stored inside, you would need to call the following function
    • Hashtable - Load (Key (Triggering unit)) of (0) from <hash_var>
    • Comment - (Key (Triggering unit)) is a unique handle id given to the triggering unit while
    • Comment - 0 is an integer that represents the parent key hashtable. It could be any number that you wish to use.
Exit Trigger:
  • Events
    • - A unit leaves (designated region)
  • Conditions -
  • Actions -
    • Unit Group - Remove (Triggering Unit) from udg_Group
    • Hashtable - Save 0. as (Key (Triggering unit)) of (0) in <hash_var>
    • Comment - This effectively flushes out the data stored in the hashtable
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Number of units in Group) equal to 0
      • Then - Actions
        • Trigger - Disable Anular <gen>
      • Else - Actions
  • Anular
    • Events
      • Time - Every 0.5 seconds of game time
    • Conditions
    • Actions
      • Set Center = Tower <gen>
      • Set APOINTTEMP = (Position of Center)
      • Set Group = (Units within 400.00 of APOINTTEMP)
      • Custom script: call RemoveLocation (udg_APOINTTEMP)
      • Unit Group - Pick every unit in Group and do (Actions)
        • Loop - Actions
          • Set Real = (Life of (Picked unit))
          • Wait 0.45 seconds
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Life of (Picked unit)) Greater than Real
            • Then - Actions
              • Unit - Set life of (Picked unit) to Real
            • Else - Actions
      • Custom script: call DestroyGroup (udg_Group)

The Iteration trigger:
(Note: This trigger should be disabled by default)
  • Anular
    • Events
      • Time - Every 0.5 seconds of game time
    • Conditions
    • Actions
      • Comment - You would no longer need these variables below...
      • Set Center = Tower <gen>
      • Set APOINTTEMP = (Position of Center)
      • Set Group = (Units within 400.00 of APOINTTEMP)
      • Custom script: call RemoveLocation (udg_APOINTTEMP)
      • Comment - ...above
      • Comment -
      • Unit Group - Pick every unit in Group and do (Actions)
        • Loop - Actions
          • Set Real = (Load (Key (Picked unit)) of (0) from <hash_var>)
          • Comment - The following wait function is unnecessary
          • Wait 0.45 seconds
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Life of (Picked unit)) not equal to Real
            • Then - Actions
              • Unit - Set life of (Picked unit) to Real
            • Else - Actions
      • Comment - Since the group variable will be in use for the whole game, you could just delete the line below.
      • Custom script: call DestroyGroup (udg_Group)


We'll try the same thing, only with arrays

Initialization:
  • Init
    • Events
      • - map initialization
    • Conditions
    • Actions
    • Custom Script: set udg_Group = CreateGroup()
    • Comment - What we'll need is a real array variable, and an integer array variable...
An allocation and deallocation function. You'll need to move this to the map header
JASS:
function <unique-name>_allocate takes nothing returns integer
    local integer this = <int_arr>[0]
    if <int_arr>[this] == 0 then
        set this = this + 1
        set <int_arr>[0] = this
        return this
    endif
    set <int_arr>[0] = <int_arr>[this]
    set <int_arr>[this] = 0
    return this
endfunction

function <unique-name>_deallocate takes integer this returns nothing
    set <int_arr>[this] = <int_arr>[0]
    set <int_arr>[0] = this
endfunction

Enter Trigger
  • Events
    • - A unit enters (designated region)
  • Conditions -
  • Actions -
    • Custom Script: local integer <int_shadow> = <unique-name>_allocate()
    • Comment - The <int_shadow> can be a global variable or a local one. If the former, this allows for persistent GUI.
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Number of units in Group) equal to 0
      • Then - Actions
        • Trigger - Enable Anular <gen>
      • Else - Actions
    • Unit Group - Add (Triggering Unit) to udg_Group
    • set <real_arr>[<int_shadow>] = Life of (Triggering Unit)
    • Comment - If you aren't using any systems that are utilizing User Data for units, then you can assign the User Data to the triggering unit,..
    • Comment - provided that they do not become overridden.
    • Unit - Set the custom value of (Triggering unit) to <int_shadow>
    • Comment - If it really is a local variable without the udg_ prefix, use this instead..
    • Custom Script - call SetUnitUserData(GetTriggerUnit(), <int_shadow>)
Exit Trigger:
  • Events
    • - A unit leaves (designated region)
  • Conditions -
  • Actions -
    • Unit Group - Remove (Triggering Unit) from udg_Group
    • set <real_arr>[Custom value of (Triggering Unit)] = 0.
    • Custom Script: call <unique-name>_deallocate(GetUnitUserData(GetTriggerUnit()))
    • Unit - Set the custom value of (Triggering Unit) to 0.
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Number of units in Group) equal to 0
      • Then - Actions
        • Trigger - Disable Anular <gen>
      • Else - Actions
The Iteration trigger:

  • Anular
    • Events
      • Time - Every 0.5 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in Group and do (Actions)
        • Loop - Actions
          • Set Real = <real_arr>[Custom value of (Picked unit)]
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Life of (Picked unit)) not equal to Real
            • Then - Actions
              • Unit - Set life of (Picked unit) to Real
            • Else - Actions
<unique-name> is a name-placer for your function, you can change it to whatever you like.

 
Last edited:

Jampion

Code Reviewer
Level 15
Joined
Mar 25, 2016
Messages
1,327
I only looked very short at the triggers, but wouldn't that also disable any kind of damage?
Using a dds you can change the stored health whenever the unit takes damage to not disable damage at the same time.
 
Level 5
Joined
Feb 18, 2016
Messages
96
You would need to catch the units that are in the region first, (using a Unit Enters Region event), and include them in a group. You would also need to store their health at the time that they entered. This could be done with this:

Hashtable

Arrays


Initialization:
  • Events
    • - map initialization
  • Conditions -
  • Actions -
    • Hashtable - Create a hashtable
    • Set <hash_var> = (last created hashtable)
    • Custom script : set udg_Group = CreateGroup()
    • Comment - The custom script done above creates a group for us to use later on.
    • Comment - Do note that an uninitialized group variable would be useless when adding units to it directly.
Enter Trigger:
  • Events
    • - A unit enters (designated region)
  • Conditions -
  • Actions -
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Number of units in Group) equal to 0
      • Then - Actions
        • Trigger - Enable Anular <gen>
      • Else - Actions
    • Unit Group - Add (Triggering Unit) to udg_Group
    • Hashtable - Save (Life of (Triggering unit)) as (Key (Triggering unit)) of (0) in <hash_var>
    • Comment - This saves the data in the hashtable, which in this case is the life of the triggering unit.
    • Comment - To access the data stored inside, you would need to call the following function
    • Hashtable - Load (Key (Triggering unit)) of (0) from <hash_var>
    • Comment - (Key (Triggering unit)) is a unique handle id given to the triggering unit while
    • Comment - 0 is an integer that represents the parent key hashtable. It could be any number that you wish to use.
Exit Trigger:
  • Events
    • - A unit leaves (designated region)
  • Conditions -
  • Actions -
    • Unit Group - Remove (Triggering Unit) from udg_Group
    • Hashtable - Save 0. as (Key (Triggering unit)) of (0) in <hash_var>
    • Comment - This effectively flushes out the data stored in the hashtable
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Number of units in Group) equal to 0
      • Then - Actions
        • Trigger - Disable Anular <gen>
      • Else - Actions


The Iteration trigger:
(Note: This trigger should be disabled by default)
  • Anular
    • Events
      • Time - Every 0.5 seconds of game time
    • Conditions
    • Actions
      • Comment - You would no longer need these variables below...
      • Set Center = Tower <gen>
      • Set APOINTTEMP = (Position of Center)
      • Set Group = (Units within 400.00 of APOINTTEMP)
      • Custom script: call RemoveLocation (udg_APOINTTEMP)
      • Comment - ...above
      • Comment -
      • Unit Group - Pick every unit in Group and do (Actions)
        • Loop - Actions
          • Set Real = (Load (Key (Picked unit)) of (0) from <hash_var>)
          • Comment - The following wait function is unnecessary
          • Wait 0.45 seconds
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Life of (Picked unit)) not equal to Real
            • Then - Actions
              • Unit - Set life of (Picked unit) to Real
            • Else - Actions
      • Comment - Since the group variable will be in use for the whole game, you could just delete the line below.
      • Custom script: call DestroyGroup (udg_Group)


We'll try the same thing, only with arrays

Initialization:
  • Init
    • Events
      • - map initialization
    • Conditions
    • Actions
    • Custom Script: set udg_Group = CreateGroup()
    • Comment - What we'll need is a real array variable, and an integer array variable...
An allocation and deallocation function. You'll need to move this to the map header
JASS:
function <unique-name>_allocate takes nothing returns integer
    local integer this = <int_arr>[0]
    if <int_arr>[this] == 0 then
        set this = this + 1
        set <int_arr>[0] = this
        return this
    endif
    set <int_arr>[0] = <int_arr>[this]
    set <int_arr>[this] = 0
    return this
endfunction

function <unique-name>_deallocate takes integer this returns nothing
    set <int_arr>[this] = <int_arr>[0]
    set <int_arr>[0] = this
endfunction

Enter Trigger
  • Events
    • - A unit enters (designated region)
  • Conditions -
  • Actions -
    • Custom Script: local integer <int_shadow> = <unique-name>_allocate()
    • Comment - The <int_shadow> can be a global variable or a local one. If the former, this allows for persistent GUI.
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Number of units in Group) equal to 0
      • Then - Actions
        • Trigger - Enable Anular <gen>
      • Else - Actions
    • Unit Group - Add (Triggering Unit) to udg_Group
    • set <real_arr>[<int_shadow>] = Life of (Triggering Unit)
    • Comment - If you aren't using any systems that are utilizing User Data for units, then you can assign the User Data to the triggering unit,..
    • Comment - provided that they do not become overridden.
    • Unit - Set the custom value of (Triggering unit) to <int_shadow>
    • Comment - If it really is a local variable without the udg_ prefix, use this instead..
    • Custom Script - call SetUnitUserData(GetTriggerUnit(), <int_shadow>)
Exit Trigger:
  • Events
    • - A unit leaves (designated region)
  • Conditions -
  • Actions -
    • Unit Group - Remove (Triggering Unit) from udg_Group
    • set <real_arr>[Custom value of (Triggering Unit)] = 0.
    • Custom Script: call <unique-name>_deallocate(GetUnitUserData(GetTriggerUnit()))
    • Unit - Set the custom value of (Triggering Unit) to 0.
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Number of units in Group) equal to 0
      • Then - Actions
        • Trigger - Disable Anular <gen>
      • Else - Actions
The Iteration trigger:

  • Anular
    • Events
      • Time - Every 0.5 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in Group and do (Actions)
        • Loop - Actions
          • Set Real = <real_arr>[Custom value of (Picked unit)]
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Life of (Picked unit)) not equal to Real
            • Then - Actions
              • Unit - Set life of (Picked unit) to Real
            • Else - Actions
<unique-name> is a name-placer for your function, you can change it to whatever you like.



It is perfectly working. thank you but i have 1 more question

I understood how these triggers work and i also tried to make it with a unit but it does not work and i can not finde where my error is
May you help me?

  • AnularHP
    • Events
      • Time - Every 0.50 seconds of game time
    • Conditions
    • Actions
      • Set APOINTTEMP = (Position of Unit)
      • Set GroupB = (Units within 800.00 of APOINTTEMP)
      • Unit Group - Pick every unit in GroupB and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) has buff Anular ) Equal to True
              • ((Picked unit) is in Group) Equal to False
            • Then - Actions
              • Unit Group - Add (Picked unit) to Group
              • Hashtable - Save (Life of (Picked unit)) as (Key (Picked unit)) of 0 in HashVar
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) is in Group) Equal to True
              • ((Picked unit) has buff Anular ) Equal to False
            • Then - Actions
              • Unit Group - Remove (Picked unit) from Group
              • Hashtable - Save 0.00 as (Key (Picked unit)) of 0 in HashVar
            • Else - Actions
      • Custom script: call RemoveLocation (udg_APOINTTEMP)
      • Custom script: call DestroyGroup (udg_GroupB)
      • Wait 0.48 seconds
      • Unit Group - Pick every unit in Group and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) belongs to an enemy of (Owner of Unit)) Equal to True
            • Then - Actions
              • Set Real = (Load (Key (Picked unit)) of 0 from HashVar)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Life of (Picked unit)) Greater than Real
                • Then - Actions
                  • Unit - Set life of (Picked unit) to Real
                • Else - Actions
            • Else - Actions
 
It is perfectly working. thank you but i have 1 more question

I understood how these triggers work and i also tried to make it with a unit but it does not work and i can not finde where my error is
May you help me?

  • AnularHP
    • Events
      • Time - Every 0.50 seconds of game time
    • Conditions
    • Actions
      • Set APOINTTEMP = (Position of Unit)
      • Set GroupB = (Units within 800.00 of APOINTTEMP)
      • Unit Group - Pick every unit in GroupB and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) has buff Anular ) Equal to True
              • ((Picked unit) is in Group) Equal to False
            • Then - Actions
              • Unit Group - Add (Picked unit) to Group
              • Hashtable - Save (Life of (Picked unit)) as (Key (Picked unit)) of 0 in HashVar
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) is in Group) Equal to True
              • ((Picked unit) has buff Anular ) Equal to False
            • Then - Actions
              • Unit Group - Remove (Picked unit) from Group
              • Hashtable - Save 0.00 as (Key (Picked unit)) of 0 in HashVar
            • Else - Actions
      • Custom script: call RemoveLocation (udg_APOINTTEMP)
      • Custom script: call DestroyGroup (udg_GroupB)
      • Wait 0.48 seconds
      • Unit Group - Pick every unit in Group and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) belongs to an enemy of (Owner of Unit)) Equal to True
            • Then - Actions
              • Set Real = (Load (Key (Picked unit)) of 0 from HashVar)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Life of (Picked unit)) Greater than Real
                • Then - Actions
                  • Unit - Set life of (Picked unit) to Real
                • Else - Actions
            • Else - Actions

I'll try polishing up your trigger instead:

  • AnularHP
    • Events
      • Time - Every 0.50 seconds of game time
    • Conditions
    • Actions
      • Set APOINTTEMP = (Position of Unit)
      • set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units within 800.00 of APOINTTEMP) and do (Actions)
        • Loop - Actions
          • Custom Script: if (GetUnitAbilityLevel(GetEnumUnit(), <ANULAR_raw>) != 0) then
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) is in Group) Equal to False
            • Then - Actions
              • Unit Group - Add (Picked unit) to Group
              • Hashtable - Save (Life of (Picked unit)) as (Key (Picked unit)) of 0 in HashVar
            • Else - Actions
          • Custom Script: else
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) is in Group) Equal to True
            • Then - Actions
              • Unit Group - Remove (Picked unit) from Group
              • Hashtable - Save 0.00 as (Key (Picked unit)) of 0 in HashVar
            • Else - Actions
          • Custom Script: endif
      • Custom script: call RemoveLocation (udg_APOINTTEMP)
      • Unit Group - Pick every unit in Group and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) belongs to an enemy of (Owner of Unit)) Equal to True
            • Then - Actions
              • Set Real = (Load (Key (Picked unit)) of 0 from HashVar)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Life of (Picked unit)) Greater than Real
                • Then - Actions
                  • Unit - Set life of (Picked unit) to Real
                • Else - Actions
            • Else - Actions
Explanation will be found in the spoiler below:

- As you have noticed, the GroupB variable simply disappeared, and you might worry about potential leaks. Worry not, for the global variable bj_wantDestroyGroup will help you.
The variable is set to true before the Unit Group - Pick every unit... action because of how it works. This delves into JASS territory so here it is:

JASS:
       function ForGroupBJ takes group whichGroup, code callback returns nothing
           // If the user wants the group destroyed, remember that fact and clear
           // the flag, in case it is used again in the callback.
           local boolean wantDestroy = bj_wantDestroyGroup
           set bj_wantDestroyGroup = false

           call ForGroup(whichGroup, callback)

           // If the user wants the group destroyed, do so now.
           if (wantDestroy) then
               call DestroyGroup(whichGroup)
           endif
       endfunction
The action Unit Group - Pick every unit ... is the function above in JASS. Now, let's look at (Units within 800.00 of APOINTTEMP)..

JASS:
       function GetUnitsInRangeOfLocAll takes real radius, location whichLocation returns group
           return GetUnitsInRangeOfLocMatching(radius, whichLocation, null)
       endfunction

If you have JNGP or WEX or JassCraft, you would notice that the function GetUnitsInRangeOfLocMatching declares a local group g which it initializes via CreateGroup(). Then it calls a native to include all units matching the conditions, destroys those conditions and returns that group. So it ends up being called once and only once.

If you don't have it, the function is stated as follows:
JASS:
       function GetUnitsInRangeOfLocMatching takes real radius, location whichLocation, boolexpr filter returns group
           local group g = CreateGroup()
           call GroupEnumUnitsInRangeOfLoc(g, whichLocation, radius, filter)
           call DestroyBoolExpr(filter)
           return g
        endfunction

Back to the Unit Group - Pick every unit..., you can observe that a group handle was created dynamically for a one-time use, making it a viable candidate for a bj_wantDestroyGroup = true declaration. This ends up destroying that group which prevents leakage of memory.

Phew... that was a lot to say, and that's just the first part.
 
Last edited:
Status
Not open for further replies.
Top