library TimedUnitScale /* v2.0
Information
¯¯¯¯¯¯¯¯¯¯¯
Allows you smoothly to change a unit's scale over time.
It is required you to read the GetUnitScale library,
if you modified default scale values in object editor.
Credits:
¯¯¯¯¯¯¯¯
Resources:
- TriggerHappy
- Nestharus
*/ requires /*
*/ GetUnitScale /* hiveworkshop.com/forums/submissions-414/snippet-getunitscale-262274/
*/ UnitDex /* hiveworkshop.com/threads/system-unitdex-unit-indexer.248209/
*/ List /* attached in map and in thread, because nestharus removed it I can't find original destinaion anymore
struct UnitScale
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
static method operator enableAll= takes boolean flag returns nothing
- when set to "false" it will pause all scale changes for all units
- when set to "true" it will continue again
static method operator [] takes unit who returns thistype
- That's the only interface for the user to get an instance.
- Use this to call methods or to set/read other members:
method apply takes real newScale, real duration returns UnitScaleData
- use this to apply a new scale change
- you also can use GetUnitScale function to mimic add & substract behaviour.
method stopScale takes UnitScaleData sd returns nothing
- you can use the return value from the "apply" method to manualy destroy a scale instance.
- do this at your own risk
method destroy
- "destroy" will destroy all scale instances.
boolean enabled
- set this to "false" if you want to disable, but not destroy a unit's scale changes
- when set to "true" it will continue again
readonly boolean exists
returns the flag if there currently exists any scale instance
readonly integer count
returns amount of current scale instances for our unit
Example:
local UnitScale myInstance = UnitScale[GetTriggerUnit()]
- we get the instance for our unit.
local UnitScaleData data = myInstance.apply(5, 10)
- this will call the apply method for myInstance.
- it will try to set it's scale to "5" over "10" seconds.
call instance.stopScale(data)
- will destroy the applied scale instance
Pay attention for the example. When the user will start multiple scale instances,
it oboviously is not ensured that the unit will have exactly the scale of "5" after "10" seconds.
If you want ensure accurate values you can check for already running instances, or use the .destroy() method before apply().
struct UnitScaleData
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
That's the struct returned by the apply method above.
You have further access from it:
method operator time takes nothing returns real
- returns the remaining time of the instance
method operator time= takes real r returns nothing
- define a new remaining time
- only positives will be allowed
method operator scalePerSecond takes nothing returns real
- return the current scale rate perSecond
method operator scalePerSecond= takes real r returns nothing
- define a new sclare rate perSecond.
- only positives will be allowed.
**************************************************************************/
globals
private constant timer CLOCK = CreateTimer()
private constant real TIMEOUT = .031250000
endglobals
struct UnitScaleData extends array
implement List
real duration // Remaining duration for scaling
real amount // scale-amount per interval
method operator time takes nothing returns real
return .duration
endmethod
method operator time= takes real r returns nothing
set .duration = RAbsBJ(r)
endmethod
method operator scalePerSecond takes nothing returns real
return .amount/TIMEOUT
endmethod
method operator scalePerSecond= takes real r returns nothing
set .amount = RAbsBJ(r)*TIMEOUT
endmethod
endstruct
struct UnitScale extends array
private static boolean systemEnabled = false
boolean enabled
readonly boolean exists // Does a UnitScale currently exist?
readonly integer count // How often a unit is currently regstered.
private unit u
private UnitScaleData head
private thistype prev
private thistype next
private static thistype first = 0
static method operator [] takes unit who returns thistype
return GetUnitId(who)
endmethod
private method destroy takes nothing returns nothing
if not .exists then
return
endif
call .head.destroy()
set .count = 0
if (this == thistype.first) then
set thistype.first = this.next
endif
set this.next.prev = this.prev
set this.prev.next = this.next
if (thistype.first == 0) then
call PauseTimer(CLOCK)
set thistype.systemEnabled = false
endif
set .exists = false
set .u = null
endmethod
method stopScale takes UnitScaleData sd returns nothing
set .count = .count - 1
if .count == 0 then
call.destroy()
else
call sd.remove()
endif
endmethod
private static method callback takes nothing returns nothing
local thistype this = thistype.first
local UnitScaleData element
local UnitScaleData temp
loop
exitwhen (this == 0)
if (GetUnitTypeId(.u) == 0) then
call .destroy()
elseif (.enabled) then
set element = .head.first
loop
exitwhen element == 0
set temp = element.next
call SetUnitScale(.u, (GetUnitScale(.u) + element.amount), 1, 1)
if (element.duration <= TIMEOUT) then
call .stopScale(element)
else
set element.duration = element.duration - TIMEOUT
endif
set element = temp
endloop
endif
set this = this.next
endloop
endmethod
method apply takes real newScale, real duration returns UnitScaleData
local unit u = GetUnitById(this)
local UnitScaleData element
if (newScale == GetUnitScale(u)) then
return 0
endif
if (duration < 0) then
debug call BJDebugMsg("UnitScale: Durations smaller or equal 0 will lead to instant scaling.")
set duration = 0
endif
if (duration == 0) then
call SetUnitScale(u, newScale, 1, 1)
return 0
endif
set this = GetUnitId(u)
if .count == 0 then
set .head = UnitScaleData.create()
set .enabled = true
set .exists = true
set .u = u
if (thistype.first == 0) then
call TimerStart(CLOCK, TIMEOUT, true, function thistype.callback)
set thistype.systemEnabled = true
endif
set this.next = thistype.first
set thistype.first.prev = this
set thistype.first = this
set this.prev = 0
endif
set element = .head.enqueue()
set element.duration = duration
set element.amount = (newScale - GetUnitScale(u)) / (duration/TIMEOUT)
set .count = .count + 1
return element
endmethod
static method operator enableAll= takes boolean flag returns nothing
if flag and not thistype.systemEnabled and thistype.first != 0 then
call TimerStart(CLOCK, TIMEOUT, true, function thistype.callback)
set thistype.systemEnabled = flag
elseif not flag and not thistype.systemEnabled then
call PauseTimer(CLOCK)
set thistype.systemEnabled = flag
endif
endmethod
endstruct
endlibrary
v2.0 - Internaly the structure is a bit cleaner and uses an other struct. - Reworked API syntax and added a bit more powers for user. v.1.6a- Removed not directly needed requierements. v.1.6- Moved timer callback, to prevent trigger evaluation. - Updated GetUnitScale in demo. v.1.5.0a- Removed stop-scale-onDeath config. v.1.5.0- Seperated GetUnitScale from system. v.1.4.2- Only allocate if all conditions are true. - Renamed two API functions. Again ... v1.4.1- Forgot to rename 2 API functions. v1.4.0- Structure reduced. Double scaling is not possible anymore. Only single scale -> straight forward. v1.3.2- Static if added for v1.3.1onDeath .- Optimized method v1.3.0onDeindex .- Cancel scaling onDeindex. v1.2.1- Canceling scaling onDeath now possible. - Note was outdated. Changed. v1.2.0- API functions moved below struct. - Now also 0 and negative values are allowed as parameter, and will be automatically be fixed, if needed. v1.1.0- Fixed a bug with scale accuracy. - v1.0function GetUnitDefaultScale added.- function StopGrows added.- function ResetScale added.- Division with 0 bug fixed. - Tiny code optimizations. - release |