1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Music Contest #10 - Results are finally published! Drop by to check some retro songs and congratulate the winners!
    Dismiss Notice
  3. Join Terraining Contest #19 and witness the aftermath!
    Dismiss Notice
  4. The 3rd Melee Mapping Contest is ON! Join in on a ride of a 4v4 melee experience!
    Dismiss Notice
  5. The 30th edition of the Modeling Contest is finally up! The Portable Buildings need your attention, so come along and have a blast!
    Dismiss Notice

MoveSpeedX for GUI v1.1.0.0

Submitted by PurgeandFire
This bundle is marked as approved. It works and satisfies the submission rules.
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:
Code (vJASS):
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
Moderator
24th Nov 2011 Bribe: Approved and highly recommended.
  1. venomancerVN

    venomancerVN

    Joined:
    Aug 2, 2015
    Messages:
    5
    Resources:
    0
    Resources:
    0
    Good Job!
     
  2. Cake is a Lie

    Cake is a Lie

    Joined:
    Oct 1, 2017
    Messages:
    99
    Resources:
    0
    Resources:
    0
    Actually,I found a bug...
     
  3. Cake is a Lie

    Cake is a Lie

    Joined:
    Oct 1, 2017
    Messages:
    99
    Resources:
    0
    Resources:
    0
    I just found a bug...
    When you order him to move,hold shift and move again...There,he stopped...
     
  4. Almia

    Almia

    Joined:
    Apr 24, 2012
    Messages:
    4,832
    Resources:
    35
    Spells:
    30
    Tutorials:
    4
    JASS:
    1
    Resources:
    35
    It is good, until it tries to pass a two-tile wide path.