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

Small Code Snippets

Level 29
Joined
Jul 29, 2007
Messages
5,174
Just for the heck of it.

JASS:
function getGroupUnitsNum takes group g returns integer
    local unit u
    local integer i = 0
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        call GroupRemoveUnit(g, u)
        set i = i + 1
    endloop
    return i
endfunction

Better then the crappy real function I think.
 
Level 9
Joined
Mar 25, 2005
Messages
252
Take the wantDestroy feature out of CountUnitsInGroup and you have the best 'count units in group' function you can get:
JASS:
function GroupCountUnits takes group g returns integer
    set bj_groupCountUnits = 0
    call ForGroup(g, function CountUnitsInGroupEnum)
    return bj_groupCountUnits
endfunction

What makes you think your function is better than CountUnitsInGroup? What you're doing clears the group and is slower (except for small groups perhaps).
 
Level 9
Joined
Mar 25, 2005
Messages
252
ForGroup doesn't clear the group nor do I see any reason it should.

Also when you count the number of units in a group the order in which the units are counted doesn't matter at all, and the same goes for literally every single thing I have ever needed to do with groups, and finally I wouldn't be so sure that ForGroup doesn't use the same order.

Do you have an example of a situation where the order of looping actually matters? I couldn't come up with any...

But anyways the counting function you posted is just a slow version of CountUnitsInGroup that also clears the group.
 
Level 6
Joined
Aug 15, 2007
Messages
209
An easy to use floating text function. It is good for autocast spells, or to show how much damage someone takes.

JASS:
function Text takes string s, string color, real x, real y returns nothing   
local texttag t = CreateTextTag()    
call SetTextTagText(t, s, .023)    
call SetTextTagPos(t, x,y, 100)    
call SetTextTagVelocity(t, 0, .0277)        
if color == "red" then            
call SetTextTagColor(t, 255, 0, 0, 255)        
elseif color == "orange" then            
call SetTextTagColor(t, 255, 138, 8, 255)        
elseif color == "yellow" then            
call SetTextTagColor(t, 255, 255, 0, 255)        
elseif color == "green" then            
call SetTextTagColor(t, 24, 190, 0, 255)       
 elseif color == "blue" then            
call SetTextTagColor(t, 0, 0, 255, 255)        
elseif color == "purple" then            
call SetTextTagColor(t, 82, 0, 132, 255)        
elseif color == "black" then            
call SetTextTagColor(t, 0,0,0, 255)        
endif    call SetTextTagLifespan( t, 3.00 )    
call SetTextTagFadepoint( t, 2.00 )    
call SetTextTagPermanent( t, false )   
 set t = null
endfunction
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Uhm Jetherit, I think there has been an error in pasting, look at your endif line.

Interesting, Herman, I was never into those things anyways, can you show us how to do it? (I hope this didn't sound sarcastic, because it's not)
 
Level 12
Joined
Aug 20, 2007
Messages
866
Ok sure

Well, the call SetTextTagColor() function really should be considered a BJ function, because this is what it does....

JASS:
function SetTextTagColor takes texttag t, integer red , integer blue, integer green, integer alpha returns nothing
    local string colorcode = "|" + I2S(C2H(alpha)) + I2S(C2H(red)) + I2S(C2H(blue)) + I2S(C2H(green))
    local string originaltext = SomeHowGetsTheTextTagText(t)
    set colorcode = colorcode + originaltext + "|r"
    call SetTextTagText(t, colorcode, DoesNotAffectTheFont(t))
endfunction

*I'm using a second function because I don't feel like writing out the math of it, they probably do not use a second function for it, because it would be unnecessary

***C2H represents - ConvertToHexidecimal

The only part I don't understand is it somehow gets the textags current text, and it doesn't affect the texttag's font

The way I would do the TextTag, is use an outside program, probably made in VB to quickly convert + display those 4 integers, or maybe not even display, just convert, and then do my function like this...

JASS:
function Floatie takes string s, string colorcode, real x, real y returns nothing
    local texttag t = CreateTextTag()

    call SetTextTagText(t, colorcode + s + "|r", .023)
    call SetTextTagPos(t, x,y, 100)
    call SetTextTagVelocity(t, 0, .0277)
    call SetTextTagLifespan( t, 3.00 )
    call SetTextTagFadepoint( t, 2.00 )
    call SetTextTagPermanent( t, false )

    set t = null
endfunction

Again, using an outside program to do your hex conversions for the colors very quickly would be the best option
 
Level 12
Joined
Aug 20, 2007
Messages
866
Is all good, I tend to need to research every little detail of anything technical I may need to use, when it comes to just talking I pretty much just let whatever thought that pops into my mid fly out
 
Level 9
Joined
Mar 25, 2005
Messages
252
JASS:
library QuickTimer
    //============================================================================
    // Attaches and integer to a timer and makes it expire after about 0 seconds.
    //
    function TimerExpireQuick takes timer t, integer data, code handlerFunc returns nothing
        call TimerStart(t, data/2147483648., false, handlerFunc)
    endfunction

    //============================================================================
    // Returns the integer attached to a timer.
    //
    function QuickTimerGetData takes timer t returns integer
        return R2I(TimerGetTimeout(t)*2147483648.)
    endfunction
endlibrary

Both of these functions are inline friendly (afaik) which means that the latest version of jasshelper inlines them. The only thing in this that requires vJass is the library so by removing it you can make a no-vJass version of it.

JASS:
library IssuePostStopOrder requires QuickTimer
    private struct Data
        unit u
    endstruct
    private function PostActions takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local Data d = Data(QuickTimerGetData(t))
        call IssueImmediateOrderById(d.u, 851972)
        call d.destroy()
        call DestroyTimer(t)
        set t = null
    endfunction
    function IssuePostStopOrder takes unit u returns nothing
        local Data d = Data.create()
        set d.u = u
        call TimerExpireQuick(CreateTimer(), integer(d), function PostActions)
    endfunction
endlibrary
 
Last edited:
Level 12
Joined
Aug 20, 2007
Messages
866
JASS:
library QuickTimer
    //============================================================================
    // Attaches and integer to a timer and makes it expire after about 0 seconds.
    //
    function TimerExpireQuick takes timer t, integer data, code handlerFunc returns nothing
        call TimerStart(t, data/2147483648., false, handlerFunc)
    endfunction

    //============================================================================
    // Returns the integer attached to a timer.
    //
    function QuickTimerGetData takes timer t returns integer
        return R2I(TimerGetTimeout(t)*2147483648.)
    endfunction
endlibrary

Both of these functions are inline friendly (afaik) which means that the latest version of jasshelper inlines them. The only thing in this that requires vJass is the library so by removing it you can make a no-vJass version of it.

JASS:
library IssuePostTriggerStopOrder requires QuickTimer
    private struct Data
        unit u
    endstruct
    private function PostTriggerActions takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local Data d = Data(QuickTimerGetData(t))
        call IssueImmediateOrderById(d.u, 851972)
        call d.destroy()
        call DestroyTimer(t)
        set t = null
    endfunction
    function IssuePostTriggerStopOrder takes unit u returns nothing
        local Data d = Data.create()
        set d.u = u
        call TimerExpireQuick(CreateTimer(), integer(d), function PostTriggerActions)
    endfunction
endlibrary

Is it necessary to have vJASS for that?, that seems like a simple concept that really wouldn't require vJASS at all

I'm actually extremely glad you posted that, because I never thought of it, and it is so simple ><
 
Level 9
Joined
Mar 25, 2005
Messages
252
Is it necessary to have vJASS for that?, that seems like a simple concept that really wouldn't require vJASS at all

Only vJass features in it are the library QuickTimer and endlibrary lines, so it doesn't really need vJass, but it is something that vJass using people would place in a library anyway so I wanted to be the one who names that library. To make a vJassless version out of it just remove those library lines from it.
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Nah, it doesn't require vJass, just remove the first and the last line (library and endlibrary), put that code in your map header and you're good to go :)

Though I really must say that I don't see why is that function useful. It's same like I do this:

JASS:
function Func2 takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit u = GetHandleUnit(t, "u")
    call RemoveUnit(u)
    call SetHandleHandle(t, "u", null)
    call DestroyTimer(t)
    set t = null
    set u = null
endfunction

function Func1 takes nothing returns nothing
    local timer t = CreateTimer()
    local unit u = GetSpellTargetUnit()
    call SetHandleHandle(t, "u", u)
    call TimerStart(t, 0, false, function Func2)
    set t = null
    set u = null
endfunction

Instead of just doing this:

JASS:
function Func takes nothing returns nothing
    call RemoveUnit(GetSpellTargetUnit())
endfunction


I don't have anything against your function, Disciple, but I would be grateful if you gave one good example of it's usage.
 
Level 12
Joined
Aug 20, 2007
Messages
866
Oh, yeah it is used for code execution, and you can totally avoid using the gamecache, from my experience is very slow

~Probably used in conjunction with a global/data system
 
Level 9
Joined
Mar 25, 2005
Messages
252
Though I really must say that I don't see why is that function useful. It's same like I do this:

--

I don't have anything against your function, Disciple, but I would be grateful if you gave one good example of it's usage.

If you have a trigger that fires when a unit is issued an order, you can't issue orders to the unit directly in that trigger's actions (or conditions). It just won't do anything. Using TriggerExecute/Evaluate or ExecuteFunc won't help. Giving the order right after the event works instead.

Also sometimes you might want to run some code after the everything that is going to be run at the moment.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
If you have a trigger that fires when a unit is issued an order, you can't issue orders to the unit directly in that trigger's actions (or conditions).
sorry but wtf ?
I know only one problem.
Trying to give an immediate order to an unit when a location/widget order fire on it.

and i solve this problem with that :

JASS:
call PauseUnit(GetTriggerUnit(),true) // generate an location order (0,0),  851973
call IssueImmediateOrderById ( GetTriggerUnit() , 851973) // or order stop if you want this order
call PauseUnit(GetTriggerUnit(),false)
// your order if it's different to stop
// or nothing if you want the unit to keep his last immediate order

851973 is the order when the unit is stunned (widget order, and the target is the widget who stun the unit) or pause (location order, 0,0)
 
Level 1
Joined
May 28, 2008
Messages
8
trigger help

So, at the risk of sounding like a big-time n00b, which I kinda am, I am having a nightmare getting the trigger editor on WorldEdit to perform what it seems should be a simple task: checking what kind of unit the triggering unit is. The best I can come up with is generic types, like buildings, town halls, workers, etc. - but I need to have it work on a specific breed of unit only, because I want it to replace unit X with unit Y.

Basically what I'm trying to do is make my eggs in my StarCraft mod hatch when they finish building, but I can't figure out how.

I considered trying Jass to achieve my ends until, much to my dismay, it looked an awful lot like programming. Which I lack the capacity to do.

So if anyone knows a good way to achieve what I'm trying to do with the trigger editor, or they have some pre-fabricated code that will help me achieve my goal, I would be very grateful.
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
If you have a trigger that fires when a unit is issued an order, you can't issue orders to the unit directly in that trigger's actions (or conditions). It just won't do anything. Using TriggerExecute/Evaluate or ExecuteFunc won't help. Giving the order right after the event works instead.

Lol, look at the bottom of the first post :).

So, at the risk of sounding like a big-time n00b, which I kinda am, I am having a nightmare getting the trigger editor on WorldEdit to perform what it seems should be a simple task: checking what kind of unit the triggering unit is. The best I can come up with is generic types, like buildings, town halls, workers, etc. - but I need to have it work on a specific breed of unit only, because I want it to replace unit X with unit Y.

Basically what I'm trying to do is make my eggs in my StarCraft mod hatch when they finish building, but I can't figure out how.

I considered trying Jass to achieve my ends until, much to my dismay, it looked an awful lot like programming. Which I lack the capacity to do.

So if anyone knows a good way to achieve what I'm trying to do with the trigger editor, or they have some pre-fabricated code that will help me achieve my goal, I would be very grateful.

Very poetic, I must say.

I think what you're looking for is the unit-type comparison, look at the conditions and you'll find it (you were obviously trying to find it in the boolean comparison).
 
Level 1
Joined
May 28, 2008
Messages
8
I think what you're looking for is the unit-type comparison, look at the conditions and you'll find it (you were obviously trying to find it in the boolean comparison).

Yeh, I thought I'd checked that already and hit a dead end last time, but turns out that one did the trick. I guess I'm just a dork. Thanks! :thumbs_up:
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Troll-Brain, there are other situations in which it applies.

For example, as discovered by Firzen_Zero, when you order a research to start researching when another just finishes (I assume this is the same with training units, too) if you don't have the timer there it will put the research at the start of the queue, and any building upgrades will be permanently disabled afterwards.
 
SafeFilter:
JASS:
function SafeFilter takes nothing returns boolean
     return true
endfunction

What this function does, is provides a substitute for using null as a boolexpr argument. Using null creates a leak, and sucks when grouping. You would use it like:
JASS:
    call GroupEnumUnitsInRange(g,x,y,radius,Condition(function SafeFilter))

Something like that.

It is also good to inline TriggerRegisterAnyUnitEventBJ(...) as it leaks too.

Though these are minimalish, they can build up for stuff like groups in periodic events etc...

:]

[If anyone can point out any mistakes in this post, feel free to do so!]
 
Level 12
Joined
Aug 20, 2007
Messages
866
There is something I have come across that leaks with events, but the Condition() function creates a boolexpr handle, whch would need to be destroyed when you are through with the function

By my understanding, using Condition(function SafeFilter) would create a handle that will leak if you do not set it to a variable to be removed/deleted

I may be totally wrong
 
There is something I have come across that leaks with events, but the Condition() function creates a boolexpr handle, whch would need to be destroyed when you are through with the function

By my understanding, using Condition(function SafeFilter) would create a handle that will leak if you do not set it to a variable to be removed/deleted

I may be totally wrong

No, Vexorian said that it is ok to use Condition() as conditions are reused, not created each time. And he said somewhere that it might be hazardous to destroy it.
http://wc3campaigns.net/showthread.php?t=93513

Read that thread.

Jazradel later clarified one-time usage isn't too hazardous to destroy conditions I think.
EDIT: Can't find the thread for this, it was so long ago over at theHelper. :(

Because it wasn't my or his thread, he just posted in it so I couldn't find it.

And using null as an argument does leak. Grim001 told me that I think. Lol, I will search for the threads.
http://wc3campaigns.net/showthread.php?t=100575

Condition(function BLEH) doesn't leak, but triggerconditions do. Hey, TriggerRegisterAnyUnitEventBJ() leaks also, but that is kind of minimal since you won't use it much unless you create a trigger that uses that event for some spell or something. :p
 
Level 12
Joined
Aug 20, 2007
Messages
866
Hm, I read those threads

Really didn't explain much

Memory leaks are memory that is no longer used, but has not been removed from memory

When you make a trigger handle, register events, and add condition/actions, its all memory

I do not know why null leaks, but I have tested for myself a trigger destroy system for a damage detection system, and null leaks like a dirty mother

I used another experiment to test using a SafeFilter(), and found I could remove eliminate the event leaks :)

But my problem is this, if your going to create a boolexpr handle, and never use it again, the handle must be eliminated (when using GroupEnum() you never use the handle again)

In triggerconditions it is considered not a memory leak, because if you were to destroy the condition attached to your trigger, your trigger wouldn't function properly :O, so you leave it, taking up memory

I am totally unfamiliar with the boolexpr cache, which makes very little sense to me, so for now I will continue to remove any boolexpr I am not using

(like boolexprs for groupenum() functions)

I think the TriggerRegisterAnyUnitEventBJ() only leaks due to using null (I think)

I hope PurplePoot sees this thread and responds
 
Hm, I read those threads

Really didn't explain much

Memory leaks are memory that is no longer used, but has not been removed from memory

When you make a trigger handle, register events, and add condition/actions, its all memory

Obviously, but you are still using it. ;) You are still using the condition so you don't have to destroy it. It is like destroying a trigger.

But my problem is this, if your going to create a boolexpr handle, and never use it again, the handle must be eliminated (when using GroupEnum() you never use the handle again)

The thing is, boolexprs are reused rather than created every single time.

In triggerconditions it is considered not a memory leak, because if you were to destroy the condition attached to your trigger, your trigger wouldn't function properly :O, so you leave it, taking up memory

I think triggerconditions leak, but yeah... Everything you create practically leaks :bored:, it is kind of minimalistic.

I am totally unfamiliar with the boolexpr cache, which makes very little sense to me, so for now I will continue to remove any boolexpr I am not using

(like boolexprs for groupenum() functions)

Yeah, I am seriously wondering what these "problems" that might occur with destroying boolexprs. But it is kind of unnecessary. I just say go with the flow. :p

I think the TriggerRegisterAnyUnitEventBJ() only leaks due to using null (I think)

Yeah, it is the only leak, but since you won't use it periodically unless in some sort of spell, it shouldn't be too worrysome.

I hope PurplePoot sees this thread and responds

Yeah, I'm not really a notable JASSer. :( Other than me helping tons, of course. :p
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Think of boolexprs like strings, that comparison is often very helpful. You don't destroy neither of them (with an exception that you can't destroy strings, but you can destroy boolexprs) and they are both reused.

You destroy the triggercondition with TriggerRemoveCondition() when you locally create a trigger (you also destroy triggeractions).

JASS:
local trigger t = CreateTrigger()
local triggeraction ta = TriggerAddAction(function Actions)
local triggercondition tc = TriggerAddCondition(function Conditions)
// ...
// ...
call TriggerRemoveAction(t, ta)
call TriggerRemoveCondition(t, tc)
call DestroyTrigger(t)

set t = null
set ta = null
set tc = null

People think that triggeractions/triggerconditions are destroyed when you destroy the actual trigger, but in reality, they aren't destroyed and they leak.

The bug about boolexprs is because they are reused, destroying one boolexpr will destroy the other one if they are created from the same function.
 
Level 1
Joined
Jun 18, 2008
Messages
6
GetUnitSomewhere() (deluxe GetClosestUnit :p)

I'm not exactly sure how I submit a snippet but it wouldn't let me make a new thread so I'll just post here :)

This is my version of the "GetClosestUnit" functions. Yes, I know there are plenty out there, but mine is simple, fast, requires no Globals and has extra features.
This function provides a nice simple base for more advanced functions, and is still useful as is.

(I originally posted a more crude version of this a while ago on thehelper.net under the name wonderpriest...Link)


JASS:
//***************************
//----GetUnitSomewhere by Quraji----
//***************************
//
//  To use in your map simply paste this whole code into your custom script
//  section, or an empty trigger (above all functions that will use this code)
//
//
//  Contains two functions:
//
//  SubtractGroupFromGroup takes group source, group todestroy...
//  This function removes all units in a reference group (todestroy)from a
//  source group (source).
//  You must include it for GetUnitSomewhere(), but also feel free to use it for 
//  other functions
//
//
//
//  GetUnitSomewhere takes real sourceX, real sourceY, real range, boolean outsiderange, boolean nearest, boolean considerdead, boolexpr cond returns unit
//  Don't let the number of parameters scare you, this is easy to use. This
//  function allows you to select the nearest or farthest unit inside or outside
//  a designated circle.
//
//  Parameters:
//
//  real sourceX and real sourceY
//  these are the X and Y coordinates of the point at the center of the area
//  to be considered.
//
//  real range
//  this is the range of the function, or the radius of the area to be considered
//  (a circle).
//
//  boolean outsiderange
//  if false, the function will consider units inside the circle, if true it will
//  consider all units selected BUT the ones in the circle.
//  (remember that the circle's radius is decided by the range parameter)
//
//  boolean nearest
//  if true, the function will select the nearest unit to the center point inside
//  the area to be considered (as you'd expect a normal GetClosestUnit()
//  function to do. if false, however, it will select the farthest unit
//
//  boolean considerdead
//  if false the function will ignore dead units.
//  (leave this at false unless you need the function to select recently killed
//  units)
//
//  boolexpr cond
//  finally, this is where you add your own conditions if you need them by
//  using a boolexpr.  
//
//
//  Extra feature:
//
//  This function sets the bj_lastHauntedGoldMine game variable to the unit
//  it selects, as well as returning the unit. This enables JASS users to use
//  the function as normal, but provides a convenience for GUI users, as they
//  can simply select the unit from the drop down menu for any unit field by
//  selecting "Last Haunted Gold Mine". This also allows all variables to be
//  nulled.
//**********************

function SubtractGroupFromGroup takes group source, group todestroy returns group
 local unit current

   loop
    set current = FirstOfGroup(todestroy)
     exitwhen current==null

       call GroupRemoveUnit(source, current)
       call GroupRemoveUnit(todestroy, current)
   endloop
  
   set current = null
   return source    
endfunction   

                                                                                            
function GetUnitSomewhere takes real sourceX, real sourceY, real range, boolean outsiderange, boolean nearest, boolean considerdead, boolexpr cond returns unit
 local group g=CreateGroup()
 local group tempg=CreateGroup()
 local unit current 
 local unit winner
 local real currentX
 local real currentY
 local real dist
 
   call GroupEnumUnitsInRange(g,sourceX,sourceY,range,cond)
   
   if not nearest then
     set range=.0
   endif  
     
   if outsiderange then
   
     call GroupEnumUnitsInRect(tempg,bj_mapInitialPlayableArea,cond)
     set g = SubtractGroupFromGroup(tempg,g) 
      
   endif
     
   loop
                          
    set current=FirstOfGroup(g)
     exitwhen current==null   
      
       if GetWidgetLife(current)>0.405 or considerdead then
       
         set currentX=GetWidgetX(current)-sourceX                   
         set currentY=GetWidgetY(current)-sourceY                   
         set dist=SquareRoot(currentX*currentX+currentY*currentY)
       
         if outsiderange then
           set range=dist
           set outsiderange = not outsiderange
         endif  
           
         if (nearest and dist<=range) or (not nearest and dist>=range) then 
                    
           set winner=current
           set range=dist 
                    
         endif   
  
       endif
                
     call GroupRemoveUnit(g,current)
   endloop 
     
     call DestroyGroup(g) 
     call DestroyGroup(tempg)

     set tempg=null                   
     set g=null          
     set current=null
     
     set bj_lastHauntedGoldMine=winner   
     set winner=null 
       
   return bj_lastHauntedGoldMine        
endfunction

Hope you find it useful :)
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
requires no Globals
Ideally, you should only use globals for temp groups such as these, not locals.

--

For SubtractGroupFromGroup, you should instead use GroupRemoveGroup, or an edited version thereof which has the bj_wantDestroyGroup bit removed.

--

Rather than having boolean conditions, you should just allow a boolexpr.

--

Silvenon's function is generally better, however, I'm tempted to revise even it to quicken it.
 
Level 1
Joined
Jun 18, 2008
Messages
6
> Ideally, you should only use globals for temp groups such as these, not locals.

Why?

> For SubtractGroupFromGroup, you should instead use GroupRemoveGroup, or an edited version thereof which has the bj_wantDestroyGroup bit removed.

Ah, didn't know there was a "GroupRemoveGroup" function. Oh well, mine works fine.

>Rather than having boolean conditions, you should just allow a boolexpr.

There is a boolexpr allowed for extra conditions, however I found those 3 booleans to be very useful. "outsiderange" and "nearest" are simply part of the main function of the erm....function. And "considerdead" I added because many people use functions like this without realizing that they do return dead units.

>Silvenon's function is generally better, however, I'm tempted to revise even it to quicken it.

Can you point me to Silvenon's function please? I can't find it.
Also, I'm confused as to what you mean by "however, I'm tempted to revise even it to quicken it." :p
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Because then you don't have to declare a local, create the group, destroy the group, and null the local.

And since GroupEnums clear the group, you don't even need to clear.

There is a boolexpr allowed for extra conditions, however I found those 3 booleans to be very useful. "outsiderange" and "nearest" are simply part of the main function of the erm....function. And "considerdead" I added because many people use functions like this without realizing that they do return dead units.
The biggest problem with this method is the horribly long parameter list.

Can you point me to Silvenon's function please? I can't find it.
The GetClosestUnit function in the first post.

Also, I'm confused as to what you mean by "however, I'm tempted to revise even it to quicken it." :p
Fix up Silv's so it uses a global group, among other things. Or get him to, of course.
 
Top