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

MoveSpeedX for GUI v1.1.0.0

Requires JassNewGenPack v5d and JassHelper 0.A.2.B!

This library allows you to set unit move speeds beyond the 522 limit. Special thanks to Jesus4Lyf for the base code. It has been modified from the normal MoveSpeedX to be compatible with GUI. While the system is in vJASS, you can simply use the GUI function to modify the speed and it will do the rest for you. To retrieve speed properly, you can use the global array named "UnitSpeedX". To retrieve it for a specific unit, it would be UnitSpeedX[Custom value of <unit>]. Note that you need a unit indexer for that to work properly.

It has some quirks with very high speeds (beyond ~1000) but otherwise it works perfectly.

*Note*: Please read the documentation.

System:
JASS:
library MoveSpeedXGUI /* v1.1.0.0
*************************************************************************************
*
*   This library allows you to set unit movement speeds beyond 522 without bugs.
*   This is an extension of the library MoveSpeedX, but is formatted for GUI use.
*   Credits to Jesus4Lyf for the original system.
*
************************************************************************************
*
*   SETTINGS
*/
globals
    private constant real PERIOD = 0.03125
        //  This is the period on which all units will be run.
        // If you lower this value, movement bonuses will be smoother,
        // but will require more processing power (lag more).
        //  Also, the lower this is, the higher the move speed can be
        // before it starts bugging on waypoints. The lowest valid
        // period is 0.00125. A period of 0.00625 is very robust.
    private constant real MARGIN = 0.01
        // This is the margin of approximation when comparing reals.
        // You will most likely not need to change this.
endglobals
/*
************************************************************************************
*
*    Functions
*
*        function GetUnitMoveSpeedX takes unit whichUnit returns real
*           - Returns a unit movement speed. The GUI function will
*           - not return the correct value. This function will always
*           - return the correct value regardless of whether the unit
*           - has a movement speed beyond 522.
*
************************************************************************************
*
*   REQUIREMENTS
*
*       1.  JassNewGen Pack v5d
*       2.  JassHelper 0.A.2.B
*       3.  Any unit indexer
*
*   HOW TO IMPLEMENT
*  
*       1.  Copy the 'folder' MoveSpeedX.
*       2.  Paste it into your map.
*       3.  Open "Advanced -> Gameplay Constants".
*       4.  Checkmark "Use Custom Gameplay Constants".
*       5.  Find the field, "Movement - Unit Speed - Maximum", change
*           that to 522.
*       6.  Find the field, "Movement - Unit Speed - Minimum", hold
*           shift and click, and change it to 0.
*       7.  Read HOW TO USE.
*
************************************************************************************
*
*   HOW TO USE
*
*       This system will automatically work by itself. You can use the
*       normal GUI function for modifying unit movement speeds. Simply
*       use "Unit - Set Movement Speed", input whatever value you want,
*       and you are good to go! It will handle values beyond 522 by itself.
*
*       HOWEVER, the GUI function will not return correct values if a unit
*       has a movement speed greater than 522. To fix this, use the function
*       GetUnitMoveSpeedX to return the correct value. A sample is given in
*       the trigger "Speed Change" in the test map.
*
************************************************************************************
*
*   NOTES
*
*       Units that were issued orders as groups might not *always* end up in the proper
*       "order". (they might not end up in an organized formation) They do sometimes though.
*       This is only for units with speeds above 522.
*
*       This also will not factor in bonuses and probably not slows either.
*
*       Units may waddle around the point for a little bit. Reduce PERIOD to fix
*       it a little bit. I recommend about 0.02 if you have really high speeds.
*
************************************************************************************/

    private function ApproxEqual takes real A, real B returns boolean
        return (A >= (B - MARGIN)) and (A <= (B + MARGIN))
    endfunction
   
    private module M
        private static trigger issued = CreateTrigger()
       
        thistype next
        thistype prev
       
        boolean enabled
        unit curr
        real speed
        real x
        real y
        real ox
        real oy
       
        method destroy takes nothing returns nothing
            set this.next.prev = this.prev
            set this.prev.next = this.next
            set this.enabled = false
        endmethod
           
        private static method periodic takes nothing returns nothing
            local thistype this = thistype(0).next // first instance in list
            local real nx // the x-coordinate after tick
            local real ny // the y-coordinate after tick
            local real dx // distance between new-x and old-x
            local real dy // distance between new-y and old-y
            local real d  // distance between new point and old point
            local integer order // the unit's current order
            local unit u // unit being affected 
            loop
                exitwhen this == 0
                set u  = .curr
                set nx = GetUnitX(u)
                set ny = GetUnitY(u)
                if IsUnitType(u, UNIT_TYPE_DEAD) then
                    call this.destroy()
                elseif not ApproxEqual(nx, .x) or not ApproxEqual(ny, .y) then
                    if (not IsUnitPaused(u)) and GetUnitAbilityLevel(u, 'BSTN') == 0 and GetUnitAbilityLevel(u, 'BPSE') == 0 then
                        set order = GetUnitCurrentOrder(u)
                        set dx = nx - .x
                        set dy = ny - .y
                        set d  = SquareRoot(dx * dx + dy * dy)
                        set dx = dx / d * .speed // move the unit offset-x by this
                        set dy = dy / d * .speed // move the unit offset-y by this
                       
                        if (order == 851986 or order == 851971) and /*
                        */ (this.ox - nx)*(this.ox - nx) < (dx*dx) and /*
                        */ (this.oy - ny)*(this.oy - ny) < (dy*dy) then
                            // if the unit is issued a move or smart order and they are near their destination
                            // then move them there instantly (removes a bit of glitchyness towards the end)
                            call SetUnitX(u, .ox)
                            call SetUnitY(u, .oy)
                            set .x = .ox
                            set .y = .oy
                            call IssueImmediateOrderById(u, 851972) // order them to stop
                        else
                            set .x = nx + dx
                            set .y = ny + dy
                            call SetUnitX(u, .x)
                            call SetUnitY(u, .y)
                        endif
                    endif
                endif
                set this = this.next
            endloop
            set u = null
        endmethod
       
        static method create takes unit whichUnit, real newSpeed returns thistype
            local thistype this = GetUnitUserData(whichUnit)
            set this.next = thistype(0).next
            set thistype(0).next.prev = this
            set thistype(0).next = this
            set this.prev  = 0
            set this.curr  = whichUnit
            set this.speed = (newSpeed - 522) * PERIOD
            set this.x     = GetUnitX(whichUnit)
            set this.y     = GetUnitY(whichUnit)
            set this.enabled = true
            return this
        endmethod
       
        static method update takes unit whichUnit, real newSpeed returns nothing
            local thistype this = GetUnitUserData(whichUnit)
            if this.enabled then
                if newSpeed > 522 then
                    set this.speed = (newSpeed - 522) * PERIOD
                else
                    call this.destroy()
                endif
            elseif newSpeed > 522 then
                call thistype.create(whichUnit, newSpeed)
            endif
        endmethod
       
        private static method storeOrderPoint takes nothing returns boolean
            local thistype this = GetUnitUserData(GetTriggerUnit())
            set this.ox = GetOrderPointX()
            set this.oy = GetOrderPointY()
            return false
        endmethod
   
        private static method onInit takes nothing returns nothing
            call TimerStart(CreateTimer(), PERIOD, true, function thistype.periodic)
            call TriggerRegisterAnyUnitEventBJ(issued, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
            call TriggerAddCondition(issued, Condition(function thistype.storeOrderPoint))
        endmethod
    endmodule
   
    private struct MoveSpeedStruct extends array
        implement M
    endstruct
   
    function GetUnitMoveSpeedX takes unit whichUnit returns real
        if MoveSpeedStruct(GetUnitUserData(whichUnit)).enabled then
            return udg_UnitSpeedX[GetUnitUserData(whichUnit)]
        endif
        return GetUnitMoveSpeed(whichUnit)
    endfunction
   
    function SetUnitMoveSpeedX takes unit whichUnit, real newSpeed returns nothing
        call MoveSpeedStruct.update(whichUnit, newSpeed)
        set udg_UnitSpeedX[GetUnitUserData(whichUnit)] = newSpeed
    endfunction

    hook SetUnitMoveSpeed SetUnitMoveSpeedX
endlibrary

Please report any bugs.

Changelog:
1.0.0.0 - Initial release
1.0.0.1 - Minor changes to constants.
1.1.0.0 - No longer requires JASS for retrieving speeds. Updated to use a unit indexer for faster speeds. Also is less prone to glitchy movement towards the end.

Keywords:
move, speed, nitro, boost, movespeed, movespeedx, sprint, dash
Contents

MoveSpeedX GUI (Map)

Reviews
24th Nov 2011 Bribe: Approved and highly recommended.

Moderator

M

Moderator

24th Nov 2011
Bribe: Approved and highly recommended.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Instead of ".rn" use the ".prev" member.

Make a local unit to store ".curr" so you don't spam array referencing.

It doesn't matter but "set thistype(0).next.prev = 0" is faster than "set this.next.prev = 0".

You can initialize "hash" from the globals block and use a library initializer for the timer. This prevents the need of the struct altogether.
 
Instead of ".rn" use the ".prev" member.

Make a local unit to store ".curr" so you don't spam array referencing.

It doesn't matter but "set thistype(0).next.prev = 0" is faster than "set this.next.prev = 0".

You can initialize "hash" from the globals block and use a library initializer for the timer. This prevents the need of the struct altogether.

kk I'll update it soon.

downloading it and i will edit this post after

EDIT dont work for me since i got the WE sad i expected it to work when title sais GUI :p

Sorry, it needs Jass NewGen Pack v5d. You can download it here:
http://www.wc3c.net/showthread.php?t=90999

It is GUI-friendly in the sense that you don't need to use any JASS functions to modify the unit's movement speed. You can just use the normal function as shown in the test map. ;)

Thanks everyone else for the comments.

EDIT: Updated for Bribe's comments.
 
Last edited:
When you check it through triggers, it will show 522 speed. Sadly, JassNewGen didn't expand its features much on hooking so I can only detect when functions occur; I can't override them. =(

That's why the JASS function has to be used.
GetUnitMoveSpeedX(unit)

Here are some examples:
  • Custom script: set udg_TempReal = GetUnitMoveSpeedX(udg_MyUnit)
  • // Retrieves the movement speed of the unit of "MyUnit" and assigns it to "TempReal"
  • Custom script: set udg_TempReal = GetUnitMoveSpeedX(GetTriggerUnit())
  • // Retrieves the movement speed of the triggering unit and assigns it to "TempReal"
However, you can set the movement speed however you want as normal.
  • Unit - Set <Unit> movement speed to 1043
That would work just fine; my system would detect it and do everything accordingly.
 
Level 6
Joined
Oct 23, 2011
Messages
182
Would this bug if I use SetUnitX/Y/Position? since it would probably think the unit moved

If so, should i hook those functions
and do something like this?

set MoveSpeedStruct[unit].x = new x
 
Now that I think about it, it may have a slight chance to accelerate the movement if you have something that moves the unit, such as a knockback.

Although, if you pause the unit before moving them, it will not cause any problems.

I'll run tests eventually and update this system if I find any problems. Thanks for bringing that to my attention. :) I could either add an option to disable the system for a unit (in case you need to move the unit), or I suppose i could also check if the unit is issued an order or not.

I based this off of MoveSpeedX by Jesus4Lyf so I didn't do too much bug testing aside from the actual system.
 

SDM

SDM

Level 1
Joined
May 7, 2012
Messages
2
hey an author i have a little question.Why does hero moves after he reach the target point.The model moves right and left some times and then stops.How can we skip that?
 
Oh yeah it happens when he moves too fast. Sometimes he'll skip over the spot he wants to walk on, and that causes him to end up cycling back and forth until he gets to the right spot.

This thing hasn't been completely bug fixed. If I get back on my other computer, I'll try to fix or reduce it.

One fix:
JASS:
private constant real PERIOD = 0.03125
        //  This is the period on which all units will be run.
        // If you lower this value, movement bonuses will be smoother,
        // but will require more processing power (lag more).
        //  Also, the lower this is, the higher the move speed can be
        // before it starts bugging on waypoints. The lowest valid
        // period is 0.00125. A period of 0.00625 is very robust.
You can change the period to be a bit lower and it may fix that problem or at least reduce the amount of occurrences.
 
Last edited:

SDM

SDM

Level 1
Joined
May 7, 2012
Messages
2
i've just used 1500 or 1000 movement speed and he skips from point to point. I'll wait your fix,thanks
 
Sorry for the long wait. I've updated the system to fix some of the glitchiness. It may skip around a bit on the way to the path, but that would require reworking the whole thing to completely remove. Just reduce the PERIOD constant to try to make it less glitchy.

Maybe I'll do mag's method eventually, but for now it should work pretty well. It takes up a bit more performance math-wise, but it is nothing noticeable ingame even on my crappy computer. If a unit is close enough to the point they've been issued to, then it will just put them there so they don't waddle around like a headless chicken trying to get on the right spot.

This new version also has a global to track speeds so you don't need to use custom script anymore. However, it now requires a unit indexer. (Bribe's is the one used in my test map)

Hopefully people will have fewer problems!
 
Level 12
Joined
Oct 16, 2008
Messages
512
This looks very nice, but i have a question: if i give queued orders to my high-speed unit, can this thing cancel the rest of the orders?
I'm simply asking because of the part of the code that orders the unit to stop. I don't understand even a half of the code honestly, i just know i've had this problem with some custom systems before (like jumps).
 
Level 16
Joined
Jul 31, 2012
Messages
2,217
the death knight bugs a bit when you come higher than 750 movement speed;
when you order him to travel a big distance like 1/4 of the map, he will stop at a point and start moving around himself like turning very weirdly and then he continues his march

anw nice system 4/5
 
Level 3
Joined
Oct 13, 2009
Messages
29
Very good System and it already got rid of AIDS System like the original MoveSpeedX by Jessus4Lyf.

For people who want to make a spell that change unit speed above 522 using this MovespeedX GUI System, create a trigger like this:

  • castbonus
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to (==) Rune of Speed
    • Actions
      • Unit - Set (Triggering unit) movement speed to 1000.00
 
Last edited:
Level 3
Joined
Oct 13, 2009
Messages
29
Hi, I'm making a spell that increase unit movement speed pass 522 in a few second, but after SetUnitMovespeedX is there a way to RemoveUnitMovespeedX ?
I don't know how to get unit real Movement speed ignore bonus from item, aura.. If I simply use the GUI function GetUnitMovespeed before call SetUnitMovespeedX and then SetUnitMovespeed then it will cause bug, unit speed will get bonus from item/aura also.

IDEA: Create a copy of original unit for Player 15 and remove all item, buff anything and then get its movespeed...
 
Level 33
Joined
Apr 24, 2012
Messages
5,113
There are some things that might be bugs in the system:

1) Movespeed less than 522 won't modify the unit's movespeed.
2) Units that have movespeed greater than 522 and was ordered to go to location where it must go around some obstructions, will go back-and-forth as if it was confused at which path it will take
 
There are some things that might be bugs in the system:

1) Movespeed less than 522 won't modify the unit's movespeed.
2) Units that have movespeed greater than 522 and was ordered to go to location where it must go around some obstructions, will go back-and-forth as if it was confused at which path it will take

(1) Works fine for me. If you meant it doesn't modify the movespeed in the code--it does. It hooks on to SetUnitMoveSpeed(). So if you set a unit's move speed to <= 522, then it destroys their instance (if it exists) or just does nothing. Hooks still ultimately call the function, so it'll still end up calling SetUnitMoveSpeed(u, num) for that unit.

(2) Yeah, I'm aware. This still ultimately relies on wc3's default movement, so if it skips past the target or a waypoint it'll end up trying to go back and forth between it. I might take a look at this system again down the line.

Thanks for the feedback. :)
 
Level 20
Joined
May 16, 2012
Messages
635
I think i found a bug. In my map, when some unit acquires a boots, i set the movement speed to 750, and it works fine until that unit dies. when it revives, still with boots, but the ms is slow, i think back to the older value or to the vale specified in the object editor. So any solutions for this? Nice system btw.
 
I think i found a bug. In my map, when some unit acquires a boots, i set the movement speed to 750, and it works fine until that unit dies. when it revives, still with boots, but the ms is slow, i think back to the older value or to the vale specified in the object editor. So any solutions for this? Nice system btw.

You'll want to create a trigger with an event that detects when the unit/hero revives. Check if they have the items in their inventory, and apply the bonus again. You might be able to get help with this in WEHZ, if you don't know where to start. :)
 
Level 8
Joined
Jul 25, 2009
Messages
194
Just a heads up for anyone using this library that importing this library means it's gonna run some stuff periodically, which probably isn't noticeable but it's probably best to turn it off when you don't need it.
E.g. if you're just using this library for a spell then you should only run the periodic functions in the library if spell is being cast.
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
Just a heads up for anyone using this library that importing this library means it's gonna run some stuff periodically, which probably isn't noticeable but it's probably best to turn it off when you don't need it.
E.g. if you're just using this library for a spell then you should only run the periodic functions in the library if spell is being cast.

Shouldn't the system handle that?
 
Top