1. Are you planning to upload your awesome map to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still haven't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. Join the 6th Melee Mapping Contest for a chance to have your map featured in this year's Hive Cup!
    Dismiss Notice
  5. Shoot to thrill, play to kill. Sate your hunger with the 33rd Modeling Contest!
    Dismiss Notice
  6. Do you hear boss music? It's the 17th Mini Mapping Contest!
    Dismiss Notice
  7. Let your favorite entries duke it out in the 15th Techtree Contest Poll.
    Dismiss Notice
  8. Weave light to take you to your highest hopes - the 6th Special Effect Contest is here!
    Dismiss Notice
  9. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Trigger Viewer

Impossible Siege 2.06b Reforged.w3x
Variables
Variables
Impossible Siege Core
MapGeneral
Defines
Angles Library
Dummy Casts Library
unit hashtable keys 1
unit hashtable keys 2
Floating Text Library
HashProcCooldown
HashtableUtils
ItemHashtableUtils
Damage Event Methods
Damage Event
Healing Even Methods
Healing Event
RefreshDamageTriggers
Out Of Combat
Creep Aggro System
Aggro Bar
Shield System
---------------------------
MakeUnitPassive
IsUnitDead
ListModule
RegionalFog
GetTerrainZ library
TerrainPathAbility
Knockbackable and Giant
Parabola Movement
MakeUnitFall
Damage Over Time
AddHeroMS
AddHeroParameter Lib
AggroWarning
FadeInTime Lib
ini
Handle Counter
Restart the Game
Victory
PreloadingArrays
Preloading On
Fog Init
map ini
multiHeroRegime
DifficultiesChoosing
unit ini
ClearDiedUnits
no ally attack
Upgrade Balance
commands
Tips
Commands
Red Commands
Camera Settings
Camera Settings New
clear
suicide
test
testAnim
test
move 0
move 1
move 2
move 3
move 4
move 5
move 6
level
camera
PlayerCameraBound
Change Camera Bound
Debug
camera bounds chapter1
camera bounds chapter2
camera bounds chapter3
camera bounds moltencore
camera bounds stonecore
camera bounds eredars
camera bounds island
heroes,boards,players ini
Player Mouse Event
player hashtable keys
Hero ini
Hero picked
HeroLevelUp
HeroExperience
Attributes Improvement
multiboard
Multiboard on Click
Hero Stats Little
Hero Stats Big
Hero Stats refresh
Aggro Table
Refresh Aggro Table
hero revival
Hero Dies
players
LeavetheGame
MoneyCash
items ini
Items Initializer
Items Descriptor
Items PickUp
Item Sell
Item Lose
Item Upgrade
chargesonactives
itembaseitems
itembasehashkeys
itembasehashadds
itemget
itemlose
item abilities
Troggbane
Heavens Fall
Barrier Shield
Coldwraith Plate
Lightbringer Chest
Abomination Ribcage
Firehand Gauntlets
Demon Stalker Gauntlets
Gloves of Holy Might
Helm of the Elder Moon
Broken Ram Skull Helm
Daybreaker Helm
Frostbrood Sapphire Ring
Tome of the Ice Lord
Book of Binding Will
Book of Highborne Hymns
potions
Potions BASE
PotionsUtils
BookOfOblivion
Potions Library
Charges Stacks Library
Dropped Charged
chapter 1
Waves
C1 waves Init
C1 defeat
Voting to Restart
Failed Voting
first cinematic
c1 battle ini
c1 sec ini
c1 Ends
waves
Left Waves C1
Right Waves C1
Middle Waves C1
SpecWaves C1
KnockUnitsC1
=====
Creep Abilities
Heroism Warlock
Chaos Meteor Chosen Seer
Ignition Matron
Punishment Succubus
Legion Strike Felguard
Stampede Salamander
Mana Ejection Voidwalker
Vortex Zarshuull
chapter 2
C2 Spawns Library
Meteor Strike Library
chapter2 teleport
C2 defeat
chapter 2 ini
C2 Units ini
C2 Cinematic
C2 waves ini
C2 Ends
waves
METEOR RAIN
TOP Waves C2
RIGHT TOP Waves C2
RIGHT BOT Waves C2
Rock Golem
Mud Golem
GolemAbsorb
chapter 3
Chapter3StonecoreTeleport
Chapter3EnterLocation
Chapter3Init
Chapter3Start
Chapter3Waves
BurnTree Faceless
BurnTree Walker
BurnTree Arsonist
AttackTreeMelee
AttackTreeRanged
Chapter3Defeat
Pit Lords
PitLordsActions
PitLordCharge
PitLordFelHammer
PitLordHellfirePortal
island
IslandEnterLocation
Molten Core (Magmaw)
Molten Core Teleport
Molten Core Teleport Back
molten core ini
magmaw preload
magmaw sumtimer
magmaw ini
magmaw summon effect
The Stonecore(Supremus)
Stonecore Teleport
Stonecore Teleport Back
stonecore ini
supremus preload
supremus sumtimer
supremus ini
EredarsAbyss (Eredars)
EredarsAbyssTeleport
EredarsAbyssEnter
heroes
SPELL HASH KEYS
AbilityDescriptor
AbilityDescriptor
Horde Champion
Horde Champion Talents
Battle Standard
Massacre
Blood Hurricane
Berserk
Heroic Leap
Heroic Leap Loop
Sorceress
Sorceress Talents
Dragons Roar
Arcane Beam
Icy Disaster
Ice Impale
Piercing Ice
Global Annihilation
Tribal Shaman
Shaman Talents
Wolf Form NO CAST
Healing Rain
Chain Heal
Mana Spring Totem
Heroism
Bloodelf Captain
Bloodelf CaptainTalents
Taunt
Shield Wall
Intervene
Shield Slam
Weapon Clap
CaptainAbilityTooltips
Stonebreaker
Stonebreaker Talents
Earthquake
Boulder Falls
Rodeo
Rodeo Cancel
Ragging Charge
Burning Totem Effect
Druid of the Grove
Druid Talents
Rebirth
Lifebloom
Regrowth
Mark of the Wild
Tree of Life
Death Knight
Ranger
Death Knight Talents
Death Grip
Frostwyrms Fury
Frostmourne
PresenceOfTheLichKing
Obliteration
unused
Hands of Death
Death Coil
Bone Barrier
Ranger Talents
Summon Wofl
Cobra Shot
Chakram Trap
KIll Command
Chimaera Shot
Priest
Priest Talents
Guardian Spirit
Flash Heal
Prayer of Healing
Shield of Faith
Divine Hymn
Eretic
EreticAbilitiesSwitch
Bone Storm
bosses
Magmaw
Magma Slam
Magma Slam Acts
Magma Wave
Magma Wave Acts
Magma Burrow
Magma Burrow Move
Damage Stone
Magmaw defeat
Magmaw BattleGroup New
Supremus
Chaos Meteor
Meteor Cast
Step Clap
SupremusCharge
Catapult Strike
AbyssCall
Supremus defeat
Supremus defeat procceed
Supremus BattleGroup
Eredars
EredarsChange
EredarsVoid
EredarsCast
EredarsSargeras
EredarsDefeat
Eredars BattleGroup
Enter map-specific custom script code below. This text will be included in the map script after variables are declared and before any trigger code.

		
Name Type Is Array Initial Value
ABoard multiboard Yes
Abysal_Catapult timer No
BOSSENCOUNTER_Group group No
C1_Garrosh unit No
C1_Timer timer No
C1_TWindow timerdialog No
C1_Vendors unit Yes
C2_ENDTIMER timer No
C2_ENDTIMERWINDOW timerdialog No
C2_Footmans group No
C2_Timerini timer No
C2_TimerStart timer No
C_Spawns location Yes
Catapult unit No
ChapterTimer timer No
Classhash integer Yes
ColCharge_Timer timer No
ColorString string Yes
Crit_Chance real Yes
Dummy_Group group No
Evade_Chance real Yes
GA_Caster unit No
GA_Duration real No
Hall_of_Fame unit No
hash hashtable No
Hero unitcode Yes
HeroClass string Yes
HeroCount integer No
Heroes unit Yes
HeroIcon string Yes
HL_Angle real No
HL_Caster unit No
HL_Damage real No
HL_Distance real No
HL_Effect effect No
HL_FlySpeed real No
HL_Points location Yes
HL_Speed real No
ID_Caster unit No
ID_Damage real No
ID_Point location No
ID_Timer timer No
Item_Adds1 real Yes
Item_Adds2 real Yes
Item_Count integer No
Item_hashslot1 integer Yes
Item_hashslot2 integer Yes
Item_Main itemcode Yes
Kills integer Yes
KingOfStormwind unit No
LeakPoint location Yes
LeftTimer timer No
LoopInteger integer No
Magmaw unit No
Magmaw_Burow2 timer No
Magmaw_Burrow timer No
Magmaw_BurTimes integer No
Magmaw_Firebreath timer No
Magmaw_IsBurrow boolean No
Magmaw_Slam timer No
Magmawini_timer timer No
MagmawLocVisited boolean Yes
MagS_Degree real No
MagS_Effect effect No
MagS_Int integer No
MBoard multiboard Yes
Meteor_Timer timer No
MeteorStrike_Timer timer No
MeteorStrike_Window timerdialog No
MiddleTimer timer No
Molten_Preload integer Yes
NBoard multiboard Yes
PlayerCount integer No
Players player Yes
Players_Group force No
PlayersInGame integer No
Potions_COUNT integer No
Potions_DISABLED itemcode Yes
Potions_ORIGIN itemcode Yes
Potions_RUNE itemcode Yes
RightTimer timer No
Selector unit Yes
SimError sound No
Singleplayer boolean No
SoloModeDialog dialog No
SoloModeMultiButton button No
SoloModeSoloButton button No
SPD_Bonus real Yes
Spec_WaveC1_Timer timer No
Spec_WaveCount integer No
Spec_WaveUnits unitcode Yes
Special_WaveC1_Window timerdialog No
SpiritHealerLoc location Yes
Supremus unit No
SupremusTimer timer No
temp_force force No
temp_group group No
temp_int integer No
temp_real real No
temp_str string No
Temp_Unit unit No
temp_unit unit No
Tips string Yes
Tips_Force force No
TipsCount integer No
Votes integer No
Voting_Group force No
VotingTimer timer No
library MapGameplayUtils

globals
//integer DD_Count = 1
//integer ME_Count = 3
//integer ST_Count = 5
//integer TR_Count = 6

player ORGRIMMAR = Player(6)
player INVADERS = Player(7)
player STORMWIND = Player(8)
player DARNASSUS = Player(9)
endglobals

function IsUnitAPlayerHero takes unit u returns boolean
    local integer i = 1
    loop
       exitwhen i > udg_PlayerCount
       if udg_Heroes[i] == u then
          return true
       endif
       set i = i + 1
    endloop
    return false
endfunction

function AddLocalEffectTarget takes unit u, string eff, string attach, player pl returns effect
local string e = ""
if GetLocalPlayer() == pl then
 set e = eff
endif
return AddSpecialEffectTarget(e, u, attach)
endfunction

function StopCameraShake takes nothing returns nothing
 local timer t = GetExpiredTimer()
 local player p = LoadPlayerHandle(udg_hash,GetHandleId(t),1)
 call CameraClearNoiseForPlayer(p)
 call FlushChildHashtable(udg_hash,GetHandleId(t))
 call DestroyTimer(t)
 set t = null
 set p = null
endfunction

function MoltenCore takes player whichPlayer,integer red,integer green,integer blue returns nothing
 if GetLocalPlayer() == whichPlayer then
  call SetWaterBaseColor(red,green,blue,255)
 endif
endfunction
 
function OrkTown takes player whichPlayer returns nothing
 if GetLocalPlayer() == whichPlayer then
  call SetWaterBaseColor(0,100,250,255)
 endif
endfunction

function SimError takes player ForPlayer, string msg returns nothing
  if udg_SimError==null then
    set udg_SimError=CreateSoundFromLabel( "InterfaceError",false,false,false,10,10)
  endif
  if (GetLocalPlayer() == ForPlayer) then
    call ClearTextMessages()
    call DisplayTimedTextToPlayer( ForPlayer, 0.52, -1.00, 2.00, "|cffffcc00"+msg+"|r" )
    call StartSound( udg_SimError )
  endif
endfunction

function GoldTextTag takes string s, real x,real y returns nothing
local texttag tt = CreateTextTag()
call SetTextTagText(tt, s, 0.023)
call SetTextTagPos(tt,x,y,55.)
call SetTextTagPermanent(tt,false)
call SetTextTagLifespan(tt,1.5)
call SetTextTagVelocityBJ(tt,55.,90.)
call ShowTextTagForceBJ(true,tt,udg_Players_Group)
set tt = null
endfunction

/*
function GetHeroType takes integer u returns string
     if u<=DD_Count then
      return "Damage Dealer"
     elseif (u>DD_Count) and u<=ME_Count then
      return "Mage"
     elseif (u>ME_Count) and (u<=ST_Count) then
      return "Support"
     else
      return "Tanker"
     endif
  return "Error"
endfunction
*/


endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//globals
//constant mapcontrol USER = MAP_CONTROL_USER
//constant unitstate UNIT_LIFE = UNIT_STATE_LIFE
//constant unitstate UNIT_MANA = UNIT_STATE_MANA
//constant unitstate UNIT_MAX_LIFE = UNIT_STATE_MAX_LIFE
//constant unitstate UNIT_MAX_MANA = UNIT_STATE_MAX_MANA
//constant playerunitevent SPELL_EFFECT = EVENT_PLAYER_UNIT_SPELL_EFFECT
//constant playerevent PLAYER_CHAT = EVENT_PLAYER_CHAT
//constant unittype TYPE_DEAD = UNIT_TYPE_DEAD
//constant unittype TYPE_HERO = UNIT_TYPE_HERO
//endglobals
//TESH.scrollpos=1
//TESH.alwaysfold=0
library Angles

function ConvertAngleTo180 takes real a returns real
if a < -180. then
  return 360.+a
elseif a > 180. then
  return a-360.
endif
return a
endfunction

function DifferenceBetweenAngles takes real a1, real a2 returns real
  return RAbsBJ(ConvertAngleTo180(ConvertAngleTo180(a2)-ConvertAngleTo180(a1)))
endfunction

endlibrary
//TESH.scrollpos=20
//TESH.alwaysfold=0
library DummyCasts //'h009' - dummy rawcode

function DummyCastTarget takes unit owner, unit target,integer abilid,integer abillvl,string order returns nothing
local real x = GetUnitX(owner)
local real y = GetUnitY(owner)
local unit a = CreateUnit(GetOwningPlayer(owner),'h009',x,y,0.)
      call UnitAddAbility(a,abilid)
      call SetUnitAbilityLevel(a,abilid,abillvl)
      call IssueTargetOrder(a,order,target)
      call UnitApplyTimedLife(a,'BHwe',0.5)
set a = null
endfunction

function DummyCastNonTarget takes unit u, integer abilid,integer abillvl,string order returns nothing
 local real x = GetUnitX(u)
 local real y = GetUnitY(u)
 local unit a = CreateUnit(GetOwningPlayer(u),'h009',x,y,0.)
  call UnitAddAbility(a,abilid)
  call SetUnitAbilityLevel(a,abilid,abillvl)
  call IssueImmediateOrder(a,order)
  call UnitApplyTimedLife(a,'BHwe',0.5)
  set a = null
endfunction

function DummyCastPoint takes unit u,real c, real d, integer abilid,integer abillvl,string order returns nothing
 local unit a = CreateUnit(GetOwningPlayer(u),'h009',c,d,0.)
  call UnitAddAbility(a,abilid)
  call SetUnitAbilityLevel(a,abilid,abillvl)
  call IssuePointOrder(a,order,c,d)
  call UnitApplyTimedLife(a,'BHwe',0.5)
  set a = null
endfunction

endlibrary
 
hashtable keys
1 - Evasion (percent)
2 - Crit (percent)
3 - Block Amount (value)
4 - Haste (percent)
5 - Spell Power (value)
6 - Crit Multiplier (value)
7 - Splash Damage (value)
8 - Healing Reduce to unit (REDUCE TO ATTACKED UNIT) (value) WTF is this
9 - Healing Bonus to targeted units (BONUS TO THIS UNIT) (value)
10 - Attack damage multiplier (need +1 in calculations) (value)
11 - Bonus to Healing effect, done by unit (in mult value)
12 - Critical strike % increase to Taker (in percent)
13 - Life-stealing (in value)
14 - Block Chance (percent)
15 - Chance to miss (percent)
16 - Spell Resist(value)
17 - Absorb phys damage
18 - Absorb spec effect
19 - FREE
20 - FREE
21 - Last Dealed Phys Damage
22 - Phys Dmg Reduce Multiplier (value)
23 - % bonus to OUT-Combat HP regeneration (value)
24 - % bonus to OUT-Combat MP regeneration (value)
25 - % bonus to OUT-Combat BOTH regenerations (value)
26 - % bonus to IN-Combat HP regeneration (value)
27 - % bonus to IN-Combat MP regeneration (value)
28 - % bonus to IN-Combat BOTH regenerations (value)
29 - Aggro multiplier(value)
30 - Hero Class
31 - Out of Combat Timer

30 - HeroClass (STRING)
31 - Out of Combat Timer (TIMER)
32 - IsUnitInCombat (BOOLEAN)
33 - Healing Potions used during one combat (INTEGER)
34 - Mana Potions used during one combat (INTEGER)
35 - Elixirs used during one combat (INTEGER)
36 - IsBattleElixirUsed (BOOLEAN)
37 - IsGuardElixirUsed (BOOLEAN)
38 - ARMOR PENETRATION TIMER

98 - hero icon multiboard
99 - Intervene CASTER (UNIT)
100 - Chapter number (INTEGER)
101-199 - Hero Abilities
201-299 - SpecialUnits Storage
300 - isUnitGiant
310 - NotGiveGold
311 - NotGiveEx

200 - region camera bound on hero
350
400+ new era parameters
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AddTextTag initializer onInit

globals
   boolean IS_ENEMY_TEXT = false
   boolean IS_HEALING_TEXT = false
   boolean IS_SPELL_DAMAGE_TEXT = false
   boolean IS_PHYS_DAMAGE_TEXT = false
 
   private constant real REFRESH_PREVIOUS_TEXTTAG = 0.75
   private constant real MIN_ANGLE = 45.
   private constant real MAX_ANGLE = 135.
   private constant integer PREVIOUS_TEXTTAG_TIME_ELAPSED_HASH = 1000
   private group AFFECTED = CreateGroup()
   private timer TT_TIMER = CreateTimer()
endglobals

private function GroupRefresh takes nothing returns nothing
   local unit u = GetEnumUnit()
   local real elapsed = LoadReal(udg_hash,GetHandleId(u),PREVIOUS_TEXTTAG_TIME_ELAPSED_HASH)
   set elapsed = elapsed + 0.04
   if elapsed > REFRESH_PREVIOUS_TEXTTAG then
      call GroupRemoveUnit(AFFECTED,u)
   else
      call SaveReal(udg_hash,GetHandleId(u),PREVIOUS_TEXTTAG_TIME_ELAPSED_HASH,elapsed)
   endif
   set u = null
endfunction

private function onTimer takes nothing returns nothing
   call ForGroup(AFFECTED, function GroupRefresh)
endfunction

function AddTextTagUnit takes string s, unit u, force play, real angle, real size,real duration, real Zoffset returns nothing
local texttag tt = CreateTextTag()
local real previous = LoadReal(udg_hash,GetHandleId(u),PREVIOUS_TEXTTAG_TIME_ELAPSED_HASH)
local real newangle = angle
   call SetTextTagText(tt,s,size * 0.023 / 10.)
   call SetTextTagPosUnit(tt,u,Zoffset)
   call SetTextTagColor(tt,255,255,255,255)
   call SetTextTagPermanent(tt,false)
   call SetTextTagLifespan(tt,duration)
   call SetTextTagFadepoint(tt,0.5)

   if previous < REFRESH_PREVIOUS_TEXTTAG then
        set newangle = GetRandomReal(MIN_ANGLE,MAX_ANGLE)
   endif

   call SetTextTagVelocity(tt, 0.0355*Cos(newangle*bj_DEGTORAD),0.0355*Sin(newangle*bj_DEGTORAD))
   call SaveReal(udg_hash,GetHandleId(u),PREVIOUS_TEXTTAG_TIME_ELAPSED_HASH,0.)
   call GroupAddUnit(AFFECTED,u)
   if (IsPlayerInForce(GetLocalPlayer(), udg_Players_Group)) then
   call SetTextTagVisibility(tt, false)
   endif

   if (IsPlayerInForce(GetLocalPlayer(), play)) then
     if IS_ENEMY_TEXT then
          if IsPlayerInForce(GetLocalPlayer(),ENEMY_TEXT_FORCE) and IsPlayerInForce(GetLocalPlayer(),BATTLE_TEXT_FORCE) then
                 call SetTextTagVisibility(tt, true)
          endif
     elseif IS_HEALING_TEXT then
          if IsPlayerInForce(GetLocalPlayer(),HEALING_TEXT_FORCE) and IsPlayerInForce(GetLocalPlayer(),BATTLE_TEXT_FORCE) then
                 call SetTextTagVisibility(tt, true)
          endif
     elseif IS_PHYS_DAMAGE_TEXT then
          if IsPlayerInForce(GetLocalPlayer(),PHYS_DAMAGE_TEXT_FORCE) and IsPlayerInForce(GetLocalPlayer(),BATTLE_TEXT_FORCE) then
                 call SetTextTagVisibility(tt, true)
          endif
     elseif IS_SPELL_DAMAGE_TEXT then
          if IsPlayerInForce(GetLocalPlayer(),SPELL_DAMAGE_TEXT_FORCE) and IsPlayerInForce(GetLocalPlayer(),BATTLE_TEXT_FORCE) then
                 call SetTextTagVisibility(tt, true)
          endif
     else
          call SetTextTagVisibility(tt, true)
     endif
   endif
   //call ForceClear(play)
set tt = null
endfunction

private function onInit takes nothing returns nothing
   call TimerStart(TT_TIMER,0.04,true,function onTimer)
endfunction

endlibrary
 
//Item abilities are saved as  integers in the corresponding hash keys.
//This library allows to put a cooldown on the desired hashkey, which allows not to trigger abiliy proc if it is in cooldown.

library HashprocCooldowns initializer onInit

globals
        private integer UNITS_COUNT = 0
        private constant integer MAX_COOLDOWNS = 100
        private unit array UNITS
        private timer HCTimer = CreateTimer()
endglobals

private struct cooldownsSt
        integer Count = 0
        integer array Hash[MAX_COOLDOWNS]
        real array Remaining[MAX_COOLDOWNS]
endstruct

globals  
        private cooldownsSt array HC
endglobals

private function onTimer takes nothing returns nothing
      local integer k = 1
      local integer j = 1
      local boolean HasCooldowns = false
 
      loop
          exitwhen k > UNITS_COUNT
          set j = 1
          set HasCooldowns = false
          loop
              exitwhen j>HC[k].Count
              if HC[k].Remaining[j]>0. then
                 set HC[k].Remaining[j] = HC[k].Remaining[j] - 0.04
                 //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,15.,"Removing cooldown on " + GetUnitName(UNITS[k]) + ". Remaining time: " + R2S(HC[k].Remaining[j]))
                 set HasCooldowns = true
              endif
              set j = j + 1
          endloop
          if not HasCooldowns then
             //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,15.,"No cooldowns on " + GetUnitName(UNITS[k]))
             set UNITS[k] = null
          endif
          set k = k + 1
      endloop
endfunction

private function onInit takes nothing returns nothing
       call TimerStart(HCTimer,0.04,true,function onTimer)
endfunction


//Returns -1 if not found
private function GetUnitCooldownsId takes unit whichUnit returns integer
        local integer i = 1
       
        loop
           exitwhen i>UNITS_COUNT or UNITS[i]==whichUnit
           set i = i +1
        endloop

        if i<=UNITS_COUNT then
           return i
        endif

        return -1
endfunction

private function NewUnitCooldownsId takes unit whichUnit returns integer
        local integer i = 1

        loop
           exitwhen i > UNITS_COUNT or UNITS[i]==null
           set i = i + 1
        endloop

        if i<=UNITS_COUNT then
           set UNITS[i] = whichUnit
           return i
        endif
       
        set UNITS_COUNT = UNITS_COUNT + 1
        set HC[UNITS_COUNT] = cooldownsSt.create()
        set UNITS[UNITS_COUNT] = whichUnit
        return UNITS_COUNT
endfunction

function HasUnitCooldownHash takes unit whichUnit, integer hashId returns boolean
        local integer k = GetUnitCooldownsId(whichUnit)
        local integer j = 1
        if k==-1 then
           return false
           //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,15.,"No cooldown before")
        endif

        loop
           exitwhen HC[k].Hash[j]==hashId or j>HC[k].Count
           set j = j + 1
        endloop

        return HC[k].Remaining[j]>0
endfunction

function UnitAddHashCooldown takes unit whichUnit, integer hashId, real cooldown returns nothing
        local integer k = GetUnitCooldownsId(whichUnit)
        local integer j = 1

        if k==-1 then
           set k = NewUnitCooldownsId(whichUnit)
        endif
        //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,15.,"Adding a cooldown on " + GetUnitName(whichUnit) + " as " + I2S(k) + "'th unit in library")
        loop
           exitwhen j>HC[k].Count or HC[k].Hash[j]==hashId or HC[k].Remaining[j]<=0.
           set j = j + 1
        endloop

        if j<= HC[k].Count then
           set HC[k].Hash[j] = hashId
           set HC[k].Remaining[j] = cooldown
        else
           set HC[k].Count = HC[k].Count + 1
           set HC[k].Hash[HC[k].Count] = hashId
           set HC[k].Remaining[HC[k].Count] = cooldown
        endif
endfunction

endlibrary
library HashtableUtils
/*
1 - Evasion (percent)
2 - Crit (percent)
3 - Block Amount (value)
4 - Haste (percent)
5 - Spell Power (value)
6 - Crit Multiplier (value)
7 - Splash Damage (value)
8 - Healing Reduce to unit (REDUCE TO ATTACKED UNIT)  (value)
9 - Healing Bonus to targeted units (BONUS TO THIS UNIT)  (value)
10 - Attack damage multiplier (need +1 in calculations) (value)
11 - Bonus to Healing effect, done by unit (in mult value)
12 - Critical strike % increase to Taker (in percent)
13 - Life-stealing (in value)
14 - Block Chance (percent)
15 - Chance to miss (percent)
16 - Spell Resist(value)
17 - Absorb phys damage
18 - Absorb spec effect
19 - Spell Crit
20 - Spell Crit Received Bonus
21 - Last Dealed Phys Damage
22 - Phys Dmg Reduce Multiplier (value)
23 - % bonus to OUT-Combat HP regeneration (value)
24 - % bonus to OUT-Combat MP regeneration (value)
25 - % bonus to OUT-Combat BOTH regenerations (value)
26 - % bonus to IN-Combat HP regeneration (value)
27 - % bonus to IN-Combat MP regeneration (value)
28 - % bonus to IN-Combat BOTH regenerations (value)
29 - Aggro multiplier(value)
30 - Hero Class
31 - Healing Crit
*/


globals
      private constant integer EVASION_HASH = 1
      private constant integer CRIT_HASH = 2
      private constant integer BLOCKAMOUNT_HASH = 3
      private constant integer HASTE_HASH = 4
      private constant integer SPELLPOWER_HASH = 5
      private constant integer CRITMULTIPLIER_HASH = 6
      private constant integer SPLASH_HASH = 7
      private constant integer HEALINGATTACKREDUCE_HASH = 8
      private constant integer HEALINGRECEIVEBONUS_HASH = 9
      private constant integer ATTACKDAMAGEMULTIPLIER_HASH = 10
      private constant integer HEALINGBONUS_HASH = 11
      private constant integer CRITRECEIVEDBONUS_HASH = 12
      private constant integer LIFESTEALING_HASH = 13
      private constant integer BLOCKCHANCE_HASH = 14
      private constant integer MISSCHANCE_HASH = 15
      private constant integer SPELLRESIST_HASH = 16
      private constant integer SPELLCRIT_HASH = 19
      private constant integer SPELLCRIT_RECEIVED_BONUS_HASH = 20
      private constant integer PHYSDMGREDUCE_HASH = 22
      private constant integer OUTCOMBAT_HP_MP_REGEN_HASH = 25
     
      private constant integer SPELL_CRIT_MULTIPLIER_HASH = 40

      private constant integer INCOMBAT_MP_REGEN_HASH = 27
      private constant integer AGGRO_MULTIPLIER_HASH = 29

      private constant integer RAGE_REGEN_BONUS_HASH = 400
      private constant integer FOCUS_REGEN_BONUS_HASH = 401
      private constant integer ENERGY_REGEN_BONUS_HASH = 402
      private constant integer MANA_REGEN_BONUS_HASH = 403
      private constant integer RUNES_REGEN_BONUS_HASH = 404
      private constant integer SELF_HEALING_BONUS_HASH = 405

      private constant integer FROST_DAMAGE_BONUS_HASH = 410
      private constant integer FIRE_DAMAGE_BONUS_HASH = 411
      private constant integer ARCANE_DAMAGE_BONUS_HASH = 412
      private constant integer WATER_DAMAGE_BONUS_HASH = 413
      private constant integer ELEMENTAL_DAMAGE_BONUS_HASH = 414
      private constant integer BLEEDING_DAMAGE_BONUS_HASH = 415
      private constant integer EARTH_DAMAGE_BONUS_HASH = 416
 
      private constant integer FROST_DAMAGE_RECEIVED_BONUS_HASH = 417
      private constant integer FIRE_DAMAGE_RECEIVED_BONUS_HASH = 418
      private constant integer ARCANE_DAMAGE_RECEIVED_BONUS_HASH = 419
      private constant integer WATER_DAMAGE_RECEIVED_BONUS_HASH = 420
      private constant integer ELEMENTAL_DAMAGE_RECEIVED_BONUS_HASH = 421
      private constant integer BLEEDING_DAMAGE_RECEIVED_BONUS_HASH = 422
      private constant integer EARTH_DAMAGE_RECEIVED_BONUS_HASH = 423

      private constant integer PERIODIC_HEALING_RECEIVED_BONUS_HASH = 424
      private constant integer PERIODIC_HEALING_BONUS_HASH = 425

      private constant integer PERIODIC_HEALING_CRIT_HASH = 426
      private constant integer PERIODIC_DAMAGE_BONUS_HASH = 427
      private constant integer HEALING_CRIT_MULTIPLIER_HASH = 428
   
      private constant integer DOTED_UNITS_SPELL_DAMAGE_BONUS_HASH = 429
endglobals

function GetDotedUnitsSpellDamageBonusHash takes nothing returns integer
      return DOTED_UNITS_SPELL_DAMAGE_BONUS_HASH
endfunction

function GetHealingCritMultiplierHash takes nothing returns integer
      return HEALING_CRIT_MULTIPLIER_HASH
endfunction

function GetPeriodicHealingCritHash takes nothing returns integer
      return PERIODIC_HEALING_CRIT_HASH
endfunction

function GetPeriodicDamageBonusHash takes nothing returns integer
      return PERIODIC_DAMAGE_BONUS_HASH
endfunction

function GetAggroMultiplierHash takes nothing returns integer
      return AGGRO_MULTIPLIER_HASH
endfunction
 
function GetPeriodicHealingBonusHash takes nothing returns integer
      return PERIODIC_HEALING_BONUS_HASH
endfunction

function GetPeriodicHealingReceivedBonusHash takes nothing returns integer
      return PERIODIC_HEALING_RECEIVED_BONUS_HASH
endfunction

function GetSpellCritMultiplierHash takes nothing returns integer
      return SPELL_CRIT_MULTIPLIER_HASH
endfunction

function GetSpellCritReceivedBonusHash takes nothing returns integer
      return SPELLCRIT_RECEIVED_BONUS_HASH
endfunction

function GetSpellCritHash takes nothing returns integer
      return SPELLCRIT_HASH
endfunction

function GetEarthDamageReceivedBonusHash takes nothing returns integer
      return EARTH_DAMAGE_RECEIVED_BONUS_HASH
endfunction

function GetBleedingDamageReceivedBonusHash takes nothing returns integer
      return BLEEDING_DAMAGE_RECEIVED_BONUS_HASH
endfunction

function GetFrostDamageReceivedBonusHash takes nothing returns integer
      return FROST_DAMAGE_RECEIVED_BONUS_HASH
endfunction

function GetFireDamageReceivedBonusHash takes nothing returns integer
      return FIRE_DAMAGE_RECEIVED_BONUS_HASH
endfunction

function GetArcaneDamageReceivedBonusHash takes nothing returns integer
      return ARCANE_DAMAGE_RECEIVED_BONUS_HASH
endfunction

function GetWaterDamageReceivedBonusHash takes nothing returns integer
      return WATER_DAMAGE_RECEIVED_BONUS_HASH
endfunction

function GetElementalDamageReceivedBonusHash takes nothing returns integer
      return ELEMENTAL_DAMAGE_RECEIVED_BONUS_HASH
endfunction

function GetEarthDamageBonusHash takes nothing returns integer
      return EARTH_DAMAGE_BONUS_HASH
endfunction

function GetFrostDamageBonusHash takes nothing returns integer
      return FROST_DAMAGE_BONUS_HASH
endfunction

function GetFireDamageBonusHash takes nothing returns integer
      return FIRE_DAMAGE_BONUS_HASH
endfunction

function GetArcaneDamageBonusHash takes nothing returns integer
      return ARCANE_DAMAGE_BONUS_HASH
endfunction

function GetWaterDamageBonusHash takes nothing returns integer
      return WATER_DAMAGE_BONUS_HASH
endfunction

function GetElementalDamageBonusHash takes nothing returns integer
      return ELEMENTAL_DAMAGE_BONUS_HASH
endfunction

function GetBleedingDamageBonusHash takes nothing returns integer
      return BLEEDING_DAMAGE_BONUS_HASH
endfunction

function GetSelfHealingBonusHash takes nothing returns integer
      return SELF_HEALING_BONUS_HASH
endfunction

function GetEnergyRegenBonusHash takes nothing returns integer
      return ENERGY_REGEN_BONUS_HASH
endfunction

function GetRageRegenBonusHash takes nothing returns integer
      return RAGE_REGEN_BONUS_HASH
endfunction

function GetFocusRegenBonusHash takes nothing returns integer
      return FOCUS_REGEN_BONUS_HASH
endfunction

function GetManaRegenBonusHash takes nothing returns integer
      return MANA_REGEN_BONUS_HASH
endfunction

function GetRunesRegenBonusHash takes nothing returns integer
      return RUNES_REGEN_BONUS_HASH
endfunction

function GetEvasionHash takes nothing returns integer
      return EVASION_HASH
endfunction

function GetCritHash takes nothing returns integer
      return CRIT_HASH
endfunction

function GetBlockAmountHash takes nothing returns integer
      return BLOCKAMOUNT_HASH
endfunction

function GetHasteHash takes nothing returns integer
      return HASTE_HASH
endfunction

function GetSpellPowerHash takes nothing returns integer
      return SPELLPOWER_HASH
endfunction

function GetCritMultiplierHash takes nothing returns integer
      return CRITMULTIPLIER_HASH
endfunction

function GetSplashHash takes nothing returns integer
      return SPLASH_HASH
endfunction

function GetHealingAttackReduceHash takes nothing returns integer
      return HEALINGATTACKREDUCE_HASH
endfunction

function GetReceivedHealingBonusHash takes nothing returns integer
      return HEALINGRECEIVEBONUS_HASH
endfunction

function GetAttackDamageMultiplierHash takes nothing returns integer
      return ATTACKDAMAGEMULTIPLIER_HASH
endfunction

function GetHealingBonusHash takes nothing returns integer
      return HEALINGBONUS_HASH
endfunction

function GetCritReceivedBonusHash takes nothing returns integer
      return CRITRECEIVEDBONUS_HASH
endfunction

function GetLifestealingHash takes nothing returns integer
      return LIFESTEALING_HASH
endfunction

function GetBlockChanceHash takes nothing returns integer
      return BLOCKCHANCE_HASH
endfunction

function GetMissChanceHash takes nothing returns integer
      return MISSCHANCE_HASH
endfunction

function GetSpellResistHash takes nothing returns integer
      return SPELLRESIST_HASH
endfunction

function GetPhysDmgReduceHash takes nothing returns integer
      return PHYSDMGREDUCE_HASH
endfunction

function GetOutCombatHpMpRegenHash takes nothing returns integer
      return OUTCOMBAT_HP_MP_REGEN_HASH
endfunction

function GetInCombatManaRegenHash takes nothing returns integer
      return INCOMBAT_MP_REGEN_HASH
endfunction


//Get Parameters

function GetUnitEvasion takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),EVASION_HASH)
endfunction

function GetUnitCritChancePercent takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),CRIT_HASH)
endfunction

function GetUnitBlockAmount takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),BLOCKAMOUNT_HASH)
endfunction

function GetUnitHastePercent takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),HASTE_HASH)
endfunction

function GetUnitSpellPower takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),SPELLPOWER_HASH)
endfunction

function GetUnitSpellCrit takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),SPELLCRIT_HASH)
endfunction

function GetUnitCritMultiplier takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),CRITMULTIPLIER_HASH)
endfunction

function GetUnitSplashValue takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),SPLASH_HASH)
endfunction

function GetUnitHealingAttackReduceValue takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),HEALINGATTACKREDUCE_HASH)
endfunction

function GetUnitHealingReceivedBonusValue takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),HEALINGRECEIVEBONUS_HASH)
endfunction

function GetUnitAttackDamageMultiplier takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),ATTACKDAMAGEMULTIPLIER_HASH)
endfunction

function GetUnitHealingBonusValue takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),HEALINGBONUS_HASH)
endfunction

function GetUnitCritReceivedBonusPercent takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),CRITRECEIVEDBONUS_HASH)
endfunction

function GetUnitLifeStealValue takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),LIFESTEALING_HASH)
endfunction

function GetUnitBlockChancePercent takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),BLOCKCHANCE_HASH)
endfunction

function GetUnitMissChancePercent takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),MISSCHANCE_HASH)
endfunction

function GetUnitSpellResistValue takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),SPELLRESIST_HASH)
endfunction

function GetUnitPhysResistValue takes unit whichUnit returns real
      return LoadReal(udg_hash,GetHandleId(whichUnit),PHYSDMGREDUCE_HASH)
endfunction

endlibrary
library ItemHashtableUtils

globals

private constant integer FLAMEBREATHER_HASH = 600
private constant real FLAMEBREATHER_COOLDOWN = 30.
private constant real FLAMEBREATHER_PROC_CHANCE = 40.
private constant real FLAMEBREATHER_PROC_DURATION = 10.

private constant integer HUNGERING_COLD_HASH = 601
private constant real HUNGERING_COLD_COOLDOWN = 30.
private constant real HUNGERING_COLD_PROC_CHANCE = 30.
private constant integer HUNGERING_COLD_ABILCODE = 'A00G'

private constant integer TROGGBANE_HASH = 602
private constant real TROGGBANE_LIFE_STEAL = 0.5
private constant real TROGGBANE_DAMAGE_MULT = 0.5
private constant real TROGGBANE_DURATION = 10.

private constant integer KANG_HASH = 603
private constant integer KANG_ABILCODE = 'A00C'
private constant real KANG_COOLDOWN = 25.

private constant integer BLADEBREAKER_HASH = 604
private constant real BLADEBREAKER_DAMAGE = 100.
private constant real BLADEBREAKER_DOT_DURATION = 3.
private constant real BLADEBREAKER_DOT_PERIOD = 1.
private constant real BLADEBREAKER_COOLDOWN = 15.
private constant real BLADEBREAKER_PROC_CHANCE = 30.

private constant integer HEAVENS_FALL_HASH = 605
private constant real HEAVENS_FALL_DURATION = 10.
private constant real HEAVENS_FALL_BASE_HASTE = 5.
private constant real HEAVENS_FALL_LVL_HASTE = 5.

private constant integer INCINERATUS_HASH = 606
private constant real INCINERATUS_DOT_DAMAGE = 100.
private constant real INCINERATUS_DOT_DURATION = 4.
private constant real INCINERATUS_DOT_PERIOD = 1.
private constant real INCINERATUS_COOLDOWN = 15.
private constant real INCINERATUS_PROC_CHANCE = 40.

private constant integer ICECORESTAFF_HASH = 607
private constant real ICECORESTAFF_MANA = 0.01

private constant integer MAGHARI_HASH = 608
private constant real MAGHARI_SPELLPOWER_BONUS = 50.
private constant real MAGHARI_PROC_CHANCE = 30.
private constant real MAGHARI_DURATION = 10.
private constant real MAGHARI_COOLDOWN = 30.

private constant integer SKULLFLAME_HASH = 609
private constant real SKULLFLAME_DAMAGE = 0.4

private constant integer BARRIER_HASH = 610
private constant real BARRIER_RESIST = 0.1
private constant real BARRIER_DURATION = 15.

private constant integer WALL_HASH = 611
private constant real WALL_DURATION = 10.
private constant real WALL_COOLDOWN = 2.5
private constant real WALL_BLOCK_BONUS = 10.

private constant integer SACRED_HASH = 612
private constant real SACRED_DURATION = 10.
private constant real SACRED_COOLDOWN = 2.5
private constant real SACRED_HEALING_BONUS = 0.1

private constant integer MAGMA_BREASTPLATE_HASH = 613
private constant real MAGMA_BREASTPLATE_DURATION = 10.
private constant real MAGMA_BREASTPLATE_COOLDOWN = 30.
private constant real MAGMA_BREASTPLATE_THRESHOLD = 0.45
private constant real MAGMA_BREASTPLATE_DODGE = 20.

private constant integer COLDWRAITH_PLATE_HASH = 614
private constant real COLDWRAITH_PLATE_ABSORB = 1000.
private constant real COLDWRAITH_PLATE_DURATION = 10.

private constant integer ABOMINATION_RIBCAGE_HASH = 615
private constant real ABOMINATION_RIBCAGE_BLOCK_AMOUNT = 100.
private constant real ABOMINATION_RIBCAGE_DURATION = 10.

private constant integer LIGHTBRINGER_HASH = 616
private constant real LIGHTBRINGER_RECEIVED_HEALING = 0.25
private constant real LIGHTBRINGER_DURATION = 10.

private constant integer FIREHAND_GAUNTLETS_HASH = 617
private constant integer FIREHAND_GAUNTLETS_EXPERTISE = 20
private constant real FIREHAND_GAUNTLETS_DURATION = 10.

private constant integer FROSTGIANT_GLOVES_HASH = 618
private constant real FROSTGIANT_GLOVES_DURATION = 5.
private constant real FROSTGIANT_GLOVES_COOLDOWN = 30.

private constant integer DEMON_STALKER_GAUNTLETS_HASH = 619
private constant real DEMON_STALKER_GAUNTLETS_DURATION = 10.
private constant real DEMON_STALKER_GAUNTLETS_BLOCK_CHANCE = 10.

private constant integer GLOVES_HOLY_MIGHT_HASH = 620
private constant real GLOVES_HOLY_MIGHT_DURATION = 10.
private constant real GLOVES_HOLY_MIGHT_DAMAGE_CONSUMED = 0.1

private constant integer DAYBREAKER_HELM_HASH = 621
private constant real DAYBREAKER_HELM_DURATION = 10.
private constant real DAYBREAKER_HELM_DAMAGE_AMPLIFY = 0.1
private constant real DAYBREAKER_HELM_AFFECT_DURATION = 40.

private constant integer FROSTFORGED_HELM_HASH = 622
private constant real FROSTFORGED_HELM_DURATION = 10.
private constant real FROSTFORGED_HELM_COOLDOWN = 40.
private constant real FROSTFORGED_HELM_RECEIVED_HEALING_BONUS = 0.2
private constant real FROSTFORGED_HELM_HP_THRESHOLD = 0.45

private constant integer BROKEN_RAM_HELM_HASH = 623
private constant real BROKEN_RAM_HELM_DURATION = 15.
private constant real BROKEN_RAM_HELM_DAMAGE_CONSUME = 0.1

private constant integer ELDER_MOON_HELM_HASH = 624
private constant real ELDER_MOON_HELM_DURATION = 15.
private constant real ELDER_MOON_HELM_INCOMBAT_MANAREGEN = 0.3

private constant integer FROSTBROOD_SAPPHIRE_RING_HASH = 625
private constant real FROSTBROOD_SAPPHIRE_RING_DURATION = 10.
private constant real FROSTBROOD_SAPPHIRE_RING_SPELLPOWER = 75.

private constant integer TOME_OF_THE_ICE_LORD_HASH = 626
private constant real TOME_OF_THE_ICE_LORD_DURATION = 10.
private constant real TOME_OF_THE_ICE_LORD_SPELL_CRIT_POWER = 0.1
private constant real TOME_OF_THE_ICE_LORD_DAMAGE_CONSUMED = 0.25

private constant integer BOOK_OF_BINDING_WILL_HASH = 627
private constant real BOOK_OF_BINDING_WILL_SPELL_CRIT = 4.
private constant real BOOK_OF_BINDING_WILL_HP_THRESHOLD = 0.75

private constant integer BOOK_OF_HIGNBORNE_HYMNS_HASH = 628
private constant real BOOK_OF_HIGNBORNE_HYMNS_DURATION = 10.
private constant real BOOK_OF_HIGNBORNE_HYMNS_COOLDOWN = 25.
private constant real BOOK_OF_HIGNBORNE_HYMNS_ENERGY_REGEN = 0.25


endglobals

function GetBookOfHighborneHymnsDescriptionByLevel takes integer lvl returns string
   return "Improves hero's Energy regeneration by |cffbe8080" + I2S(R2I(BOOK_OF_HIGNBORNE_HYMNS_ENERGY_REGEN*100*lvl)) + "%|r for " + I2S(R2I(BOOK_OF_HIGNBORNE_HYMNS_DURATION)) + " sec. if his healing crits. Has a " + I2S(R2I(BOOK_OF_HIGNBORNE_HYMNS_COOLDOWN)) + " sec. internal cooldown."
endfunction

function GetBookOfBindingWillDescriptionByLevel takes integer lvl returns string
   return "Improves hero's Spell Crit by |cffbe8080" + I2S(R2I(BOOK_OF_BINDING_WILL_SPELL_CRIT*lvl)) + "%|r if his hp is below " + I2S(R2I(BOOK_OF_BINDING_WILL_HP_THRESHOLD*100))  + "%|r."
endfunction

function GetTomeOfTheIceLordDescriptionByLevel takes integer lvl returns string
   return "Improves hero's Spell Crit Power by |cffbe8080" + I2S(R2I(TOME_OF_THE_ICE_LORD_SPELL_CRIT_POWER*100*lvl)) + "%|r and makes him consume |cffbe8080" + I2S(R2I(TOME_OF_THE_ICE_LORD_DAMAGE_CONSUMED*100*lvl)) + "%|r of the dealed spell damage to heal himself. Lasts for " + I2S(R2I(TOME_OF_THE_ICE_LORD_DURATION)) + " sec. (|c007EBFF1active|r)"
endfunction

function GetFrostbroodSapphireRingDescriptionByLevel takes integer lvl returns string
   return "Improves hero's Spell Power by |cffbe8080" + I2S(R2I(FROSTBROOD_SAPPHIRE_RING_SPELLPOWER*lvl)) + "|r for " + I2S(R2I(FROSTBROOD_SAPPHIRE_RING_DURATION)) + " sec. (|c007EBFF1active|r)"
endfunction

function GetElderMoonHelmDescriptionByLevel takes integer lvl returns string
   return "Improves the in-combat mana regeneration by |cffbe8080" + I2S(R2I(ELDER_MOON_HELM_INCOMBAT_MANAREGEN*100*lvl)) + "%|r for " + I2S(R2I(ELDER_MOON_HELM_DURATION)) + " sec. (|c007EBFF1active|r)"
endfunction

function GetBrokenRamHelmDescriptionByLevel takes integer lvl returns string
   return "Causes the hero to consume |cffbe8080" + I2S(R2I(BROKEN_RAM_HELM_DAMAGE_CONSUME*100*lvl)) + "%|r of taken damage into his attack (|c007EBFF1active|r)"
endfunction

function GetFrostforgedHelmDescriptionByLevel takes integer lvl returns string
 return "Increases the received healing by |cffbe8080" + I2S(R2I(FROSTFORGED_HELM_RECEIVED_HEALING_BONUS*100*lvl)) + "%|r for " + I2S(R2I(FROSTFORGED_HELM_DURATION)) + " sec. every time hero's hp drops below " + I2S(R2I(FROSTFORGED_HELM_HP_THRESHOLD*100))+ "%. Has a " + I2S(R2I(FROSTFORGED_HELM_COOLDOWN)) + " sec. internal cooldown."
endfunction

function GetDaybreakerHelmDescriptionByLevel takes integer lvl returns string
   return "Burns nearby enemies in 300 AOE, amplifying their damage taken by |cffbe8080" + I2S(R2I(DAYBREAKER_HELM_DAMAGE_AMPLIFY*100)) + "%|r for " + I2S(R2I(DAYBREAKER_HELM_DURATION)) + " sec. Affected units cannot be affected again in the next " + I2S(R2I(DAYBREAKER_HELM_AFFECT_DURATION)) + " sec. (|c007EBFF1active|r)"
endfunction

function GetGlovesOfHolyMightDescriptionByLevel takes integer lvl returns string
   return "Creates a runic barrier for " + I2S(R2I(GLOVES_HOLY_MIGHT_DURATION)) + " sec. that converts |cffbe8080" + I2S(R2I(GLOVES_HOLY_MIGHT_DAMAGE_CONSUMED*100*lvl)) + "%|r of the taken damage into hero's mana (|c007EBFF1active|r)"
endfunction

function GetDemonStalkerGauntletsDescriptionByLevel takes integer lvl returns string
 return "Increases the block chance by |cffbe8080" + I2S(R2I(DEMON_STALKER_GAUNTLETS_BLOCK_CHANCE*lvl)) + "%|r for " + I2S(R2I(DEMON_STALKER_GAUNTLETS_DURATION)) + " sec. (|c007EBFF1active|r)"
endfunction

function GetFrostgiantGlovesDescriptionByLevel takes integer lvl returns string
 return "Protects the hero from critical hits for |cffbe8080" + I2S(R2I(FROSTGIANT_GLOVES_DURATION*lvl)) + "|r sec. each time he dodges an attack. Has a " + I2S(R2I(FROSTGIANT_GLOVES_COOLDOWN)) + " sec. internal cooldown."
endfunction

function GetFirehandGauntletsDescriptionByLevel takes integer lvl returns string
 return "Improves the hero expertise by |cffbe8080" + I2S(R2I(FIREHAND_GAUNTLETS_EXPERTISE*lvl)) + "|r for " + I2S(R2I(FIREHAND_GAUNTLETS_DURATION)) + " sec. (|c007EBFF1active|r)"
endfunction

function GetLightbringerChestguardDescriptionByLevel takes integer lvl returns string
 return "Improves the received healing by |cffbe8080" + I2S(R2I(LIGHTBRINGER_RECEIVED_HEALING*100*lvl)) + "%|r for " + I2S(R2I(LIGHTBRINGER_DURATION)) + " sec. (|c007EBFF1active|r)"
endfunction

function GetAbominationRibcageDescriptionByLevel takes integer lvl returns string
 return "Improves the block amount by |cffbe8080" + I2S(R2I(ABOMINATION_RIBCAGE_BLOCK_AMOUNT*lvl)) + "|r for " + I2S(R2I(ABOMINATION_RIBCAGE_DURATION)) + " sec. (|c007EBFF1active|r)"
endfunction

function GetColdwraithPlateDescriptionByLevel takes integer lvl returns string
 return "Protets the hero by a frost barrier, which absorbs |cffbe8080" + I2S(R2I(COLDWRAITH_PLATE_ABSORB*lvl)) + "|r incoming damage (but no more than 50% of incoming damage at a time) and lasts for " + I2S(R2I(COLDWRAITH_PLATE_DURATION)) + " sec. (|c007EBFF1active|r)"
endfunction

function GetMagmaBreastplateDescriptionByLevel takes integer lvl returns string
 return "Increases the dodge chance by |cffbe8080" + I2S(R2I(MAGMA_BREASTPLATE_DODGE*lvl)) + "%|r for " + I2S(R2I(MAGMA_BREASTPLATE_DURATION)) + " sec. every time hero's hp drops below " + I2S(R2I(MAGMA_BREASTPLATE_THRESHOLD*100))+ "%. Has a " + I2S(R2I(MAGMA_BREASTPLATE_COOLDOWN)) + " sec. internal cooldown."
endfunction

function GetSacredProtectorDescriptionByLevel takes integer lvl returns string
 return "Improves the healing received by |cffbe8080" + I2S(R2I(SACRED_HEALING_BONUS*100*lvl)) + "|r for " + I2S(R2I(SACRED_DURATION)) + " sec. every time the hero dodges an attack. Has a " + I2S(R2I(SACRED_COOLDOWN)) + " sec. internal cooldown."
endfunction

function GetWallOfTheDeadDescriptionByLevel takes integer lvl returns string
 return "Improves the block ammount by |cffbe8080" + I2S(R2I(WALL_BLOCK_BONUS*lvl)) + "|r for " + I2S(R2I(WALL_DURATION)) + " sec. at each successful block. Has a " + I2S(R2I(WALL_COOLDOWN)) + " sec. internal cooldown."
endfunction

function GetBarrierShieldDescriptionByLevel takes integer lvl returns string
 return "Improves the spell resist by |cffbe8080" + I2S(R2I(BARRIER_RESIST*100*lvl)) + "%|r for " + I2S(R2I(BARRIER_DURATION)) + " sec. (|c007EBFF1active|r)"
endfunction

function GetSkullflameDescriptionByLevel takes integer lvl returns string
 return "Deals |cffbe8080" + I2S(R2I(SKULLFLAME_DAMAGE*100*lvl)) + "%|r of the block amount to the attacker at each successful block."
endfunction

function GetIcecoreStaffDescriptionByLevel takes integer lvl returns string
 return "Converts |cffbe8080" + I2S(R2I(ICECORESTAFF_MANA*100*lvl)) + "%|r of the dealed spell damage into hero's mana."
endfunction

function GetMaghariDescriptionByLevel takes integer lvl returns string
 return "Grants a " + I2S(R2I(MAGHARI_PROC_CHANCE)) + "% chance, while dealing magical damage, to get |cffbe8080" + I2S(R2I(MAGHARI_SPELLPOWER_BONUS*lvl)) + "|r bonus Spell power for " + I2S(R2I(MAGHARI_DURATION)) + " sec. Has a " + I2S(R2I(MAGHARI_COOLDOWN)) + " sec. internal cooldown."
endfunction

function GetIncineratusDescriptionByLevel takes integer lvl returns string
 return "Grants a " + I2S(R2I(INCINERATUS_PROC_CHANCE)) + "% chance, while dealing magical damage, to burn the target enemy for |cffbe8080" + I2S(R2I(INCINERATUS_DOT_DAMAGE*lvl)) + "|r damage per " + I2S(R2I(INCINERATUS_DOT_PERIOD)) + " sec. over " + I2S(R2I(INCINERATUS_DOT_DURATION)) + " sec. Has a " + I2S(R2I(INCINERATUS_COOLDOWN)) + " sec. internal cooldown."
endfunction

function GetHeavensFallDescriptionByLevel takes integer lvl returns string
 return "Increases the haste rating by |cffbe8080" + I2S(R2I(HEAVENS_FALL_BASE_HASTE+HEAVENS_FALL_LVL_HASTE*lvl)) + "%|r. Lasts for " + I2S(R2I(HEAVENS_FALL_DURATION)) +" seconds(|c007EBFF1active|r))"
endfunction

function GetBladebreakerDescriptionByLevel takes integer lvl returns string
 return "Grants a " + I2S(R2I(BLADEBREAKER_PROC_CHANCE)) + "% change to apply a bleeding effect to the target, dealing |cffbe8080" + I2S(R2I(lvl*BLADEBREAKER_DAMAGE)) + "|r damage per second for "+ I2S(R2I(BLADEBREAKER_DOT_DURATION)) + " seconds. Has a " + I2S(R2I(BLADEBREAKER_COOLDOWN)) + " seconds internal cooldown."
endfunction

function GetTroggbaneDescriptionByLevel takes integer lvl returns string
 return "Causes the hero to deal " + I2S(100+R2I(TROGGBANE_DAMAGE_MULT*100)) + "% of normal damage with each attack and consume |cffbe8080" + I2S(lvl*R2I(100*TROGGBANE_LIFE_STEAL)) +"%|r of this damage to heal himself. Lasts for " + I2S(R2I(TROGGBANE_DURATION)) +" seconds(|c007EBFF1active|r)"
endfunction

function GetHungeringColdDescriptionByLevel takes integer lvl returns string
 return "Grants a " + I2S(R2I(HUNGERING_COLD_PROC_CHANCE)) + "% chance on attack to freeze the enemies in 350 AOE, reducing their armor by |cffbe8080" + I2S(lvl * 4) + "|r. Has a " + I2S(R2I(HUNGERING_COLD_COOLDOWN)) + " seconds internal cooldown."
endfunction

function GetFlameBreatherDescriptionByLevel takes integer lvl returns string
 return "Grants a " + I2S(R2I(FLAMEBREATHER_PROC_CHANCE)) + "% chance on attack to increase the attack damage by |cffbe8080" + I2S(lvl * 100) + "|r for " + I2S(R2I(FLAMEBREATHER_PROC_DURATION)) + " seconds. Has a " + I2S(R2I(FLAMEBREATHER_COOLDOWN)) + " seconds internal cooldown."
endfunction

function GetKangDescriptionByLevel takes integer lvl returns string
 return "Reduces the attack damage of enemies in 500 AOE by |cffbe8080" + I2S(10+5*lvl) + "%|r every time the hero deals a crit. Has a " + I2S(R2I(KANG_COOLDOWN)) + " seconds internal cooldown."
endfunction

//////

function GetBookOfHighborneHymnsEnergyRegen takes nothing returns real
   return BOOK_OF_HIGNBORNE_HYMNS_ENERGY_REGEN
endfunction

function GetBookOfHighborneHymnsCooldown takes nothing returns real
   return BOOK_OF_HIGNBORNE_HYMNS_COOLDOWN
endfunction

function GetBookOfHighborneHymnsDuration takes nothing returns real
   return BOOK_OF_HIGNBORNE_HYMNS_DURATION
endfunction

function GetBookOfHighborneHymnsHash takes nothing returns integer
   return BOOK_OF_HIGNBORNE_HYMNS_HASH
endfunction

function GetBookOfBindingWillSpellCrit takes nothing returns real
   return BOOK_OF_BINDING_WILL_SPELL_CRIT
endfunction

function GetBookOfBindingWillHpThreshold takes nothing returns real
   return BOOK_OF_BINDING_WILL_HP_THRESHOLD
endfunction

function GetBookOfBindingWillHash takes nothing returns integer
   return BOOK_OF_BINDING_WILL_HASH
endfunction

function GetTomeOfTheIceLordDamageConsumed takes nothing returns real
   return TOME_OF_THE_ICE_LORD_DAMAGE_CONSUMED
endfunction

function GetTomeOfTheIceLordSpellCritPower takes nothing returns real
   return TOME_OF_THE_ICE_LORD_SPELL_CRIT_POWER
endfunction

function GetTomeOfTheIceLordDuration takes nothing returns real
   return TOME_OF_THE_ICE_LORD_DURATION
endfunction

function GetTomeOfTheIceLordHash takes nothing returns integer
   return TOME_OF_THE_ICE_LORD_HASH
endfunction

function GetFrostbroodSapphireRingHash takes nothing returns integer
      return FROSTBROOD_SAPPHIRE_RING_HASH
endfunction

function GetFrostbroodSapphireRingSpellPower takes nothing returns real
      return FROSTBROOD_SAPPHIRE_RING_SPELLPOWER
endfunction

function GetFrostbroodSapphireRingDuration takes nothing returns real
      return FROSTBROOD_SAPPHIRE_RING_DURATION
endfunction

function GetElderMoonHelmBonusInCombatRegen takes nothing returns real
      return ELDER_MOON_HELM_INCOMBAT_MANAREGEN
endfunction

function GetElderMoonHelmDuration takes nothing returns real
      return ELDER_MOON_HELM_DURATION
endfunction

function GetElderMoonHelmHash takes nothing returns integer
      return ELDER_MOON_HELM_HASH
endfunction

function GetBrokenRamHelmDuration takes nothing returns real
      return BROKEN_RAM_HELM_DURATION
endfunction

function GetBrokenRamHelmDamageConsume takes nothing returns real
      return BROKEN_RAM_HELM_DAMAGE_CONSUME
endfunction

function GetBrokenRamHelmHash takes nothing returns integer
      return BROKEN_RAM_HELM_HASH
endfunction

function GetFrostforgedHelmHpThreshold takes nothing returns real
      return FROSTFORGED_HELM_HP_THRESHOLD
endfunction

function GetFrostforgedHelmReceivedHealingBonus takes nothing returns real
      return FROSTFORGED_HELM_RECEIVED_HEALING_BONUS
endfunction

function GetFrostforgedHelmCooldown takes nothing returns real
      return FROSTFORGED_HELM_COOLDOWN
endfunction

function GetFrostforgedHelmDuration takes nothing returns real
      return FROSTFORGED_HELM_DURATION
endfunction

function GetFrostforgedHelmHash takes nothing returns integer
      return FROSTFORGED_HELM_HASH
endfunction

function GetDaybreakerHelmAffectDuration takes nothing returns real
      return DAYBREAKER_HELM_AFFECT_DURATION
endfunction

function GetDaybreakerHelmDamageAmplify takes nothing returns real
      return DAYBREAKER_HELM_DAMAGE_AMPLIFY
endfunction

function GetDaybreakerHelmDuration takes nothing returns real
      return DAYBREAKER_HELM_DURATION
endfunction

function GetDaybreakerHelmHash takes nothing returns integer
      return DAYBREAKER_HELM_HASH
endfunction

function GetGlovesOfHolyMightDamageConsumed takes nothing returns real
        return GLOVES_HOLY_MIGHT_DAMAGE_CONSUMED
endfunction

function GetGlovesOfHolyMightDuration takes nothing returns real
        return GLOVES_HOLY_MIGHT_DURATION
endfunction

function GetGlovesOfHolyMightHash takes nothing returns integer
        return GLOVES_HOLY_MIGHT_HASH
endfunction

function GetDemonStalkerGauntletsBlockChance takes nothing returns real
        return DEMON_STALKER_GAUNTLETS_BLOCK_CHANCE
endfunction

function GetDemonStalkerGauntletsDuration takes nothing returns real
        return DEMON_STALKER_GAUNTLETS_DURATION
endfunction

function GetDemonStalkerGauntletsHash takes nothing returns integer
        return DEMON_STALKER_GAUNTLETS_HASH
endfunction

function GetFrostgiantGlovesCooldown takes nothing returns real
        return FROSTGIANT_GLOVES_COOLDOWN
endfunction

function GetFrostgiantGlovesDuration takes nothing returns real
        return FROSTGIANT_GLOVES_DURATION
endfunction

function GetFrostgiantGlovesHash takes nothing returns integer
        return FROSTGIANT_GLOVES_HASH
endfunction

function GetFirehandGauntletsDuration takes nothing returns real
        return FIREHAND_GAUNTLETS_DURATION
endfunction

function GetFirehandGauntletsExpertise takes nothing returns integer
        return FIREHAND_GAUNTLETS_EXPERTISE
endfunction

function GetFirehandGauntletsHash takes nothing returns integer
        return FIREHAND_GAUNTLETS_HASH
endfunction

function GetLightbringerChestguardHash takes nothing returns integer
        return LIGHTBRINGER_HASH
endfunction

function GetLightbringerChestguardDuration takes nothing returns real
        return LIGHTBRINGER_DURATION
endfunction

function GetLightbringerChestguardReceivedHealing takes nothing returns real
        return LIGHTBRINGER_RECEIVED_HEALING
endfunction

function GetColdwraithPlateHash takes nothing returns integer
        return COLDWRAITH_PLATE_HASH
endfunction

function GetColdwraithPlateDuration takes nothing returns real
        return COLDWRAITH_PLATE_DURATION
endfunction

function GetColdwraithPlateAbsorb takes nothing returns real
        return COLDWRAITH_PLATE_ABSORB
endfunction

function GetAbominationRibcageDuration takes nothing returns real
        return ABOMINATION_RIBCAGE_DURATION
endfunction

function GetAbominationRibcageBlockAmount takes nothing returns real
        return ABOMINATION_RIBCAGE_BLOCK_AMOUNT
endfunction

function GetAbominationRibcageHash takes nothing returns integer
        return ABOMINATION_RIBCAGE_HASH
endfunction

function GetMagmaBreastplateDodge takes nothing returns real
        return MAGMA_BREASTPLATE_DODGE
endfunction

function GetMagmaBreastplateThreshold takes nothing returns real
        return MAGMA_BREASTPLATE_THRESHOLD
endfunction

function GetMagmaBreastplateCooldown takes nothing returns real
        return MAGMA_BREASTPLATE_COOLDOWN
endfunction

function GetMagmaBreastplateDuration takes nothing returns real
        return MAGMA_BREASTPLATE_DURATION
endfunction

function GetMagmaBreastplateHash takes nothing returns integer
        return MAGMA_BREASTPLATE_HASH
endfunction

function GetSacredProtectorDuration takes nothing returns real
        return SACRED_DURATION
endfunction

function GetSacredProtectorCooldown takes nothing returns real
        return SACRED_COOLDOWN
endfunction

function GetSacredProtectorHealing takes nothing returns real
        return SACRED_HEALING_BONUS
endfunction

function GetSacredProtectorHash takes nothing returns integer
        return SACRED_HASH
endfunction

function GetWallOfTheDeadDuration takes nothing returns real
        return WALL_DURATION
endfunction

function GetWallOfTheDeadCooldown takes nothing returns real
        return WALL_COOLDOWN
endfunction

function GetWallOfTheDeadBlock takes nothing returns real
        return WALL_BLOCK_BONUS
endfunction

function GetWallOfTheDeadHash takes nothing returns integer
        return WALL_HASH
endfunction

function GetBarrierShieldResist takes nothing returns real
        return BARRIER_RESIST
endfunction

function GetBarrierShieldDuration takes nothing returns real
        return BARRIER_DURATION
endfunction

function GetBarrierShieldHash takes nothing returns integer
        return BARRIER_HASH
endfunction


function GetSkullflameDamage takes nothing returns real
        return SKULLFLAME_DAMAGE
endfunction

function GetSkullflameHash takes nothing returns integer
        return SKULLFLAME_HASH
endfunction

function GetIncineratusHash takes nothing returns integer
        return INCINERATUS_HASH
endfunction

function GetIncineratusDotDuration takes nothing returns real
        return INCINERATUS_DOT_DURATION
endfunction

function GetIncineratusDotPeriod takes nothing returns real
        return INCINERATUS_DOT_PERIOD
endfunction

function GetIncineratusDotDamage takes nothing returns real
        return INCINERATUS_DOT_DAMAGE
endfunction

function GetIncineratusProcChance takes nothing returns real
        return INCINERATUS_PROC_CHANCE
endfunction

function GetIncineratusCooldown takes nothing returns real
        return INCINERATUS_COOLDOWN
endfunction

function GetIcecoreStaffHash takes nothing returns integer
        return ICECORESTAFF_HASH
endfunction

function GetIcecoreStaffMana takes nothing returns real
        return ICECORESTAFF_MANA
endfunction

function GetMaghariProcChance takes nothing returns real
        return MAGHARI_PROC_CHANCE
endfunction

function GetMaghariHash takes nothing returns integer
        return MAGHARI_HASH
endfunction

function GetMaghariCooldown takes nothing returns real
        return MAGHARI_COOLDOWN
endfunction

function GetMaghariDuration takes nothing returns real
        return MAGHARI_DURATION
endfunction

function GetMaghariSpellPowerBonus takes nothing returns real
        return MAGHARI_SPELLPOWER_BONUS
endfunction

function GetHeavensFallLvlHaste takes nothing returns real
       return HEAVENS_FALL_LVL_HASTE
endfunction

function GetHeavensFallBaseHaste takes nothing returns real
       return HEAVENS_FALL_BASE_HASTE
endfunction

function GetHeavensFallDuration takes nothing returns real
       return HEAVENS_FALL_DURATION
endfunction

function GetHeavensFallHash takes nothing returns integer
       return HEAVENS_FALL_HASH
endfunction

function GetBladebreakerProcChance takes nothing returns real
       return BLADEBREAKER_PROC_CHANCE
endfunction

function GetBladebreakerCooldown takes nothing returns real
       return BLADEBREAKER_COOLDOWN
endfunction

function GetBladebreakerDotDuration takes nothing returns real
       return BLADEBREAKER_DOT_DURATION
endfunction

function GetBladebreakerDotPeriod takes nothing returns real
       return BLADEBREAKER_DOT_PERIOD
endfunction

function GetBladebreakerDamage takes nothing returns real
       return BLADEBREAKER_DAMAGE
endfunction

function GetBladebreakerHash takes nothing returns integer
       return BLADEBREAKER_HASH
endfunction

function GetKangCooldown takes nothing returns real
       return KANG_COOLDOWN
endfunction

function GetKangAbil takes nothing returns integer
       return KANG_ABILCODE
endfunction

function GetKangHash takes nothing returns integer
       return KANG_HASH
endfunction

function GetTroggbaneDamageMult takes nothing returns real
       return TROGGBANE_DAMAGE_MULT
endfunction

function GetTroggbaneLifeSteal takes nothing returns real
       return TROGGBANE_LIFE_STEAL
endfunction

function GetTroggbaneDuration takes nothing returns real
       return TROGGBANE_DURATION
endfunction

function GetTroggbaneHash takes nothing returns integer
       return TROGGBANE_HASH
endfunction

function GetHungeringColdAbil takes nothing returns integer
       return HUNGERING_COLD_ABILCODE
endfunction

function GetHungeringColdProcChance takes nothing returns real
       return HUNGERING_COLD_PROC_CHANCE
endfunction

function GetHungeringColdHash takes nothing returns integer
       return HUNGERING_COLD_HASH
endfunction

function GetHungeringColdCooldown takes nothing returns real
       return HUNGERING_COLD_COOLDOWN
endfunction

function GetFlameBreatherProcChance takes nothing returns real
       return FLAMEBREATHER_PROC_CHANCE
endfunction

function GetFlameBreatherHash takes nothing returns integer
       return FLAMEBREATHER_HASH
endfunction

function GetFlameBreatherCooldown takes nothing returns real
       return FLAMEBREATHER_COOLDOWN
endfunction

endlibrary
library DamageEventMethods initializer onInit

globals
        //0 for physical, 1 for magical
        private integer LAST_DAMAGE_TYPE = 0
        //0 for non-doted, 1 for bleeding etc. See DamageOverTime library
        //Todo: elemental damage
        private integer DOT_TYPE = 0
        private boolean ELEMENTAL = false
        private boolean FROST = false
        private boolean EARTH = false
        private boolean FIRE = false
        private boolean WATER = false
        private boolean ARCANE = false
        private string array DOT_NAMES[10]
endglobals

private function onInit takes nothing returns nothing
        set DOT_NAMES[0]  = "none"
        set DOT_NAMES[2] = "BLEEDING"
        set DOT_NAMES[1] = "BURNING"
        set DOT_NAMES[3] = "FREEZING"
        set DOT_NAMES[4] = "PLAGUED"
        set DOT_NAMES[5] = "POISONED"
endfunction

function GetLastDamageType takes nothing returns string
         if LAST_DAMAGE_TYPE == 0 then
            return "PHYSICAL"
         endif
         if LAST_DAMAGE_TYPE == 1 then
            return "MAGICAL"
         endif
         return ""
endfunction

function IsLastDamageFrost takes nothing returns boolean
         return FROST
endfunction

function IsLastDamageFire takes nothing returns boolean
         return FIRE
endfunction

function IsLastDamageArcane takes nothing returns boolean
         return ARCANE
endfunction

function IsLastDamageEarth takes nothing returns boolean
         return EARTH
endfunction

function IsLastDamageWater takes nothing returns boolean
         return WATER
endfunction

function IsLastDamageElemental takes nothing returns boolean
         return ELEMENTAL
endfunction

function IsLastDamageDot takes nothing returns boolean
         return DOT_TYPE > 0
endfunction

function GetLastDotType takes nothing returns string
        return DOT_NAMES[DOT_TYPE]
endfunction

function DealPhysicalDamage takes unit Dealer, unit Taker, real Damage returns nothing
        set LAST_DAMAGE_TYPE = 0
        call UnitDamageTarget(Dealer,Taker,Damage,false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS)
        set LAST_DAMAGE_TYPE = -1
endfunction

private function DealPhysicalDamageOverTime takes unit Dealer, unit Taker, real Damage, integer DotType returns nothing
        set LAST_DAMAGE_TYPE = 0
        set DOT_TYPE = DotType
        call UnitDamageTarget(Dealer,Taker,Damage,false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS)
        set LAST_DAMAGE_TYPE = -1
        set DOT_TYPE = 0
endfunction

function DealMagicalDamage takes unit Dealer, unit Taker, real Damage returns nothing
        set LAST_DAMAGE_TYPE = 1
        set DOT_TYPE = 0
        set ELEMENTAL = false
        set FROST = false
        set FIRE = false
        set WATER = false
        set ARCANE = false
        call UnitDamageTarget(Dealer,Taker,Damage,false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS)
        set LAST_DAMAGE_TYPE = -1
endfunction

function DealMagicalDamageOfType takes unit Dealer, unit Taker, real Damage, string Type returns nothing
        set LAST_DAMAGE_TYPE = 1
        set DOT_TYPE = 0
        set ELEMENTAL = false
        set FROST = false
        set EARTH = false
        set FIRE = false
        set WATER = false
        set ARCANE = false
        if Type == "FIRE" then
           set FIRE = true
           set ELEMENTAL = true
        endif
       
        if Type == "FROST" then
           set FROST = true
           set ELEMENTAL = true
        endif

        if Type == "EARTH" then
           set EARTH = true
           set ELEMENTAL = true
        endif

        if Type == "WATER" then
           set WATER = true
           set ELEMENTAL = true
        endif

        if Type == "ARCANE" then
           set ARCANE = true
           set ELEMENTAL = true
        endif    

        if Type == "ELEMENTAL" then
           set ELEMENTAL = true
        endif
        call UnitDamageTarget(Dealer,Taker,Damage,false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS)
        set LAST_DAMAGE_TYPE = -1
        set DOT_TYPE = 0
        set ELEMENTAL = false
        set FROST = false
        set EARTH = false
        set FIRE = false
        set WATER = false
        set ARCANE = false
endfunction

private function DealMagicalDamageOverTime takes unit Dealer, unit Taker, real Damage, integer DotType returns nothing
        set LAST_DAMAGE_TYPE = 1
        set DOT_TYPE = DotType
        set ELEMENTAL = false
        set FROST = false
        set EARTH = false
        set FIRE = false
        set WATER = false
        set ARCANE = false
        if DotType == 1 then
           set FIRE = true
           set ELEMENTAL = true
        endif
        if DotType == 3 then
           set FROST = true
           set ELEMENTAL = true
        endif
       
        call UnitDamageTarget(Dealer,Taker,Damage,false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS)
        set LAST_DAMAGE_TYPE = -1
        set DOT_TYPE = 0
        set ELEMENTAL = false
        set FROST = false
        set EARTH = false
        set FIRE = false
        set WATER = false
        set ARCANE = false
endfunction

function DealFrostDamage takes unit Dealer, unit Taker, real Damage returns nothing
        set LAST_DAMAGE_TYPE = 1
        set DOT_TYPE = 0
        set ELEMENTAL = false
        set FROST = true
        set EARTH = false
        set FIRE = false
        set WATER = false
        set ARCANE = false
        call UnitDamageTarget(Dealer,Taker,Damage,false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS)
        set LAST_DAMAGE_TYPE = -1
        set FROST = false
endfunction

function DealEarthDamage takes unit Dealer, unit Taker, real Damage returns nothing
        set LAST_DAMAGE_TYPE = 1
        set DOT_TYPE = 0
        set ELEMENTAL = false
        set FROST = false
        set EARTH = true
        set FIRE = false
        set WATER = false
        set ARCANE = false
        call UnitDamageTarget(Dealer,Taker,Damage,false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS)
        set LAST_DAMAGE_TYPE = -1
        set EARTH = false
endfunction

function DealFireDamage takes unit Dealer, unit Taker, real Damage returns nothing
        set LAST_DAMAGE_TYPE = 1
        set DOT_TYPE = 0
        set ELEMENTAL = true
        set FROST = false
        set EARTH = false
        set FIRE = true
        set WATER = false
        set ARCANE = false
        call UnitDamageTarget(Dealer,Taker,Damage,false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS)
        set LAST_DAMAGE_TYPE = -1
        set FIRE = false
endfunction

function DealWaterDamage takes unit Dealer, unit Taker, real Damage returns nothing
        set LAST_DAMAGE_TYPE = 1
        set DOT_TYPE = 0
        set ELEMENTAL = true
        set FROST = false
        set EARTH = false
        set FIRE = false
        set WATER = true
        set ARCANE = false
        call UnitDamageTarget(Dealer,Taker,Damage,false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS)
        set LAST_DAMAGE_TYPE = -1
        set WATER = false
endfunction

function DealArcaneDamage takes unit Dealer, unit Taker, real Damage returns nothing
        set LAST_DAMAGE_TYPE = 1
        set DOT_TYPE = 0
        set ELEMENTAL = true
        set FROST = false
        set EARTH = false
        set FIRE = false
        set WATER = false
        set ARCANE = true
        call UnitDamageTarget(Dealer,Taker,Damage,false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNIVERSAL,WEAPON_TYPE_WHOKNOWS)
        set LAST_DAMAGE_TYPE = -1
        set ARCANE = false
endfunction

function DealDotTypeDamage takes unit Dealer, unit Taker, real Damage, integer DotType returns nothing
        set DOT_TYPE = DotType

        if DotType==2 then
           call DealPhysicalDamageOverTime(Dealer,Taker,Damage,DotType)
        else
           call DealMagicalDamageOverTime(Dealer,Taker,Damage,DotType)
        endif

        set DOT_TYPE = 0
endfunction

endlibrary
hashtable keys
1 - Evasion (percent)
2 - Crit (percent)
3 - Block Amount (value)
4 - Haste (percent)
5 - Spell Power (value)
6 - Crit Multiplier (value)
7 - Splash Damage (value)
8 - Healing Reduce to unit (REDUCE TO ATTACKED UNIT) (value)
9 - Healing Received Bonus (value)
10 - Attack damage multiplier (need +1 in calculations) (value)
11 - Bonus to Healing effect, done by unit (in mult value)
12 - Critical strike % increase to Taker (in percent)
13 - Life-stealing (in value)
14 - Block Chance (percent)
15 - Chance to miss (percent)
16 - Spell Resist(value)
17 - Absorb phys damage
18 - Absorb spec effect
19 - Spell Crit
20 - Spell Crit Received Bonus
21 - Last Dealed Phys Damage
22 - Phys Dmg Reduce Multiplier (value)
23 - % bonus to OUT-Combat HP regeneration (value)
24 - % bonus to OUT-Combat MP regeneration (value)
25 - % bonus to OUT-Combat BOTH regenerations (value)
26 - % bonus to IN-Combat HP regeneration (value)
27 - % bonus to IN-Combat MP regeneration (value)
28 - % bonus to IN-Combat BOTH regenerations (value)
29 - Aggro multiplier(value)
30 - Healing Crit

30 - HeroClass (STRING)
31 - Out of Combat Timer (TIMER)
32 - IsUnitInCombat (BOOLEAN)
33 - Healing Potions used during one combat (INTEGER)
34 - Mana Potions used during one combat (INTEGER)
35 - Elixirs used during one combat (INTEGER)
36 - IsBattleElixirUsed (BOOLEAN)
37 - IsGuardElixirUsed (BOOLEAN)
38 - ARMOR PENETRATION TIMER

99 - Intervene CASTER (UNIT)
100 - Revival Integer (INTEGER)
100-199 - Hero Abilities
200-299 - SpecialUnits Storage
300 - isUnitGiant
310 - CanGiveGold
311 - CanGiveEx
//TESH.scrollpos=523
//TESH.alwaysfold=0
library DAMAGEEVENT initializer DAMAGE_EVENT_INI requires DummyCasts, AddTextTag, Angles, OutOfCombat

globals
private constant integer RANGER = 'H00O'
private constant integer WOLF = 'o00B'
private constant integer HORDECHAMPION = 'O002'
private constant integer BLOODELFCAPTAIN = 'O005'
//DAMAGE VARIABLES
group DPS_GROUP = CreateGroup() //Group for dummies which deals damage per sec
group FIRE_DPS_GROUP = CreateGroup()
group ELEMENTAL_DPS_GROUP = CreateGroup()
group ONE_ATTACK_REMOVE_GROUP = CreateGroup()
group MAP_UNITS_ALIVE = CreateGroup()
trigger DAMAGE_EVENT_TRIGGER = null
real GLOBAL_MEELE_SPLASH_ANGLE = 0.
private real SPLASH_DAMAGE = 0.
private real SPLASH_PERCENT = 0.
private real SPLASH_ANGLE = 0.
private unit SPLASH_DEALER = null
private unit SPLASH_CENTER = null
//DAMAGE CONSTANTS
private constant integer DETECTOR_RAWCODE = 'B000' //Damage Detector Buff
constant integer ARMOR_PENETRATION = 'A02A'
private constant real ARMOR_PER_EXPERTISE = 0.2
private constant real SPLASH_DAMAGE_RADIUS = 200.
private constant string SPLASH_COLOR = "|c007EBFF1"
private constant string ENEMY_PHYS_COLOR = "|c00FF0000"
private constant string MISS_COLOR = "|cffFF0000"
private constant string BLOCK_COLOR = "|c00FF0000"
private constant string CRIT_COLOR = "|c00FF0000"
private constant string RESIST_COLOR = "|c007EBFF1"
private constant string SPELL_CRIT_COLOR = "|c001CE6B9"
private constant string SPELL_COLOR = "|c000080FF"
private constant string ENEMY_SPELL_COLOR = "|cff6f2583"
private constant string ENEMY_SPELL_CRIT_COLOR = "|cff6f2583"
private constant string ABSORB_COLOR = "|c00FFFFFF"
private constant string MAGICAL_ABSORB_COLOR = "|cffff00ff"
endglobals

function fullhp takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit u = LoadUnitHandle(udg_hash,GetHandleId(t),1)
   call SetWidgetLife(u,GetUnitState(u,UNIT_STATE_MAX_LIFE))
   call FlushChildHashtable(udg_hash, GetHandleId(t))
   call DestroyTimer(t)
   set t = null
   set u = null
endfunction

function fullhpBlock takes nothing returns nothing
   local timer t = GetExpiredTimer()
   local unit u = LoadUnitHandle(udg_hash,GetHandleId(t),1)
   local real dmg = LoadReal(udg_hash,GetHandleId(t),2)
   call SetWidgetLife(u, GetWidgetLife(u) + dmg + 1.)
   call FlushChildHashtable(udg_hash, GetHandleId(t))
   call DestroyTimer(t)
   set t = null
   set u = null
endfunction

function DamageBlock takes unit u, real dmg returns nothing
local timer t = null
local real CURRENT_HP = GetWidgetLife(u)
   if CURRENT_HP <= dmg then
    call SetWidgetLife(u,CURRENT_HP + dmg + 1.)
   elseif CURRENT_HP >= (GetUnitState(u, UNIT_STATE_MAX_LIFE)-dmg) then
    set t = CreateTimer()
    call TimerStart(t,0.0,false,function fullhpBlock)
    call SaveUnitHandle(udg_hash,GetHandleId(t),1,u)
    call SaveReal(udg_hash,GetHandleId(t),2,dmg)
    set t = null
   else
   call SetWidgetLife(u,CURRENT_HP + dmg)
   endif
endfunction

function IsUnitSplashed takes location p1,location p2, real ang returns boolean
 local real a = ConvertAngleTo180(AngleBetweenPoints(p1,p2))
 local real k = DifferenceBetweenAngles(a,ConvertAngleTo180(ang))
 if (k >= 60 and k<=-60) or (k <= 60 and k>= -60) then
  return true
 else
  return false
 endif
endfunction

function SplashConds takes nothing returns boolean
 return (GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0 ) and (IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(SPLASH_DEALER)))
endfunction

function DealSplash takes nothing returns nothing
 local unit a = GetEnumUnit()
 local real curdmg = SPLASH_DAMAGE * SPLASH_PERCENT
 local location p1 = GetUnitLoc(a)
 local location p2 = GetUnitLoc(SPLASH_DEALER)
 local force play = CreateForce()
        call ForceAddPlayer(play,GetOwningPlayer(SPLASH_DEALER))
        call ForceAddPlayer(play,GetOwningPlayer(a))
 
 if (IsUnitSplashed(p1,p2,SPLASH_ANGLE+180.)) then
  call DisableTrigger(DAMAGE_EVENT_TRIGGER)
  call UnitDamageTarget(SPLASH_DEALER,a,curdmg,true,false,ATTACK_TYPE_CHAOS,null,null)
  call EnableTrigger(DAMAGE_EVENT_TRIGGER)
  if GetPlayerController(GetOwningPlayer(SPLASH_DEALER)) == MAP_CONTROL_USER and IsUnitType(SPLASH_DEALER,UNIT_TYPE_HERO) then
       call Aggro.add(a,SPLASH_DEALER,curdmg*0.05*(1.+LoadReal(udg_hash,GetHandleId(SPLASH_DEALER),29)))
  endif

  //Check Frostmourne buff on ATTACKER to add Frostmourne damage done
  if GetUnitAbilityLevel(SPLASH_DEALER,FROSTMOURNE_BUFFCODE)>0 then
    call SaveReal(udg_hash,GetHandleId(SPLASH_DEALER),FROSTMOURNE_HASHKEY_DAMAGE,LoadReal(udg_hash,GetHandleId(SPLASH_DEALER),FROSTMOURNE_HASHKEY_DAMAGE)+curdmg)
    call DestroyEffect(AddSpecialEffectTarget("Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl",GetEnumUnit(),"chest"))
  else
    call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Items\\AIfb\\AIfbSpecialArt.mdl",GetEnumUnit(),"overhead"))
  endif
  if IsUnitEnemy(SPLASH_DEALER,Player(7)) then
     set IS_PHYS_DAMAGE_TEXT = true
     call AddTextTagUnit(SPLASH_COLOR + I2S(R2I(curdmg)) + "|r",a,play,GLOBAL_MEELE_SPLASH_ANGLE,10.,1.5,-50.)
     set IS_PHYS_DAMAGE_TEXT = false
  else
     set IS_ENEMY_TEXT = true
     call AddTextTagUnit(SPLASH_COLOR + I2S(R2I(curdmg)) + "|r",a,play,GLOBAL_MEELE_SPLASH_ANGLE,10.,1.5,-50.)
     set IS_ENEMY_TEXT = false
  endif
 endif
 call DestroyForce(play)
 call RemoveLocation(p1)
 call RemoveLocation(p2)
 set a = null
 set p1 = null
 set p2 = null
 set play = null
endfunction

function DealSplash_Ranged takes nothing returns nothing
 local unit a = GetEnumUnit()
 local real curdmg = SPLASH_DAMAGE * SPLASH_PERCENT
 local force play = CreateForce()
  call ForceAddPlayer(play,GetOwningPlayer(SPLASH_DEALER))
  call ForceAddPlayer(play,GetOwningPlayer(a))
  call DisableTrigger(DAMAGE_EVENT_TRIGGER)
  call UnitDamageTarget(SPLASH_DEALER,a,curdmg,true,false,ATTACK_TYPE_CHAOS,null,null)
  call EnableTrigger(DAMAGE_EVENT_TRIGGER)
  if GetPlayerController(GetOwningPlayer(SPLASH_DEALER)) == MAP_CONTROL_USER and IsUnitType(SPLASH_DEALER,UNIT_TYPE_HERO) then
       call Aggro.add(a,SPLASH_DEALER,curdmg*0.05*(1.+LoadReal(udg_hash,GetHandleId(SPLASH_DEALER),29)))
  endif

  if IsUnitEnemy(SPLASH_DEALER,Player(7)) then
     set IS_PHYS_DAMAGE_TEXT = true
     call AddTextTagUnit(SPLASH_COLOR + I2S(R2I(curdmg)) + "|r",a,play,90.,10.,1.5,-50.)
     set IS_PHYS_DAMAGE_TEXT = false
  else
     set IS_ENEMY_TEXT = true
     call AddTextTagUnit(SPLASH_COLOR + I2S(R2I(curdmg)) + "|r",a,play,90.,10.,1.5,-50.)
     set IS_ENEMY_TEXT = false
  endif

  call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Items\\AIfb\\AIfbSpecialArt.mdl",GetEnumUnit(),"overhead"))
 call DestroyForce(play)
 set play = null
endfunction

function SplashDmg takes unit u,unit u2, real dmg,real persplash, real ang returns nothing
local location p = GetUnitLoc(u)
local group g = CreateGroup()
local boolexpr GROUPFILTER = Condition(function SplashConds)
set SPLASH_DEALER = u2
set SPLASH_CENTER = u
set SPLASH_DAMAGE = dmg
set SPLASH_PERCENT = persplash
set SPLASH_ANGLE = ang
if dmg > 0. then
call GroupEnumUnitsInRangeOfLoc(g,p,SPLASH_DAMAGE_RADIUS, GROUPFILTER)
call GroupRemoveUnit(g,u)
if IsUnitType(u2,UNIT_TYPE_RANGED_ATTACKER) then
call ForGroup(g,function DealSplash_Ranged)
else
call ForGroup(g,function DealSplash)
endif
endif
call DestroyGroup(g)
call DestroyBoolExpr(GROUPFILTER)
call RemoveLocation(p)
set g = null
set p = null
set GROUPFILTER = null
endfunction

function ReleaseFlame takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit u = LoadUnitHandle(udg_hash,GetHandleId(t),2)
local integer id = LoadInteger(udg_hash,GetHandleId(t),1)
call UnitRemoveAbility(u,id)
call FlushChildHashtable(udg_hash,GetHandleId(t))
call DestroyTimer(t)
set t = null
set u = null
endfunction

function DestroyEffectEnd takes nothing returns nothing
local timer t = GetExpiredTimer()
local effect e = LoadEffectHandle(udg_hash,GetHandleId(t),1)
call FlushChildHashtable(udg_hash,GetHandleId(t))
call DestroyEffect(e)
call DestroyTimer(t)
set t = null
set e = null
endfunction

function DestroyEffectTimed takes effect e, real dur returns nothing
local timer t = CreateTimer()
call SaveEffectHandle(udg_hash,GetHandleId(t),1,e)
call TimerStart(t,dur,false,function DestroyEffectEnd)
set t = null
endfunction

function ARMOR_RESET takes nothing returns nothing
call UnitRemoveAbility(LoadUnitHandle(udg_hash,GetHandleId(GetExpiredTimer()),1),ARMOR_PENETRATION)
call RemoveSavedHandle(udg_hash,GetHandleId(LoadUnitHandle(udg_hash,GetHandleId(GetExpiredTimer()),1)),38)
call FlushChildHashtable(udg_hash,GetHandleId(GetExpiredTimer()))
call DestroyTimer(GetExpiredTimer())
endfunction

//function UnitAddMana takes unit u, real mana returns nothing
//if (GetUnitState(u,UNIT_STATE_MAX_MANA)>200.)  then
//call RegenerateMana(u,mana)
//endif
//endfunction

function ApplyArmorPenetration takes unit whichUnit, real value returns nothing
        if GetUnitAbilityLevel(whichUnit,ARMOR_PENETRATION) > 0 then
           call SetUnitAbilityLevel(whichUnit,ARMOR_PENETRATION,GetUnitAbilityLevel(whichUnit,ARMOR_PENETRATION) + R2I(value))
           call TimerStart(LoadTimerHandle(udg_hash,GetHandleId(whichUnit),38),4.,false,function ARMOR_RESET)
        else
           call UnitAddAbility(whichUnit,ARMOR_PENETRATION)
           call SetUnitAbilityLevel(whichUnit,ARMOR_PENETRATION,R2I(value))
           call SaveTimerHandle(udg_hash,GetHandleId(whichUnit),38,CreateTimer())
           call TimerStart(LoadTimerHandle(udg_hash,GetHandleId(whichUnit),38),4.,false,function ARMOR_RESET)
           call SaveUnitHandle(udg_hash,GetHandleId(LoadTimerHandle(udg_hash,GetHandleId(whichUnit),38)),1,whichUnit)
        endif
endfunction

private function CheckBattleground takes unit ATTACKER, unit TAKER returns nothing
        local boolean TAKERHERO = IsUnitAPlayerHero(TAKER)
        local boolean ATTACKERHERO = IsUnitAPlayerHero(ATTACKER)
       
        if MAGMAW_BATTLE_INITIALIZED then
             if ATTACKER==udg_Magmaw and TAKERHERO then
                  if not IsUnitInGroup(TAKER,MAGMAW_BATTLEGROUP) then
                       call GroupAddUnit(MAGMAW_BATTLEGROUP,TAKER)
                  endif
             endif
             if TAKER==udg_Magmaw and ATTACKERHERO then
                  if not IsUnitInGroup(ATTACKER,MAGMAW_BATTLEGROUP) then
                       call GroupAddUnit(MAGMAW_BATTLEGROUP,ATTACKER)
                  endif
             endif
        endif

        if SUPREMUS_BATTLE_INITIALIZED then
             if ATTACKER==udg_Supremus and TAKERHERO then
                  if not IsUnitInGroup(TAKER,SUPREMUS_BATTLEGROUP) then
                       call GroupAddUnit(SUPREMUS_BATTLEGROUP,TAKER)
                  endif
             endif
             if TAKER==udg_Supremus and ATTACKERHERO then
                  if not IsUnitInGroup(ATTACKER,SUPREMUS_BATTLEGROUP) then
                       call GroupAddUnit(SUPREMUS_BATTLEGROUP,ATTACKER)
                  endif
             endif
        endif

        if EREDARS_BATTLE_INITIALIZED then
             if (ATTACKER==ARCHIMONDE or ATTACKER==KILJAEDEN) and TAKERHERO then
                  if not IsUnitInGroup(TAKER,EREDARS_BATTLEGROUP) then
                       call GroupAddUnit(EREDARS_BATTLEGROUP,TAKER)
                  endif
             endif
             if (TAKER==ARCHIMONDE or TAKER==KILJAEDEN) and ATTACKERHERO then
                  if not IsUnitInGroup(ATTACKER,EREDARS_BATTLEGROUP) then
                       call GroupAddUnit(EREDARS_BATTLEGROUP,ATTACKER)
                  endif
             endif
        endif
endfunction

function Damage_Detect_Main takes nothing returns nothing
//locals for both damage types
local unit TAKER = GetTriggerUnit()
local unit ATTACKER = GetEventDamageSource()
local player P_TAKER = GetOwningPlayer(TAKER)
local player P_ATTACKER = GetOwningPlayer(ATTACKER)
local integer ID_ATTACKER = GetHandleId(ATTACKER)
local integer ID_TAKER = GetHandleId(TAKER)
local real MIND = 90.
local real MAXD = 90.
local unit TARGET = GetTriggerUnit()
local boolean PhysAttackFullyBlocked = false
local boolean PhysAttackFullyReduced = false
local boolean PhysAttackFullyAbsorbed = false
local boolean MagicalAttackFullyAbsorbed = false
local boolean AttackCritical = false
local boolean PHYSICAL_ABILITY = false
local integer i = 0
local real CRIT = LoadReal(udg_hash,ID_ATTACKER,GetCritHash())
local real MULTIPLIER = LoadReal(udg_hash,ID_ATTACKER,GetCritMultiplierHash())
local real CRITADD = LoadReal(udg_hash,ID_TAKER,12)
local real AGGRO = LoadReal(udg_hash,ID_ATTACKER,29)
local real DAMAGE = 0.
local force TEXTFORCE = CreateForce()
local string TEXT = "|c00FFFFFF-"
local string ENEMY_CRIT = ""
local effect e = null
local timer t = null
local timer t1 = null
local unit tempunit = null
local integer HOLYMIGHT = 0
//locals for phys damage type
local real PENETRATION = 0.
local real REDUCTION = 0.
local real EVASION = 0.
local real BLOCKVALUE = 0.
local real ABSORB = 0.
local real Haste = 0.
local real Splash = 0.
local real Mortal = 0.
local real Healing = 0.
local real DmgInc = 0.
local real LIFESTEALING = 0.
local real BLOCKCHANCE = 0.
local real CHANCETOMISS = 0.
local integer FLAMEBREATHER = 0
local integer KANGTD = 0
local integer HUNGERING = 0
local integer BLADEBREAKER = 0
local integer SKULLFLAME = 0
local integer WALLOFTHEDEAD = 0
local integer SACREDSHIELD = 0
local integer MAGMAPLATE = 0
local integer FROSTGIANTS = 0
local integer SKULLRAM = 0
local integer FROSTFORGED = 0
//locals for spell damage type
local real SPELLPOWER = 0.
local real SPELL_CRIT = 0.
local real SPELL_CRIT_RECEIVED_BONUS = 0.
local real SPELL_CRIT_MULTIPLIER = 0.
local real SPELLRESIST = 0.
local integer INCINERATUS = 0
local integer ICECORE = 0
local integer MAGHARI = 0
local real tempr = 0.
local real ElementalsMult = 0.
//BEGIN

call CheckBattleground(ATTACKER,TAKER)

call ForceAddPlayer(TEXTFORCE,GetOwningPlayer(ATTACKER))
call ForceAddPlayer(TEXTFORCE,GetOwningPlayer(TAKER))
if IsUnitType(TAKER,UNIT_TYPE_HERO) and GetPlayerController(P_TAKER)== MAP_CONTROL_USER then //MAKE TAKER HERO IN COMBAT
//call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,15.,"Making in combat TAKER")
call MAKE_UNIT_COMBAT(TAKER)
set HOLYMIGHT = LoadInteger(udg_hash,ID_TAKER,GetGlovesOfHolyMightHash())
set SKULLRAM = LoadInteger(udg_hash,ID_TAKER,GetBrokenRamHelmHash())
set FROSTFORGED = LoadInteger(udg_hash,ID_TAKER,GetFrostforgedHelmHash())
endif
if IsUnitType(ATTACKER,UNIT_TYPE_HERO) and GetPlayerController(P_ATTACKER)== MAP_CONTROL_USER  then //MAKE ATTACKER HERO IN COMBAT
//call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,15.,"Making in combat ATTACKER")
call MAKE_UNIT_COMBAT(ATTACKER)
endif                                   //END

//Check if the damage is physical and from ability
if GetPlayerController(P_ATTACKER)== MAP_CONTROL_USER and not (GetUnitAbilityLevel(TAKER,DETECTOR_RAWCODE)>0) then
   if GetLastDamageType()=="PHYSICAL" and not IsUnitInGroup(ATTACKER,DPS_GROUP) then
      set PHYSICAL_ABILITY = true
   endif
endif

if IsUnitInGroup(ATTACKER,WATER_CLEANSING_DUMMIES) then
     if IsUnitCarriesWater(TAKER) then
         call DestroyEffect(AddSpecialEffectTarget("Abilities\\Weapons\\WaterElementalMissile\\WaterElementalMissile.mdl",ATTACKER,"origin"))
         call KillUnit(ATTACKER)
     endif
endif

if GetUnitAbilityLevel(TAKER,DETECTOR_RAWCODE)>0 or PHYSICAL_ABILITY then //PHYS DAMAGE CHECK
call UnitRemoveAbility(TAKER,DETECTOR_RAWCODE)

//Check Intervene buff on TAKER to redirect
if GetUnitAbilityLevel(TAKER,'B00A')>0 then
     set tempunit = LoadUnitHandle(udg_hash,ID_TAKER,99)
     if not IsUnitType(tempunit,UNIT_TYPE_DEAD) then
     call DamageBlock(TAKER,GetEventDamage())
     set TAKER = tempunit
     set P_TAKER = GetOwningPlayer(TAKER)
     set ID_TAKER = GetHandleId(TAKER)
     call DisableTrigger(DAMAGE_EVENT_TRIGGER)
     call UnitDamageTarget(ATTACKER,TAKER,GetEventDamage(),true,false,ATTACK_TYPE_CHAOS,null,null)
     call EnableTrigger(DAMAGE_EVENT_TRIGGER)
     endif
endif

//Check PresenceOfTheLichKing buff to freeze
if GetUnitAbilityLevel(TAKER,PRESENCE_BUFFCODE)>0 then
     if LoadInteger(udg_hash,ID_TAKER,PRESENCE_HASH_CHARGES)>0 then
         call SaveUnitHandle(udg_hash,GetHandleId(PRESENCE_TIMER),1,ATTACKER)
         call SaveUnitHandle(udg_hash,GetHandleId(PRESENCE_TIMER),2,TAKER)
         call TimerStart(PRESENCE_TIMER,0.0,false,null)
     endif
endif

set REDUCTION = LoadReal(udg_hash,ID_TAKER,22)
set EVASION = LoadReal(udg_hash,ID_TAKER,1)
set BLOCKVALUE = LoadReal(udg_hash,ID_TAKER,3)
//set ABSORB = LoadReal(udg_hash,ID_TAKER,17)
set Haste = LoadReal(udg_hash,ID_ATTACKER,4)
set Splash = LoadReal(udg_hash,ID_ATTACKER,7)
set Mortal = LoadReal(udg_hash,ID_ATTACKER,8)
set Healing = LoadReal(udg_hash,ID_TAKER,9)
set DmgInc = LoadReal(udg_hash,ID_ATTACKER,10)
set LIFESTEALING = LoadReal(udg_hash,ID_ATTACKER,13)
set BLOCKCHANCE = LoadReal(udg_hash,ID_TAKER,14)
set CHANCETOMISS = LoadReal(udg_hash,ID_ATTACKER,15)

if not IsUnitType(ATTACKER,UNIT_TYPE_MELEE_ATTACKER) then
    set Haste = Haste * 0.5
endif

if IsUnitType(ATTACKER,UNIT_TYPE_HERO) then
//INITIALIZATION PHYS ATTACK ITEMS
set PENETRATION = I2R(GetHeroAgi(ATTACKER,true))
set HUNGERING = LoadInteger(udg_hash,ID_ATTACKER,GetHungeringColdHash())
set BLADEBREAKER = LoadInteger(udg_hash,ID_ATTACKER,GetBladebreakerHash())
set KANGTD = LoadInteger(udg_hash,ID_ATTACKER,GetKangHash())
set FLAMEBREATHER = LoadInteger(udg_hash,ID_ATTACKER,GetFlameBreatherHash())
//ENDINI
endif



if IsUnitType(TAKER,UNIT_TYPE_HERO) then
//INITIALIZATION PHYS DEFEND ITEMS
set SKULLFLAME = LoadInteger(udg_hash,ID_TAKER,GetSkullflameHash())
set WALLOFTHEDEAD = LoadInteger(udg_hash,ID_TAKER,GetWallOfTheDeadHash())
set SACREDSHIELD = LoadInteger(udg_hash,ID_TAKER,GetSacredProtectorHash())
set MAGMAPLATE = LoadInteger(udg_hash,ID_TAKER,GetMagmaBreastplateHash())
set FROSTGIANTS = LoadInteger(udg_hash,ID_TAKER,GetFrostgiantGlovesHash())
//ENDINI
endif
set TEXT = "|c00FFFFFF-"
if IsUnitType(ATTACKER,UNIT_TYPE_MELEE_ATTACKER) then
set MIND = GetUnitFacing(ATTACKER)
set MAXD = MIND
set GLOBAL_MEELE_SPLASH_ANGLE = MIND
endif
set DAMAGE = ( GetEventDamage()*(1. + DmgInc) )
if PHYSICAL_ABILITY and IsLastDamageDot() and GetLastDotType()=="BLEEDING" then
      set tempr = LoadReal(udg_hash,ID_ATTACKER, GetBleedingDamageBonusHash())+LoadReal(udg_hash,ID_TAKER,GetBleedingDamageReceivedBonusHash())
      if tempr > 0 then
         call DisableTrigger(DAMAGE_EVENT_TRIGGER)
         call UnitDamageTarget(ATTACKER,TAKER,DAMAGE*tempr,true,false,ATTACK_TYPE_CHAOS,null,null)
         call EnableTrigger(DAMAGE_EVENT_TRIGGER)
         set DAMAGE = DAMAGE * (1 + tempr)
      endif
endif

//Check Frostmourne buff on ATTACKER to trigger effects
if GetUnitAbilityLevel(ATTACKER,FROSTMOURNE_BUFFCODE)>0 then
    if not LoadBoolean(udg_hash,GetHandleId(ATTACKER),FROSTMOURNE_HASHKEY_FLAG) then
        call SaveBoolean(udg_hash,GetHandleId(ATTACKER),FROSTMOURNE_HASHKEY_FLAG,true)
        set Splash = Splash + 0.25*GetUnitAbilityLevel(ATTACKER,FROSTMOURNE_ABILCODE)
        set tempr = DAMAGE + GetUnitSpellPower(ATTACKER)*(0.125*GetUnitAbilityLevel(ATTACKER,FROSTMOURNE_ABILCODE))
        if LoadInteger(udg_hash,ID_ATTACKER,INEXORABLE_ASSAULT_LEVEL_HASH)>0 then
           set tempr = tempr + GetUnitSpellPower(ATTACKER)*LoadInteger(udg_hash,ID_ATTACKER,INEXORABLE_ASSAULT_LEVEL_HASH)*INEXORABLE_ASSAULT_SPELLPOWER_EFFECT_BONUS
           set CRIT = CRIT + LoadInteger(udg_hash,ID_ATTACKER,INEXORABLE_ASSAULT_LEVEL_HASH)*INEXORABLE_ASSAULT_CRIT_INCREASE
        endif    
        call DisableTrigger(DAMAGE_EVENT_TRIGGER)
        call UnitDamageTarget(ATTACKER,TAKER,tempr-DAMAGE,true,false,ATTACK_TYPE_CHAOS,null,null)
        call EnableTrigger(DAMAGE_EVENT_TRIGGER)
        set DAMAGE = tempr      
        call SaveUnitHandle(udg_hash,GetHandleId(FROSTMOURNE_TIMER),1,ATTACKER)
        if LoadInteger(udg_hash,GetHandleId(ATTACKER),FROSTMOURNE_HASHKEY_CHARGES) >= 4 then
           set CRIT = CRIT + 100.
        endif
        call TimerStart(FROSTMOURNE_TIMER,0.0,false,null)
    endif
endif

//Check ChimaeraShot buff on ATTACKER
if GetUnitAbilityLevel(ATTACKER,CHIMAERASHOT_BUFFCODE)>0 and not PHYSICAL_ABILITY then
        call UnitRemoveAbility(ATTACKER,CHIMAERASHOT_BUFFCODE)
        call UnitRemoveAbility(ATTACKER,CHIMAERASHOT_VENOMCODE)
        call SaveUnitHandle(udg_hash,GetHandleId(CHIMAERASHOT_TIMER),1,ATTACKER)
        call SaveUnitHandle(udg_hash,GetHandleId(CHIMAERASHOT_TIMER),2,TAKER)
        call TimerStart(CHIMAERASHOT_TIMER,0.0,false,null)
endif

//Check KillCommand buff on ATTACKER

if GetUnitAbilityLevel(ATTACKER,KILLCOMMAND_WOLFABILCODE)>0 then
        set Splash = Splash + KILLCOMMAND_SPLASH*GetUnitAbilityLevel(ATTACKER,KILLCOMMAND_WOLFABILCODE)
        call DisableTrigger(DAMAGE_EVENT_TRIGGER)
        call UnitDamageTarget(ATTACKER,TAKER,KILLCOMMAND_WOLFBONUSDAMAGE*GetUnitAbilityLevel(ATTACKER,KILLCOMMAND_WOLFABILCODE),true,false,ATTACK_TYPE_CHAOS,null,null)
        call EnableTrigger(DAMAGE_EVENT_TRIGGER)
        set DAMAGE = DAMAGE + KILLCOMMAND_WOLFBONUSDAMAGE*GetUnitAbilityLevel(ATTACKER,KILLCOMMAND_WOLFABILCODE)
        call SaveUnitHandle(udg_hash,GetHandleId(KILLCOMMAND_TIMER),1,ATTACKER)
        call SaveUnitHandle(udg_hash,GetHandleId(KILLCOMMAND_TIMER),2,TAKER)
        call TimerStart(KILLCOMMAND_TIMER,0.0,false,null)
endif

//Check Felhammer (Pit Lord) buff
if GetUnitAbilityLevel(ATTACKER,FELHAMMER_BUFFCODE)>0 then
        set Splash = Splash + FELHAMMER_SPLASH
        call DisableTrigger(DAMAGE_EVENT_TRIGGER)
        call UnitDamageTarget(ATTACKER,TAKER,FELHAMMER_BONUSDAMAGE,true,false,ATTACK_TYPE_CHAOS,null,null)
        call EnableTrigger(DAMAGE_EVENT_TRIGGER)
        set DAMAGE = DAMAGE + FELHAMMER_BONUSDAMAGE
        call SaveUnitHandle(udg_hash,GetHandleId(FELHAMMER_TIMER),1,ATTACKER)
        call SaveUnitHandle(udg_hash,GetHandleId(FELHAMMER_TIMER),2,TAKER)
        call TimerStart(FELHAMMER_TIMER,0.0,false,null)
endif

//Check Legion Strike(Felguard Annihilator) buff
if GetUnitAbilityLevel(ATTACKER,LEGION_STRIKE_BUFFCODE)>0 then
        set Splash = Splash + LEGION_STRIKE_SPLASH
        call DisableTrigger(DAMAGE_EVENT_TRIGGER)
        call UnitDamageTarget(ATTACKER,TAKER,LEGION_STRIKE_BONUSDAMAGE,true,false,ATTACK_TYPE_CHAOS,null,null)
        call EnableTrigger(DAMAGE_EVENT_TRIGGER)
        set DAMAGE = DAMAGE + LEGION_STRIKE_BONUSDAMAGE
        call SaveUnitHandle(udg_hash,GetHandleId(LEGION_STRIKE_TIMER),1,ATTACKER)
        call SaveUnitHandle(udg_hash,GetHandleId(LEGION_STRIKE_TIMER),2,TAKER)
        call TimerStart(LEGION_STRIKE_TIMER,0.0,false,null)
endif

//Check Punishment (Succub) buff
if GetUnitAbilityLevel(ATTACKER,PUNISHMENT_BUFFCODE)>0 then
        call SaveUnitHandle(udg_hash,GetHandleId(PUNISHMENT_TIMER),1,ATTACKER)
        call SaveUnitHandle(udg_hash,GetHandleId(PUNISHMENT_TIMER),2,TAKER)
        call TimerStart(PUNISHMENT_TIMER,0.0,false,null)
endif

//Check Firehands (Kiljaeden) buff
if GetUnitAbilityLevel(ATTACKER,FIREHANDS_BUFFCODE)>0 then
        set Splash = Splash + FIREHANDS_SPLASH
        call DisableTrigger(DAMAGE_EVENT_TRIGGER)
        call UnitDamageTarget(ATTACKER,TAKER,FIREHANDS_BONUSDAMAGE,true,false,ATTACK_TYPE_CHAOS,null,null)
        call EnableTrigger(DAMAGE_EVENT_TRIGGER)
        set DAMAGE = DAMAGE + FIREHANDS_BONUSDAMAGE
        call SaveUnitHandle(C3_hash,GetHandleId(FIREHANDS_TIMER),1,ATTACKER)
        call SaveUnitHandle(C3_hash,GetHandleId(FIREHANDS_TIMER),2,TAKER)
        call TimerStart(FIREHANDS_TIMER,0.0,false,null)
endif

//Check Null Barrier (Archimonde) buff
if GetUnitAbilityLevel(TAKER,NULLBARRIER_BUFFCODE)>0 then
        call SaveUnitHandle(C3_hash,GetHandleId(NULLBARRIER_TIMER),1,ATTACKER)
        call SaveUnitHandle(C3_hash,GetHandleId(NULLBARRIER_TIMER),2,TAKER)
        call TimerStart(NULLBARRIER_TIMER,0.0,false,null)
endif

//Refresh Ranger last target for Wolf
if GetUnitTypeId(ATTACKER)==RANGER and not PHYSICAL_ABILITY then
        call SaveUnitHandle(udg_hash,GetHandleId(LoadUnitHandle(udg_hash,ID_ATTACKER,SUMMON_WOLF_WOLFCASTERHASH)),SUMMON_WOLF_LASTRANGERTARGETHASH,TAKER)
        if LoadInteger(udg_hash,ID_ATTACKER,KILLER_INSTINCT_LEVEL_HASH)>0 and GetWidgetLife(TAKER)/GetUnitState(TAKER,UNIT_STATE_MAX_LIFE) < KILLER_INSTINCT_HP_THRESHOLD  then
           set CRIT = CRIT + KILLER_INSTINCT_CRIT_BONUS*LoadInteger(udg_hash,ID_ATTACKER,KILLER_INSTINCT_LEVEL_HASH)
        endif
endif

//Apply killer instinct or Smell of Blood for Wolf
if GetUnitTypeId(ATTACKER) == WOLF then
        if LoadInteger(udg_hash,ID_ATTACKER,KILLER_INSTINCT_LEVEL_HASH)>0 and GetWidgetLife(TAKER)/GetUnitState(TAKER,UNIT_STATE_MAX_LIFE) < KILLER_INSTINCT_HP_THRESHOLD  then
           set CRIT = CRIT + KILLER_INSTINCT_CRIT_BONUS*LoadInteger(udg_hash,ID_ATTACKER,KILLER_INSTINCT_LEVEL_HASH)
        endif
        if LoadInteger(udg_hash,ID_ATTACKER,SMELL_OF_BLOOD_LEVEL_HASH)>0 and IsUnitDotBleeding(TAKER) then
           set DAMAGE = DAMAGE * (1 + SMELL_OF_BLOOD_DAMAGE_INC*LoadInteger(udg_hash,ID_ATTACKER,SMELL_OF_BLOOD_LEVEL_HASH))
           call DisableTrigger(DAMAGE_EVENT_TRIGGER)
           call UnitDamageTarget(ATTACKER,TAKER,DAMAGE*SMELL_OF_BLOOD_DAMAGE_INC*LoadInteger(udg_hash,ID_ATTACKER,SMELL_OF_BLOOD_LEVEL_HASH),true,false,ATTACK_TYPE_CHAOS,null,null)
           call EnableTrigger(DAMAGE_EVENT_TRIGGER)
        endif
endif

if GetUnitTypeId(ATTACKER) == BLOODELFCAPTAIN and not PHYSICAL_ABILITY then
     if GetRandomInt(0,100) <= LoadInteger(udg_hash,ID_ATTACKER,HEAVY_REPERCUSSIONS_LEVEL_HASH)*HEAVY_REPERCUSSIONS_PROC_CHANCE then
          call BlzEndUnitAbilityCooldown(ATTACKER,SHIELD_SLAM_ABILCODE)
     endif
endif

if REDUCTION > 0 then
if REDUCTION <= 1. then
call DamageBlock(TAKER,DAMAGE*REDUCTION)
else
call DamageBlock(TAKER,DAMAGE)
endif
set DAMAGE = DAMAGE - (DAMAGE*REDUCTION)
if DAMAGE <= 0. then
set PhysAttackFullyReduced = true
endif
elseif REDUCTION < 0 then
call DisableTrigger(DAMAGE_EVENT_TRIGGER)
call UnitDamageTarget(ATTACKER,TARGET,-1.*DAMAGE*REDUCTION,true,false,ATTACK_TYPE_CHAOS,null,null)
call EnableTrigger(DAMAGE_EVENT_TRIGGER)
set DAMAGE = DAMAGE + (-1.*DAMAGE * REDUCTION)
endif
    if GetOwningPlayer(ATTACKER) == Player(7) then
     set TEXT = ENEMY_PHYS_COLOR + "-"
     set MAXD = MIND + 90.
     set MIND = MIND - 90.
    endif
    if HUNGERING > 0 and not PHYSICAL_ABILITY then
       if GetRandomReal(1.,100.)<=GetHungeringColdProcChance() and not HasUnitCooldownHash(ATTACKER,GetHungeringColdHash()) then
           call DummyCastNonTarget(ATTACKER,GetHungeringColdAbil(),HUNGERING,"howlofterror")
           call UnitAddHashCooldown(ATTACKER,GetHungeringColdHash(),GetHungeringColdCooldown())
       endif
    endif
    if BLADEBREAKER > 0 and not PHYSICAL_ABILITY then
      if GetRandomReal(1.,100.)<=GetBladebreakerProcChance() and not HasUnitCooldownHash(ATTACKER,GetBladebreakerHash()) then
           call DOT(ATTACKER,TAKER,GetBladebreakerDamage()*BLADEBREAKER,GetBladebreakerDotDuration(),GetBladebreakerDotPeriod(),2,"Objects\\Spawnmodels\\Orc\\Orcblood\\BattrollBlood.mdl","chest",false)
           call UnitAddHashCooldown(ATTACKER,GetBladebreakerHash(),GetBladebreakerCooldown())
      endif    
    endif
    if FLAMEBREATHER > 0 and not PHYSICAL_ABILITY then
     if GetRandomReal(1.,100.) <= GetFlameBreatherProcChance() and not HasUnitCooldownHash(ATTACKER,GetFlameBreatherHash()) then
      set t = CreateTimer()
      call TimerStart(t,10.,false,function ReleaseFlame)
      call SaveUnitHandle(udg_hash,GetHandleId(t),2,ATTACKER)
      call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\BattleRoar\\RoarCaster.mdl",ATTACKER,"origin"))
      call UnitAddAbility(ATTACKER,'A007')
      call SetUnitAbilityLevel(ATTACKER,'A007',FLAMEBREATHER)
      call SaveInteger(udg_hash,GetHandleId(t),1,'A007')    
      call UnitAddHashCooldown(ATTACKER,GetFlameBreatherHash(),GetFlameBreatherCooldown())
    endif
     
    endif
    if (GetRandomReal(1.,100.) <= Haste) and GetUnitAbilityLevel(ATTACKER,'A002') <= 0 then
     call UnitAddAbility(ATTACKER,'A002')
     set MIND = 45
     set MAXD = 135
    else
    call UnitRemoveAbility(ATTACKER,'A002')
    endif
    if Mortal>0. then
     call AddHeroParameter(TAKER,-Mortal,5.,9,"","")
     call AddHeroParameter(ATTACKER,-Mortal,5.,8,"","")
    endif
    if DAMAGE > 0. then
if (GetRandomReal(1.,100.) <= EVASION + CHANCETOMISS) and GetUnitAbilityLevel(ATTACKER,'B004')<=0 then
        set TEXT = MISS_COLOR + "miss|r"
        set TARGET = ATTACKER
        call DamageBlock(TAKER,DAMAGE)
        set DAMAGE = 0.
        if SACREDSHIELD > 0 then
              if not HasUnitCooldownHash(TAKER,GetSacredProtectorHash()) then
                 call AddHeroParameter(TAKER,SACREDSHIELD,10.,9,"Abilities\\Spells\\NightElf\\FaerieDragonInvis\\FaerieDragon_Invis.mdl","overhead")
                 call UnitAddHashCooldown(TAKER,GetSacredProtectorHash(),GetSacredProtectorCooldown())
              endif
        endif
        if FROSTGIANTS > 0 then
         if not HasUnitCooldownHash(TAKER,GetFrostgiantGlovesHash()) then
            set IHP_ABI = 'A030'
            set IHP_BUFFER = 'B00S'
            call AddHeroParameter(TAKER,0.,GetFrostgiantGlovesDuration()*FROSTGIANTS,0,"","")
            call UnitAddHashCooldown(TAKER,GetFrostgiantGlovesHash(),GetFrostgiantGlovesCooldown())
         endif
        endif
elseif (GetRandomReal(1.,100.) <= CRIT + CRITADD) and (GetUnitAbilityLevel(TAKER,'A030') <= 0) then
        call DisableTrigger(DAMAGE_EVENT_TRIGGER)
        call UnitDamageTarget(ATTACKER,TAKER,DAMAGE*(1.+MULTIPLIER),true,false, ATTACK_TYPE_CHAOS,null,null)
        call EnableTrigger(DAMAGE_EVENT_TRIGGER)
        if GetPlayerController(P_ATTACKER) == MAP_CONTROL_USER then
        set TEXT ="<" + TEXT + CRIT_COLOR + I2S( R2I((2.0 + MULTIPLIER) * DAMAGE) ) + "|r>"
        set AttackCritical = true
        else
        set ENEMY_CRIT = "!"
        endif
        set DAMAGE = DAMAGE * (2.+MULTIPLIER)
        //Checking for deep wounds
        if GetUnitTypeId(ATTACKER)==HORDECHAMPION and not IS_BLOOD_HURRICANE_DAMAGE then
            if LoadInteger(udg_hash,ID_ATTACKER,DEEP_WOUNDS_LEVEL_HASH) > 0 then
                 call AUTODOT(ATTACKER,TAKER,DAMAGE*(DEEP_WOUNDS_BLEED_DAMAGE*LoadInteger(udg_hash,ID_ATTACKER,DEEP_WOUNDS_LEVEL_HASH)),DEEP_WOUNDS_BLEED_DURATION,DEEP_WOUNDS_BLEED_PERIOD,2,"Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl","chest",false)
            endif
        endif

        if GetUnitAbilityLevel(ATTACKER,'B001') > 0 and not PHYSICAL_ABILITY then
         call AddHeroParameter(ATTACKER,0.1*I2R(GetUnitAbilityLevel(ATTACKER,'A003')),10.,6,"none","none")
        endif
        if KANGTD > 0 then
            if not HasUnitCooldownHash(ATTACKER,GetKangHash()) then
               call DummyCastNonTarget(ATTACKER,GetKangAbil(),KANGTD,"howlofterror")
               call UnitAddHashCooldown(ATTACKER,GetKangHash(),GetKangCooldown())
            endif
        endif
        if PENETRATION > 0. and not PHYSICAL_ABILITY then
          if GetUnitAbilityLevel(TAKER,ARMOR_PENETRATION) > 0 then
           if GetRandomReal(1.,100.) <= 30. then
           call SetUnitAbilityLevel(TAKER,ARMOR_PENETRATION,GetUnitAbilityLevel(TAKER,ARMOR_PENETRATION) + R2I(PENETRATION * 0.2))
           call TimerStart(LoadTimerHandle(udg_hash,ID_TAKER,38),5.,false,function ARMOR_RESET)
           endif
          else
           call UnitAddAbility(TAKER,ARMOR_PENETRATION)
           call SetUnitAbilityLevel(TAKER,ARMOR_PENETRATION,R2I(PENETRATION * 0.2))
           call SaveTimerHandle(udg_hash,ID_TAKER,38,CreateTimer())
           call TimerStart(LoadTimerHandle(udg_hash,ID_TAKER,38),5.,false,function ARMOR_RESET)
           call SaveUnitHandle(udg_hash,GetHandleId(LoadTimerHandle(udg_hash,ID_TAKER,38)),1,TAKER)
         endif
        endif
else
        if DmgInc > 0. then
        call DisableTrigger(DAMAGE_EVENT_TRIGGER)
        call UnitDamageTarget(ATTACKER,TAKER,DAMAGE + BLOCKVALUE - GetEventDamage(),true,false,ATTACK_TYPE_CHAOS,null,null)
        call EnableTrigger(DAMAGE_EVENT_TRIGGER)
        endif
endif
endif
set ABSORB = UnitShield.Block(TAKER,DAMAGE,0)
if ABSORB > 0. and DAMAGE>0. then
 if ABSORB >= DAMAGE then
  call DamageBlock(TAKER,DAMAGE)
  set DAMAGE = 0.
  set PhysAttackFullyAbsorbed = true
 else
  call DamageBlock(TAKER,ABSORB)
  set DAMAGE = DAMAGE - ABSORB
 endif
endif
if GetRandomReal(1.,100.) <= BLOCKCHANCE and BLOCKVALUE > 0. and DAMAGE > 0. then
     if BLOCKVALUE > DAMAGE then
     call DamageBlock(TAKER,DAMAGE)
     set DAMAGE = 0.
     set PhysAttackFullyBlocked = true
     else
     call DamageBlock(TAKER,BLOCKVALUE)
     set DAMAGE = DAMAGE - BLOCKVALUE
     endif
     if SKULLFLAME > 0 then
     call DealPhysicalDamage(TAKER,ATTACKER,BLOCKVALUE*SKULLFLAME*GetSkullflameDamage())
     call DestroyEffect(AddSpecialEffectTarget("Abilities\\Weapons\\GyroCopter\\GyroCopterMissile.mdl",ATTACKER,"head"))
     endif
     if WALLOFTHEDEAD > 0 then
         if not HasUnitCooldownHash(TAKER,GetWallOfTheDeadHash()) then
             call AddHeroParameter(TAKER,WALLOFTHEDEAD*GetWallOfTheDeadBlock(),GetWallOfTheDeadDuration(),GetBlockAmountHash(),"none","none")
             call UnitAddHashCooldown(TAKER,GetWallOfTheDeadHash(),GetWallOfTheDeadCooldown())
         endif
     endif
endif
if DAMAGE > 0. then
 if not AttackCritical then
  set TEXT = TEXT + I2S(R2I(DAMAGE)) + ENEMY_CRIT
 endif
if Splash > 0. and not PHYSICAL_ABILITY then
call SplashDmg(TAKER,ATTACKER,DAMAGE,Splash,GetUnitFacing(ATTACKER))
endif
if LIFESTEALING > 0. and not PHYSICAL_ABILITY then
    call HealUnit(ATTACKER,ATTACKER,DAMAGE*LIFESTEALING)
    if not IS_BLOOD_HURRICANE_DAMAGE then
         call DestroyEffectTimed(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\VampiricAura\\VampiricAuraTarget.mdl",ATTACKER,"chest"),1.)
    endif
endif
call SaveReal(udg_hash,ID_ATTACKER,21,DAMAGE)
endif
if PhysAttackFullyReduced then
set TEXT = "|c00FFFF80immune|r"
elseif PhysAttackFullyBlocked then
set TEXT = BLOCK_COLOR + "block|r"
elseif PhysAttackFullyAbsorbed then
set TEXT = "|c00FFFFFFabsorb|r"
endif
if MAGMAPLATE > 0 then
 if GetWidgetLife(TAKER) - DAMAGE <= GetUnitState(TAKER,UNIT_STATE_MAX_LIFE) * GetMagmaBreastplateThreshold() and not HasUnitCooldownHash(TAKER,GetMagmaBreastplateHash()) then
  call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Demon\\DarkPortal\\DarkPortalTarget.mdl",TAKER,"origin"))
  call AddHeroParameter(TAKER,GetMagmaBreastplateDodge()*MAGMAPLATE,GetMagmaBreastplateDuration(),GetEvasionHash(),"Abilities\\Spells\\Orc\\SpiritLink\\SpiritLinkTarget.mdl","chest")
  call UnitAddHashCooldown(TAKER,GetMagmaBreastplateHash(),GetMagmaBreastplateCooldown())
 endif
endif
if HOLYMIGHT > 0 and GetUnitAbilityLevel(TAKER,'A02Z') > 0 then
     call RegenerateMana(TAKER,DAMAGE*GetGlovesOfHolyMightDamageConsumed()*HOLYMIGHT)
endif
if SKULLRAM > 0 and GetUnitAbilityLevel(TAKER,'A036') > 0 then
call SetUnitAbilityLevel(TAKER,'A036',GetUnitAbilityLevel(TAKER,'A036') + R2I(SKULLRAM*GetBrokenRamHelmDamageConsume()*DAMAGE/5.))
endif
if FROSTFORGED > 0 then
 if GetWidgetLife(TAKER) - DAMAGE <= GetUnitState(TAKER,UNIT_STATE_MAX_LIFE) * GetFrostforgedHelmHpThreshold() and not HasUnitCooldownHash(TAKER,GetFrostforgedHelmHash()) then
  set IHP_ABI = 'A037'
  set IHP_BUFFER = 'B00V'
  call AddHeroParameter(TAKER,FROSTFORGED*GetFrostforgedHelmReceivedHealingBonus(),GetFrostforgedHelmDuration(),GetReceivedHealingBonusHash(),"","")
  call UnitAddHashCooldown(TAKER,GetFrostforgedHelmHash(),GetFrostforgedHelmCooldown())
 endif
endif

if not IS_BLOOD_HURRICANE_DAMAGE then

if IsUnitEnemy(TARGET,Player(7)) then
     set IS_ENEMY_TEXT = true
     call AddTextTagUnit(TEXT,TARGET,TEXTFORCE,GetRandomReal(MIND,MAXD),10.,1.5,-50.)
     set IS_ENEMY_TEXT = false
else
     set IS_PHYS_DAMAGE_TEXT = true
     call AddTextTagUnit(TEXT,TARGET,TEXTFORCE,GetRandomReal(MIND,MAXD),10.,1.5,-50.)
     set IS_PHYS_DAMAGE_TEXT = false
endif

endif

//Check if Horde Champion and add rage
if GetUnitTypeId(ATTACKER)==HORDECHAMPION or GetUnitTypeId(ATTACKER)==BLOODELFCAPTAIN and DAMAGE>0. then
     if PHYSICAL_ABILITY then
        call RegenerateRage(ATTACKER,0.01*DAMAGE*0.25)
     else
        call RegenerateRage(ATTACKER,0.01*DAMAGE)
     endif
endif
if GetUnitTypeId(TAKER)==BLOODELFCAPTAIN and DAMAGE>0. then
      call RegenerateRage(TAKER,0.01*DAMAGE*0.5)
endif
//Check Frostmourne buff on ATTACKER to add Frostmourne damage done
if GetUnitAbilityLevel(ATTACKER,FROSTMOURNE_BUFFCODE)>0 then
    call SaveReal(udg_hash,GetHandleId(ATTACKER),FROSTMOURNE_HASHKEY_DAMAGE,LoadReal(udg_hash,GetHandleId(ATTACKER),FROSTMOURNE_HASHKEY_DAMAGE)+DAMAGE)
endif
//----------------------------------------------------------------------------------------------------------
else //Begining of Spell Damage Actions
     set SPELLRESIST = LoadReal(udg_hash,ID_TAKER,GetSpellResistHash())
     set SPELL_CRIT = LoadReal(udg_hash,ID_ATTACKER,GetSpellCritHash())
     set SPELL_CRIT_RECEIVED_BONUS = LoadReal(udg_hash,ID_TAKER,GetSpellCritReceivedBonusHash())
     set SPELL_CRIT_MULTIPLIER = LoadReal(udg_hash,ID_TAKER,GetSpellCritMultiplierHash())

     if IsUnitType(ATTACKER,UNIT_TYPE_HERO) then
     //INI SPELL COMBAT ITEMS
          set INCINERATUS = LoadInteger(udg_hash,ID_ATTACKER,GetIncineratusHash())
          set ICECORE = LoadInteger(udg_hash,ID_ATTACKER,GetIcecoreStaffHash())
          set MAGHARI = LoadInteger(udg_hash,ID_ATTACKER,GetMaghariHash())
     //ENDINI
     endif

     set DAMAGE = GetEventDamage()

     if IsLastDamageElemental() or IsUnitInGroup(ATTACKER,ELEMENTAL_DPS_GROUP) then
          set ElementalsMult = ElementalsMult + LoadReal(udg_hash,ID_ATTACKER,GetElementalDamageBonusHash())
          set ElementalsMult = ElementalsMult + LoadReal(udg_hash,ID_TAKER,GetElementalDamageReceivedBonusHash())
     endif
     if IsLastDamageFire() or IsUnitInGroup(ATTACKER,FIRE_DPS_GROUP) then
          set ElementalsMult = ElementalsMult + LoadReal(udg_hash,ID_ATTACKER,GetFireDamageBonusHash())
          set ElementalsMult = ElementalsMult + LoadReal(udg_hash,ID_TAKER,GetFireDamageReceivedBonusHash())
     endif
     if IsLastDamageFrost() then
          set ElementalsMult = ElementalsMult + LoadReal(udg_hash,ID_ATTACKER,GetFrostDamageBonusHash())
          set ElementalsMult = ElementalsMult + LoadReal(udg_hash,ID_TAKER,GetFireDamageReceivedBonusHash())
     endif
     if IsLastDamageWater() then
          set ElementalsMult = ElementalsMult + LoadReal(udg_hash,ID_ATTACKER,GetWaterDamageBonusHash())
          set ElementalsMult = ElementalsMult + LoadReal(udg_hash,ID_TAKER,GetWaterDamageReceivedBonusHash())
     endif
     if IsLastDamageEarth() then
          set ElementalsMult = ElementalsMult + LoadReal(udg_hash,ID_ATTACKER,GetEarthDamageBonusHash())
          set ElementalsMult = ElementalsMult + LoadReal(udg_hash,ID_TAKER,GetEarthDamageReceivedBonusHash())
     endif
     if IsLastDamageArcane() then
          set ElementalsMult = ElementalsMult + LoadReal(udg_hash,ID_ATTACKER,GetArcaneDamageBonusHash())
          set ElementalsMult = ElementalsMult + LoadReal(udg_hash,ID_TAKER,GetArcaneDamageReceivedBonusHash())
     endif
     if IsLastDamageDot() then
          set ElementalsMult = ElementalsMult + LoadReal(udg_hash,ID_ATTACKER,GetPeriodicDamageBonusHash())
     endif
     if IsUnitDoted(TAKER) then
          set ElementalsMult = ElementalsMult + LoadReal(udg_hash,ID_ATTACKER,GetDotedUnitsSpellDamageBonusHash())
     endif

     if ElementalsMult>0. then
          call DisableTrigger(DAMAGE_EVENT_TRIGGER)
          call UnitDamageTarget(ATTACKER,TAKER,DAMAGE*ElementalsMult,false,true,ATTACK_TYPE_CHAOS,null,null)
          call EnableTrigger(DAMAGE_EVENT_TRIGGER)
          set DAMAGE = DAMAGE * (1 + ElementalsMult)
     endif

     if IsUnitInGroup(ATTACKER,DPS_GROUP) then
          set SPELLPOWER = LoadReal(udg_hash,ID_ATTACKER,5)
          set DAMAGE = DAMAGE + SPELLPOWER
          call DisableTrigger(DAMAGE_EVENT_TRIGGER)
          call UnitDamageTarget(ATTACKER,TAKER,SPELLPOWER,false,true,ATTACK_TYPE_CHAOS,null,null)
          call EnableTrigger(DAMAGE_EVENT_TRIGGER)
     endif

     if INCINERATUS > 0 then
          if GetRandomReal(1.,100.) <= GetIncineratusProcChance() and not HasUnitCooldownHash(ATTACKER,GetIncineratusHash()) then
               call DOT(ATTACKER,TAKER,INCINERATUS*GetIncineratusDotDamage(),GetIncineratusDotDuration(),GetIncineratusDotPeriod(),1,"Abilities\\Spells\\Items\\AIfb\\AIfbSpecialArt.mdl","chest",false)
               call UnitAddHashCooldown(ATTACKER,GetIncineratusHash(),GetIncineratusCooldown())
          endif
     endif

     if MAGHARI > 0 then
          if GetRandomReal(1.,100.) <= GetMaghariProcChance() and not HasUnitCooldownHash(ATTACKER,GetMaghariHash()) then
               call AddHeroParameter(ATTACKER,MAGHARI,GetMaghariDuration(),GetSpellPowerHash(),"Abilities\\Spells\\Other\\Drain\\ManaDrainCaster.mdl","overhead")
               call UnitAddHashCooldown(ATTACKER,GetMaghariHash(),GetMaghariCooldown())
          endif
     endif

     if SPELLRESIST > 0. then

     if SPELLRESIST <= 1. then
          call DamageBlock(TAKER,DAMAGE*SPELLRESIST)
          set DAMAGE = DAMAGE - (DAMAGE*SPELLRESIST)
          //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,15.,"DamageResisted: " + R2S(DAMAGE*SPELLRESIST) + ". Remained damage: " + R2S(DAMAGE) )
     else
          call DamageBlock(TAKER,DAMAGE)
          set DAMAGE = 0.
     endif

     elseif SPELLRESIST < 0. then
          call DisableTrigger(DAMAGE_EVENT_TRIGGER)
          call UnitDamageTarget(ATTACKER,TAKER,-1.*DAMAGE*SPELLRESIST,false,true,ATTACK_TYPE_CHAOS,null,null)
          call EnableTrigger(DAMAGE_EVENT_TRIGGER)
          set DAMAGE = DAMAGE +(-1.*DAMAGE*SPELLRESIST)
     endif

     set ABSORB = UnitShield.Block(TAKER,DAMAGE,1)
     if ABSORB > 0. and DAMAGE>0. then
          if ABSORB >= DAMAGE then
               call DamageBlock(TAKER,DAMAGE)
               set DAMAGE = 0.
               set MagicalAttackFullyAbsorbed = true
          else
               call DamageBlock(TAKER,ABSORB)
               set DAMAGE = DAMAGE - ABSORB
          endif
     endif

     if DAMAGE <= 0. then
          if SPELLRESIST>0. then
               set TEXT = RESIST_COLOR + "resist|r"
          endif
          if MagicalAttackFullyAbsorbed then
               set TEXT = MAGICAL_ABSORB_COLOR + "absorbed|r"
          endif
     else
          if GetRandomReal(1.,100.)<=SPELL_CRIT+SPELL_CRIT_RECEIVED_BONUS and DAMAGE>0. then
               set DAMAGE = (2.0+SPELL_CRIT_MULTIPLIER)*DAMAGE
   
               if GetPlayerController(P_ATTACKER) == MAP_CONTROL_COMPUTER then
                    set TEXT = "<"+ENEMY_SPELL_CRIT_COLOR+I2S(R2I(DAMAGE))+">"
               else
                    set TEXT = "<"+SPELL_CRIT_COLOR+I2S(R2I(DAMAGE))+">"
               endif
               set AttackCritical = true
               call DisableTrigger(DAMAGE_EVENT_TRIGGER)
               call UnitDamageTarget(ATTACKER,TAKER,DAMAGE*(1.+MULTIPLIER),false,false,ATTACK_TYPE_CHAOS,null,null)
               call EnableTrigger(DAMAGE_EVENT_TRIGGER)
          endif
     endif

     if ICECORE > 0 then
          call RegenerateMana(ATTACKER,DAMAGE*ICECORE*GetIcecoreStaffMana())
     endif
     if HOLYMIGHT > 0 and GetUnitAbilityLevel(TAKER,'A02Z') > 0 then
          call RegenerateMana(TAKER,DAMAGE*GetGlovesOfHolyMightDamageConsumed()*HOLYMIGHT)
     endif
     if SKULLRAM > 0 and GetUnitAbilityLevel(TAKER,'A036') > 0 then
          call SetUnitAbilityLevel(TAKER,'A036',GetUnitAbilityLevel(TAKER,'A036') + R2I(SKULLRAM*GetBrokenRamHelmDamageConsume()*DAMAGE/5.))
     endif
     if FROSTFORGED > 0 then
          if GetWidgetLife(TAKER) - DAMAGE <= GetUnitState(TAKER,UNIT_STATE_MAX_LIFE) * GetFrostforgedHelmHpThreshold() and not HasUnitCooldownHash(TAKER,GetFrostforgedHelmHash()) then
               set IHP_ABI = 'A037'
               set IHP_BUFFER = 'B00V'
               call AddHeroParameter(TAKER,FROSTFORGED*GetFrostforgedHelmReceivedHealingBonus(),GetFrostforgedHelmDuration(),GetReceivedHealingBonusHash(),"","")
               call UnitAddHashCooldown(TAKER,GetFrostforgedHelmHash(),GetFrostforgedHelmCooldown())
          endif
     endif
     if GetUnitAbilityLevel(ATTACKER,TOME_OF_THE_ICE_LORD_BUFF)>0 then
          call HealUnit(ATTACKER,ATTACKER, DAMAGE*GetTomeOfTheIceLordDamageConsumed()*LoadInteger(udg_hash,ID_ATTACKER,GetTomeOfTheIceLordHash()))
     endif

     if not AttackCritical and DAMAGE > 0. then
          if GetPlayerController(P_ATTACKER) == MAP_CONTROL_COMPUTER then
               set TEXT = ENEMY_SPELL_COLOR+I2S(R2I(DAMAGE))
          else
               set TEXT = SPELL_COLOR+I2S(R2I(DAMAGE))
          endif
     endif

     if IsUnitEnemy(TAKER,Player(7)) then
          set IS_ENEMY_TEXT = true
          call AddTextTagUnit(TEXT,TAKER,TEXTFORCE,GetRandomReal(MIND,MAXD),10.,1.5,0.)
          set IS_ENEMY_TEXT = false
     else
          set IS_SPELL_DAMAGE_TEXT = true
          call AddTextTagUnit(TEXT,TAKER,TEXTFORCE,GetRandomReal(MIND,MAXD),10.,1.5,0.)
          set IS_SPELL_DAMAGE_TEXT = false
     endif
     call DestroyForce(TEXTFORCE)
endif

     if GetWidgetLife(TAKER) <= DAMAGE and GetUnitAbilityLevel(TAKER,GUARDIAN_SPIRIT_BUFFCODE) > 0 then
          call BlzSetEventDamage(0.)
          call SetUnitState(TAKER,UNIT_STATE_LIFE,GetUnitState(TAKER,UNIT_STATE_MAX_LIFE)*GUARDIAN_SPIRIT_LIFE_PERCENT)
          call UnitRemoveAbility(TAKER,GUARDIAN_SPIRIT_AURACODE)
          call UnitRemoveAbility(TAKER,GUARDIAN_SPIRIT_BUFFCODE)
          call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Human\\Resurrect\\ResurrectCaster.mdl",TAKER,"origin"))
     endif

     if GetPlayerController(P_ATTACKER) == MAP_CONTROL_USER and IsUnitType(ATTACKER,UNIT_TYPE_HERO) then
          call Aggro.add(TAKER,ATTACKER,DAMAGE*0.05*(1.+AGGRO))
     endif
     if GetPlayerController(P_ATTACKER) == MAP_CONTROL_COMPUTER and not (GetUnitAbilityLevel(ATTACKER,'Aloc')>0.) then
          if Aggro.target(ATTACKER) == TAKER then
               call Aggro.add(ATTACKER,TAKER,0.)
          endif
     endif

//Clearing-------------------------------------------------------------------
call DestroyForce(TEXTFORCE)
set TEXTFORCE = null
set tempunit = null
set ATTACKER = null
set P_TAKER = null
set P_ATTACKER = null
set TAKER = null
set TARGET = null
set t = null
set t1 = null
set e = null
endfunction

function Damage_Detect_Conds takes nothing returns boolean
if IsUnitInGroup(GetEventDamageSource(),ONE_ATTACK_REMOVE_GROUP) then
   call GroupRemoveUnit(ONE_ATTACK_REMOVE_GROUP,GetEventDamageSource())
   call RemoveUnit(GetEventDamageSource())
   return false
endif
return GetEventDamage()>1. and not IsUnitInGroup(GetEventDamageSource(), udg_Dummy_Group) and not IsUnitType(GetTriggerUnit(),UNIT_TYPE_DEAD)
endfunction

function REGISTER_UNIT_EVENT takes nothing returns nothing
call TriggerRegisterUnitEvent( DAMAGE_EVENT_TRIGGER, GetTriggerUnit(), EVENT_UNIT_DAMAGED )
call TriggerRegisterUnitEvent( HEALEVENT_TRIGGER, GetTriggerUnit(),EVENT_UNIT_DAMAGED)
call GroupAddUnit(MAP_UNITS_ALIVE,GetTriggerUnit())
call UnitAddAbility(GetTriggerUnit(),'Aave')
call UnitRemoveAbility(GetTriggerUnit(),'Aave')
endfunction

private function RegisterUnitsAlive takes nothing returns nothing
    call TriggerRegisterUnitEvent( DAMAGE_EVENT_TRIGGER, GetEnumUnit(), EVENT_UNIT_DAMAGED )
endfunction

function RefreshDamageEventTrigger takes nothing returns nothing
    call DestroyTrigger(DAMAGE_EVENT_TRIGGER)

    set DAMAGE_EVENT_TRIGGER = CreateTrigger()
    call TriggerAddAction(DAMAGE_EVENT_TRIGGER, function Damage_Detect_Main)
    call TriggerAddCondition(DAMAGE_EVENT_TRIGGER,Filter(function Damage_Detect_Conds))

    call ForGroup(MAP_UNITS_ALIVE,function RegisterUnitsAlive)
endfunction

function DAMAGE_EVENT_INI takes nothing returns nothing
    local trigger t = CreateTrigger()
    local region rectRegion = CreateRegion()
    call RegionAddRect(rectRegion, bj_mapInitialPlayableArea)
    call TriggerRegisterEnterRegion(t,rectRegion,null)
    call TriggerAddAction(t,function REGISTER_UNIT_EVENT)
    set t = null
    set rectRegion = null
    //MAIN TRIGGER
    set DAMAGE_EVENT_TRIGGER = CreateTrigger()
    call TriggerAddAction(DAMAGE_EVENT_TRIGGER, function Damage_Detect_Main)
    call TriggerAddCondition(DAMAGE_EVENT_TRIGGER,Filter(function Damage_Detect_Conds))
endfunction

endlibrary

 
library HealingEventMethods initializer onInit

globals
        private boolean PERIODIC = false
        private boolean LIFESTEALING = false

endglobals

private function onInit takes nothing returns nothing
       
endfunction

function IsLastHealingPeriodic takes nothing returns boolean
         return PERIODIC
endfunction

function HealUnit takes unit Healer, unit Target, real Healing returns nothing
        set PERIODIC = false
        set LIFESTEALING = false
        call UnitDamageTarget(Healer,Target,-1*Healing,false,false,ATTACK_TYPE_NORMAL,null,null)
endfunction

function HealUnitPeriodic takes unit Healer, unit Target, real Healing returns nothing
        set PERIODIC = true
        set LIFESTEALING = false
        call UnitDamageTarget(Healer,Target,-1*Healing,false,false,ATTACK_TYPE_NORMAL,null,null)
        set PERIODIC = false
endfunction

endlibrary
hashkeys
30 - Healing Crit
//TESH.scrollpos=0
//TESH.alwaysfold=0
library HealingEvent initializer onInit requires OutOfCombat

globals
trigger HEALEVENT_TRIGGER = null
endglobals

private function onHeal takes nothing returns nothing
local unit TAKER = GetTriggerUnit()
local unit HEALER = GetEventDamageSource()
local integer ID_TAKER = GetHandleId(TAKER)
local integer ID_HEALER = GetHandleId(HEALER)
local player P_TAKER = GetOwningPlayer(TAKER)
local player P_HEALER = GetOwningPlayer(HEALER)
local real BASEHEAL = -1.*GetEventDamage()
local real HEAL = -1.*GetEventDamage()
local real HEAL_RECEIDED_BONUS = LoadReal(udg_hash,ID_TAKER,GetReceivedHealingBonusHash())
local real HEAL_BONUS = LoadReal(udg_hash,ID_HEALER,GetHealingBonusHash())
local real SELFHEAL = 0.
local string TXT = ""
local boolean IS_CRITICAL = false
local force HEALFORCE = CreateForce()
local boolean IsHealerInCombat = LoadBoolean(udg_hash,GetHandleId(HEALER),32)
local boolean IsTakerInCombat = LoadBoolean(udg_hash,GetHandleId(TAKER),32)
local real PERIODIC_HEALING_RECEIVED_BONUS = 0.
local real PERIODIC_HEALING_BONUS = 0.
local real PERIODIC_HEALING_CRIT = 0.
local real HEALING_CRIT = LoadReal(udg_hash,ID_HEALER,GetSpellCritHash())
local real HEALING_CRIT_MULTIPLIER = LoadReal(udg_hash,ID_HEALER,GetHealingCritMultiplierHash())
local integer BOOK_OF_HIGHBORNE_HYMNS_LEVEL = 0
local real CRIT = 0.
//Start some actions

      if HEALER==TAKER then
          set SELFHEAL = LoadReal(udg_hash,ID_HEALER,GetSelfHealingBonusHash())
      endif

      set HEAL = HEAL * (1. + HEAL_RECEIDED_BONUS+HEAL_BONUS+SELFHEAL)

      if IsLastHealingPeriodic() then
         set PERIODIC_HEALING_RECEIVED_BONUS = LoadReal(udg_hash,ID_TAKER,GetPeriodicHealingReceivedBonusHash())
         set PERIODIC_HEALING_BONUS = LoadReal(udg_hash,ID_HEALER,GetPeriodicHealingBonusHash())
         set HEAL = HEAL * (1. + PERIODIC_HEALING_RECEIVED_BONUS+PERIODIC_HEALING_BONUS)
         set PERIODIC_HEALING_CRIT = LoadReal(udg_hash,ID_HEALER,GetPeriodicHealingCritHash())
      endif

      set CRIT = HEALING_CRIT + PERIODIC_HEALING_CRIT

      if GetRandomInt(0,100) <= CRIT then
         set HEAL = HEAL * (2+HEALING_CRIT_MULTIPLIER)
         set IS_CRITICAL = true
         set BOOK_OF_HIGHBORNE_HYMNS_LEVEL = LoadInteger(udg_hash,ID_HEALER,GetBookOfHighborneHymnsHash())
         if BOOK_OF_HIGHBORNE_HYMNS_LEVEL > 0 and not HasUnitCooldownHash(HEALER,GetBookOfHighborneHymnsHash()) then
                set IHP_ABI = GetBookOfHighborneHymnsAbilBuff()
                set IHP_BUFFER = GetBookOfHighborneHymnsBuff()
                call AddHeroParameter(HEALER,GetBookOfHighborneHymnsEnergyRegen()*BOOK_OF_HIGHBORNE_HYMNS_LEVEL,GetBookOfHighborneHymnsDuration(),GetEnergyRegenBonusHash(),"","")          
                call UnitAddHashCooldown(HEALER,GetBookOfHighborneHymnsHash(),GetBookOfHighborneHymnsCooldown())
         endif
      endif

      call DisableTrigger(GetTriggeringTrigger())
      call UnitDamageTarget(HEALER,TAKER,-1*(HEAL-BASEHEAL),false,false,ATTACK_TYPE_NORMAL,null,null)
      call EnableTrigger(GetTriggeringTrigger())

      if HEAL > (GetUnitState(TAKER,UNIT_STATE_MAX_LIFE) - GetWidgetLife(TAKER)) then
           set HEAL = GetUnitState(TAKER,UNIT_STATE_MAX_LIFE) - GetWidgetLife(TAKER)
      endif

      if not IS_BLOOD_HURRICANE_DAMAGE then
      if HEAL>0. then
           if IS_CRITICAL then
               set TXT = "+<|c0000FF00" + I2S(R2I(HEAL)) + "|r!>"
           else    
               set TXT = "+|c0000FF00" + I2S(R2I(HEAL)) + "|r"
           endif
      endif
      endif
//--------------------------------------------------------

call ForceAddPlayer(HEALFORCE,GetOwningPlayer(HEALER))
call ForceAddPlayer(HEALFORCE,GetOwningPlayer(TAKER))
if IsUnitType(TAKER,UNIT_TYPE_HERO) and GetPlayerController(P_TAKER)== MAP_CONTROL_USER and IsHealerInCombat then
call MAKE_UNIT_COMBAT(TAKER)
endif
if IsUnitType(HEALER,UNIT_TYPE_HERO) and GetPlayerController(P_HEALER)== MAP_CONTROL_USER and IsTakerInCombat then
call MAKE_UNIT_COMBAT(HEALER)
endif
set IS_HEALING_TEXT = true
call AddTextTagUnit(TXT,TAKER,HEALFORCE,90.,10.,1.5,0.)
set IS_HEALING_TEXT = false
call DestroyForce(HEALFORCE)
set TAKER = null
set HEALER = null
set HEALFORCE = null
endfunction

private function Conds takes nothing returns boolean
return GetEventDamage() < 0. and not IsUnitType(GetTriggerUnit(),UNIT_TYPE_DEAD)
endfunction

private function onInit takes nothing returns nothing
set HEALEVENT_TRIGGER = CreateTrigger()
call TriggerAddCondition(HEALEVENT_TRIGGER,Condition(function Conds))
call TriggerAddAction(HEALEVENT_TRIGGER,function onHeal)
endfunction

private function RegisterUnitsAlive takes nothing returns nothing
    call TriggerRegisterUnitEvent( HEALEVENT_TRIGGER, GetEnumUnit(),EVENT_UNIT_DAMAGED)
endfunction

function RefreshHealingEventTrigger takes nothing returns nothing
    call DestroyTrigger(HEALEVENT_TRIGGER)

    set HEALEVENT_TRIGGER = CreateTrigger()
    call TriggerAddCondition(HEALEVENT_TRIGGER,Condition(function Conds))
    call TriggerAddAction(HEALEVENT_TRIGGER,function onHeal)

    call ForGroup(MAP_UNITS_ALIVE, function RegisterUnitsAlive)
endfunction

endlibrary
 
library RefreshCombatTriggers initializer onInit requires DAMAGEEVENT, HealingEvent

globals
      timer REFRESH_COMBAT_TRIGGERS_TIMER = CreateTimer()
endglobals

private function RefreshCombatTriggers takes nothing returns nothing
     call RefreshDamageEventTrigger()
     call RefreshHealingEventTrigger()
endfunction

private function onInit takes nothing returns nothing
     local trigger t = CreateTrigger()
     
     call TriggerRegisterTimerExpireEvent(t,REFRESH_COMBAT_TRIGGERS_TIMER)
     call TriggerAddAction(t, function RefreshCombatTriggers)

     set t = null
endfunction

endlibrary
//TESH.scrollpos=63
//TESH.alwaysfold=0
library OutOfCombat requires PotionsUtils,AddTextTag,HeroInitializer

globals
     private constant integer RANGER = 'H00O'
     private constant integer HORDE_CHAMPION = 'O002'
     private constant integer BLOODELF_CAPTAIN = 'O005'
     private constant integer COMBATHASH = 32 //Is Unit In Combat
     private constant real RAGE_REGEN_IN_COMBAT = 3.
     private constant real RAGE_REGEN_OUT_COMBAT = -3.
     private constant real SPIRIT_MANA_REGEN_FACTOR = 0.4

     constant integer OUT_OF_COMBAT_TIMER_HASH = 31
endglobals

function IsUnitInCombat takes unit whichUnit returns boolean
     return LoadBoolean(udg_hash,GetHandleId(whichUnit),COMBATHASH)
endfunction

function RegenerateRage takes unit whichUnit, real value returns nothing
     local real rageBonusMult = LoadReal(udg_hash,GetHandleId(whichUnit),GetRageRegenBonusHash())
     local real energyBonusMult = LoadReal(udg_hash,GetHandleId(whichUnit),GetEnergyRegenBonusHash())
     local real reg = 0.
     if value>0 then
        set reg = value*(1+rageBonusMult+energyBonusMult)
     else
        set reg = value
     endif
     call SetUnitState(whichUnit,UNIT_STATE_MANA, GetUnitState(whichUnit,UNIT_STATE_MANA)+reg)
endfunction

function RegenerateFocus takes unit whichUnit, real value returns nothing
     local real focusBonusMult = LoadReal(udg_hash,GetHandleId(whichUnit),GetFocusRegenBonusHash())
     local real energyBonusMult = LoadReal(udg_hash,GetHandleId(whichUnit),GetEnergyRegenBonusHash())
     call SetUnitState(whichUnit,UNIT_STATE_MANA, GetUnitState(whichUnit,UNIT_STATE_MANA)+value*(1+focusBonusMult+energyBonusMult))
endfunction

function RegenerateMana takes unit whichUnit, real value returns nothing
     local real manaBonusMult = LoadReal(udg_hash,GetHandleId(whichUnit),GetManaRegenBonusHash())
     local real energyBonusMult = LoadReal(udg_hash,GetHandleId(whichUnit),GetEnergyRegenBonusHash())
     local real reg = 0.
     if GetUnitState(whichUnit,UNIT_STATE_MAX_MANA) > 200. then
           if value > 0 then
                 set reg = value*(1+manaBonusMult+energyBonusMult)
           else
                 set reg = value
           endif
           call SetUnitState(whichUnit,UNIT_STATE_MANA, GetUnitState(whichUnit,UNIT_STATE_MANA)+reg)
     endif
endfunction

function RegenerateRunes takes unit whichUnit, real value returns nothing
     local real runesBonusMult = LoadReal(udg_hash,GetHandleId(whichUnit),GetRunesRegenBonusHash())
     local real energyBonusMult = LoadReal(udg_hash,GetHandleId(whichUnit),GetEnergyRegenBonusHash())
     call SetUnitState(whichUnit,UNIT_STATE_MANA, GetUnitState(whichUnit,UNIT_STATE_MANA)+value*(1+runesBonusMult+energyBonusMult))
endfunction

function RegenerateEnergy takes unit whichUnit, real value returns nothing
     local string str = GetHeroEnergy(whichUnit)
     if str == "Rage" then
          call RegenerateRage(whichUnit,value)
     endif
     if str == "Focus" then
          call RegenerateFocus(whichUnit,value)
     endif
     if str == "Mana" then
          call RegenerateMana(whichUnit,value)
     endif
     if str == "Runes" then
          call RegenerateRunes(whichUnit,value)
     endif
endfunction

private function REGEN_OUT_OF_COMBAT takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit u = LoadUnitHandle(udg_hash,GetHandleId(t),1)
local boolean IS_UNIT_IN_COMBAT = LoadBoolean(udg_hash,GetHandleId(u),32)
local integer id = GetHandleId(u)
local real hpreg = GetUnitState(u,UNIT_STATE_MAX_LIFE)*0.1
local real mpreg = GetUnitState(u,UNIT_STATE_MAX_MANA)*0.1
local real hpbonus = LoadReal(udg_hash,id,23)
local real mpbonus = LoadReal(udg_hash,id,24)
local real allbonus = LoadReal(udg_hash,id,25)
set hpreg = hpreg * (1. + hpbonus + allbonus)
set mpreg = mpreg * (1. + mpbonus + allbonus)
if not IS_UNIT_IN_COMBAT then
  call SetWidgetLife(u,GetWidgetLife(u)+hpreg)
  if GetUnitState(u,UNIT_STATE_MAX_MANA)>200 then
       call RegenerateMana(u,mpreg)
  endif
  if GetUnitTypeId(u)==HORDE_CHAMPION or GetUnitTypeId(u)==BLOODELF_CAPTAIN then
     call RegenerateRage(u,RAGE_REGEN_OUT_COMBAT)
  endif
else
  call FlushChildHashtable(udg_hash,GetHandleId(t))
  call DestroyTimer(t)
endif
set t = null
set u = null
endfunction

private function REGEN_IN_COMBAT takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit u = LoadUnitHandle(udg_hash,GetHandleId(t),1)
local boolean IsInCombat = LoadBoolean(udg_hash,GetHandleId(u),32)
local real hpbonus = LoadReal(udg_hash,GetHandleId(u),26)
local real mpbonus = LoadReal(udg_hash,GetHandleId(u),27)
local real bothbonus = LoadReal(udg_hash,GetHandleId(u),28)
local real toRegenMana = SPIRIT_MANA_REGEN_FACTOR * I2R(GetHeroInt(u,true))
if IsInCombat then
   if GetUnitState(u,UNIT_STATE_MAX_MANA) > 200. then
     call RegenerateMana( u,toRegenMana + toRegenMana*(mpbonus+bothbonus) )
   endif
   if GetUnitTypeId(u)==HORDE_CHAMPION or GetUnitTypeId(u)==BLOODELF_CAPTAIN then
     call RegenerateRage(u,RAGE_REGEN_IN_COMBAT)
   endif
else
    call FlushChildHashtable(udg_hash,GetHandleId(t))
    call DestroyTimer(t)
endif
set t = null
set u = null
endfunction

function OUT_OF_COMBAT takes nothing returns nothing
local timer t = GetExpiredTimer()
local timer t1 = CreateTimer()
local unit u = LoadUnitHandle(udg_hash,GetHandleId(t),1)
local integer slot = 0
local integer index = 1
local integer charges = 0
local integer rawcode = 0
call SaveInteger(udg_hash,GetHandleId(u),33,0)
call SaveInteger(udg_hash,GetHandleId(u),34,0)
call SaveInteger(udg_hash,GetHandleId(u),35,0)
loop
 exitwhen slot > 5
 set rawcode = GetItemTypeId(UnitItemInSlot(u,slot))
  set index = 1
  loop
   exitwhen index > udg_Potions_COUNT
    if rawcode == udg_Potions_DISABLED[index] then
       set charges = GetItemCharges(UnitItemInSlot(u,slot))
       call RemoveItem(UnitItemInSlot(u,slot))
       call UnitAddItemToSlotById(u,GetOriginPotion(rawcode),slot)
       call SetItemCharges(UnitItemInSlot(u,slot),charges)
    endif
   set index = index + 1
  endloop
 set slot = slot + 1
endloop
call ForceAddPlayer(udg_temp_force,GetOwningPlayer(u))
call AddTextTagUnit("|c00FF0000Out of combat|r",u,udg_temp_force,270.,9.,2.,-100.)
call SaveUnitHandle(udg_hash,GetHandleId(t1),1,u)
call TimerStart(t1,5.,true,function REGEN_OUT_OF_COMBAT)
call FlushChildHashtable(udg_hash,GetHandleId(t))
call RemoveSavedHandle(udg_hash,GetHandleId(u),OUT_OF_COMBAT_TIMER_HASH)
call SaveBoolean(udg_hash,GetHandleId(u),32,false)

if GetUnitTypeId(u) == RANGER then
     if HaveSavedHandle(udg_hash,GetHandleId(u),SUMMON_WOLF_WOLFCASTERHASH) then
        call SaveBoolean(udg_hash,GetHandleId(LoadUnitHandle(udg_hash,GetHandleId(u),SUMMON_WOLF_WOLFCASTERHASH)),SUMMON_WOLF_COMBATHASH, false)
     endif
endif

call DestroyTimer(t)
set t = null
set t1 = null
set u = null
endfunction

function MAKE_UNIT_COMBAT takes unit u returns nothing
local timer t = null
local timer t1 = null
if not IsUnitType(u,UNIT_TYPE_DEAD) then
   if HaveSavedHandle(udg_hash,GetHandleId(u),OUT_OF_COMBAT_TIMER_HASH) then
     call TimerStart(LoadTimerHandle(udg_hash,GetHandleId(u),OUT_OF_COMBAT_TIMER_HASH),8.,false,function OUT_OF_COMBAT)
   else
     set t = CreateTimer()
     call SaveTimerHandle(udg_hash,GetHandleId(u),OUT_OF_COMBAT_TIMER_HASH,t)
     call SaveUnitHandle(udg_hash,GetHandleId(t),1,u)
     call TimerStart(t,6.+2*CURRENT_DIFFICULTY,false,function OUT_OF_COMBAT)
     call ForceAddPlayer(udg_temp_force,GetOwningPlayer(u))
     call AddTextTagUnit("|c00FF0000Entering combat|r",u,udg_temp_force,270.,9.,2.,-200.)

     if GetUnitTypeId(u) == RANGER then
        if HaveSavedHandle(udg_hash,GetHandleId(u),SUMMON_WOLF_WOLFCASTERHASH) then
           call SaveBoolean(udg_hash,GetHandleId(LoadUnitHandle(udg_hash,GetHandleId(u),SUMMON_WOLF_WOLFCASTERHASH)),SUMMON_WOLF_COMBATHASH, true)
        endif
     endif

     set t1 = CreateTimer()
     call TimerStart(t1,5.,true,function REGEN_IN_COMBAT)
     call SaveUnitHandle(udg_hash,GetHandleId(t1),1,u)
     set t1 = null
     set t = null
   endif
   call SaveBoolean(udg_hash,GetHandleId(u),32,true)
endif
endfunction

endlibrary
//TESH.scrollpos=238
//TESH.alwaysfold=0
library CreepAggro initializer onInit requires IsUnitDead

/*
Create by GodLike! aka Helpmeplz aka Demolishka
Give me credit if you use it in your map.

Uses GetUnitUserData()

functions:

call Aggro.new(unit ForUnit) - creates an aggro table for "ForUnit"
call Aggro.add(unit ForUnit,unit Attacker,real amount) - adds a "amount" of aggro to "ForUnit" from "Attacker"
call Aggro.get(unit ForUnit,unit Attacker,boolean percent) - returns an aggro amount of "ForUnit" genericed by "Attacker". If "percent" is true then returns the percent value from ALL aggro
call Aggro.target(unit ForUnit) - returns the current target for "ForUnit"
call Aggro.top(unit ForUnit) - returns the amount of Aggro of "ForUnit"'s Target
call Aggro.clear(unit ForUnit,unit Attacker) - clears the aggro of "Attacker" for "ForUnit". If "Attacker" is null then clears FULL AGGRO TABLE for "ForUnit"
call Aggro.remove(unit ForUnit) - removes the Aggro Table for "ForUnit"
call Aggro.ignoreAggro(unit whichUnit, real duration, unit TARGET, boolean ignorePrevious) - makes the unit whichUnit ignore aggro table in his attack orders (but still count aggro from attackes) for duration. Start attack TARGET if not null and ignores previous ignoreAggro callbacks if ignorePrevious is true.
*/



globals
private constant integer MAX_ATTACKERS = 10      //maximum attackers of one unit
private constant real CLEAR_AGGRO_PERIOD = 10.   //time after the last attack when the Aggro of unit will be cleared
private constant real TARGET_AGGRO_BONUS = 2.   //multiplier if the unit gets aggro from its attacker
private constant real AGGRO_MULTIPLIER_TO_REDIRECT = 1.1 // How much the unit should generate threat value (comparing with his target's target) to make the target attack him
private constant real TIMER_PERIOD = 0.1


endglobals

struct Aggro
    private static Aggro array st
    private static integer index = 0
    private static timer t = CreateTimer()
    static trigger trg = CreateTrigger()
    static group ordered = CreateGroup()
    integer Count = 0
    unit Unit = null
    unit Target = null
    unit CHASED_TARGET = null
    real IGNORE_TIME = 0.
    unit array Attacker[MAX_ATTACKERS]
    real array Aggro[MAX_ATTACKERS]
    real array Dur[MAX_ATTACKERS]
   
static method GetNewTarget takes unit whichUnit returns integer
     local integer i = GetUnitUserData(whichUnit)
     local integer k = 0
     local integer j = 0

     loop
     exitwhen j >= .st[i].Count
          if .st[i].Aggro[j] > .st[i].Aggro[k] then
               set k = j
          endif
     set j = j + 1
     endloop

     return k
endmethod
   
static method add takes unit whichUnit, unit ATTACKER,real amount returns boolean
     local integer i = GetUnitUserData(whichUnit)
     local integer j = 0
     local boolean founded = false
     if CHAPTER2_INITIALIZED then
         return false
     endif
     if not (.st[i].Unit == whichUnit) then
         call Aggro.new(whichUnit)
         set i = GetUnitUserData(whichUnit)
     endif
     
          if (not (.st[i].IGNORE_TIME > 0.) and .st[i].Target == ATTACKER) or (.st[i].IGNORE_TIME > 0. and .st[i].CHASED_TARGET==ATTACKER) then
               set amount = amount * TARGET_AGGRO_BONUS
          endif

          loop
          exitwhen j >= .st[i].Count
               if .st[i].Attacker[j] == ATTACKER then
                    set founded = true
                    if amount > 0. then
                        //call BJDebugMsg("Adding " + R2S(amount) + "threat from " + GetUnitName(.st[i].Attacker[j]) + " to " + GetUnitName(.st[i].Unit))
                    endif
                    set .st[i].Aggro[j] = .st[i].Aggro[j] + amount
                    set .st[i].Dur[j] = CLEAR_AGGRO_PERIOD
                    if not (.st[i].IGNORE_TIME > 0.) and .st[i].Aggro[j] > AGGRO_MULTIPLIER_TO_REDIRECT*Aggro.Targetaggro(whichUnit) and not( .st[i].Attacker[j] == .st[i].Target ) then
                         //call BJDebugMsg(GetUnitName(.st[i].Attacker[j]) + "'s aggro on " + GetUnitName(.st[i].Unit)+ " is " + R2S(.st[i].Aggro[j]) + " that is greater that " + R2S(AGGRO_MULTIPLIER_TO_REDIRECT*Aggro.Targetaggro(whichUnit)) + ". So redirect.")
                         set .st[i].Target = ATTACKER
                         call IssueTargetOrder(whichUnit,"attack",ATTACKER)
                    endif
                    set j = .st[i].Count
               endif
          set j = j + 1
          endloop
          if not founded then
               if .st[i].Count <= MAX_ATTACKERS then
                    set .st[i].Attacker[.st[i].Count] = ATTACKER
                    set .st[i].Aggro[.st[i].Count] = amount
                    set .st[i].Dur[.st[i].Count] = CLEAR_AGGRO_PERIOD
                    if not (.st[i].IGNORE_TIME > 0.) and amount > AGGRO_MULTIPLIER_TO_REDIRECT*Aggro.Targetaggro(whichUnit) then
                         //call BJDebugMsg("New unit " + GetUnitName(ATTACKER) + "'s aggro on " + GetUnitName(.st[i].Unit)+ " is " + R2S(.st[i].Aggro[j]) + " that is greater that " + R2S(AGGRO_MULTIPLIER_TO_REDIRECT*Aggro.Targetaggro(whichUnit)) + ". So redirect.")
                         set .st[i].Target = ATTACKER
                         call IssueTargetOrder(whichUnit,"attack",ATTACKER)
                    endif
                    set .st[i].Count = .st[i].Count + 1
              endif
          endif
      return true
endmethod

static method ignoreAggro takes unit whichUnit, real duration, unit ATTACK_TARGET, boolean ignorePrevious returns nothing
     local integer i = GetUnitUserData(whichUnit)

     if not (.st[i].Unit == whichUnit) then
         call Aggro.new(whichUnit)
         set i = GetUnitUserData(whichUnit)
     endif

     if not(.st[i].IGNORE_TIME>0.) or ignorePrevious then
          if ignorePrevious then
              //call BJDebugMsg(GetUnitName(whichUnit) + " charges " + GetUnitName(ATTACK_TARGET))
          else
              //call BJDebugMsg(GetUnitName(whichUnit) + " taunted by " + GetUnitName(ATTACK_TARGET))
          endif
          call Aggro.add(.st[i].Unit,ATTACK_TARGET,0.)
          set .st[i].IGNORE_TIME = duration
          if .st[i].IGNORE_TIME > 0. and not IsUnitDeadBX(ATTACK_TARGET) then
               //set .st[i].Target = ATTACK_TARGET
               set .st[i].CHASED_TARGET = ATTACK_TARGET
               call IssueTargetOrder(.st[i].Unit,"attack",ATTACK_TARGET)
          endif
     endif
endmethod
 
static method get takes unit TARGET, unit ATTACKER, boolean percent returns real
     local integer i = GetUnitUserData(TARGET)
     local integer j = 0
     local real aggro = 0.
     local real mainaggro = 0.

     if .st[i].Count > 0 then
          loop
          exitwhen j >= .st[i].Count
               set mainaggro = mainaggro + .st[i].Aggro[j]
               if .st[i].Attacker[j] == ATTACKER then
                    set aggro = .st[i].Aggro[j]
               endif
          set j = j + 1
          endloop
          if percent then
               return aggro / mainaggro * 100.
          endif

     return aggro
     endif

     return 0.
endmethod
 
static method target takes unit whichUnit returns unit
     if whichUnit == .st[GetUnitUserData(whichUnit)].Unit then
          return .st[GetUnitUserData(whichUnit)].Target
     endif

     return null
endmethod
 
static method Targetaggro takes unit whichUnit returns real
     if whichUnit == .st[GetUnitUserData(whichUnit)].Unit then
          //call BJDebugMsg("Returning target aggro ")
          return Aggro.get(whichUnit,.st[GetUnitUserData(whichUnit)].Target,false)
     endif
     return 0.
endmethod
 
static method clear takes unit whichUnit, unit Attacker returns nothing
     local integer i = GetUnitUserData(whichUnit)
     local integer j = 0
     local integer k = 0

     if not (Attacker == null) then
          loop
          exitwhen j >= .st[i].Count
               if Attacker == .st[i].Attacker[j] then
                    if .st[i].Attacker[j] == .st[i].Target then
                         set .st[i].Target = null
                         call IssueImmediateOrder(.st[i].Unit,"stop")
                    endif
                    if .st[i].Attacker[j] == .st[i].CHASED_TARGET then
                         set .st[i].IGNORE_TIME = 0.
                         set .st[i].CHASED_TARGET = null
                         if not IsUnitDeadBX(.st[i].Target) then
                              call IssueTargetOrder(.st[i].Unit,"attack",.st[i].Target)
                         else
                              call IssueImmediateOrder(.st[i].Unit,"stop")
                         endif
                    endif
                    set .st[i].Count = .st[i].Count - 1
                    set .st[i].Attacker[j] = .st[i].Attacker[.st[i].Count]
                    set .st[i].Aggro[j] = .st[i].Aggro[.st[i].Count]
                    set .st[i].Dur[j] = .st[i].Dur[.st[i].Count]
                    set .st[i].Attacker[.st[i].Count] = null
                    set j = .st[i].Count
               endif
          set j = j + 1
          endloop
          if .st[i].Count == 0 then
               set .st[i].Target = null
               set .st[i].Count = 0
               set .st[i].Target = null
               set .st[i].IGNORE_TIME = 0.
               set .st[i].CHASED_TARGET = null
          elseif .st[i].Target == null then
               if not ( (.st[i].IGNORE_TIME>0.) and not IsUnitDeadBX(.st[i].CHASED_TARGET)) then
                    set k = Aggro.GetNewTarget(.st[i].Unit)
                    set .st[i].Target = .st[i].Attacker[k]
                    //call BJDebugMsg("Clear: case of attack")
                    call IssueTargetOrder(.st[i].Unit,"attack",.st[i].Target)
               endif
          endif
     else
          set .st[i].Count = 0
          set .st[i].Target = null
          set .st[i].IGNORE_TIME = 0.
          set .st[i].CHASED_TARGET = null
          call IssueImmediateOrder(whichUnit,"stop")
     endif
endmethod
 
private static method remove takes integer i returns nothing
          //call BJDebugMsg("Removing" + GetUnitName(.st[i].Unit))
          if .st[i].Count > 0 and .st[i] != null then
               call .st[i].destroy()
          endif
          set .index = .index - 1
          set .st[i] = .st[.index]
          set .st[.index] = 0
          call SetUnitUserData(.st[i].Unit, i)
          if .index == 0 then
               call PauseTimer(.t)
          endif
          //call BJDebugMsg("Removed aggro table for: " + GetUnitName(whichUnit) + "with .index " + I2S(GetUnitUserData(whichUnit)))
endmethod
 
static method onTimer takes nothing returns nothing
     local integer i = 0
     local integer j = 0
     local integer k = 0

     loop
     exitwhen i >= .index
          if IsUnitDeadBX(.st[i].Unit) then
               //call BJDebugMsg(GetUnitName(.st[i].Unit) + "is dead or null. Removing")
               call Aggro.remove(i)
               set i = i - 1
          else
         
          if .st[i].IGNORE_TIME>0. then
               set .st[i].IGNORE_TIME = .st[i].IGNORE_TIME - TIMER_PERIOD
               
               if .st[i].IGNORE_TIME < 0. or IsUnitDeadBX(.st[i].CHASED_TARGET) then
                   //call BJDebugMsg("IGNORE finished on " + GetUnitName(.st[i].Unit))
                   set .st[i].CHASED_TARGET = null
                   if not IsUnitDeadBX(.st[i].Target) then
                        call IssueTargetOrder(.st[i].Unit,"attack",.st[i].Target)
                   else
                        call IssueImmediateOrder(.st[i].Unit,"stop")
                   endif
               endif
          endif
          //call BJDebugMsg("onTimer for " + GetUnitName(.st[i].Unit))
          set j = 0
          loop
          exitwhen j >= .st[i].Count
               set .st[i].Dur[j] = .st[i].Dur[j] - TIMER_PERIOD
               if (.st[i].Dur[j] <= 0. and not(.st[i].Attacker[j]==.st[i].CHASED_TARGET) ) or IsUnitDeadBX(.st[i].Attacker[j]) then
                    if .st[i].Attacker[j] == .st[i].Target then
                         set .st[i].Target = null
                         call IssueImmediateOrder(.st[i].Unit,"stop")
                    endif
                    set .st[i].Count = .st[i].Count - 1
                    set .st[i].Attacker[j] = .st[i].Attacker[.st[i].Count]
                    set .st[i].Aggro[j] = .st[i].Aggro[.st[i].Count]
                    set .st[i].Dur[j] = .st[i].Dur[.st[i].Count]
                    set j = j - 1
               endif
          set j = j + 1
          endloop
          //call BJDebugMsg("j-loop finished")
          if .st[i].Count == 0 then
               set .st[i].Target = null
          elseif .st[i].Target == null then
               if not ( (.st[i].IGNORE_TIME>0.) and not IsUnitDeadBX(.st[i].CHASED_TARGET)) then
                    set k = Aggro.GetNewTarget(.st[i].Unit)
                    set .st[i].Target = .st[i].Attacker[k]
                    //call BJDebugMsg("onTimer case of attack")
                    call IssueTargetOrder(.st[i].Unit,"attack",.st[i].Target)
               endif
          endif

          endif
     set i = i + 1
     endloop
endmethod
 
static method new takes unit whichUnit returns nothing
     if (GetUnitUserData(whichUnit) >= .index) or not (.st[GetUnitUserData(whichUnit)].Unit == whichUnit) then      
          set .st[.index] = Aggro.create()
          set .st[.index].Unit = whichUnit
          set .st[.index].Target = null
          set .st[.index].Count = 0
          set .st[.index].CHASED_TARGET = null
          set .st[.index].IGNORE_TIME = 0.
          //call BJDebugMsg("Setting user data for " + GetUnitName(whichUnit) + " to " + I2S(.index) )
          call SetUnitUserData(whichUnit,.index)
          if .index == 0 then
               call TimerStart(.t,TIMER_PERIOD,true,function Aggro.onTimer)
          endif
          if not IsUnitInGroup(whichUnit,.ordered) then
               call TriggerRegisterUnitEvent(Aggro.trg,whichUnit,EVENT_UNIT_ISSUED_TARGET_ORDER)
               call GroupAddUnit(.ordered,whichUnit)
          endif
          set .index = .index + 1
          //call BJDebugMsg("Created aggro table for: " + GetUnitName(whichUnit) + "with index= " + I2S(GetUnitUserData(whichUnit)))
     endif
endmethod
 
static method onOrder takes nothing returns boolean
     local integer i = 0
     if GetIssuedOrderId() == OrderId("attack") then
          set i = GetUnitUserData(GetTriggerUnit())
          if .st[i].Unit==GetTriggerUnit() then
               if not (GetOrderTargetUnit() == .st[i].Target) and not (.st[i].IGNORE_TIME>0. ) and not IsUnitDeadBX(.st[i].Target) then
                    call IssueTargetOrder(.st[i].Unit,"attack",.st[i].Target)
                    //call BJDebugMsg("Redirecting " + GetUnitName(GetTriggerUnit()) + " to target " + GetUnitName(.st[i].Target))
               endif
               if .st[i].IGNORE_TIME>0. and not IsUnitDeadBX(.st[i].CHASED_TARGET) and not (GetOrderTargetUnit() == .st[i].CHASED_TARGET) then
                    call IssueTargetOrder(.st[i].Unit,"attack",.st[i].CHASED_TARGET)
                    //call BJDebugMsg("Redirecting " + GetUnitName(GetTriggerUnit()) + " to CHASED target " + GetUnitName(.st[i].CHASED_TARGET))
               endif
          endif
     endif
     return false
endmethod

endstruct

private function onInit takes nothing returns nothing
     call TriggerAddCondition(Aggro.trg,Condition(function Aggro.onOrder))
endfunction

endlibrary
//TESH.scrollpos=26
//TESH.alwaysfold=0
library AggroTable initializer onInit requires CreepAggro

/*
Created by GodLike aka Helpmeplz
Give me credit if you use it in your map.

This system allows you to adds an Aggro bar for your multiboard, showing an Aggro amount of any Unit on the other.

functions:

Table.add(ForUnit,Attacker,Mb,Row,S_COLUMN,E_COLUMN) - adds an Aggro Bar (showing Aggro of "Attacker" on "ForUnit") for multiboard "mb" in row "ROW" starts with S_COMUN and Ends with E_COLUMN.
Automaticaly increases the counts of rows/columns of multiboard if they are lesser than needed.
NOTE: the differense beetwen the start column and the end column must be at least 3!

Table.remove(ForUnit,Attacker,Mb) - removes an Aggro Bar (showing Aggro of "Attacker" on "ForUnit") for multiboard "mb"
NOTE: I think you won't create two aggro bars in various rows. That's why this function doesn't require row number.

*/


globals
     private string array Bars[24]
     private constant integer MAX_TABLES = 20
endglobals

struct Table
     static Table array st[MAX_TABLES]
     static integer index = 0
     static timer t = CreateTimer()
     unit Target = null
     unit Attacker = null
     multiboard mb = null
     integer ROW = 0
     real COUNT = 0
     integer S_COL = 0
     integer E_COL = 0
     
static method GetIcon takes integer index,integer s_col, integer e_col returns string
     if index == s_col then
          return Bars[0]
     elseif index == e_col then
          return Bars[23]
     endif

     return Bars[24]
endmethod
 
static method RefreshTable takes nothing returns nothing
     local integer i = 0
     local integer j = 0
     local multiboarditem mbi = null
     local string icon = ""
     local integer k = 0

     loop
     exitwhen i >= .index
          set j = .st[i].S_COL
          set k = R2I(Aggro.get(.st[i].Target,.st[i].Attacker,true) / .st[i].COUNT)
          loop
          exitwhen j > .st[i].E_COL
               set mbi = MultiboardGetItem(.st[i].mb,.st[i].ROW,j)
               if j == .st[i].S_COL then
                    if k == 0 then
                         set icon = Bars[0]
                    elseif k>=7 then
                         set k=k-7
                         set icon = Bars[7]
                    else
                         set icon = Bars[k]
                         set k = 0
                    endif
               elseif j == .st[i].E_COL then
                    if k==0 then
                         set icon = Bars[23]
                    elseif k>=7 then
                         set icon = Bars[22]
                    else
                         set icon = Bars[15+k]
                    endif
               else
                    if k==0 then
                         set icon = Bars[24]
                    elseif k>=7 then
                         set k = k - 7
                         set icon = Bars[15]
                    else
                         set icon = Bars[7+k]
                         set k = 0
                    endif
               endif
          set j = j + 1
          call MultiboardSetItemIcon(mbi,icon)
          call MultiboardReleaseItem(mbi)
          set mbi = null
          endloop
     set i = i + 1
     endloop
endmethod
 
static method remove takes multiboard m, integer row returns nothing
     local integer i = 0
     local integer j = 0
     local multiboarditem mbi = null

     loop
     exitwhen i >=. index
          if .st[i].ROW == row and .st[i].mb == m then
               set j = .st[i].S_COL
               loop
               exitwhen j > .st[i].E_COL
                    set mbi = MultiboardGetItem(.st[i].mb,.st[i].ROW,j)
                    call MultiboardSetItemStyle(mbi,false,false)
                    call MultiboardReleaseItem(mbi)
                    set mbi = null
               set j = j + 1
               endloop
               call .st[i].destroy()
               set .index = .index - 1
               set .st[i] = .st[.index]
               if .index == 0 then
                    call PauseTimer(.t)
               endif
               set i = .index
          endif
     set i = i + 1
     endloop
endmethod
     
static method add takes unit Target,unit Attacker, multiboard m,integer row,integer s_col,integer e_col returns nothing
     local integer i = 0
     local multiboarditem mbi = null

     set .st[.index] = Table.create()
     set .st[.index].mb = m
     set .st[.index].ROW = row
     set .st[.index].S_COL = s_col
     set .st[.index].E_COL = e_col
     set .st[.index].Target = Target
     set .st[.index].Attacker = Attacker
     set .st[.index].COUNT = 100. / ( (e_col - s_col + 1) * 8 - 2)
     if e_col > MultiboardGetColumnCount(m) then
          call MultiboardSetColumnCount(m,e_col)
     endif
     if row > MultiboardGetRowCount(m) then
          call MultiboardSetRowCount(m,row)
     endif
     set i = s_col
     loop
     exitwhen i > .st[.index].E_COL
          set mbi = MultiboardGetItem(m,row,i)
          call MultiboardSetItemStyle(mbi,false,true)
          call MultiboardSetItemWidth(mbi,0.01)
          call MultiboardSetItemIcon(mbi,Table.GetIcon(i,.st[.index].S_COL,.st[.index].E_COL))
          call MultiboardReleaseItem(mbi)
          set mbi = null
     set i = i + 1
     endloop
     if .index == 0 then
          call TimerStart(.t,0.04,true,function Table.RefreshTable)
     endif
     set .index = .index + 1
endmethod
 
endstruct

private function onInit takes nothing returns nothing
set Bars[0] = "war3mapImported\\AggroL0.tga"
set Bars[1] = "war3mapImported\\AggroL1.tga"
set Bars[2] = "war3mapImported\\AggroL2.tga"
set Bars[3] = "war3mapImported\\AggroL3.tga"
set Bars[4] = "war3mapImported\\AggroL4.tga"
set Bars[5] = "war3mapImported\\AggroL5.tga"
set Bars[6] = "war3mapImported\\AggroL6.tga"
set Bars[7] = "war3mapImported\\AggroL7.tga"
set Bars[8] = "war3mapImported\\AggroM1.tga"
set Bars[9] = "war3mapImported\\AggroM2.tga"
set Bars[10] = "war3mapImported\\AggroM3.tga"
set Bars[11] = "war3mapImported\\AggroM4.tga"
set Bars[12] = "war3mapImported\\AggroM5.tga"
set Bars[13] = "war3mapImported\\AggroM6.tga"
set Bars[14] = "war3mapImported\\AggroM7.tga"
set Bars[15] = "war3mapImported\\AggroM8.tga"
set Bars[16] = "war3mapImported\\AggroR1.tga"
set Bars[17] = "war3mapImported\\AggroR2.tga"
set Bars[18] = "war3mapImported\\AggroR3.tga"
set Bars[19] = "war3mapImported\\AggroR4.tga"
set Bars[20] = "war3mapImported\\AggroR5.tga"
set Bars[21] = "war3mapImported\\AggroR6.tga"
set Bars[22] = "war3mapImported\\AggroR7.tga"
set Bars[23] = "war3mapImported\\AggroR0.tga"
set Bars[24] = "war3mapImported\\AggroM0.tga"
endfunction

endlibrary
library ShieldSystem

globals
     private constant integer MAX_SHIELDS = 50 // Maximum shields on one unit
     private constant integer MAX_UNITS = 100 // Maximum units, which may have shields at the same time
     private constant real TIMER_PERIOD = 0.25 //Shield duration checking timer period


     private constant unit array INDEXED_UNITS[MAX_UNITS]
     private integer INDEXED_UNIT_COUNT = 0
endglobals

private function GetShieldUnitIndex takes unit whichUnit returns integer
     local integer i = 1
     local integer pos = INDEXED_UNIT_COUNT + 1
     local boolean found = false

     loop
         exitwhen i > INDEXED_UNIT_COUNT or found
         if INDEXED_UNITS[i] == null and (i < pos) then
              set pos = i
         endif
         if INDEXED_UNITS[i] == whichUnit then
              set found = true
              set pos = i
         endif
         set i = i + 1
     endloop
     if not(INDEXED_UNITS[pos] == whichUnit) then
          set INDEXED_UNITS[pos] = whichUnit
          //call BJDebugMsg("Creating new index for " + GetUnitName(whichUnit) + " as " + I2S(pos))
     endif
     if pos > INDEXED_UNIT_COUNT then
          set INDEXED_UNIT_COUNT = INDEXED_UNIT_COUNT + 1
     endif
     
     return pos
endfunction

private function IsUnitShielded takes unit whichUnit returns boolean
     local integer i = 1
     local boolean found = false

     loop
          exitwhen i > INDEXED_UNIT_COUNT or found
          if INDEXED_UNITS[i] == whichUnit then
               set found = true
          endif
          set i = i + 1
     endloop
 
     if found then
          return true
     endif
   
     return false
endfunction

private struct Shield
     unit CASTER = null
     integer AURACODE
     integer BUFFCODE
     real REMAINING_TIME
     real DURABILITY
     real MAX_DURABILITY
     real BLOCK_MULT // a value beetwen 0 and 1 = which part of damage will be blocked
     integer BLOCK_DAMAGE_TYPE // -1 any damage, 0 phys damage, 1 magical damage
endstruct

struct UnitShield
     private static UnitShield array st[MAX_UNITS]
     private static timer t = null
     private static Shield tempShield
     unit TARGET
     integer N = 0 // number of shields on target
     Shield array Shields[MAX_SHIELDS]

     private static method UnitWithIndexHasBuff takes integer k, integer forbidden_i, integer BUFFCODE returns boolean
          local integer i = 1
          loop
               exitwhen i > .st[k].N
               if .st[k].Shields[i].BUFFCODE == BUFFCODE and not(i==forbidden_i) then
                    return true
               endif
               set i = i + 1
          endloop
          return false
     endmethod

     private static method RemoveUnitFromIndexerByIndex takes integer k returns nothing
          local integer i = 1
          set INDEXED_UNITS[k] = null
          loop
               exitwhen i > .st[k].N
               call UnitRemoveAbility(.st[k].TARGET,.st[k].Shields[i].AURACODE)
               call UnitRemoveAbility(.st[k].TARGET,.st[k].Shields[i].BUFFCODE)
               call .st[k].Shields[i].destroy()
               set .st[k].Shields[i] = 0
               set i = i + 1
          endloop
          call .st[k].destroy()
          if k == INDEXED_UNIT_COUNT then
               set INDEXED_UNIT_COUNT = INDEXED_UNIT_COUNT - 1
          endif
     endmethod

     private static method RemoveShieldByIndexes takes integer k, integer i returns nothing

          if not UnitWithIndexHasBuff(k,i,.st[k].Shields[i].BUFFCODE) then
               call UnitRemoveAbility(.st[k].TARGET,.st[k].Shields[i].AURACODE)
               call UnitRemoveAbility(.st[k].TARGET,.st[k].Shields[i].BUFFCODE)
          endif

          call .st[k].Shields[i].destroy()
          set .st[k].Shields[i] = .st[k].Shields[.st[k].N]
          set .st[k].Shields[.st[k].N] = 0
          set .st[k].N = .st[k].N - 1
         
          //if no shields on unit remove it from indexer
          if .st[k].N == 0 and not (IsUnitType(.st[k].TARGET,UNIT_TYPE_HERO)) then
               call RemoveUnitFromIndexerByIndex(k)
          endif          
     endmethod

     private static method onTimer takes nothing returns nothing
          local integer k = 1
          local integer i = 1
          local integer j = 1
          local boolean flag = false
          //call BJDebugMsg("Timer Tick")
          loop
               exitwhen k > INDEXED_UNIT_COUNT
               if IsUnitDeadBX(.st[k].TARGET) then
                    call RemoveUnitFromIndexerByIndex(k)
               else
               set i = 1
               loop
                    exitwhen i > .st[k].N
                    //call BJDebugMsg("Lowering time for k=" + I2S(k) + ", i=" + I2S(i) + " by " + R2S(TIMER_PERIOD))
                    set .st[k].Shields[i].REMAINING_TIME = .st[k].Shields[i].REMAINING_TIME - TIMER_PERIOD    
                    if .st[k].Shields[i].REMAINING_TIME <= 0. then
                         //call BJDebugMsg("Shield " + I2S(i) + " for " + GetUnitName(.st[k].TARGET) + " with index k=" + I2S(k) + " has expired.")
                         call RemoveShieldByIndexes(k,i)
                         set i = i - 1
                    endif
                    set i = i + 1
               endloop

               //Sorting shields in increasing in REMAINING_TIME order
               set i = 1
               loop
                    exitwhen i > .st[k].N
                    set j = i+1
                    loop
                         exitwhen j > .st[k].N
                         if .st[k].Shields[i].REMAINING_TIME > .st[k].Shields[j].REMAINING_TIME then
                              set tempShield = .st[k].Shields[i]
                              set .st[k].Shields[i] = .st[k].Shields[j]
                              set .st[k].Shields[j] = tempShield
                         endif
                         set j = j + 1
                    endloop
                    set i = i + 1
               endloop

               endif
               set k = k + 1
          endloop
     endmethod

     static method IncreaseShieldDurability takes unit TARGET, unit CASTER, integer BUFFCODE, real durability, boolean PERCENTMAXDUR returns boolean
          local integer k = 0
          local integer i = 1
          if IsUnitShielded(TARGET) then
               set k = GetShieldUnitIndex(TARGET)
          else
               return false
          endif
          loop
               exitwhen i > .st[k].N
               if (.st[k].Shields[i].BUFFCODE == BUFFCODE) or (BUFFCODE == 0) then
                    if (.st[k].Shields[i].CASTER == CASTER) or (CASTER == null) then
                         if PERCENTMAXDUR then
                              set .st[k].Shields[i].DURABILITY = .st[k].Shields[i].DURABILITY + .st[k].Shields[i].MAX_DURABILITY*durability
                         else
                              set .st[k].Shields[i].DURABILITY = .st[k].Shields[i].DURABILITY + durability
                         endif
                    endif
               endif
               set i = i + 1
          endloop
          return true
     endmethod

     static method IncreaseShieldDuration takes unit TARGET, unit CASTER, integer BUFFCODE, real duration returns boolean
          local integer k = 0
          local integer i = 1
          if IsUnitShielded(TARGET) then
               set k = GetShieldUnitIndex(TARGET)
          else
               return false
          endif
          loop
               exitwhen i > .st[k].N
               if (.st[k].Shields[i].BUFFCODE == BUFFCODE) or (BUFFCODE == 0) then
                    if (.st[k].Shields[i].CASTER == CASTER) or (CASTER == null) then
                         set .st[k].Shields[i].REMAINING_TIME = .st[k].Shields[i].REMAINING_TIME + duration
                    endif
               endif
               set i = i + 1
          endloop
          return true
     endmethod

     //Try to block a part of damage (AMOUNT) of a given type (damageTYPE) for unit (whichUnit) and returns the blocked part
     
     static method Block takes unit whichUnit, real AMOUNT, integer damageTYPE returns real
          local integer k = 0
          local integer i = 1
          local real blocked = 0.
          local real curAmount = AMOUNT
          local real tempAmount = 0.
          if IsUnitShielded(whichUnit) then
               set k = GetShieldUnitIndex(whichUnit)
          else
               return 0.
          endif

          loop
               exitwhen i > .st[k].N or curAmount <= 0.
               if (.st[k].Shields[i].BLOCK_DAMAGE_TYPE == damageTYPE) or (.st[k].Shields[i].BLOCK_DAMAGE_TYPE == -1) then
                    set tempAmount = AMOUNT * .st[k].Shields[i].BLOCK_MULT
                    if tempAmount > curAmount then
                         set tempAmount = curAmount
                    endif
                    if .st[k].Shields[i].DURABILITY > tempAmount then
                         set .st[k].Shields[i].DURABILITY = .st[k].Shields[i].DURABILITY - tempAmount
                         set blocked = blocked + tempAmount
                         set curAmount = curAmount - tempAmount
                    else
                         set blocked = blocked + .st[k].Shields[i].DURABILITY
                         set curAmount = curAmount - .st[k].Shields[i].DURABILITY
                         call RemoveShieldByIndexes(k,i)
                         set i = i - 1
                    endif
               endif
               set i = i + 1
          endloop

          return blocked
     endmethod

     static method Add takes unit TARGET, unit CASTER, real AMOUNT, real DURATION, integer damageTYPE