1. Are you planning to upload your awesome spell or system 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 havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  5. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  6. The results are out! Check them out.
    Dismiss Notice
  7. The poll for Hive's 12th Concept Art Contest is up! Go cast your vote for your favourite genie!
    Dismiss Notice
  8. The raddest synthwave tracks were chosen - Check out our Music Contest #12 - Results and congratulate the winners!
    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

Silithid Devourer Spellset V1.01.w3x
Variables
Initialization
Melee Initialization
Hero Abilities
Rupturing Stab
Leech Life
Corpse Crusher
Blood Boil
Helpful Files
RuSt Variable Creator
LeLi Variable Creator
CoCr Variable Creator
BlBo Variable Creator
This Map
Spawn heroes
Test Notification

		
Name Type Is Array Initial Value
BlBo_Blue integer Yes
BlBo_DamageTick real Yes
BlBo_DamageTickCurrent real Yes
BlBo_Duration real Yes
BlBo_Green integer Yes
BlBo_HealthDamage real Yes
BlBo_ManaDamage real Yes
BlBo_NextNode integer Yes
BlBo_NodeNumber integer No
BlBo_PrevNode integer Yes
BlBo_RecyclableNodes integer No
BlBo_RecycleNodes integer Yes
BlBo_Red integer Yes
BlBo_Timer timer No
BlBo_Unit unit Yes
CoCr_AuraDelay real No
CoCr_BleedHealHealth real Yes
CoCr_BleedHealMana real Yes
CoCr_Caster unit Yes
CoCr_CorpseAOE real Yes
CoCr_CorpseHealHealth real Yes
CoCr_CorpseHealMana real Yes
CoCr_CurrentHeight real Yes
CoCr_Direction boolean Yes
CoCr_Effect effect Yes
CoCr_HomeNode integer Yes
CoCr_Level integer Yes
CoCr_MapMaxX real No
CoCr_MapMaxY real No
CoCr_MapMinX real No
CoCr_MapMinY real No
CoCr_NextNode integer Yes
CoCr_NodeNumber integer No
CoCr_Player player Yes
CoCr_PrevNode integer Yes
CoCr_RecyclableNodes integer No
CoCr_RecycleNodes integer Yes
CoCr_SlowAOE real Yes
CoCr_SlowBloodScale real Yes
CoCr_SlowBonusSpeed real Yes
CoCr_SlowCorpseScale real Yes
CoCr_SlowDuration real Yes
CoCr_SlowedGroup group No
CoCr_SlowHealthDamage real Yes
CoCr_SlowManaDamage real Yes
CoCr_SlowSpeed real Yes
CoCr_StageID integer Yes
CoCr_TempGroup group No
CoCr_TempGroup2 group No
CoCr_Timer timer No
CoCr_Unit unit Yes
CoCr_X real Yes
CoCr_XVel real Yes
CoCr_Y real Yes
CoCr_YVel real Yes
CoCr_ZLoc location No
CoCr_ZVel real Yes
LeLi_Caster unit Yes
LeLi_Delay real Yes
LeLi_DelayStart real Yes
LeLi_Duration real Yes
LeLi_GrabbedTarget boolean Yes
LeLi_HealthDamage real Yes
LeLi_HealthHeal real Yes
LeLi_ManaDamage real Yes
LeLi_ManaHeal real Yes
LeLi_ManaRefund real Yes
LeLi_NextNode integer Yes
LeLi_NodeNumber integer No
LeLi_PrevNode integer Yes
LeLi_RecyclableNodes integer No
LeLi_RecycleNodes integer Yes
LeLi_Stunner unit No
LeLi_Timer timer No
LeLi_Unit unit Yes
RuSt_BleedDamageHealth real Yes
RuSt_BleedDamageMana real Yes
RuSt_BloodiedEffect effect Yes
RuSt_Caster unit Yes
RuSt_DamageDelay real Yes
RuSt_DamageDelayStart real Yes
RuSt_Duration real Yes
RuSt_NextNode integer Yes
RuSt_NodeNumber integer No
RuSt_PrevNode integer Yes
RuSt_RecyclableNodes integer No
RuSt_RecycleNodes integer Yes
RuSt_Timer timer No
RuSt_Unit unit Yes
Default melee game initialization for all players
Melee Initialization
  Events
    Map initialization
  Conditions
  Actions
    Melee Game - Use melee time of day (for all players)
    Melee Game - Limit Heroes to 1 per Hero-type (for all players)
    Melee Game - Give trained Heroes a Scroll of Town Portal (for all players)
    Melee Game - Set starting resources (for all players)
    Melee Game - Remove creeps and critters from used start locations (for all players)
    Melee Game - Create starting units (for all players)
    Melee Game - Run melee AI scripts (for computer players)
    Melee Game - Enforce victory/defeat conditions (for all players)
////////////////////////////////////////////////////////////////////
//                     RUPTURING STAB V1.01                       //
//  Author: Tank-Commander                                        //
//  Purpose: Simple Stab & Damage over time ability to use in     //
//           combo with other abilities                           //
//                                                                //
//  Notes:                                                        //
//    -  Read the readme before you try modifying the config      //
//    -  Use the "Helpful files" to help you import the system    //
//                                                                //
//                                                                //
//  If you have used this spell in your map, you are required     //
//  to give credits to Tank-Commander for the creation of it      //
//  If you would like to use snippets of code from this for       //
//  whatever, getting permission and crediting the source/linking //
//  would be much appreciated.                                    //
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  README:                                                       //
//    Before modifying this spell a few things need to be         //
//    understood and read, this is one of those things, while     //
//    most modification can be considered intuitive, it still     //
//    helps to read through these intstructions, as they will     //
//    inform you about how to configure this spell to your        //
//    desire.                                                     //
//----------------------------------------------------------------//
//  Initial importing: The variable creator trigger can be        //
//  imported first and if you have the correct settings (file,    //
//  preferences, General, automatically create unknown variables  //
//  checked, then when you paste in the variable creator it       //
//  will automatically give you all the variables you need for    //
//  this spell                                                    //
//                                                                //
//  While the remaining object editor based data is not required  //
//  to function (provided they're replaced with equivelents)      //
//  it's recommended that they are also imported, if their data   //
//  value are not the same as listed in the configuration, those  //
//  configurables will need to be changed to work correctly       //
//----------------------------------------------------------------//
//  TimerSpeed: This is the rate at which the loop timer of the   //
//  ability runs the default value 0.03125 allows the loop        //
//  function to run 32 times per second giving a smooth ability   //
constant function RuSt_TimerSpeed takes nothing returns real
    return 0.031250000
endfunction
//----------------------------------------------------------------//
//  Ability: This is the raw code for the ability used as a base  //
//  to see raw data press ctrl + d in the object editor, do it    //
//  again to revert to normal                                     //
constant function RuSt_Ability takes nothing returns integer
    return 'A000'
endfunction
//----------------------------------------------------------------//
//  BonusBuff: This is the raw code for the ability used to       //
//  Apply damage bonuses to the ability (it can be either a       //
//  regular ability or a specific buff which the caster can be    //
//  afflicted with to give optionally temporary or permanent      //
//  buffs to this ability                                         //
constant function RuSt_BonusBuff takes nothing returns integer
    return 'B003'
endfunction
//----------------------------------------------------------------//
//  BleedBuff: This is the raw code of the ability used to        //
//  debuff units damaged by this ability, it should be based off  //
//  slow aura                                                     //
constant function RuSt_BleedBuff takes nothing returns integer
    return 'A001'
endfunction
//----------------------------------------------------------------//
//  DrainBuff: This is the same as BuffAbility except used for    //
//  extending the duration of BleedBuff based on the target of    //
//  the ability having this buff applied to them                  //
constant function RuSt_DrainBuff takes nothing returns integer
    return 'B001'
endfunction
//----------------------------------------------------------------//
//  BleedDelay: This is the time in seconds between each bit of   //
//  damage dealt to the target via bleeding                       //
function RuSt_BleedDelay takes real level returns real
    return 0.312500000
endfunction
//----------------------------------------------------------------//
//  BleedDuration: This is how long the target will bleed for in  //
//  seconds
function RuSt_BleedDuration takes real level returns real
    return 4.
endfunction
//----------------------------------------------------------------//
//  BleedDamageHealth: This is the amount of damage the target    //
//  takes over the duration of the bleeding                       //
function RuSt_BleedDamageHealth takes real level returns real
    return 15 + 15 * level
endfunction
//----------------------------------------------------------------//
//  BleedDamageMana: This is this is the amount of mana lost by   //
//  the target over the duration of the bleeding                  //
function RuSt_BleedDamageMana takes real level returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  BonusBleedDamageHealth: This is the extra bleed damage taken  //
//  if the caster has BonusBuff applied to them when first        //
//  stabbing                                                      //
function RuSt_BonusBleedDamageHealth takes real level returns real
    return 15 * level
endfunction
//----------------------------------------------------------------//
//  BonusBleedDamageMana: This is the extra bleed mana lost if    //
//  the caster has BonusBuff applied to them when first stabbing  //
function RuSt_BonusBleedDamageMana takes real level returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  StabDamageHealth: This is the amount of damage taken by the   //
//  target when they are first stabbed                            //
function RuSt_StabDamageHealth takes real level returns real
    return 25 + (25 * level)
endfunction
//----------------------------------------------------------------//
//  StabDamageMana: This is the amount of mana lost by the target //
//  when they are first stabbed                                   //
function RuSt_StabDamageMana takes real level returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  BonusStabDamageHealth: This is the extra Stab damage taken if //
// the caster has BonusBuff applied to them when first stabbing   //
function RuSt_BonusStabDamageHealth takes real level returns real
    return 25 * level
endfunction
//----------------------------------------------------------------//
//  BonusStabDamageMana: This is the extra Stab mana lost if the  //
//  caster has BonusBuff applied to them when first stabbing      //
function RuSt_BonusStabDamageMana takes real level returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  StabEffect: This is the effect played on the target when      //
//  they are stabbed                                              //
constant function RuSt_StabEffect takes nothing returns string
    return "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
endfunction
//----------------------------------------------------------------//
//  StabAttachmentPoint: This is the location on the target that  //
//  StabEffect is played on                                       //
constant function RuSt_StabAttachmentPoint takes nothing returns string
    return "chest"
endfunction
//----------------------------------------------------------------//
//  BleedingEffect: This is the effect played on the target for   //
//  the duration that they are bleeding                           //
constant function RuSt_BleedingEffect takes nothing returns string
    return "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
endfunction
//----------------------------------------------------------------//
//  BleedingAttachmentPoint: This is the location on the target   //
//  that BleedingEffect & DrainCombinedEffect are played on       //
constant function RuSt_BleedingAttachmentPoint takes nothing returns string
    return "origin"
endfunction
//----------------------------------------------------------------//
//  BloodiedEffect: This is the effect played on the caster on    //
//  the body part or weapon they used to stab the target          //
constant function RuSt_BloodiedEffect takes nothing returns string
    return "Objects\\Spawnmodels\\Other\\HumanBloodCinematicEffect\\HumanBloodCinematicEffect.mdl"
endfunction
//----------------------------------------------------------------//
//  BloodiedAttachmentPoint: This is the location on the caster   //
//  that BloodiedEffect is played on                              //
constant function RuSt_BloodiedAttachmentPoint takes nothing returns string
    return "sprite first"
endfunction
//----------------------------------------------------------------//
//  DrainCombinedEffect: This is the effect played to denote      //
//  that the duration of the bleeding is being extended via the   //
//  target having DrainBuff applied to them                       //
constant function RuSt_DrainCombinedEffect takes nothing returns string
    return "Abilities\\Spells\\Undead\\CarrionSwarm\\CarrionSwarmDamage.mdl"
endfunction
//----------------------------------------------------------------//
//  AttackType: This is the attack type used by the spell         //
constant function RuSt_AttackType takes nothing returns attacktype
    return ATTACK_TYPE_NORMAL
endfunction
//----------------------------------------------------------------//
//  DamageType: This is the damagetype used by the spell, armour  //
//  reduces the damage based on this type                         //
constant function RuSt_DamageType takes nothing returns damagetype
    return DAMAGE_TYPE_NORMAL
endfunction
//----------------------------------------------------------------//
//  WeaponType: This is the weapontype used by the spell
constant function RuSt_WeaponType takes nothing returns weapontype
    return null
endfunction
//----------------------------------------------------------------//
//                      END OF CONFIGURATION                      //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////
//  Funtion used to check if a unit is still bleeding            //
///////////////////////////////////////////////////////////////////
function RuSt_IsNotBleeding takes unit u returns boolean
    local integer node = 0
   
    loop
        set node = udg_RuSt_NextNode[node]
        exitwhen node == 0
   
        if udg_RuSt_Unit[node] == u then
            return false
        endif

    endloop
   
    return true
endfunction

///////////////////////////////////////////////////////////////////
//  Function used to primarily deal Damage over time but also    //
//  adds artificial delay to mimic warcraft mechanics for        //
//  Damage over time while keeping in strict time with the       //
//  duration of the ability                                      //
///////////////////////////////////////////////////////////////////
function RuSt_Loop takes nothing returns nothing
    local integer node = 0
   
    loop
        set node = udg_RuSt_NextNode[node]
        exitwhen node == 0
       
        //Extend duration if the enemy is being leeched
        if GetUnitAbilityLevel(udg_RuSt_Unit[node], RuSt_DrainBuff()) > 0 then
            set udg_RuSt_Duration[node] = udg_RuSt_Duration[node] + RuSt_TimerSpeed()
            call DestroyEffect(AddSpecialEffectTarget(RuSt_DrainCombinedEffect(), udg_RuSt_Unit[node], RuSt_BleedingAttachmentPoint()))
        endif
       
        //Check if the spell is not finished
        if udg_RuSt_Duration[node] > 0. then
            set udg_RuSt_Duration[node] = udg_RuSt_Duration[node] - RuSt_TimerSpeed()
            set udg_RuSt_DamageDelay[node] = udg_RuSt_DamageDelay[node] - RuSt_TimerSpeed()
           
            //Check if it's time to deal damage again
            if udg_RuSt_DamageDelay[node] <= 0. then
                //Deal damage
                set udg_RuSt_DamageDelay[node] = udg_RuSt_DamageDelayStart[node]
                call DestroyEffect(AddSpecialEffectTarget(RuSt_BleedingEffect(), udg_RuSt_Unit[node], RuSt_BleedingAttachmentPoint()))
                call UnitDamageTarget(udg_RuSt_Caster[node], udg_RuSt_Unit[node], udg_RuSt_BleedDamageHealth[node], true, false, RuSt_AttackType(), RuSt_DamageType(), RuSt_WeaponType())
                call SetUnitState(udg_RuSt_Unit[node], UNIT_STATE_MANA, GetUnitState(udg_RuSt_Unit[node], UNIT_STATE_MANA) - udg_RuSt_BleedDamageMana[node])
            endif
           
        else
            call DestroyEffect(udg_RuSt_BloodiedEffect[node])
           
            //Recycle
            set udg_RuSt_RecycleNodes[udg_RuSt_RecyclableNodes] = node
            set udg_RuSt_RecyclableNodes = udg_RuSt_RecyclableNodes + 1
            set udg_RuSt_NextNode[udg_RuSt_PrevNode[node]] = udg_RuSt_NextNode[node]
            set udg_RuSt_PrevNode[udg_RuSt_NextNode[node]] = udg_RuSt_PrevNode[node]
           
            //Check if this is the last instance of this unit bleeding
            if RuSt_IsNotBleeding(udg_RuSt_Unit[node]) then
                call UnitRemoveAbility(udg_RuSt_Unit[node], RuSt_BleedBuff())

                //Pause timer if this was the last instance
                if (udg_RuSt_PrevNode[0] == 0) then
                    call PauseTimer(udg_RuSt_Timer)
                endif
               
            endif
           
        endif
       
    endloop
   
endfunction

///////////////////////////////////////////////////////////////////
//  Function used to deal damage from the ability and cause      //
//  target units to start bleeding                               //
///////////////////////////////////////////////////////////////////
function RuSt_Cast takes nothing returns boolean
    //Set up locals
    local integer node
    local real level
   
    if (GetSpellAbilityId() == RuSt_Ability()) then
        //Set up Node
        if (udg_RuSt_RecyclableNodes == 0) then
            set udg_RuSt_NodeNumber = udg_RuSt_NodeNumber + 1
            set node = udg_RuSt_NodeNumber
        else
            set udg_RuSt_RecyclableNodes = udg_RuSt_RecyclableNodes - 1
            set node = udg_RuSt_RecycleNodes[udg_RuSt_RecyclableNodes]
        endif

        set udg_RuSt_NextNode[node] = 0
        set udg_RuSt_NextNode[udg_RuSt_PrevNode[0]] = node
        set udg_RuSt_PrevNode[node] = udg_RuSt_PrevNode[0]
        set udg_RuSt_PrevNode[0] = node
       
        //Start timer if this is the only instance
        if (udg_RuSt_PrevNode[node] == 0) then
            call TimerStart(udg_RuSt_Timer, RuSt_TimerSpeed(), true, function RuSt_Loop)
        endif
       
        //Apply Data
        set udg_RuSt_Unit[node] = GetSpellTargetUnit()
        set udg_RuSt_Caster[node] = GetTriggerUnit()
        set udg_RuSt_BloodiedEffect[node] = AddSpecialEffectTarget(RuSt_BloodiedEffect(), udg_RuSt_Caster[node], RuSt_BloodiedAttachmentPoint())
        set level = GetUnitAbilityLevel(udg_RuSt_Caster[node], RuSt_Ability())
        set udg_RuSt_DamageDelayStart[node] = RuSt_BleedDelay(level)
        set udg_RuSt_DamageDelay[node] = udg_RuSt_DamageDelayStart[node]
        set udg_RuSt_Duration[node] = RuSt_BleedDuration(level)

        //Stab Effect
        call UnitAddAbility(udg_RuSt_Unit[node], RuSt_BleedBuff())
        call DestroyEffect(AddSpecialEffectTarget(RuSt_StabEffect(), udg_RuSt_Unit[node], RuSt_StabAttachmentPoint()))
       
        //Check for Blood Boil Bonuses
        if GetUnitAbilityLevel(udg_RuSt_Caster[node], RuSt_BonusBuff()) > 0 then
            set udg_RuSt_BleedDamageHealth[node] = (RuSt_BleedDamageHealth(level) + RuSt_BonusBleedDamageHealth(level)) / (udg_RuSt_Duration[node] / udg_RuSt_DamageDelay[node])
            set udg_RuSt_BleedDamageMana[node] = (RuSt_BleedDamageMana(level) + RuSt_BonusBleedDamageMana(level)) / (udg_RuSt_Duration[node] / udg_RuSt_DamageDelay[node])
            call UnitDamageTarget(udg_RuSt_Caster[node], udg_RuSt_Unit[node], RuSt_StabDamageHealth(level) + RuSt_BonusStabDamageHealth(level), true, false, RuSt_AttackType(), RuSt_DamageType(), RuSt_WeaponType())
            call SetUnitState(udg_RuSt_Unit[node], UNIT_STATE_MANA, GetUnitState(udg_RuSt_Unit[node], UNIT_STATE_MANA) - (RuSt_StabDamageMana(level) + RuSt_BonusStabDamageMana(level)))
        else
            set udg_RuSt_BleedDamageHealth[node] = RuSt_BleedDamageHealth(level) / (udg_RuSt_Duration[node] / udg_RuSt_DamageDelay[node])
            set udg_RuSt_BleedDamageMana[node] = RuSt_BleedDamageMana(level) / (udg_RuSt_Duration[node] / udg_RuSt_DamageDelay[node])
            call UnitDamageTarget(udg_RuSt_Caster[node], udg_RuSt_Unit[node], RuSt_StabDamageHealth(level), true, false, RuSt_AttackType(), RuSt_DamageType(), RuSt_WeaponType())
            call SetUnitState(udg_RuSt_Unit[node], UNIT_STATE_MANA, GetUnitState(udg_RuSt_Unit[node], UNIT_STATE_MANA) - RuSt_StabDamageMana(level))
        endif
       
    endif
   
    return false
endfunction

///////////////////////////////////////////////////////////////////
//  Function used to initialise the event listeners of the spell //
///////////////////////////////////////////////////////////////////
function InitTrig_Rupturing_Stab takes nothing returns nothing
    local trigger t = CreateTrigger()
   
    //Set up trigger
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function RuSt_Cast))
endfunction
///////////////////////////////////////////////////////////////////
//  END OF THE SPELL                                             //
///////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//                       LEECH LIFE V1.01                         //
//  Author: Tank-Commander                                        //
//  Requires: Dummy.mdl                                           //
//  Purpose: Stun and drain health from the target, useful to     //
//           disable enemy heroes                                 //
//                                                                //
//  Credits: Vexorian (dummy.mdl)                                 //
//                                                                //
//  Notes:                                                        //
//    -  Read the readme before you try modifying the config      //
//    -  Use the "Helpful files" to help you import the system    //
//                                                                //
//                                                                //
//  If you have used this spell in your map, you are required     //
//  to give credits to Tank-Commander for the creation of it      //
//  If you would like to use snippets of code from this for       //
//  whatever, getting permission and crediting the source/linking //
//  would be much appreciated.                                    //
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  README:                                                       //
//    Before modifying this spell a few things need to be         //
//    understood and read, this is one of those things, while     //
//    most modification can be considered intuitive, it still     //
//    helps to read through these intstructions, as they will     //
//    inform you about how to configure this spell to your        //
//    desire.                                                     //
//----------------------------------------------------------------//
//  Initial importing: The variable creator trigger can be        //
//  imported first and if you have the correct settings (file,    //
//  preferences, General, automatically create unknown variables  //
//  checked, then when you paste in the variable creator it       //
//  will automatically give you all the variables you need for    //
//  this spell                                                    //
//                                                                //
//  While the remaining object editor based data is not required  //
//  to function (provided they're replaced with equivelents)      //
//  it's recommended that they are also imported, if their data   //
//  value are not the same as listed in the configuration, those  //
//  configurables will need to be changed to work correctly       //
//----------------------------------------------------------------//
//  TimerSpeed: This is the rate at which the loop timer of the   //
//  ability runs the default value 0.03125 allows the loop        //
//  function to run 32 times per second giving a smooth ability   //
constant function LeLi_TimerSpeed takes nothing returns real
    return 0.031250000
endfunction
//----------------------------------------------------------------//
//  Ability: This is the raw code for the ability used as a base  //
//  to see raw data press ctrl + d in the object editor, do it    //
//  again to revert to normal                                     //
constant function LeLi_Ability takes nothing returns integer
    return 'A002'
endfunction
//----------------------------------------------------------------//
//  BonusBuff: This is the raw code for the ability used to       //
//  Apply damage bonuses to the ability (it can be either a       //
//  regular ability or a specific buff which the caster can be    //
//  afflicted with to give optionally temporary or permanent      //
//  buffs to this ability                                         //
constant function LeLi_BonusBuff takes nothing returns integer
    return 'B003'
endfunction
//----------------------------------------------------------------//
//  BleedBuff: This is the raw code of the ability used to        //
//  debuff units damaged by this ability, it should be based off  //
//  slow aura                                                     //
constant function LeLi_BleedBuff takes nothing returns integer
    return 'B000'
endfunction
//----------------------------------------------------------------//
//  DummyPlayer: This is the player who will own all dummy units  //
//  created by this spell, it should be a neutral player as to    //
//  not mess with scorescreens                                    //
constant function LeLi_DummyPlayer takes nothing returns player
    return Player(14)
endfunction
//----------------------------------------------------------------//
//  DummyUnit: This is the raw code for the unit used as a dummy  //
//  by the ability, it should use dummy.mdl as its model or some  //
//  other invisible model                                         //
constant function LeLi_DummyUnit takes nothing returns integer
    return 'u000'
endfunction
//----------------------------------------------------------------//
//  DummyStunAbility: This is the raw code of the ability used    //
//  to stun targets of the ability and hold them in place         //
constant function LeLi_DummyStunAbility takes nothing returns integer
    return 'A003'
endfunction
//----------------------------------------------------------------//
//  DummyStunOrder: This is the OrderID to go with the stun       //
//  ability in order ot get the dummy to use it, for stormbolt    //
//  as a base ability this is 852095                              //
constant function LeLi_DummyStunOrder takes nothing returns integer
    return 852095
endfunction
//----------------------------------------------------------------//
//  Order: This is the OrderID to match the ability to make sure  //
//  the caster is always channeling the spell, for drain this is  //
//  852488 (852387 for pre-1.28 versions of warcraft III)         //
constant function LeLi_Order takes nothing returns integer
    return 852488
endfunction
//----------------------------------------------------------------//
//  StopOrder: This is the OrderID to match the order the unit is //
//  given when the unit escapes its range as to stop channeling   //
//  the spell for "stop" this is 851972                           //
constant function LeLi_StopOrder takes nothing returns integer
    return 851972
endfunction
//----------------------------------------------------------------//
//  DeathAnimation: This is the animation name used if the unit   //
//  is killed during the channel of the spell                     //
constant function LeLi_DeathAnimation takes nothing returns string
    return "death"
endfunction
//----------------------------------------------------------------//
//  LoopAnimation: The animation name used during the channel of  //
//  the spell                                                     //
constant function LeLi_LoopAnimation takes nothing returns string
    return "channel"
endfunction
//----------------------------------------------------------------//
//  StopAnimation: This is the animation used when the spell      //
//  ends once the channel has ended to reset the unit animations  //
constant function LeLi_StopAnimation takes nothing returns string
    return "stand"
endfunction
//----------------------------------------------------------------//
//  MaxRange: This is the maximum distance at which the unit is   //
//  able to grab on to a unit, units leaving this radius (either  //
//  from teleporting away or running) will stop the drain, the    //
//  value is squared to make calculations faster                  //
function LeLi_MaxRange takes nothing returns real
    return 62500. //this is 250 * 250
endfunction
//----------------------------------------------------------------//
//  Delay: This is the time in seconds between damage dealt and   //
//  life restored to the caster                                   //
function LeLi_Delay takes real level returns real
    return 0.8
endfunction
//----------------------------------------------------------------//
//  Duration: This is the time in seconds that the spell lasts    //
//  for                                                           //
function LeLi_Duration takes real level returns real
    return 4.05
endfunction
//----------------------------------------------------------------//
//  HealthDamage: This is the amount of damage dealt to the       //
//  target over the duration of life leech                        //
function LeLi_HealthDamage takes real level returns real
    return 65 + (10 * level)
endfunction
//----------------------------------------------------------------//
//  ManaDamage: This is the amount of mana lost by the target     //
//  over the duration of life leech                               //
function LeLi_ManaDamage takes real level returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  BonusHealthDamage: This is the extra damage taken if the      //
//  caster has BonusBuff applied to them when first grabbing      //
//  the target                                                    //
function LeLi_BonusHealthDamage takes real level returns real
    return 50.
endfunction
//----------------------------------------------------------------//
//  BonusManaDamage: This is the extra mana lost if the caster    //
//  has BonusBuff applied to them when first grabbing the target  //
function LeLi_BonusManaDamage takes real level returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  HealthHeal: This is the amount of health restored to the      //
//  caster over the duration of life leech                        //
function LeLi_HealthHeal takes real level returns real
    return 80 + (20 * level)
endfunction
//----------------------------------------------------------------//
//  ManaHeal: This is the amount of mana restored to the caster   //
//  over the duration of life leech                               //
function LeLi_ManaHeal takes real level returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  BonusHealthHeal: This is the amount of extra health restored  //
//  if the target has BleedBuff when first grabbed                //
function LeLi_BonusHealthHeal takes real level returns real
    return 35 * level
endfunction
//----------------------------------------------------------------//
//  BonusManaHeal: This is the amount of extra mana restored if   //
//  the target has BleedBuff when first grabbed                   //
function LeLi_BonusManaHeal takes real level returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  ManaRefund: The amount of mana given back to the caster when  //
//  lifeleech misses (units avoid being grabbed entirely)         //
function LeLi_ManaRefund takes real level returns real
    return 95. - (15. * level)
endfunction
//----------------------------------------------------------------//
//  AttackType: This is the attack type used by the spell         //
constant function LeLi_AttackType takes nothing returns attacktype
    return ATTACK_TYPE_NORMAL
endfunction
//----------------------------------------------------------------//
//  DamageType: This is the damagetype used by the spell, armour  //
//  reduces the damage based on this type                         //
constant function LeLi_DamageType takes nothing returns damagetype
    return DAMAGE_TYPE_NORMAL
endfunction
//----------------------------------------------------------------//
//  WeaponType: This is the weapon type used by the spell         //
constant function LeLi_WeaponType takes nothing returns weapontype
    return null
endfunction
//----------------------------------------------------------------//
//  StunDissapate: This is the time in seconds in takes for the   //
//  stun dummy to be removed                                      //
constant function LeLi_StunDissapate takes nothing returns real
    return 2.
endfunction
//----------------------------------------------------------------//
//                      END OF CONFIGURATION                      //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////
//  Function used to deal damage delayed to mimic ingame         //
//  mechanics, apply stun and control the animations of the      //
//  caster to allow them to visually leech, also permits         //
//  the caster to cancel the ability rather than relying on      //
//  pausing them when the spell starts                           //
///////////////////////////////////////////////////////////////////
function LeLi_Loop takes nothing returns nothing
    local integer node = 0
    local integer tempNode
    local unit u
    local real dx
    local real dy
   
    loop
        set node = udg_LeLi_NextNode[node]
        exitwhen node == 0
        set dx = GetUnitX(udg_LeLi_Unit[node]) - GetUnitX(udg_LeLi_Caster[node])
        set dy = GetUnitY(udg_LeLi_Unit[node]) - GetUnitY(udg_LeLi_Caster[node])
       
        if (udg_LeLi_Duration[node] >= 0.) and (GetUnitCurrentOrder(udg_LeLi_Caster[node]) == LeLi_Order()) and not(IsUnitType(udg_LeLi_Unit[node],UNIT_TYPE_DEAD)) and (dx * dx + dy * dy < LeLi_MaxRange()) then
            set udg_LeLi_Duration[node] = udg_LeLi_Duration[node] - LeLi_TimerSpeed()
            set udg_LeLi_Delay[node] = udg_LeLi_Delay[node] - LeLi_TimerSpeed()
           
            //Successfully grabbed, disable refund and queue animations
            call QueueUnitAnimation(udg_LeLi_Caster[node], LeLi_LoopAnimation())
            if not (udg_LeLi_GrabbedTarget[node]) then
                set udg_LeLi_GrabbedTarget[node] = true
            endif
           
            //Stun unit being leeched
            call SetUnitX(udg_LeLi_Stunner, GetUnitX(udg_LeLi_Unit[node]))
            call SetUnitY(udg_LeLi_Stunner, GetUnitY(udg_LeLi_Unit[node]))
            call IssueTargetOrderById(udg_LeLi_Stunner, LeLi_DummyStunOrder(), udg_LeLi_Unit[node])
           
            //Drain life
            if udg_LeLi_Delay[node] <= 0. then
                set udg_LeLi_Delay[node] = udg_LeLi_DelayStart[node]
                call UnitDamageTarget(udg_LeLi_Caster[node], udg_LeLi_Unit[node], udg_LeLi_HealthDamage[node], true, false, LeLi_AttackType(), LeLi_DamageType(), LeLi_WeaponType())
                call SetWidgetLife(udg_LeLi_Caster[node], GetWidgetLife(udg_LeLi_Caster[node]) + udg_LeLi_HealthHeal[node])
                call SetUnitState(udg_LeLi_Unit[node], UNIT_STATE_MANA, GetUnitState(udg_LeLi_Unit[node], UNIT_STATE_MANA) - udg_LeLi_ManaDamage[node])
                call SetUnitState(udg_LeLi_Caster[node], UNIT_STATE_MANA, GetUnitState(udg_LeLi_Caster[node], UNIT_STATE_MANA) + udg_LeLi_ManaHeal[node])
            endif
           
        else
           
            //In the event of the unit "dodging" stop the channel
            if GetUnitCurrentOrder(udg_LeLi_Caster[node]) == LeLi_Order() then
                call IssueImmediateOrderById(udg_LeLi_Caster[node], LeLi_StopOrder())
            endif
           
            //Refund manacost on whiff
            if not(udg_LeLi_GrabbedTarget[node]) then
                call SetUnitState(udg_LeLi_Caster[node], UNIT_STATE_MANA, GetUnitState(udg_LeLi_Caster[node], UNIT_STATE_MANA) + udg_LeLi_ManaRefund[node])
            endif
           
            call SetUnitPropWindow(udg_LeLi_Unit[node], GetUnitDefaultPropWindow(udg_LeLi_Unit[node]) * bj_DEGTORAD)
           
            if IsUnitType(udg_LeLi_Caster[node], UNIT_TYPE_DEAD) then
                call SetUnitAnimation(udg_LeLi_Caster[node], LeLi_DeathAnimation())
            else
                call SetUnitAnimation(udg_LeLi_Caster[node], LeLi_StopAnimation())
            endif
           
            //Recycle
            set udg_LeLi_RecycleNodes[udg_LeLi_RecyclableNodes] = node
            set udg_LeLi_RecyclableNodes = udg_LeLi_RecyclableNodes + 1
            set udg_LeLi_NextNode[udg_LeLi_PrevNode[node]] = udg_LeLi_NextNode[node]
            set udg_LeLi_PrevNode[udg_LeLi_NextNode[node]] = udg_LeLi_PrevNode[node]

            //Pause timer if this was the last instance
            if (udg_LeLi_PrevNode[0] == 0) then
                call PauseTimer(udg_LeLi_Timer)
            endif
           
        endif
       
    endloop
   
endfunction

///////////////////////////////////////////////////////////////////
//  Function used when the ability is cast to set up spell data  //
//  and to prevent the target from moving as well as work        //
//  out any bonuses from bleeding buffs                          //
///////////////////////////////////////////////////////////////////
function LeLi_Cast takes nothing returns boolean
    local integer node
    local real level
    local real tempreal
   
    if (GetSpellAbilityId() == LeLi_Ability()) then
        //Set up Node
        if (udg_LeLi_RecyclableNodes == 0) then
            set udg_LeLi_NodeNumber = udg_LeLi_NodeNumber + 1
            set node = udg_LeLi_NodeNumber
        else
            set udg_LeLi_RecyclableNodes = udg_LeLi_RecyclableNodes - 1
            set node = udg_LeLi_RecycleNodes[udg_LeLi_RecyclableNodes]
        endif

        set udg_LeLi_NextNode[node] = 0
        set udg_LeLi_NextNode[udg_LeLi_PrevNode[0]] = node
        set udg_LeLi_PrevNode[node] = udg_LeLi_PrevNode[0]
        set udg_LeLi_PrevNode[0] = node
       
        //Start timer if this is the only instance
        if (udg_LeLi_PrevNode[node] == 0) then
            call TimerStart(udg_LeLi_Timer, LeLi_TimerSpeed(), true, function LeLi_Loop)
        endif    

        //Set up date
        set udg_LeLi_Unit[node] = GetSpellTargetUnit()
        set udg_LeLi_Caster[node] = GetTriggerUnit()
        set level = GetUnitAbilityLevel(udg_LeLi_Caster[node], LeLi_Ability())
        set udg_LeLi_Duration[node] = LeLi_Duration(level)
        set udg_LeLi_DelayStart[node] = LeLi_Delay(level)
        set udg_LeLi_Delay[node] = udg_LeLi_DelayStart[node]
        set udg_LeLi_GrabbedTarget[node] = false
        set udg_LeLi_ManaRefund[node] = LeLi_ManaRefund(level)
        set tempreal = udg_LeLi_Duration[node] / udg_LeLi_Delay[node]
        call SetUnitPropWindow(udg_LeLi_Unit[node], 0)
        call SetUnitAnimation(udg_LeLi_Caster[node], LeLi_LoopAnimation())
       
        //Apply bonuses
        if GetUnitAbilityLevel(udg_LeLi_Caster[node], LeLi_BonusBuff()) > 0 then
            set udg_LeLi_HealthDamage[node] = (LeLi_HealthDamage(level) + LeLi_BonusHealthDamage(level)) / tempreal
            set udg_LeLi_ManaDamage[node] = (LeLi_ManaDamage(level) + LeLi_BonusManaDamage(level)) / tempreal
        else
            set udg_LeLi_HealthDamage[node] = LeLi_HealthDamage(level) / tempreal
            set udg_LeLi_ManaDamage[node] = LeLi_ManaDamage(level) / tempreal
        endif
       
        if GetUnitAbilityLevel(udg_LeLi_Unit[node], LeLi_BleedBuff()) > 0 then
            set udg_LeLi_HealthHeal[node] = (LeLi_HealthHeal(level) + LeLi_BonusHealthHeal(level)) / tempreal
            set udg_LeLi_ManaHeal[node] = (LeLi_ManaHeal(level) + LeLi_BonusManaHeal(level)) / tempreal
        else
            set udg_LeLi_HealthHeal[node] = LeLi_HealthHeal(level) / tempreal
            set udg_LeLi_ManaHeal[node] = LeLi_ManaHeal(level) / tempreal
        endif
       
    endif
   
    return false
endfunction

///////////////////////////////////////////////////////////////////
//  Function used to initialise the event listeners of the spell //
///////////////////////////////////////////////////////////////////
function InitTrig_Leech_Life takes nothing returns nothing
    local trigger t = CreateTrigger()
   
    //Set up trigger
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function LeLi_Cast))
   
    //Create stunning unit
    set udg_LeLi_Stunner = CreateUnit(LeLi_DummyPlayer(), LeLi_DummyUnit(), 0., 0., 0.)
    call UnitAddAbility(udg_LeLi_Stunner, LeLi_DummyStunAbility())
    call UnitRemoveAbility(udg_LeLi_Stunner, 'Amov')
endfunction
///////////////////////////////////////////////////////////////////
//  END OF THE SPELL                                             //
///////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//                     CORPSE CRUSHER V1.01                       //
//  Author: Tank-Commander                                        //
//  Requires: Dummy.mdl                                           //
//  Purpose: Sustain ability to convert corpses into health &     //
//           mana, can also be used to slow units in an AOE       //
//                                                                //
//  Credits: Vexorian (dummy.mdl)                                 //
//                                                                //
//  Notes:                                                        //
//    -  Read the readme before you try modifying the config      //
//    -  Use the "Helpful files" to help you import the system    //
//                                                                //
//                                                                //
//  If you have used this spell in your map, you are required     //
//  to give credits to Tank-Commander for the creation of it      //
//  If you would like to use snippets of code from this for       //
//  whatever, getting permission and crediting the source/linking //
//  would be much appreciated.                                    //
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  README:                                                       //
//    Before modifying this spell a few things need to be         //
//    understood and read, this is one of those things, while     //
//    most modification can be considered intuitive, it still     //
//    helps to read through these intstructions, as they will     //
//    inform you about how to configure this spell to your        //
//    desire.                                                     //
//----------------------------------------------------------------//
//  Initial importing: The variable creator trigger can be        //
//  imported first and if you have the correct settings (file,    //
//  preferences, General, automatically create unknown variables  //
//  checked, then when you paste in the variable creator it       //
//  will automatically give you all the variables you need for    //
//  this spell                                                    //
//                                                                //
//  While the remaining object editor based data is not required  //
//  to function (provided they're replaced with equivelents)      //
//  it's recommended that they are also imported, if their data   //
//  value are not the same as listed in the configuration, those  //
//  configurables will need to be changed to work correctly       //
//----------------------------------------------------------------//
//  TimerSpeed: This is the rate at which the loop timer of the   //
//  ability runs the default value 0.03125 allows the loop        //
//  function to run 32 times per second giving a smooth ability   //
constant function CoCr_TimerSpeed takes nothing returns real
    return 0.031250000
endfunction
//----------------------------------------------------------------//
//  CheckTimerRate: This is the time in seconds between each      //
//  check for units that have been added to the map with the      //
//  ability (use if units are trained or spawned throughout the   //
//  map)                                                          //
constant function CoCr_CheckTimerRate takes nothing returns real
    return 0.5
endfunction
//----------------------------------------------------------------//
//  CheckTimerPeriodic: Set to true if units that have the        //
//  ability aren't preplaced in the map but also don't learn      //
//  the ability like heroes (trained units for example)           //
constant function CoCr_CheckTimerPeriodic takes nothing returns boolean
    return false
endfunction
//----------------------------------------------------------------//
//  AuraDelay: This is the time in seconds between slowing new    //
//  units and removing it from ones whom have left the AOE        //
constant function CoCr_AuraDelay takes nothing returns real
    return 0.25
endfunction
//----------------------------------------------------------------//
//  Ability: This is the raw code for the ability used as a base  //
//  to see raw data press ctrl + d in the object editor, do it    //
//  again to revert to normal                                     //
constant function CoCr_Ability takes nothing returns integer
    return 'A004'
endfunction
//----------------------------------------------------------------//
//  SlowAbility: This is the raw code for the ability used to     //
//  slow units in the blood pool, should be based off slow aura   //
constant function CoCr_SlowAbility takes nothing returns integer
    return 'A007'
endfunction
//----------------------------------------------------------------//
//  BonusBuff: This is the raw code for the ability used to       //
//  Apply speed bonuses to the ability (it can be either a        //
//  regular ability or a specific buff which the caster can be    //
//  afflicted with to give optionally temporary or permanent      //
//  buffs to this ability                                         //
constant function CoCr_BonusBuff takes nothing returns integer
    return 'A005'
endfunction
//----------------------------------------------------------------//
//  BleedBuff: This is the raw code of the ability used to        //
//  restore mana to the caster if the target has this buff        //
constant function CoCr_BleedBuff takes nothing returns integer
    return 'A001'
endfunction
//----------------------------------------------------------------//
//  DummyPlayer: This is the player who will own all dummy units  //
//  created by this spell, it should be a neutral player as to    //
//  not mess with scorescreens                                    //
constant function CoCr_DummyPlayer takes nothing returns player
    return Player(14)
endfunction
//----------------------------------------------------------------//
//  DummyUnit: This is the raw code for the unit used as a dummy  //
//  by the ability, it should use dummy.mdl as its model or some  //
//  other invisible model                                         //
constant function CoCr_DummyUnit takes nothing returns integer
    return 'u000'
endfunction
//----------------------------------------------------------------//
//  BloodEffect: This is the effect attached to the dummy once    //
//  it lands at the target point                                  //
constant function CoCr_BloodEffect takes nothing returns string
    return "Abilities\\Spells\\Other\\HowlOfTerror\\HowlCaster.mdl"
endfunction
//----------------------------------------------------------------//
//  AttachmentPointBlood: This is the location on the dummy model //
//  that the blood effect is placed onto                          //
constant function CoCr_AttachmentPointBlood takes nothing returns string
    return "origin"
endfunction
//----------------------------------------------------------------//
//  BloodMiniEffect: This is the effect used to create the pool   //
//  of blood marking the AOE of the ability                       //
constant function CoCr_BloodMiniEffect takes nothing returns string
    return "Abilities\\Weapons\\SludgeMissile\\SludgeMissile.mdl"
endfunction
//----------------------------------------------------------------//
//  AttachmentPointMini: This is the location on the dummy model  //
//  that the mini blood effect is placed onto                     //
constant function CoCr_AttachmentPointMini takes nothing returns string
    return "origin"
endfunction
//----------------------------------------------------------------//
//  BleedHealEffect: This is the effect created when the ability  //
//  hits a target affected by BleedBuff                           //
constant function CoCr_BleedHealEffect takes nothing returns string
    return "Abilities\\Spells\\Items\\AIma\\AImaTarget.mdl"
endfunction
//----------------------------------------------------------------//
//  AttachmentPointBleedHeal: This is the location on the dummy   //
//  model that the healing effect is placed onto                  //
constant function CoCr_AttachmentPointBleedHeal takes nothing returns string
    return "origin"
endfunction
//----------------------------------------------------------------//
//  CorpseCrushEffect: This is the effect created when a corpse   //
//  is consumed by the caster                                     //
constant function CoCr_CorpseCrushEffect takes nothing returns string
    return "Objects\\Spawnmodels\\Orc\\OrcLargeDeathExplode\\OrcLargeDeathExplode.mdl"
endfunction
//----------------------------------------------------------------//
//  CorpseHealEffectL This is the effect created on the caster    //
//  when they consume a corpse                                    //
constant function CoCr_CorpseHealEffect takes nothing returns string
    return "Objects\\Spawnmodels\\Orc\\OrcSmallDeathExplode\\OrcSmallDeathExplode.mdl"
endfunction
//----------------------------------------------------------------//
//  AttachmentPointCorpseHeal: This is the location on the dummy  //
//  model that the crushing effect is placed onto                 //
constant function CoCr_AttachmentPointCorpseHeal takes nothing returns string
    return "origin"
endfunction
//----------------------------------------------------------------//
//  CorpseLaunchEffect: This is the model used for the corpse     //
//  launched toward the target point of the ability from the      //
//  caster                                                        //
constant function CoCr_CorpseLaunchEffect takes nothing returns string
    return "Abilities\\Weapons\\MeatwagonMissile\\MeatwagonMissile.mdl"
endfunction
//----------------------------------------------------------------//
//  AttachmentPointLaunch: This is the location on the dummy      //
//  model that the crushing effect is placed onto                 //
constant function CoCr_AttachmentPointLaunch takes nothing returns string
    return "origin"
endfunction
//----------------------------------------------------------------//
//  SlowBloodScale: This is the size of the BloodEffect 1 = 100%  //
//  scale or default size                                         //
function CoCr_SlowBloodScale takes real level returns real
    return 1.5
endfunction
//----------------------------------------------------------------//
//  SlowCorpseScale: This is the size of the CorpseLaunchEffect   //
//  1 = 100% scale of default size                                //
function CoCr_SlowCorpseScale takes real level returns real
    return 2.
endfunction
//----------------------------------------------------------------//
//  SlowBloodMiniScale: This is the size of the BloodMiniEffect   //
//  1 = 100% scale of default size                                //
constant function CoCr_SlowBloodMiniScale takes nothing returns real
    return 1.5
endfunction
//----------------------------------------------------------------//
//  SlowBloodMiniSpace: This is the amount of space taken up      //
//  by each BloodMiniEffect - this allows for the models to make  //
//  a seemless pool and should be adjusted to match each model    //
//  try to use as few effects as possible                         //
constant function CoCr_SlowBloodMiniSpace takes nothing returns real
    return 75.
endfunction
//----------------------------------------------------------------//
//  SlowSpinSpeed: This is the degrees per second that each       //
//  BloodMiniEffect moves around in the circle around the centre  //
//  of the blood pool                                             //
constant function CoCr_SlowSpinSpeed takes nothing returns real
    return 73.3385978 * CoCr_TimerSpeed() * bj_DEGTORAD
endfunction
//----------------------------------------------------------------//
//  Gravity: This is the strength of gravity pulling the corpse   //
//  thrown back into the ground, higher values lead to a sharper  //
//  arc taken by the projectile                                   //
constant function CoCr_Gravity takes nothing returns real
    return -60. * CoCr_TimerSpeed()
endfunction
//----------------------------------------------------------------//
//  HeightLet: This is the fly height which is considered close   //
//  enough to the ground to count as grounded (this is because    //
//  fly heights when often set to 0 actually set to ~0.04 so      //
//  comparisons for current fly height below 0 will not work)     //
constant function CoCr_HeightLet takes nothing returns real
    return 5.
endfunction
//----------------------------------------------------------------//
//  StartHeight: This is the starting fly height of the corpse    //
constant function CoCr_StartHeight takes nothing returns real
    return 50.
endfunction
//----------------------------------------------------------------//
//  CorpseAOE: This is the distance from a corpse to the caster   //
//  for the caster to consume the corpse                          //
function CoCr_CorpseAOE takes real level returns real
    return 150.
endfunction
//----------------------------------------------------------------//
//  CorpseHealHealth: This is the health restored to the caster   //
//  by consuming a corpse                                         //
function CoCr_CorpseHealHealth takes real level returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  CorpseHealMana: This is the mana restored to the caster by    //
//  consuming a corpse                                            //
function CoCr_CorpseHealMana takes real level returns real
    return 30 + (10 * (level - 1))
endfunction
//----------------------------------------------------------------//
//  SlowAOE: This is the distance from the centre of the blood    //
//  pool that units within are affected by the slow of the pool   //
function CoCr_SlowAOE takes real level returns real
    return 250.
endfunction
//----------------------------------------------------------------//
//  SlowDuration: This is the duration that the slowing blood     //
//  pool lasts for in seconds                                     //
function CoCr_SlowDuration takes real level returns real
    return 4. + (1. * level)
endfunction
//----------------------------------------------------------------//
//  SlowHealthDamage: This is the damage dealt to units hit by    //
//  the launched corpse upon impact                               //
function CoCr_SlowHealthDamage takes real level returns real
    return 50.
endfunction
//----------------------------------------------------------------//
//  SlowManaDamage: This is the amount of mana lost by units hit  //
//  by the launched corpse upon impact                            //
function CoCr_SlowManaDamage takes real level returns real    
    return 0.
endfunction
//----------------------------------------------------------------//
//  SlowSpeed: This is the speed of the launched corpse in        //
//  distance per second                                           //
function CoCr_SlowSpeed takes real level returns real
    return 1400. * CoCr_TimerSpeed()
endfunction
//----------------------------------------------------------------//
//  SlowBonusSpeed: This is the bonus speed of the launched       //
//  corpse in distance per second when the casted is affected by  //
//  BonusBuff                                                     //
function CoCr_SlowBonusSpeed takes real level returns real
    return 800. * CoCr_TimerSpeed()
endfunction
//----------------------------------------------------------------//
//  BleedHealHealth: This is the amount of health restored to     //
//  the caster if a target hit by the launched corpse is affected //
//  by BleedBuff                                                  //
function CoCr_BleedHealHealth takes real level returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  BleedHealMana: This is the amount of mana restored to the     //
//  caster if a target hit by the launched corpse is affected     //
//  by BleedBuff                                                  //
function CoCr_BleedHealMana takes real level returns real
    return 25.
endfunction
//----------------------------------------------------------------//
//  AttackType: This is the attack type used by the spell         //
constant function CoCr_AttackType takes nothing returns attacktype
    return ATTACK_TYPE_NORMAL
endfunction
//----------------------------------------------------------------//
//  DamageType: This is the damagetype used by the spell, armour  //
//  reduces the damage based on this type                         //
constant function CoCr_DamageType takes nothing returns damagetype
    return DAMAGE_TYPE_NORMAL
endfunction
//----------------------------------------------------------------//
//  WeaponType: This is the weapon type used by the spell         //
constant function CoCr_WeaponType takes nothing returns weapontype
    return null
endfunction
//----------------------------------------------------------------//
//                         READ ONLY                              //
//----------------------------------------------------------------//
//  CasterStageID: StageID used by casters in the spell           //
constant function CoCr_CasterStageID takes nothing returns integer
    return 1
endfunction
//----------------------------------------------------------------//
//  CorpseStageID: StageID used by launched corpses in the spell  //
constant function CoCr_CorpseStageID takes nothing returns integer
    return 2
endfunction
//----------------------------------------------------------------//
//  BloodPoolStageID: StageID used by the central dummy in the    //
//  blood pool                                                    //
constant function CoCr_BloodPoolStageID takes nothing returns integer
    return 3
endfunction
//----------------------------------------------------------------//
//  BloodPoolMiniStageID: StageID used by the spinning effects    //
//  within the AOE of the blood pool                              //
constant function CoCr_BloodPoolMiniStageID takes nothing returns integer
    return 4
endfunction
//----------------------------------------------------------------//
//  2PI: stores the value of 2 * PI in order to keep processing   //
//  fast                                                          //
constant function CoCr_2PI takes nothing returns real
    return 2 * bj_PI
endfunction
//----------------------------------------------------------------//
//                      END OF CONFIGURATION                      //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  Function used to distinguish what counts as a valid target    //
//  for the slowing caused by the pool of blood                   //
////////////////////////////////////////////////////////////////////
function CoCr_DamageFilter takes unit u, player pl returns boolean
    return IsUnitEnemy(u, pl) and not(IsUnitType(u, UNIT_TYPE_STRUCTURE) or IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) or IsUnitType(u, UNIT_TYPE_DEAD) or IsUnitType(u, UNIT_TYPE_FLYING) or GetUnitTypeId(u) == 0)
endfunction

////////////////////////////////////////////////////////////////////
//  This function is used to distinguish what counts as a corpse  //
//  to the ability (this stops heroes/structures and locusts      //
//  being counted as a valid corpse)                              //
////////////////////////////////////////////////////////////////////
function CoCr_CorpseFilter takes unit u returns boolean
    return IsUnitType(u, UNIT_TYPE_DEAD) and not(IsUnitType(u, UNIT_TYPE_HERO)) and not(IsUnitType(u, UNIT_TYPE_STRUCTURE)) and GetUnitAbilityLevel(u,'Aloc') == 0 and not(IsUnitType(u, UNIT_TYPE_SUMMONED)) and not(IsUnitType(u, UNIT_TYPE_MECHANICAL))
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to update level data of a particular node       //
////////////////////////////////////////////////////////////////////
function CoCr_SetLevelData takes unit u, real level, integer node returns nothing
    //Set up all the level data
    set udg_CoCr_Unit[node] = u
    set udg_CoCr_CorpseAOE[node] = CoCr_CorpseAOE(level)
    set udg_CoCr_CorpseHealHealth[node] = CoCr_CorpseHealHealth(level)
    set udg_CoCr_CorpseHealMana[node] = CoCr_CorpseHealMana(level)
    set udg_CoCr_SlowAOE[node] = CoCr_SlowAOE(level)
    set udg_CoCr_SlowBloodScale[node] = CoCr_SlowBloodScale(level)
    set udg_CoCr_SlowCorpseScale[node] = CoCr_SlowCorpseScale(level)
    set udg_CoCr_SlowDuration[node] = CoCr_SlowDuration(level)
    set udg_CoCr_SlowHealthDamage[node] = CoCr_SlowHealthDamage(level)
    set udg_CoCr_SlowManaDamage[node] = CoCr_SlowManaDamage(level)
    set udg_CoCr_SlowSpeed[node] = CoCr_SlowSpeed(level)
    set udg_CoCr_SlowBonusSpeed[node] = CoCr_SlowBonusSpeed(level)
    set udg_CoCr_BleedHealHealth[node] = CoCr_BleedHealHealth(level)
    set udg_CoCr_BleedHealMana[node] = CoCr_BleedHealMana(level)
    set udg_CoCr_Level[node] = R2I(level)
    set udg_CoCr_StageID[node] = CoCr_CasterStageID()
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to get the Z height of various locations        //
////////////////////////////////////////////////////////////////////
function CoCr_GetZ takes real x, real y returns real

    call MoveLocation(udg_CoCr_ZLoc, x, y)
    return GetLocationZ(udg_CoCr_ZLoc)
   
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to remove nodes from the linked list            //
////////////////////////////////////////////////////////////////////
function CoCr_RecycleNode takes integer node returns nothing
    //Recycle
    set udg_CoCr_RecycleNodes[udg_CoCr_RecyclableNodes] = node
    set udg_CoCr_RecyclableNodes = udg_CoCr_RecyclableNodes + 1
    set udg_CoCr_NextNode[udg_CoCr_PrevNode[node]] = udg_CoCr_NextNode[node]
    set udg_CoCr_PrevNode[udg_CoCr_NextNode[node]] = udg_CoCr_PrevNode[node]
   
    //Pause timer if this was the last instance
    if (udg_CoCr_PrevNode[0] == 0) then
        call PauseTimer(udg_CoCr_Timer)
    endif
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to add Nodes to the linked list                 //
////////////////////////////////////////////////////////////////////
function CoCr_CreateNode takes nothing returns integer
    local integer node
    //Set up Node
    if (udg_CoCr_RecyclableNodes == 0) then
        set udg_CoCr_NodeNumber = udg_CoCr_NodeNumber + 1
        set node = udg_CoCr_NodeNumber
    else
        set udg_CoCr_RecyclableNodes = udg_CoCr_RecyclableNodes - 1
        set node = udg_CoCr_RecycleNodes[udg_CoCr_RecyclableNodes]
    endif

    set udg_CoCr_NextNode[node] = 0
    set udg_CoCr_NextNode[udg_CoCr_PrevNode[0]] = node
    set udg_CoCr_PrevNode[node] = udg_CoCr_PrevNode[0]
    set udg_CoCr_PrevNode[0] = node
   
    return node
endfunction
////////////////////////////////////////////////////////////////////
//  Function used to remove the aura from units that are no       //
//  longer being affected by a blood pool                         //
////////////////////////////////////////////////////////////////////
function CoCr_AuraRemove takes nothing returns nothing
    local unit u = GetEnumUnit()
   
    if not(IsUnitInGroup(u, udg_CoCr_TempGroup2)) then
        call UnitRemoveAbility(u, CoCr_SlowAbility())
        call GroupRemoveUnit(udg_CoCr_SlowedGroup, u)
    endif
   
    set u = null
endfunction

////////////////////////////////////////////////////////////////////
//  Main function used to handle all of the various aspects of    //
//  the ability from consuming corpses to moving the projectile   //
//  and managing units that are being affected by the blood pool  //
////////////////////////////////////////////////////////////////////
function CoCr_Loop takes nothing returns nothing
    local integer node = 0
    local integer tempNode
    local real dist
    local real angle
    local real angle2
    local real anglelet
    local real circ
    local unit u
    local real x
    local real y
    local boolean b
   
    loop
        set node = udg_CoCr_NextNode[node]
        exitwhen node == 0
       
        if udg_CoCr_StageID[node] == CoCr_CasterStageID() then
            if not(GetUnitTypeId(udg_CoCr_Unit[node]) == null) then
               
                //Make sure the unit is alive and hasn't used a tome of retraining
                if not(IsUnitType(udg_CoCr_Unit[node], UNIT_TYPE_DEAD)) and GetUnitAbilityLevel(udg_CoCr_Unit[node], CoCr_Ability()) > 0 then
                    //Find corpses
                    call GroupEnumUnitsInRange(udg_CoCr_TempGroup, GetUnitX(udg_CoCr_Unit[node]), GetUnitY(udg_CoCr_Unit[node]), udg_CoCr_CorpseAOE[node], null)
               
                    loop
                        set u = FirstOfGroup(udg_CoCr_TempGroup)
                        exitwhen u == null
                        call GroupRemoveUnit(udg_CoCr_TempGroup, u)
                        if CoCr_CorpseFilter(u) then
                            //Splatter corpse and heal the caster
                            call DestroyEffect(AddSpecialEffect(CoCr_CorpseCrushEffect(), GetUnitX(u), GetUnitY(u)))
                            call SetWidgetLife(udg_CoCr_Unit[node], GetWidgetLife(udg_CoCr_Unit[node]) + udg_CoCr_CorpseHealHealth[node])
                            call SetUnitState(udg_CoCr_Unit[node], UNIT_STATE_MANA, GetUnitState(udg_CoCr_Unit[node], UNIT_STATE_MANA) + udg_CoCr_CorpseHealMana[node])
                            call DestroyEffect(AddSpecialEffectTarget(CoCr_CorpseHealEffect(), udg_CoCr_Unit[node], CoCr_AttachmentPointCorpseHeal()))
                            call RemoveUnit(u)
                        endif
                       
                    endloop
                   
                elseif GetUnitAbilityLevel(udg_CoCr_Unit[node], CoCr_Ability()) == 0 then
                    call CoCr_RecycleNode(node)
                endif
               
            else
                call CoCr_RecycleNode(node)
            endif
           
        elseif udg_CoCr_StageID[node] == CoCr_CorpseStageID() then
            set x = GetUnitX(udg_CoCr_Unit[node]) + udg_CoCr_XVel[node]
            set y = GetUnitY(udg_CoCr_Unit[node]) + udg_CoCr_YVel[node]
           
            //Keep the unit inside the map bounds
            if ((udg_CoCr_MapMinX <= x) and (x <= udg_CoCr_MapMaxX) and (udg_CoCr_MapMinY <= y)and (y <= udg_CoCr_MapMaxY)) then
                call SetUnitX(udg_CoCr_Unit[node], x)
                call SetUnitY(udg_CoCr_Unit[node], y)
            endif
           
            //Change fly height
            set udg_CoCr_CurrentHeight[node] = udg_CoCr_CurrentHeight[node] + udg_CoCr_ZVel[node]
            set udg_CoCr_ZVel[node] = udg_CoCr_ZVel[node] + CoCr_Gravity()
            call SetUnitFlyHeight(udg_CoCr_Unit[node], udg_CoCr_CurrentHeight[node] - CoCr_GetZ(x, y), 0.)
           
            //Check for impact
            if GetUnitFlyHeight(udg_CoCr_Unit[node]) <= CoCr_HeightLet() then
                set udg_CoCr_X[node] = x
                set udg_CoCr_Y[node] = y
                set udg_CoCr_ZVel[node] = GetUnitFacing(udg_CoCr_Unit[node]) * bj_RADTODEG
                set udg_CoCr_StageID[node] = CoCr_BloodPoolStageID()
                call DestroyEffect(udg_CoCr_Effect[node])
                set udg_CoCr_Effect[node] = AddSpecialEffectTarget(CoCr_BloodEffect(), udg_CoCr_Unit[node], CoCr_AttachmentPointBlood())
                call SetUnitScale(udg_CoCr_Unit[node], udg_CoCr_SlowBloodScale[node], 0., 0.)
               
                //Damage
                set b = false
                call GroupEnumUnitsInRange(udg_CoCr_TempGroup, x, y, udg_CoCr_SlowAOE[node], null)
               
                loop
                    set u = FirstOfGroup(udg_CoCr_TempGroup)
                    exitwhen u == null
                    call GroupRemoveUnit(udg_CoCr_TempGroup, u)
                   
                    if CoCr_DamageFilter(u, udg_CoCr_Player[node]) then
                        call UnitDamageTarget(udg_CoCr_Caster[node], u, udg_CoCr_SlowHealthDamage[node], true, true, CoCr_AttackType(), CoCr_DamageType(), CoCr_WeaponType())
                        call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - udg_CoCr_SlowManaDamage[node])
                   
                        //Heal Bonuses
                        if not(b) and GetUnitAbilityLevel(u, CoCr_BleedBuff()) > 0 then
                            set b = true
                            call SetWidgetLife(udg_CoCr_Caster[node], GetWidgetLife(udg_CoCr_Caster[node]) + udg_CoCr_BleedHealHealth[node])
                            call SetUnitState(udg_CoCr_Caster[node], UNIT_STATE_MANA, GetUnitState(udg_CoCr_Caster[node], UNIT_STATE_MANA) + udg_CoCr_BleedHealMana[node])
                            call DestroyEffect(AddSpecialEffectTarget(CoCr_BleedHealEffect(), udg_CoCr_Caster[node], CoCr_AttachmentPointBleedHeal()))
                        endif
                       
                    endif
                   
                endloop
               
                //Creating the aura effect
                set dist = CoCr_SlowBloodMiniSpace()
                set b = false
               
                loop
                    exitwhen dist > udg_CoCr_SlowAOE[node]
                   
                    set angle2 = CoCr_2PI() / ((CoCr_2PI() * dist) / CoCr_SlowBloodMiniSpace())
                    set angle = angle2
                    set anglelet = CoCr_2PI() + (angle2 / 2)
                    set b = not(b)
                   
                    loop
                        exitwhen angle > anglelet
                       
                        //Create new aura segment and apply effects
                        set x = udg_CoCr_X[node] + dist * Cos(angle)
                        set y = udg_CoCr_Y[node] + dist * Sin(angle)
                        set tempNode = CoCr_CreateNode()
                        set udg_CoCr_Unit[tempNode] = CreateUnit(CoCr_DummyPlayer(), CoCr_DummyUnit(), x, y, angle * bj_RADTODEG + 90)
                        set udg_CoCr_Effect[tempNode] = AddSpecialEffectTarget(CoCr_BloodMiniEffect(), udg_CoCr_Unit[tempNode], CoCr_AttachmentPointMini())
                        call SetUnitScale(udg_CoCr_Unit[tempNode], CoCr_SlowBloodMiniScale(), 0., 0.)
                        call SetUnitFlyHeight(udg_CoCr_Unit[tempNode], 0., 0.)
                        set udg_CoCr_Direction[tempNode] = b
                        set udg_CoCr_HomeNode[tempNode] = node
                        set udg_CoCr_X[tempNode] = dist
                        set udg_CoCr_ZVel[tempNode] = angle
                        set udg_CoCr_StageID[tempNode] = CoCr_BloodPoolMiniStageID()
                       
                        set angle = angle + angle2
                    endloop
                   
                    set dist = dist + CoCr_SlowBloodMiniSpace()
                endloop
               
            endif
           
        elseif udg_CoCr_StageID[node] == CoCr_BloodPoolMiniStageID() then
           
            //Check if the aura is still active
            if IsUnitType(udg_CoCr_Unit[udg_CoCr_HomeNode[node]], UNIT_TYPE_DEAD) or GetUnitTypeId(udg_CoCr_Unit[udg_CoCr_HomeNode[node]]) == 0 then
                call DestroyEffect(udg_CoCr_Effect[node])
                call SetWidgetLife(udg_CoCr_Unit[node], 0.)
                call CoCr_RecycleNode(node)
            else
           
                //Update aura positions
                if udg_CoCr_Direction[node] then
                    set angle = udg_CoCr_ZVel[node] + udg_CoCr_ZVel[udg_CoCr_HomeNode[node]]
                else
                    set angle = udg_CoCr_ZVel[node] - udg_CoCr_ZVel[udg_CoCr_HomeNode[node]]
                endif
           
                call SetUnitX(udg_CoCr_Unit[node], udg_CoCr_X[udg_CoCr_HomeNode[node]] + udg_CoCr_X[node] * Cos(angle))
                call SetUnitY(udg_CoCr_Unit[node], udg_CoCr_Y[udg_CoCr_HomeNode[node]] + udg_CoCr_X[node] * Sin(angle))
                call SetUnitFacing(udg_CoCr_Unit[node], angle * bj_RADTODEG + 90)
            endif
           
        elseif udg_CoCr_SlowDuration[node] > 0 then
            set udg_CoCr_SlowDuration[node] = udg_CoCr_SlowDuration[node] - CoCr_TimerSpeed()
            set udg_CoCr_ZVel[node] = udg_CoCr_ZVel[node] + CoCr_SlowSpinSpeed()
            //Slow units
            call GroupEnumUnitsInRange(udg_CoCr_TempGroup, udg_CoCr_X[node], udg_CoCr_Y[node], udg_CoCr_SlowAOE[node], null)
           
            loop
                set u = FirstOfGroup(udg_CoCr_TempGroup)
                exitwhen u == null                
                call GroupRemoveUnit(udg_CoCr_TempGroup, u)

                if CoCr_DamageFilter(u, udg_CoCr_Player[node]) then
                    call GroupAddUnit(udg_CoCr_TempGroup2, u)
               
                    if not(IsUnitInGroup(u, udg_CoCr_SlowedGroup)) then
                        call GroupAddUnit(udg_CoCr_SlowedGroup, u)
                    endif
               
                    call UnitAddAbility(u, CoCr_SlowAbility())
                    call SetUnitAbilityLevel(u, CoCr_SlowAbility(), udg_CoCr_Level[node])                
                endif
               
            endloop
           
        else
            //Remove dummy
            call DestroyEffect(udg_CoCr_Effect[node])
            call SetWidgetLife(udg_CoCr_Unit[node], 0.)
            call CoCr_RecycleNode(node)
        endif
       
    endloop
   
    //Clean up slowed units
    if udg_CoCr_AuraDelay < 0 then
        set udg_CoCr_AuraDelay = CoCr_AuraDelay()
        call ForGroup(udg_CoCr_SlowedGroup, function CoCr_AuraRemove)
        call GroupClear(udg_CoCr_TempGroup2)
    else
        set udg_CoCr_AuraDelay = udg_CoCr_AuraDelay - CoCr_TimerSpeed()
    endif
   
endfunction

////////////////////////////////////////////////////////////////////
//  This function is used to find the node of units registered    //
//  in the system, it creates a node for the unit if no node      //
//  can be found for it                                           //
////////////////////////////////////////////////////////////////////
function CoCr_GetUnitNode takes unit u returns integer
    local integer node = 0
   
    loop
        set node = udg_CoCr_NextNode[node]
        exitwhen node == 0
       
        if udg_CoCr_Unit[node] == u then
            return node
        endif
       
    endloop
   
    set node = CoCr_CreateNode()
   
    //Start timer if this is the only instance
    if (udg_CoCr_PrevNode[node] == 0) then
        call TimerStart(udg_CoCr_Timer, CoCr_TimerSpeed(), true, function CoCr_Loop)
    endif
   
    return node
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to create spell data used by the corpse in      //
//  transit and the slow aura area upon landing                   //
////////////////////////////////////////////////////////////////////
function CoCr_Cast takes nothing returns boolean
    local integer node
    local integer tempNode
    local real speed
    local real angle
    local real x
    local real y
    local real x2
    local real y2
    local real dx
    local real dy
   
    if (GetSpellAbilityId() == CoCr_Ability()) then
        set node = CoCr_CreateNode()
        set tempNode = CoCr_GetUnitNode(GetTriggerUnit())
       
        //Set up data
        set udg_CoCr_StageID[node] = CoCr_CorpseStageID()
        set udg_CoCr_Caster[node] = udg_CoCr_Unit[tempNode]
       
        set x = GetUnitX(udg_CoCr_Unit[tempNode])
        set y = GetUnitY(udg_CoCr_Unit[tempNode])
        set x2 = GetSpellTargetX()
        set y2 = GetSpellTargetY()
        set dx = x2 - x
        set dy = y2 - y
        set angle = Atan2(dy, dx)
       
        //Create unit and apply effects
        set udg_CoCr_Unit[node] = CreateUnit(CoCr_DummyPlayer(), CoCr_DummyUnit(), x, y, angle * bj_RADTODEG)
        set udg_CoCr_Player[node] = GetOwningPlayer(udg_CoCr_Unit[tempNode])
        call PauseUnit(udg_CoCr_Unit[node], true)
        if UnitAddAbility(udg_CoCr_Unit[node], 'Amrf') and UnitRemoveAbility(udg_CoCr_Unit[node], 'Amrf') then
        endif
        set udg_CoCr_Effect[node] = AddSpecialEffectTarget(CoCr_CorpseLaunchEffect(), udg_CoCr_Unit[node], CoCr_AttachmentPointLaunch())
        call SetUnitScale(udg_CoCr_Unit[node], udg_CoCr_SlowCorpseScale[tempNode], 0., 0.)
       
        if GetUnitAbilityLevel(udg_CoCr_Caster[node], CoCr_BonusBuff()) > 0 then
            set speed = udg_CoCr_SlowSpeed[tempNode] + udg_CoCr_SlowBonusSpeed[tempNode]
        else
            set speed = udg_CoCr_SlowSpeed[tempNode]
        endif
       
        set udg_CoCr_SlowAOE[node] = udg_CoCr_SlowAOE[tempNode]
        set udg_CoCr_XVel[node] = speed * Cos(angle)
        set udg_CoCr_YVel[node] = speed * Sin(angle)
        set speed = SquareRoot(dx * dx + dy * dy) / speed
        set udg_CoCr_CurrentHeight[node] = CoCr_GetZ(x,y) + CoCr_StartHeight()
        set udg_CoCr_ZVel[node] = ((CoCr_GetZ(x2, y2) - udg_CoCr_CurrentHeight[node]) - (CoCr_Gravity() * speed * speed) / 2)  / speed
        //Duplicate data to prevent level up mid-flight affecting the ability
        set udg_CoCr_SlowHealthDamage[node] = udg_CoCr_SlowHealthDamage[tempNode]
        set udg_CoCr_SlowManaDamage[node] = udg_CoCr_SlowManaDamage[tempNode]
        set udg_CoCr_SlowBloodScale[node] = udg_CoCr_SlowBloodScale[tempNode]
        set udg_CoCr_SlowDuration[node] = udg_CoCr_SlowDuration[tempNode]
        set udg_CoCr_BleedHealHealth[node] = udg_CoCr_BleedHealHealth[tempNode]
        set udg_CoCr_BleedHealMana[node] = udg_CoCr_BleedHealMana[tempNode]
        set udg_CoCr_Level[node] = udg_CoCr_Level[tempNode]
        call SetUnitFlyHeight(udg_CoCr_Unit[node], CoCr_StartHeight(), 0.)
    endif
   
    return false
endfunction

////////////////////////////////////////////////////////////////////
//  Function used when a hero learns an ability to update their   //
//  level data if they have a node (and create one for them if    //
//  they don't)                                                   //
////////////////////////////////////////////////////////////////////
function CoCr_Update takes nothing returns boolean
    local unit u
   
    if GetLearnedSkill() == CoCr_Ability() then
        set u = GetTriggerUnit()
        //Set up all data
        call CoCr_SetLevelData(u, GetLearnedSkillLevel(), CoCr_GetUnitNode(u))
        set u = null
    endif
   
    return false
endfunction


////////////////////////////////////////////////////////////////////
//  This function's primary purpose is to add all preplaced units //
//  with the aura on the map to the system, however it can also   //
//  be utilised for units which are added at runtime with the     //
//  aura so that they can function correctly despite not running  //
//  the other trigger (the same goes with trained units)          //
////////////////////////////////////////////////////////////////////
function CoCr_RegisterExisting takes nothing returns boolean
    //Sets up locals
    local unit u
    local real level
   
    //Adds all units on the map to a unit group
    call GroupEnumUnitsInRect(udg_CoCr_TempGroup, bj_mapInitialPlayableArea, null)
   
    //Scans through the unit group looking for units with the ability
    loop
        set u = FirstOfGroup(udg_CoCr_TempGroup)
        exitwhen u == null

        set level = GetUnitAbilityLevel(u, CoCr_Ability())
        //Checks that the selected unit has the ability
        if (level > 0) then
            //Attempts to add the unit
            call CoCr_SetLevelData(u, level, CoCr_GetUnitNode(u))
        endif
 
        call GroupRemoveUnit(udg_CoCr_TempGroup, u)
    endloop
   
    //Checks if this function will run constantly, if not then destroy the trigger
    if (not(CoCr_CheckTimerPeriodic())) then
        call DestroyTrigger(GetTriggeringTrigger())
    endif

    return false
endfunction

///////////////////////////////////////////////////////////////////
//  Function used to initialise the event listeners of the spell //
///////////////////////////////////////////////////////////////////
function InitTrig_Corpse_Crusher takes nothing returns nothing
    local trigger t = CreateTrigger()
   
    //Set up cast trigger
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function CoCr_Cast))
    //Set up learn trigger
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
    call TriggerAddCondition(t, Condition(function CoCr_Update))
    //Set up initial hero enabling trigger
    set t = CreateTrigger()
    //Sets up the event listener, if the function is periodic, then it will run constantly instead of just at the start
    call TriggerRegisterTimerEvent(t, CoCr_CheckTimerRate(), CoCr_CheckTimerPeriodic())
    call TriggerAddCondition(t, Condition(function CoCr_RegisterExisting))
   
    set udg_CoCr_ZLoc = Location(0., 0.)
    set udg_CoCr_MapMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
    set udg_CoCr_MapMinX = GetRectMinX(bj_mapInitialPlayableArea)
    set udg_CoCr_MapMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
    set udg_CoCr_MapMinY = GetRectMinY(bj_mapInitialPlayableArea)
endfunction
///////////////////////////////////////////////////////////////////
//  END OF THE SPELL                                             //
///////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//                       BLOOD BOIL V1.01                         //
//  Author: Tank-Commander                                        //
//  Purpose: Ultimate buff ability which enhances other spells    //
//                                                                //
//  Notes:                                                        //
//    -  Read the readme before you try modifying the config      //
//    -  Use the "Helpful files" to help you import the system    //
//                                                                //
//                                                                //
//  If you have used this spell in your map, you are required     //
//  to give credits to Tank-Commander for the creation of it      //
//  If you would like to use snippets of code from this for       //
//  whatever, getting permission and crediting the source/linking //
//  would be much appreciated.                                    //
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  README:                                                       //
//    Before modifying this spell a few things need to be         //
//    understood and read, this is one of those things, while     //
//    most modification can be considered intuitive, it still     //
//    helps to read through these intstructions, as they will     //
//    inform you about how to configure this spell to your        //
//    desire.                                                     //
//----------------------------------------------------------------//
//  Initial importing: The variable creator trigger can be        //
//  imported first and if you have the correct settings (file,    //
//  preferences, General, automatically create unknown variables  //
//  checked, then when you paste in the variable creator it       //
//  will automatically give you all the variables you need for    //
//  this spell                                                    //
//                                                                //
//  While the remaining object editor based data is not required  //
//  to function (provided they're replaced with equivelents)      //
//  it's recommended that they are also imported, if their data   //
//  value are not the same as listed in the configuration, those  //
//  configurables will need to be changed to work correctly       //
//----------------------------------------------------------------//
//  TimerSpeed: This is the rate at which the loop timer of the   //
//  ability runs the default value 0.03125 allows the loop        //
//  function to run 32 times per second giving a smooth ability   //
constant function BlBo_TimerSpeed takes nothing returns real
    return 0.03125000
endfunction
//----------------------------------------------------------------//
//  Ability: This is the raw code for the ability used as a base  //
//  to see raw data press ctrl + d in the object editor, do it    //
//  again to revert to normal                                     //
constant function BlBo_Ability takes nothing returns integer
    return 'A006'
endfunction
//----------------------------------------------------------------//
//  BuffAbility: This is the raw code for the ability used to     //
//  apply the blood boil buff to the caster, it should be based   //
//  off slow aura                                                 //
constant function BlBo_BuffAbility takes nothing returns integer
    return 'A005'
endfunction
//----------------------------------------------------------------//
//  Duration: This is how long in seconds the ability lasts for   //
function BlBo_Duration takes real level returns real
    return 60.
endfunction
//----------------------------------------------------------------//
//  DamageTick: This is how many seconds there are between each   //
//  set of damage, this should evenly divide into the duration    //
function BlBo_DamageTick takes real level returns real
    return 1.
endfunction
//----------------------------------------------------------------//
//  HealthDamage: This is the total amount of health damage the   //
//  caster takes over the duration of the spell, set this to a    //
//  negative value to make it heal the caster instead             //
function BlBo_HealthDamage takes real level returns real
    return 600.
endfunction
//----------------------------------------------------------------//
//  ManaDamage: This is the total amount of mana damage the       //
//  caster takes over the duration of the spell, set this to a    //
//  negative value to make it heal the caster instead             //
function BlBo_ManaDamage takes real level returns real    
    return -60.
endfunction
//----------------------------------------------------------------//
//  DamageEffect: This is the effect played on the caster when    //
//  they take damage or are healed by the ability                 //
constant function BlBo_DamageEffect takes nothing returns string
    return "Abilities\\Weapons\\HydraliskImpact\\HydraliskImpact.mdl"
endfunction
//----------------------------------------------------------------//
//  DamageAttachmentPoint: This is the location on the hero that  //
//  the DamageEffect is placed onto                               //
constant function BlBo_DamageAttachmentPoint takes nothing returns string
    return "chest"
endfunction
//----------------------------------------------------------------//
//  HueRed: This is how red the hero goes when they take damage   //
constant function BlBo_HueRed takes nothing returns integer
    return 255
endfunction
//----------------------------------------------------------------//
//  HueBlue: This is how blue the hero goes when they take damage
constant function BlBo_HueBlue takes nothing returns integer
    return 120
endfunction
//----------------------------------------------------------------//
//  HueGreen: This is how green the hero goes when they take      //
//  damage                                                        //
constant function BlBo_HueGreen takes nothing returns integer
    return 120
endfunction
//----------------------------------------------------------------//
//  HueRecoverSpeed: This is how quickly the heroes colour is     //
//  restored to normal (255/255/255) this runs at a rate of       //
//  the TimerSpeed, so by default tihs runs 32 times per second   //
//  (e.g. if HueBlue is set to 50 and this to 4  then after 1     //
//  second the blue hue will now be 178                           //
constant function BlBo_HueRecoverSpeed takes nothing returns integer
    return 4
endfunction
//----------------------------------------------------------------//
//  UseHue: Set this to true to make the hero use the hue         //
//  colours when castig the spell, don't use if the hero has a    //
//  default colouration other than 255/255/255                    //
constant function BlBo_UseHue takes nothing returns boolean
    return true
endfunction
//----------------------------------------------------------------//
//                      END OF CONFIGURATION                      //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////
//  Function used to check if a unit currently has any remaining //
//  blood boil buffs (this is relevent if the ability can be     //
//  casted multiple times by the same unit)                      //
///////////////////////////////////////////////////////////////////
function BlBo_IsNotBuffed takes unit u returns boolean
    local integer node = 0
   
    loop
        set node = udg_BlBo_NextNode[node]
        exitwhen node == 0
       
        if udg_BlBo_Unit[node] == u then
            return false
        endif
       
    endloop
   
    return true
endfunction

///////////////////////////////////////////////////////////////////
//  Function used to deal damage to units over time when they    //
//  have the buff, delays it to match standard ingame mechanics  //
///////////////////////////////////////////////////////////////////
function BlBo_Loop takes nothing returns nothing
    local integer node = 0
   
    loop
        set node = udg_BlBo_NextNode[node]
        exitwhen node == 0
       
        if udg_BlBo_Duration[node] >= 0 then
            set udg_BlBo_Duration[node] = udg_BlBo_Duration[node] - BlBo_TimerSpeed()
            set udg_BlBo_DamageTickCurrent[node] = udg_BlBo_DamageTickCurrent[node] - BlBo_TimerSpeed()
           
            if udg_BlBo_DamageTickCurrent[node] <= 0 then
                //Deal damage/heal
                set udg_BlBo_DamageTickCurrent[node] = udg_BlBo_DamageTick[node]
                call SetWidgetLife(udg_BlBo_Unit[node], GetWidgetLife(udg_BlBo_Unit[node]) - udg_BlBo_HealthDamage[node])
                call SetUnitState(udg_BlBo_Unit[node], UNIT_STATE_MANA, GetUnitState(udg_BlBo_Unit[node], UNIT_STATE_MANA) - udg_BlBo_ManaDamage[node])
                call DestroyEffect(AddSpecialEffectTarget(BlBo_DamageEffect(), udg_BlBo_Unit[node], BlBo_DamageAttachmentPoint()))
               
                //Reset Colours
                if BlBo_UseHue() then
                    set udg_BlBo_Red[node] = BlBo_HueRed()
                    set udg_BlBo_Blue[node] = BlBo_HueBlue()
                    set udg_BlBo_Green[node] = BlBo_HueGreen()
                endif
               
            //Apply Colour change
            elseif BlBo_UseHue() then
                set udg_BlBo_Red[node] = udg_BlBo_Red[node] + BlBo_HueRecoverSpeed()
                set udg_BlBo_Blue[node] = udg_BlBo_Blue[node] + BlBo_HueRecoverSpeed()
                set udg_BlBo_Green[node] = udg_BlBo_Green[node] + BlBo_HueRecoverSpeed()
            endif
           
            call SetUnitVertexColor(udg_BlBo_Unit[node], udg_BlBo_Red[node], udg_BlBo_Green[node], udg_BlBo_Blue[node], 255)
        else
       
            //Recycle
            set udg_BlBo_RecycleNodes[udg_BlBo_RecyclableNodes] = node
            set udg_BlBo_RecyclableNodes = udg_BlBo_RecyclableNodes + 1
            set udg_BlBo_NextNode[udg_BlBo_PrevNode[node]] = udg_BlBo_NextNode[node]
            set udg_BlBo_PrevNode[udg_BlBo_NextNode[node]] = udg_BlBo_PrevNode[node]

            if BlBo_IsNotBuffed(udg_BlBo_Unit[node]) then
                call UnitRemoveAbility(udg_BlBo_Unit[node], BlBo_BuffAbility())
               
                //Reset colours
                if BlBo_UseHue() then
                    call SetUnitVertexColor(udg_BlBo_Unit[node], 255, 255, 255, 255)
                endif
               
                //Pause timer if this was the last instance
                if (udg_BlBo_PrevNode[0] == 0) then
                    call PauseTimer(udg_BlBo_Timer)
                endif
               
            endif
        endif
       
    endloop
   
endfunction

///////////////////////////////////////////////////////////////////
//  Function used when the spell is cast to apply the buff and   //
//  set up unit data for the loop                                //
///////////////////////////////////////////////////////////////////
function BlBo_Cast takes nothing returns boolean
    local integer node
    local real level

    if (GetSpellAbilityId() == BlBo_Ability()) then
        //Set up Node
        if (udg_BlBo_RecyclableNodes == 0) then
            set udg_BlBo_NodeNumber = udg_BlBo_NodeNumber + 1
            set node = udg_BlBo_NodeNumber
        else
            set udg_BlBo_RecyclableNodes = udg_BlBo_RecyclableNodes - 1
            set node = udg_BlBo_RecycleNodes[udg_BlBo_RecyclableNodes]
        endif

        set udg_BlBo_NextNode[node] = 0
        set udg_BlBo_NextNode[udg_BlBo_PrevNode[0]] = node
        set udg_BlBo_PrevNode[node] = udg_BlBo_PrevNode[0]
        set udg_BlBo_PrevNode[0] = node
       
        //Start timer if this is the only instance
        if (udg_BlBo_PrevNode[node] == 0) then
            call TimerStart(udg_BlBo_Timer, BlBo_TimerSpeed(), true, function BlBo_Loop)
        endif
       
        //set up instance data
        set udg_BlBo_Unit[node] = GetTriggerUnit()
        set level = GetUnitAbilityLevel(udg_BlBo_Unit[node], BlBo_Ability())
        set udg_BlBo_Duration[node] = BlBo_Duration(level)
        set udg_BlBo_DamageTick[node] = BlBo_DamageTick(level)
        set udg_BlBo_DamageTickCurrent[node] = udg_BlBo_DamageTick[node]
        set udg_BlBo_HealthDamage[node] = BlBo_HealthDamage(level) / udg_BlBo_Duration[node]
        set udg_BlBo_ManaDamage[node] = BlBo_ManaDamage(level) / udg_BlBo_Duration[node]
        call UnitAddAbility(udg_BlBo_Unit[node], BlBo_BuffAbility())
        call SetUnitAbilityLevel(udg_BlBo_Unit[node], BlBo_BuffAbility(), R2I(level))
       
        if BlBo_UseHue() then
            set udg_BlBo_Red[node] = BlBo_HueRed()
            set udg_BlBo_Blue[node] = BlBo_HueBlue()
            set udg_BlBo_Green[node] = BlBo_HueGreen()
        endif
       
    endif
   
    return false
endfunction

///////////////////////////////////////////////////////////////////
//  Function used to initialise the event listeners of the spell //
///////////////////////////////////////////////////////////////////
function InitTrig_Blood_Boil takes nothing returns nothing
    local trigger t = CreateTrigger()

    //Set up trigger
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function BlBo_Cast))
endfunction
///////////////////////////////////////////////////////////////////
//  END OF THE SPELL                                             //
///////////////////////////////////////////////////////////////////
RuSt Variable Creator
  Events
  Conditions
  Actions
    Set RuSt_BleedDamageHealth[0] = 0.00
    Set RuSt_BleedDamageMana[0] = 0.00
    Set RuSt_BloodiedEffect[0] = RuSt_BloodiedEffect[0]
    Set RuSt_Caster[0] = RuSt_Caster[0]
    Set RuSt_DamageDelay[0] = 0.00
    Set RuSt_DamageDelayStart[0] = 0.00
    Set RuSt_Duration[0] = 0.00
    Set RuSt_NextNode[0] = 0
    Set RuSt_NodeNumber = 0
    Set RuSt_PrevNode[0] = 0
    Set RuSt_RecyclableNodes = 0
    Set RuSt_RecycleNodes[0] = 0
    Set RuSt_Timer = RuSt_Timer
    Set RuSt_Unit[0] = RuSt_Unit[0]
LeLi Variable Creator
  Events
  Conditions
  Actions
    Set LeLi_Caster[0] = No unit
    Set LeLi_Delay[0] = 0.00
    Set LeLi_DelayStart[0] = 0.00
    Set LeLi_Duration[0] = 0.00
    Set LeLi_GrabbedTarget[0] = False
    Set LeLi_HealthDamage[0] = 0.00
    Set LeLi_HealthHeal[0] = 0.00
    Set LeLi_ManaDamage[0] = 0.00
    Set LeLi_ManaHeal[0] = 0.00
    Set LeLi_ManaRefund[0] = 0.00
    Set LeLi_NextNode[0] = 0
    Set LeLi_NodeNumber = 0
    Set LeLi_PrevNode[0] = 0
    Set LeLi_RecyclableNodes = 0
    Set LeLi_RecycleNodes[0] = 0
    Set LeLi_Stunner = No unit
    Set LeLi_Timer = LeLi_Timer
    Set LeLi_Unit[0] = No unit
CoCr Variable Creator
  Events
  Conditions
  Actions
    Set CoCr_AuraDelay = 0.00
    Set CoCr_BleedHealHealth[0] = 0.00
    Set CoCr_BleedHealMana[0] = 0.00
    Set CoCr_Caster[0] = No unit
    Set CoCr_CorpseAOE[0] = 0.00
    Set CoCr_CorpseHealHealth[0] = 0.00
    Set CoCr_CorpseHealMana[0] = 0.00
    Set CoCr_CurrentHeight[0] = 0.00
    Set CoCr_Direction[0] = False
    Set CoCr_Effect[0] = CoCr_Effect[0]
    Set CoCr_HomeNode[0] = 0
    Set CoCr_Level[0] = 0
    Set CoCr_MapMaxX = 0.00
    Set CoCr_MapMaxY = 0.00
    Set CoCr_MapMinX = 0.00
    Set CoCr_MapMinY = 0.00
    Set CoCr_NextNode[0] = 0
    Set CoCr_NodeNumber = 0
    Set CoCr_Player[0] = CoCr_Player[0]
    Set CoCr_PrevNode[0] = 0
    Set CoCr_RecyclableNodes = 0
    Set CoCr_RecycleNodes[0] = 0
    Set CoCr_SlowAOE[0] = 0.00
    Set CoCr_SlowBloodScale[0] = 0.00
    Set CoCr_SlowBonusSpeed[0] = 0.00
    Set CoCr_SlowCorpseScale[0] = 0.00
    Set CoCr_SlowDuration[0] = 0.00
    Set CoCr_SlowHealthDamage[0] = 0.00
    Set CoCr_SlowManaDamage[0] = 0.00
    Set CoCr_SlowSpeed[0] = 0.00
    Set CoCr_SlowedGroup = CoCr_SlowedGroup
    Set CoCr_StageID[0] = 0
    Set CoCr_TempGroup = CoCr_TempGroup
    Set CoCr_TempGroup2 = CoCr_TempGroup2
    Set CoCr_Timer = CoCr_Timer
    Set CoCr_Unit[0] = No unit
    Set CoCr_X[0] = 0.00
    Set CoCr_XVel[0] = 0.00
    Set CoCr_Y[0] = 0.00
    Set CoCr_YVel[0] = 0.00
    Set CoCr_ZLoc = CoCr_ZLoc
    Set CoCr_ZVel[0] = 0.00
BlBo Variable Creator
  Events
  Conditions
  Actions
    Set BlBo_Blue[0] = 0
    Set BlBo_DamageTick[0] = 0.00
    Set BlBo_DamageTickCurrent[0] = 0.00
    Set BlBo_Duration[0] = 0.00
    Set BlBo_Green[0] = 0
    Set BlBo_HealthDamage[0] = 0.00
    Set BlBo_ManaDamage[0] = 0.00
    Set BlBo_NextNode[0] = 0
    Set BlBo_NodeNumber = 0
    Set BlBo_PrevNode[0] = 0
    Set BlBo_RecyclableNodes = 0
    Set BlBo_RecycleNodes[0] = 0
    Set BlBo_Red[0] = 0
    Set BlBo_Timer = BlBo_Timer
    Set BlBo_Unit[0] = BlBo_Unit[0]
Spawn heroes
  Events
    Player - Player 1 (Red) skips a cinematic sequence
  Conditions
  Actions
    Custom script: local integer level = 2
    Custom script: local unit u
    Custom script: call CreateUnit(Player(0), 'N000', 0., 0., 0.)
    Custom script: loop
    Custom script: exitwhen level > 10
    Custom script: set u = CreateUnit(Player(0), 'N000', 0., 0., 0.)
    Custom script: call SetHeroLevel(u, level, true)
    Custom script: set level = level + 1
    Custom script: endloop
    Custom script: set u = null
Test Notification
  Events
    Time - Elapsed game time is 1.00 seconds
  Conditions
  Actions
    Game - Display to (All players) the text: Press ESC as Player 1 to spawn Silithid Devourers (levels 1-10)