Snippet Library: GetUnitSomewhere

quraji

zap
Reaction score
144
This is just a few functions to make it easier to pick units (for spells and whatnot).

What it can do:
Can pick the nearest or farthest unit inside a range, or outside of a range. Most likely getting the nearest unit in a range will be most useful, but the others may come in handy.

Features:
-You can cycle through an already made group instead of making a new one (set the GUS_Group global to your group.)
-It's quick
-Pretty easy to use

All functions at the bottom of the code are pretty self explanatory.

Globals:
Code:
GUS_Group
Set this to your own group to cycle through it.

minrange
Lowest possible range when getting the "farthest" unit (you shouldn't usually need to change this).

maxrange
The range within which to check for GetNearestUnit (you shouldn't usually need to change this).

error_prefix
If you're debugging, an error will be shown if no unit is assigned by any of the functions, this is to change the beginning of the debug message if you need to

This version requires vJass:

JASS:
//
    //_______________________________________________________
    //      GetUnitSomewhere functions by quraji
    //___________________________v2.1________________________
    //
    //  Some functions created to easily pick a unit within
    //  or outside a range (whether it be the farthest or
    //  closest unit).
    //
    //  Simple to use. Just call the proper function (see bottom
    //  of script for function list). It returns a unit as well 
    //  as setting the blizzard global bj_lastHauntedGoldMine.
    //
    //  _______________________________________________________
    //  GUI users:
    //  Simply create a custom script with the function call:
    //
    //  Custom script:   call GetNearestUnit(udg_x, udg_y, null)
    //
    //  Then, select Last Haunted Gold Mine from the unit drop-
    //  down list to use the unit:
    //
    //  Unit - Kill (Last Haunted Gold Mine)
    //  _______________________________________________________
    // 
    //  _______________________________________________________
    //  Globals:
    //
    //  group GUS_Group - If set, the functions will only return
    //                    in the group
    //  real GUS_minrange - The minimum distance from the source
    //                      the unit must be*
    //  real GUS_maxrange - The maximum distance from the source
    //                      a unit can be*
    //
    //  *probably won't need to be changed
    //  _______________________________________________________
    //
    //  No credits desired unless you use this library within your
    //  own system. Simply leave in the header:
    //  GetUnitSomewhere functions by quraji (v X.x)
    //  _______________________________________________________
    
    

library GetUnitSomewhere

    globals
        group GUS_Group = null
        real GUS_minrange = 0.
        real GUS_maxrange = 9999999.
        private string error_prefix = "GUS Error: "
    endglobals

    private function ReturnTrue takes nothing returns boolean
        return true
    endfunction

    
    //Main Functions
    //==============================================
    
    private function GetUnitInRange takes real sourceX, real sourceY, real range, boolean nearest, boolexpr cond returns unit
        local group g = GUS_Group
        local unit current = null
        local unit winner = null
        local real dist = 0.
        local real x = 0.
        local real y = 0.
        
        if cond == null then
            set cond = Condition(function ReturnTrue)
        endif
    
        if g == null then
            set g = CreateGroup()
            call GroupEnumUnitsInRange(g, sourceX, sourceY, range, cond)
        endif
    
        if nearest == false then
            set range = GUS_minrange
        endif
        
         
        loop
            set current = FirstOfGroup(g)
            exitwhen current == null
            
            if GetUnitState(current, UNIT_STATE_LIFE) > .405 then
            
                set x = GetUnitX(current)-sourceX
                set y = GetUnitY(current)-sourceY
                set dist = SquareRoot(x*x + y*y)
                
                if ((nearest and dist <= range) or (nearest == false and dist >= range)) and dist <= GUS_maxrange then
                
                    set winner = current
                    set range = dist
                
                endif
            
            endif
            
            call GroupRemoveUnit(g, current)
        
        endloop
            
  debug if winner == null then
      debug call BJDebugMsg("|cffff0000" + error_prefix +"|rNo unit assigned!")
  debug endif
        
        call DestroyGroup(g)
        set bj_lastHauntedGoldMine = winner
        
        set winner = null
        set g = null
        
        
        return bj_lastHauntedGoldMine
    endfunction
    
    private function GetUnitOutsideRange takes real sourceX, real sourceY, real range, boolean nearest, boolexpr cond returns unit
        local group g = GUS_Group
        local unit current = null
        local unit winner = null
        local real dist = 0.
        local real x = 0.
        local real y = 0.
        local real origrange = range
        local boolean b = true
                
        if cond == null then
            set cond = Condition(function ReturnTrue)
        endif
    
        if GUS_Group == null then
            set g = CreateGroup()
            call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, Condition(function ReturnTrue))
        endif
        
        if nearest == false then
            set range = GUS_minrange
        endif
            
        
        loop
        
            set current = FirstOfGroup(g)
            exitwhen current == null
            
            if GetUnitState(current, UNIT_STATE_LIFE) > .405 then

                set x = GetUnitX(current)-sourceX
                set y = GetUnitY(current)-sourceY
                set dist = SquareRoot(x*x + y*y)
                
                if dist >= origrange then
                
                    if b then
                        set range = dist
                        set b = false
                    endif
                    
                    if ((nearest and dist <= range) or (nearest == false and dist >= range)) and dist >= GUS_minrange and dist <= GUS_maxrange then
                        
                        set winner = current
                        set range = dist 
                  
                    endif
                
                endif
            
            endif
            
            call GroupRemoveUnit(g, current)
        
        endloop
        
  debug if winner == null then
      debug call BJDebugMsg("|cffff0000" + error_prefix +"|rNo unit assigned!")
  debug endif
        
        call DestroyGroup(g)
        set bj_lastHauntedGoldMine = winner
        
        set winner = null
        set g = null
        
        
        return bj_lastHauntedGoldMine
    
    endfunction
    
    
    //*****************************************
    //USER FUNCTIONS
    //*****************************************
    
    //Extremes
    //=========================================

    //get the nearest unit to the source
    function GetNearestUnit takes real x, real y, boolexpr cond returns unit
        return GetUnitInRange(x, y, GUS_maxrange, true, cond)
    endfunction
    
    //get the farthest unit from the source
    function GetFarthestUnit takes real x, real y, boolexpr cond returns unit
        return GetUnitOutsideRange(x, y, GUS_minrange, false, cond)
    endfunction
        
        
    //GetUnitInRange functions
    //=========================================
    
    //get nearest unit in a range
    function GetNearestUnitInRange takes real x, real y, real range, boolexpr cond returns unit
        return GetUnitInRange(x, y, range, true, cond)
    endfunction
        
    //get farthest unit in a range
    function GetFarthestUnitInRange takes real x, real y, real range, boolexpr cond returns unit
        return GetUnitInRange(x, y, range, false, cond)
    endfunction
    
    
    //GetUnitOutsideRange functions
    //=========================================
    
    //get nearest unit outside of a range
    function GetNearestUnitOutsideRange takes real x, real y, real range, boolexpr cond returns unit
        return GetUnitOutsideRange(x, y, range, true, cond)
    endfunction
    
    //get the farthest unit outside of a range
    function GetFarthestUnitOutsideRange takes real x, real y, real range, boolexpr cond returns unit
        return GetUnitOutsideRange(x, y, range, false, cond)
    endfunction
    
endlibrary


Here is an older version that does not require vJass (deprecated):
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)
//
// (feel free to omit this section from your code, I only ask credit if
// you copy this function for your own system/submitted code, no credits
// needed if you use it in a map)
//
// Contains one main function:
//
//
// 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. if you don't, pass "Condition(function ReturnTrue)"
//
// function GetUnitSomewhereEx takes real x, real y, real range returns unit
// A simplified version, returns a non-dead unit within range
//
// function GetUnitSomewhereExCond takes real x, real y, real range, boolexpr cond returns unit
// A simplified version, returns a non-dead unit within range, matching condition
//
// 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. If you wish this variable not to be tampered with, uncomment the
// "return winner" line of code at the bottom of the function.
//**********************

function ReturnTrue takes nothing returns boolean
  return true
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 unit current
 local unit winner
 local real currentX
 local real currentY
 local real dist
 local real rangeorig = range

   if outsiderange then
     call GroupEnumUnitsInRect(g,bj_mapInitialPlayableArea,cond)
   else
     call GroupEnumUnitsInRange(g,sourceX,sourceY,range,cond)
   endif

   if not nearest then
     set range=.0
   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 (outsiderange and (dist > rangeorig)) or outsiderange == false then

           if (nearest and dist<=range) or (not nearest and dist>=range) then

             set winner=current
             set range=dist

           endif

         endif

       endif

     call GroupRemoveUnit(g,current)
   endloop

     call DestroyGroup(g)

     set g=null
set current=null

     //return winner
     //uncomment above line if you wish bj_lastHauntedGoldMine to remain untampered with

     set bj_lastHauntedGoldMine=winner
     set winner=null

   return bj_lastHauntedGoldMine
endfunction

function GetUnitSomewhereEx takes real x, real y, real range returns unit
  return GetUnitSomewhere(x,y,range,false,true,false, Condition(function ReturnTrue))
endfunction

function GetUnitSomewhereExCond takes real x, real y, real range, boolexpr cond returns unit
  return GetUnitSomewhere(x,y,range,false,true,false,cond)
endfunction


Any questions/comments/suggestions are welcome :thup:


Demo map uses the vJass version.
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
Very nice, gj :thup:

Just one thing. Shouldn't GetUnitInRange and GetUnitOutsideRange be private?
 

quraji

zap
Reaction score
144
I guess they could be, but it's not really necessary I don't think :p

Meh, might as well since the bottom functions cover them anyways.

And thanks <3
 

Romek

Super Moderator
Reaction score
963
Those Globals could all be Private too.

Otherwise, these are very useful functions. Simple too :)
 

quraji

zap
Reaction score
144
Those Globals could all be Private too.

Otherwise, these are very useful functions. Simple too :)

No, the other three are supposed to be public. If for any reason you want to set minrange or maxrange yourself, it's possible. I suppose the GUS prefix should be used but meh. Also the group isn't for the code itself, it's for you to set it so that you can make the function only use units from that group, instead of grouping units by range and the boolexpr.

Thanks for the comments.
 
Reaction score
86
Nice snippet :thup: Now I don't have to keep remaking it whenever I need to find nearest unit :D
^^ Good call o_O

SideNote: Wasn't the new Batman movie amazing o_O
^^ Indeed... It is an understatement...

<<Reply, Didn't want to waste a post o_O
 

quraji

zap
Reaction score
144
>>Nice System :thup:

It's a snippet :p


>>Now I don't have to keep remaking it whenever I need to find nearest unit :D

Glad someone is going to use it :D


>>SideNote: Wasn't the new Batman movie amazing o_O

That's an understatement.
 

quraji

zap
Reaction score
144
Updated to new version, just did a few minor changes and included the documentation above the library :thup:
 

Sooda

Diversity enchants
Reaction score
318
You don't need to set max range 99999..., better would set it to 0., in function set first units distance as max distance, pick next unit and check does its distance is smaller or not, if it is set new max distance and unit who was chosen.

Your jass version function names doesn't have prefixes which may lead to function name collisions.
 

quraji

zap
Reaction score
144
>>You don't need to set max range 99999..., better would set it to 0., in function set first units distance as max distance, pick next unit and check does its distance is smaller or not, if it is set new max distance and unit who was chosen.

It does do that (look at range). maxrange is just a way of globally limiting the maximum distance between source and unit. Defaulting it to a high bound like 99999 makes sure that never comes in to play unless the user wants it to (by re-setting it).


>>Your jass version function names doesn't have prefixes which may lead to function name collisions.

Well, good. It's a deprecated version and everyone should use vJass anyways :p
 

Prometheus

Everything is mutable; nothing is sacred
Reaction score
589
I think your function names could use a bit of modification and such.
Plus add a location function.
JASS:
function GetNearestUnitOutsideRange takes real x, real y, real range, boolexpr cond returns unit

JASS:
function GetNearestUnitOutsideRangeLoc takes location l, real range, boolexpr cond returns unit
 

quraji

zap
Reaction score
144
>>I think your function names could use a bit of modification and such.

Such as...?


>>Plus add a location function.

I don't feel like doubling the amount of functions this has. It's easy enough to use GetLocationX, GetLocationY yourself.


Thanks for your comment.
 

Prometheus

Everything is mutable; nothing is sacred
Reaction score
589
Forget the name changes but why are you using "Last Haunted Gold Mine"?
 

Flare

Stops copies me!
Reaction score
662
Forget the name changes but why are you using "Last Haunted Gold Mine"?

For GUI users, so they can access it in the GUI actions

JASS:
    //  GUI users:
    //  Simply create a custom script with the function call:
    //
    //  Custom script:   call GetNearestUnit(udg_x, udg_y, null)
    //
    //  Then, select Last Haunted Gold Mine from the unit drop-
    //  down list to use the unit:
    //
    //  Unit - Kill (Last Haunted Gold Mine)
 

quraji

zap
Reaction score
144
<3 Flare

Forget the name changes but why are you using "Last Haunted Gold Mine"?

In case you still don't read the documentation, even after it's quoted :p:

I use it to reduce the amount of custom script a GUI user has to use. I picked bj_lastHauntedGoldMine because I thought it'd have the least chance to cause any sort of conflict ever...because, who ever uses that variable (plus, it's at the top of the list, so you don't have to scroll...bonus!).
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top