library Bladedance initializer Init
private function Conditions takes nothing returns boolean
//this sets which ability triggers the cast
//to change this, just change the ability code type variable
//in the GUI init, this updates automatically to that
return GetSpellAbilityId() == udg_BladedanceAbility
endfunction
private function Expire takes nothing returns nothing
//Local Timer functions used to remove the Clones without triggering Unit - Dies effects
local timer t = GetExpiredTimer()
local integer timerId = GetHandleId(t)
local integer i = 0
local unit clone
local effect startEffect
loop
exitwhen i >= 12
set clone = LoadUnitHandle(udg_BladedanceHash, timerId, i)
if clone != null then
call DestroyEffect(AddSpecialEffect(udg_BladedanceExpireEffect, GetUnitX(clone), GetUnitY(clone)))
call RemoveUnit(clone)
endif
set i = i + 1
endloop
//destroy persistent aura effect created on cast
set startEffect = LoadEffectHandle(udg_BladedanceHash, timerId, 200)
if startEffect != null then
call BlzSetSpecialEffectAlpha(startEffect, 0)
call BlzSetSpecialEffectScale(startEffect, 0.01)
call DestroyEffect(startEffect)
endif
call FlushChildHashtable(udg_BladedanceHash, timerId)
call DestroyTimer(t)
set startEffect = null
set clone = null
set t = null
endfunction
private function StopClones takes nothing returns nothing
//This function makes clones stop when they reach their designed position
//To change those positions, use the premade GUI variables
//dont mess with this unless you know what you are doing
local timer t = GetExpiredTimer()
local integer timerId = GetHandleId(t)
local integer startIndex = LoadInteger(udg_BladedanceHash, timerId, 100)
local integer endIndex = LoadInteger(udg_BladedanceHash, timerId, 101)
local integer spellTimerId = LoadInteger(udg_BladedanceHash, timerId, 102)
local integer i = startIndex
local unit clone
loop
exitwhen i > endIndex
set clone = LoadUnitHandle(udg_BladedanceHash, spellTimerId, i)
if clone != null then
call IssueImmediateOrder(clone, "holdposition")
call BlzSetUnitRealField(clone, UNIT_RF_SPEED, 0.00)
endif
set i = i + 1
endloop
call FlushChildHashtable(udg_BladedanceHash, timerId)
call DestroyTimer(t)
set clone = null
set t = null
endfunction
private function CopyInventory takes unit caster, unit clone returns nothing
//Function that copies the casting heros inventory
//items given to clones that (drop on death) do not create dropped copies
//all on-hit functions are inherited by clones too
//to disable clones copying inventory, change BladedanceCopyItemsBool to False in variable init
local integer i = 0
local item casterItem
local item clonesItem
loop
exitwhen i >= bj_MAX_INVENTORY
set casterItem = UnitItemInSlot(caster, i)
if casterItem != null then
set clonesItem = CreateItem(GetItemTypeId(casterItem), GetUnitX(clone), GetUnitY(clone))
call UnitAddItem(clone, clonesItem)
endif
set i = i + 1
endloop
set casterItem = null
set clonesItem = null
endfunction
private function CopyPassiveAbilities takes unit caster, unit clone returns nothing
//this function copies passibe abilieties of heroes such as Critical Strike, bash, cleave, poison on hit etc...
//to add or remove abilities that the clone inherits, use GUI variables "BladedancePassives" in the variable init
local integer i = 1
local integer abilityId
local integer abilityLevel
loop
exitwhen i > udg_BladedancePassivesMax
set abilityId = udg_BladedancePassives[i]
set abilityLevel = GetUnitAbilityLevel(caster, abilityId)
if abilityLevel > 0 then
call UnitAddAbility(clone, abilityId)
call SetUnitAbilityLevel(clone, abilityId, abilityLevel)
endif
set i = i + 1
endloop
endfunction
private function Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local player owner
local timer t
local integer timerId
local timer stopTimer
local integer stopTimerId
local effect startEffect
local integer spellLevel
local integer casterLevel
local real multiplier
local integer strength
local integer agility
local integer intelligence
local integer i
local unit clone
local real casterX
local real casterY
local real facing
local real angle
local real targetX
local real targetY
//This event triggers when the casting of the ability begins to play an animation
//This is done because blizzard is fucking dogshit and the object editor natives doet work properly
if GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_CHANNEL then
call TriggerSleepAction(0.00)
call SetUnitAnimationByIndex(caster, 4)
set caster = null
return
endif
set owner = GetOwningPlayer(caster)
set t = CreateTimer()
set timerId = GetHandleId(t)
set i = 0
set spellLevel = GetUnitAbilityLevel(caster, udg_BladedanceAbility)
set casterLevel = GetHeroLevel(caster)
set casterX = GetUnitX(caster)
set casterY = GetUnitY(caster)
set facing = GetUnitFacing(caster)
//persistent aura effect that lasts as long as the clones
set startEffect = AddSpecialEffect("ManaAura_SpinEdit.mdx", casterX, casterY)
call BlzSetSpecialEffectAlpha(startEffect, 55)
call BlzSetSpecialEffectTimeScale(startEffect, 0.15)
call BlzSetSpecialEffectScale(startEffect, 8.75)
call SaveEffectHandle(udg_BladedanceHash, timerId, 200, startEffect)
if spellLevel == 1 then
set multiplier = 0.33
elseif spellLevel == 2 then
set multiplier = 0.66
else
set multiplier = 1.00
endif
//This part copies the heroes Str + Agi + Int and then gives it to the clone
set strength = R2I(GetHeroStr(caster, true) * multiplier)
set agility = R2I(GetHeroAgi(caster, true) * multiplier)
set intelligence = R2I(GetHeroInt(caster, true) * multiplier)
loop
exitwhen i >= 6
set angle = (90.00 - I2R(i) * 60.00) * bj_DEGTORAD
set targetX = casterX + udg_BladedanceOuterDistance * Cos(angle)
set targetY = casterY + udg_BladedanceOuterDistance * Sin(angle)
//clone creation (unit type of created clone is set in GUI Variable)
set clone = CreateUnit(owner, udg_BladedanceCloneUnitType, casterX, casterY, facing)
//disables XP for clone (important, dont touch)
call SuspendHeroXP(clone, true)
//Declares weather units should copy items or not from the hero based on Bool variable
if udg_BladedanceCopyItemsBool then
call CopyInventory(caster, clone)
endif
call SetHeroLevel(clone, casterLevel, false)
call SetHeroStr(clone, strength, true)
call SetHeroAgi(clone, agility, true)
call SetHeroInt(clone, intelligence, true)
//runs the function that copies passive abilities after checking for learned / level
call CopyPassiveAbilities(caster, clone)
//add 50 range to clones. Its ran for both 0 and 1 index because idk, it just doesnt work when i do 0 or 1 only...
call BlzSetUnitWeaponRealField(clone, UNIT_WEAPON_RF_ATTACK_RANGE, 0, BlzGetUnitWeaponRealField(clone, UNIT_WEAPON_RF_ATTACK_RANGE, 0) + udg_BladedanceBonusAttackRange)
call BlzSetUnitWeaponRealField(clone, UNIT_WEAPON_RF_ATTACK_RANGE, 1, BlzGetUnitWeaponRealField(clone, UNIT_WEAPON_RF_ATTACK_RANGE, 1) + udg_BladedanceBonusAttackRange)
//this function adds the cloned unit transparency. I didnt bother to variable this, but maybe i should?
//anyway if you want the clones to be MORE ghosty or LEES ghosty, just change the 200 at the end to 0-255 (255 is 0% transparent)
call SetUnitVertexColor(clone, 100, 100, 100, 200)
call IssuePointOrder(clone, "move", targetX, targetY)
call SaveUnitHandle(udg_BladedanceHash, timerId, i, clone)
//And now is just does the exact same thing again, for the second row of clones
set targetX = casterX + udg_BladedanceInnerDistance * Cos(angle)
set targetY = casterY + udg_BladedanceInnerDistance * Sin(angle)
set clone = CreateUnit(owner, udg_BladedanceCloneUnitType, casterX, casterY, facing)
//disables XP for clone (important, dont touch)
call SuspendHeroXP(clone, true)
if udg_BladedanceCopyItemsBool then
call CopyInventory(caster, clone)
endif
call SetHeroLevel(clone, casterLevel, false)
call SetHeroStr(clone, strength, true)
call SetHeroAgi(clone, agility, true)
call SetHeroInt(clone, intelligence, true)
call CopyPassiveAbilities(caster, clone)
call BlzSetUnitWeaponRealField(clone, UNIT_WEAPON_RF_ATTACK_RANGE, 0, BlzGetUnitWeaponRealField(clone, UNIT_WEAPON_RF_ATTACK_RANGE, 0) + udg_BladedanceBonusAttackRange)
call BlzSetUnitWeaponRealField(clone, UNIT_WEAPON_RF_ATTACK_RANGE, 1, BlzGetUnitWeaponRealField(clone, UNIT_WEAPON_RF_ATTACK_RANGE, 1) + udg_BladedanceBonusAttackRange)
call SetUnitVertexColor(clone, 100, 100, 100, 200)
call IssuePointOrder(clone, "move", targetX, targetY)
call SaveUnitHandle(udg_BladedanceHash, timerId, i + 6, clone)
set i = i + 1
endloop
//timer starting for expiration
set stopTimer = CreateTimer()
set stopTimerId = GetHandleId(stopTimer)
call SaveInteger(udg_BladedanceHash, stopTimerId, 100, 6)
call SaveInteger(udg_BladedanceHash, stopTimerId, 101, 11)
call SaveInteger(udg_BladedanceHash, stopTimerId, 102, timerId)
call TimerStart(stopTimer, udg_BladedanceInnerDistance / udg_BladedanceCloneMoveSpeed, false, function StopClones)
set stopTimer = CreateTimer()
set stopTimerId = GetHandleId(stopTimer)
call SaveInteger(udg_BladedanceHash, stopTimerId, 100, 0)
call SaveInteger(udg_BladedanceHash, stopTimerId, 101, 5)
call SaveInteger(udg_BladedanceHash, stopTimerId, 102, timerId)
call TimerStart(stopTimer, udg_BladedanceOuterDistance / udg_BladedanceCloneMoveSpeed, false, function StopClones)
call TimerStart(t, udg_BladedanceDuration, false, function Expire)
//locals cleaup
set startEffect = null
set caster = null
set owner = null
set clone = null
set t = null
set stopTimer = null
endfunction
//Function registering. DO NOT MESS WITH THIS unless you know what you are doing
private function Init takes nothing returns nothing
local trigger trig = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_CHANNEL)
call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trig, Condition(function Conditions))
call TriggerAddAction(trig, function Actions)
set trig = null
endfunction
endlibrary