//***************************************************************************************************
//* ========================
//* Venom Orb ver.1.0
//* ========================
//* Made by Shdow89
//*
//*
//* How to implement:
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* 1. Copy the spell "Venom Orb" to your map.
//*
//* 2. - Copy the unit "Venom Orb Dummy" to your map.
//* - Change the rawcode of the unit in the spell code.
//* - You can change the dummy unit model path (if you would like to look different), and it's scaling value (size).
//*
//* 3. Make a global variable of type unit group and name it damage_group (case sensitive).
//*
//* 4, Make a global variable of type unit and name it getdamager (case sensitive).
//*
//* 5. - Copy the trigger InitHashtable to your map.
//* - Copy the enitre enitre costum script section to your's in your map (icon, with the map name is the costum script section)
//* - Copy the trigger Venom Orb to your map.
//* - Change the spell raw codes in the spell code, and other data to what you desire.
//* - Enjoy
//* Choosable/Effects:
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* Go down through constant function and change to what you like. Units affected are:
//* Enemy Units, Non-Structure, Non-Magic Immune and living. You can change this in
//* function Venom_Orb_Pick_ActionFilter, after the if call.
//*
//*
//* Editor's Word:
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* This spell should acheive MUI grouping without having to use dynamic group creation.
//* At some point it's working, but as you may see I'm still using one dynamic group creation
//* (or maybe not). This spell should really be MUI and leak-less.
//*
//* Spells Action:
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* Sends an orb to the targeted area, dealing damage to unit it passes by, while leaving
//* a deadly posion on them. Units will take damage each 0.5 seconds for a short duration.
//* If the unit is moving it will receive 50 % more damage.
//*
//* Credits:
//* ¯¯¯¯¯¯¯¯
//* dgriff for help with groups.
//* Paskovich for floating text as an external system.
//*
//**************************************************************************************************************
constant function Venom_Orb_End_SFX takes nothing returns string
return "Abilities\\Weapons\\ChimaeraAcidMissile\\ChimaeraAcidMissile.mdl" // This effect is spawned when orb reaches it's destination, and when units get hit by it.
endfunction
constant function Venom_Orb_DoT_SFX takes nothing returns string
return "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl" // This effect is spawned every 0.5 (choosable) seconds on the poison affected unit.
endfunction
constant function Venom_Orb_ID takes nothing returns integer
return 'A000' // Venom Orb spell raw code. Change to yours.
endfunction
constant function Venom_Orb_Dummy_ID takes nothing returns integer
return 'h000' // Venom Orb Dummy unit raw code. Change to yours.
endfunction
constant function Venom_Orb_Travel_Dist takes integer i returns real
return 400.0 * i // How far does the orb travel before it's destroyed. 400 * level of Venom Orb.
endfunction
constant function Venom_Orb_Move_Speed takes nothing returns real
return 30.0 // How fast is the orb moving.
endfunction
constant function Venom_Orb_Pick_Radius takes nothing returns real
return 175.0 // Collision radius of the orb (with enemy units). AOE of the spell.
endfunction
constant function Venom_Orb_DoT_Time takes integer i returns real
return 1.0 * i // The duration of the Damage over Time effect. 1 * level of the Venom Orb seconds.
endfunction
constant function Venom_Orb_Init_Damage takes integer i returns real
return 25.0 * i // Initial damage that orb deals. When it coolides with the enemy units.
endfunction
constant function Venom_Orb_DoT_Damage takes integer i returns real
return 20.0 * i // The DoT damage. Damage enemy unit receives every -x- seconds.
endfunction
constant function Venom_Orb_DoT_MoveInc takes nothing returns real
return 0.5 // If the unit is moving, how much should damage be increased. 0.5 stands for 50 %. 1 stands for 100 %.
endfunction
constant function Venom_Orb_DoTimer_Loop takes nothing returns real
return 0.5 // Damage over Time durational loop effect. This means every 0.5 seconds unit will get damaged, until the DoT duration expires.
endfunction
constant function Venom_Orb_MoveTimer_Loop takes nothing returns real
return 0.03 // Timer loop speed for moving the dummy unit. I suggest you leave this as it is.
endfunction
//Done with constants. Don't touch anything below this if you are unsure.
//======================================================================================================================
function Venom_Orb_Conditions takes nothing returns boolean
return GetSpellAbilityId() == Venom_Orb_ID()
endfunction
//======================================================================================================================
//The DoT function for enemy units.
//===================================
function Venom_Orb_DoT takes nothing returns nothing
local timer dmg = GetExpiredTimer()
local unit tar = LoadUnitHandle(udg_NowHash, GetHandleId(dmg), 1)
local unit damager = LoadUnitHandle(udg_NowHash, GetHandleId(dmg), 4)
local real dur = LoadReal (udg_NowHash, GetHandleId(dmg), 2)
local real curDur = LoadReal (udg_NowHash, GetHandleId(dmg), 5)
local real x = LoadReal (udg_NowHash, GetHandleId(dmg), 6)
local real y = LoadReal (udg_NowHash, GetHandleId(dmg), 7)
local real x1 = GetUnitX (tar)
local real y1 = GetUnitY (tar)
local real damage = LoadReal (udg_NowHash, GetHandleId(dmg), 8)
if curDur < dur and IsUnitType(tar, UNIT_TYPE_DEAD) == false then
if x != x1 or y != y1 then
set damage = damage + (damage * Venom_Orb_DoT_MoveInc())
call UnitDamageTarget (damager, tar, damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_POISON, WEAPON_TYPE_WHOKNOWS)
call DestroyEffect (AddSpecialEffect (Venom_Orb_DoT_SFX(), x1, y1))
//Creating a floating text.
call FloatText (I2S(R2I(damage)) + "!", 0, 255, 0, x1, y1, 0.07, 0.5, 1.5)
call SaveReal (udg_NowHash, GetHandleId(dmg), 5, curDur + Venom_Orb_DoTimer_Loop())
call SaveReal (udg_NowHash, GetHandleId(dmg), 6, x1)
call SaveReal (udg_NowHash, GetHandleId(dmg), 7, y1)
set tar = null
set damager = null
set dmg = null
else
call UnitDamageTarget (damager, tar, damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_POISON, WEAPON_TYPE_WHOKNOWS)
call DestroyEffect (AddSpecialEffect (Venom_Orb_DoT_SFX(), x1, y1))
call SaveReal (udg_NowHash, GetHandleId(dmg), 5, curDur + Venom_Orb_DoTimer_Loop())
//Another floating text.
call FloatText (I2S(R2I(damage)) + "!", 0, 255, 0, x1, y1, 0.07, 0.5, 1.5)
call SaveReal (udg_NowHash, GetHandleId(dmg), 6, x1)
call SaveReal (udg_NowHash, GetHandleId(dmg), 7, y1)
set tar = null
set damager = null
set dmg = null
endif
else
call PauseTimer(dmg)
call DestroyTimer(dmg)
call FlushChildHashtable(udg_NowHash, GetHandleId(dmg))
set dmg = null
set tar = null
set damager = null
endif
endfunction
//===================================================================================
//Filter pick and add to DoT function for enemy units. Boolexpr as callback for group
//===================================================================================
function Venom_Orb_Pick_ActionFilter takes nothing returns boolean
local unit u = GetFilterUnit()
local timer dmg = null
if IsUnitEnemy(u, GetOwningPlayer(udg_getdamager)) == true and IsUnitType(u, UNIT_TYPE_STRUCTURE) == false and IsUnitType(u, UNIT_TYPE_DEAD) == false and IsUnitInGroup(u, udg_damage_group) == false then
call DestroyEffect (AddSpecialEffect(Venom_Orb_End_SFX(), GetUnitX(u), GetUnitY(u)))
call UnitDamageTarget(udg_getdamager, u, Venom_Orb_Init_Damage(GetUnitAbilityLevel(udg_getdamager, Venom_Orb_ID())), true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_POISON, WEAPON_TYPE_WHOKNOWS)
set dmg = CreateTimer()
call SaveUnitHandle (udg_NowHash, GetHandleId(dmg), 1, u)
call SaveUnitHandle (udg_NowHash, GetHandleId(dmg), 4, udg_getdamager)
call SaveReal (udg_NowHash, GetHandleId(dmg), 2, Venom_Orb_DoT_Time(GetUnitAbilityLevel(udg_getdamager, Venom_Orb_ID())))
call SaveReal (udg_NowHash, GetHandleId(dmg), 5, 0.0)
call SaveReal (udg_NowHash, GetHandleId(dmg), 6, GetUnitX(u))
call SaveReal (udg_NowHash, GetHandleId(dmg), 7, GetUnitY(u))
call SaveReal (udg_NowHash, GetHandleId(dmg), 8, Venom_Orb_DoT_Damage(GetUnitAbilityLevel(udg_getdamager, Venom_Orb_ID())))
call TimerStart (dmg, Venom_Orb_DoTimer_Loop(), true, function Venom_Orb_DoT)
set dmg = null
call GroupAddUnit (udg_damage_group, u)
endif
set u = null
return false
endfunction
//=======================================
//The function for moving the dummy unit.
//=======================================
function Venom_Orb_Move takes nothing returns nothing
local timer move = GetExpiredTimer()
local timer dmg = null
local unit miss = LoadUnitHandle(udg_NowHash, GetHandleId(move), 1)
local real tarX = LoadReal (udg_NowHash, GetHandleId(move), 2)
local real tarY = LoadReal (udg_NowHash, GetHandleId(move), 3)
local real uniX = GetUnitX (miss)
local real uniY = GetUnitY (miss)
local real dist = SquareRoot ((uniX - tarX) * (uniX - tarX) + (uniY - tarY) * (uniY - tarY))
local real angle = Atan2 (tarY - uniY, tarX - uniX)
local real moveX = uniX + Venom_Orb_Move_Speed() * Cos(angle)
local real moveY = uniY + Venom_Orb_Move_Speed() * Sin(angle)
if dist <= Venom_Orb_Move_Speed() or IsTerrainPathable(moveX, moveY, PATHING_TYPE_FLYABILITY) == true then
call PauseTimer(move)
call DestroyTimer(move)
call FlushChildHashtable(udg_NowHash, GetHandleId(move))
set move = null
call DestroyEffect(AddSpecialEffect(Venom_Orb_End_SFX(), uniX, uniY))
call RemoveUnit(miss)
call GroupClear(udg_damage_group)
set miss = null
else
call SetUnitPosition (miss, moveX, moveY)
set udg_getdamager = LoadUnitHandle(udg_NowHash, GetHandleId(move), 5)
set udg_damage_group = LoadGroupHandle(udg_NowHash, GetHandleId(move), 20)
call GroupEnumUnitsInRange(LoadGroupHandle(udg_NowHash, StringHash("Global G"), 0), moveX, moveY, Venom_Orb_Pick_Radius(), Condition(function Venom_Orb_Pick_ActionFilter))
call SaveGroupHandle(udg_NowHash, GetHandleId(move), 20, udg_damage_group)
set miss = null
set move = null
endif
endfunction
//===============================================
//The starting function. Action, on cast function
//=================================================
function Venom_Orb_Actions takes nothing returns nothing
local timer move = CreateTimer()
local unit cast = GetTriggerUnit()
local real angle = Atan2 (GetSpellTargetY() - GetUnitY(cast), GetSpellTargetX() - GetUnitX(cast))
local real crX = GetUnitX(cast) + 15.0 * Cos(angle)
local real crY = GetUnitY(cast) + 15.0 * Sin(angle)
local unit miss = CreateUnit(GetOwningPlayer(cast), Venom_Orb_Dummy_ID(), crX, crY, angle * bj_RADTODEG)
local real targetX = GetUnitX(cast) + Venom_Orb_Travel_Dist(GetUnitAbilityLevel(cast, Venom_Orb_ID())) * Cos(angle)
local real targetY = GetUnitY(cast) + Venom_Orb_Travel_Dist(GetUnitAbilityLevel(cast, Venom_Orb_ID())) * Sin(angle)
call SaveUnitHandle (udg_NowHash, GetHandleId(move), 1, miss)
call SaveUnitHandle (udg_NowHash, GetHandleId(move), 5, cast)
call SaveGroupHandle(udg_NowHash, GetHandleId(move), 20, CreateGroup())
call SaveReal (udg_NowHash, GetHandleId(move), 2, targetX)
call SaveReal (udg_NowHash, GetHandleId(move), 3, targetY)
call TimerStart (move, Venom_Orb_MoveTimer_Loop(), true, function Venom_Orb_Move)
set cast = null
set miss = null
set move = null
endfunction
//=====================================================================================================================================
// **INIT TRIGGER**
//============================
function InitTrig_Venom_Orb takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function Venom_Orb_Conditions))
call TriggerAddAction(t, function Venom_Orb_Actions)
call Preload(Venom_Orb_End_SFX())
call Preload(Venom_Orb_DoT_SFX())
call PreloadStart()
endfunction