Name | Type | is_array | initial_value |
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Event
//2.0.0.1
/////////////////////////////////////////////////////////////////////////
//function CreateEvent takes nothing returns integer
//function TriggerRegisterEvent takes trigger t, integer ev returns nothing
//function RegisterEvent takes boolexpr c, integer ev returns nothing
//function FireEvent takes integer ev returns nothing
//struct Event extends array
//static method create takes nothing returns thistype
//method registerTrigger takes trigger t returns nothing
//method register takes boolexpr c returns nothing
//method fire takes nothing returns nothing
/////////////////////////////////////////////////////////////////////////
globals
private real q=0
endglobals
struct Event extends array
private static integer w=0
private static trigger array e
static method create takes nothing returns thistype
set w=w+1
set e[w]=CreateTrigger()
return w
endmethod
method registerTrigger takes trigger t returns nothing
call TriggerRegisterVariableEvent(t,SCOPE_PRIVATE+"q",EQUAL,this)
endmethod
method register takes boolexpr c returns nothing
call TriggerAddCondition(e[this],c)
endmethod
method fire takes nothing returns nothing
set q=0
set q=this
call TriggerEvaluate(e[this])
endmethod
endstruct
function CreateEvent takes nothing returns Event
return Event.create()
endfunction
function TriggerRegisterEvent takes trigger t,Event ev returns nothing
call ev.registerTrigger(t)
endfunction
function RegisterEvent takes boolexpr c,Event ev returns nothing
call ev.register(c)
endfunction
function FireEvent takes Event ev returns nothing
call ev.fire()
endfunction
endlibrary
//TESH.scrollpos=42
//TESH.alwaysfold=0
library TimerUtilsEx requires optional Table
/*************************************************
*
* TimerUtilsEx
* v2.1.0.2
* By Vexorian, Bribe & Magtheridon96
*
* Original version by Vexorian.
*
* Flavors:
* Hashtable:
* - RAM: Minimal
* - TimerData: Slow
*
* Array:
* - RAM: Maximal
* - TimerData: Fast
*
* All the functions have O(1) complexity.
* The Array version is the fastest, but the hashtable
* version is the safest. The Array version is still
* quite safe though, and I would recommend using it.
* The system is much slower in debug mode.
*
* Optional Requirement:
* - Table by Bribe
* - hiveworkshop.com/forums/showthread.php?t=188084
*
* API:
* ----
* - function NewTimer takes nothing returns timer
* - Returns a new timer from the stack.
* - function NewTimerEx takes integer i returns timer
* - Returns a new timer from the stack and attaches a value to it.
* - function ReleaseTimer takes timer t returns integer
* - Throws a timer back into the stack. Also returns timer data.
* - function SetTimerData takes timer t, integer value returns nothing
* - Attaches a value to a timer.
* - function GetTimerData takes timer t returns integer
* - Returns the attached value.
*
*************************************************/
// Configuration
globals
// Use hashtable, or fast array?
private constant boolean USE_HASH = true
// Max Number of Timers Held in Stack
private constant integer QUANTITY = 512
endglobals
globals
private timer array tT
private integer tN = 0
endglobals
private module Init
private static method onInit takes nothing returns nothing
static if not USE_HASH then
local integer i = QUANTITY
loop
set i = i - 1
set tT[i] = CreateTimer()
exitwhen i == 0
endloop
set tN = QUANTITY
elseif LIBRARY_Table then
set tb = Table.create()
endif
endmethod
endmodule
// JassHelper doesn't support static ifs for globals.
private struct Data extends array
static if not USE_HASH then
static integer array data
endif
static if LIBRARY_Table then
static Table tb = 0
else
static hashtable ht = InitHashtable()
endif
implement Init
endstruct
// Double free protection
private function ValidTimer takes integer i returns boolean
static if LIBRARY_Table then
return Data.tb.boolean[-i]
else
return LoadBoolean(Data.ht, i, 1)
endif
endfunction
private function Get takes integer id returns integer
debug if not ValidTimer(id) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to get data from invalid timer.")
debug endif
static if USE_HASH then
static if LIBRARY_Table then
return Data.tb[id]
else
return LoadInteger(Data.ht, id, 0)
endif
else
return Data.data[id - 0x100000]
endif
endfunction
private function Set takes integer id, integer data returns nothing
debug if not ValidTimer(id) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to attach data to invalid timer.")
debug endif
static if USE_HASH then
static if LIBRARY_Table then
set Data.tb[id] = data
else
call SaveInteger(Data.ht, id, 0, data)
endif
else
set Data.data[id - 0x100000] = data
endif
endfunction
function SetTimerData takes timer t, integer data returns nothing
call Set(GetHandleId(t), data)
endfunction
function GetTimerData takes timer t returns integer
return Get(GetHandleId(t))
endfunction
function NewTimerEx takes integer data returns timer
local integer id
if tN == 0 then
static if USE_HASH then
set tT[0] = CreateTimer()
else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: No Timers In The Stack! You must increase 'QUANTITY'")
return null
endif
else
set tN = tN - 1
endif
set id = GetHandleId(tT[tN])
static if LIBRARY_Table then
set Data.tb.boolean[-id] = true
else
call SaveBoolean(Data.ht, id, 1, true)
endif
call Set(id, data)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
function ReleaseTimer takes timer t returns integer
local integer id = GetHandleId(t)
local integer data = 0
// Pause the timer just in case.
call PauseTimer(t)
// Make sure the timer is valid.
if ValidTimer(id) then
// Get the timer's data.
set data = Get(id)
// Unmark handle id as a valid timer.
static if LIBRARY_Table then
call Data.tb.boolean.remove(-id)
else
call RemoveSavedBoolean(Data.ht, id, 1)
endif
//If it's not run in USE_HASH mode, this next block is useless.
static if USE_HASH then
//At least clear hash memory while it's in the recycle stack.
static if LIBRARY_Table then
call Data.tb.remove(id)
else
call RemoveSavedInteger(Data.ht, id, 0)
endif
// If the recycle limit is reached
if tN == QUANTITY then
// then we destroy the timer.
call DestroyTimer(t)
return data
endif
endif
//Recycle the timer.
set tT[tN] = t
set tN = tN + 1
//Tried to pass a bad timer.
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to release non-active timer!")
endif
//Return Timer Data.
return data
endfunction
endlibrary
library TimerUtils requires TimerUtilsEx
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitIndexer /* v4.0.2.8
*************************************************************************************
*
* Assigns unique indexes to units via unit user data.
*
*************************************************************************************
*
* */uses/*
*
* */ WorldBounds /* hiveworkshop.com/forums/jass-functions-413/snippet-worldbounds-180494/
* */ Event /* hiveworkshop.com/forums/submissions-414/snippet-event-186555/
*
************************************************************************************
*
* Functions
*
* function RegisterUnitIndexEvent takes boolexpr codeToRegister, Event unitIndexEvent returns nothing
* function TriggerRegisterUnitIndexEvent takes trigger triggerToRegister, Event unitIndexEvent returns nothing
*
* function GetUnitById takes integer index returns unit
* - Returns unit given a unit index
* function GetUnitId takes unit u returns integer
* - Returns unit index given a unit
*
* function IsUnitIndexed takes unit u returns boolean
* function IsUnitDeindexing takes unit u returns boolean
*
* function GetIndexedUnitId takes nothing returns integer
* function GetIndexedUnit takes nothing returns unit
*
************************************************************************************
*
* module UnitIndexStructMethods
* static method operator [] takes unit u returns thistype
* - Return GetUnitUserData(u)
*
* readonly unit unit
* - The indexed unit of the struct
*
************************************************************************************
*
* module UnitIndexStruct extends UnitIndexStructMethods
*
* - A pseudo module interface that runs a set of methods if they exist and provides
* - a few fields and operators. Runs on static ifs to minimize code.
*
* readonly boolean allocated
* - Is unit allocated for the struct
*
* Interface:
*
* - These methods don't have to exist. If they don't exist, the code
* - that calls them won't even be in the module.
*
* private method index takes nothing returns nothing
* - called when a unit is indexed and passes the filter.
* -
* - thistype this: Unit's index
* private method deindex takes nothing returns nothing
* - called when a unit is deindexed and is allocated for struct
* -
* - thistype this: Unit's index
* private static method filter takes unit unitToIndex returns boolean
* - Determines whether or not to allocate struct for unit
* -
* - unit unitToIndex: Unit being filtered
*
************************************************************************************
*
* struct UnitIndexer extends array
*
* - Controls the unit indexer system.
*
* static constant Event UnitIndexer.INDEX
* static constant Event UnitIndexer.DEINDEX
* - Don't register functions and triggers directly to the events. Register them via
* - RegisterUnitIndexEvent and TriggerRegisterUnitIndexEvent.
*
* static boolean enabled
* - Enables and disables unit indexing. Useful for filtering out dummy units.
*
************************************************************************************
*
* struct UnitIndex extends UnitIndexStructMethods
*
* - Constrols specific unit indexes.
*
* method lock takes nothing returns nothing
* - Locks an index. When an index is locked, it will not be recycled
* - when the unit is deindexed until all locks are removed. Deindex
* - events still fire at the appropriate times, the index just doesn't
* - get thrown into the recycler.
* method unlock takes nothing returns nothing
* - Unlocks an index.
*
************************************************************************************/
globals
private constant integer ABILITIES_UNIT_INDEXER = 'A000'
private trigger q=CreateTrigger()
private trigger l=CreateTrigger()
private unit array e
private integer r=0
private integer y=0
private integer o=0
private boolean a=false
private integer array n
private integer array p
private integer array lc
endglobals
function GetIndexedUnitId takes nothing returns integer
return o
endfunction
function GetIndexedUnit takes nothing returns unit
return e[o]
endfunction
//! runtextmacro optional UNIT_LIST_LIB()
private struct PreLoader extends array
public static method run takes nothing returns nothing
call DestroyTimer(GetExpiredTimer())
set a=true
endmethod
public static method eval takes trigger t returns nothing
local integer f=n[0]
local integer d=o
loop
exitwhen 0==f
if (IsTriggerEnabled(t)) then
set o=f
if (TriggerEvaluate(t)) then
call TriggerExecute(t)
endif
else
exitwhen true
endif
set f=n[f]
endloop
set o=d
endmethod
public static method evalb takes boolexpr c returns nothing
local trigger t=CreateTrigger()
local thistype f=n[0]
local integer d=o
call TriggerAddCondition(t,c)
loop
exitwhen 0==f
set o=f
call TriggerEvaluate(t)
set f=n[f]
endloop
call DestroyTrigger(t)
set t=null
set o=d
endmethod
endstruct
//! runtextmacro optional UNIT_EVENT_MACRO()
private module UnitIndexerInit
private static method onInit takes nothing returns nothing
local integer i=15
local boolexpr bc=Condition(function thistype.onLeave)
local boolexpr bc2=Condition(function thistype.onEnter)
local group g=CreateGroup()
local player p
set INDEX=CreateEvent()
set DEINDEX=CreateEvent()
call TriggerRegisterEnterRegion(q,WorldBounds.worldRegion,bc2)
loop
set p=Player(i)
call TriggerRegisterPlayerUnitEvent(l,p,EVENT_PLAYER_UNIT_ISSUED_ORDER,bc)
call SetPlayerAbilityAvailable(p,ABILITIES_UNIT_INDEXER,false)
call GroupEnumUnitsOfPlayer(g,p,bc2)
exitwhen 0==i
set i=i-1
endloop
call DestroyGroup(g)
set bc=null
set g=null
set bc2=null
set p=null
call TimerStart(CreateTimer(),0,false,function PreLoader.run)
endmethod
endmodule
struct UnitIndex extends array
method lock takes nothing returns nothing
debug if (null!=e[this]) then
set lc[this]=lc[this]+1
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"UNIT INDEXER ERROR: ATTEMPT TO LOCK NULL INDEX")
debug endif
endmethod
method unlock takes nothing returns nothing
debug if (0<lc[this]) then
set lc[this]=lc[this]-1
if (0==lc[this] and null==e[this]) then
set n[this]=y
set y=this
endif
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"UNIT INDEXER ERROR: ATTEMPT TO UNLOCK UNLOCKED INDEX")
debug endif
endmethod
method operator unit takes nothing returns unit
return e[this]
endmethod
static method operator [] takes unit whichUnit returns thistype
return GetUnitUserData(whichUnit)
endmethod
endstruct
struct UnitIndexer extends array
readonly static Event INDEX
readonly static Event DEINDEX
static method operator enabled takes nothing returns boolean
return IsTriggerEnabled(q)
endmethod
static method operator enabled= takes boolean b returns nothing
if (b) then
call DisableTrigger(q)
call DisableTrigger(l)
else
call EnableTrigger(q)
call EnableTrigger(l)
endif
endmethod
private static method onEnter takes nothing returns boolean
local unit Q=GetFilterUnit()
local integer i
local integer d=o
if (Q!=e[GetUnitUserData(Q)] and 0==GetUnitUserData(Q)) then
if (0==y) then
set r=r+1
set i=r
else
set i=y
set y=n[y]
endif
call UnitAddAbility(Q,ABILITIES_UNIT_INDEXER)
call UnitMakeAbilityPermanent(Q,true,ABILITIES_UNIT_INDEXER)
call SetUnitUserData(Q,i)
set e[i]=Q
static if not LIBRARY_UnitList then
if (not a)then
set p[i]=p[0]
set n[p[0]]=i
set n[i]=0
set p[0]=i
endif
else
set p[i]=p[0]
set n[p[0]]=i
set n[i]=0
set p[0]=i
call GroupAddUnit(g,e[i])
endif
set o=i
call FireEvent(INDEX)
set o=d
endif
set Q=null
return false
endmethod
private static method onLeave takes nothing returns boolean
static if LIBRARY_UnitEvent then
implement optional UnitEventModule
else
local unit u=GetFilterUnit()
local integer i=GetUnitUserData(u)
local integer d=o
if (0==GetUnitAbilityLevel(u,ABILITIES_UNIT_INDEXER) and u==e[i]) then
static if not LIBRARY_UnitList then
if (not a)then
set n[p[i]]=n[i]
set p[n[i]]=p[i]
endif
else
set n[p[i]]=n[i]
set p[n[i]]=p[i]
call GroupRemoveUnit(g,e[i])
endif
set o=i
call FireEvent(DEINDEX)
set o=d
if (0==lc[i]) then
set n[i]=y
set y=i
endif
set e[i]=null
endif
set u=null
endif
return false
endmethod
implement UnitIndexerInit
endstruct
//! runtextmacro optional UNIT_EVENT_MACRO_2()
function RegisterUnitIndexEvent takes boolexpr c,integer ev returns nothing
call RegisterEvent(c, ev)
if (not a and ev==UnitIndexer.INDEX and 0!=n[0]) then
call PreLoader.evalb(c)
endif
endfunction
function TriggerRegisterUnitIndexEvent takes trigger t,integer ev returns nothing
call TriggerRegisterEvent(t,ev)
if (not a and ev == UnitIndexer.INDEX and 0!=n[0]) then
call PreLoader.eval(t)
endif
endfunction
function GetUnitById takes integer W returns unit
return e[W]
endfunction
function GetUnitId takes unit u returns integer
return GetUnitUserData(u)
endfunction
function IsUnitIndexed takes unit u returns boolean
return u==e[GetUnitUserData(u)]
endfunction
function IsUnitDeindexing takes unit u returns boolean
return IsUnitIndexed(u) and 0==GetUnitAbilityLevel(u,ABILITIES_UNIT_INDEXER)
endfunction
module UnitIndexStructMethods
static method operator [] takes unit u returns thistype
return GetUnitUserData(u)
endmethod
method operator unit takes nothing returns unit
return e[this]
endmethod
endmodule
module UnitIndexStruct
implement UnitIndexStructMethods
static if thistype.filter.exists then
static if thistype.index.exists then
static if thistype.deindex.exists then
readonly boolean allocated
else
method operator allocated takes nothing returns boolean
return filter(e[this])
endmethod
endif
else
method operator allocated takes nothing returns boolean
return filter(e[this])
endmethod
endif
elseif (thistype.index.exists) then
static if thistype.deindex.exists then
readonly boolean allocated
else
method operator allocated takes nothing returns boolean
return this==GetUnitUserData(e[this])
endmethod
endif
else
method operator allocated takes nothing returns boolean
return this==GetUnitUserData(e[this])
endmethod
endif
static if thistype.index.exists then
private static method onIndexEvent takes nothing returns boolean
static if thistype.filter.exists then
if (filter(e[o])) then
static if thistype.deindex.exists then
set thistype(o).allocated=true
endif
call thistype(o).index()
endif
else
static if thistype.deindex.exists then
set thistype(o).allocated=true
endif
call thistype(o).index()
endif
return false
endmethod
endif
static if thistype.deindex.exists then
private static method onDeindexEvent takes nothing returns boolean
static if thistype.filter.exists then
static if thistype.index.exists then
if (thistype(o).allocated) then
set thistype(o).allocated=false
call thistype(o).deindex()
endif
else
if (filter(e[o])) then
call thistype(o).deindex()
endif
endif
else
static if thistype.index.exists then
set thistype(o).allocated=false
endif
call thistype(o).deindex()
endif
return false
endmethod
endif
static if thistype.index.exists then
static if thistype.deindex.exists then
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onIndexEvent),UnitIndexer.INDEX)
call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent),UnitIndexer.DEINDEX)
endmethod
else
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onIndexEvent),UnitIndexer.INDEX)
endmethod
endif
elseif thistype.deindex.exists then
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent),UnitIndexer.DEINDEX)
endmethod
endif
endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library WorldBounds
//struct WorldBounds extends array
//static readonly rect world
// same as GetWorldBounds()
//static readonly region worldRegion
// contains world for triggers
//static readonly real maxX
//static readonly real maxY
//static readonly real minX
//static readonly real minY
//static readonly real centerX
//static readonly real centerY
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world=GetWorldBounds()
set maxX=GetRectMaxX(world)
set maxY=GetRectMaxY(world)
set minX=GetRectMinX(world)
set minY=GetRectMinY(world)
set centerX=(maxX+minX)/2
set centerY=(minY+maxY)/2
set worldRegion=CreateRegion()
call RegionAddRect(worldRegion,world)
endmethod
endmodule
struct WorldBounds extends array
readonly static real maxX
readonly static real maxY
readonly static real minX
readonly static real minY
readonly static real centerX
readonly static real centerY
readonly static rect world
readonly static region worldRegion
implement WorldBoundInit
endstruct
endlibrary
//TESH.scrollpos=107
//TESH.alwaysfold=0
library MotionBlur uses TimerUtils, UnitIndexer
/***********************************************************************************
* MotionBlur
* __________
* v1.0.0.0
* by Thelordmarshall
*
* This code allow to add motion blur for a unit and destroy
* by calling .destroy() method. Useful for dash spells.
*
* API:
* ____
*
* struct MotionBlur extends array
* - method add takes integer typeId, string animation, real animSpeed, integer blurLvl, integer blurSpeed, boolean getDummy returns nothing
* - Add motion blur for unit.
* - method destroy takes nothing returns nothing
* - Add motion blur for unit.
* - method addSimple takes integer blurLvl, integer blurSpeed, boolean removeUnit returns nothing
* - This method add timer transparency for a unit. You not need call
* destroy method on finish.
*
* Copyright © 2014.
************************************************************************************/
//Configuration.
globals
private constant player DUMMY_OWNER = Player(PLAYER_NEUTRAL_PASSIVE)
endglobals
//EndConfig.
struct MotionBlur extends array
private static constant real PERIOD = .03125
private static unit mt_blurDummy
private unit source
private unit blur
private string animation
private real animSpeed
private integer typeId
private integer blurLvl
private integer blurSpeed
private boolean getDummy
private boolean destroyBlur
private boolean removeUnit
implement UnitIndexStruct
private static method blurLoop takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
set .blurLvl = .blurLvl-.blurSpeed
call SetUnitVertexColor(.blur,255,255,255,.blurLvl)
if .blurLvl <= 0 then
if .removeUnit then
call RemoveUnit(.blur)
else
call SetUnitVertexColor(.blur,255,255,255,255)
endif
set .blur = null
call ReleaseTimer(t)
endif
set t = null
endmethod
private method getBlurDummy takes integer id, real x, real y, real a returns unit
set mt_blurDummy = CreateUnit(DUMMY_OWNER,id,0.,0.,a)
call UnitAddAbility(mt_blurDummy,'Aloc')
call UnitAddAbility(mt_blurDummy,'Aeth')
call UnitAddAbility(mt_blurDummy,'Avul')
call SetUnitPathing(mt_blurDummy,false)
call SetUnitPosition(mt_blurDummy,x,y)
call SetUnitColor(mt_blurDummy,GetPlayerColor(GetOwningPlayer(.source)))
return mt_blurDummy
endmethod
private static method onLoop takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local real x = GetUnitX(.source)
local real y = GetUnitY(.source)
local real a = GetUnitFacing(.source)
local thistype newId
local unit blur
if .getDummy then
set blur = .getBlurDummy(.typeId,x,y,a)
else
set blur = CreateUnit(GetOwningPlayer(.source),.typeId,x,y,a)
endif
call SetUnitTimeScale(blur,.animSpeed*.01)
call SetUnitAnimation(blur,.animation)
set newId = GetUnitId(blur)
set newId.blur = blur
set newId.blurLvl = .blurLvl
set newId.blurSpeed = .blurSpeed
set newId.removeUnit = true
call TimerStart(NewTimerEx(newId),PERIOD,true,function thistype.blurLoop)
if .destroyBlur then
set .source = null
call ReleaseTimer(t)
endif
set blur = null
set t = null
endmethod
method add takes integer typeId, string animation, real animSpeed, integer blurLvl, integer blurSpeed, boolean getDummy returns nothing
set .source = .unit
set .typeId = typeId
set .animation = animation
set .animSpeed = animSpeed
set .blurLvl = blurLvl
set .blurSpeed = blurSpeed
set .getDummy = getDummy
set .destroyBlur = false
call TimerStart(NewTimerEx(this),PERIOD,true,function thistype.onLoop)
endmethod
method addSimple takes integer blurLvl, integer blurSpeed, boolean removeUnit returns nothing
set .blur = .unit
set .blurLvl = blurLvl
set .blurSpeed = blurSpeed
set .removeUnit = removeUnit
call TimerStart(NewTimerEx(this),PERIOD,true,function thistype.blurLoop)
endmethod
method destroy takes nothing returns nothing
set .destroyBlur = true
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library TerrainPathability initializer Init
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This script can be used to detect the type of pathing at a specific point.
//* It is valuable to do it this way because the IsTerrainPathable is very
//* counterintuitive and returns in odd ways and aren't always as you would
//* expect. This library, however, facilitates detecting those things reliably
//* and easily.
//*
//******************************************************************************
//*
//* > function IsTerrainDeepWater takes real x, real y returns boolean
//* > function IsTerrainShallowWater takes real x, real y returns boolean
//* > function IsTerrainLand takes real x, real y returns boolean
//* > function IsTerrainPlatform takes real x, real y returns boolean
//* > function IsTerrainWalkable takes real x, real y returns boolean
//*
//* These functions return true if the given point is of the type specified
//* in the function's name and false if it is not. For the IsTerrainWalkable
//* function, the MAX_RANGE constant below is the maximum deviation range from
//* the supplied coordinates that will still return true.
//*
//* The IsTerrainPlatform works for any preplaced walkable destructable. It will
//* return true over bridges, destructable ramps, elevators, and invisible
//* platforms. Walkable destructables created at runtime do not create the same
//* pathing hole as preplaced ones do, so this will return false for them. All
//* other functions except IsTerrainWalkable return false for platforms, because
//* the platform itself erases their pathing when the map is saved.
//*
//* After calling IsTerrainWalkable(x, y), the following two global variables
//* gain meaning. They return the X and Y coordinates of the nearest walkable
//* point to the specified coordinates. These will only deviate from the
//* IsTerrainWalkable function arguments if the function returned false.
//*
//* Variables that can be used from the library:
//* [real] TerrainPathability_X
//* [real] TerrainPathability_Y
//*
globals
private constant real MAX_RANGE = 10.
private constant integer DUMMY_ITEM_ID = 'wolg'
endglobals
globals
private item Item = null
private rect Find = null
private item array Hid
private integer HidMax = 0
public real X = 0.
public real Y = 0.
endglobals
function IsTerrainDeepWater takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
function IsTerrainShallowWater takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
function IsTerrainLand takes real x, real y returns boolean
return IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY)
endfunction
function IsTerrainPlatform takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
private function HideItem takes nothing returns nothing
if IsItemVisible(GetEnumItem()) then
set Hid[HidMax] = GetEnumItem()
call SetItemVisible(Hid[HidMax], false)
set HidMax = HidMax + 1
endif
endfunction
function IsTerrainWalkable takes real x, real y returns boolean
//Hide any items in the area to avoid conflicts with our item
call MoveRectTo(Find, x, y)
call EnumItemsInRect(Find ,null, function HideItem)
//Try to move the test item and get its coords
call SetItemPosition(Item, x, y) //Unhides the item
set X = GetItemX(Item)
set Y = GetItemY(Item)
static if LIBRARY_IsTerrainWalkable then
//This is for compatibility with the IsTerrainWalkable library
set IsTerrainWalkable_X = X
set IsTerrainWalkable_Y = Y
endif
call SetItemVisible(Item, false)//Hide it again
//Unhide any items hidden at the start
loop
exitwhen HidMax <= 0
set HidMax = HidMax - 1
call SetItemVisible(Hid[HidMax], true)
set Hid[HidMax] = null
endloop
//Return walkability
return (X-x)*(X-x)+(Y-y)*(Y-y) <= MAX_RANGE*MAX_RANGE and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
private function Init takes nothing returns nothing
set Find = Rect(0., 0., 128., 128.)
set Item = CreateItem(DUMMY_ITEM_ID, 0, 0)
call SetItemVisible(Item, false)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope HolyDash
/***********************************************************************************
* HolyDash
* ________
* v1.0.1.1
* by Thelordmarshall
*
* The Paladin move fast toward one point, causing damage to all enemy
* units in the way and healing your allies for 30% of the inflicted
* damage.
*
* Level 1 - 700 cast range, 90 damage + 9% of strength (Configurable).
* Level 2 - 900 cast range, 170 damage + 17% of strength (Configurable).
* Level 3 - 1100 cast range, 280 damage + 24% of strength (Configurable).
* Level 4 - 1300 cast range, 360 damage + 30% of strength (Configurable).
*
* Cooldown: 19/17/15/13 seconds.
*
* How to import:
* ______________
*
* - Copy the folder "Requires" and "Holy Dash Spell".
* - Copy the dummy unit and ability.
* - Copy the ability Unit Indexing.
* - Configure all raw codes in UnitIndexer and HolyDash triggers.
* - You can configure other parameters of the spell (optional).
* - Enjoy.
*
* Credits:
* ________
*
* - Vexorian: TimerUtils.
* - Nestharus: UnitIndexer.
* - PitzerMike: DestructableLib functions.
* - Rising_Dusk: TerrainPathability
*
* Copyright © 2014.
************************************************************************************/
globals
private real array dmgLvl
private real array attLvl
endglobals
//CONFIGURATION
globals
//Raw codes
private constant integer SPELL_ID = 'A001' //Raw code of your ability.
private constant integer DASH_DUMMY = 'h000' //Dummy raw code.
private constant integer MAIN_CASTER = 'H001' //Raw code of the main caster.
//Basic Configuration
private constant real DASH_SPEED_TIME = .8 //Max speed of the dash (in seconds).
private constant real DASH_AOE = 90. //Units affected in this range.
private constant real TAG_SIZE = .02 //Textag size.
private constant real DASH_ANIM_SPEED = 120. //Caster animation speed.
private constant real DUMMY_ANIM_SPEED = 220. //Dummy animation speed.
private constant integer MOTION_BLUR_LEVEL = 90 //Transparency of the dummy unit (from 0 to 255).
private constant integer MOTION_TIME = 4 //Time/speed to add transparency and remove the dummy unit.
private constant string ATTACH_FX_CASTER = "weapon" //Attach point of the fx caster.
private constant string ATTACH_FX = "origin" //Attach point of the fx enemys.
private constant string DASH_ANIMATION = "attack" //Animation for the caster.
private constant string DUMMY_ANIMATION = "attack" //Animation for dummys.
private constant damagetype DASH_DMG_TYPE = DAMAGE_TYPE_DIVINE
//Tag colors
private constant string TAG_HEAL_COLOR = "|c00FEBA0E"
private constant string TAG_DMG_COLOR = "|c00FF0000"
//Fx
private constant string DASH_FX_CASTER = "Abilities\\Spells\\Other\\HealingSpray\\HealBottleMissile.mdl"
private constant string DASH_FX_ALLY = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl"
private constant string DASH_FX_ENEMY = "Abilities\\Spells\\Demon\\DarkPortal\\DarkPortalTarget.mdl"
private constant string DASH_EXTRA_FX = "Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl" //fx used in not walkable terrain.
//Knockback fxs (if use the knockback feature)
private constant string KNOCKBACKED_FX1 = "Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl" //fx in land.
private constant string KNOCKBACKED_FX2 = "Abilities\\Spells\\Undead\\AbsorbMana\\AbsorbManaBirthMissile.mdl" //fx in water.
//Advance Configuration
private constant boolean SHOW_TEXT_TAG = true
private constant boolean PAUSE_CASTER = true
private constant boolean HIT_TREES = true
private constant boolean USE_KNOCKBACK = true //Konckback for enemys.
private constant real KNOCKBACKED_DIS = 85.
private constant real KNOCKBACKED_SPEED = 1.
private constant real REFRESH_PERIOD = .03125 //Recomended: .03125 (or 0.03 in GUI)
private constant real DEBUG_PERIOD = 5. //Time to disable the ability, only in case if not turn off automatically.
endglobals
//Damage base for each level.
private function DamageConfig takes nothing returns nothing
set dmgLvl[1] = 90.
set dmgLvl[2] = 170.
set dmgLvl[3] = 280.
set dmgLvl[4] = 360.
endfunction
//Attribute % for each level.
private function AttributePercentConfig takes nothing returns nothing
set attLvl[1] = 9.
set attLvl[2] = 17.
set attLvl[3] = 24.
set attLvl[4] = 30.
endfunction
//Attribute type, used for damage calculation, you can use str, int or agi.
private function AttributeType takes unit caster returns integer
return GetHeroStr(caster,true)
endfunction
//Heal calculation.
private function GetHeal takes real dmg returns real
return dmg*30./100. // =30%
endfunction
//Filter for afected units.
private function ConfigFilter takes unit u returns boolean
return GetWidgetLife(u) > .405 and not IsUnitType(u,UNIT_TYPE_STRUCTURE) and not IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE)
endfunction
//ENDCONFIGURATION
//Core.
private struct HolyDash extends array
static if HIT_TREES then
static rect treesRect
static unit treesMurderer
endif
static if USE_KNOCKBACK then
unit knockbacked
endif
unit caster
player p
real cos
real sin
real dmg
real d1
real d2
real tTotal
group dashGroup
effect fx
method showTag takes string s, real x, real y returns nothing
local texttag tag = CreateTextTag()
call SetTextTagText(tag,s,TAG_SIZE)
call SetTextTagPos(tag,x,y,16.)
call SetTextTagVelocity(tag,0.,.0355)
call SetTextTagFadepoint(tag,1.5)
call SetTextTagLifespan(tag,2.)
call SetTextTagPermanent(tag,false)
set tag = null
endmethod
static method fxOnGround takes real x, real y returns nothing
local real AoE = 250.
local integer duration = R2I(.4*1000.)
local real spaceWave = 5.*duration/10.
local real timeWave = 5.*AoE/200.
local real radiusRatio = AoE/50.
call TerrainDeformStop(TerrainDeformRipple(x,y,AoE,80.,duration,2,spaceWave,timeWave,radiusRatio,true),duration)
endmethod
static if HIT_TREES then
//Credits to PitzerMike for this function.
static method isDesIsTree takes destructable d returns boolean
local boolean result = false
if d != null then
call PauseUnit(treesMurderer,false)
set result = IssueTargetOrder(treesMurderer,"harvest",d)
call PauseUnit(treesMurderer,true)
endif
return result
endmethod
static method destoyTrees takes nothing returns nothing
local destructable d = GetEnumDestructable()
if GetDestructableLife(d) > .405 and .isDesIsTree(d) then
call KillDestructable(d)
endif
set d = null
endmethod
endif
static if USE_KNOCKBACK then
static method onKnockback takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local real x = GetUnitX(.knockbacked)
local real y = GetUnitY(.knockbacked)
set .tTotal = .tTotal+REFRESH_PERIOD
if not IsUnitPaused(.knockbacked) then
call PauseUnit(.knockbacked,true)
endif
call SetUnitPosition(.knockbacked,x+.d1*.cos,y+.d1*.sin)
if IsTerrainLand(x,y) then
call DestroyEffect(AddSpecialEffect(KNOCKBACKED_FX1,x,y))
elseif IsTerrainShallowWater(x,y) then
call DestroyEffect(AddSpecialEffect(KNOCKBACKED_FX2,x,y))
endif
set .d1 = .d1-.d2
if .d1 <= 0. or .tTotal >= DEBUG_PERIOD then
call PauseUnit(.knockbacked,false)
call SetUnitPathing(.knockbacked,true)
set .knockbacked = null
call ReleaseTimer(t)
endif
set t = null
endmethod
static method startKnockback takes unit u, real a returns nothing
local thistype this = thistype[GetUnitId(u)]
local integer q = R2I(KNOCKBACKED_SPEED/REFRESH_PERIOD)
set .knockbacked = u
set .cos = Cos(a)
set .sin = Sin(a)
set .d1 = 2.*KNOCKBACKED_DIS/q+1.
set .d2 = .d1/q
set .tTotal = 0.
call SetUnitPathing(.knockbacked,false)
call TimerStart(NewTimerEx(this),REFRESH_PERIOD,true,function thistype.onKnockback)
endmethod
endif
method destroy takes nothing returns nothing
call SetUnitTimeScale(.caster,100.*.01)
call SetUnitAnimation(.caster,"attack")
call PauseUnit(.caster,false)
call SetUnitPathing(.caster,true)
call DestroyGroup(.dashGroup)
call DestroyEffect(.fx)
call MotionBlur[.caster].destroy()
set .p = null
set .caster = null
set .dashGroup = null
endmethod
static method onLoop takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local real x = GetUnitX(.caster)
local real y = GetUnitY(.caster)
local real x2
local real y2
local real maxLife
local real life
local real heal
local unit u
set .tTotal = .tTotal+REFRESH_PERIOD
static if PAUSE_CASTER then
if not IsUnitPaused(.caster) then
call PauseUnit(.caster,true)
endif
endif
call SetUnitPosition(.caster,x+.d1*.cos,y+.d1*.sin)
call SetUnitAnimation(.caster,DASH_ANIMATION)
if not IsTerrainWalkable(x,y) then
call DestroyEffect(AddSpecialEffect(DASH_EXTRA_FX,x,y))
endif
call GroupEnumUnitsInRange(bj_lastCreatedGroup,x,y,DASH_AOE,null)
loop
set u = FirstOfGroup(bj_lastCreatedGroup)
call GroupRemoveUnit(bj_lastCreatedGroup,u)
if ConfigFilter(u) and not IsUnitInGroup(u,.dashGroup) and u != .caster then
set x2 = GetUnitX(u)
set y2 = GetUnitY(u)
if IsUnitEnemy(u,.p) then
call UnitDamageTarget(.caster,u,.dmg,false,false,ATTACK_TYPE_HERO,DASH_DMG_TYPE,null)
//! textmacro OnHit takes FX,TAG_COLOR,REAL_VALUE
call DestroyEffect(AddSpecialEffectTarget($FX$,u,ATTACH_FX))
static if SHOW_TEXT_TAG then
call .showTag($TAG_COLOR$+I2S(R2I($REAL_VALUE$))+"!|r",GetUnitX(u),GetUnitY(u))
endif
call .fxOnGround(x2,y2)
//! endtextmacro
//! runtextmacro OnHit("DASH_FX_ENEMY","TAG_DMG_COLOR",".dmg")
static if USE_KNOCKBACK then
call .startKnockback(u,Atan2(y2-y,x2-x))
endif
else //If ally
set maxLife = GetUnitState(u,UNIT_STATE_MAX_LIFE)
set life = GetUnitState(u,UNIT_STATE_LIFE)
if life < maxLife then
set heal = GetHeal(.dmg)
call SetWidgetLife(u,life+heal)
//! runtextmacro OnHit("DASH_FX_ALLY","TAG_HEAL_COLOR","heal")
endif
endif
call GroupAddUnit(.dashGroup,u)
endif
exitwhen u == null
endloop
static if HIT_TREES then
call MoveRectTo(treesRect,x,y)
call EnumDestructablesInRect(treesRect,null,function thistype.destoyTrees)
endif
set .d1 = .d1-.d2
if .d1 <= 0. or tTotal >= DEBUG_PERIOD then
call .fxOnGround(x,y)
call .destroy()
call ReleaseTimer(t)
endif
set t = null
endmethod
static method onCast takes nothing returns boolean
local unit u = GetTriggerUnit()
local real x1 = GetUnitX(u)
local real y1 = GetUnitY(u)
local real x2 = GetSpellTargetX()
local real y2 = GetSpellTargetY()
local real a = Atan2(y2-y1,x2-x1)
local integer lvl = GetUnitAbilityLevel(u,SPELL_ID)
local integer id = GetUnitTypeId(u)
local integer q = R2I(DASH_SPEED_TIME/REFRESH_PERIOD)
local thistype this = thistype[GetUnitId(u)]
if GetSpellAbilityId() == SPELL_ID then
set .caster = u
set .p = GetTriggerPlayer()
set .cos = Cos(a)
set .sin = Sin(a)
set .d1 = 2.*SquareRoot(Pow(x2-x1,2)+Pow(y2-y1,2))/(q+1.)
set .d2 = .d1/q
set .dmg = dmgLvl[lvl]+I2R(AttributeType(.caster))*attLvl[lvl]/100.
set .fx = AddSpecialEffectTarget(DASH_FX_CASTER,.caster,ATTACH_FX_CASTER)
set .dashGroup = CreateGroup()
set .tTotal = 0.
//Activating the motion blur.
if id == MAIN_CASTER then
call MotionBlur[.caster].add(DASH_DUMMY,DUMMY_ANIMATION,DUMMY_ANIM_SPEED,MOTION_BLUR_LEVEL,MOTION_TIME,false)
else
call MotionBlur[.caster].add(id,DUMMY_ANIMATION,DUMMY_ANIM_SPEED,MOTION_BLUR_LEVEL,MOTION_TIME,true)
endif
call SetUnitPathing(.caster,false)
call SetUnitTimeScale(.caster,DASH_ANIM_SPEED*.01)
call TimerStart(NewTimerEx(this),REFRESH_PERIOD,true,function thistype.onLoop)
endif
set u = null
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call DamageConfig()
call AttributePercentConfig()
//Configuring the trees murderer dummy unit and rect(used for EnumDestructablesInRect).
static if HIT_TREES then
set treesMurderer = CreateUnit(Player(15),'hfoo',0.,0.,0.)
call ShowUnit(treesMurderer,false)
call UnitAddAbility(treesMurderer,'Ahrl')
call UnitAddAbility(treesMurderer,'Aloc')
call PauseUnit(treesMurderer,true)
set treesRect = Rect(-DASH_AOE,-DASH_AOE,DASH_AOE,DASH_AOE)
endif
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function thistype.onCast))
endmethod
endstruct
endscope