// CONFIGURATION
// Constants
// Main spell raw code
constant function LB_GetSpellID takes nothing returns integer
return 'A005'
endfunction
// Stun raw code
constant function LB_GetStunID takes nothing returns integer
return 'A000'
endfunction
// Spell book raw code
constant function LB_GetSpellBookID takes nothing returns integer
return 'A001'
endfunction
// Caster dummy raw code
constant function LB_DummyCasterID takes nothing returns integer
return 'h000'
endfunction
// Target effect
constant function LB_Sfx takes nothing returns string
return "Abilities\\Spells\\Demon\\DarkPortal\\DarkPortalTarget.mdl"
endfunction
// Charge effect
constant function LB_ChargeSfx takes nothing returns string
return "Abilities\\Spells\\Orc\\Shockwave\\ShockwaveMissile.mdl"
endfunction
// Caster effect
constant function LB_Sfx1 takes nothing returns string
return "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
endfunction
// Attachment point
constant function LB_AttachPoint takes nothing returns string
return "origin"
endfunction
// Movement interval
constant function LB_Interval takes nothing returns real
return 0.03125
endfunction
// Booleans
// Should Smart Charge be enabled?
// True = enable Smart Charge, the Hero will choose another nearby valid unit to charge at
// if he is unable to reach the original target.
// False = disable Smart Charge
constant function LB_SmartCharge takes nothing returns boolean
return true
endfunction
// Filter valid units for Smart Charge
function LB_FilterUnit takes unit caster, unit u returns boolean
return IsUnitEnemy(u, GetOwningPlayer(caster)) and GetWidgetLife(u) > 0.405 and GetUnitAbilityLevel(u, 'Avul') == 0 and not IsUnitType (u, UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitType (u, UNIT_TYPE_STRUCTURE)
endfunction
// AoE check for Smart Charge
constant function LB_AoE takes nothing returns real
return 600.
endfunction
// Get Abilities Level
function LB_SpellLvl takes unit caster returns integer
return GetUnitAbilityLevel (caster, LB_GetSpellID()) // Get the spell level of the caster
endfunction
// Level dependable values
// Main target damage
function LB_DamageEnemy takes integer level returns real
return 45. + level*5.
endfunction
// Self damage
function LB_DamageSelf takes integer level returns real
return 40. - level*5.
endfunction
// Charge Speed
function LB_Speed takes integer level returns real
return (1000. + level*100.)/(1/LB_Interval())
endfunction
// Attack - Damage - Weapon type
// Attack type
function LB_AttackType takes nothing returns attacktype
return ATTACK_TYPE_HERO
endfunction
// Damage type
function LB_DamageType takes nothing returns damagetype
return DAMAGE_TYPE_MAGIC
endfunction
// Weapon type
function LB_WeaponType takes nothing returns weapontype
return WEAPON_TYPE_WHOKNOWS
endfunction
// END CONFIGURATION
// PRELOAD
function LB_Preload takes nothing returns nothing
local unit u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), LB_DummyCasterID(), 0, 0, 0.00)
local integer i = 0
call UnitAddAbility(u, LB_GetSpellID())
call UnitAddAbility(u, LB_GetStunID())
call UnitAddAbility(u, LB_GetSpellBookID())
loop
call SetPlayerAbilityAvailable(Player(i), LB_GetSpellBookID(), false)
set i = i + 1
exitwhen i > 15
endloop
call RemoveUnit (u)
set u = null
endfunction
// END PRELOAD
// PATHING CHECK
function LB_HideItems takes nothing returns nothing
if IsItemVisible (GetEnumItem()) then
set udg_LB_ItemArray[udg_LB_Integer] = GetEnumItem()
call SetItemVisible (udg_LB_ItemArray[udg_LB_Integer], false)
set udg_LB_Integer = udg_LB_Integer + 1
endif
endfunction
function LB_IsPathable takes real x, real y, item i returns boolean
local real x1
local real y1
call MoveRectTo (LoadRectHandle (udg_LB_Hashtable, -3, -1), x, y)
call EnumItemsInRect (LoadRectHandle (udg_LB_Hashtable, -3, -1), null, function LB_HideItems)
call SetItemPosition (i, x, y)
set x1 = GetItemX(i) - x
set y1 = GetItemY(i) - y
call SetItemVisible(i, false)
loop
exitwhen udg_LB_Integer <= 0
set udg_LB_Integer = udg_LB_Integer - 1
call SetItemVisible (udg_LB_ItemArray[udg_LB_Integer], true)
set udg_LB_ItemArray[udg_LB_Integer] = null
endloop
return x1*x1 + y1*y1 < 256 and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
// END PATHING CHECK
// SPELL FUNCTIONS
// Here we create a list of units that can be picked from
function LB_MakeList takes nothing returns boolean
local unit u = GetFilterUnit()
local integer i = LoadInteger(udg_LB_Hashtable, -4, 0)
local integer ID = LoadInteger(udg_LB_Hashtable, -4, -3)
local boolean b = LB_FilterUnit(LoadUnitHandle(udg_LB_Hashtable, -4, -2), u) and u != LoadUnitHandle(udg_LB_Hashtable, -4, -1) and not IsUnitInGroup(u, LoadGroupHandle(udg_LB_Hashtable, ID, 8))
if b then
set i = i + 1
call SaveUnitHandle(udg_LB_Hashtable, -4, i, u)
endif
call SaveInteger(udg_LB_Hashtable, -4, 0, i)
set u = null
return false
endfunction
// The loop where we index, deindex, and recycle everything
function LB_TimerLoop takes nothing returns nothing
local integer ID
local integer listmax = LoadInteger(udg_LB_Hashtable, -1, 0 )
local unit caster
local unit target
local unit dummy
local integer i = 0
local real x1
local real y1
local real x2
local real y2
local real x3
local real y3
local real x4
local real y4
local real angle
local integer level
local group g
local integer i1
local boolean b
local group g1
// Now we start looping through all the spell instances
loop
exitwhen i >= listmax
// First we load the saved values of a spell instance
set i = i + 1
set ID = LoadInteger (udg_LB_Hashtable, -1, i)
set caster = LoadUnitHandle (udg_LB_Hashtable, ID, 1)
set target = LoadUnitHandle (udg_LB_Hashtable, ID, 2)
set dummy = LoadUnitHandle (udg_LB_Hashtable, ID, 4)
set level = LB_SpellLvl (caster)
set x1 = GetUnitX (caster)
set y1 = GetUnitY (caster)
set x2 = GetUnitX (target)
set y2 = GetUnitY (target)
set g1 = LoadGroupHandle (udg_LB_Hashtable, ID, 8)
if (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) < 22500 then
call UnitRemoveAbility(caster, LB_GetSpellBookID())
call SetUnitTurnSpeed(caster, GetUnitDefaultTurnSpeed(caster))
call DestroyEffect(AddSpecialEffectTarget(LB_Sfx1(), caster, LB_AttachPoint()))
call DestroyEffect(AddSpecialEffectTarget(LB_Sfx(), target, LB_AttachPoint()))
call DestroyEffect(LoadEffectHandle(udg_LB_Hashtable, ID, 3))
call SetUnitState(caster, UNIT_STATE_LIFE, GetUnitState(caster, UNIT_STATE_LIFE)*(1 - (LB_DamageSelf(level)/100)))
call UnitDamageTarget(caster, target, GetUnitState(target, UNIT_STATE_LIFE)*(LB_DamageEnemy(level)/100), false, false, LB_AttackType(), LB_DamageType(), LB_WeaponType())
call IssueTargetOrder(caster, "attack", target)
call UnitAddAbility(dummy, LB_GetStunID())
call SetUnitX(dummy, x2)
call SetUnitY(dummy, y2)
call IssueTargetOrder(dummy, "thunderbolt", target)
call KillUnit(dummy)
call DestroyGroup (g1)
if listmax != i then
call SaveInteger (udg_LB_Hashtable, LoadInteger (udg_LB_Hashtable, -1, listmax), 0, i)
call SaveInteger (udg_LB_Hashtable, -1, i, LoadInteger (udg_LB_Hashtable, -1, listmax))
call RemoveSavedInteger (udg_LB_Hashtable, -1, listmax)
set i = i - 1
endif
set listmax = listmax - 1
call SaveInteger (udg_LB_Hashtable, -1, 0, listmax)
if LoadInteger (udg_LB_Hashtable, 0, 0) + 1 == LoadInteger (udg_LB_Hashtable, 0, -1) then
call FlushChildHashtable (udg_LB_Hashtable, 0)
call PauseTimer (LoadTimerHandle (udg_LB_Hashtable, -2, 0))
else
call SaveInteger (udg_LB_Hashtable, 0, 0, LoadInteger (udg_LB_Hashtable, 0, 0) + 1)
call SaveInteger (udg_LB_Hashtable, 0, LoadInteger (udg_LB_Hashtable, 0, 0), ID)
endif
call FlushChildHashtable (udg_LB_Hashtable, ID)
else
set b = LoadBoolean (udg_LB_Hashtable, ID, 7)
if b then
call UnitRemoveAbility(caster, LB_GetSpellBookID())
call SetUnitTurnSpeed(caster, GetUnitDefaultTurnSpeed(caster))
call KillUnit(dummy)
call DestroyEffect(LoadEffectHandle(udg_LB_Hashtable, ID, 3))
call DestroyGroup (g1)
if listmax != i then
call SaveInteger (udg_LB_Hashtable, LoadInteger (udg_LB_Hashtable, -1, listmax), 0, i)
call SaveInteger (udg_LB_Hashtable, -1, i, LoadInteger (udg_LB_Hashtable, -1, listmax))
call RemoveSavedInteger (udg_LB_Hashtable, -1, listmax)
set i = i - 1
endif
set listmax = listmax - 1
call SaveInteger (udg_LB_Hashtable, -1, 0, listmax)
if LoadInteger (udg_LB_Hashtable, 0, 0) + 1 == LoadInteger (udg_LB_Hashtable, 0, -1) then
call FlushChildHashtable (udg_LB_Hashtable, 0)
call PauseTimer (LoadTimerHandle (udg_LB_Hashtable, -2, 0))
else
call SaveInteger (udg_LB_Hashtable, 0, 0, LoadInteger(udg_LB_Hashtable, 0, 0) + 1)
call SaveInteger (udg_LB_Hashtable, 0, LoadInteger(udg_LB_Hashtable, 0, 0), ID)
endif
call FlushChildHashtable (udg_LB_Hashtable, ID)
else
if IsUnitType(caster, UNIT_TYPE_DEAD) then
call SaveBoolean (udg_LB_Hashtable, ID, 7, true)
else
set angle = Atan2(y2-y1, x2-x1)
set x3 = LoadReal (udg_LB_Hashtable, ID, 5)
set y3 = LoadReal (udg_LB_Hashtable, ID, 6)
set x4 = x1 + (LB_Speed(level))*Cos(angle)
set y4 = y1 + (LB_Speed(level))*Sin(angle)
call SaveReal (udg_LB_Hashtable, ID, 5, x2)
call SaveReal (udg_LB_Hashtable, ID, 6, y2)
if IsUnitType(target, UNIT_TYPE_DEAD) or (x3-x2)*(x3-x2) + (y3-y2)*(y3-y2) > 1960000 or not LB_IsPathable(x4, y4, LoadItemHandle (udg_LB_Hashtable, -3, 0)) then
if LB_SmartCharge() then
call GroupAddUnit (g1, target)
set g = CreateGroup()
call SaveUnitHandle(udg_LB_Hashtable, -4, -1, target)
call SaveUnitHandle(udg_LB_Hashtable, -4, -2, caster)
call SaveInteger(udg_LB_Hashtable, -4, -3, ID)
call GroupEnumUnitsInRange(g, x1, y1, LB_AoE(), Condition(function LB_MakeList))
call DestroyGroup(g)
set g = null
set i1 = LoadInteger(udg_LB_Hashtable, -4, 0)
if i1 == 0 then
call SaveBoolean (udg_LB_Hashtable, ID, 7, true)
else
call SaveUnitHandle(udg_LB_Hashtable, ID, 2, LoadUnitHandle(udg_LB_Hashtable, -4, GetRandomInt(1, i1)))
call FlushChildHashtable(udg_LB_Hashtable, -4)
endif
else
call SaveBoolean (udg_LB_Hashtable, ID, 7, true)
endif
else
// Move the caster
call SetUnitX (caster, x4)
call SetUnitY (caster, y4)
call SetUnitFacing (caster, angle*bj_RADTODEG)
endif
endif
endif
endif
set dummy = null
set caster = null
set target = null
set g1 = null
endloop
endfunction
// Initiate function
function Trig_LB_Conditions takes nothing returns boolean
local unit caster
local unit target
local integer ID
local integer listmax
if GetSpellAbilityId() == LB_GetSpellID() then
set caster = GetTriggerUnit()
call UnitAddAbility(caster, LB_GetSpellBookID())
call SetUnitTurnSpeed (caster, 0)
set target = GetSpellTargetUnit()
set ID = LoadInteger (udg_LB_Hashtable, 0, 0)
// Now we start indexing the main projectiles
if ID>0 then
call SaveInteger (udg_LB_Hashtable, 0, 0, ID - 1)
set ID = LoadInteger (udg_LB_Hashtable, 0, ID)
else
set ID = LoadInteger (udg_LB_Hashtable, 0, -1) + 1
call SaveInteger (udg_LB_Hashtable,0 , -1, ID)
if ID == 1 then
call TimerStart (LoadTimerHandle (udg_LB_Hashtable, -2, 0), LB_Interval(), true, function LB_TimerLoop)
endif
endif
// Save the values related to this spell instance
call SaveUnitHandle (udg_LB_Hashtable, ID, 1, caster)
call SaveUnitHandle (udg_LB_Hashtable, ID, 2, target)
call SaveEffectHandle (udg_LB_Hashtable, ID, 3, AddSpecialEffectTarget(LB_ChargeSfx(), caster, LB_AttachPoint()))
call SaveUnitHandle (udg_LB_Hashtable, ID, 4, CreateUnit(GetOwningPlayer(caster), LB_DummyCasterID(), GetUnitX(caster), GetUnitY(caster), 0.00))
call SaveReal (udg_LB_Hashtable, ID, 5, GetUnitX(target))
call SaveReal (udg_LB_Hashtable, ID, 6, GetUnitY(target))
call SaveGroupHandle (udg_LB_Hashtable, ID, 8, CreateGroup())
set listmax = LoadInteger (udg_LB_Hashtable, -1, 0) + 1
call SaveInteger(udg_LB_Hashtable, -1, 0, listmax )
call SaveInteger (udg_LB_Hashtable, -1, listmax, ID)
call SaveInteger (udg_LB_Hashtable, ID, 0, listmax)
set caster = null
set target = null
endif
return false
endfunction
//===========================================================================
function InitTrig_Life_Break takes nothing returns nothing
local trigger t = CreateTrigger()
set udg_LB_Hashtable = InitHashtable()
call LB_Preload()
call SaveTimerHandle (udg_LB_Hashtable, -2, 0, CreateTimer())
call SaveItemHandle (udg_LB_Hashtable, -3, 0, CreateItem('afac', 0, 0))
call SaveRectHandle (udg_LB_Hashtable, -3, -1, Rect (0, 0, 128, 128))
call SetItemVisible (LoadItemHandle (udg_LB_Hashtable, -3, 0), false)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition( function Trig_LB_Conditions ) )
set t = null
endfunction