1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. Hey guys, we've posted the Results for the 30th Modeling Contest. Check them out!
    Dismiss Notice
  4. The 15th Mini-Mapping Contest came to an end. The Secrets of Warcraft 3 are soon to be revealed! Come and vote in the public poll for your favorite maps.
    Dismiss Notice
  5. The 12th incarnation of the Music Contest is LIVE! The theme is Synthwave. Knight Rider needs a song to listen to on his journey. You should definitely have some fun with this theme!
    Dismiss Notice
  6. Join other hivers in a friendly concept-art contest. The contestants have to create a genie coming out of its container. We wish you the best of luck!
    Dismiss Notice
  7. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Wander

Submitted by BPower
This bundle is marked as approved. It works and satisfies the submission rules.

Library Wander



Libary Wander mimics the native Wander ability, while
granting advanced controll over the unit movement.​

Obligatory Requirements Optional Requirements


  • Code (vJASS):
    native UnitAlive takes unit id returns boolean

    library Wander uses Table optional TimerUtils
    //==================================================================
    // Version: 1.4.2
    // Author: BPower
    //==================================================================
    // Libary Wander mimics the native Wander ability, while
    // granting advanced controll over the unit movement.
    //==================================================================
    // Credits to:
    //     Vexorian for TimerUtils    -    wc3c.net/showthread.php?t=101322
    //     Bribe for Table            -    hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
    //==================================================================
    // API:
    //
    //    Methods:
    //
    //        static method operator [] takes unit whichUnit returns thistype
    //
    //        static method create takes unit whichUnit, real range, real cooldown returns thistype
    //
    //        method destroy takes nothing returns nothing
    //
    //        method exists takes nothing returns boolean
    //
    //        method pause takes nothing returns nothing
    //
    //        method resume takes nothing returns nothing
    //
    //    Fields:
    //
    //        readonly unit   source
    //                 real   radius
    //                 real   centerX
    //                 real   centerY
    //                 real   timeout ( The timer timeout )
    //                 real   random  ( Optionally adds a random interval to the timer timeout )
    //                 string order   ( Either "move" or "attack" are recommended )
    //
    //==================================================================
    // User settings:

        globals
            private constant real   DEFAULT_TIMER_TIMEOUT = 1.0
            private constant string DEFAULT_ORDER_STRING  = "move"
        endglobals
       
    //==================================================================
    // Wander code. Make changes carefully.
    //==================================================================
       
        globals
            private Table table
        endglobals
       
        private module Init
            private static method onInit takes nothing returns nothing
                call thistype.init()
            endmethod
        endmodule

        private function Random takes nothing returns real
            return GetRandomReal(0., 1.)
        endfunction
       
        struct Wander// extends array
            // implement Alloc
            //
            // Struct members:
            readonly unit   source
                     real   radius
                     real   centerX
                     real   centerY
                     real   timeout
                     real   random
                     string order
                     
            private  timer  tmr
           
            method operator exists takes nothing returns boolean
                return tmr != null
            endmethod
           
            static method operator [] takes unit whichUnit returns thistype
                return table[GetHandleId(whichUnit)]
            endmethod
           
            method pause takes nothing returns nothing
                call PauseTimer(tmr)
            endmethod
           
            method resume takes nothing returns nothing
                call ResumeTimer(tmr)
            endmethod
               
            method destroy takes nothing returns nothing
                if not exists then
                    return
                endif
               
                call deallocate()
                call table.remove(GetHandleId(source))
                static if LIBRARY_TimerUtils then
                    call ReleaseTimer(tmr)
                else
                    call table.remove(GetHandleId(tmr))
                    call DestroyTimer(tmr)
                endif
               
                set source = null
                set tmr    = null
            endmethod
           
            method issueWander takes nothing returns boolean
                local real t = Random()*2*bj_PI
                local real r = Random() + Random()
                if r > 1. then
                    set r = (2 - r)*radius
                else
                    set r = r*radius
                endif
               
                return IssuePointOrder(source, order, centerX + r*Cos(t), centerY + r*Sin(t))
            endmethod
           
            private static method onPeriodic takes nothing returns nothing
                static if LIBRARY_TimerUtils then
                    local thistype this = GetTimerData(GetExpiredTimer())
                else
                    local thistype this = table[GetHandleId(GetExpiredTimer())]
                endif
                   
                if UnitAlive(source) then
                       // There are a few order ids, which eventually mess with the following unit order comparison.
                       // For example order id 851974. An endless going, undocumented order serving no obvious purpose.
                    if GetUnitCurrentOrder(source) == 0 and issueWander() then
                        call TimerStart(tmr, timeout + random*Random(), true, function thistype.onPeriodic)
                    else
                        // Update in short intervals until a wander order is issued.
                        call TimerStart(tmr, DEFAULT_TIMER_TIMEOUT, true, function thistype.onPeriodic)
                    endif
                else
                    call destroy()
                endif
            endmethod
       
            static method create takes unit whichUnit, real range, real cooldown returns thistype
                local thistype this = thistype[whichUnit]
               
                if not exists then
                    set this   = thistype.allocate()
                    set source = whichUnit
                    set order  = DEFAULT_ORDER_STRING
                    set table[GetHandleId(whichUnit)] = this
                   
                    static if not LIBRARY_TimerUtils then
                        set tmr = CreateTimer()
                        set table[GetHandleId(tmr)] = this
                    else
                        set tmr = NewTimerEx(this)
                    endif
                endif
               
                set radius  = range
                set random  = 0.
                set centerX = GetUnitX(whichUnit)
                set centerY = GetUnitY(whichUnit)
                set timeout = RMaxBJ(0., cooldown)
               
                call TimerStart(tmr, timeout, true, function thistype.onPeriodic)
               
                return this
            endmethod

            private static method init takes nothing returns nothing
                set table = Table.create()
            endmethod
            implement Init
           
        endstruct
    endlibrary


Credits:
Bribe for SpellEffectEvent
Vexorian for TimerUtils​

Keywords:
Wander
Contents

Just another Warcraft III map (Map)

Reviews
Moderator
Wander v1.4.1 | Reviewed by Flux | 3 April 2016 Wander provides an advanced alternative to the default Wander ability allowing to control the timing (with random option), order, search radius and the wandering can be pause/unpause. Units...
  1. pred1980

    pred1980

    Joined:
    Mar 19, 2010
    Messages:
    844
    Resources:
    1
    Maps:
    1
    Resources:
    1
    Hi, can u tell me how can i extract the part of the random point calculation? I need it for another spell. I just need a function to get a Random Location in a circle...

    My approach is like that, but im not sure if its good ...

    Code (vJASS):
    function RandomPointCircle takes real x, real y, real d returns location
            local real cx = GetRandomReal(-d, d)
            local real ty = SquareRoot(d * d - cx * cx)
           
            return Location(x + cx, y + GetRandomReal(-ty, ty))
    endfunction
     
  2. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    7,950
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Code (vJASS):

    function MovePointInCircleRandom takes location p, real radius, real centerX, real centerY returns nothing
        local real angle = GetRandomReal(-bj_PI, bj_PI)
        set radius = GetRandomReal(-radius, radius)
        call MoveLocation(p, centerX + Cos(angle) * radius, centerY + Sin(angle) * radius)
    endfunction
     
     
  3. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Take a look into the graphics from Flux's post ( link ).

    The one I used the the third one, circular uniform.
    What Bribe wrote above is the second graphic, cicular non-uniform.

    The code is:

    Code (vJASS):
        private function Random takes nothing returns real
            return GetRandomReal(0., 1.)
        endfunction
         
        private function GetRandomRange takes real radius returns real
            local real r = Random() + Random()
            if r > 1. then
                return (2 - r)*radius
            endif
            return r*radius
        endfunction
       
        function RandomPointCircle takes real x, real y, real d return location
            local real theta = Random()*2*bj_PI
            local real range = GetRandomRange(d)
            return Location(x + range*Cos(theta), y + range*Sin(theta))
        endfunction


    Squeezed into one function
    Code (vJASS):

        function RandomPointCircle takes real x, real y, real d return location
            local real theta  = GetRandomReal(0., 1.)*2*bj_PI
            local real random = GetRandomReal(0., 1.) + GetRandomReal(0., 1.)
            if random > 1. then
                set random = (2 - random)*d
            else
                set random = random*d
            endif
            return Location(x + random*Cos(theta), y + random*Sin(theta))
        endfunction    
     
     
  4. pred1980

    pred1980

    Joined:
    Mar 19, 2010
    Messages:
    844
    Resources:
    1
    Maps:
    1
    Resources:
    1
    ok, so i'll change it to your squeezed version, thank you. Last question.... is the retrun value a leak problem?
     
  5. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    7,950
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Yes, which is why I recommend MoveLocation if you insist on using locations instead of coordinates.
     
  6. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Eventually, but only if you forget to remove the location later.

    Btw this one should also work properly ( Disk Point Picking )
    Code (vJASS):
        function RandomPointCircle takes real x, real y, real d return location
            local real theta = GetRandomReal(0., 1.)*2*bj_PI
            local real range = SquareRoot(GetRandomReal(0., 1.)*d*d)
            return Location(x + range*Cos(theta), y + range*Sin(theta))
        endfunction