1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. The poll for our 11th Music Contest is up! Help us choose the most awesome cinematic tracks by casting a vote!
    Dismiss Notice
  3. Melee Mapping contest #3 - Poll is up! Vote for the best 4v4 melee maps!
    Dismiss Notice
  4. The 30th edition of the Modeling Contest is finally up! The Portable Buildings need your attention, so come along and have a blast!
    Dismiss Notice
  5. The Aftermath has been revealed for the 19th Terraining Contest! Be sure to check out the Results and see what came out of it.
    Dismiss Notice

Silithid Devourer Spellset V1.01

Submitted by Tank-Commander
This bundle is marked as approved. It works and satisfies the submission rules.
HC8 - Team Special Ops Entry
Artist: A.R.
Coder: Tank-Commander
Hero
[​IMG] Proper Names: Ferl'piej the Deranged, Kikidrill the Hematophagous, Amorg'tik, Tremal the Sanguine, Qilarid, Mutrali, Vourg the Ruthless

Silithid Devourer
Warrior Hero, exceptional at disruptive spells and duelling other heroes. Can learn Rupturing Stab, Leech Life, Corpse Crusher, and Blood Boil.

Attacks land units.

Role: Disruptive Tank Theme: Bloody Silithid, violent & durable
Playstyle
Boasting high agility and strength the Silithid Devourer has a strong ability to duel with access to powerful single target damage and stun abilities as well as the ability to regenerate health and mana quickly. The cost of these high stats is a low max mana leading to a need to manage it carefully and difficulty in prolonged fights - The Devourer relies on consuming corpses of allies or enemies to regenerate its mana and keep up its onslaught.

There are three distinct ways on how to play the Silithid Devourer based on what abiliies you pick:
Sustained Offensive: Max Q then E; pick up W only if you want the utility, needs healing support hero (e.g. Shadow Hunter)
Full Tank: Max W then E, pick up Q early on for damage and buff to W heal, low damage output
All-Out Offensive: Max Q then W; do not pick up E, needs mana regen hero (e.g. archmage, bloodmage)

Early Game: When first summoning the hero you will have the choice between single target damage (Q), single target drain & stun (W), or mana regen with a weak AOE damage/slow (E). Generally speaking your Q is the best option with W being a good option against opponents likely to use a melee hero to harass you as you can stun them and get some free hits with other units (possibly even bodyblock/force tp) at level 2 E will become necessary (use it to consume all the corpses of your creep camp to get the mana you spent back. When starting W do not use it when there is more than one enemy left in a creep camp the manacost is high (half your mana at level 1) and takes 2-3 corpses to regenerate the mana from your E (30 mana per corpse)

Mid Game: By now you should have your second hero and you should have leveled your Q for damage or W/E for additional sustain depending on how you play, the Devourer does well with heroes which can regenerate either his health or mana and Heroes with access to other debuffs or buffs as they complement the melee nature of the Devourer. When engaging with the enemy his E is good for pursuing enemies and his W can secure a body-blocked or slowed straggler comfortably - catching a hero with it will lock it down for 4 seconds. At level 6 the ultimate (R) can be used to give a massive damage surge for 60 seconds but will beg the need for potions or a hero who can heal them due to the self-inflicted damage. The increased speed can also assist in making a game-winning capture of a hero but be careful as the damage cannot be cancelled and it adds up quickly (a total of 600 out of your max 1045 health at level 6 disregarding passive regen).

Late Game: Towards the end of the game the Devourer really comes in to its own - at this point the mana issues will be all but nonexistent save for spamming your high level Q or low level W, the ability damage should make picking away at enemy armies easy providing more than enough corpses and using your R will be much safer making the damage spike potential much more threatening
Tips
Combos: The Devourer's abilities interact with each other to enhance its combat capabilities centering around their Q ability which applies a bleed effect on enemies hit. Using the W on a bleeding enemy regenerates extra health and extends the bleeding effect and using the E on them refunds the cost of casting it. In addition the R also applies bonuses making the Q and W deal additional damage and increasing the projectile speed of the E. Which allows you to use the following combos:
- Q->W
- Q->E->W
- Q->W->E->Q
- Q->W->E->W->Q (Bodyblocked Opponent)
- Q->E->Q
- R->Q->W->Chase->Q->E->W
- R->Q->E->Q->Q->E->Q->Q->E->(etc.)
- R->E->Q->W
- R->E->W->Q

Leeching Life: Your W is very expensive at low levels so it should be saved for when you direly need health or to disable priority targets (enemy heroes, boss mob in a creep camp) in addition it has the ability to whiff if your opponent gets too far away from you before you latch on (it won't cost you any mana if you miss but the ability will still go on cooldown), this necessitates that when chasing a fast enemy use your E to slow your target or to have body blocked them to give you time to grab them

Manacost Nightmare: If you're struggling to manage the mana or simply need to boost the amount you can use spells pick up either mana potions, a mantle of intelligence + 3 (+45 mana) or other similar items. Alternatively train units or Heroes that can help with your mana issues (Archmage, Obsidian Statue or Bloodmage). Health Regeneration/Armour can also help with this by lowering the need to use your W to just the times you want to stun a unit for a long time (Shadow Hunter, Dreadlord, Lich, Paladin, Keeper of the Grove)

Graverobber: your E can be used to interfere with necromancer centred undead play by consuming the corpses they would use to summon skeletons though they may also deny your mana regen by getting to them first. Similarly when playing undead or attacking an undead player the graveyard can be used as an easy means to regenerate mana as it periodically spawns corpses you can consume
[​IMG] Model Information:
- Race: Silithid
- 242.4kb for all textures and models (main and portrait)
- 19kb for all icons (BTN/DISBTN/Scorescreen)
- 8 Limbs (4 arms/claws, 4 legs)
- Stinger
- Atrophied wings
- Completely custom animations including unique ones for each ability
- Attachment points on all limbs (Sprite first for stinger, second & third for extra claws)
- Built-in Sound effects on spell throw and channel
- Custom texture for the body and an animated texture for the abdomen
- Team colour on the wings and abdomen
Model Thread
Icon Thread
Stats
Stat Base Growth Max
[​IMG] 22 3.00 49 Primary
[​IMG] 19 2.00 37
[​IMG] 11 1.00 20
Abilities
Icon Tooltip
[​IMG] Q - Rupturing Stab Manacost: 30/45/60 Cooldown: 6 seconds
The caster swings at the target with its stinger dealing damage and causing them to bleed for 4 seconds. Targetting bleeding enemies with other abilities applies bonuses.

Level 1 - 50 initial damage, 30 bleed damage.
Level 2 - 75 initial damage, 60 bleed damage.
Level 3 - 100 initial damage, 90 bleed damage.
[​IMG] W - Leech Life Manacost: 80/65/50 Cooldown: 8 seconds
Latches on to enemy units pinning them and draining blood dealing damage and restoring health to the caster over 4 seconds bleeding enemies bleed for 4 more seconds and restores extra health to the caster.

Level 1 - 75 damage dealt, 100 health restored, 35 extra restored.
Level 2 - 85 damage dealt, 120 health restored, 70 extra restored.
Level 3 - 95 damage dealt, 140 health restored, 105 extra restored.
[​IMG] E - Corpse Crusher Manacost: 50 Cooldown: 18/16/14 seconds
Allows the caster to passively consume corpses to regenerate mana, can be cast actively to launch a corpse at the target point that will deal 50 damage and slow enemies in an area for a duration. Hitting a bleeding enemy with the corpse refunds half the cost of the spell.

Level 1 - 30 mana restored, weak slow, lasts 5 seconds.
Level 2 - 45 mana restored, medium slow, lasts 6 seconds.
Level 3 - 60 mana restored, strong slow, lasts 7 seconds.
[​IMG] R - Blood Boil Manacost: 120 Cooldown: 120 seconds
The caster's heart rate surges increasing their attack and movement speed substantially while also increasing mana regeneration at the cost of 10 health every second, additionally their abilities are enhanced. Lasts 60 seconds.

Rupturing Stab - stab damage increased by 25 per level, bleed damage increased by 15 per level.
Life Leech - damage increased by 50.
Corpse Crusher - faster projectile.
Showcases
  • GIF Code
    [​IMG]
    Code (vJASS):

    ////////////////////////////////////////////////////////////////////
    //                     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                                             //
    ///////////////////////////////////////////////////////////////////
     
  • GIF Code
    [​IMG]
    Code (vJASS):
    ////////////////////////////////////////////////////////////////////
    //                       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                                             //
    ///////////////////////////////////////////////////////////////////
     
  • GIF Code
    [​IMG]
    Code (vJASS):
    ////////////////////////////////////////////////////////////////////
    //                     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                                             //
    ///////////////////////////////////////////////////////////////////
  • GIF Code
    [​IMG]
    Code (vJASS):
    ////////////////////////////////////////////////////////////////////
    //                       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                                             //
    ///////////////////////////////////////////////////////////////////
Changelog

-=V1.00=-
- Initial Upload
-=V1.01=-
- Changed prefixes to be 4 characters rather than 2
- Changed all instances of "Node" to "node" for variable naming consistency
- Leech Life now uses 1 dummy rather than creating one each time a unit is stunned
- Added additional Attachment Point options for Corpse Crusher
- Rearranged the config for Rupturing Stab to put attachment points near effects
-=Null=-
- OrderID changes in 1.28 broke Leech Life, resolved this issue
Contents

Silithid Devourer Spellset (Map)

Reviews
KILLCIDE
Never have to worry about ugly code from you, Tank-Commander. Other than extremely clean and well-documented code, there was not anything gamebreaking. This spellpack is a great addition to our database. Needs Fixed Rupturing Stab Nothing Leech...
  1. WhiteFang

    WhiteFang

    Joined:
    Jul 6, 2014
    Messages:
    3,256
    Resources:
    0
    Resources:
    0
    Just wanted to say I really like the layout of the description
     
  2. StoPCampinGn00b

    StoPCampinGn00b

    Community Manager

    Joined:
    Apr 2, 2013
    Messages:
    2,459
    Resources:
    1
    Maps:
    1
    Resources:
    1
    Wow, the visuals and design on the animations, spells, and the model itself are crazy good. Though "Leech Life" makes me want to puke, no joke lol.
     
  3. Clanzion

    Clanzion

    Joined:
    Jul 4, 2016
    Messages:
    257
    Resources:
    0
    Resources:
    0
    This was almost exactly what I was looking for. Great work as always.
     
  4. Kam

    Kam

    Blizzard Associate Producer

    Joined:
    Aug 3, 2004
    Messages:
    2,609
    Resources:
    23
    Models:
    8
    Icons:
    2
    Maps:
    13
    Resources:
    23
    Outstanding presentation!

    The gif for Corpse Crusher is broken.
     
  5. Tank-Commander

    Tank-Commander

    Spell Reviewer

    Joined:
    May 26, 2009
    Messages:
    1,547
    Resources:
    44
    Packs:
    1
    Spells:
    41
    Tutorials:
    2
    Resources:
    44
    The GIF still functions fine for me - try emptying the cache and reloading
     
  6. KILLCIDE

    KILLCIDE

    Administrator

    Joined:
    Jul 22, 2015
    Messages:
    3,448
    Resources:
    20
    Models:
    2
    Icons:
    10
    Spells:
    7
    Tutorials:
    1
    Resources:
    20
    Never have to worry about ugly code from you, Tank-Commander. Other than extremely clean and well-documented code, there was not anything gamebreaking. This spellpack is a great addition to our database.


    Needs Fixed

    • Rupturing Stab
      • Nothing

    • Leech Life
      • Nothing

    • Corpse Crusher
      • Nothing

    • Blood Boil
      • Nothing

    Suggestions

    • Rupturing Stab
      • RS is too generic as a prefix for variables and functions
      • I would rearrange the constant functions for effects so that the actual effect and their attachment points are side by side. At the moment, it's a little hard to distinguish which attachment point belongs to which effect without having to go back and forth
      • I would rename
        local integer Node
        to
        local integer node
        just for code consistency
      • Instead of looping through the instances to check if the unit is still bleeding, you can just check if they stil lhave the buff

    • Leech Life
      • LL is too generic as a prefix for variables and functions
      • I would rename
        local integer Node
        to
        local integer node
        just for code consistency
      • Instead of constantly creating a stun dummy and then removing it whenever the leeched unit needs to be stunned, just create one on initialization and move it around when you need to

    • Corpse Crusher
      • CC is too generic as a prefix for variables and functions
      • I would create a seperate attachment point for every different effect. Some effects look weird when they are on the origin, some look weird when in overhead, so it's better to have the option to change the attachment point if a user desires to change the effect. I think you got lucky with having them all look good on origin
      • Nothing wrong with
        function CC_2PI
        , but I thought it was just funny how you're literally squeezing in nanoseconds xD
      • You currently have 2 seperate loops just to register
        EVENT_PLAYER_UNIT_SPELL_EFFECT
        and
        EVENT_PLAYER_HERO_SKILL
        when you could have just made your own single loop and used the natives directly
      • In
        function CC_Update
        , you can use
        GetLearnedSkillLevel()
        over
        GetUnitAbilityLevel(u, CC_Ability())
      • I would rename
        local integer Node
        to
        local integer node
        just for code consistency
      • The black magic math you do in your loop is beyond me. I'm going to assume they are right (inb4 someone points out I'm wrong for approving this because something is wrong with the calculations)

    • Blood Boil
      • BB is too generic as a prefix for variables and functions
      • I would add extra constant functions that allow users to put in what the default RGB is for the hero or unit. Currently, you are just assuming they are 255 across the board
      • I would rename
        local integer Node
        to
        local integer node
        just for code consistency

    Status


    Approved
     
  7. Kyrbi0

    Kyrbi0

    Joined:
    Jul 29, 2008
    Messages:
    7,617
    Resources:
    1
    Models:
    1
    Resources:
    1
    Boy, if only we had someone with a math degree to figure that part out... ;P
     
  8. KILLCIDE

    KILLCIDE

    Administrator

    Joined:
    Jul 22, 2015
    Messages:
    3,448
    Resources:
    20
    Models:
    2
    Icons:
    10
    Spells:
    7
    Tutorials:
    1
    Resources:
    20
    Ehhh we would someone who knows vector physics :p
     
  9. Bladesmaster123

    Bladesmaster123

    Joined:
    Dec 26, 2016
    Messages:
    2
    Resources:
    0
    Resources:
    0
    good looking hero but i would have preferred if Blood Boil was based on immolation or mana shield so you could diactivate it instead increase the health cost, this way it's like sacrificing Health for Power whenever you want,just an idea though the hero is cool