library MoveSpeedXGUI /* v1.0.0.1
*************************************************************************************
*
* 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.
*
************************************************************************************
*
* 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
*
* HOW TO IMPLEMENT
*
* 1. Copy the trigger MoveSpeedXGUI.
* 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
*
* The unit may move randomly about one point before finally stopping. If
* this occurs, try changing PERIOD or reduce the unit movement speed.
*
* This also will not factor in bonuses.
*
************************************************************************************/
private function ApproxEqual takes real A, real B returns boolean
return (A >= (B - MARGIN)) and (A <= (B + MARGIN))
endfunction
private module M
private static integer ic = 0
private static integer ir = 0
static hashtable hash = InitHashtable()
thistype next
thistype prev
unit curr
real speed
real x
real y
method destroy takes nothing returns nothing
set this.next.prev = this.prev
set this.prev.next = this.next
set .prev = ir
set ir = this
call RemoveSavedInteger(hash, 0, GetHandleId(.curr))
endmethod
private static method periodic takes nothing returns nothing
local thistype this = thistype(0).next // first instance in list
local real nx = 0 // the x-coordinate after tick
local real ny = 0 // the y-coordinate after tick
local real dx = 0 // distance between new-x and old-x
local real dy = 0 // distance between new-y and old-y
local real d = 0 // distance between new point and old point
local unit u // unit being affected
loop
exitwhen this == 0
set u = .curr
set nx = GetUnitX(u)
set ny = GetUnitY(u)
if (not IsUnitPaused(u)) and GetUnitAbilityLevel(u, 'BSTN') == 0 and GetUnitAbilityLevel(u, 'BPSE') == 0 then
if not ApproxEqual(nx, .x) or not ApproxEqual(ny, .y) then
set dx = nx - .x
set dy = ny - .y
set d = SquareRoot(dx * dx + dy * dy)
set .x = nx + dx / d * .speed
set .y = ny + dy / d * .speed
call SetUnitX(u, .x)
call SetUnitY(u, .y)
endif
endif
set this = this.next
endloop
set u = null
endmethod
static method create takes unit whichUnit, real newSpeed returns thistype
local thistype this = ir
if this == 0 then
set ic = ic + 1
set this = ic
else
set ir = .prev
endif
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)
call SaveInteger(hash, 0, GetHandleId(whichUnit), this)
return this
endmethod
static method update takes unit whichUnit, real newSpeed returns nothing
local thistype this = 0
if HaveSavedInteger(hash, 0, GetHandleId(whichUnit)) then
set this = LoadInteger(hash, 0, GetHandleId(whichUnit))
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 onInit takes nothing returns nothing
call TimerStart(CreateTimer(), PERIOD, true, function thistype.periodic)
endmethod
endmodule
private struct MoveSpeedStruct extends array
implement M
endstruct
function GetUnitMoveSpeedX takes unit whichUnit returns real
if HaveSavedInteger(MoveSpeedStruct.hash, 0, GetHandleId(whichUnit)) then
return (MoveSpeedStruct(LoadInteger(MoveSpeedStruct.hash, 0, GetHandleId(whichUnit))).speed/PERIOD)+522
endif
return GetUnitMoveSpeed(whichUnit)
endfunction
function SetUnitMoveSpeedX takes unit whichUnit, real newSpeed returns nothing
call MoveSpeedStruct.update(whichUnit, newSpeed)
endfunction
hook SetUnitMoveSpeed SetUnitMoveSpeedX
endlibrary