- Joined
- Mar 29, 2016
- Messages
- 688
Motion Sensor v1.4.0
Note:
As of version v1.4.0, there have been major changes in the API. To maintain backwards compatibility, library MotionSensorBC is available below. Just put it in your map and all will be seamless.
Please read the script header for the complete documentation and for more information.
You might also want to check the demo map below, its nice =). Plus it also has a GUI extension.
Motion Sensor Script
Rupture library
Rupture Moving Units
v1.4.0
- Major API changes (Also added a backwards compatibility lib)
- Made the configuration constant public
- Added a readonly linked-list for unit indexes registered in the system
- Changes in the GUI Plugin
- Other changes
v1.3c
- Not uploaded
v1.3b
- Added a new public module for running motion events within a struct
- Added two new groups SENSOR_GROUP_MOVING and SENSOR_GROUP_STATIONARY to allow users to easily loop through desired units
- The motion change event now uses TriggerEvaluate() instead of TRVE for a faster execution
- Changed prevX and prevY's privacy from being private to readonly
- Added function wrappers for getting the prevX and prevY of a unit
- Added a debug message in the operator []= to warm users when they try to double-free or double-register a unit
- When enabling the Sensor, it checks first if the sensorGroup is empty before running the periodic actions
- Updated the Rupture Spell code and the demo map
- Updated the documentation
- Other changes
v1.3
- Not uploaded
v1.2c
- Renamed some global constants
- Updated the demo map
v1.2b
- Made some proper functions/methods arrangements
- Removed the method operators < and ==
- Removed some unnecessary debug messages
- Fixed some compile errors on the demo script
- Other changes
v1.2
- The system now uses struct APIs but function wrappers are still available for users who are not so accustomed to using structs
- Now provides a boolean struct member for checking if a unit is registered to the system or not
- Some naming changes
- Optimized some parts of the script
- Some fixes and other changes
v1.1b
- Added a new API function IsSensorEnabled() for checking if the MotionSensor is enabled or disabled
- Some changes on the Demo Map
- Functions for registering codes now do not inline for the reason that it will throw an error when the code passed returns nothing in case it inlines
- Fixed the problem regarding Pause/Unpause timer
- The periodic function now only runs when there is a unit registered
- Other changes
v1.1
- API functions for getting a unit's motion stats are now inlined to array lookups
- Added more functionality to the system
- Now allows you to remove a triggercondition from a motion event
- Users can now choose if they want to automatically add all units to the system or if they want to add units manually
- Now uses arrays instead of hashtable
- Added UnitDex as a requirement, TimerUtils and GroupUtils as optional requirements
- The system no longer enumerates units in the map every period but stores them to a global group
- All public functions now inline when DEBUG_MODE is OFF
- Added a demo map
- Other changes
v1.0
- First Release
Note:
As of version v1.4.0, there have been major changes in the API. To maintain backwards compatibility, library MotionSensorBC is available below. Just put it in your map and all will be seamless.
Please read the script header for the complete documentation and for more information.
You might also want to check the demo map below, its nice =). Plus it also has a GUI extension.
Motion Sensor Script
JASS:
library MotionSensor /* v1.4.0 https://www.hiveworkshop.com/threads/system-motion-sensor.287219/
*/requires /*
*/UnitDex /* http://www.hiveworkshop.com/threads/248209
*///! novjass
|=============|
| Author: AGD |
|=============|
/* This simple system allows you to check if the current motion
a unit is stationary or in motion (This includes triggered
motion). You can also use this to get the instantaneous speed
of a unit and its direction of motion. This also allows you to
detect a change in motion event i.e. when either a unit in
motion stops or a stationary unit moves. Furthermore, the system
includes many other utilities regarding unit motion. */
|==============|
| Struct API |
|==============|
struct MotionSensor
readonly thistype prev
readonly thistype next
/* - unit index links */
readonly boolean sensored /* Checks if the Sensor instance is registered */
readonly boolean moving /* Checks if it is moving or not */
readonly real speed /* The instantaneous speed */
readonly real direction /* The direction of motion */
readonly real deltaX /* X component of the instantaneous speed */
readonly real deltaY /* Y component of the instantaneous speed */
readonly real prevX /* The previous x-coordinate */
readonly real prevY /* The previous y-coordinate */
readonly static unit triggerUnit /* The motion changing unit */
readonly static integer newMotionState /* The current motion state of the motion changing unit */
static method operator [] takes unit u returns Sensor/*
- Returns a Sensor instance based on the unit parameter
*/static method operator []= takes unit u, boolean flag returns nothing/*
- Registers/Unregisters a unit to the system
*/static method operator enabled takes nothing returns boolean/*
- Checks if the Motion Sensor is enabled or disabled
*/static method operator enabled= takes boolean flag returns nothing/*
- Enables/Disables the Motion Sensor
*/static method registerMotionChangeEvent takes code c returns triggercondition/*
*/static method unregisterMotionChangeEvent takes triggercondition tc returns nothing/*
- Registers a code to run during a motion change event / Unregisters
*/static method registerMotionStartEvent takes code c returns triggercondition/*
*/static method unregisterMotionStartEvent takes triggercondition tc returns nothing/*
- Registers a code to run when a unit stops moving / Unregisters
*/static method registerMotionStopEvent takes code c returns triggercondition/*
*/static method unregisterMotionStopEvent takes triggercondition tc returns nothing/*
- Registers a code to run when a stationary unit moves / Unregisters */
|================|
| Function API |
|================|
/* All these functions inline when DEBUG_MODE is OFF except for
RegisterEvent functions which was done intentionally to allow
users to pass code that returns nothing
*/function GetInstantaneousSpeed takes unit u returns real/*
- Returns the instantaneous speed of a unit
*/function GetMotionDirection takes unit u returns real/*
- Returns the current direction of a unit's motion
*/function GetUnitDeltaX takes unit u returns real/*
*/function GetUnitDeltaY takes unit u returns real/*
- Returns the x/y-component of a unit's instantaneous velocity
*/function GetUnitPreviousX takes unit u returns real/*
*/function GetUnitPreviousY takes unit u returns real/*
- Returns the previous x/y-coordinate of the unit
*/function IsUnitMoving takes unit u returns boolean/*
- Checks if a unit is currently moving or not
*/function IsUnitSensored takes unit u returns boolean/*
- Checks if a unit is registered to the system or not
*/function RegisterMotionChangeEvent takes code c returns triggercondition/*
*/function UnregisterMotionChangeEvent takes triggercondition tc returns nothing/*
- Registers a code to run on a motion change event / Unregisters it
*/function RegisterMotionStartEvent takes code c returns triggercondition/*
*/function UnregisterMotionStartEvent takes triggercondition tc returns nothing/*
- Registers a code to run when a stationary unit moves / Unregisters it
*/function RegisterMotionStopEvent takes code c returns triggercondition/*
*/function UnregisterMotionStopEvent takes triggercondition tc returns nothing/*
- Registers a code to run when a unit in motion stops / Unregisters it
*/function SensorAddUnit takes unit u returns nothing
function SensorRemoveUnit takes unit u returns nothing/*
- Registers/Unregisters a unit to the system
*/function GetNewMotionState takes nothing returns integer/*
- Refers to the current motion state of the motion changing unit
*/function GetMotionChangingUnit takes nothing returns unit/*
- Refers to the motion changing unit
*/function MotionSensorEnable takes nothing returns nothing
function MotionSensorDisable takes nothing returns nothing/*
- Switches the motion sensor ON/OFF
*/function IsSensorEnabled takes nothing returns boolean/*
- Checks if the system is enabled of disabled */
|===========|
| Constants |
|===========|
Groups:
group SENSOR_GROUP_MOVING
group SENSOR_GROUP_STATIONARY
/* You can use these groups to easily loop among moving/stationary
units like so: */
loop
set u = FirstOfGroup(SENSOR_GROUP_MOVING)
exitwhen u == null
call GroupRemoveUnit(SENSOR_GROUP_MOVING, u)
call GroupAddUnit(tempGroup, u)
// ...Do stuffs...
endloop
set forSwap = SENSOR_GROUP_MOVING
set SENSOR_GROUP_MOVING = tempGroup
set tempGroup = forSwap
// Note: Do not destroy these groups nor set them to something
// else without setting them back to their original value
// before the thread execution is finished
Integers:
integer MOTION_STATE_MOVING
integer MOTION_STATE_STATIONARY
/* You can use these constants to check what is the new motion state
of the event like so: */
if GetNewMotionState() == MOTION_STATE_MOVING then
call KillUnit(GetMotionChangingUnit())
elseif GetNewMotionState() == MOTION_STATE_STATIONARY then
call RemoveUnit(GetMotionChangingUnit())
endif
|=========|
| Modules |
|=========|
module MotionChangeEvent/*
- You should implement this below your static methods named
onMotionStart and onMotionStop if you have any. Otherwise,
it will generate extra code behind the scenes which is not
so good.
- If static methods onMotionStart and/or onMotionStop is found
in your struct, this will automatically register them to run
on their corresponding motion change events (Note that you
will not be able to unregister the mentioned methods). */
//! endnovjass
/*=========================== Configuration ===========================*/
private module Configuration
/* Unit position check interval (Values greater than 0.03
causes a bit of inaccuracy in the given instantaneous
speed of a unit. As the value lowers, the accuracy
increases at the cost of performance.) */
static constant real PERIOD = 0.03
/* Set to true if you want the system to automatically
register units upon entering the map. Set to false if
you want to manually register units. */
static constant boolean AUTO_REGISTER_UNITS = true
endmodule
/*======================= End of Configuration ========================*/
/* Do not change anything below this line if you're not so sure on */
/* what you're doing. */
/*=====================================================================*/
private keyword Init
globals
constant integer MOTION_STATE_MOVING = 1
constant integer MOTION_STATE_STATIONARY = 2
group SENSOR_GROUP_MOVING = CreateGroup()
group SENSOR_GROUP_STATIONARY = CreateGroup()
endglobals
struct MotionSensor extends array
implement Configuration
readonly boolean sensored
readonly boolean moving
readonly real speed
readonly real direction
readonly real deltaX
readonly real deltaY
readonly real prevX
readonly real prevY
readonly static unit triggerUnit
readonly static integer newMotionState
readonly thistype prev
readonly thistype next
private static boolean isEnabled
private static timer staticTimer = CreateTimer()
private static trigger onMoveTrig = CreateTrigger()
private static trigger onStopTrig = CreateTrigger()
private static trigger onMotionTrig = CreateTrigger()
debug private static method debug takes string msg returns nothing
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 30, "|CFFFFCC00[Motion Sensor]|R " + msg)
debug endmethod
private static method onPeriodic takes nothing returns nothing
local unit u
local real dx
local real dy
local real unitX
local real unitY
local boolean prevState
local thistype node = thistype(0).next
loop
exitwhen node == 0
set u = GetUnitById(node)
set prevState = node.moving
set unitX = GetUnitX(u)
set unitY = GetUnitY(u)
set dx = unitX - node.prevX
set dy = unitY - node.prevY
set node.prevX = unitX
set node.prevY = unitY
set node.deltaX = dx
set node.deltaY = dy
set node.speed = SquareRoot(dx*dx + dy*dy)/PERIOD
set node.direction = bj_RADTODEG*Atan2(dy, dx)
set node.moving = node.speed > 0.00
if prevState != node.moving then
set triggerUnit = u
if node.moving then
call GroupRemoveUnit(SENSOR_GROUP_STATIONARY, u)
call GroupAddUnit(SENSOR_GROUP_MOVING, u)
set newMotionState = MOTION_STATE_MOVING
call TriggerEvaluate(onMoveTrig)
else
call GroupRemoveUnit(SENSOR_GROUP_MOVING, u)
call GroupAddUnit(SENSOR_GROUP_STATIONARY, u)
set newMotionState = MOTION_STATE_STATIONARY
call TriggerEvaluate(onStopTrig)
endif
set newMotionState = 0
endif
set u = null
set node = node.next
endloop
endmethod
static method operator enabled takes nothing returns boolean
return isEnabled
endmethod
static method operator enabled= takes boolean flag returns nothing
set isEnabled = flag
if flag then
if thistype(0).next != 0 then
call TimerStart(staticTimer, PERIOD, true, function thistype.onPeriodic)
endif
else
call PauseTimer(staticTimer)
endif
endmethod
static method operator [] takes unit u returns thistype
debug if not thistype(GetUnitId(u)).sensored then
debug call debug("|CFFFF0000Operator [] error: Attempt to use an unregistered instance|R")
debug return 0
debug endif
return GetUnitId(u)
endmethod
static method operator []= takes unit u, boolean flag returns nothing
local thistype node
if u != null then
set node = GetUnitId(u)
if flag then
debug if node.sensored then
debug call debug("|CFFFF0000Operator []= error: Attempt to register an already registered instance|R")
debug return
debug endif
/* Enable the Sensor iterator again when this is the first instance to be added on the list */
if enabled and thistype(0).next == 0 then
call TimerStart(staticTimer, PERIOD, true, function thistype.onPeriodic)
endif
set node.prev = thistype(0).prev
set node.next = 0
set thistype(0).prev = node
set node.prev.next = node
call GroupAddUnit(SENSOR_GROUP_STATIONARY, u)
/* Initialize prevX and prevY for the newly registered unit to
prevent it from causing a motion change event false positive */
set node.prevX = GetUnitX(u)
set node.prevY = GetUnitY(u)
else
debug if not node.sensored then
debug call debug("|CFFFF0000Operator []= error: Attempt to unregister an already unregistered instance|R")
debug return
debug endif
if IsUnitInGroup(u, SENSOR_GROUP_MOVING) then
call GroupRemoveUnit(SENSOR_GROUP_MOVING, u)
else
call GroupRemoveUnit(SENSOR_GROUP_STATIONARY, u)
endif
set node.moving = false
set node.deltaX = 0.00
set node.deltaY = 0.00
set node.prevX = 0.00
set node.prevY = 0.00
set node.speed = 0.00
set node.direction = 0.00
set node.next.prev = node.prev
set node.prev.next = node.next
set node.prev = 0
set node.next = 0
/* If the list is empty, stop iterating */
if enabled and thistype(0).next == 0 then
call PauseTimer(staticTimer)
endif
endif
set node.sensored = flag
debug else
debug call debug("|CFFFF0000Operator []= error: Attempt to register a null unit|R")
endif
endmethod
static method registerMotionStartEvent takes code c returns triggercondition
return TriggerAddCondition(onMoveTrig, Filter(c))
endmethod
static method unregisterMotionStartEvent takes triggercondition tc returns nothing
call TriggerRemoveCondition(onMoveTrig, tc)
endmethod
static method registerMotionStopEvent takes code c returns triggercondition
return TriggerAddCondition(onStopTrig, Filter(c))
endmethod
static method unregisterMotionStopEvent takes triggercondition tc returns nothing
call TriggerRemoveCondition(onStopTrig, tc)
endmethod
static method registerMotionChangeEvent takes code c returns triggercondition
return TriggerAddCondition(onMotionTrig, Filter(c))
endmethod
static method unregisterMotionChangeEvent takes triggercondition tc returns nothing
call TriggerRemoveCondition(onMotionTrig, tc)
endmethod
static if thistype.AUTO_REGISTER_UNITS then
private static method onUnitIndex takes nothing returns nothing
set thistype[GetIndexedUnit()] = true
endmethod
endif
private static method onUnitDeindex takes nothing returns nothing
static if thistype.AUTO_REGISTER_UNITS then
set thistype[GetIndexedUnit()] = false
else
if thistype(GetUnitId(GetIndexedUnit())).sensored then
set thistype[GetIndexedUnit()] = false
endif
endif
endmethod
private static method onMotionChange takes nothing returns nothing
call TriggerEvaluate(onMotionTrig)
endmethod
private static method init takes nothing returns nothing
local code onUnitDeindex = function thistype.onUnitDeindex
local code onMotionChange = function thistype.onMotionChange
static if thistype.AUTO_REGISTER_UNITS then
local code onUnitIndex = function thistype.onUnitIndex
call OnUnitIndex(onUnitIndex)
endif
call OnUnitDeindex(onUnitDeindex)
call registerMotionStartEvent(onMotionChange)
call registerMotionStopEvent(onMotionChange)
/* Turn on Sensor */
set enabled = true
endmethod
implement Init
endstruct
private module Init
private static method onInit takes nothing returns nothing
call init()
endmethod
endmodule
module MotionChangeEvent
static if thistype.onMotionStart.exists and thistype.onMotionStop.exists then
private static method onInit takes nothing returns nothing
call RegisterMotionStartEvent(function thistype.onMotionStart)
call RegisterMotionStopEvent(function thistype.onMotionStop)
endmethod
elseif thistype.onMotionStart.exists then
private static method onInit takes nothing returns nothing
call RegisterMotionStartEvent(function thistype.onMotionStart)
endmethod
elseif thistype.onMotionStop.exists then
private static method onInit takes nothing returns nothing
call RegisterMotionStopEvent(function thistype.onMotionStop)
endmethod
endif
endmodule
/*=====================================================================*/
function RegisterMotionChangeEvent takes code c returns triggercondition
return MotionSensor.registerMotionChangeEvent(c)
return null
endfunction
function UnregisterMotionChangeEvent takes triggercondition tc returns nothing
call MotionSensor.unregisterMotionChangeEvent(tc)
endfunction
function RegisterMotionStartEvent takes code c returns triggercondition
return MotionSensor.registerMotionStartEvent(c)
return null
endfunction
function UnregisterMotionStartEvent takes triggercondition tc returns nothing
call MotionSensor.unregisterMotionStartEvent(tc)
endfunction
function RegisterMotionStopEvent takes code c returns triggercondition
return MotionSensor.registerMotionStopEvent(c)
return null
endfunction
function UnregisterMotionStopEvent takes triggercondition tc returns nothing
call MotionSensor.unregisterMotionStopEvent(tc)
endfunction
function SensorAddUnit takes unit u returns nothing
set MotionSensor[u] = true
endfunction
function SensorRemoveUnit takes unit u returns nothing
set MotionSensor[u] = false
endfunction
function GetMotionChangingUnit takes nothing returns unit
return MotionSensor.triggerUnit
endfunction
function GetNewMotionState takes nothing returns integer
return MotionSensor.newMotionState
endfunction
function GetInstantaneousSpeed takes unit u returns real
return MotionSensor[u].speed
endfunction
function GetUnitDeltaX takes unit u returns real
return MotionSensor[u].deltaX
endfunction
function GetUnitDeltaY takes unit u returns real
return MotionSensor[u].deltaY
endfunction
function GetUnitPreviousX takes unit u returns real
return MotionSensor[u].prevX
endfunction
function GetUnitPreviousY takes unit u returns real
return MotionSensor[u].prevY
endfunction
function GetMotionDirection takes unit u returns real
return MotionSensor[u].direction
endfunction
function IsUnitMoving takes unit u returns boolean
return MotionSensor[u].moving
endfunction
function IsUnitSensored takes unit u returns boolean
return MotionSensor(GetUnitId(u)).sensored
endfunction
function MotionSensorEnable takes nothing returns nothing
set MotionSensor.enabled = true
endfunction
function MotionSensorDisable takes nothing returns nothing
set MotionSensor.enabled = false
endfunction
function IsSensorEnabled takes nothing returns boolean
return MotionSensor.enabled
endfunction
//! runtextmacro optional MOTION_SENSOR_BC()
endlibrary
JASS:
library MotionSensorBC/* for versions 1.3b and below*/ requires MotionSensor
//! textmacro MOTION_SENSOR_BC
struct Sensor extends array
method operator flag takes nothing returns boolean
return MotionSensor(this).sensored
endmethod
method operator moving takes nothing returns boolean
return MotionSensor(this).moving
endmethod
method operator speed takes nothing returns real
return MotionSensor(this).speed
endmethod
method operator direction takes nothing returns real
return MotionSensor(this).direction
endmethod
method operator deltaX takes nothing returns real
return MotionSensor(this).deltaX
endmethod
method operator deltaY takes nothing returns real
return MotionSensor(this).deltaY
endmethod
method operator prevX takes nothing returns real
return MotionSensor(this).prevX
endmethod
method operator prevY takes nothing returns real
return MotionSensor(this).prevY
endmethod
static method operator triggerUnit takes nothing returns unit
return MotionSensor.triggerUnit
endmethod
static method operator newMotionState takes nothing returns real
return I2R(MotionSensor.newMotionState)
endmethod
static method operator [] takes unit u returns Sensor
return MotionSensor[u]
endmethod
static method operator []= takes unit u, boolean flag returns nothing
set MotionSensor[u] = flag
endmethod
static method operator enabled= takes boolean flag returns nothing
set MotionSensor.enabled = flag
endmethod
static method operator enabled takes nothing returns boolean
return MotionSensor.enabled
endmethod
static method addMotionChangeEvent takes code c returns triggercondition
return MotionSensor.registerMotionChangeEvent(c)
endmethod
static method addOnMoveEvent takes code c returns triggercondition
return MotionSensor.registerMotionStartEvent(c)
endmethod
static method addOnStopEvent takes code c returns triggercondition
return MotionSensor.registerMotionStopEvent(c)
endmethod
static method removeMotionChangeEvent takes triggercondition tc returns nothing
call MotionSensor.unregisterMotionChangeEvent(tc)
endmethod
static method removeOnMoveEvent takes triggercondition tc returns nothing
call MotionSensor.unregisterMotionStartEvent(tc)
endmethod
static method removeOnStopEvent takes triggercondition tc returns nothing
call MotionSensor.unregisterMotionStopEvent(tc)
endmethod
endstruct
function RemoveMotionChangeEvent takes triggercondition tc returns nothing
call UnregisterMotionChangeEvent(tc)
endfunction
function RegisterOnMoveEvent takes code c returns triggercondition
return RegisterMotionStartEvent(c)
endfunction
function RemoveOnMoveEvent takes triggercondition tc returns nothing
call UnregisterMotionStartEvent(tc)
endfunction
function RegisterOnStopEvent takes code c returns triggercondition
return RegisterMotionStopEvent(c)
endfunction
function RemoveOnStopEvent takes triggercondition tc returns nothing
call UnregisterMotionStopEvent(tc)
endfunction
//! endtextmacro
endlibrary
Rupture library
JASS:
library Rupture uses MotionSensor, UnitDex, TimerUtils
struct Rupture extends array
private timer timer
private boolean allocated
private effect sfx
private real interval
private real elapsed
private string periodicSfx
private string markAttachpoint
private string periodicAttachpoint
unit caster
unit target
real dpd
real duration
attacktype at
damagetype dt
weapontype wt
method destroy takes nothing returns nothing
call DestroyEffect(.sfx)
call ReleaseTimer(.timer)
set .allocated = false
set .sfx = null
set .timer = null
set .interval = 0
set .dpd = 0
set .elapsed = 0
set .duration = 0
set .at = null
set .dt = null
set .wt = null
set .periodicSfx = null
set .periodicAttachpoint = null
set .markAttachpoint = null
set .caster = null
set .target = null
endmethod
private static method periodic takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
local Sensor s = Sensor[.target]
set .elapsed = .elapsed + .interval
if IsUnitType(.target, UNIT_TYPE_DEAD) or (.duration != 0.00 and .elapsed > .duration) then
call .destroy()
elseif s.moving then
if .dpd > 0.00 then
call UnitDamageTarget(.caster, .target, s.speed*.dpd*.interval, true, false, .at, .dt, .wt)
elseif .dpd < 0.00 then
call SetWidgetLife(.target, GetWidgetLife(.target) - s.speed*.dpd*.interval)
call UnitDamageTarget(.caster, .target, 0.01, true, false, .at, .dt, .wt)
endif
call DestroyEffect(AddSpecialEffectTarget(.periodicSfx, .target, .periodicAttachpoint))
endif
endmethod
static method create takes real period, unit caster, unit target, real duration, real impactDamage, real damagePerDistance, string impactSfx, string markSfx, string periodicSfx, string impactAttachpoint, string markAttachpoint, string periodicAttachpoint, attacktype at, damagetype dt, weapontype wt returns thistype
local thistype this = GetUnitId(target)
if target != null and not .allocated then
if caster == null then
set caster = target
endif
set .allocated = true
set .at = at
set .dt = dt
set .wt = wt
set .interval = period
set .dpd = damagePerDistance
set .duration = duration
set .caster = caster
set .target = target
set .markAttachpoint = markSfx
set .periodicAttachpoint = periodicAttachpoint
set .periodicSfx = periodicSfx
set .sfx = AddSpecialEffectTarget(markSfx, target, markAttachpoint)
set .timer = NewTimerEx(this)
if impactDamage < 0.00 then
call SetWidgetLife(target, GetWidgetLife(target) - impactDamage)
call UnitDamageTarget(caster, target, 0.01, true, false, at, dt, wt)
else
call UnitDamageTarget(caster, target, impactDamage, true, false, at, dt, wt)
endif
call DestroyEffect(AddSpecialEffectTarget(impactSfx, target, impactAttachpoint))
call TimerStart(.timer, 0.05, true, function thistype.periodic)
endif
return this
endmethod
method operator effect= takes string model returns nothing
call DestroyEffect(.sfx)
set .sfx = AddSpecialEffectTarget(model, .target, .markAttachpoint)
endmethod
method changeMarkEffect takes string newModel, string newAttachpoint returns nothing
set .markAttachpoint = newAttachpoint
set .effect = newModel
endmethod
method changePeriodicEffect takes string newModel, string newAttachpoint returns nothing
set .periodicSfx = newModel
set .periodicAttachpoint = newAttachpoint
endmethod
method operator period= takes real newPeriod returns nothing
set .interval = newPeriod
call TimerStart(.timer, newPeriod, true, function thistype.periodic)
endmethod
endstruct
endlibrary
Rupture Moving Units
JASS:
library RuptureSpell requires MotionSensor, Rupture
globals
private constant real LOOP_INTERVAL = 0.05
private constant real DPD = 0.50
private constant real DURATION = 0.00 //Permanent
private constant real START_DAMAGE = 60.00
private constant attacktype AT = ATTACK_TYPE_HERO
private constant damagetype DT = DAMAGE_TYPE_NORMAL
private constant weapontype WT = null
private constant string SFX_MODEL_1 = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
private constant string SFX_MODEL_2 = "Abilities\\Spells\\Orc\\TrollBerserk\\HeadhunterWEAPONSLeft.mdl"
private constant string SFX_MODEL_3 = "Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl"
private constant string SFX_MODEL_4 = "Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl"
private constant string SFX_MODEL_5 = "Abilities\\Spells\\Other\\Drain\\DrainTarget.mdl"
private constant string SFX_MODEL_6 = null
private constant string ATTACH_POINT_1 = "overhead"
private constant string ATTACH_POINT_2 = "origin"
private constant string ATTACH_POINT_3 = "chest"
private constant string ATTACH_POINT_4 = "origin"
private constant string ATTACH_POINT_5 = "origin"
private constant string ATTACH_POINT_6 = null
endglobals
//===================================================================================================
private struct Spell extends array
private static trigger trig1 = CreateTrigger()
private static trigger trig2 = CreateTrigger()
private static method onMotionStart takes nothing returns nothing
if GetWidgetLife(Sensor.triggerUnit) < START_DAMAGE + 1.00 then
call Rupture.create(LOOP_INTERVAL, Sensor.triggerUnit, Sensor.triggerUnit, DURATION, -START_DAMAGE, -DPD, SFX_MODEL_4, SFX_MODEL_5, SFX_MODEL_6, ATTACH_POINT_4, ATTACH_POINT_5, ATTACH_POINT_6, AT, DT, WT)
else
call Rupture.create(LOOP_INTERVAL, Sensor.triggerUnit, Sensor.triggerUnit, DURATION, START_DAMAGE, DPD, SFX_MODEL_1, SFX_MODEL_2, SFX_MODEL_3, ATTACH_POINT_1, ATTACH_POINT_2, ATTACH_POINT_3, AT, DT, WT)
endif
endmethod
private static method onMotionStop takes nothing returns nothing
call Rupture(GetUnitId(Sensor.triggerUnit)).destroy()
endmethod
private static method shiftEffect1 takes nothing returns nothing
local Rupture this
local unit u = GetTriggerUnit()
if Sensor[u].moving then
set this = Rupture(GetUnitId(u))
set this.dpd = -this.dpd
call this.changeMarkEffect(SFX_MODEL_5, ATTACH_POINT_5)
call this.changePeriodicEffect(SFX_MODEL_6, ATTACH_POINT_6)
endif
set u = null
endmethod
private static method shiftEffect2 takes nothing returns nothing
local Rupture this
local unit u = GetTriggerUnit()
if Sensor[u].moving then
set this = Rupture(GetUnitId(u))
set this.dpd = -this.dpd
call this.changeMarkEffect(SFX_MODEL_2, ATTACH_POINT_2)
call this.changePeriodicEffect(SFX_MODEL_3, ATTACH_POINT_3)
endif
set u = null
endmethod
private static method registerUnit takes nothing returns nothing
local unit u = GetIndexedUnit()
call TriggerRegisterUnitStateEvent(trig1, u, UNIT_STATE_LIFE, LESS_THAN, 20.00)
call TriggerRegisterUnitStateEvent(trig2, u, UNIT_STATE_LIFE, GREATER_THAN, GetUnitState(u, UNIT_STATE_MAX_LIFE) - 10.00)
set u = null
endmethod
private static method onInit takes nothing returns nothing
local code register = function thistype.registerUnit
local code shiftEffect1 = function thistype.shiftEffect1
local code shiftEffect2 = function thistype.shiftEffect2
call OnUnitIndex(register)
call TriggerAddCondition(trig1, Filter(shiftEffect1))
call TriggerAddCondition(trig2, Filter(shiftEffect2))
endmethod
implement MotionChangeEvent
endstruct
endlibrary
v1.4.0
- Major API changes (Also added a backwards compatibility lib)
- Made the configuration constant public
- Added a readonly linked-list for unit indexes registered in the system
- Changes in the GUI Plugin
- Other changes
v1.3c
- Not uploaded
v1.3b
- Added a new public module for running motion events within a struct
- Added two new groups SENSOR_GROUP_MOVING and SENSOR_GROUP_STATIONARY to allow users to easily loop through desired units
- The motion change event now uses TriggerEvaluate() instead of TRVE for a faster execution
- Changed prevX and prevY's privacy from being private to readonly
- Added function wrappers for getting the prevX and prevY of a unit
- Added a debug message in the operator []= to warm users when they try to double-free or double-register a unit
- When enabling the Sensor, it checks first if the sensorGroup is empty before running the periodic actions
- Updated the Rupture Spell code and the demo map
- Updated the documentation
- Other changes
v1.3
- Not uploaded
v1.2c
- Renamed some global constants
- Updated the demo map
v1.2b
- Made some proper functions/methods arrangements
- Removed the method operators < and ==
- Removed some unnecessary debug messages
- Fixed some compile errors on the demo script
- Other changes
v1.2
- The system now uses struct APIs but function wrappers are still available for users who are not so accustomed to using structs
- Now provides a boolean struct member for checking if a unit is registered to the system or not
- Some naming changes
- Optimized some parts of the script
- Some fixes and other changes
v1.1b
- Added a new API function IsSensorEnabled() for checking if the MotionSensor is enabled or disabled
- Some changes on the Demo Map
- Functions for registering codes now do not inline for the reason that it will throw an error when the code passed returns nothing in case it inlines
- Fixed the problem regarding Pause/Unpause timer
- The periodic function now only runs when there is a unit registered
- Other changes
v1.1
- API functions for getting a unit's motion stats are now inlined to array lookups
- Added more functionality to the system
- Now allows you to remove a triggercondition from a motion event
- Users can now choose if they want to automatically add all units to the system or if they want to add units manually
- Now uses arrays instead of hashtable
- Added UnitDex as a requirement, TimerUtils and GroupUtils as optional requirements
- The system no longer enumerates units in the map every period but stores them to a global group
- All public functions now inline when DEBUG_MODE is OFF
- Added a demo map
- Other changes
v1.0
- First Release
Attachments
Last edited: