//TESH.scrollpos=0
//TESH.alwaysfold=0
Name | Type | is_array | initial_value |
//TESH.scrollpos=0
//TESH.alwaysfold=0
**********************
*
* Amumu
* v1.2.1.0
* By tRu.Style
*
* - Amumu "The Sad Mummy" of LoL
* - http://gameinfo.na.leagueoflegends.com/en/game-info/champions/amumu/
*
* Requirements:
* -------------
*
* TimerUtils v 2.0 - by Vexorian
* - http://www.wc3c.net/showthread.php?t=101322
*
* Implementation Instructions
* ---------------------------
*
* 1. Copy ability
* 2. Copy unit
* 3. Copy trigger
* 4. Setup variable
* 5. Now ready
*
* Fixed:
* Now normal work for E and Q ability
**********************
//TESH.scrollpos=18
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//* 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.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* 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.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = true
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//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, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
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==ARRAY_SIZE) 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 init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=60
//TESH.alwaysfold=0
scope AmumuQ initializer Init
globals
private constant real SPEED = 60 // Dummy and caster speed
private constant real BASIC_DAMAGE = 30 // Standard damage, how it's work? Watch to GetDamage function
private constant real DAMAGE_PER_LVL = 50 // Damage pre lvl
private constant real DISTANCE = 800 // Max distance
private constant real RANGE = 100 // Unit pick radius
private constant real MAGIC_NUMBER = 57.29 // Прост))00
private constant real PERIOD = .04 // Timeout timer
private constant string LIGHTNING_MODEL = "DRAL" // Lightning type
private constant integer ABILITY_ID = 'A000' // Spell ID
private constant integer DUMMY_CASTER_ID = 'h002' // Dummy caster
private constant integer STUN_ID = 'A005' // Stun spell id
private constant integer DUMMY_HEAD_ID = 'h001' // Head chain dummy ID
private constant boolean STUN = true // boolean for end spell, if stun = true then target is stunned
private constant boolean PRELOAD = true // give preload for stun ability?
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_HERO
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_MAGIC
/**/
private group GROUP = CreateGroup()
endglobals
//Target check
private function Q_Boolean takes unit u,unit e returns boolean
return /*
*/ IsUnitEnemy(e,GetOwningPlayer(u)) and /* // target enemy? true
*/ not IsUnitType(e,UNIT_TYPE_DEAD) and /* //Alive target?
*/ GetUnitTypeId(e) != 0 and /* // Alive target?
*/ not IsUnitType(e, UNIT_TYPE_STRUCTURE) and /* // target don't structure
*/ not IsUnitType(e, UNIT_TYPE_MECHANICAL) and /* // target don't mechanical
*/ not IsUnitType(e, UNIT_TYPE_MAGIC_IMMUNE) // target don't magic immune
endfunction
//Damage easy function
private function GetDamage takes unit u returns real
return BASIC_DAMAGE + (DAMAGE_PER_LVL * GetUnitAbilityLevel(u,ABILITY_ID))
endfunction
//This function checks the distance
function DistanceBetweenCoords takes real x1, real y1, real x2, real y2 returns real
return SquareRoot((x1-x2) * (x1-x2) + (y1-y2) * (y1-y2))
endfunction
//Don't touch struct//////
/* */ private struct Q //
/* */ unit caster //
/* */ unit target //
/* */ unit dummy //
/* */ real damage //
/* */ real x //
/* */ real y //
/* */ real dis //
/* */ lightning l //
/* */endstruct //
//////////////////////////
private function SecondLoop takes nothing returns nothing
local timer t = GetExpiredTimer()
local Q data = GetTimerData(t)
local real x = GetUnitX(data.caster)
local real y = GetUnitY(data.caster)
local real X = x - SPEED * Cos(Atan2(GetUnitY(data.caster) - GetUnitY(data.target),GetUnitX(data.caster) - GetUnitX(data.target)))
local real Y = y - SPEED * Sin(Atan2(GetUnitY(data.caster) - GetUnitY(data.target),GetUnitX(data.caster) - GetUnitX(data.target)))
if DistanceBetweenCoords(x,y,GetUnitX(data.target),GetUnitY(data.target)) < 100 then
call RemoveUnit(data.dummy)
call DestroyLightning(data.l)
call data.destroy()
call ReleaseTimer(t)
set data.caster = null
set data.target = null
set data.dummy = null
set data.l = null
else
call SetUnitX(data.caster,X)
call SetUnitY(data.caster,Y)
call MoveLightning(data.l,true,x,y,GetUnitX(data.dummy),GetUnitY(data.dummy))
endif
set t = null
endfunction
private function FirstLoop takes nothing returns nothing
local timer t = GetExpiredTimer()
local Q data = GetTimerData(t)
local real x = GetUnitX(data.dummy)
local real y = GetUnitY(data.dummy)
local real X = x + SPEED * Cos(Atan2(data.y - GetUnitY(data.caster),data.x - GetUnitX(data.caster)))
local real Y = y + SPEED * Sin(Atan2(data.y - GetUnitY(data.caster),data.x - GetUnitX(data.caster)))
local unit e
if data.dis >= DISTANCE then
call RemoveUnit(data.dummy)
call DestroyLightning(data.l)
call data.destroy()
call ReleaseTimer(t)
set data.caster = null
set data.target = null
set data.dummy = null
set data.l = null
else
call SetUnitX(data.dummy,X)
call SetUnitY(data.dummy,Y)
call MoveLightning(data.l,true,GetUnitX(data.caster),GetUnitY(data.caster),x,y)
call GroupEnumUnitsInRange(GROUP,X,Y,RANGE, null)
loop
set e = FirstOfGroup(GROUP)
exitwhen(e == null)
call GroupRemoveUnit(GROUP,e)
if Q_Boolean(data.caster,e) then
call UnitDamageTarget(data.caster,e,data.damage,false,false,ATTACK_TYPE,DAMAGE_TYPE,null)
if STUN then
set bj_lastCreatedUnit = CreateUnit(GetOwningPlayer(data.caster),DUMMY_CASTER_ID,x,y,GetUnitFacing(data.target))
call UnitAddAbility(bj_lastCreatedUnit,STUN_ID)
call IssueTargetOrder(bj_lastCreatedUnit,"thunderbolt",e)
endif
call PauseTimer(t)
call TimerStart(t,.04,true,function SecondLoop)
set data.target = e
endif
endloop
endif
call GroupClear(GROUP)
set data.dis = data.dis + SPEED
set t = null
set e = null
endfunction
private function QAct takes nothing returns boolean
local Q data
if GetSpellAbilityId() == ABILITY_ID then
set data = Q.create()
set data.caster = GetTriggerUnit()
set data.dummy = CreateUnit(GetTriggerPlayer(),DUMMY_HEAD_ID,GetUnitX(data.caster),GetUnitY(data.caster),Atan2(GetSpellTargetY() - GetUnitY(data.caster),GetSpellTargetX() - GetUnitX(data.caster)) * MAGIC_NUMBER)
set data.damage = GetDamage(data.caster)
set data.l = AddLightning(LIGHTNING_MODEL,true,GetUnitX(data.caster),GetUnitY(data.caster),GetUnitX(data.dummy),GetUnitY(data.dummy))
set data.dis = 0.
set data.x = GetSpellTargetX()
set data.y = GetSpellTargetY()
call TimerStart(NewTimerEx(data),PERIOD,true,function FirstLoop)
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger()
static if PRELOAD then
set bj_lastCreatedUnit = CreateUnit(Player(0),DUMMY_CASTER_ID,0,0,0)
call UnitAddAbility(bj_lastCreatedUnit,STUN_ID)
endif
call TriggerRegisterAnyUnitEventBJ(trg,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trg,Condition(function QAct))
set trg = null
endfunction
endscope
//TESH.scrollpos=39
//TESH.alwaysfold=0
scope AmumuW initializer Init
globals
private constant real BASIC_DAMAGE = 4 // Standard damage, how it's work? Watch to GetDamage function
private constant real DAMAGE_PER_LVL = 4 // Per lvl damage
private constant real HP_BASIC_DAMAGE = 1.2 // Percentage of the damage on the health of
private constant real HP_DAMAGE_PER_LVL = .3 // Per lvl hp damage
private constant real RANGE = 300 // Radius
private constant real REDIOD = 1 // Evre x seconde
private constant integer ABILITY_ID = 'A001' // Spell id
private constant integer BUFF_ID = 'B000' // Buff id
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_HERO
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_MAGIC
/**/
private group GROUP = CreateGroup()
endglobals
//Target check
private function W_Boolean takes unit u,unit e returns boolean
return /*
*/ IsUnitEnemy(e,GetOwningPlayer(u)) and /* // target enemy? true
*/ not IsUnitType(e,UNIT_TYPE_DEAD) and /* //Alive target?
*/ GetUnitTypeId(e) != 0 and /* // Alive target?
*/ not IsUnitType(e, UNIT_TYPE_STRUCTURE) and /* // target don't structure
*/ not IsUnitType(e, UNIT_TYPE_MECHANICAL) and /* // target don't mechanical
*/ not IsUnitType(e, UNIT_TYPE_MAGIC_IMMUNE) // target don't magic immune
endfunction
private function GetDamage takes unit u,unit e returns real
return (BASIC_DAMAGE + (DAMAGE_PER_LVL*GetUnitAbilityLevel(u,ABILITY_ID))) + (((HP_BASIC_DAMAGE+HP_DAMAGE_PER_LVL*GetUnitAbilityLevel(u,ABILITY_ID))*GetWidgetLife(e))*.01)
endfunction
//Don't touch struct//////
/* */private struct W //
/* */ unit caster //
/* */endstruct //
//////////////////////////
private function FirstLoop takes nothing returns nothing
local timer t = GetExpiredTimer()
local W data = GetTimerData(t)
local real x = GetUnitX(data.caster)
local real y = GetUnitY(data.caster)
local unit e
if GetUnitAbilityLevel(data.caster,BUFF_ID) > 0 and (not IsUnitType(data.caster, UNIT_TYPE_DEAD)) and GetUnitTypeId(data.caster) != 0 then
call GroupEnumUnitsInRange(GROUP,x,y,RANGE, null)
loop
set e = FirstOfGroup(GROUP)
exitwhen(e == null)
call GroupRemoveUnit(GROUP,e)
if W_Boolean(data.caster,e) then
call UnitDamageTarget(data.caster,e,GetDamage(data.caster,e),false,false,ATTACK_TYPE,DAMAGE_TYPE,null)
endif
endloop
else
call data.destroy()
call ReleaseTimer(t)
set data.caster = null
endif
call GroupClear(GROUP)
set e = null
set t = null
endfunction
private function WAct takes nothing returns boolean
local W data
if GetSpellAbilityId() == ABILITY_ID then
set data = W.create()
set data.caster = GetTriggerUnit()
call TimerStart(NewTimerEx(data),REDIOD,true,function FirstLoop)
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trg,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trg,Condition(function WAct))
set trg = null
endfunction
endscope
//TESH.scrollpos=2
//TESH.alwaysfold=0
scope AmumuE initializer Init
globals
private constant real BASIC_DAMAGE = 50 // Standard damage
private constant real DAMAGE_PER_LVL = 50 // Per lvl damage
private constant real RANGE = 350 // Radius
private constant integer LOOP = 20 // Effect count (360\LOOP,effects are created in a circle)
private constant integer ABILITY_ID = 'A002' // Spell id
private constant string EFFECT = "Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl" // no comments
private constant boolean PRELOAD = true // Preload effect?
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_HERO
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_MAGIC
/**/
private group GROUP = CreateGroup()
endglobals
private function GetDamage takes unit u returns real
return BASIC_DAMAGE + (DAMAGE_PER_LVL*GetUnitAbilityLevel(u,ABILITY_ID))
endfunction
//Target check
private function E_Boolean takes unit u,unit e returns boolean
return /*
*/ IsUnitEnemy(e,GetOwningPlayer(u)) and /* // target enemy? true
*/ not IsUnitType(e,UNIT_TYPE_DEAD) and /* //Alive target?
*/ GetUnitTypeId(e) != 0 and /* // Alive target?
*/ not IsUnitType(e, UNIT_TYPE_STRUCTURE) and /* // target don't structure
*/ not IsUnitType(e, UNIT_TYPE_MECHANICAL) and /* // target don't mechanical
*/ not IsUnitType(e, UNIT_TYPE_MAGIC_IMMUNE) // target don't magic immune
endfunction
private function EAct takes nothing returns boolean
local unit u
local unit e
local real x
local real y
local integer i
if GetSpellAbilityId() == ABILITY_ID then
set u = GetTriggerUnit()
set x = GetUnitX(u)
set y = GetUnitY(u)
set i = 0
call GroupEnumUnitsInRange(GROUP,x,y,RANGE, null)
loop
set e = FirstOfGroup(GROUP)
exitwhen(e == null)
call GroupRemoveUnit(GROUP,e)
if E_Boolean(u,e) then
call UnitDamageTarget(u,e,GetDamage(u),false,false,ATTACK_TYPE,DAMAGE_TYPE,null)
endif
endloop
loop
exitwhen i == LOOP
call DestroyEffect(AddSpecialEffect(EFFECT,GetUnitX(u) + (RANGE-35) * Cos(i),GetUnitY(u) + (RANGE-35) * Sin(i)))
set i = i + 1
endloop
call GroupClear(GROUP)
endif
set e = null
set u = null
return false
endfunction
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger()
static if PRELOAD then
call Preload(EFFECT)
endif
call TriggerRegisterAnyUnitEventBJ(trg,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trg,Condition(function EAct))
set trg = null
endfunction
endscope
//TESH.scrollpos=41
//TESH.alwaysfold=0
scope AmumuR initializer Init
globals
private constant real BASIC_DAMAGE = 50 // Standard damage
private constant real DAMAGE_PER_LVL = 100 // Per lvl damage
private constant real RANGE = 600 // Radius
private constant integer LOOP = 36 // Effect count (360\LOOP,effects are created in a circle)
private constant integer ABILITY_ID = 'A003' // Spell id
private constant integer ROOT_ID = 'A004' // Root id
private constant integer DUMMY_MODEL_ID = 'h003' // Duumy effect model
private constant integer DUMMY_CASTER_ID = 'h002' // Dummy spell caster
private constant string EFFECT = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl" // no comments
private constant boolean PRELOAD = true // preload effect and root?
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_HERO
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_MAGIC
/**/
private group GROUP = CreateGroup()
endglobals
private function GetDamage takes unit u returns real
return BASIC_DAMAGE + (DAMAGE_PER_LVL*GetUnitAbilityLevel(u,ABILITY_ID))
endfunction
//Target check
private function R_Boolean takes unit u,unit e returns boolean
return /*
*/ IsUnitEnemy(e,GetOwningPlayer(u)) and /* // target enemy? true
*/ not IsUnitType(e,UNIT_TYPE_DEAD) and /* //Alive target?
*/ GetUnitTypeId(e) != 0 and /* // Alive target?
*/ not IsUnitType(e, UNIT_TYPE_STRUCTURE) and /* // target don't structure
*/ not IsUnitType(e, UNIT_TYPE_MECHANICAL) and /* // target don't mechanical
*/ not IsUnitType(e, UNIT_TYPE_MAGIC_IMMUNE) // target don't magic immune
endfunction
private function RAct takes nothing returns boolean
local unit u
local unit e
local unit dummy
local real x
local real y
local integer i
if GetSpellAbilityId() == ABILITY_ID then
set u = GetTriggerUnit()
set x = GetUnitX(u)
set y = GetUnitY(u)
set dummy = CreateUnit(GetOwningPlayer(u),DUMMY_MODEL_ID,x,y,0)
set i = 0
call SetUnitScale(dummy,RANGE/100,RANGE/100,RANGE/100)
call GroupEnumUnitsInRange(GROUP,x,y,RANGE, null)
loop
set e = FirstOfGroup(GROUP)
exitwhen(e == null)
call GroupRemoveUnit(GROUP,e)
if R_Boolean(u,e) then
set bj_lastCreatedUnit = CreateUnit(GetOwningPlayer(u),DUMMY_CASTER_ID,x,y,GetUnitFacing(e))
call UnitAddAbility(bj_lastCreatedUnit,ROOT_ID)
call IssueTargetOrder(bj_lastCreatedUnit,"entanglingroots",e)
call UnitDamageTarget(u,e,GetDamage(u),false,false,ATTACK_TYPE,DAMAGE_TYPE,null)
endif
endloop
loop
exitwhen i == LOOP
call DestroyEffect(AddSpecialEffect(EFFECT,GetUnitX(u) + (RANGE-100) * Cos(i),GetUnitY(u) + (RANGE-100) * Sin(i)))
set i = i + 1
endloop
call GroupClear(GROUP)
endif
set u = null
set dummy = null
set e = null
return false
endfunction
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger()
static if PRELOAD then
set bj_lastCreatedUnit = CreateUnit(Player(0),DUMMY_CASTER_ID,0,0,0)
call UnitAddAbility(bj_lastCreatedUnit,ROOT_ID)
call Preload(EFFECT)
endif
call TriggerRegisterAnyUnitEventBJ(trg,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trg,Condition(function RAct))
set trg = null
endfunction
endscope