Name | Type | is_array | initial_value |
//TESH.scrollpos=36
//TESH.alwaysfold=0
library_once TimerUtils initializer redInit
//*********************************************************************
//* TimerUtils (Red flavor)
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3campaigns.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Red flavor: Fastest, method in existence for timer attaching,
//* only takes an array lookup, H2I and subtraction.
//* However, all the code in your map requires extra care
//* not to forget to call ReleaseTimer. It also requires
//* to preload a lot of timers at map init, they use
//* memory and handle ids.
//*
//* I recommend you run your map in debug mode the first
//* time after adding it, make sure you can see map init messages
//* if nothing appears, all is done, if an error appears, it might
//* suggest you a value with OFFSET, in that case, update that value
//* if it still does not work after updating (rare), try a bigger
//* OFFSET by 1000 for example. (Sounds hard? Then use blue or purple
//* timerutils that are friendlier though not as fast)
//*
//********************************************************************
//================================================================
globals
private constant integer OFFSET = 0x100000
private constant integer QUANTITY = 256
private constant integer ARRAY_SIZE = 8191 //changing this to a higher value would effectively
//cripple the performance making this thing irrelevant
endglobals
//=================================================================================================
private function H2I takes handle h returns integer
return GetHandleId( h )
endfunction
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
debug if(H2I(t)-OFFSET<0) then
debug call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
debug endif
set data[H2I(t)-OFFSET]=value
endfunction
function GetTimerData takes timer t returns integer
debug if(H2I(t)-OFFSET<0) then
debug call BJDebugMsg("GetTimerData: Wrong handle id, only use GetTimerData on timers created by NewTimer")
debug endif
return data[H2I(t)-OFFSET]
endfunction
//==========================================================================================
globals
private timer array tT
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
if (tN==0) then
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, please increase it for your map, fix your map's timer leaks or switch to blue flavor when applicable")
set tT[0]=CreateTimer()
if (H2I(tT[0])-OFFSET<0) or (H2I(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably switch to the blue flavor or fix timer leaks.")
return null
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==8191) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function redInit takes nothing returns nothing
local integer i=0
local integer bestoffset=-1
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set bestoffset=H2I(tT[i])
endif
if (H2I(tT[i])-OFFSET>=ARRAY_SIZE) then
debug call BJDebugMsg("TimerUtils_redInit: Failed a initializing attempt")
debug call BJDebugMsg("The timer limit is "+I2S(i))
debug call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low, to change OFFSET to "+I2S(bestoffset) )
exitwhen true
endif
if (H2I(tT[i])-OFFSET>=0) then
set i=i+1
endif
endloop
set tN=i
endfunction
endlibrary
//TESH.scrollpos=44
//TESH.alwaysfold=0
library BoundSentinel initializer init
//*************************************************
//* BoundSentinel
//* -------------
//* Don't leave your units unsupervised, naughty
//* them may try to get out of the map bounds and
//* crash your game.
//*
//* To implement, just get a vJass compiler and
//* copy this library/trigger to your map.
//*
//*************************************************
//==================================================
globals
// High enough so the unit is no longer visible, low enough so the
// game doesn't crash...
//
// I think you need 0.0 or soemthing negative prior to patch 1.22
//
private constant real EXTRA = 500.0
endglobals
//=========================================================================================
globals
private real maxx
private real maxy
private real minx
private real miny
endglobals
//=======================================================================
private function dis takes nothing returns nothing
local unit u=GetTriggerUnit()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
if(x>maxx) then
set x=maxx
elseif(x<minx) then
set x=minx
endif
if(y>maxy) then
set y=maxy
elseif(y<miny) then
set y=miny
endif
call SetUnitX(u,x)
call SetUnitY(u,y)
set u=null
endfunction
private function init takes nothing returns nothing
local trigger t=CreateTrigger()
local region r=CreateRegion()
local rect rc
set minx=GetCameraBoundMinX() - EXTRA
set miny=GetCameraBoundMinY() - EXTRA
set maxx=GetCameraBoundMaxX() + EXTRA
set maxy=GetCameraBoundMaxY() + EXTRA
set rc=Rect(minx,miny,maxx,maxy)
call RegionAddRect(r, rc)
call RemoveRect(rc)
call TriggerRegisterLeaveRegion(t,r, null)
call TriggerAddAction(t, function dis)
//this is not necessary but I'll do it anyway:
set t=null
set r=null
set rc=null
endfunction
endlibrary
//TESH.scrollpos=21
//TESH.alwaysfold=0
library IsTerrainWalkable initializer Init
//*****************************************************************
//* IsTerrainWalkable
//*
//* rewritten in vJass by: Anitarf
//* original implementation: Vexorian
//*
//* A function for checking if a point is pathable for ground
//* units (it does so by attempting to move an item there and
//* checking where it ended up), typically used to stop sliding
//* units before they end up stuck in trees. If the point is not
//* pathable, the function will also determine the nearest point
//* that is (the point where the item ends up).
//*****************************************************************
globals
// this value is how far from a point the item may end up for the point to be considered pathable
private constant real MAX_RANGE = 10.0
// the following two variables are set to the position of the item after each pathing check
// that way, if a point isn't pathable, these will be the coordinates of the nearest point that is
public real X = 0.0
public real Y = 0.0
// END OF CALIBRATION SECTION
// ================================================================
private rect r
private item check
private item array hidden
private integer hiddenMax = 0
endglobals
private function Init takes nothing returns nothing
set check = CreateItem('ciri',0,0)
call SetItemVisible(check,false)
set r = Rect(0.0,0.0,128.0,128.0)
endfunction
private function HideBothersomeItem takes nothing returns nothing
if IsItemVisible(GetEnumItem()) then
set hidden[hiddenMax]=GetEnumItem()
call SetItemVisible(hidden[hiddenMax],false)
set hiddenMax=hiddenMax+1
endif
endfunction
// ================================================================
function IsTerrainWalkable takes real x, real y returns boolean
// first, hide any items in the area so they don't get in the way of our item
call MoveRectTo(r, x,y)
call EnumItemsInRect(r,null,function HideBothersomeItem)
// try to move the check item and get it's coordinates
call SetItemPosition(check,x,y)//this unhides the item...
set X = GetItemX(check)
set Y = GetItemY(check)
call SetItemVisible(check,false)//...so we must hide it again
// before returning, unhide any items that got hidden at the start
loop
exitwhen hiddenMax<=0
set hiddenMax=hiddenMax-1
call SetItemVisible(hidden[hiddenMax],true)
set hidden[hiddenMax]=null
endloop
// return pathability status
return (x-X)*(x-X)+(y-Y)*(y-Y) < MAX_RANGE*MAX_RANGE
endfunction
endlibrary
//TESH.scrollpos=52
//TESH.alwaysfold=0
library groupaddunitsnearline
globals
//upper bound for the collision size of units
private constant real MAX_COLLISSION = 128.
//this is aproximately how much space of the rects is used by the line
//a higher value yields less unnecessary checks but also more rects
private constant real desiredefficiency = 0.6
//---
private rect temprect = Rect(0,0,0,0)
private group tempenumgroup = CreateGroup()
private group tempgroup
private real temppx
private real temppy
private real tempdnx
private real tempdny
private real tempwidth
private real tempd
endglobals
//returns the maximum of 4 reals
private function max4 takes real a, real b, real c, real d returns real
local real max = a
if b > max then
set max = b
endif
if c > max then
set max = c
endif
if d > max then
set max = d
endif
return max
endfunction
//returns the minimum of 4 reals
private function min4 takes real a, real b, real c, real d returns real
local real min = a
if b < min then
set min = b
endif
if c < min then
set min = c
endif
if d < min then
set min = d
endif
return min
endfunction
private function Add takes nothing returns boolean
//position of unit
local real x = GetUnitX(GetFilterUnit())
local real y = GetUnitY(GetFilterUnit())
//vector from the beginning of the line to the unit
local real dx = x - temppx
local real dy = y - temppy
//distance from the beginning of the line to that point on the line which is closest to the unit (uses dot-product)
local real d = dx * tempdnx + dy * tempdny
local real cx
local real cy
//cut off points outside the line
if d <= 0 then
set d = 0
elseif d >= tempd then
set d = tempd
endif
//the closest point to the unit on the line
set cx = temppx + d * tempdnx
set cy = temppy + d * tempdny
if IsUnitInRangeXY(GetFilterUnit(), cx, cy, tempwidth) then
call GroupAddUnit(tempgroup, GetFilterUnit())
endif
return false
endfunction
function GroupAddUnitsNearLine takes group g, real px, real py, real qx, real qy, real width returns nothing
//the line width width
local real l1x
local real l1y
local real l2x
local real l2y
local real l3x
local real l3y
local real l4x
local real l4y
//d = from p to q
local real dx = qx - px
local real dy = qy - py
local real dlen = SquareRoot(dx*dx + dy*dy)
//normalized d
local real dxn = dx / dlen
local real dyn = dy / dlen
//divisions
local integer divisions = 1
//bonus for correct overlapping of rects
local real bonusx = 0.
local real bonusy = 0.
//integer for loop
local integer i
//the outer rect
local real rectminx
local real rectmaxx
local real rectminy
local real rectmaxy
set width = width + MAX_COLLISSION
//calculate the number of divisions needed to approximately match desiredefficiency
if dx != 0 and dy != 0 then
set divisions = 1 + R2I(SquareRoot(desiredefficiency*desiredefficiency / (width*width/(dx*dx) + width*width/(dy*dy))))
endif
//this calculates a bonus so that there are intersections between the different rects
//(without this we would miss some units between the rects)
if dy != 0 and divisions > 1 then
set bonusx = width / 2 * dlen / dx// ?dy
endif
if dx != 0 and divisions > 1 then
set bonusy = width / 2 * dlen / dy // ? dx
endif
//calculate first line segment
set l1x = - width*dyn
set l1y = width*dxn
set l2x = width*dyn
set l2y = - width*dxn
set l3x = l2x + dx/divisions + bonusx
set l3y = l2y + dy/divisions + bonusy
set l4x = l1x + dx/divisions + bonusx
set l4y = l1y + dy/divisions + bonusy
//calculate bounds of the first line segment
set rectminx = min4(l1x,l2x,l3x,l4x)
set rectmaxx = max4(l1x,l2x,l3x,l4x)
set rectminy = min4(l1y,l2y,l3y,l4y)
set rectmaxy = max4(l1y,l2y,l3y,l4y)
//set temp vars for groupenum
set tempgroup = g
set temppx = px
set temppy = py
set tempdnx = dxn
set tempdny = dyn
set tempwidth = width - MAX_COLLISSION
set tempd = dlen
set i = 0
loop
exitwhen i >= divisions
//---
//move rect to right position
call SetRect(temprect, px + i * dx / divisions + rectminx, py + i * dy / divisions + rectminy, px + i * dx / divisions + rectmaxx, py + i * dy / divisions + rectmaxy)
//enum units in rect
call GroupEnumUnitsInRect(tempenumgroup, temprect, Condition(function Add))
//---
set i = i + 1
endloop
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope DarkAgility initializer init
//*************************************************************************************************************//
// Dark Agility v0.02 //
// by //
// cedi //
// //
// needs: TimerUtils by Vexorian //
// Bound Sentinel by Vexorian //
// Dummy Model by //
// IsTerrainWalkable by Antiarf //
// IsUnitNearLine by peq //
//*************************************************************************************************************//
//For use, copy the trigger to your map, copy the dummy create a spell and adjust the values below.
private keyword Main
private keyword Shadow
private keyword Arrow
globals
//ID of the spell
private constant integer SPELL_ID = 'A000'
private constant integer DUMMY_ID = 'h000'
private constant integer HERO_DUMMY_ID = 'h001'
//Interval of the moves
private constant real TIMER_INTERVAL = 0.01
//Main
private constant integer COLOR_RED = 125
private constant integer COLOR_GREEN = 125
private constant integer COLOR_BLUE = 125
private constant integer COLOR_ALPHA = 255
private constant integer ANIMATION = 6
private constant real SPEED = 1000.00
private constant real ILLU_TIME = 0.5
private constant real SHADOW_INTERVAL = 0.035
private constant real PICK_INTERVAL = 0.20
private constant real ANI_TIME = 1.334
private constant real ANI_SPEED = 15.00
private constant real ANI_SPEED_SHADOW = 1.00
private constant real SHADOW_SIZE = 1.00
private constant real Z_START = 60.00
private constant string DAMAGE_SFX = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
//Arrow
private constant integer A_COLOR_RED = 255
private constant integer A_COLOR_GREEN = 255
private constant integer A_COLOR_BLUE = 255
private constant integer A_COLOR_ALPHA = 125
private constant real SHOOT_RANGE = 600.00
private constant real SHOOT_SPEED = 600.00
private constant real SHOOT_AOE = 10.00
private constant real SHOOT_SIZE = 1.00
private constant string SHOOT_MODEL = "Abilities\\Weapons\\Arrow\\ArrowMissile.mdl"
private constant string SHOOT_ADD = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
private constant string SHOOT_DMG_SFX = "Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl"
//System
private Main TEMPMAIN
private Arrow TEMPARROW
private Shadow TEMPSHADOW
private group TEMPGROUP = CreateGroup()
endglobals
private function HIT_FUNC takes Main m, unit target returns nothing
//Do your uber crazy things, like knockback, dot, slow ...
endfunction
private function ARROW_HIT_FUNC takes Arrow a returns nothing
//Do your uber crazy things, like knockback, dot, slow ... //Care arrow gets destroyed after call
endfunction
private function DAMAGE takes integer level returns real
return 100.00 + 50 * level
endfunction
private function ARROW_DAMAGE takes integer level returns real
return 100.00 + 50 * level
endfunction
private function AOE takes integer level returns real
return 55.00 + 5 * level
endfunction
private function CD takes integer level returns real
return 0.10 - 0.01 * level
endfunction
//*************************************************************************************************************//
// !SYSTEM! //
//*************************************************************************************************************//
private function AngleBetweenUnits takes unit u, unit u2 returns real
return bj_RADTODEG * Atan2(GetUnitY( u2 ) - GetUnitY( u ), GetUnitX( u2 ) - GetUnitX( u ))
endfunction
private function AngleBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction
private function DistanceBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
local real dx = x2 - x1
local real dy = y2 - y1
return SquareRoot(dx * dx + dy * dy)
endfunction
private function IsAliveAndUnitAndNotMagicImmune takes nothing returns boolean
return GetWidgetLife( GetFilterUnit() ) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false
endfunction
private function A_OuterControl takes nothing returns nothing
set TEMPARROW = GetTimerData( GetExpiredTimer() )
call TEMPARROW.control()
endfunction
private function OuterControl takes nothing returns nothing
set TEMPMAIN = GetTimerData( GetExpiredTimer() )
call TEMPMAIN.control()
endfunction
private function RemoveShadow takes nothing returns nothing
local timer t = GetExpiredTimer()
set TEMPSHADOW = GetTimerData( t )
set TEMPSHADOW.alpha = TEMPSHADOW.alpha - TEMPSHADOW.alphaneg
call SetUnitVertexColor( TEMPSHADOW.u, COLOR_RED, COLOR_GREEN, COLOR_BLUE, R2I( TEMPSHADOW.alpha - 0.5 ) )
if TEMPSHADOW.alpha <= 0.00 then
call KillUnit( TEMPSHADOW.u )
call RemoveUnit( TEMPSHADOW.u )
call ReleaseTimer( t )
endif
set t = null
endfunction
private struct Shadow
unit u = null
real alpha = 0.00
real alphaneg = 0.00
static method create takes unit u returns thistype
local thistype this = thistype.allocate()
set .u = u
set .alpha = COLOR_ALPHA
set .alphaneg = .alpha * TIMER_INTERVAL / ILLU_TIME
return this
endmethod
endstruct
private struct Arrow
unit u = null
unit caster = null
unit target = null
integer level = 1
effect model = null
effect add = null
timer t = null
method onDestroy takes nothing returns nothing
call DestroyEffect( AddSpecialEffectTarget( SHOOT_DMG_SFX, .target, "chest" ) )
call UnitDamageTarget( .caster, .target, ARROW_DAMAGE( .level ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
call ARROW_HIT_FUNC( this )
call DestroyEffect( .model )
call DestroyEffect( .add )
set .model = null
set .add = null
call KillUnit( .u )
set .u = null
set .caster = null
set .target = null
call ReleaseTimer( .t )
set .t = null
endmethod
method control takes nothing returns nothing
local real angle = AngleBetweenUnits( .u, .target )
local real x = GetUnitX( .u )
local real y = GetUnitY( .u )
local real z = GetUnitFlyHeight( .target ) - GetUnitFlyHeight( .u )
local integer times = 0
call SetUnitFacing( .u, angle )
set angle = angle * bj_DEGTORAD
set x = x + Cos( angle ) * SHOOT_SPEED * TIMER_INTERVAL
set y = y + Sin( angle ) * SHOOT_SPEED * TIMER_INTERVAL
set times = R2I( DistanceBetweenCoordinates( GetUnitX( .u ), x, GetUnitY( .u ), y ) / ( SHOOT_SPEED * TIMER_INTERVAL ) + 0.5 )
call SetUnitX( .u, x )
call SetUnitY( .u, y )
if IsUnitInRange( .u, .target, SHOOT_AOE ) then
call .destroy()
return
endif
if z != 0.00 then
call SetUnitFlyHeight( .u, GetUnitFlyHeight( .u ) + z / times, 0 )
endif
endmethod
static method create takes unit caster, unit target, integer level returns thistype
local thistype this = thistype.allocate()
set .caster = caster
set .target = target
set .u = CreateUnit( GetOwningPlayer( caster ), DUMMY_ID, GetUnitX( caster ), GetUnitY( caster ), 0.00 )
set .level = level
set .model = AddSpecialEffectTarget( SHOOT_MODEL, .u, "origin" )
set .add = AddSpecialEffectTarget( SHOOT_ADD, .u, "origin" )
set .t = NewTimer()
call SetUnitFlyHeight( .u, Z_START, 0 )
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function A_OuterControl )
call SetUnitScale( .u, SHOOT_SIZE, SHOOT_SIZE, SHOOT_SIZE )
call SetUnitVertexColor( .u, A_COLOR_RED, A_COLOR_GREEN, A_COLOR_BLUE, A_COLOR_ALPHA )
return this
endmethod
endstruct
private struct Main
unit caster = null
real targx = 0.00
real targy = 0.00
real x = 0.00
real y = 0.00
real vx = 0.00
real vy = 0.00
real angle = 0.00
real distance = 0.00 //Distance moved
real fdistance = 0.00 //Full distance
real pickint = 0.00
real shadowint = 0.00
real aniint = 0.00
real shotint = 0.00
integer level = 1
integer i = 0
timer t = null
group g = null
group targets = null
method shot takes nothing returns nothing
local unit u = GroupPickRandomUnit( .targets )
if u != null then
call Arrow.create( .caster, u, .level )
endif
set u = null
endmethod
method createShadow takes nothing returns nothing
local timer t = NewTimer()
local unit u = CreateUnit( Player( 12 ), HERO_DUMMY_ID, .x, .y, .angle )
set TEMPSHADOW = Shadow.create( u )
call SetUnitTimeScale( u, ANI_SPEED_SHADOW )
call SetUnitAnimationByIndex( u, ANIMATION )
call SetUnitScale( u, SHADOW_SIZE, SHADOW_SIZE, SHADOW_SIZE )
call SetUnitVertexColor( u, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_ALPHA )
call SetTimerData( t, TEMPSHADOW )
call TimerStart( t, TIMER_INTERVAL, true, function RemoveShadow )
endmethod
method pick takes nothing returns nothing
local unit u = null
call GroupEnumUnitsInRange( TEMPGROUP, .x, .y, AOE( .level ), Condition( function IsAliveAndUnitAndNotMagicImmune ) )
loop
set u = FirstOfGroup( TEMPGROUP )
if IsUnitEnemy( u, GetOwningPlayer( .caster ) ) then
if not IsUnitInGroup( u, .g ) then
call DestroyEffect( AddSpecialEffectTarget( DAMAGE_SFX, u, "chest" ) )
call UnitDamageTarget( .caster, u, DAMAGE( .level ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
call HIT_FUNC( this, u )
call GroupAddUnit( .g, u )
endif
endif
call GroupRemoveUnit( TEMPGROUP, u )
set u = null
endloop
endmethod
method control takes nothing returns nothing
if .i == 3 then
call PauseUnit( .caster, true )
else
set .i = .i + 1
endif
if .distance >= .fdistance then
call .destroy()
endif
set .distance = .distance + SPEED * TIMER_INTERVAL
set .x = .x + .vx
set .y = .y + .vy
call SetUnitX( .caster, .x )
call SetUnitY( .caster, .y )
set .shotint = .shotint + TIMER_INTERVAL
if .shotint >= CD( .level ) then
set .shotint = 0.00
call .shot()
endif
set .pickint = .pickint + TIMER_INTERVAL
if .pickint >= PICK_INTERVAL then
set .pickint = 0.00
call .pick()
endif
set .shadowint = .shadowint + TIMER_INTERVAL
if .shadowint >= SHADOW_INTERVAL then
set .shadowint = 0.00
call .createShadow()
endif
set .aniint = .aniint + TIMER_INTERVAL
if .aniint >= ANI_TIME / ANI_SPEED then
set .aniint = 0.00
call SetUnitAnimationByIndex( .caster, ANIMATION )
endif
endmethod
method onDestroy takes nothing returns nothing
call SetUnitAnimation( .caster, "stand" )
call SetUnitTimeScale( .caster, 1.00 )
call PauseUnit( .caster, false )
call SetUnitInvulnerable( .caster, false )
call SetUnitPathing( .caster, true )
set .caster = null
call GroupClear( .g )
call DestroyGroup( .g )
set .g = null
call GroupClear( .targets )
call DestroyGroup( .targets )
set .targets = null
call ReleaseTimer( .t )
set .t = null
endmethod
static method create takes unit caster, real targx, real targy returns thistype
local thistype this = thistype.allocate()
local integer i
local real x
local real y
local unit u
set .caster = caster
set .targx = targx
set .targy = targy
set .x = GetUnitX( caster )
set .y = GetUnitY( caster )
set .level = GetUnitAbilityLevel( caster, SPELL_ID )
set .t = NewTimer()
call SetTimerData( .t, this )
set .angle = AngleBetweenCoordinates( .x, targx, .y, targy )
set .distance = DistanceBetweenCoordinates( .x, targx, .y, targy )
set .distance = .distance / ( SPEED * TIMER_INTERVAL )
set .vx = Cos( .angle * bj_DEGTORAD ) * SPEED * TIMER_INTERVAL
set .vy = Sin( .angle * bj_DEGTORAD ) * SPEED * TIMER_INTERVAL
set i = R2I( .distance + 0.5 ) * 4
set x = .x
set y = .y
set .g = CreateGroup()
set .targets = CreateGroup()
call GroupAddUnitsNearLine( .targets, .x, .y, .targx, .targy, SHOOT_RANGE )
call SetUnitInvulnerable( .caster, true )
call SetUnitPathing( .caster, false )
loop
exitwhen i < 0
set x = x + .vx / 4
set y = y + .vy / 4
if not IsTerrainWalkable( x, y ) or IsTerrainPathable( x, y, PATHING_TYPE_WALKABILITY ) then
set .targx = x
set .targy = y
exitwhen true
endif
set i = i - 1
endloop
set .distance = 0.00
set .fdistance = DistanceBetweenCoordinates( .x, .targx, .y, .targy )
call GroupAddGroup( .targets, TEMPGROUP )
loop
set u = FirstOfGroup( TEMPGROUP )
exitwhen u == null
if GetUnitTypeId( u ) != DUMMY_ID and GetUnitTypeId( u ) != HERO_DUMMY_ID and IsUnitEnemy( u, GetOwningPlayer( .caster ) ) and GetWidgetLife( u ) > 0.405 and IsUnitType(u, UNIT_TYPE_STRUCTURE) == false and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) == false then
//good target
else
//not good
call GroupRemoveUnit( .targets, u )
endif
call GroupRemoveUnit( TEMPGROUP, u )
set u = null
endloop
call SetUnitTimeScale( .caster, ANI_SPEED )
call SetUnitAnimationByIndex( .caster, ANIMATION )
call TimerStart( .t, TIMER_INTERVAL, true, function OuterControl )
return this
endmethod
endstruct
private function IsSpell takes nothing returns nothing
if GetSpellAbilityId() == SPELL_ID then
call Main.create( GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY() )
endif
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddAction( t, function IsSpell )
set t = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Revive_Units_Conditions takes nothing returns boolean
return IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == false
endfunction
function Trig_Revive_Units_Actions takes nothing returns nothing
if GetUnitTypeId( GetTriggerUnit() ) == 'h000' then
return
endif
call TriggerSleepAction( 10.00 )
call CreateUnit( GetOwningPlayer( GetTriggerUnit() ), GetUnitTypeId( GetTriggerUnit() ), GetUnitX( GetTriggerUnit() ), GetUnitY( GetTriggerUnit() ), GetUnitFacing( GetTriggerUnit() ) )
endfunction
//===========================================================================
function InitTrig_Revive_Units takes nothing returns nothing
set gg_trg_Revive_Units = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Revive_Units, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Revive_Units, Condition( function Trig_Revive_Units_Conditions ) )
call TriggerAddAction( gg_trg_Revive_Units, function Trig_Revive_Units_Actions )
endfunction