library SlidingSystem/* v3.4 By IcemanBo
*/ requires /*
*/ UnitIndexer /* The one in test map. (by Nestharus v4.0.2.6)
*/ TimerUtils /* http://www.wc3c.net/showthread.php?t=101322
*/ Table /* http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*/ WorldBounds /* https://github.com/nestharus/JASS/blob/master/jass/Systems/WorldBounds/script.j
*/ Event /* The one in test map.
** Info
** ¯¯¯¯¯¯¯¯
**
** Sliders can have a special sliding behaviour on different terrain types.
** Each slider also can have it's own movement speed while sliding,
** seperated and indepentand from the terrain type.
**
** This library provides various possibilities
** to create an individual behaviour for each terrain type. (Config - Part)
**
**
** Struct Terrain:
**
**
** static method create takes integer terainType, real terrainSpeed returns thistype
**
** Furthermore you can define and read these public members:
** (by default all values are "0" or "false".
**
** pullSpeed = Unit will be constantly pulled with this speed. (real)
** pullDirection = Direction for pulling, in degrees. (real)
** angle = Angle that will be added, when steering. (real)
** lifeAddition = Life that will be added each second. Negagtive values are also possible. (real)
** allowSteer = If unit can steer on the tarrainType or not. (boolean)
** allowCast = If unit can cast on the terrainType or not. (boolean)
** kill = Kill the unit on the terrainType or not. (boolean)
**
**
** You can have a look into folder TestMap -> "Terrain Settings" for a better understanding and examples.
**
**
** Struct Slider:
**
**
** static methods:
** ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
**
** static method create takes unit u returns thistype
**
** static method getSliderId takes unit u returns thistype
**
** static method isUnitSlider takes unit u returns boolean
**
**
**
** methods:
** ¯¯¯¯¯¯¯¯¯¯
**
** method destroy takes nothing returns nothing
**
** method enable takes boolean b returns nothing (disabled instance can't slide)
**
** method isEnabled takes nothing returns boolean
**
** method getDefaultSpeed takes nothing returns real
**
** method getTempSpeed takes nothing returns real
**
** method setDefaultSpeed takes real s returns nothing
**
** method addDefaultSpeed takes real s returns nothing
**
** method addTempSpeed takes real speed, real duration returns nothing
**
**
**
** Deindexed units will be automatically removed from system.
** You can have a look into folder TestMap -> "Create Slider" for a better understanding and examples.
**
***************************************************************************
**
** Credits to guys named in brackets.
**
** Requires:
** - Table (Bribe)
** - TimerUtils (Vexorian)
** - UnitIndexer (Nestharus)
** • WorldBounds (Nestharus)
** • Event (Nestharus)
**
**
**************************************************************************
*
*
************************ Configuration - Start ***************************/
globals
private constant boolean SLIDER_UNCLICKABLE = true // Make Slider unclickable.
private constant boolean SLIDER_NO_PATHING = true // Disable pathing for Slider.
private constant boolean CHECK_PATHING = false // Check for pathability while sliding.
/************************ Configuration - End *****************************/
private constant real INTERVAL = .03 // Sliding looks smoother smoother with .03 instead of 0.312500.
private constant real TPS = 1/INTERVAL // Operation threads per second
private trigger steerTrigger = CreateTrigger()
private trigger moveTrigger = CreateTrigger() // Sliding looks smoother with trigger instead of a timer.
private constant integer SMART = 851971
private constant integer STOP = 851972
private constant integer PATROL = 851990
private constant integer MOVE = 851986
endglobals
/*
* Terrain struct, to define sliding behaviour.
*/
struct Terrain
private static key k
private static Table table = k
private integer terrainType
real speed
real pullSpeed = 0
real pullDirection = 0
real angle = 0
real lifeAddition = 0
boolean allowSteer = false
boolean allowCast = false
boolean kill = false
static method create takes integer whichTerrain, real whichSpeed returns thistype
local thistype this = thistype.allocate()
set thistype.table[whichTerrain] = this
set this.terrainType = whichTerrain
set this.speed = whichSpeed/TPS
return this
endmethod
static method operator [] takes integer i returns thistype
return thistype.table[i]
endmethod
endstruct
/*
* Acceleration struct, to manipulate Slider's temporary speed
*/
private struct Acceleration
public timer tim
public real speedChange
public Slider instance
static method create takes Slider slider, real speed returns thistype
local thistype this = thistype.allocate()
set this.instance = slider
set this.speedChange = speed
return this
endmethod
method destroy takes nothing returns nothing
call this.deallocate()
call ReleaseTimer(tim)
endmethod
endstruct
/*
* Slider struct (main code)
*/
struct Slider
private static thistype array list
private static boolean array is // Is unit a slider
private unit slider
public real defaultSpeed // Permanent speed
public real bonusSpeed // Temporary speed
private real propWindow
private real turnSpeed
private boolean enabled // If slider is currently enabled.
private thistype prev
private thistype next
static thistype first = 0
static method create takes unit u returns thistype
local thistype this
local integer index = GetUnitUserData(u)
if (isUnitSlider(u)) then
debug call BJDebugMsg("Error - Sliding System - create: " + GetUnitName(u) + ", Index[" + I2S(index) + "] is already a Slider." )
return 0
endif
set this = thistype.allocate()
set this.slider = u
set thistype.list[index] = this
set this.is[index] = true
set this.enabled = true
set this.propWindow = GetUnitDefaultPropWindow(slider)*bj_RADTODEG
set this.turnSpeed = GetUnitDefaultTurnSpeed(slider)
static if (SLIDER_UNCLICKABLE) then
call UnitAddAbility(u,'Aloc')
call ShowUnit(u,false)
call ShowUnit(u,true)
call UnitRemoveAbility(u,'Aloc')
endif
static if (SLIDE_NO_PATHING) then
call SetUnitPathing( u, false )
endif
if (thistype.first == 0) then
call EnableTrigger(moveTrigger)
endif
set this.next = thistype.first
set thistype.first.prev = this
set thistype.first = this
set this.prev = 0
return this
endmethod
method destroy takes nothing returns nothing
local integer index = GetUnitUserData(slider)
call this.deallocate()
set thistype.list[index] = 0
set this.is[index] = false
set this.slider = null
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 DisableTrigger(moveTrigger)
endif
endmethod
/*
* Sliding - Movement (periodic call)
*/
private static method onMove takes nothing returns nothing
local real angle
local real offset
local real x
local real y
local integer terrainType
local thistype this = thistype.first
loop
exitwhen this == 0
if enabled then
set x = GetUnitX(slider)
set y = GetUnitY(slider)
set terrainType = GetTerrainType(x, y)
// Check if slider is on a registered terrain type.
if (Terrain[terrainType] != 0) then
if (Terrain[terrainType].kill) then
call KillUnit(slider)
else
set angle = (GetUnitFacing(slider)*bj_DEGTORAD)
set offset = defaultSpeed + bonusSpeed + Terrain[terrainType].speed
// Heal/damage the slider.
call SetWidgetLife(slider,GetWidgetLife(slider) + Terrain[terrainType].lifeAddition/TPS)
set x = x + offset * Cos(angle)
set y = y + offset * Sin(angle)
// Sliding
static if (CHECK_PATHING) then
call SetUnitPosition(slider, x, y)
else
call SetUnitX(slider, x)
call SetUnitY(slider, y)
endif
// Check if terrain type is pulling.
if (Terrain[terrainType].pullSpeed != 0) then
static if (CHECK_PATHING) then
call SetUnitPosition(slider, x + (Terrain[terrainType].pullSpeed/TPS) * Cos(Terrain[terrainType].pullDirection*bj_DEGTORAD), y + (Terrain[terrainType].pullSpeed/TPS) * Sin(Terrain[terrainType].pullDirection*bj_DEGTORAD))
else
call SetUnitX(slider, x + (Terrain[terrainType].pullSpeed/TPS) * Cos(Terrain[terrainType].pullDirection*bj_DEGTORAD))
call SetUnitY(slider, y + (Terrain[terrainType].pullSpeed/TPS) * Sin(Terrain[terrainType].pullDirection*bj_DEGTORAD))
endif
endif
// Make slider unmoveable while sliding.
call SetUnitPropWindow(slider, 0)
call SetUnitTurnSpeed(slider, 0.00)
endif
else
// Make slider moveable.
call SetUnitPropWindow(slider, propWindow )
call SetUnitTurnSpeed(slider, turnSpeed)
endif
endif
set this = next
endloop
endmethod
/*
* Sliding - Steering
*/
private static method onTurn takes nothing returns boolean
local unit u = GetTriggerUnit()
local real x
local real y
local integer terrainType
local integer order = GetIssuedOrderId()
local boolean b = true
if (isUnitSlider(u) and list[GetUnitUserData(u)].enabled) then
set x = GetUnitX(u)
set y = GetUnitY(u)
set terrainType = GetTerrainType(x, y)
// Check if slider is on a registered terrain type.
if (Terrain[terrainType] != 0) then
if( (order == SMART) and (Terrain[terrainType].allowSteer)) then
// Let the slider turn.
call SetUnitFacing( u, (Atan2(GetOrderPointY() - y , GetOrderPointX() - x) * bj_RADTODEG) + Terrain[terrainType].angle)
elseif ((order != SMART) and (order != MOVE) and (order != PATROL) and (Terrain[terrainType].allowCast)) then
// The slider is casting an ability. Let him face wanted position, if allowed.
call SetUnitFacing( u, Atan2(GetOrderPointY() - y , GetOrderPointX() - x) * bj_RADTODEG)
set b = false
endif
if ((order == SMART) or (order == MOVE) or (order == PATROL) or (b)) then
call DisableTrigger( steerTrigger )
call PauseUnit (u,true)
call IssueImmediateOrderById(u, STOP) // That will abbort unit's order if unit is not casting.
call PauseUnit (u,false)
call EnableTrigger( steerTrigger )
endif
endif
endif
set u = null
return false
endmethod
// API - Start
static method getSliderId takes unit u returns thistype
return list[GetUnitUserData(u)]
endmethod
static method isUnitSlider takes unit u returns boolean
return is[GetUnitUserData(u)]
endmethod
method enable takes boolean b returns nothing
set enabled = b
endmethod
method isEnabled takes nothing returns boolean
return enabled
endmethod
method getDefaultSpeed takes nothing returns real
return defaultSpeed*TPS
endmethod
method getTempSpeed takes nothing returns real
return bonusSpeed*TPS
endmethod
/* Permanent Boost */
method setDefaultSpeed takes real s returns nothing
set defaultSpeed = s/TPS
endmethod
method addDefaultSpeed takes real s returns nothing
set defaultSpeed = defaultSpeed + s/TPS
endmethod
/* Temporary Boost */
private static method callback takes nothing returns nothing
local Acceleration this = GetTimerData(GetExpiredTimer())
set this.instance.bonusSpeed = this.instance.bonusSpeed - this.speedChange
call this.destroy()
endmethod
method addTempSpeed takes real speed, real duration returns nothing
local integer handleId
local Acceleration newData
if duration > 0 then
set speed = speed/TPS
set bonusSpeed = bonusSpeed + speed
set newData = Acceleration.create(this, speed)
set newData.tim = NewTimerEx(newData)
call TimerStart(newData.tim, duration, false, function thistype.callback)
else
debug call BJDebugMsg("Error - Sliding System - AddTempSpeed: Duration must be greater 0.")
endif
endmethod
// API - End
private static method onDeindex takes nothing returns boolean
if (thistype.isUnitSlider(GetIndexedUnit())) then
call thistype.getSliderId(GetIndexedUnit()).destroy()
endif
return false
endmethod
private static method onInit takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ( steerTrigger, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerAddCondition(steerTrigger, Condition(function thistype.onTurn))
call TriggerRegisterTimerEvent(moveTrigger, INTERVAL, true)
call TriggerAddAction(moveTrigger, function thistype.onMove)
call DisableTrigger(moveTrigger)
call RegisterUnitIndexEvent(Condition(function thistype.onDeindex), UnitIndexer.DEINDEX)
endmethod
endstruct
endlibrary