• 🏆 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!

[JASS] Help with spell

Status
Not open for further replies.
I'm trying to make an activateable/deactivateable spell that heals 3 units for 0.30 hit points every 0.03 seconds. I've managed to pull it off, but the spell is not MUI and bugs out when two units casts it. It drains mana until it reaches 0 or spell is deactivated. No two units can be healed by this spell at the same time.

This is what it looks like:
attachment.php


  • Reconstruction Beam OnActivate
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • Or - Any (Conditions) are true
        • Conditions
          • (Ability being cast) Equal to Reconstruction Beam ON
          • (Ability being cast) Equal to Reconstruction Beam OFF
    • Actions
      • Set ID_1 = (Custom value of (Triggering unit))
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Ability being cast) Equal to Reconstruction Beam ON
        • Then - Actions
          • Set RecBeam_MaxTargets[ID_1] = 4
          • Set RecBeam_MaxDistance[ID_1] = 450.00
          • Unit Group - Add (Triggering unit) to RecBeam_Group
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Reconstruction Beam OnLoop <gen> is on) Equal to False
            • Then - Actions
              • Trigger - Turn on Reconstruction Beam OnLoop <gen>
            • Else - Actions
          • Unit - Remove (Ability being cast) from (Triggering unit)
          • Unit - Add Reconstruction Beam OFF to (Triggering unit)
        • Else - Actions
          • Set RecBeam_RecBeamOff[ID_1] = True
          • Unit - Remove (Ability being cast) from (Triggering unit)
          • Unit - Add Reconstruction Beam ON to (Triggering unit)
JASS:
function Trig_Reconstruction_Beam_OnLoop_Actions takes nothing returns nothing

    local unit MC = null
    local unit u = null
    local unit array ViableTargets
    
    local integer id = 0
    local integer UnitID = 0
    local integer uIndex = 0
    local integer LoopCount = 0
    local integer RandomIndex = 0
    
    local real x1 = 0.00
    local real y1 = 0.00
    local real z1 = 0.00
    local real x2 = 0.00
    local real y2 = 0.00
    local real z2 = 0.00
    local real dx = 0.00
    local real dy = 0.00
    //local real angle = 0.00
    local real dist = 0.00
    local real UnitLife = 0.00
    local real HealAmount = 0.30
    
    loop
        set MC = FirstOfGroup(udg_RecBeam_Group)
        exitwhen MC == null
        
        set id = GetUnitUserData(MC)
        call GroupRemoveUnit(udg_RecBeam_Group, MC)
        if not udg_RecBeam_RecBeamOff[id] then
            call GroupAddUnit(udg_RecBeam_GroupTemp, MC)
        endif
        
        set x1 = GetUnitX(MC)
        set y1 = GetUnitY(MC)
        set z1 = GetUnitFlyHeight(MC) + 30
        
        loop // One MC can heal multiple units at the same time. This is what this loop is for.
            set LoopCount = LoopCount + 1
            exitwhen LoopCount >= udg_RecBeam_MaxTargets[id]
            
            //set UnitID = id * udg_RecBeam_MaxTargets[id] + LoopCount
            set UnitID = id * 4 + LoopCount
            
            set x2 = GetUnitX(udg_RecBeam_CurrentTarget[UnitID])
            set y2 = GetUnitY(udg_RecBeam_CurrentTarget[UnitID])
            set z2 = GetUnitFlyHeight(udg_RecBeam_CurrentTarget[UnitID]) + 60
            
            if udg_RecBeam_CurrentTarget[UnitID] == null then
            
                call GroupEnumUnitsInRange(udg_RecBeam_EnumGroup, x1, y1, udg_RecBeam_MaxDistance[id], null)
                
                if FirstOfGroup(udg_RecBeam_EnumGroup) != null then
                    loop // This loop filters out undesireable units. Alternatively, make a filter function somewhere to use with the GroupEnumUnitsInRange
                        set u = FirstOfGroup(udg_RecBeam_EnumGroup)
                        exitwhen u == null
                        
                        call GroupRemoveUnit(udg_RecBeam_EnumGroup, u)
                        set uIndex = GetUnitUserData(u)
                        set UnitLife = GetUnitState(u, UNIT_STATE_MAX_LIFE)
                        if IsUnitAlly(u, GetOwningPlayer(MC)) and GetUnitState(u, UNIT_STATE_LIFE) < UnitLife and GetUnitState(u, UNIT_STATE_LIFE) > 0.00 /*
                        */ and IsUnitType(u, UNIT_TYPE_MECHANICAL) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and u != MC and not udg_RecBeam_IsBeingHealed[uIndex] then
                            set RandomIndex = RandomIndex + 1
                            set ViableTargets[RandomIndex] = u
                        endif
                    endloop
                    
                    if RandomIndex > 0 then // this picks a random unit within the viable pool of pre-selected units
                        set udg_RecBeam_CurrentTarget[UnitID] = ViableTargets[GetRandomInt(1, RandomIndex)]
                        set uIndex = GetUnitUserData(udg_RecBeam_CurrentTarget[UnitID])
                        set udg_RecBeam_IsBeingHealed[uIndex] = true
                        
                        set udg_RecBeam_Caster[UnitID] = CreateUnit(GetOwningPlayer(MC), 'dumm', x1, y1, 0)
                        set udg_RecBeam_Mover[UnitID] = CreateUnit(GetOwningPlayer(MC), 'dumm', x2, y2, 0)
                        call PauseUnit(udg_RecBeam_Caster[UnitID], true)
                        call PauseUnit(udg_RecBeam_Mover[UnitID], true)
                        call UnitAddAbility(udg_RecBeam_Caster[UnitID], 'pbct')
                        call UnitAddAbility(udg_RecBeam_Mover[UnitID], 'pbct')
                        
                        set udg_RecBeam_LightningFX[UnitID] = AddLightningEx("GRSB", true, x1, y2, z1, x2, y2, z2)
                        call SetLightningColor(udg_RecBeam_LightningFX[UnitID], 0.20, 0.20, 1.00, 1.00)
                    
                        loop // this clears ViableTargets[RandomIndex]
                            exitwhen RandomIndex == 0
                            set ViableTargets[RandomIndex] = null
                            set RandomIndex = RandomIndex - 1
                        endloop
                    endif
                endif
                
            else
                set dx = x2 - x1
                set dy = y2 - y1
                set dist = SquareRoot(dx*dx + dy*dy) // this is necessary to see if the unit has gone out of healing range
                
                call SetUnitPosition(udg_RecBeam_Caster[UnitID], x1, y1)
                call SetUnitFlyHeight(udg_RecBeam_Caster[UnitID], z1, 0.00)
                
                call SetUnitPosition(udg_RecBeam_Mover[UnitID], x2, y2)
                call SetUnitFlyHeight(udg_RecBeam_Mover[UnitID], z2, 0.00)
                
                if udg_RecBeam_LightningFX[UnitID] != null then
                    call MoveLightningEx(udg_RecBeam_LightningFX[UnitID], true, x1, y1, z1, x2, y2, z2)
                endif
                
                set UnitLife = GetUnitState(udg_RecBeam_CurrentTarget[UnitID], UNIT_STATE_LIFE)
                if UnitLife >=  GetUnitState(udg_RecBeam_CurrentTarget[UnitID], UNIT_STATE_MAX_LIFE) or UnitLife <= 0.00 or dist > udg_RecBeam_MaxDistance[id] or udg_RecBeam_RecBeamOff[id] then
                    
                    set uIndex = GetUnitUserData(udg_RecBeam_CurrentTarget[UnitID])
                    set udg_RecBeam_IsBeingHealed[uIndex] = false
                    set udg_RecBeam_CurrentTarget[UnitID] = null
                    
                    //unpause the mover and caster and kill them
                    call PauseUnit(udg_RecBeam_Caster[UnitID], false)
                    call PauseUnit(udg_RecBeam_Mover[UnitID], false)
                    call UnitApplyTimedLife(udg_RecBeam_Mover[UnitID], 'BTLF', 0.01)
                    call UnitApplyTimedLife(udg_RecBeam_Caster[UnitID], 'BTLF', 0.01)
                    
                    // if there is a lightning fx, destroy it. This is also a precaution as destroying a null lightning variable will crash the game. I think...
                    // replacing a non-null lightning with another one does crash the game for sure though.
                    if udg_RecBeam_LightningFX[UnitID] != null then
                        call DestroyLightning(udg_RecBeam_LightningFX[UnitID])
                        set udg_RecBeam_LightningFX[UnitID] = null
                    endif
                else
                    call SetUnitState(udg_RecBeam_CurrentTarget[UnitID], UNIT_STATE_LIFE, UnitLife + HealAmount)
                    call SetUnitState(MC, UNIT_STATE_MANA, GetUnitState(MC, UNIT_STATE_MANA) - 0.06)
                    if GetUnitState(MC, UNIT_STATE_MANA) <= 0.1 then
                        //call IssueImmediateOrder(MC, "channel")
                        set udg_RecBeam_RecBeamOff[id] = true
                        call UnitRemoveAbility(MC, 'trbd')
                        call UnitAddAbility(MC, 'trba')
                    endif
                endif
                
            endif
            
        endloop
    
    endloop
    
    if udg_RecBeam_RecBeamOff[id] == true then
        set udg_RecBeam_RecBeamOff[id] = false
    endif
    
    loop
        set MC = FirstOfGroup(udg_RecBeam_GroupTemp)
        exitwhen MC == null
        call GroupRemoveUnit(udg_RecBeam_GroupTemp, MC)
        call GroupAddUnit(udg_RecBeam_Group, MC)
    endloop
    
    if FirstOfGroup(udg_RecBeam_Group) == null then
        call DisableTrigger(GetTriggeringTrigger())
    endif

endfunction

//===========================================================================
function InitTrig_Reconstruction_Beam_OnLoop takes nothing returns nothing
    set gg_trg_Reconstruction_Beam_OnLoop = CreateTrigger(  )
    call DisableTrigger( gg_trg_Reconstruction_Beam_OnLoop )
    call TriggerRegisterTimerEvent( gg_trg_Reconstruction_Beam_OnLoop, 0.03, true )
    call TriggerAddAction( gg_trg_Reconstruction_Beam_OnLoop, function Trig_Reconstruction_Beam_OnLoop_Actions )
endfunction

There are two suspected culprits to this issue:

1) loop within loops; the last time I tried having loops within an existing loop, the spell I was trying to make failed, so I've guessing a similar thing may be happening here.
2) 2D array: I used 2D array to identify what unit is being healed by what healer. Idk if I did it right though.

Any help anyone can give would be welcome.
 

Attachments

  • RecBeam.jpg
    RecBeam.jpg
    244.9 KB · Views: 202
Last edited:
Level 11
Joined
Dec 19, 2012
Messages
411
I can't found where you assign your group : udg_RectBeam_Group
And also this boolean : udg_RecBeam_RecBeamOff[id]

I believe they are assigned through the onCast function, posting the onCast trigger would be more helpful to debug your spell.
 
Can you please clarify:
1 is caster able to move while spell is activated or is it channeling spell
2 those 3 target units are constant when catched at start or they can change (if out of range or there were 2 at start but few sec later 3rd moves closer to caster and is catched)

1. It's toggleable like Immolation, so caster can move and do whatever without interrupting the spells. Deactivating or reaching 0 mana will end the spell.
2. The spell uses 2D arrays and loops through as many times as there are units to be caught - if a variable is null, enumerate all units in range and pick a viable target. If the unit variable is not null, then check of health or range. If both are acceptable, aka within 450 raneg, not dead, and not at full health, heal the unit. Otherwise, null the variable.


I find this concept motivating. I might give it a shot (at a later date).

Emphasis on might.

Neat :3


I can't found where you assign your group : udg_RectBeam_Group
And also this boolean : udg_RecBeam_RecBeamOff[id]

I believe they are assigned through the onCast function, posting the onCast trigger would be more helpful to debug your spell.

I've updated the OP with the OnCast trigger.
 
Level 11
Joined
Dec 19, 2012
Messages
411
Ok, i will try to debug your script, so far, i noticed few problems :


1.
JASS:
        loop // One MC can heal multiple units at the same time. This is what this loop is for.
            set LoopCount = LoopCount + 1
            exitwhen LoopCount >= udg_RecBeam_MaxTargets[id]
            
            //set UnitID = id * udg_RecBeam_MaxTargets[id] + LoopCount
            set UnitID = id * 4 + LoopCount
            
            set x2 = GetUnitX(udg_RecBeam_CurrentTarget[UnitID])
            set y2 = GetUnitY(udg_RecBeam_CurrentTarget[UnitID])
            set z2 = GetUnitFlyHeight(udg_RecBeam_CurrentTarget[UnitID]) + 60
            
            if udg_RecBeam_CurrentTarget[UnitID] == null then
From here, udg_RecBeam_CurrentTarget you are not even assign to a unit reference to it and directly getting any values from "null" pointer?

2.GetUnitState(u, UNIT_STATE_LIFE) > 0.00
If you are trying to filter out dead unit, the value should be > 0.405, or another option for checking, native UnitAlive takes unit u returns boolean

3. UnitLife <= 0.00 same as 2.




(Optional suggestions for improvement of your spell) :

1. I would suggest you to use unit array for storing triggering unit instead of unit group.
JASS:
/*Explaination:
I see you are using unit group for pick all triggering unit, removing and
re-adding the unit constantly. I believe using unit array variable
would makes the code much more shorten, and cleaner, as well as more efficient.*/

2. This condition block can be removed : if FirstOfGroup(udg_RecBeam_EnumGroup) != null then
JASS:
/*Explanation:
Since you are going to loop through udg_RecBeam_EnumGroup,
the loop will exit immediately if the group contains no unit. (Less code generated)*/

3.
JASS:
call SetUnitPosition(udg_RecBeam_Caster[UnitID], x1, y1)
...
call SetUnitPosition(udg_RecBeam_Mover[UnitID], x2, y2)

//can be changed to 

call SetUnitX(udg_RecBeam_Caster[UnitID], x1)
call SetUnitY(udg_RecBeam_Caster[UnitID], y1)
...
call SetUnitX(udg_RecBeam_Mover[UnitID], x2)
call SetUnitY(udg_RecBeam_Mover[UnitID], y2)

/*SetUnitX and SetUnitY perform faster then SetUnitPosition as they don't require path
checking, unless you want to include path checking for it.*/





And, do your GetUnitUserData returns correct value? Where do you assign the values for each unit?
 
Ok, i will try to debug your script, so far, i noticed few problems :


1.
JASS:
        loop // One MC can heal multiple units at the same time. This is what this loop is for.
            set LoopCount = LoopCount + 1
            exitwhen LoopCount >= udg_RecBeam_MaxTargets[id]
            
            //set UnitID = id * udg_RecBeam_MaxTargets[id] + LoopCount
            set UnitID = id * 4 + LoopCount
            
            set x2 = GetUnitX(udg_RecBeam_CurrentTarget[UnitID])
            set y2 = GetUnitY(udg_RecBeam_CurrentTarget[UnitID])
            set z2 = GetUnitFlyHeight(udg_RecBeam_CurrentTarget[UnitID]) + 60
            
            if udg_RecBeam_CurrentTarget[UnitID] == null then
From here, udg_RecBeam_CurrentTarget you are not even assign to a unit reference to it and directly getting any values from "null" pointer?

2.GetUnitState(u, UNIT_STATE_LIFE) > 0.00
If you are trying to filter out dead unit, the value should be > 0.405, or another option for checking, native UnitAlive takes unit u returns boolean

3. UnitLife <= 0.00 same as 2.




(Optional suggestions for improvement of your spell) :

1. I would suggest you to use unit array for storing triggering unit instead of unit group.
JASS:
/*Explaination:
I see you are using unit group for pick all triggering unit, removing and
re-adding the unit constantly. I believe using unit array variable
would makes the code much more shorten, and cleaner, as well as more efficient.*/

2. This condition block can be removed : if FirstOfGroup(udg_RecBeam_EnumGroup) != null then
JASS:
/*Explanation:
Since you are going to loop through udg_RecBeam_EnumGroup,
the loop will exit immediately if the group contains no unit. (Less code generated)*/

3.
JASS:
call SetUnitPosition(udg_RecBeam_Caster[UnitID], x1, y1)
...
call SetUnitPosition(udg_RecBeam_Mover[UnitID], x2, y2)

//can be changed to 

call SetUnitX(udg_RecBeam_Caster[UnitID], x1)
call SetUnitY(udg_RecBeam_Caster[UnitID], y1)
...
call SetUnitX(udg_RecBeam_Mover[UnitID], x2)
call SetUnitY(udg_RecBeam_Mover[UnitID], y2)

/*SetUnitX and SetUnitY perform faster then SetUnitPosition as they don't require path
checking, unless you want to include path checking for it.*/





And, do your GetUnitUserData returns correct value? Where do you assign the values for each unit?

1. Well I check the X/Y coordinates even if udg_RecBeam_CurrentTarget is null because those coordinates are used in either the if or the else. If it's null, it gets re-assigned once udg_RecBeam_CurrentTarget has a value. Would it be better if I put those lines in the else directly? (EDIT: looked at my code again and I'm not sure why I did that anymore. I'm still using the null value to create the Mover at them... so maybe I should move those lines after the value's been assigned to the unit variable after all)

2. I was unaware UnitAlive was a native :p (EDIT: JNGP says that's not a native)

3. same as above

(Optimisation)
1. Wouldn't I need some sort of of recycling system if I used arrays? I don't think I know how to do that.

2. Point. Will change.

3 I've heard SetUnitPosition with paused units is even faster than SetUnitX/Y. Dunno if that's true. I tend to avoid SetUnitX/Y if I can because stuff that go out of bounds will crash the game, and I have no idea how to use World Bounds or BoundSentinel.

PS: I'm using Bribe's Unit Indexer for indexing. GetUnitUserData should indeed return correct value.
 
Level 11
Joined
Dec 19, 2012
Messages
411
1. Well I check the X/Y coordinates even if udg_RecBeam_CurrentTarget is null because those coordinates are used in either the if or the else. If it's null, it gets re-assigned once udg_RecBeam_CurrentTarget has a value. Would it be better if I put those lines in the else directly? (EDIT: looked at my code again and I'm not sure why I did that anymore. I'm still using the null value to create the Mover at them... so maybe I should move those lines after the value's been assigned to the unit variable after all)
You should do that, always try to maximize you trigger efficiency, as well as skipping any unnecessary functions.

2. I was unaware UnitAlive was a native :p (EDIT: JNGP says that's not a native)

3. same as above
It is a native function, just hidden, you need to declare it in your script to use it.

1. Wouldn't I need some sort of of recycling system if I used arrays? I don't think I know how to do that.
It mostly look like this :
JASS:
set index = index + 1
set unit[index] = GetTriggerUnit()
...
  if index == 1 then
    call EnableTrigger(yourPeriodicTrigger)
  endif
JASS:
local integer i = 0
loop
  exitwhen i > index
    if true then //if your spell done
      if i != index then //you are not going to set same things.
        set unit[i] = unit[index]
        ...
        set i = i - 1 //since you are setting the last to the current index
                        //you will need to decrease by 1 in order not to miss this loop
      endif
      set unit[index] = null
      set index = index - 1 //reduce spell instance by one

      if index == 0 then //if no more spell instance
        call DisableTrigger(GetTriggeringTrigger())
      endif
    endif
  set i = i + 1
endloop

3 I've heard SetUnitPosition with paused units is even faster than SetUnitX/Y. Dunno if that's true. I tend to avoid SetUnitX/Y if I can because stuff that go out of bounds will crash the game, and I have no idea how to use World Bounds or BoundSentinel.
I've heard like SetUnitPosition will performs faster if unit is paused, but still i believe SetUnitX/Y still faster than it. If your unit (targeted unit) can't move outside of the map, then the dummy units would be also inside the playable map area (as you set their position at triggering unit and targeted unit respectively)



EDIT : Well i didn't notice your unitID formula, but still if 4 units matching all conditions, your targeted unit may be changed
 
You should do that, always try to maximize you trigger efficiency, as well as skipping any unnecessary functions.


It is a native function, just hidden, you need to declare it in your script to use it.
How do I do that?

It mostly look like this :
JASS:
set index = index + 1
set unit[index] = GetTriggerUnit()
...
  if index == 1 then
    call EnableTrigger(yourPeriodicTrigger)
  endif
JASS:
local integer i = 0
loop
  exitwhen i > index
    if true then //if your spell done
      if i != index then //you are not going to set same things.
        set unit[i] = unit[index]
        ...
        set i = i - 1 //since you are setting the last to the current index
                        //you will need to decrease by 1 in order not to miss this loop
      endif
      set unit[index] = null
      set index = index - 1 //reduce spell instance by one

      if index == 0 then //if no more spell instance
        call DisableTrigger(GetTriggeringTrigger())
      endif
    endif
  set i = i + 1
endloop
Ah, I see. I'll see if I can implement it.

EDIT : Well i didn't notice your unitID formula, but still if 4 units matching all conditions, your targeted unit may be changed
I'm using 2D arrays for that. The spell is supposed to only target 3 units, but I used 4 since I think the index starts on 1 instead of 0. Something like that. I'm a bit confused by that myself tbh.
 
Level 11
Joined
Dec 19, 2012
Messages
411
How do I do that?
In your map header script, copy and paste this : native UnitAlive takes unit u returns boolean
Now you can freely use it anywhere in your trigger. Example :
JASS:
local unit u = GetTriggerUnit()
if UnitAlive(u) then
    call BJDebugMsg("unit " + GetUnitName(u) + " is still alive")
endif
set u = null

I'm using 2D arrays for that. The spell is supposed to only target 3 units, but I used 4 since I think the index starts on 1 instead of 0. Something like that. I'm a bit confused by that myself tbh.
Reply : then you could change it to 3 for avoid confusion :D
My original meaning : well i actually understand when i read though your trigger. What i mean is, 4th unit (if around caster there present 4th unit with all matching conditions), 1st/2nd/3rd unit targeted may changed like 4th/2nd/3rd or 1st/4th/3rd or 1st/2nd/4th etc... (hopefully i did really read and understand the trigger right)
This I tested, problem not exists.




Does your trigger still working? If not, i actually hard to spot anymore mistake (for spell efficiency, still can be improved). A test map would be the best to debugging your trigger.
 
Last edited:
Level 11
Joined
Dec 19, 2012
Messages
411
Ok so i managed to found out the problem (I wonder why i didn't notice this when i debugging your trigger)


The only problem :LoopCount is not reset to 0 when 2nd unit done (this is how group works as the 2nd unit added to group will be picked as first unit). So the LoopCount for 1st unit will be 4, resulting loop exit immediately. Simple reset LoopCount to 0 and your spell would be working properly :
JASS:
        set x1 = GetUnitX(MC)
        set y1 = GetUnitY(MC)
        set z1 = GetUnitFlyHeight(MC) + 30
        set LoopCount = 0 //This line
        
        loop // One MC can heal multiple units at the same time. This is what this loop is for.
            set LoopCount = LoopCount + 1
            exitwhen LoopCount >= udg_RecBeam_MaxTargets[id]
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
I more or less created this and then noticed someone else solved it in the end, oh well I tried. It's not finished, I just created the core mechanic which is the lightnings. The minor stuff such as doing the healing is just adding one line.

This was the code I used:
JASS:
//! zinc
	library constructionLib
	{
		hashtable hash = InitHashtable();
		group g = CreateGroup();
		
		public struct construction
		{
			integer allowed = 3;
			lightning l [3];
			unit targets[3];
			unit u;
			integer current = 0;
			static unit caster;
			
			static method detection()
			{
				unit u = GetEnumUnit();
				integer id = LoadInteger(hash, GetHandleId(caster), 0);
				boolean taken = LoadBoolean(hash, GetHandleId(u), 1);
				location Main;
				location temp;
				
				if(construction(id).current < construction(id).allowed && taken == false && u != caster)
				{
					Main = GetUnitLoc(construction(id).u);
					temp = GetUnitLoc(u);
					construction(id).current += 1;
					construction(id).targets[construction(id).current] = u;
					construction(id).l[construction(id).current] = AddLightningLoc("MFPB", Main, temp);
					SaveBoolean(hash, GetHandleId(u), 1, true);
				}
			}
			
			method update()
			{
				location loc = GetUnitLoc(this.u);
				location temp;
				integer i = 0;
				caster = this.u;
				ForGroup(GetUnitsInRangeOfLocAll(300, loc), function construction.detection);
				while(i <= this.current)
				{
					temp = GetUnitLoc(targets[i]);
					MoveLightningLoc(l[i], loc, temp);
					RemoveLocation(temp);
					i += 1;
				}
				RemoveLocation(loc);
				loc = null;
				temp = null;
			}
			
			static method create(unit u) -> thistype
			{
				thistype this = thistype.allocate();
				SaveInteger(hash, GetHandleId(u), 0, this);
				this.u = u;
				GroupAddUnit(g, u);
				return this;
			}
		}
		
		function groupActions()
		{
			unit u = GetEnumUnit();
			integer h = GetHandleId(u);
			integer id = LoadInteger(hash, h, 0);
			construction(id).update();
		}
		
		function update()
		{
			ForGroup(g, function groupActions);
		}
		
		function onInit()
		{
			TimerStart(CreateTimer(), 0.03, true, function update);
		}
	}
//! endzinc
 
Status
Not open for further replies.
Top