//Mystic Snake by Zaio - http://www.hiveworkshop.com/forums/spells-569/mystic-snake-v1-5-a-204984/
//===================================================================================================================================
//To Import this spell:
//1 - Make sure you have installed TimerUtils (instructions on main page in the hidden tap called IMPORTANT:Requires)
//2 - Copy over the ability and dummy and edit them as you want
//3 - Create a hashtable named hash (if you already one named hash, skip to 4) by opening up variable editor (Ctrl + B)
//4 - Make sure "automatically create unknown variables when pasting trigger data" is enabled in map preferences
//5 - Copy over this trigger to your map
//6 - Edit the 2 configurables below for your map
constant function MSDID takes nothing returns integer
return 'h000' // The dummy's ID (ctrl + d in object editor)
endfunction
constant function MSAID takes nothing returns integer
return 'A000' // The ability's ID (ctrl + d in object editor)
endfunction
//7(Optional) - If you want the snake icon and model, export the imports used in this map and save their name along with their path into a word document (or something similar) open up your map and import the models, set their custom paths to the ones you wrote down earlier
//8(Optional) - Change the ability and dummy icons to ReplaceableTextures\CommandButtons\BTNMysticSnakeNew.blp then change the dummy's model file to MysticSnake.mdl
//9(Optional) - Change the tooltips (highly recommended) to your preference, they have been poorly done in the test map because it is all about the map they are running in, almost all maps use different base values for health on heros and units, therefore the tooltip will need to be changed accordingly.
//10(Optional) - Customize the dummy as wanted, reduce/increase its sight radius etc and change the configurables below.
//11 - DONE!
//======================================== CONFIGURABLES ============================================================================
function MSIBN takes nothing returns integer
return 3 // The base number of jumps + (level of ability * MSABN)
endfunction
function MSABN takes nothing returns integer
return 1 // The extra number of bounces per level (e.g. if this is set to 1 and MSIBN is set to 3, level 1 will bounce 4 times, level 2 will bounce 5 times etc)
endfunction
function MSIMB takes nothing returns real
return 70.00 // The mana burn base amount + (level of ability * MSAMB)
endfunction
function MSAMB takes nothing returns real
return 30.00 // The mana burn increment per level (e.g. if this is set to 30.00 and MSIMB is set to 70.00, level 1 will burn upto 100 base mana, level 2 upto 130 mana etc)
endfunction
function MSPDI takes nothing returns real
return 120.00 // This is the percentage of mana burn increase (if set to 120.00 = 20% increase per bounce)
endfunction
function MSEOM takes nothing returns string
return "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl" // The effect path if the snake returns to the caster
endfunction
function MSEOT takes nothing returns string
return "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl" // The effect path if the snake hits an enemy
endfunction
function MSEAM takes nothing returns string
return "chest" // The attachment point for the effect if the snake returns to the caster
endfunction
function MSEAT takes nothing returns string
return "overhead" // The attachment point for the effect if the snake hits an enemy
endfunction
function MSDPS takes nothing returns real
return 300.00 // This is the distance the snake will travel per second
endfunction
function MSRAOE takes nothing returns real
return 100.00 // This is the max distance the snake must be to return to the caster to restore mana
endfunction
function MSAAOE takes nothing returns real
return 50.00 // This is the max distance the snake must be to attack a unit and steal mana
endfunction
function MSSR takes nothing returns real
return 400.00 // This is the search radius the snake will check units in after it has mana burned a different unit
endfunction
//============================================ END CONFIGURABLES ==========================================================
//============================= DO NOT EDIT BELOW THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING! =================================
function MSFilter takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = not IsUnitInGroup(u, udg_Temp_Group) and IsUnitEnemy(u, GetOwningPlayer(udg_Temp_Unit)) and not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not IsUnitType(u, UNIT_TYPE_MECHANICAL) and not (GetUnitAbilityLevel(u, 'Bams') > 0) and not (GetUnitAbilityLevel(u, 'BHds') > 0)
set u = null
return b
endfunction
function Loop takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetHandleId(t)
local integer bn = LoadInteger(udg_hash, id, 3)
local unit s = LoadUnitHandle(udg_hash, id, 1)
local unit u
local unit u2
local unit u3
local unit u4 = LoadUnitHandle(udg_hash, id, 2)
local real x
local real x2
local real x3
local real y
local real y2
local real y3
local real a
local real d
local real m
local real m2
local real dx
local real dy
local group g
local real dmg
if 0 >= bn or u4 == null then
set u2 = LoadUnitHandle(udg_hash, id, 0)
if IsUnitType(u2, UNIT_TYPE_DEAD) then
set g = LoadGroupHandle(udg_hash, id, 4)
call DestroyGroup(g)
set g = null
call ReleaseTimer(t)
call KillUnit(s)
call FlushChildHashtable(udg_hash, id)
else
set x3 = GetUnitX(u2)
set y3 = GetUnitY(u2)
set x2 = GetUnitX(s)
set y2 = GetUnitY(s)
set dx = x3 - x2
set dy = y3 - y2
set d = SquareRoot(dx * dx + dy * dy)
if d <= MSRAOE() then
set m = LoadReal(udg_hash, id, 6)
call SetUnitState(u2, UNIT_STATE_MANA, (GetUnitState(u2, UNIT_STATE_MANA) + m))
call DestroyEffect(AddSpecialEffectTarget(MSEOM(), u2, MSEAM()))
set g = LoadGroupHandle(udg_hash, id, 4)
call DestroyGroup(g)
set g = null
call ReleaseTimer(t)
call KillUnit(s)
call FlushChildHashtable(udg_hash, id)
else
set a = Atan2(y3 - y2, x3 - x2)
set x = x2 + MSDPS() / 33. * Cos(a)
set y = y2 + MSDPS() / 33. * Sin(a)
call SetUnitX(s, x)
call SetUnitY(s, y)
call SetUnitFacing(s, (bj_RADTODEG * a))
endif
endif
set u2 = null
else
set x = GetUnitX(s)
set y = GetUnitY(s)
set u = LoadUnitHandle(udg_hash, id, 2)
set x2 = GetUnitX(u)
set y2 = GetUnitY(u)
set dx = x2 - x
set dy = y2 - y
set d = SquareRoot(dx * dx + dy * dy)
if d <= MSAAOE() then
if not IsUnitType(u, UNIT_TYPE_DEAD) then
set u3 = LoadUnitHandle(udg_hash, id, 0)
set dmg = LoadReal(udg_hash, id, 5)
set m2 = GetUnitState(u, UNIT_STATE_MANA)
set m = LoadReal(udg_hash, id, 6)
if dmg > m2 then
set m = (m + m2)
call SetUnitState(u, UNIT_STATE_MANA, 0.)
else
set m = (m + dmg)
call SetUnitState(u, UNIT_STATE_MANA, (GetUnitState(u, UNIT_STATE_MANA) - dmg))
endif
call UnitDamageTarget(u3, u, dmg, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
call DestroyEffect(AddSpecialEffectTarget(MSEOT(), u, MSEAT()))
call SaveReal(udg_hash, id, 6, m)
set dmg = (dmg * (MSPDI() / 100))
call SaveReal(udg_hash, id, 5, dmg)
set u3 = null
endif
set udg_Temp_Group = LoadGroupHandle(udg_hash, id, 4)
call GroupAddUnit(udg_Temp_Group, u)
set udg_Temp_Unit = s
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, MSSR(), Filter(function MSFilter))
set u2 = FirstOfGroup(bj_lastCreatedGroup)
if u2 != null then
call SaveUnitHandle(udg_hash, id, 2, u2)
set bn = (bn - 1)
call SaveInteger(udg_hash, id, 3, bn)
set u2 = null
else
call RemoveSavedHandle(udg_hash, id, 2)
endif
else
set a = Atan2(y2 - y, x2 - x)
set x3 = x + MSDPS() / 33. * Cos(a)
set y3 = y + MSDPS() / 33. * Sin(a)
call SetUnitX(s, x3)
call SetUnitY(s, y3)
call SetUnitFacing(s, (bj_RADTODEG * a))
endif
set u = null
endif
set t = null
set s = null
set u4 = null
endfunction
function Start takes nothing returns boolean
local unit u
local timer t
local unit u2
local real x
local real y
local integer id
if GetSpellAbilityId() == MSAID() then
set t = NewTimer()
set id = GetHandleId(t)
set u = GetTriggerUnit()
set x = GetUnitX(u)
set y = GetUnitY(u)
set u2 = GetSpellTargetUnit()
set bj_lastCreatedUnit = CreateUnit(GetTriggerPlayer(), MSDID(), x, y, bj_RADTODEG * Atan2(GetUnitY(u2) - y, GetUnitX(u2) - x))
call TimerStart(t, 0.03125, true, function Loop)
call SaveUnitHandle(udg_hash, id, 0, u)
call SaveUnitHandle(udg_hash, id, 1, bj_lastCreatedUnit)
call SaveUnitHandle(udg_hash, id, 2, u2)
call SaveInteger(udg_hash, id, 3, MSIBN() + (MSABN() * GetUnitAbilityLevel(u, MSAID())))
call SaveGroupHandle(udg_hash, id, 4, CreateGroup())
call SaveReal(udg_hash, id, 5, (MSIMB() + (MSAMB() * GetUnitAbilityLevel(u, MSAID()))))
set u = null
set u2 = null
set t = null
endif
return false
endfunction
function InitTrig_Mystic_Snake takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Start ) )
if udg_hash == null then
set udg_hash = InitHashtable()
endif
set t = null
endfunction