Moderator
M
Moderator
24th Nov 2011
Bribe: Approved and highly recommended.
Bribe: Approved and highly recommended.
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