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

[System (vJass)] Anachrons Move System

My updated Move System.


JASS:
//:******************************************************************************
//:  Anachrons Move System 
//:    by dhk_undead_lord / aka Anachron
//:    version 1.05
//:
//:
//:  ABOUT:
//:  This system has been thought to be able to easily
//:  create and manage spawn ways of troops.
//:  Top priority is the automatic movement control,
//:  such as high customizeability for users.
//:
//:  WHAT YOU NEED:
//:  You need JassNewGenPack to use this vJASS system.
//:  (Download it here: http://www.wc3c.net/showthread.php?goto=newpost&t=90999)
//:  
//:  STEPS TO IMPORT:
//:  I.) Copy this code.
//:  II.) Paste it into the head of your map.
//:  (Therefor go to the Trigger Editor, select the mapname and paste
//:   into the area on the right)
//:  III.) Save your map! 
//:  (With File - Save Map (S) or control + S. DO NOT SAVE WITH SAVE AS!)
//:  IV.) You got it! You imported the system.
//:  
//:  To make sure this system works, you should try a few tests!
//:  
//:  METHODS
//:  
//:  >WayPoint.create takes real baseX, real baseY, real targX, real targY, real targRadius
//:  Constructor of WayPoints.
//:  
//:  >WayPoint.moveUnit takes unit u
//:  Move any unit to the target of this waypoint!
//:  
//:  >Way.create takes boolean scCon, boolean stCon, boolean hdCon returns Way
//:  Create a new Way, say whether orders should recast attack/move or not.
//:  
//:  >Way.addWayPoint takes WayPoint wp returns nothing
//:  Add a waypoint to the system! Horray, another patrol point.
//:
//:  >Way.addUnit takes unit u returns nothing
//:  Adds an unit to the way. Automaticly moves to the first waypoint.
//:
//:  >Way.removeUnit takes unit u returns nothing
//:  Remove a unit from the way system.
//:
//:  >Way.moveUnit takes unit u, integer curPos returns nothing
//:  Move the unit u to the waypoint curPos's position
//:
//:  >Way.moveNext takes unit u, integer curPos returns nothing
//:  Sets the new wayPoint for the unit u
//:
//:  >Way.getNearestWP takes unit u returns integer
//:  A very nice function to find the nearest waypoint of an unit.
//:  Is perfect for Revive spells were you need to reregister,
//:  because with this function its pretty easy to get the correct waypoint.
//:  
//:  Thanks for downloading and using my system!
//:  
//:  Please don't forget to give credits to me (dhk_undead_lord / Aka Anachron)
//:
//:******************************************************************************  
library AnaMoveSys initializer init
    //==========================================================================
    // %CUSTOMIZATION AREA%: Feel free to change anything to what you need!
    //==========================================================================
    globals
        //: %Default Values%
        //:     Basicly the radius the unit has to be to
        //:     get ordered to the next waypoint.
        private constant real TARGET_TOLERANCE          = 192.
        //:     Sets whether the unit should move again
        //:     after it casted a spell.
        private constant boolean SPELLCAST_CONTINUE      = true
        //:     Sets whether the unit should move again
        //:     after it used stop command.
        private constant boolean STOP_CONTINUE          = true
        //:     Sets whether the unit should move again
        //:     after it used the hold position command.
        private constant boolean HOLDPOSITION_CONTINUE  = false
        //:     Sets whether death units will automaticly
        //:     removed by the system.
        //:     WARNING: THIS IS HIGLY RECOMMENDED!
        //:     TO ADD UNITS (LIKE REVIVE) USE THE addUnit()
        //:     METHOD!
        private constant boolean DEATH_REMOVES = true
        
        //: %Hashtable Storage%
        //:     Sets which key is for the unit ID
        private constant integer KEY_UNIT = 0
        //:     Sets which key is for the way ID
        private constant integer KEY_WAY = 1
        //:     Sets which key is for the current
        //:     waypoint ID.
        private constant integer KEY_CURPOS = 2
        
        //: %Order Ids%
        private constant string ORDER_STOP = "stop"
        private constant string ORDER_HOLDPOSITION = "position"
        private constant string ORDER_ATTACKMOVE = "attack"
        
        //: %Timers%
        private constant timer MOVE_TIMER = CreateTimer()
        private constant real MOVE_INT = 0.75
        
        //: %Saving%
        private hashtable UNIT_DATA = InitHashtable()
        private group MOVING_UNITS = CreateGroup()
    endglobals
    
    //: %Conditions of reordering the units
    //: Here you can define the conditions,
    //: such as owner controlling and other
    //: useful filters.
    public function globalCheck takes nothing returns boolean
        return LoadWidgetHandle(UNIT_DATA, GetHandleId(GetTriggerUnit()), KEY_UNIT) != null
    endfunction
    
    public function checkSpellcast takes nothing returns boolean
        return globalCheck()
    endfunction
    
    public function checkStopOrder takes nothing returns boolean
        return globalCheck() and GetIssuedOrderId() == OrderId(ORDER_STOP)
    endfunction
    
    public function checkHoldOrder takes nothing returns boolean
        return globalCheck() and GetIssuedOrderId() == OrderId(ORDER_HOLDPOSITION)
    endfunction
    
    //==========================================================================
    //: %DO NOT CHANGE THIS UNLIKE YOU KNOW WHAT YOU ARE DOING%
    //==========================================================================
    
    public function reOrderUnit takes nothing returns nothing
        local integer unitID = 0
        local integer wayID = 0
        local integer curPos = 0
        
        if IsUnitInGroup(GetTriggerUnit(), MOVING_UNITS) then
            set unitID = GetHandleId(GetTriggerUnit())
            set wayID = LoadInteger(UNIT_DATA, unitID, KEY_WAY)
            set curPos = LoadInteger(UNIT_DATA, unitID, KEY_CURPOS)
            debug call BJDebugMsg("!AoSMoveSys] |NOTICE| <Way[" + I2S(wayID) + "]> <Reorder unit " + I2S(unitID) + ">")
            call Way.instances[wayID].moveUnit(GetTriggerUnit(), curPos)
        endif
    endfunction
    
    public function checkUnregister takes nothing returns boolean
        return GetOwningPlayer(GetTriggerUnit()) == Player(0)
    endfunction
    
    public function unregisterUnit takes nothing returns nothing
        local integer wayID = LoadInteger(UNIT_DATA, GetHandleId(GetTriggerUnit()), KEY_WAY)
        
        call Way.instances[wayID].removeUnit(GetTriggerUnit())   
    endfunction

    struct WayPoint
        real baseX = 0.
        real baseY = 0.
        
        real targX = 0.
        real targY = 0.
        real targRadius = 0.
        
        integer ID = 0
        
        //: =================================
        //: CREATE NEW INSTANCES
        //: =================================
        public static method create takes real bX, real bY, real tX, real tY, real tR returns WayPoint
            local thistype wp = thistype.allocate()
                set wp.baseX = bX
                set wp.baseY = bY
                set wp.targX = tX
                set wp.targY = tY
                set wp.targRadius = tR
            return wp
        endmethod
        //: =================================
        
        //: =================================
        //: Move the unit to the target loc
        //: =================================
        public method moveUnit takes unit u returns nothing
            call IssuePointOrder(u, ORDER_ATTACKMOVE, .targX, .targY)
        endmethod
        //: =================================   
    endstruct
    
    struct Way
        group units = CreateGroup()
        
        integer ID = 0
        static Way array instances[8191]
        static integer index = 0
        
        integer curwpID = 0
        WayPoint array wayPoints[128]
        
        //: Saves the triggers for the
        //: auto remove functions.
        //:     -> spellcast?
        static trigger scTrig = CreateTrigger()
        //:     -> stop?
        static trigger stTrig = CreateTrigger()
        //:     -> hold position?
        static trigger hpTrig = CreateTrigger()
        
        //: This unregisters unit which die
        static trigger deathTrig = CreateTrigger()
        
        //: =================================
        //: CREATE NEW INSTANCES
        //: =================================
        public static method create takes nothing returns thistype
            local thistype wy = thistype.allocate()
                call thistype.addWay(wy)
            return wy
        endmethod
        //: =================================
        
        //: =================================
        //: Add and remove ways to the system
        //: =================================
        private static method addWay takes thistype wy returns nothing
            set wy.ID = thistype.index
            set thistype.instances[thistype.index] = wy
            set thistype.index = thistype.index + 1
        endmethod
        
        private static method removeWay takes thistype wy returns nothing
            set thistype.instances[wy.ID] = thistype.instances[thistype.index]
            set thistype.index = thistype.index - 1
        endmethod
        //: =================================
        
        //: ====================================
        //: Add and remove Way Point to the way
        //: ====================================
        public method addWayPoint takes WayPoint wp returns nothing
            set wp.ID = .curwpID
            set .wayPoints[.curwpID] = wp
            set .curwpID = .curwpID + 1
        endmethod
        
        public method removeWayPoint takes WayPoint wp returns nothing
            set .wayPoints[wp.ID] = .wayPoints[.curwpID]
            set .curwpID = .curwpID - 1
        endmethod
        //: ====================================
        
        //: ====================================
        //: Add and remove units to the way
        //: ====================================
        public method addUnit takes unit u, integer curPos returns nothing
            if not(IsUnitInGroup(u, .units)) then
                call SaveWidgetHandle(UNIT_DATA, GetHandleId(u), KEY_UNIT, u)
                call SaveInteger(UNIT_DATA, GetHandleId(u), KEY_WAY, .ID)
                call SaveInteger(UNIT_DATA, GetHandleId(u), KEY_CURPOS, curPos)
                
                call GroupAddUnit(.units, u)
                call GroupAddUnit(MOVING_UNITS, u)
                
                call .moveUnit(u, curPos)
            else
                debug call BJDebugMsg("!AoSMoveSys] |ERROR| <Way[" + I2S(.ID) + "]> <addUnit: UNIT ALREADY REGISTERED!>")
            endif
        endmethod
        
        public method removeUnit takes unit u returns nothing
            call FlushChildHashtable(UNIT_DATA, GetHandleId(u))
            call GroupRemoveUnit(.units, u)
            call GroupRemoveUnit(MOVING_UNITS, u)
            debug call BJDebugMsg("!AoSMoveSys] |NOTICE| <Way[" + I2S(.ID) + "]> <removeUnit: UNIT HAS BEEN REMOVED!>")
        endmethod
        //: ====================================
        
        //: ====================================
        //: Move an unit to the target 
        //: ====================================
        public method moveUnit takes unit u, integer curPos returns nothing
            call .wayPoints[curPos].moveUnit(u)     
        endmethod
        
        public method moveNext takes unit u, integer curPos returns nothing
            set curPos = curPos + 1
            if curPos < .curwpID then
                //: %Save data and move unit%
                call SaveInteger(UNIT_DATA, GetHandleId(u), KEY_CURPOS, curPos)
                call .moveUnit(u, curPos)
            else
                call .removeUnit(u)
            endif
        endmethod
        //: ====================================
        
        //: ====================================
        //: Additional Methods for users
        //: ====================================
        public method getNearestWP takes unit u returns integer
            local integer foundWP = -1
            local WayPoint wp = 0
            local integer i = 0
            local real tmpDist = 0.
            //: !Do NOT change this
            local real dist = 100000000.
            
            loop
                exitwhen i >= .curwpID
                
                // %Compare the distances%
                set tmpDist = SquareRoot(GetUnitX(u) * wp.targX + GetUnitY(u) * wp.targY)
                if tmpDist <= dist then
                    set foundWP = i
                    set dist = tmpDist    
                endif
                
                set i = i + 1    
            endloop
            
            return foundWP
        endmethod
        //: ====================================
        
        //: ====================================
        //: Desctrutor Method
        //: ====================================
        private method onDestroy takes nothing returns nothing
            local integer i = 0
            
            loop
                exitwhen i >= .curwpID
                
                call .wayPoints[i].destroy()
                 
                set i = i + 1
            endloop
            
            call thistype.removeWay(this)
        endmethod
        //: ====================================
    endstruct
    
    private struct MoveOrders
    
        //: =================================
        //: CHECK ALL WAYS FOR SPAWNING
        //: =================================
        static method checkWays takes nothing returns nothing
            local Way wy = 0
            local WayPoint wp = 0
            local integer i = 0
            
            local unit u = null
            local group g = CreateGroup()
            local integer unitID = 0
            local integer wpID = 0
            
            local real dx = 0.
            local real dy = 0.
            local real dist = 0.
            
            loop
                exitwhen i >= Way.index
                
                //----------------
                //: %Reset Data%
                //----------------
                set u = null
                call GroupClear(g)
                set wy = 0
                set wp = 0
                set unitID = 0
                //----------------
                
                set wy = Way.instances[i]
                call GroupAddGroup(wy.units, g)
                
                loop
                    set u = FirstOfGroup(g)
                    exitwhen u == null
                    
                    //-----------------------
                    // %Get unit data%
                    //-----------------------
                    set unitID = GetHandleId(u)
                    set wpID = LoadInteger(UNIT_DATA, unitID, KEY_CURPOS)
                    set wp = wy.wayPoints[wpID]
                
                    //: Check whether the unit is in the range of
                    //: her checkpoint
                    set dx = GetUnitX(u) - wp.targX
                    set dy = GetUnitY(u) - wp.targY
                    set dist = SquareRoot(dx * dx + dy * dy)
                    if dist <= wp.targRadius then
                        call wy.moveNext(u, wpID)
                        debug call BJDebugMsg("!AoSMoveSys] |NOTICE| <Way[" + I2S(wy.ID) + "]> <Unit " + I2S(GetHandleId(u)) + " reached target>")
                    endif
                    
                    call GroupRemoveUnit(g, u)
                endloop 
                
                set i = i + 1
            endloop
            
            call GroupClear(g)
            set u = null
            set g = null
        endmethod
        //: =================================
    endstruct
    
    private function init takes nothing returns nothing
        local integer i = 0
        call TimerStart(MOVE_TIMER, MOVE_INT, true, function MoveOrders.checkWays)
        
        if SPELLCAST_CONTINUE then
            call TriggerAddAction(Way.scTrig, function reOrderUnit)
            call TriggerAddCondition(Way.scTrig, Condition(function checkSpellcast))
            set i = 0
            loop
                exitwhen i > 15
                call TriggerRegisterPlayerUnitEvent(Way.scTrig, Player(i), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
                set i = i + 1
            endloop
        endif
                
        if STOP_CONTINUE then
            call TriggerAddAction(Way.stTrig, function reOrderUnit)
            call TriggerAddCondition(Way.stTrig, Condition(function checkStopOrder))
            set i = 0
            loop
                exitwhen i > 15
                call TriggerRegisterPlayerUnitEvent(Way.scTrig, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
                set i = i + 1
            endloop
        endif
                
        if HOLDPOSITION_CONTINUE then
            call TriggerAddAction(Way.hpTrig, function reOrderUnit)
            call TriggerAddCondition(Way.hpTrig, Condition(function checkHoldOrder))
            set i = 0
            loop
                exitwhen i > 15
                call TriggerRegisterPlayerUnitEvent(Way.hpTrig, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
                set i = i + 1
            endloop
        endif
                
        if DEATH_REMOVES then
            call TriggerAddAction(Way.deathTrig, function unregisterUnit)
            call TriggerAddCondition(Way.deathTrig, Condition(function checkUnregister))
            set i = 0
            loop
                exitwhen i > 15
                call TriggerRegisterPlayerUnitEvent(Way.deathTrig, Player(i), EVENT_PLAYER_UNIT_DEATH, null)
                set i = i + 1
            endloop
        endif
    endfunction

endlibrary



JASS:
scope example initializer init

    private function init takes nothing returns nothing
        local WayPoint wp = 0
        local Way wy = 0
        local unit u = CreateUnit(Player(0), 'hmpr', 800., -1200., 270.)
        
        call FogModifierStart(CreateFogModifierRect(Player(0), FOG_OF_WAR_VISIBLE, bj_mapInitialPlayableArea , false, false))
        
        //: Instaciate a new way
        set wy = Way.create()
        //: Add a new waypoint
        call wy.addWayPoint(WayPoint.create(800., -1200., -900., -1125., 192.))
        call wy.addWayPoint(WayPoint.create(-900., -1125., -860., -110., 192.))
        call wy.addWayPoint(WayPoint.create(-860., -110., 0., 0., 192.))
        //: Add a unit to the way, starting at waypoint 0.
        call wy.addUnit(u, 0) 
    endfunction

endscope


Update 1:
Added remove functions to all objects, moved the example in an extra function

Keywords:
Auto, Move, Move System, System, Way Point, Way, Point
Contents

Anachrons Move System 1.05 (Map)

Reviews
20:45, 6th Oct 2009 The_Reborn_Devil: It seems to be working and the code looks good. It's also quite useful. Approved. I give this system the rating Useful/Recommended [3.99/5].

Moderator

M

Moderator

20:45, 6th Oct 2009
The_Reborn_Devil:

It seems to be working and the code looks good.
It's also quite useful.
Approved.
I give this system the rating Useful/Recommended [3.99/5].
 
Level 17
Joined
Mar 2, 2009
Messages
332
Not useful to me...i need system where creep is created for ally of 5 players of team but creep mustn't be controlled by any player which exist....
To make things easier i need system where there are only 5 players in team and none of them can't control creeps...
 
Level 37
Joined
Mar 5, 2008
Messages
3,887
Not useful to me...i need system where creep is created for ally of 5 players of team but creep mustn't be controlled by any player which exist....
To make things easier i need system where there are only 5 players in team and none of them can't control creeps...

Create a unit for some non-user player and change its team color? ^^
 
Level 37
Joined
Mar 5, 2008
Messages
3,887
Looks, ok. But why making this complicated since you can just make a few regions and check the unit type of "entering unit" and if it matches the order it to move to the next region.

I'm pretty sure that this is how 90% of map makers do it ^^

But It could be useful and wen you'll make a spawn it could be useful even more (like i have any clue what's written in that script :p)
 
Thats right, but thats not he only example.

Also, while rects are squared, this system has an RADIUS,
so entering the area of the waypoint will make the unit move
to the next, while square looks ugly.

And it will also move units to the target point again
when you casted a spell, use the stop or the
hold position order.

I didn`t made the other order because its quite
crazy to order them to attack/move again
after a patrol order. (because it has to be triggered
to happen, so this is not what you want)

Looks, ok. But why making this complicated since you can just make a few regions and check the unit type of "entering unit" and if it matches the order it to move to the next region.

I'm pretty sure that this is how 90% of map makers do it ^^
Because it bugs? Ever tried moving 25 units to the same area?
it will bug on rects, but with my method units will continue try
reaching the waypoint, until they reached him.

Also, rects are ugly becaues you shouldn´t use them if you can
avoid them. why using a check trigger if the unit is entered? It
doesn´t looks well and also it is not that smooth as mine.
 
Level 13
Joined
Mar 19, 2010
Messages
870
Hey Anachron: I've a problem with your system. I dont know why but some units in my Tower defense run back to the last waypoint when they're under attack of the tower and i dont know why!!!! After reached the last point, they get reordered by your function and they try it again and move to all waypoints. Where is the Problem?
 
Level 13
Joined
Mar 19, 2010
Messages
870
Solution:

add this lines at the end of your code where you add the event stuff and add a new trigger at the top and thats all :)

JASS:
call TriggerAddAction(Way.moTrig, function reOrderUnit)
call TriggerAddCondition(Way.moTrig, Condition(function checkMoveOrder))
call TriggerRegisterPlayerUnitEvent(Way.moTrig, Player(bj_PLAYER_NEUTRAL_VICTIM), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)

And no Unit will return to the startPoint :) YEAHHH, HF
 
Level 3
Joined
Mar 26, 2011
Messages
44
Finally after a long time creating my own and its buggy. Hehehe I can use this to fix my unit spawns moving to a certain area
 
Top