[Log in / Register]
| News | Chat | Pastebin | Donations | Tutorials | Rules | Forums | Starcraft II |
| Maps | Skins | Icons | Models | Spells | Tools | Jass | Packs |
(Keeps Hive Alive)
Go Back   Warcraft 3 Spells > Spells

Reply
 
LinkBack Thread Tools
The Hive Workshop Spells:
Inferior Spellpack v1.5
Images
Highslide JS
Details
Uploaded:16:44, 19th Feb 2010
Last Updated:23:38, 24th Jul 2010
Keywords:Spell, Pack, Inferior, Dark, Curse, Deadly, Seduction, Haunting, Ghosts, Magnetic Field, Polarisation, Dread Lord, Electrician, Robot, Arms, vJASS
Type:Pack
Category:vJASS

Here is my 2nd Spellpack I upload on Hive. Because of constructive Criticism by Deaod on my 1st Spellpack I tried to improve my coding and now here it goes.

Credits goes to:
- Vexorian
- Rising_Dusk
- Earth-Fury
- grim001
- Anitarf
- TriggerHappy187
for their libraries i use in this pack;
- watermelonman_1234
for creating the 'RoboticArmsHand.mdl'
- DarkT3mpl3r
- Hanky
for teaching me vJass

Changelog
- v1.0 - Official release
- v1.1 - Added the Spell 'Robot Arms'
- v1.2 - Fixed Some Code related struff
- v1.3 - Fixed Tooltips and recoded Deadly Seduction
- v1.4 - Imported the 'RoboticArmsHand.mdl' to get rid of the stupid sound and
Implemented the TimedHandles library by TriggerHappy187
- v1.5 - Fixed a bug in Robotic Arms


Now the spells:
This pack contains 6 spells.

Screenshots
Polarisation
Robot Arms


Deadly Seduction
The Dread Lord infects an enemy with an deadly virus that makes him to attack the Dread Lords enemies. If the unit gets another order than an attack order to an enemy unit of the Dread Lord, the virus attacks the units organs dealing damage. If the unit dies the virus is released out of the targets body infecting all enemy units nearby with poison that deals damage over time. That damage is amplified if the poisoned unit moves. If a poisoned unit dies it releases a disease cloud that deals damage to its allies.



Jass:
library DeadlySeduction initializer Init needs TimerUtils, Table, GroupUtils, SpellEvent, LastOrder, ABuff
//*******************************************************************************************\\
//*******************************************************************************************\\
//*                               Deadly Seducetion By Inferior                             *\\
//*                                                                                         *\\
//*                                          v1.1                                           *\\
//*                                                                                         *\\
//*                                 *************************                               *\\
//*                                 * Requirements:         *                               *\\
//*                                 * - JassNewGenPack      *                               *\\
//*                                 * - TimerUtils          *                               *\\
//*                                 * - Table               *                               *\\
//*                                 * - GroupUtils          *                               *\\
//*                                 * - SpellEvent          *                               *\\
//*                                 * - LastOrder           *                               *\\
//*                                 * - ABuff               *                               *\\
//*                                 *************************                               *\\
//*                                                                                         *\\
//*                                                                                         *\\
//*                                                                                         *\\
//* How To Import:                                                                          *\\
//* - Copy the Spell called 'Deadly Seduction' and create 2 new Buffs, the first for        *\\
//*   your the Mainability, the second for the DiseaseCloud effect                          *\\
//* - Remove the exclamation in front of the ObjectMerger execution.                        *\\
//*   Save the map, reopen it and put the exclamations again to remove saving delay.        *\\
//* - Copy the whole Triggerscript into your map                                            *\\
//* - Import the 'Dummy.mdx' included in that map to your map                               *\\
//* - Create a dummy unit and change the model into the 'Dummy.mdx'                         *\\
//* - Now change the values of the 'ABILID', 'DUMMYID', 'DISEASEID' and 'BUFFID             *\\
//*   to the Rawcodes of the Spells, Buff and Dummy in your map                             *\\
//*                                                                                         *\\
//*    Spelldescription:                                                                    *\\
//*    The Caster infects the Target Unit with a deadly virus, that makes the Target lose   *\\
//*    his mind and even attack his allies. Each time the Target gets a new Order from      *\\
//*    its Owner, the virus destroys the Targets cells and force it to attack his allies.   *\\
//*    If the Target dies, nearby allied units get infected by the Poison flodding out of   *\\
//*    the Targts dead body. The Poison deals damage over time. If the Infected moves the   *\\
//*    Poison destroys the body faster and deals doubled damage. If an Infected unit dies,  *\\
//*    its dead body releases a deadly Cloud of poison that deals damage to allied units    *\\
//*    nearby.                                                                              *\\
//*                                                                                         *\\
//*******************************************************************************************\\
//*******************************************************************************************\\
// Globals Setting

// //! external ObjectMerger w3a ANpi DisC anam DiseaseCloud alev 3 Eim1 1 1.0 Eim1 2 1.0 Eim1 3 1.0 ahdu 1 0.1 ahdu 2 0.1 ahdu 3 0.1 adur 1 0.1 adur 2 0.1 adur 3 0.1 aare 1 250. aare 2 250. aare 3 250. atar 1 ground,enemies,neutral,organic atar 2 ground,friend,neutral,organic atar 3 ground,enemies,friend,neutral,organic

    globals
        private constant integer    ABILID         = 'A008' 
        // The AbilityId of the MainAbility
        
        private constant integer    DUMMYID        = 'e000'
        // The UnitId of the DummyUnit ( Uses imported Dummymodel ) ; you may use your own dummy here
        
        private constant integer    DISEASEID      = 'DisC'
        // The AbilityId of the DiseaseCloud ( Based on 'Permanent Immolation' )
        
        private constant integer    BUFFID         = 'B000'
        // The Rawcode of the Buff
        
        private constant real       DURATION       = 2.5
        // The Base Duration for the MainAbility
        
        private constant real       DETECTRADIUS   = 500.
        // The Radius in which the possible Targets for the MainAbility shall be detected
        
        private constant real       INFECTDURATION = 10.
        // The Duration of the Infection after the Explosion of the Main Target
        
        private constant real       INFECTPERIOD   = .02
        // The Period of the Infection Timer
        
        private constant real       EXPLODEFACTOR  = .1
        // The Factor of the Targets MAX_HP at which it explodes if it falls below
        
        private constant real       HEALTHFACTOR   = .01
        // The Factor of the Targets CURRENT_HP that is dealt as Damage per INFECTPERIOD
        
        private constant real       PAINDAMAGE     = .01
        // The Factor of the Targets MAX_HP that is dealt as Damage if its AttackOrder gets interrupted
        
        private constant real       INSTANTKILL    = 10000000.
        // The value to instantly kill an Unit. Insert here any value that is big enough to kill any Unit on your map
    
        private constant real       EXPLODERADIUS  = 350.
        // The Radius in which Units get Infected after the Main Target explodes
        
        private constant boolean    INFECTENEMIES  = false
        // The value to check the possible Targets for the Infection
        
        private constant boolean    INFECTALLIES   = true
        // The value to check the possible Targets for the Infection
        
        // The 2 values above are weird, because INFECTENEMIES means the enemies of the Main Target
        // and INFECTALLIES means the allies of the Main Target
        
        private constant string     INFECTCLOUD    = "Abilities\\Spells\\Undead\\PlagueCloud\\PlagueCloudCaster.mdl"
        // The Effect for the Dummy
        
        private constant string     INFECTTARGET   = "Units\\Undead\\PlagueCloud\\PlagueCloudtarget.mdl"
        // The Effect attached to the Infected Units
        
        private constant string     INFECTATTACH   = "head"
        // The AttachPoint for the TargetEffect
        
        private constant string     PAINEFFECT     = "Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodRifleman.mdl"
        // The Effect attached to the Main Target when it feels Pain ( interrupts AttackOrder )
        
        private constant string     PAINATTACH     = "origin"
        // The AttachPoint for the PAINEFFECT or the DummyEffect
        
        // The following values only refer to all Damage that is dealt in this Spell
        private constant boolean    DAMAGEDMEELE   = true
        private constant boolean    DAMAGEDRANGED  = false
        private constant attacktype ATTACKTYPE     = ATTACK_TYPE_MAGIC
        private constant damagetype DAMAGETYPE     = DAMAGE_TYPE_MAGIC
        private constant weapontype WEAPONTYPE     = WEAPON_TYPE_WHOKNOWS
        
        // DO NOT CHANGE THESE VALUES
        private constant integer    ATTACKORDER    = 851983
        // The OrderId for common Attack Order
        private constant integer    STOPORDER      = 851972
        // The OrderId for common Stop Order
        private constant integer    DISARMBUFF     = '&ARM'
        
        // Do not change any of the following variables
        private          unit       TEMPUNIT
        
    endglobals
    
    
    // function that returns the Duration of the Main Ability for each level
    private constant function GetRealDuration takes integer level returns real
        return DURATION+level
    endfunction
    
    // DO NOT TOUCH ANYTHING BELOW THIS COMMENT, ALTHOUGH YOU KNOW WHAT YOU DO.
    // HERE BEGINS THE SPELLS SCRIPT.
    
    private keyword Infection // DO NOT CHANGE THIS
    
    // DO NOT CHANGE THIS FUNCTION
    // this function returns an important value
    private constant function GetDiseaseLevel takes nothing returns integer
        if INFECTENEMIES and INFECTALLIES then
            return 3
        elseif INFECTENEMIES and not INFECTALLIES then
            return 2
        elseif not INFECTENEMIES and INFECTALLIES then
            return 1
        else
            return 0
        endif
    endfunction
        
    // the Filter for the Units for the MainAbility
    private function GroupFilter takes nothing returns boolean
        return IsUnitAlly(GetFilterUnit(),GetOwningPlayer(TEMPUNIT)) and GetWidgetLife(GetFilterUnit())>0.405 and IsUnitType(GetFilterUnit(),UNIT_TYPE_GROUND) and GetFilterUnit()!=TEMPUNIT
    endfunction
    
    // DO NOT CHANGE THIS FUNCTION
    // you may add more Filters if you want but do not remove any of those
    private function InfectionFilter takes nothing returns boolean
        if INFECTENEMIES and not INFECTALLIES then
            return IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(TEMPUNIT)) and GetWidgetLife(GetFilterUnit())>0.405 and Infection.InfectTable[GetFilterUnit()]==0 and GetFilterUnit()!=TEMPUNIT
        elseif not INFECTENEMIES and INFECTALLIES then 
            return IsUnitAlly(GetFilterUnit(),GetOwningPlayer(TEMPUNIT)) and GetWidgetLife(GetFilterUnit())>0.405  and Infection.InfectTable[GetFilterUnit()]==0 and GetFilterUnit()!=TEMPUNIT
        elseif INFECTENEMIES and INFECTALLIES then
            return GetWidgetLife(GetFilterUnit())>0.405 and Infection.InfectTable[GetFilterUnit()]==0 and GetFilterUnit()!=TEMPUNIT
        else
            return false
        endif
    endfunction
    
//**********************************************//
//          Struct for the Infection            //
//**********************************************//
    
private struct Infection 
    unit infected
    unit caster
    real dps
    real duration
    real x
    real y
    effect smoke
    
    static integer count      = 0
    static timer   InfectTimer
    
    static boolean array active
    static Infection array Data
    
    static HandleTable InfectTable
    
    // Deals Damage over Time and checks if the Infected unit moved.
    // If it moved it deals doubled Damage
    static method Disease takes nothing returns nothing
        local integer int=0
        local unit dum
        local effect e
        loop
            exitwhen int>=.count
            if .active[int] then
                if .Data[int].duration>=0 then
                
                // Checks if the Infected moved. If it did it takes doubled Damage
                    if GetUnitX(.Data[int].infected)==.Data[int].x and GetUnitY(.Data[int].infected)==.Data[int].y then
                        call UnitDamageTarget(.Data[int].caster,.Data[int].infected,.Data[int].dps*INFECTPERIOD*2,DAMAGEDMEELE,DAMAGEDRANGED,ATTACKTYPE,DAMAGETYPE,WEAPONTYPE)
                    else  
                        call UnitDamageTarget(.Data[int].caster,.Data[int].infected,.Data[int].dps*2*INFECTPERIOD*2,DAMAGEDMEELE,DAMAGEDRANGED,ATTACKTYPE,DAMAGETYPE,WEAPONTYPE)
                    endif
                    
                    set .Data[int].x=GetUnitX(.Data[int].infected)
                    set .Data[int].y=GetUnitY(.Data[int].infected)
                    set .Data[int].duration=.Data[int].duration-INFECTPERIOD
                    
                    // Checks if the Infected is still alive or not.
                    // If it is, it creates a Cloud that deals damage to nearby units.
                    if GetWidgetLife(.Data[int].infected)<0.405 then
                        set dum=CreateUnit(GetOwningPlayer(.Data[int].caster),DUMMYID,GetUnitX(.Data[int].infected),GetUnitY(.Data[int].infected),0)
                        call UnitAddAbility(dum,DISEASEID)
                        call SetUnitAbilityLevel(dum,DISEASEID,GetDiseaseLevel())
                        call AddSpecialEffectTarget(INFECTCLOUD,dum,PAINATTACH)
                        call UnitApplyTimedLife(dum,'Bapl',GetRealDuration(GetUnitAbilityLevel(.Data[int].caster,ABILID)))
                        call DestroyEffect(.Data[int].smoke)
                        set .active[int]=false
                        call .Data[int].destroy()
                    endif
                else
                    set .InfectTable[.Data[int].infected]=0
                    call DestroyEffect(.Data[int].smoke)
                    set .active[int]=false
                    call .Data[int].destroy()
                endif
            endif
            set int=int+1
        endloop
    endmethod
    
    static method create takes nothing returns Infection
        local Infection data=Infection.allocate()
        if .count==0 then
            set .InfectTimer=NewTimer()
            call TimerStart(.InfectTimer,INFECTPERIOD,true,function Infection.Disease)
        endif
        set .active[.count]=true
        set .Data[.count]=data
        set .count=.count+1
        return data
    endmethod
    
endstruct

//**********************************************//
//          Struct for the Main Spell           //
//**********************************************//
    
private struct Spell 
    unit caster
    unit target
    unit victim
    timer Time  
    timer Dead
    boolean Infection
    
    static trigger Order
    static HandleTable SpellTable
    
    static method Infect takes nothing returns nothing
        local Infection data
        if Infection.InfectTable[GetEnumUnit()]==0 then
            set data=Infection.create()
            set data.infected=GetEnumUnit()
            set data.caster=TEMPUNIT
            set data.x=GetUnitX(data.infected)
            set data.y=GetUnitY(data.infected)
            set data.dps=GetWidgetLife(data.infected)*HEALTHFACTOR
            set data.smoke=AddSpecialEffectTarget(INFECTTARGET,data.infected,INFECTATTACH)
            set data.duration=INFECTDURATION
            set Infection.InfectTable[data.infected]=data
        else
            set data.duration=INFECTDURATION
        endif
    endmethod
    
    // The method for the Spells End. Picks nearby units and infects them.
    static method EndSpell takes nothing returns nothing
        local Spell data=GetTimerData(GetExpiredTimer())
        if data.Infection then
            set TEMPUNIT=data.caster
            call GroupEnumUnitsInArea(ENUM_GROUP,GetUnitX(data.target),GetUnitY(data.target),EXPLODERADIUS,Condition(function InfectionFilter))
            call UnitDamageTarget(data.caster,data.target,INSTANTKILL,DAMAGEDMEELE,DAMAGEDRANGED,ATTACKTYPE,DAMAGETYPE,WEAPONTYPE)
            call ForGroup(ENUM_GROUP,function Spell.Infect)
            call GroupClear(ENUM_GROUP)
        else
            call SetUnitExploded(data.target,false)
        endif
        set Spell.SpellTable[data.target]=0
        call IssueImmediateOrderById(data.target,STOPORDER)
        call UnitRemoveAbility(data.target,BUFFID)
        call ReleaseTimer(data.Dead)
        call ReleaseTimer(data.Time)
        set data.Dead=null
        set data.Time=null
        set data.target=null
        set data.caster=null
        set data.victim=null
        set data.Infection=false
        call data.destroy()
    endmethod
    
    // Checks if the Target Unit is dead or not. Checks if the allied target that is attacked(victim) is dead or not.
    // If the victim is dead it searchs for a new one. If there is none the Spell ends and the virus is destroyed.
    static method CheckDead takes nothing returns nothing
        local Spell data=GetTimerData(GetExpiredTimer())
        if GetWidgetLife(data.target)>GetUnitState(data.target,UNIT_STATE_MAX_LIFE)*EXPLODEFACTOR then
            if GetWidgetLife(data.victim)<0.405 then
                set TEMPUNIT=data.caster
                call GroupEnumUnitsInArea(ENUM_GROUP,GetUnitX(data.target),GetUnitY(data.target),DETECTRADIUS,Condition(function GroupFilter))
                set data.victim=GroupPickRandomUnit(ENUM_GROUP)
                if data.victim==data.target then
                    call GroupRemoveUnit(ENUM_GROUP,data.victim)
                    set data.victim=GroupPickRandomUnit(ENUM_GROUP)
                endif
                call GroupClear(ENUM_GROUP)
                
                if data.victim!=null then
                    call IssueTargetOrderById(data.target,ATTACKORDER,data.victim)
                else
                    call PauseTimer(data.Time)
                    call PauseTimer(data.Dead)
                    call TimerStart(data.Time,0.0,false,function Spell.EndSpell)
                endif
            endif
        else
            set data.Infection=true
            call PauseTimer(data.Time)
            call PauseTimer(data.Dead)
            call TimerStart(data.Time,0.0,false,function Spell.EndSpell)
        endif
    endmethod
    
    // Checks if the target is ordered another order than the Attackorder and if the ordered unit is equal to victim.
    // There is one thing to mention. If the target is unable to attack, that means it does not have attack ability
    // or it is disarmed, then this spell has no effect and is removed from the Target
    // E.g. you cast Deadly Seduction on a target and after that Dark Curse and attack it. Its ability to attack is removed
    // and then the Effect of this Spell is removed aswell. That means any disarm abilities have a higher priority than this
    // Spell. And I definitly recommend not to remove the 'attack' Ability other than with disarms!!!!
    static method CheckOrder takes nothing returns boolean
        local unit ordered=GetOrderedUnit()
        local Spell data
        if GetUnitAbilityLevel(ordered,BUFFID)>0 then
            if GetUnitAbilityLevel(ordered,DISARMBUFF)==0 then
                set data=Spell.SpellTable[ordered]
                if GetWidgetLife(data.target)>GetUnitState(data.target,UNIT_STATE_MAX_LIFE)*EXPLODEFACTOR then
                    if GetWidgetLife(data.victim)>0.405 then
                        if GetOrderTargetUnit()!=data.victim or GetLastOrderId(data.target)!=ATTACKORDER then
                            call IssueTargetOrderById(data.target,ATTACKORDER,data.victim)
                            call UnitDamageTarget(data.caster,data.target,GetUnitState(data.target,UNIT_STATE_MAX_LIFE)*PAINDAMAGE,DAMAGEDMEELE,DAMAGEDRANGED,ATTACKTYPE,DAMAGETYPE,WEAPONTYPE)
                            call DestroyEffect(AddSpecialEffectTarget(PAINEFFECT,data.target,PAINATTACH))
                        endif
                    else
                        set TEMPUNIT=data.caster
                        call GroupEnumUnitsInArea(ENUM_GROUP,GetUnitX(data.target),GetUnitY(data.target),DETECTRADIUS,Condition(function GroupFilter))
                        
                        set data.victim=GroupPickRandomUnit(ENUM_GROUP)
                        if data.victim==data.target then
                            call GroupRemoveUnit(ENUM_GROUP,data.victim)
                            set data.victim=GroupPickRandomUnit(ENUM_GROUP)
                        endif
                        call GroupClear(ENUM_GROUP)
                        
                        if data.victim!=null then
                            call IssueTargetOrderById(data.target,ATTACKORDER,data.victim)
                        else
                            call PauseTimer(data.Time)
                            call PauseTimer(data.Dead)
                            call TimerStart(data.Time,0.0,false,function Spell.EndSpell)
                        endif
                    endif
                else
                    set data.Infection=true
                    call PauseTimer(data.Time)
                    call PauseTimer(data.Dead)
                    call TimerStart(data.Time,0.0,false,function Spell.EndSpell)
                endif
            else
                call PauseTimer(data.Time)
                call PauseTimer(data.Dead)
                call TimerStart(data.Time,0.0,false,function Spell.EndSpell)
            endif
            
        endif
        
        return false
    endmethod

endstruct

    // Buff declaration
    globals
        private aBuffType buffType = 0
    endglobals
    
    // executed when the Buff is removed anyhow, e.g. with a dispel
    private function Dispel takes aBuff buffType returns nothing
        local Spell data=buffType.data
        if GetUnitAbilityLevel(data.target,BUFFID)==0 then
            set data.Infection=false
            call PauseTimer(data.Time)
            call PauseTimer(data.Dead)
            call TimerStart(data.Time,0.0,false,function Spell.EndSpell)
            call ABuffRemove(buffType)
        endif
    endfunction

    // executed Function on Spellcast. Checks if there is an ally of the target unit.
    // If there is none the spell has no effect.
    private function SeductionSpell takes nothing returns nothing
    
        local Spell data
        
        if Spell.SpellTable[SpellEvent.TargetUnit]==0 then
            set data=Spell.create()
            set data.caster=SpellEvent.CastingUnit
            set data.target=SpellEvent.TargetUnit
            set data.Time=NewTimer()
            set data.Dead=NewTimer()
            set data.Infection=false
            call SetTimerData(data.Time,data)
            call SetTimerData(data.Dead,data)
            
            set TEMPUNIT=data.caster
            call GroupEnumUnitsInArea(ENUM_GROUP,GetUnitX(data.target),GetUnitY(data.target),DETECTRADIUS,Condition(function GroupFilter))
            
            set data.victim=GroupPickRandomUnit(ENUM_GROUP)
            if data.victim==data.target then
                call GroupRemoveUnit(ENUM_GROUP,data.victim)
                set data.victim=GroupPickRandomUnit(ENUM_GROUP)
            endif
            call GroupClear(ENUM_GROUP)
            
            
            set TEMPUNIT=null
            
            if data.victim!=null then
            
                call ABuffApply(buffType,data.target,data.caster,GetRealDuration(GetUnitAbilityLevel(data.caster,ABILID)),GetUnitAbilityLevel(data.caster,ABILID),data)
            
                call SetUnitExploded(data.target,true)
                call IssueTargetOrderById(data.target,ATTACKORDER,data.victim)
                
                set Spell.SpellTable[data.target]=data
                
                call TimerStart(data.Time,GetRealDuration(GetUnitAbilityLevel(data.caster,ABILID)),false,function Spell.EndSpell)
                call TimerStart(data.Dead,0.01,true,function Spell.CheckDead)
            
            else
            
                call UnitRemoveAbility(data.target,BUFFID)
                call ReleaseTimer(data.Time)
                call ReleaseTimer(data.Dead)
                call data.destroy()
                
            endif
        else
            set data=Spell.SpellTable[SpellEvent.TargetUnit]
            call ABuffApply(buffType,data.target,data.caster,GetRealDuration(GetUnitAbilityLevel(data.caster,ABILID)),GetUnitAbilityLevel(data.caster,ABILID),data)
            call PauseTimer(data.Time)
            call TimerStart(data.Time,GetRealDuration(GetUnitAbilityLevel(data.caster,ABILID)),false,function Spell.EndSpell)
        endif
    endfunction
    
    private function Init takes nothing returns nothing
        call RegisterSpellEffectResponse(ABILID,SeductionSpell)
        set Spell.SpellTable=HandleTable.create()
        set Infection.InfectTable=HandleTable.create()
        set Spell.Order=CreateTrigger()
        
        set buffType = aBuffType.create()
        set buffType.eventPeriodic = Dispel
        
        call Preload(INFECTCLOUD)
        call Preload(INFECTTARGET)
        call Preload(PAINEFFECT)
        call PreloadStart()
        
        call TriggerRegisterAnyUnitEventBJ(Spell.Order,EVENT_PLAYER_UNIT_ISSUED_ORDER)
        call TriggerRegisterAnyUnitEventBJ(Spell.Order,EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
        call TriggerRegisterAnyUnitEventBJ(Spell.Order,EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
            
        call TriggerAddCondition(Spell.Order,Condition(function Spell.CheckOrder))
    endfunction
    
endlibrary

Dark Curse
The Dread Lord uses mighty dark magic to curse a target unit with a deadly curse, that reduces the targets size. All damage taken by that unit is amplified by 50% and will cause a confusion in the targets head making it unable to attack and to execute its owners orders correctly. To damage the target with physical attacks is harder, because of the lack of size.


Jass:
library DarkCurse initializer Init needs TimerUtils, LastOrder, UnitStatus, Table, SpellEvent, ABuff, xecast, xepreload
//*******************************************************************************************\\
//*******************************************************************************************\\
//*                                  Dark Curse By Inferior                                 *\\
//*                                                                                         *\\
//*                                          v1.0                                           *\\
//*                                                                                         *\\
//*                                 *************************                               *\\
//*                                 * Requirements:         *                               *\\
//*                                 * - JassNewGenPack      *                               *\\
//*                                 * - TimerUtils          *                               *\\
//*                                 * - LastOrder           *                               *\\
//*                                 * - UnitStatus          *                               *\\
//*                                 * - Table               *                               *\\
//*                                 * - SpellEvent          *                               *\\
//*                                 * - ABuff               *                               *\\
//*                                 * - xecast              *                               *\\
//*                                 * - xepreload           *                               *\\
//*                                 *************************                               *\\
//*                                                                                         *\\
//*                                                                                         *\\
//*                                                                                         *\\
//* How To Import:                                                                          *\\
//* - Copy the Spell called 'Dark Curse' and create a Buff for your Effects                 *\\
//* - Remove the exclamation in front of the ObjectMerger execution.                        *\\
//*   Save the map, reopen it and put the exclamations again to remove saving delay.        *\\
//* - Copy the whole Triggerscript into your map                                            *\\
//* - Import the 'Dummy.mdx' included in that map to your map                               *\\
//* - Create a dummy unit and change the model into the 'Dummy.mdx'                         *\\
//* - Now change the values of the 'ABILID', 'DUMMYID', 'SHRINKID' and 'BUFFID              *\\
//*   to the Rawcodes of the Spells, Buff and Dummy in your map                             *\\
//*                                                                                         *\\
//*    Spelldescription:                                                                    *\\
//*    The Caster curses the Target with Dark Magic reducing its Size.                      *\\
//*    With this Size reduction, the damage taken is amplified and its Movement- and        *\\
//*    Attackspeed is reduced, but is harder to hit.                                        *\\
//*    Each time the Target takes damage its head is shattered, which makes it unable to    *\\
//*    attack and confuses it. Each time the Target gets an Point Order within that         *\\
//*    Confusion it will execute that Order in the complete other direction.                *\\
//*                                                                                         *\\
//*******************************************************************************************\\
//*******************************************************************************************\\
// Globals Setting

// //! external ObjectMerger w3a Ablo ShrA anam "Shrink/Slow" alev 4 areq null arqa 0 Blo1 1 -0.2 Blo1 2 -0.3 Blo1 3 -0.4 Blo1 4 -0.5 Blo2 1 -0.05 Blo2 2 -0.1 Blo2 3 -0.15 Blo2 4 -0.2 Blo3 1 -0.1 Blo3 2 -0.15 Blo3 3 -0.2 Blo3 4 -0.25 acdn 1 0.0 ahdu 1 4. ahdu 2 6. ahdu 3 8. ahdu 4 10. adur 1 2. adur 2 3. adur 3 4. adur 4 5. amcs 1 0 aran 1 9999.0 aran 2 9999.0 aran 3 9999.0 aran 4 9999.0 abuf 1 Bblo abuf 2 Bblo abuf 3 Bblo abuf 4 Bblo atar 1 "ground,enemies,air,neutral,organic" atar 2 "ground,enemies,air,neutral,organic" atar 3 "ground,enemies,air,neutral,organic" atar 4 "ground,enemies,air,neutral,organic"
// //! external ObjectMerger w3a ANth $Def anam "DefenseFactor" Uts2 1 1.5 Uts1 1 0
// //! external ObjectMerger w3a ANde $Atk anam "DamageFactor" Nde2 1 0.5 Nde3 1 0.5 Nde4 1 0.5 aher 0
// //! external ObjectMerger w3a ACev $Eva anam "EvasionFactor" Eev1 1 0.75
// //! external ObjectMerger w3a Aspb Book anam "CurseEffectBook" spb2 1 0 spb1 1 EvaA,AtkR,DefR aite 0

    globals
        private constant integer       ABILID        = 'A001'
        // The AbilityId of the Mainability
        
        private constant integer       SHRINKID      = 'ShrA'
        // The AbilityId of the Slow- and Shrinkability
        
        private constant integer       BUFFID        = 'B001'
        // The Buff of the Slow and Shrink
        
        private constant integer       EFFECTBOOK    = 'Book'
        // The Spellbook which contains the Evasion and Damageamplify Abilities
        
        private constant integer       DUMMYID       = 'e000'
        // The Id of your Dummyunit
        
        private constant integer       BLOODLUST     = 852101
        // The casting Order for the Slow and Shrink ( Here based on bloodlust )
        
        private constant integer       STOPORDER     = 851972
        // The common StopOrder
        
        private constant real          GROWTHDELAY   = 1.
        // The time the Target is growing. Will influence the possible duration to confuse the Target. Set this to 0
        // if you want it possible until the Target regains its default size
        
        private constant string        CONFUSED      = "Abilities\\Spells\\Items\\HealingSalve\\HealingSalveTarget.mdl"
        private constant string        CONFUSEATTACH = "origin"
        // The First Confusion Effect
        
        private constant string        CONFUSEEFFECT = "Abilities\\Spells\\Orc\\StasisTrap\\StasisTotemTarget.mdl"
        private constant string        EFFECTATTACH  = "overhead"
        // The Second Confusion Effect
        
        // For Descriptions for the following Variables see below
        private          real    array DURATION
        private          real    array HERODURATION
        private          real    array CONFUSEDTIME
    endglobals
    
    private function SetupSpellVariables takes nothing returns nothing
        // The duration for normal targets
        set DURATION[1]=4.-GROWTHDELAY
        set DURATION[2]=6.-GROWTHDELAY
        set DURATION[3]=8.-GROWTHDELAY
        set DURATION[4]=10.-GROWTHDELAY
        
        // The duration for Heros
        set HERODURATION[1]=2.-GROWTHDELAY
        set HERODURATION[2]=3.-GROWTHDELAY
        set HERODURATION[3]=4.-GROWTHDELAY
        set HERODURATION[4]=5.-GROWTHDELAY
        
        // The duration a unit is confused and disarmed
        set CONFUSEDTIME[1]=0.75
        set CONFUSEDTIME[2]=1.25
        set CONFUSEDTIME[3]=1.75
        set CONFUSEDTIME[4]=2.5
    endfunction
    
    // DO NOT TOUCH ANYTHING BELOW THIS COMMENT, ALTHOUGH YOU KNOW WHAT YOU DO.
    // HERE BEGINS THE SPELLS SCRIPT.

private struct DarkCurse
    unit caster
    unit target
    integer lvl
    trigger damage
    trigger order
    timer end
    timer disarm
    boolean disarmed
    boolean moved
    effect confused
    effect head
    
    static HandleTable CurseTable
    
    // Ends the Spell
    static method EndSpell takes nothing returns nothing
        local DarkCurse data=.CurseTable[GetExpiredTimer()]
        call UnitRemoveAbility(data.target,EFFECTBOOK)
        call ReleaseTimer(data.end)
        call ReleaseTimer(data.disarm)
        call DestroyTrigger(data.damage)
        call DestroyTrigger(data.order)
        call DestroyEffect(data.confused)
        call DestroyEffect(data.head)
        set data.disarmed=false
        set data.moved=false
        set data.lvl=0
        call data.destroy()
    endmethod
    
    // Removes the Disarm and Confusion
    static method RemoveDisarm takes nothing returns nothing
        local DarkCurse data=.CurseTable[GetExpiredTimer()]
        call DestroyTrigger(data.order)
        set data.disarmed=false
        call ReleaseTimer(GetExpiredTimer())
        call DestroyEffect(data.confused)
        call DestroyEffect(data.head)
    endmethod
        
    // Changes the LastOrders Coordinates
    static method ConfusedMove takes nothing returns boolean
        local DarkCurse data=.CurseTable[GetTriggeringTrigger()]
        local real x=GetUnitX(data.target)
        local real y=GetUnitY(data.target)
        local real dx=x-GetOrderPointX()
        local real dy=y-GetOrderPointY()
        set x=x+dx
        set y=y+dy
        if not data.moved then
            call AbortOrder(data.target)
            set data.moved=true
            call IssuePointOrderById(data.target,GetLastOrderId(data.target),x,y)
        else
            set data.moved=false
        endif
        
        return false
    endmethod
    
    // Executed when the target is damaged. If the damage taken is higher than 0 it is disabled and confused
    static method DisarmTarget takes nothing returns boolean
        local DarkCurse data=.CurseTable[GetTriggeringTrigger()]
        if GetEventDamage()>0 then
            if not data.disarmed then
                call DisarmUnitTimed(data.target,CONFUSEDTIME[data.lvl])
                set data.disarm=NewTimer()
                call TimerStart(data.disarm,CONFUSEDTIME[data.lvl],false,function DarkCurse.RemoveDisarm)
                set .CurseTable[data.disarm]=data
                set data.order=CreateTrigger()
                call TriggerRegisterUnitEvent(data.order,data.target,EVENT_UNIT_ISSUED_POINT_ORDER)
                call TriggerAddCondition(data.order,Condition(function DarkCurse.ConfusedMove))
                set .CurseTable[data.order]=data
                set data.disarmed=true
                set data.moved=false
                set data.confused=AddSpecialEffectTarget(CONFUSED,data.target,CONFUSEATTACH)
                set data.head=AddSpecialEffectTarget(CONFUSEEFFECT,data.target,EFFECTATTACH)
            endif
        endif
        
        return false
    endmethod
    
    static method create takes nothing returns DarkCurse
        local DarkCurse data=DarkCurse.allocate()
        return data
    endmethod

endstruct

    // Buff Declaration
    globals
        private aBuffType buffType = 0
    endglobals
    
    // executed when the Buff is removed anyhow, e.g. with a dispel
    private function Dispel takes aBuff buffType returns nothing
        local DarkCurse data=buffType.data
        if GetUnitAbilityLevel(data.target,BUFFID)==0 then
            call PauseTimer(data.end)
            call TimerStart(data.end,0.0,false,function DarkCurse.EndSpell)
            call ABuffRemove(buffType)
        endif
    endfunction

    // Executed on Spellcast
    private function CurseSpell takes nothing returns nothing
        local unit caster=SpellEvent.CastingUnit
        local unit target=SpellEvent.TargetUnit
        local integer lvl=GetUnitAbilityLevel(caster,ABILID)
        local xecast dummy
        local DarkCurse data
        
        if GetUnitAbilityLevel(target,BUFFID)==0 then
            call UnitAddAbility(target,EFFECTBOOK)
            set dummy=xecast.createBasicA(SHRINKID,BLOODLUST,GetOwningPlayer(caster))
            set dummy.level=lvl
            call dummy.castOnTarget(target)
            set data=DarkCurse.create()
            set data.caster=caster
            set data.target=target
            set data.lvl=lvl
            set data.disarmed=false
            set data.moved=false
            set data.end=NewTimer()
            set DarkCurse.CurseTable[target]=data
            // Two possibilities: If the target is a hero or not
            if IsUnitSpellResistant(target) then
                call TimerStart(data.end,HERODURATION[lvl],false,function DarkCurse.EndSpell)
                call ABuffApply(buffType,target,caster,HERODURATION[lvl],lvl,data)
            else
                call TimerStart(data.end,DURATION[lvl],false,function DarkCurse.EndSpell)
                call ABuffApply(buffType,target,caster,DURATION[lvl],lvl,data)
            endif
            set DarkCurse.CurseTable[data.end]=data
            set data.damage=CreateTrigger()
            call TriggerRegisterUnitEvent(data.damage,target,EVENT_UNIT_DAMAGED)
            call TriggerAddCondition(data.damage,Condition(function DarkCurse.DisarmTarget))
            set DarkCurse.CurseTable[data.damage]=data
        else
            set dummy=xecast.createBasicA(SHRINKID,BLOODLUST,GetOwningPlayer(caster))
            set dummy.level=lvl
            call dummy.castOnTarget(target)
            set data=DarkCurse.CurseTable[target]
            call PauseTimer(data.end)
            if IsUnitSpellResistant(target) then
                call TimerStart(data.end,HERODURATION[lvl],false,function DarkCurse.EndSpell)
                call ABuffApply(buffType,target,caster,HERODURATION[lvl],lvl,data)
            else
                call TimerStart(data.end,DURATION[lvl],false,function DarkCurse.EndSpell)
                call ABuffApply(buffType,target,caster,DURATION[lvl],lvl,data)
            endif
        endif
        
        set caster=null
        set target=null
    endfunction
    
    private function Init takes nothing returns nothing
        local integer int=0
        loop
            exitwhen int>=bj_MAX_PLAYER_SLOTS
            call SetPlayerAbilityAvailable(Player(int),EFFECTBOOK,false)
            set int=int+1
        endloop
        call SetupSpellVariables()
        call RegisterSpellEffectResponse(ABILID,CurseSpell)
        set DarkCurse.CurseTable=HandleTable.create()
        call XE_PreloadAbility(SHRINKID)
        call XE_PreloadAbility(EFFECTBOOK)
        
        set buffType=aBuffType.create()
        set buffType.eventPeriodic=Dispel
        
        call Preload(CONFUSED)
        call Preload(CONFUSEEFFECT)
        
        call PreloadStart()
    endfunction

endlibrary

Haunting Ghosts
The Dread Lord owns the souls of all dead units in reange nearby. A dead units soul haunts its killer granting a bonus if the killer is an ally of the Dread Lord or reducing its strength if the killer is an enemy. The killer will regain its common strength step by step after a short duration.
The more units are killed by the same, the higher is the Bonus or Reduction.



Jass:
library HauntingGhosts initializer Init needs TimerUtils, GroupUtils, UnitMaxState, AutoIndex, StatusModifier, Rounding, TimedHandles, SpellEvent
//*******************************************************************************************\\
//*******************************************************************************************\\
//*                                Haunting Ghosts By Inferior                              *\\
//*                                                                                         *\\
//*                                          v1.1                                           *\\
//*                                                                                         *\\
//*                                 *************************                               *\\
//*                                 * Requirements:         *                               *\\
//*                                 * - JassNewGenPack      *                               *\\
//*                                 * - TimerUtils          *                               *\\
//*                                 * - GroupUtils          *                               *\\
//*                                 * - UnitMaxState        *                               *\\
//*                                 * - AutoIndex           *                               *\\
//*                                 * - StatusModifier      *                               *\\
//*                                 * - Rounding            *                               *\\
//*                                 * - TimedHandles        *                               *\\
//*                                 * - SpellEvent          *                               *\\
//*                                 *************************                               *\\
//*                                                                                         *\\
//*                                                                                         *\\
//*                                                                                         *\\
//* How To Import:                                                                          *\\
//* - Copy the Spell called 'Haunting Ghosts' into your map                                 *\\
//* - Copy the whole Triggerscript into your map                                            *\\
//* - Now change the values of the 'ABILID' and 'DECAYTIME' to the Values in your map       *\\
//*                                                                                         *\\
//*    Spelldescription:                                                                    *\\
//*    The Caster owns over the souls of the dead units nearby. For each Unit the Killer    *\\
//*    of that unit gains a life and damage bonus over a short duration. If the Killer is   *\\
//*    an enemy of the Caster its MaxLife is reduced and its damage aswell. If the Killer   *\\
//*    is an ally its MaxLife and damage are increased. The MaxLife of the Killer           *\\
//*    regenerates to its default after a specific duration. The regeneration has its       *\\
//*    own duration. The more units were killed by one unit the higher is the bonus the     *\\
//*    Killer gains.                                                                        *\\
//*                                                                                         *\\
//*******************************************************************************************\\
//*******************************************************************************************\\
// Globals Setting

    globals
        private constant integer         ABILID         = 'A000'
        // The AbilityId of the MainSpell
        
        private constant real            DECAYTIME      = 88.
        // The time after which bones vanish. Change this to the value found in Map properties of your map
        
        private constant real            TIMERPERIOD    = 0.5
        // Do not set this value lower than 0.2. Does not really influence performance.
        // The matter is that you cannot decrease the Health by less than 1, that means every decreased Health by 0.00 up to 0.9999 will be 1
        
        private constant string          SOULEFFECT     = "Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl"
        private constant string          HAUNTEFFECT    = "Abilities\\Spells\\Orc\\EtherealForm\\SpiritWalkerChange.mdl"
        private constant string          HAUNTATTACH    = "origin"
        private constant string          LEACHEFFECT    = "Abilities\\Spells\\NightElf\\shadowstrike\\shadowstrike.mdl"
        private constant string          LEACHATTACH    = "overhead"
        
        private constant boolean         MORETHANONCE   = false
        // Allows dead units to give bonus or leached Health and Damage more than once.
        
        // For Descriptions for the following Variables see below
        private          real      array HPLEACHED
        private          integer   array DMGLEACHED
        private          real      array ADDLEACH  
        private          real      array DURATION
        private          real      array REGAINDURATION
        private          real      array AOE
        
        
    // Do not touch the following
        
        private          unit            TEMPUNIT
        private          timer           TEMPTIMER
        private          unit      array KILLERUNIT
        
        // Only used if MORETHANONCE=false
        private          boolean   array ALLREADYUSED
    endglobals
    
    
    private function SetupSpellVariables takes nothing returns nothing
        // The Healthpoints leached or added for each killed unit
        set HPLEACHED[1]=5.
        set HPLEACHED[2]=15.
        set HPLEACHED[3]=30.
        set HPLEACHED[4]=50.
        
        set DMGLEACHED[1]=2
        set DMGLEACHED[2]=3
        set DMGLEACHED[3]=4
        set DMGLEACHED[4]=5
        
        // A bonus of leached or added Healthpoints, the more units were killed
        set ADDLEACH[1]=0.
        set ADDLEACH[2]=10.
        set ADDLEACH[3]=25.
        set ADDLEACH[4]=45.
        set ADDLEACH[5]=70.
        set ADDLEACH[6]=100.
        
        // The Duration until the Healthpoints fall down
        set DURATION[1]=5.
        set DURATION[2]=6.
        set DURATION[3]=7.
        set DURATION[4]=8.
        
        // The Duration after which the origin Health is reached
        set REGAINDURATION[1]=3.
        set REGAINDURATION[2]=6.
        set REGAINDURATION[3]=9.
        set REGAINDURATION[4]=12.
        
        // The Spells Area of Effect
        set AOE[1]=550.                 
        set AOE[2]=625.
        set AOE[3]=700.
        set AOE[4]=800.
    endfunction
    
    
    // DO NOT TOUCH ANYTHING BELOW THIS COMMENT, ALTHOUGH YOU KNOW WHAT YOU DO.
    // HERE BEGINS THE SPELLS SCRIPT.
    
    
    // This two functions save the Killer of a dying Unit, because we need to know the Killer.
    // So we save the Killer in an Unit array. Now we use the AutoIndex so we can easily say that this unit
    // was killed by that unit. We Refresh this value when the unit is removed from the map. That means when its bones vanish
    // So you have to Change the DECAYTIME value to the time after which the bones get removed in your map.
    private function ClearSavedKiller takes nothing returns nothing
        local timer t=GetExpiredTimer()
        set KILLERUNIT[GetTimerData(t)]=null
        call ReleaseTimer(t)
    endfunction

    private function SaveKiller takes nothing returns boolean
        local unit killer=GetKillingUnit()
        local unit dying=GetDyingUnit()
        set KILLERUNIT[GetUnitId(dying)]=killer
        set TEMPTIMER=NewTimer()
        call SetTimerData(TEMPTIMER,GetUnitId(dying))
        call TimerStart(TEMPTIMER,DECAYTIME,false,function ClearSavedKiller)
        set killer=null
        set dying=null
        return false
    endfunction
    
private struct LeachedLife
    unit leached
    real hp
    real health
    real down
    real reg
    integer level
    integer dmg
    real duration
    real factor
    boolean done
    integer counter
    boolean active
    
    static integer count=0
    static timer Timer
    static LeachedLife array Data
    
    method clear takes nothing returns nothing
        set .leached=null
        set .hp=0
        set .health=0
        set .reg=0
        set .level=0
        set .down=0
        set .duration=0
        set .factor=0
        set .done=false
        set .counter=0
        set .active=false
    endmethod
    
    
    // this method resets the MaxLife of a target over a specific time
    static method ResetLife takes nothing returns nothing
        local integer int=0
        local LeachedLife data
        loop
            exitwhen int==.count
            set data=.Data[int]
            if data.active then
                if not data.done and data.duration>0 then
                    set data.duration=data.duration-TIMERPERIOD
                elseif not data.done and data.duration<=0 then
                    set data.done=true
                    set data.duration=REGAINDURATION[data.level]
                    set data.reg=data.hp/data.duration * TIMERPERIOD
                    set data.down=R2I(RealRounding(data.reg+0.5))*data.duration / TIMERPERIOD
                    set data.down=data.hp-data.down 
                    if data.reg<1 then
                        set data.reg=1
                    endif
                elseif data.done and data.duration>0 then
                    call DestroyEffectTimed(AddSpecialEffectTarget(HAUNTEFFECT,data.leached,HAUNTATTACH),1.5)
                    set data.duration=data.duration-TIMERPERIOD
                    set data.health=data.health-data.reg
                    call AddUnitMaxState(data.leached,UNIT_STATE_MAX_LIFE,(data.hp-data.health)*data.factor)
                    set data.hp=data.health
                    if AbsReal(data.down)>data.reg then
                        call AddUnitMaxState(data.leached,UNIT_STATE_MAX_LIFE,data.reg)
                        if data.down>0 then
                            set data.down=data.down-R2I(data.reg)
                        else 
                            set data.down=data.down+R2I(data.reg)
                        endif
                    endif
                    if data.duration==0 then
                        call AddUnitMaxState(data.leached,UNIT_STATE_MAX_LIFE,-data.down)
                    endif
                elseif data.done and data.duration<=0 then
                    call UnitAddDamage(data.leached,-data.dmg)
                    call data.clear()
                endif
            endif
            set int=int+1
        endloop
    endmethod
    
    static method create takes nothing returns LeachedLife
        local LeachedLife data=LeachedLife.allocate()
        if .count==0 then
            set .Timer=NewTimer()
            call TimerStart(.Timer,TIMERPERIOD,true,function LeachedLife.ResetLife)
        endif
        set .Data[.count]=data
        set data.done=false
        set data.active=true
        set .count=.count+1
        return data
    endmethod
    
endstruct
    
private struct Spell
    player caster
    unit killer
    integer level
    integer counter
    real factor
    effect devil
    
    static Spell array Data
    
    method clear takes nothing returns nothing
        call DestroyEffect(.devil)
        set .devil=null
        set .killer=null
        set .caster=null
        set .level=0
        set .factor=0
        set .counter=0
        call .destroy()
    endmethod
        
    // Executed for each killer on Spellcast
    method StartSpell takes nothing returns nothing
        local LeachedLife data=LeachedLife.create()
        set data.leached=.killer
        set data.level=.level
        set data.factor=.factor
        set data.hp=HPLEACHED[.level]*.counter
        set data.dmg=DMGLEACHED[.level]*.counter
        call UnitAddDamage(.killer,data.dmg)
        if .counter>6 then
            set .counter=6 
        endif
        set data.counter=.counter
        set data.hp=data.hp+ADDLEACH[.counter]
        set data.health=data.hp
        set data.down=0
        set data.reg=0
        set data.duration=DURATION[.level]
        call AddUnitMaxState(.killer,UNIT_STATE_MAX_LIFE,data.hp*.factor)
        set data.factor=data.factor*-1
        call .clear()
    endmethod
        
    
    static method create takes nothing returns Spell
        return Spell.allocate()
    endmethod
    
endstruct
    
    // Executed on Spellcast.
    // checks how much dead units are in a specific range and checks who is there killer.
    // If the Killer is an enemy its MaxLife and damage is reduced otherwise it is increased.
    // If the MORETHANONCE variable is set to true, dead units souls can be used more than once by this spell,
    // otherwise they will only once give bonuses.
    private function HauntingSpell takes nothing returns nothing
        local unit caster=SpellEvent.CastingUnit
        local real x=GetUnitX(caster)
        local real y=GetUnitY(caster)
        local unit killer
        local integer int=0
        local Spell data
        call GroupUnitsInArea(ENUM_GROUP,x,y,AOE[GetUnitAbilityLevel(caster,ABILID)])
        loop
            set TEMPUNIT=FirstOfGroup(ENUM_GROUP)
            exitwhen TEMPUNIT==null
            if MORETHANONCE then
                set ALLREADYUSED[GetUnitId(TEMPUNIT)]=false
            endif
            if GetWidgetLife(TEMPUNIT)<0.405 and not ALLREADYUSED[GetUnitId(TEMPUNIT)] then
                call AddSpecialEffect(HAUNTEFFECT,GetUnitX(TEMPUNIT),GetUnitY(TEMPUNIT))
                set killer=KILLERUNIT[GetUnitId(TEMPUNIT)]
                if not IsUnitType(killer,UNIT_TYPE_DEAD) and not IsUnitType(killer,UNIT_TYPE_STRUCTURE) and IsUnitAlly(killer,GetOwningPlayer(caster)) then
                    set data=Spell.Data[GetUnitId(killer)]
                    set ALLREADYUSED[GetUnitId(TEMPUNIT)]=true
                    if data.counter==0 then
                        set data=Spell.create()
                        set data.caster=GetOwningPlayer(caster)
                        set data.killer=killer
                        set data.level=GetUnitAbilityLevel(caster,ABILID)
                        set data.factor=1
                        set data.counter=data.counter+1
                        set Spell.Data[GetUnitId(killer)]=data
                        call DestroyEffect(AddSpecialEffectTarget(SOULEFFECT,killer,HAUNTATTACH))
                    else
                        set data.counter=data.counter+1
                    endif
                elseif not IsUnitType(killer,UNIT_TYPE_DEAD) and not IsUnitType(killer,UNIT_TYPE_STRUCTURE) and IsUnitEnemy(killer,GetOwningPlayer(caster)) then
                    set data=Spell.Data[GetUnitId(killer)]
                    set ALLREADYUSED[GetUnitId(TEMPUNIT)]=true
                    if data.counter==0 then
                        set data=Spell.create()
                        set data.killer=killer
                        set data.devil=AddSpecialEffectTarget(LEACHEFFECT,killer,LEACHATTACH)
                        set data.level=GetUnitAbilityLevel(caster,ABILID)
                        set data.factor=-1
                        set data.counter=data.counter+1
                        set Spell.Data[GetUnitId(killer)]=data
                        call DestroyEffect(AddSpecialEffectTarget(SOULEFFECT,killer,HAUNTATTACH))
                    else
                        set data.counter=data.counter+1
                    endif
                endif
            endif 
            call GroupRemoveUnit(ENUM_GROUP,TEMPUNIT)
        endloop
        call GroupClear(ENUM_GROUP)
        loop
            exitwhen int>8190 
            if Spell.Data[int].counter!=0 then
                call Spell.Data[int].StartSpell()
            endif
            set int=int+1
        endloop
        
        set caster=null
        set killer=null
    endfunction
    
    private function Init takes nothing returns nothing
        local trigger trig=CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddCondition(trig,Condition(function SaveKiller))
        call RegisterSpellEffectResponse(ABILID,HauntingSpell)
        call SetupSpellVariables()
        
        call Preload(SOULEFFECT)
        call Preload(HAUNTEFFECT)
        call Preload(LEACHEFFECT)
        call PreloadStart()
    endfunction
    
endlibrary

Polarisation
The Electrician creates a static link between him and the target unit.The target unit and the Electrician are pulled to the mid between their positions. While they both get pulled the Caster is absorbing the enemies life and converting 40% of it to mana. As long as the target is pulled it is unable to move or attack. After they reached each other the Electrician keeps up the static link, fixing the enemy to his body making the target unable to move out of a specific radius from the Electricians position.


Jass:
library Polarisation initializer Init needs TimerUtils, UnitStatus, SpellEvent
//*******************************************************************************************\\
//*******************************************************************************************\\
//*                                 Polarisation By Inferior                                *\\
//*                                                                                         *\\
//*                                          v1.0                                           *\\
//*                                                                                         *\\
//*                                 *************************                               *\\
//*                                 * Requirements:         *                               *\\
//*                                 * - JassNewGenPack      *                               *\\
//*                                 * - TimerUtils          *                               *\\
//*                                 * - UnitStatus          *                               *\\
//*                                 * - SpellEvent          *                               *\\
//*                                 *************************                               *\\
//*                                                                                         *\\
//*                                                                                         *\\
//*                                                                                         *\\
//* How To Import:                                                                          *\\
//* - Copy the Spell called 'Polarisation' into your map                                    *\\
//* - Copy the whole Triggerscript into your map                                            *\\
//* - Now change the values of the 'ABILID' to the Rawcode of the Mainability in your map   *\\
//*                                                                                         *\\
//*    Spelldescription:                                                                    *\\
//*    The Caster creates a static link between the target and himself absorbing the        *\\
//*    Targets life and converting it to Mana. The Target and the caster are pulled         *\\
//*    to the middle between their positions, while the target is disabled. The Health is   *\\
//*    absorbed during the pullphase. After they reached each other the Caster keeps up the *\\
//*    static link between him and the target. The target is now unable to move farther     *\\
//*    away than the link allows him.                                                       *\\
//*                                                                                         *\\
//*******************************************************************************************\\
//*******************************************************************************************\\
// Globals Setting

    globals
        private constant integer          ABILID        = 'A009'
        // The AbilityId of your Mainability
        
        private constant string           LIGHTNING     = "CHIM"
        // The Lightning Effect of the static link
        
        private constant real             DEFAULTHEIGHT = 50.
        // The Height of the Lightning
        
        private constant real             DEFAULTDIST   = 150.
        // The Minimum Distance which has to be reached until the Pullphase is stopped
        
        private constant real             HEALTHTOMANA  = 0.4
        // The absorbed Health to Mana Factor
        
        private constant real             PULLPERIOD    = 0.025
        // The Timer Period of this Spell
        
        // The 3 following variables are just important for the damage dealt in this spell
        private constant attacktype       ATKTYPE       = ATTACK_TYPE_NORMAL
        private constant damagetype       DMGTYPE       = DAMAGE_TYPE_UNIVERSAL
        private constant weapontype       WPNTYPE       = WEAPON_TYPE_WHOKNOWS
        
        private constant boolean          PULLDOWNAIR   = true
        // Set this to true weather Air units shall be pulled down to the ground.
        
        private constant boolean          CASTERACTION  = true
        // Set this to false weather the caster should be disabled aswell duration the Pullphase
        
        // For Descriptions for the following Variables see below
        private          real       array PULLDURATION
        private          real       array FIXDURATION
        private          real       array MAXRANGE    
        private          real       array DAMAGEDEALT 
    endglobals
    
    
    
    private function SetupSpellVariables takes nothing returns nothing
        // The time in which the target is pulled in the direction of the caster
        set PULLDURATION[1]=1.25
        set PULLDURATION[2]=1.75
        set PULLDURATION[3]=2.25
        set PULLDURATION[4]=3.
        
        // The time how long the target is fixed to the caster by the static link
        set FIXDURATION[1]=1.5
        set FIXDURATION[2]=2.
        set FIXDURATION[3]=2.5
        set FIXDURATION[4]=3.
        
        // The Maximum range the target can move away from the caster with the static link
        set MAXRANGE[1]=600.
        set MAXRANGE[2]=500.
        set MAXRANGE[3]=400.
        set MAXRANGE[4]=300.
        
        // The Damage dealt during the Pullphase
        set DAMAGEDEALT[1]=60.
        set DAMAGEDEALT[2]=125.
        set DAMAGEDEALT[3]=185.
        set DAMAGEDEALT[4]=250.
    endfunction
    
    // DO NOT TOUCH ANYTHING BELOW THIS COMMENT, ALTHOUGH YOU KNOW WHAT YOU DO.
    // HERE BEGINS THE SPELLS SCRIPT.
    
    private struct MagnetPull
        unit caster
        unit target
        real castX
        real castY
        real targX
        real targY
        real duration
        integer level
        lightning light
        
        static integer count=0
        static timer MagnetTimer
        static MagnetPull array Data
        static boolean array done
        
        // checks if the target is to far away from the caster
        // stops the spell when the static link time expires
        static method callback takes nothing returns nothing
            local integer int=0
            local MagnetPull data
            local real dx
            local real dy
            loop
                exitwhen int==.count
                set data=.Data[int]
                if data.duration>0 and not .done[int] and GetWidgetLife(data.target)>0.405 then
                    set dx=data.castX-data.targX
                    set dy=data.castY-data.targY
                    if SquareRoot(dx*dx+dy*dy)>MAXRANGE[data.level] then
                        set data.targX=data.castX-MAXRANGE[data.level]*Cos(Atan2(dy,dx))
                        set data.targY=data.castY-MAXRANGE[data.level]*Sin(Atan2(dy,dx))
                        call SetUnitX(data.target,data.targX)
                        call SetUnitY(data.target,data.targY)
                    else
                        set data.targX=GetUnitX(data.target)
                        set data.targY=GetUnitY(data.target)
                    endif
                    set data.castX=GetUnitX(data.caster)
                    set data.castY=GetUnitY(data.caster)
                    set data.duration=data.duration-PULLPERIOD
                    call MoveLightningEx(data.light,true,data.castX,data.castY,DEFAULTHEIGHT,data.targX,data.targY,DEFAULTHEIGHT)
                elseif data.light!=null and not .done[int] or GetWidgetLife(data.target)<0.405 and not .done[int] then
                    call DestroyLightning(data.light)
                    if PULLDOWNAIR and IsUnitType(data.target,UNIT_TYPE_FLYING) then
                        call SetUnitFlyHeight(data.target,GetUnitDefaultFlyHeight(data.target),100)
                    endif
                    set .done[int]=true
                    call data.destroy()
                endif
                set int=int+1
            endloop
        endmethod
            
        
        static method create takes nothing returns MagnetPull
            local MagnetPull data=MagnetPull.allocate()
            if .count==0 then
                set .MagnetTimer=NewTimer()
                call TimerStart(.MagnetTimer,PULLPERIOD,true,function MagnetPull.callback)
            endif
            set .Data[.count]=data
            set .count=.count+1
            return data
        endmethod
        
    endstruct
    
    private struct PolarPull 
        unit caster
        unit target
        real castX
        real castY
        real targX
        real targY
        real velZ
        real angle
        real distance
        real speed
        integer level
        lightning light
        
        static integer count=0
        static timer PullTimer
        static PolarPull array Data
        static boolean array done
        
        // pulls the target and the caster to they position between each other
        // Flying Units are pulled down if PULLDOWNAIR=true
        // When the Pullphase is over Flying units regain their default height
        static method callback takes nothing returns nothing
            local integer int=0
            local PolarPull data
            local MagnetPull dat
            loop
                exitwhen int==.count
                set data=.Data[int]
                if data.distance>DEFAULTDIST and not .done[int] and GetWidgetLife(data.target)>0.405 then
                    set data.castX=data.castX-data.speed*Cos(data.angle)
                    set data.castY=data.castY-data.speed*Sin(data.angle)
                    call SetUnitX(data.caster,data.castX)
                    call SetUnitY(data.caster,data.castY)
                    set data.targX=data.targX+data.speed*Cos(data.angle)
                    set data.targY=data.targY+data.speed*Sin(data.angle)
                    call SetUnitX(data.target,data.targX)
                    call SetUnitY(data.target,data.targY)
                    call UnitDamageTarget(data.caster,data.target,(DAMAGEDEALT[data.level]/PULLDURATION[data.level])*PULLPERIOD,true,false,ATKTYPE,DMGTYPE,WPNTYPE)
                    call SetUnitState(data.caster,UNIT_STATE_MANA,GetUnitState(data.caster,UNIT_STATE_MANA)+(DAMAGEDEALT[data.level]*HEALTHTOMANA/PULLDURATION[data.level])*PULLPERIOD)
                    if PULLDOWNAIR and IsUnitType(data.target,UNIT_TYPE_FLYING) then
                        call SetUnitFlyHeight(data.target,GetUnitFlyHeight(data.target)-data.velZ,0)
                        call MoveLightningEx(data.light,true,data.castX,data.castY,DEFAULTHEIGHT,data.targX,data.targY,GetUnitFlyHeight(data.target)+DEFAULTHEIGHT)
                    else
                        call MoveLightningEx(data.light,true,data.castX,data.castY,DEFAULTHEIGHT,data.targX,data.targY,DEFAULTHEIGHT)
                    endif
                    set data.distance=data.distance-2*data.speed
                elseif data.distance<=DEFAULTDIST and not .done[int] and GetWidgetLife(data.target)>0.405 then
                    set dat=MagnetPull.create()
                    set dat.caster=data.caster
                    set dat.target=data.target
                    set dat.castX=data.castX
                    set dat.castY=data.castY
                    set dat.targX=data.targX
                    set dat.targY=data.targY
                    set dat.light=data.light
                    set dat.level=data.level
                    set dat.duration=FIXDURATION[data.level]
                    if not CASTERACTION then
                        call DisableUnit(data.caster,false)
                    endif
                    call DisableUnit(data.target,false)
                    set .done[int]=true
                    call data.destroy()
                elseif GetWidgetLife(data.target)<0.405 and not .done[int] then
                    call DestroyLightning(data.light)
                    if not CASTERACTION then
                        call DisableUnit(data.caster,false)
                    endif
                    call DisableUnit(data.target,false)
                    set .done[int]=true
                    call data.destroy()
                endif
                set int=int+1
            endloop
        endmethod
        
        static method create takes nothing returns PolarPull
            local PolarPull data=PolarPull.allocate()
            if .count==0 then
                set .PullTimer=NewTimer()
                call TimerStart(.PullTimer,PULLPERIOD,true,function PolarPull.callback)
            endif
            set .Data[.count]=data
            set .count=.count+1
            return data
        endmethod
    
    endstruct
    
    // Executed on Spellcast
    // Disables the caster when CASTERACTION=false
    private function PolarisationSpell takes nothing returns nothing
        local unit caster=SpellEvent.CastingUnit
        local unit target=SpellEvent.TargetUnit
        local PolarPull data=PolarPull.create()
        local real dx=0.
        local real dy=0.
        set data.caster=caster
        set data.target=target
        set data.castX=GetUnitX(caster)
        set data.castY=GetUnitY(caster)
        set data.targX=GetUnitX(target)
        set data.targY=GetUnitY(target)
        set dx=data.castX-data.targX
        set dy=data.castY-data.targY
        set data.angle=Atan2(dy,dx)
        set data.distance=SquareRoot(dx*dx+dy*dy)
        set data.level=GetUnitAbilityLevel(caster,ABILID)
        set data.speed=(data.distance/PULLDURATION[data.level])*PULLPERIOD*0.5
        call DisableUnit(data.target,true)
        if not CASTERACTION then
            call DisableUnit(data.caster,true)
        endif
        call SetUnitAnimation(data.caster,"spell channel")
        if PULLDOWNAIR and IsUnitType(target,UNIT_TYPE_FLYING) then
            set data.velZ=(GetUnitFlyHeight(target)/PULLDURATION[data.level])*PULLPERIOD
            set data.light=AddLightningEx(LIGHTNING,true,data.castX,data.castY,DEFAULTHEIGHT,data.targX,data.targY,GetUnitFlyHeight(target)+DEFAULTHEIGHT)
        else
            set data.light=AddLightningEx(LIGHTNING,true,data.castX,data.castY,DEFAULTHEIGHT,data.targX,data.targY,DEFAULTHEIGHT)
            set data.velZ=0
        endif
        
        set caster=null
        set target=null
    endfunction
    
    private function Init takes nothing returns nothing
        call RegisterSpellEffectResponse(ABILID,PolarisationSpell)
        call SetupSpellVariables()
    endfunction
    
endlibrary

Magnetic Field
The Electrician releases the electric Energy in his body and creates a strong Magnetic Field arround him. All enemy units nearby are slowed and slightly pulled to the source of the Field. If an enemy unit contacts with the Core of the Field an discharge will shock it. The Shock is reducing its armor by 50%, dealing 5% of the units current Health and pushing it away from the Core. To keep up the Magnetic Field the caster is forced to use his mana and for each discharge the Electrician is losing some mana.


Jass:
library MagneticField initializer Init needs TimerUtils, GroupUtils, LastOrder, ArmorUtils, StatusModifier, Rounding, BoundSentinel, UnitStatus, IsUnitSpellResistant, TimedHandles, xepreload, xedamage
//********************************************************************************************\\
//********************************************************************************************\\
//*                                 Magnetic Field By Inferior                               *\\
//*                                                                                          *\\
//*                                          v1.1                                            *\\
//*                                                                                          *\\
//*                                 **************************                               *\\
//*                                 * Requirements:          *                               *\\
//*                                 * - JassNewGenPack       *                               *\\
//*                                 * - TimerUtils           *                               *\\
//*                                 * - GroupUtils           *                               *\\
//*                                 * - ArmorUtils           *                               *\\
//*                                 * - StatusModifier       *                               *\\
//*                                 * - Rounding             *                               *\\
//*                                 * - BoundSentinel        *                               *\\
//*                                 * - UnitStatus           *                               *\\
//*                                 * - IsUnitSpellResistant *                               *\\
//*                                 * - TimedHandles         *                               *\\
//*                                 * - xepreload            *                               *\\
//*                                 * - xedamage             *                               *\\
//*                                 **************************                               *\\
//*                                                                                          *\\
//*                                                                                          *\\
//*                                                                                          *\\
//* How To Import:                                                                           *\\
//* - Copy the Spell called 'Magnetic Field' and 'Magnet Aura(Slow)' into your map and       *\\
//*   create 2 buffs like those in the Object Editor with 'Magnetic Field' in its name       *\\
//* - Copy the whole Triggerscript into your map                                             *\\
//* - Now change the values of the 'ABILID' and 'SLOWID' to the RawCodes in your map         *\\
//*                                                                                          *\\
//*    Spelldescription:                                                                     *\\
//*    The Caster fills the air arround him with strong static energy, creating a strong     *\\
//*    magnetic Field arround his body that slows every enemy unit and slightly pulls them   *\\
//*    to the caster. If an enemy unit comes in contact with the caster, the unit gets       *\\
//*    shocked, losing an specific amount of its current Life and half of its armor, and     *\\
//*    pushed away. For each contact the caster loses Mana and passively burns Mana over     *\\
//*    Time as long as the Magnetic Field is active.                                         *\\
//*                                                                                          *\\
//********************************************************************************************\\
//********************************************************************************************\\
// Globals Setting

    globals
        private constant integer       ABILID         = 'A00A'
        // The AbilityId of your Mainability
        
        private constant integer       SLOWID         = 'A00B'
        // The AbilityId of your Slowing Aura
        
        private constant integer       ORDERID        = 852177
        // The OrderId to activate the Spell
        
        private constant integer       UNORDERID      = 852178
        // The OrderId to deactive the Spell
        
        private constant real          MAGNETPERIOD   = .025
        // The Timerperiod of this Spell
        
        private constant real          MINDISTANCE    = 120.
        // The Minimum Distance between the caster and an enemy until it gets pushed away
        
        private constant real          SHOCKDAMAGE    = 0.05
        // The percentage of Life an enemy loses on contact
        
        private constant real          ARMORDOWNTIME  = 5.
        // The Time the enemy loses half of its armor
        
        private constant string        IMPACTEFFECT   = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
        private constant string        IMPACTATTACH   = "origin"
        // The Effect on impact
        
        // For Descriptions for the following Variables see below
        private          real    array IMPACTMANABURN
        private          real    array BUFFERMANA  
        private          real    array PUSHDISTANCE
        private          real    array PULLSPEED
        private          real    array PULLRADIUS  
        
        // Do not change any of the following variables
        private          unit          TEMPUNIT
        private          xedamage      dmgOptions
    endglobals
    
    private function MagnetFilter takes nothing returns boolean
        return IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(TEMPUNIT)) and not IsUnitSpellResistant(GetFilterUnit()) and not IsUnitSpellImmune(GetFilterUnit()) and GetWidgetLife(GetFilterUnit())>0.405
    endfunction
    
    private function SetupSpellVariables takes nothing returns nothing
        // The Mana burnt for each Contact with an enemy
        set IMPACTMANABURN[1]=25.
        set IMPACTMANABURN[2]=20.
        set IMPACTMANABURN[3]=15.
        set IMPACTMANABURN[4]=10.
        
        // The Speed with which the enemies are pulled to the caster
        set PULLSPEED[1]=.2
        set PULLSPEED[2]=.3
        set PULLSPEED[3]=.4
        set PULLSPEED[4]=.5
        
        // The Area of Effect of the Magnetic Field
        set PULLRADIUS[1]=400.
        set PULLRADIUS[2]=550.
        set PULLRADIUS[3]=650.
        set PULLRADIUS[4]=800.
        
        // The Distance the enemies are pushed away after contact
        set PUSHDISTANCE[1]=300.
        set PUSHDISTANCE[2]=350.
        set PUSHDISTANCE[3]=400.
        set PUSHDISTANCE[4]=450.
    endfunction
    
    private function ConfigureDamageOptions takes nothing returns nothing
        set dmgOptions=xedamage.create()
        set dmgOptions.atype=ATTACK_TYPE_CHAOS
        set dmgOptions.dtype=DAMAGE_TYPE_UNIVERSAL
        set dmgOptions.wtype=WEAPON_TYPE_WHOKNOWS
    endfunction
    
    // DO NOT TOUCH ANYTHING BELOW THIS COMMENT, ALTHOUGH YOU KNOW WHAT YOU DO.
    // HERE BEGINS THE SPELLS SCRIPT.
    
    private struct MagnetPush
        unit caster
        unit target
        real speed
        real x
        real y
        real angle
        real distance
        integer dec
        integer level
        
        static integer count=0
        static timer PushTimer
        static MagnetPush array Data
        static boolean array done
        
        // pushes the enemies away after contact
        // Disarms them during the Pushphase
        static method callback takes nothing returns nothing
            local integer int=0
            local MagnetPush data
            loop
                exitwhen int==.count
                set data=.Data[int]
                if not .done[int] then
                    if data.distance>0 then
                        set data.x=data.x-data.speed*Cos(data.angle)
                        set data.y=data.y-data.speed*Sin(data.angle)
                        call SetUnitX(data.target,data.x)
                        call SetUnitY(data.target,data.y)
                        set data.distance=data.distance-data.speed
                    else
                        set .done[int]=true
                        call DisarmUnit(data.target,false)
                        call data.destroy()
                    endif
                endif
                set int=int+1
            endloop
        endmethod
    
        static method create takes nothing returns MagnetPush
            local MagnetPush data=MagnetPush.allocate()
            if .count==0 then
                set .PushTimer=NewTimer()
                call TimerStart(.PushTimer,MAGNETPERIOD,true,function MagnetPush.callback)
            endif
            set .done[.count]=false
            set .Data[.count]=data
            set .count=.count+1
            return data
        endmethod
        
    endstruct
    
    private struct MagnetField 
        unit caster
        real speed
        integer level
        
        static integer count=0
        static integer array Index
        static timer MagnetTimer
        static MagnetField array Data
        static boolean array done
        
        // Slightly pulls enemies in range to the caster
        // if they are to near to the caster they get pushed away, disarmed, and lose half of their Armor
        method operator pos= takes unit a returns nothing
            local real x=GetUnitX(a)
            local real y=GetUnitY(a)
            local real dx=GetUnitX(.caster)-x
            local real dy=GetUnitY(.caster)-y
            local real angle=Atan2(dy,dx)
            local MagnetPush data
            set x=x+.speed*Cos(angle)
            set y=y+.speed*Sin(angle)
            call SetUnitX(a,x)
            call SetUnitY(a,y)
            if SquareRoot(dx*dx+dy*dy)<MINDISTANCE then
                set data=MagnetPush.create()
                set data.caster=.caster
                set data.target=a
                set data.level=.level
                set data.x=x
                set data.y=y
                set data.angle=angle
                set data.distance=PUSHDISTANCE[data.level]
                set data.speed=25
                call DisarmUnit(a,true)
                call dmgOptions.damageTarget(data.caster,data.target,GetUnitState(data.target,UNIT_STATE_LIFE)*SHOCKDAMAGE)
                call UnitAddArmorTimed(data.target,-RealRounding(GetUnitArmor(data.target)/2),ARMORDOWNTIME)
                call DestroyEffectTimed(AddSpecialEffectTarget(IMPACTEFFECT,a,IMPACTATTACH),1.5)
                call SetUnitState(data.caster,UNIT_STATE_MANA,GetUnitState(data.caster,UNIT_STATE_MANA)-IMPACTMANABURN[data.level])
            endif
        endmethod
        
        static method callback takes nothing returns nothing
            local integer int=0
            local unit a=null
            local MagnetField data
            loop
                exitwhen int==.count 
                set data=.Data[int]
                if not .done[int] then
                    set TEMPUNIT=data.caster
                    call GroupEnumUnitsInArea(ENUM_GROUP,GetUnitX(data.caster),GetUnitY(data.caster),PULLRADIUS[data.level],Condition(function MagnetFilter))
                    loop
                        set a=FirstOfGroup(ENUM_GROUP)
                        exitwhen a==null
                        set data.pos=a
                        call GroupRemoveUnit(ENUM_GROUP,a)
                    endloop
                    call GroupClear(ENUM_GROUP)
                    set TEMPUNIT=null
                endif
                set int=int+1
                if GetUnitState(data.caster,UNIT_STATE_MANA)<=0 then
                    set .done[.Index[GetUnitId(data.caster)]]=true
                    call UnitRemoveAbility(data.caster,SLOWID)
                    call data.destroy()
                endif
            endloop
            set a=null
        endmethod
        
        static method create takes unit u returns MagnetField
            local MagnetField data=MagnetField.allocate()
            if .count==0 then
                set .MagnetTimer=NewTimer()
                call TimerStart(.MagnetTimer,MAGNETPERIOD,true,function MagnetField.callback)
            endif
            set .Data[.count]=data
            set .Index[GetUnitId(u)]=.count
            set .done[.count]=false
            set .count=.count+1
            return data
        endmethod
    
    endstruct
    
    // Executed on Spellcast
    private function MagnetSpell takes nothing returns boolean
        local unit caster=GetOrderedUnit()
        local MagnetField data
        if GetLastOrderId(caster)==ORDERID then
            set data=MagnetField.create(caster)
            set data.caster=caster
            set data.level=GetUnitAbilityLevel(caster,ABILID)
            set data.speed=PULLSPEED[data.level]
            call UnitAddAbility(data.caster,SLOWID)
            call SetUnitAbilityLevel(data.caster,SLOWID,data.level)
            call UnitAddAbility(data.caster,'A00C')
            call SetUnitAbilityLevel(data.caster,'A00C',2)
        elseif GetLastOrderId(caster)==UNORDERID then
            set data=MagnetField.Data[MagnetField.Index[GetUnitId(caster)]] 
            set MagnetField.done[MagnetField.Index[GetUnitId(caster)]]=true
            call UnitRemoveAbility(data.caster,SLOWID)
            call data.destroy()
        endif
        
        set caster=null
        
        return false
    endfunction
    
    private function Init takes nothing returns nothing
        local trigger trig=CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_ISSUED_ORDER)
        call TriggerAddCondition(trig,Condition(function MagnetSpell))
        
        call ConfigureDamageOptions()
        call SetupSpellVariables()
        call XE_PreloadAbility(SLOWID)
        call Preload(IMPACTEFFECT)
        call PreloadStart()
        
        set trig=null
    endfunction
    
endlibrary

Robot Arms
The Electrician uses his technical knowlegdes to create 3 Robot Arms that act on their own. If the Arm detects an enemy, it moves to that enemy and knocks it out on contact, dealing damage and absorbing the enemies Life. If the Electrician moves out of the enemies Range the Arm moves back. After every action, the Arms have to move back into their default Position.


Jass:
library RobotArms initializer Init needs Table, GroupUtils, TimerUtils, ABuff, ABuffHeroSkill, BoundSentinel, UnitStatus, IsUnitSpellResistant, xebasic, xefx, xedamage, Rounding
//********************************************************************************************\\
//********************************************************************************************\\
//*                                   Robot Arms By Inferior                                 *\\
//*                                                                                          *\\
//*                                          v1.3                                            *\\
//*                                                                                          *\\
//*                                 **************************                               *\\
//*                                 * Requirements:          *                               *\\
//*                                 * - JassNewGenPack       *                               *\\
//*                                 * - Table                *                               *\\
//*                                 * - GroupUtils           *                               *\\
//*                                 * - TimerUtils           *                               *\\
//*                                 * - ABuff                *                               *\\
//*                                 * - ABuffHeroSkill       *                               *\\
//*                                 * - BoundSentinel        *                               *\\
//*                                 * - UnitStatus           *                               *\\
//*                                 * - IsUnitSpellResistant *                               *\\
//*                                 * - xebasic              *                               *\\
//*                                 * - xefx                 *                               *\\
//*                                 * - xedamage             *                               *\\
//*                                 * - Rounding             *                               *\\
//*                                 **************************                               *\\
//*                                                                                          *\\
//*                                                                                          *\\
//*                                                                                          *\\
//* How To Import:                                                                           *\\
//* - Copy the Spell called 'Robot Arms', the dummy called facingdummy into your map         *\\
//*   and import the "fdummy.mdl" and "RoboticArmsHand" included in this map into yours      *\\
//* - Copy the whole Triggerscript into your map                                             *\\
//* - Change the model of your new Dummymodel and change the RawCodes of the ABILID          *\\
//*   and CHAINID to the Rawcodes in your map                                                *\\
//*                                                                                          *\\
//*    Spelldescription:                                                                     *\\
//*    The Electrician uses his technical knowlegdes to create 3 Robot Arms that act on      *\\
//*    their own. If the Arm detects an enemy, it moves to that enemy and knocks it out on   *\\
//*    contact, dealing absorbing the enemies Life. If the Electrician moves out of the      *\\
//*    enemies Range the Arm moves back. After every action, the Arms have to move back into *\\
//*    their default Position.                                                               *\\
//*                                                                                          *\\
//********************************************************************************************\\
//********************************************************************************************\\
// Globals Setting

    globals
        private constant integer        ABILID          = 'A003'
        // The AbilityId of your Main Ability
        
        private constant integer        CHAINID         = 'e001'
        // The Rawcode for your dummy. This dummy needs a specific model included in that map. You need this model if you want the full eyecandy
        
        private constant integer        MAXARMS         = 3
        // The Number of Arms. The more arms you use, the higher is the performance lack.
        
        private constant integer        CHAINPARTS      = 16
        // The Parts of Dummies for the Chain of the arm. Do not forget to change the .chain array in the struct.
        
        private constant real           CHAINSIZE       = 1.3
        // The Size of the Chain parts
        
        private constant real           ARMSPEED        = 12.
        // The Speed an arm is moving back or to a target
        
        private constant real           DMGTOHEALTH     = 1.
        // Conversionfactor from damage dealt to absorbed Health. This value is only active if USEABSORB = true
        
        private constant real           HEALTHFACTOR    = 0.05
        // The Factor of the targets MaxHealth that is absorbed. This value is only active if USEABSORB = true
        
        private constant real           DEALTDAMAGE     = 1.5 
        // Damage dealt per Period: 0.025*40=1 -> 40*1.5= 60 damage dealt per second. This value is only active if USEABSORB = false
        
        private constant real           DETECTIONRADIUS = 500.
        // The Radius in which an Arm detects an enemy
        
        private constant real           DEFAULTOFFSET   = 250.
        // The Default offset from the Electricians Position. Also defines the DefaultPosition where the arms move back to
        
        private constant real           DEFAULTHEIGHT   = 75.
        // The Default Height of the Chains
        
        private constant real           MAXHEIGHT       = 350.
        // The Maximum Height that can be reached by the arm
        
        private constant real           MINHEIGHT       = 150.
        // The Minimum Height that can be reached by the arm
        
        private constant real           MAXOFFSET       = 750.
        // The Maximum Range an arm can bent
        
        private constant string         CHAINMDL        = "RoboticArmsHand.mdx"
        // The Chains Model effect
        
        private constant string         CHAINATTACH     = "origin"
        // DO NOT CHANGE THIS (the dummy model has no other attachement)
        
        private constant string         CHAINHAND       = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
        // The End of the Arms effect
        
        private constant string         ABSORBMDL       = "Abilities\\Spells\\Undead\\AbsorbMana\\AbsorbManaBirthMissile.mdl"
        // The Effect that is used if USEABSORB = true
        
        private constant boolean        USEABSORB       = true
        // This value defines the type of damage that is dealt. if USEABSORB = false then the damage is dealt periodicly.
        // For more informations check the .OnAbsorb method.
        
        private          real     array SHOCKTIME
        // The Value that defines the time an arm deals damage to a target.
        
        // DO NOT CHANGE THIS. Defines the Damage types.
        private          xedamage       dmgOptions
        // DO NOT CHANGE THIS.
        private          unit           TEMPUNIT
        private constant integer        StunCode        = 'BPSE'
    endglobals
    
    private keyword Arm
    
    
    private function SetupSpellVariables takes nothing returns nothing
        set SHOCKTIME[1]=1.5
        set SHOCKTIME[2]=2.
        set SHOCKTIME[3]=2.75
        set SHOCKTIME[4]=3.5
    endfunction
    
    private function ConfigureDamageOptions takes nothing returns nothing
        set dmgOptions=xedamage.create()
        set dmgOptions.atype=ATTACK_TYPE_CHAOS
        set dmgOptions.dtype=DAMAGE_TYPE_UNIVERSAL
        set dmgOptions.wtype=WEAPON_TYPE_WHOKNOWS
    endfunction
    
    private function UnitFilter takes nothing returns boolean
        return IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(TEMPUNIT)) and IsUnitType(GetFilterUnit(),UNIT_TYPE_GROUND) and not IsUnitSpellImmune(GetFilterUnit()) and not Arm.stunned[GetUnitId(GetFilterUnit())] and GetWidgetLife(GetFilterUnit())>0.405 and GetUnitTypeId(GetFilterUnit())!=CHAINID
    endfunction
    
    // DO NOT TOUCH ANYTHING BELOW THIS COMMENT, ALTHOUGH YOU KNOW WHAT YOU DO.
    // HERE BEGINS THE SPELLS SCRIPT.
    
    private function AngleConv takes real angle returns real
        local integer factor=0
        if angle>=360 then
            set factor=R2I(angle/360)
            return angle-360*factor
        elseif angle<0 then
            set factor=R2I(AbsReal(angle)/360)
            return angle+360*(factor+1)
        endif
        return angle
    endfunction
    
    private function HeightCalc takes real d returns real
        return ((MINHEIGHT-MAXHEIGHT+DEFAULTHEIGHT)/MAXOFFSET)*d+MAXHEIGHT-DEFAULTHEIGHT
    endfunction
    
    // This function defines the Arm parts height
    private function ArmHeight takes real d, integer z returns real
        return HeightCalc(d)*Sin( bj_PI/CHAINPARTS * z ) + DEFAULTHEIGHT
    endfunction 
    
    // Defines the Arm parts Z-Facing.
    // THIS FUNCTION STILL NEEDS PERFECTION. IM STILL SEARCHING FOR A BETTER FORMULA
    private function UnitZFacing takes unit u, real d, integer z returns nothing
        local real s=(MAXHEIGHT-(MAXHEIGHT-MINHEIGHT)/2)/HeightCalc(d)
        local real a=s*HeightCalc(d) * bj_PI/CHAINPARTS * Cos(bj_PI/CHAINPARTS * z)
        local boolean b=a<0
        local integer v=RealRounding(AbsReal(a))
        if not b then
            call SetUnitAnimationByIndex(u,v)
        else
            call SetUnitAnimationByIndex(u,252-v)
        endif
    endfunction
    
    
    // Defines an arms Defaultpositions Facing
    private constant function Angles takes integer int returns real
        return 360./MAXARMS * int
    endfunction
    
    
    private struct Arm
        unit caster
        unit array chain[17] // Add here the value of the CHAINPARTS + 1
        unit hand
        unit targ
        integer pos=CHAINPARTS
        integer phase=0
        // 0=search after an enemy
        // 1=haunt an enemy
        // 2=shock an enemy
        // 3=out of range
        real angle
        real startangle
        real offset
        real timed
        
        xefx absorb 
        // this effect is only used if USEABSORB = true
        
        readonly integer index
        
        static integer count=0
        static boolean array done
        static boolean array stunned
        static timer ArmTimer
        static Arm array Data
        static Table array ArmTable
        static Table array HTable
        
        // You may change this function if you want.
        method OnAbsorb takes nothing returns nothing
            if USEABSORB then
                // the time between these too actions is proportional to the number of Chainparts
                if .pos==CHAINPARTS then
                    // this is executed when the Absorption effect runs off the target.
                    call dmgOptions.damageTarget(.caster,.targ,GetUnitState(.targ,UNIT_STATE_MAX_LIFE)*HEALTHFACTOR)
                elseif .pos<0 then
                    // this is executed when the Absorption effect reaches the caster
                    call SetWidgetLife(.caster,GetWidgetLife(.caster)+GetUnitState(.targ,UNIT_STATE_MAX_LIFE)*HEALTHFACTOR*DMGTOHEALTH)
                endif
            else
                // this is executed when USEABSORB=false
                // this is executed once per Timerperiod: every 0.025 seconds
                call dmgOptions.damageTarget(.caster,.targ,DEALTDAMAGE)
            endif
        endmethod
            
        // destroys the Arm on Casters death or Unlearning of the MainAbility
        method KillArm takes nothing returns boolean
            local integer int=0
            loop
                exitwhen int>CHAINPARTS
                call KillUnit(.chain[int])
                set int=int+1
            endloop
            call KillUnit(.hand)
            return true
        endmethod
        
        // sets an Arms Position and the parts Height and facing
        method PosNormal takes real offset returns nothing
            local real dx=GetUnitX(.hand)-GetUnitX(.caster)
            local real dy=GetUnitY(.hand)-GetUnitY(.caster)
            local integer i=0
            local real step=0.
            set .offset=offset
            set .angle=Atan2(dy,dx)
            if .offset>MAXOFFSET then
                set .offset=MAXOFFSET
            endif
            set step=.offset/CHAINPARTS
            loop
                exitwhen i>CHAINPARTS
                call SetUnitX(.chain[i],GetUnitX(.caster)+step*i*Cos(.angle))
                call SetUnitY(.chain[i],GetUnitY(.caster)+step*i*Sin(.angle))
                call SetUnitFacing(.chain[i],.angle*180/bj_PI)
                call SetUnitFlyHeight(.chain[i],ArmHeight(.offset,i),0)
                set i=i+1
            endloop
            call SetUnitX(.hand,GetUnitX(.chain[CHAINPARTS]))
            call SetUnitY(.hand,GetUnitY(.chain[CHAINPARTS]))
            call SetUnitFlyHeight(.hand,GetUnitFlyHeight(.chain[CHAINPARTS]),0)
        endmethod
        
        // Creates an arm on Casters revive or Learning of the Ability
        method createChain takes nothing returns nothing
            local real x=GetUnitX(.caster)
            local real y=GetUnitY(.caster)
            local integer count=CHAINPARTS
            local real dx=.offset/count
            local integer int=0
            loop
                exitwhen int>count
                set .chain[int]=CreateUnit(GetOwningPlayer(.caster),CHAINID,x,y,.angle)
                call SetUnitScale(.chain[int],CHAINSIZE,CHAINSIZE,CHAINSIZE)
                call SetUnitTimeScale(.chain[int],0.)
                call UnitZFacing(.chain[int],.offset,int)
                call UnitAddAbility(.chain[int],XE_HEIGHT_ENABLER)
                call UnitRemoveAbility(.chain[int],XE_HEIGHT_ENABLER)
                call SetUnitX(.chain[int],x+dx*Cos(.angle*bj_PI/180)*int)
                call SetUnitY(.chain[int],y+dx*Sin(.angle*bj_PI/180)*int)
                call SetUnitFlyHeight(.chain[int],ArmHeight(.offset,int),0)
                call AddSpecialEffectTarget(CHAINMDL,.chain[int],CHAINATTACH)
                set int=int+1
            endloop
            set .hand=CreateUnit(GetOwningPlayer(.caster),CHAINID,GetUnitX(.chain[CHAINPARTS]),GetUnitY(.chain[CHAINPARTS]),.angle)
            call UnitAddAbility(.hand,XE_HEIGHT_ENABLER)
            call UnitRemoveAbility(.hand,XE_HEIGHT_ENABLER)
            call SetUnitFlyHeight(.hand,GetUnitFlyHeight(.chain[CHAINPARTS]),0)
            call AddSpecialEffectTarget(CHAINHAND,.hand,CHAINATTACH)
        endmethod
        
        static method callback takes nothing returns nothing
            local integer int=0
            local Arm data
            local group g
            local unit a
            local real dx
            local real dy
            loop
                exitwhen int==Arm.count
                if not Arm.done[int] then
                    set data=Arm.Data[int]
                    
                    // Searchs possible targets for the Arm
                    if data.phase==0 then
                    
                        set TEMPUNIT=data.caster
                        call GroupEnumUnitsInArea(ENUM_GROUP,GetUnitX(data.hand),GetUnitY(data.hand),DETECTIONRADIUS,Condition(function UnitFilter))
                        set data.targ=GroupPickRandomUnit(ENUM_GROUP)
                        set TEMPUNIT=null
                        
                        call GroupClear(ENUM_GROUP)
                        
                        if data.targ!=null then
                            set data.phase=1
                        else
                            set data.angle=GetUnitFacing(data.caster)+data.startangle
                            call SetUnitX(data.hand,GetUnitX(data.caster)+DEFAULTOFFSET*Cos(data.angle*bj_DEGTORAD))
                            call SetUnitY(data.hand,GetUnitY(data.caster)+DEFAULTOFFSET*Sin(data.angle*bj_DEGTORAD))
                            call data.PosNormal(DEFAULTOFFSET)
                        endif
                        
                    // Moves the Arm to an target. If the target is out of range the arm moves back into DefaultPosition
                    elseif data.phase==1 then
                    
                        set dx=GetUnitX(data.targ)-GetUnitX(data.hand)
                        set dy=GetUnitY(data.targ)-GetUnitY(data.hand)
                        set data.angle=Atan2(dy,dx)
                        call SetUnitX(data.hand,GetUnitX(data.hand)+ARMSPEED*Cos(data.angle))
                        call SetUnitY(data.hand,GetUnitY(data.hand)+ARMSPEED*Sin(data.angle))
                        set dx=GetUnitX(data.hand)-GetUnitX(data.caster)
                        set dy=GetUnitY(data.hand)-GetUnitY(data.caster)
                        set data.angle=Atan2(dy,dx)
                        set data.offset=SquareRoot(dx*dx+dy*dy)
                        call data.PosNormal(data.offset)
                        
                        if data.offset>=MAXOFFSET then
                            set data.phase=3
                        endif
                        
                        if Arm.stunned[GetUnitId(data.targ)] then
                            set data.phase=3
                        else
                            if IsUnitInRange(data.hand,data.targ,5.0) then
                                call SetUnitX(data.hand,GetUnitX(data.targ))
                                call SetUnitY(data.hand,GetUnitY(data.targ))
                                set dx=GetUnitX(data.hand)-GetUnitX(data.caster)
                                set dy=GetUnitY(data.hand)-GetUnitY(data.caster)
                                set data.angle=Atan2(dy,dx)
                                set data.offset=SquareRoot(dx*dx+dy*dy)
                                if data.offset>MAXOFFSET then
                                    set data.phase=3
                                else
                                    call data.PosNormal(data.offset)
                                    call StunUnit(data.targ,true)
                                    set Arm.stunned[GetUnitId(data.targ)]=true
                                    set data.phase=2
                                    if USEABSORB then
                                        set data.absorb=xefx.create(GetUnitX(data.chain[.chain.size]),GetUnitY(data.chain[.chain.size]),GetUnitFacing(data.chain[.chain.size]))
                                        set data.absorb.fxpath=ABSORBMDL
                                    endif
                                endif
                            endif
                        endif
                        
                    // If the arm reached an enemy, the enemy is stunned and is sucked hp or damaged based on the USEABSORB value.
                    // The Arm moves back to default Position if the target moves out of range, or the Buff on the target is removed.
                    elseif data.phase==2 then
                        set dx=GetUnitX(data.targ)-GetUnitX(data.caster)
                        set dy=GetUnitY(data.targ)-GetUnitY(data.caster)
                        set data.angle=Atan2(dy,dx)
                        set data.offset=SquareRoot(dx*dx+dy*dy)
                        
                        if data.offset>=MAXOFFSET then
                            set data.phase=3
                            call StunUnit(data.targ,false)
                            set Arm.stunned[GetUnitId(data.targ)]=false
                            set data.timed=0
                            set data.pos=CHAINPARTS
                            set data.targ=null
                            if USEABSORB then
                                call data.absorb.hiddenDestroy()
                            endif
                        else
                            call SetUnitX(data.hand,GetUnitX(data.targ))
                            call SetUnitY(data.hand,GetUnitY(data.targ))
                            call data.PosNormal(data.offset)
                            set data.timed=data.timed+0.025
                            if USEABSORB then
                                set data.absorb.x=GetUnitX(data.chain[data.pos])
                                set data.absorb.y=GetUnitY(data.chain[data.pos])
                                set data.absorb.z=GetUnitFlyHeight(data.chain[data.pos])
                                if data.pos<0 then
                                    call data.absorb.hiddenDestroy()
                                    call data.OnAbsorb()
                                    set data.pos=CHAINPARTS
                                    set data.absorb=xefx.create(GetUnitX(data.chain[.chain.size]),GetUnitY(data.chain[.chain.size]),GetUnitFacing(data.chain[.chain.size]))
                                    set data.absorb.fxpath=ABSORBMDL
                                endif
                                if data.pos==CHAINPARTS then
                                    call data.OnAbsorb()
                                endif
                            else
                                call data.OnAbsorb()
                            endif
                            set data.pos=data.pos-1
                            if data.timed>SHOCKTIME[GetUnitAbilityLevel(data.caster,ABILID)] or GetWidgetLife(data.targ)<0.405 then
                                set data.phase=3
                                call StunUnit(data.targ,false)
                                set Arm.stunned[GetUnitId(data.targ)]=false
                                set data.timed=0
                                set data.pos=CHAINPARTS
                                if USEABSORB then
                                    call data.absorb.hiddenDestroy()
                                endif
                            else
                                call data.PosNormal(data.offset)
                            endif
                        endif
                        
                    // Moves the Arm back to DefaultPosition
                    elseif data.phase==3 then
                    
                        set dx=GetUnitX(data.hand)-GetUnitX(data.caster)-DEFAULTOFFSET*Cos((GetUnitFacing(data.caster)+data.startangle)*bj_DEGTORAD)
                        set dy=GetUnitY(data.hand)-GetUnitY(data.caster)-DEFAULTOFFSET*Sin((GetUnitFacing(data.caster)+data.startangle)*bj_DEGTORAD)
                        set data.angle=Atan2(dy,dx)
                        call SetUnitX(data.hand,GetUnitX(data.hand)-ARMSPEED*Cos(data.angle))
                        call SetUnitY(data.hand,GetUnitY(data.hand)-ARMSPEED*Sin(data.angle))
                        set dx=GetUnitX(data.caster)+DEFAULTOFFSET*Cos((GetUnitFacing(data.caster)+data.startangle)*bj_DEGTORAD)
                        set dy=GetUnitY(data.caster)+DEFAULTOFFSET*Sin((GetUnitFacing(data.caster)+data.startangle)*bj_DEGTORAD)
                        if IsUnitInRangeXY(data.hand,dx,dy,10) then
                            set data.phase=0
                            set data.targ=null
                            set data.offset=DEFAULTOFFSET
                        else
                            set dx=GetUnitX(data.hand)-GetUnitX(data.caster)
                            set dy=GetUnitY(data.hand)-GetUnitY(data.caster)
                            set data.angle=Atan2(dy,dx)
                            set data.offset=SquareRoot(dx*dx+dy*dy)
                            call data.PosNormal(data.offset)
                        endif
                    endif
                endif
                set int=int+1
            endloop
        endmethod
        
        static method create takes nothing returns Arm
            local Arm data=Arm.allocate()
            if Arm.count==0 then
                set Arm.ArmTimer=NewTimer()
                call TimerStart(Arm.ArmTimer,0.025,true,function Arm.callback)
            endif
            set data.index=Arm.count
            set Arm.Data[Arm.count]=data
            set Arm.done[Arm.count]=false
            set Arm.count=Arm.count+1
            return data
        endmethod
    endstruct
    
    globals
        private aBuffType buffType = 0
    endglobals
    
    private function AbilLearn takes aBuff buffType returns nothing
        local integer int=0
        local Arm data
        if Arm.HTable[GetHandleId(buffType.caster)][int]==0 then
            if Arm.ArmTable[buffType]==0 then
                set Arm.ArmTable[buffType]=Table.create()
            endif
            loop
                exitwhen int==MAXARMS
                set Arm.HTable[GetHandleId(buffType.caster)][int]=Table.create()
                set data=Arm.create()
                set Arm.ArmTable[buffType][int]=data
                set data.caster=buffType.caster
                set data.angle=GetUnitFacing(data.caster)+Angles(int)
                set data.startangle=Angles(int)
                set data.offset=DEFAULTOFFSET
                set Arm.HTable[GetHandleId(buffType.caster)][int]=data
                call data.createChain()
                set int=int+1
            endloop
        else 
            loop
                exitwhen int==MAXARMS
                set data=Arm.HTable[GetHandleId(buffType.caster)][int]
                set Arm.done[data.index]=false
                set data.angle=GetUnitFacing(data.caster)+Angles(int)
                set data.startangle=Angles(int)
                set data.offset=DEFAULTOFFSET
                call data.createChain()
                set int=int+1
            endloop
        endif
        
    endfunction
    
    private function CleanArms takes aBuff buffType returns nothing
        local integer int=0
        local Arm data
        loop
            exitwhen int==MAXARMS
            set data=Arm.ArmTable[buffType][int]
            call data.KillArm()
            set Arm.done[data.index]=true
            set int=int+1
        endloop
    endfunction

    private function Init takes nothing returns nothing
        set buffType=aBuffType.create()
        set buffType.eventCreate=AbilLearn
        set buffType.eventCleanup=CleanArms
        set buffType.countsAsBuff=false
        call NewABuffHeroSkill(ABILID,buffType)
        call SetupSpellVariables()
        call ConfigureDamageOptions()
        
        call Preload(CHAINMDL)
        call Preload(CHAINHAND)
        call Preload(ABSORBMDL)
        call PreloadStart()
    endfunction

endlibrary

I know i should upload a screenshot and i'll do it fast as i can, but i hope you understand that its hard to make a sreenshot of 5 spells.

Anyway i hope you enjoy that pack.

~Inferior

PS: I know my english is bad :P
Rating - 5.00 (1 vote)
(Hover and click)
Moderator Comments
Not Rated
09:31, 3rd Jun 2010
The_Reborn_Devil:

The coding looks decent, but I did notice something in the library MathFuncs. Your rounding function is way to complicated and it's not actually a bug you're correcting. This is how it is with every programming language and scripting language.
Now, to the point, your rounding function could look like this:
code

Jass:
function RealRounding takes real r returns integer
    return R2I(r+0.5)
endfunction

Simple as that. I won't reject it for something as silly as that, but it's at least something you can fix in further updates. What I did find, however, was that sometimes the robot arms remained extended after they had attacked a unit and refused to attack new units. This is something you really should fix. The other spells look good.


Status: Rejected until updated
Rating:N/A

PM me or another mod once you've updated this to get it reviewed again. Have a nice day!

This spell has not been approved in the resource section and is not guaranteed to be working.


Click here to download Inferior Spellpack.w3x (255.85 KB, 580 Downloads)

Old 02-19-2010, 05:54 PM   #2 (permalink)
Registered User Catch_ya
ALUNDRA
 
Catch_ya's Avatar
 
Join Date: May 2009
Posts: 921
Catch_ya has a spectacular aura about (137)Catch_ya has a spectacular aura about (137)Catch_ya has a spectacular aura about (137)Catch_ya has a spectacular aura about (137)
Good job! Alot of changeable globals. Also im glad this ain't GUI. At the moment im still learning vJass so I wont comment the code. But it looks clean and I did not find any BJ (other than the event of course).
By the way can someone tell me what the difference is between "library needs blahblah" and "library requires blahblah"?

5/5
__________________
I hate people who call warcraft stuff for "sexy" or "hot".
Catch_ya is online now   Reply With Quote
Old 02-19-2010, 06:00 PM   #3 (permalink)
Registered User Inferior
"-Dota Suxx-"
 
Inferior's Avatar
 
Join Date: Nov 2008
Posts: 58
Inferior has little to show at this moment (16)Inferior has little to show at this moment (16)
Thx that you like it

To your question:
Quote:
Originally Posted by Catch_ya View Post
By the way can someone tell me what the difference is between "library needs blahblah" and "library requires blahblah"?
There are 3 keywords: 'requires','needs' and 'uses'. There is no difference between them as far as i know. Its imo just a matter of style.
__________________
My Spellpack
Inferior is online now   Reply With Quote
Old 02-19-2010, 06:04 PM   #4 (permalink)
Registered User krisserz
...
 
Join Date: Feb 2009
Posts: 2,326
krisserz is just really nice (364)krisserz is just really nice (364)krisserz is just really nice (364)krisserz is just really nice (364)
Umm, well. Does it work with the newest patch? For me it doesn`t...
krisserz is offline   Reply With Quote
Old 02-19-2010, 06:06 PM   #5 (permalink)
Registered User Inferior
"-Dota Suxx-"
 
Inferior's Avatar
 
Join Date: Nov 2008
Posts: 58
Inferior has little to show at this moment (16)Inferior has little to show at this moment (16)
Hmm, dont know. It works for me and as it seems it worked for Catch_ya aswell
Inferior is online now   Reply With Quote
Old 02-19-2010, 06:07 PM   #6 (permalink)
Registered User krisserz
...
 
Join Date: Feb 2009
Posts: 2,326
krisserz is just really nice (364)krisserz is just really nice (364)krisserz is just really nice (364)krisserz is just really nice (364)
From his comment I guess he told about the code on the site.
krisserz is offline   Reply With Quote
Old 02-19-2010, 06:07 PM   #7 (permalink)
Registered User Catch_ya
ALUNDRA
 
Catch_ya's Avatar
 
Join Date: May 2009
Posts: 921
Catch_ya has a spectacular aura about (137)Catch_ya has a spectacular aura about (137)Catch_ya has a spectacular aura about (137)Catch_ya has a spectacular aura about (137)
Works fine for me. Try re-downloading. Maybe that will help.
__________________
I hate people who call warcraft stuff for "sexy" or "hot".
Catch_ya is online now   Reply With Quote
Old 02-19-2010, 06:39 PM   #8 (permalink)
Registered User hell gate
misses the :cgrin: guy
 
hell gate's Avatar
 
Join Date: Nov 2008
Posts: 549
hell gate will become famous soon enough (112)hell gate will become famous soon enough (112)hell gate will become famous soon enough (112)
it doesn't work for me too (to get it work open it with new gem we and save it but i'm too lazy :P)
__________________
Projects:

Diablo 3 New Tristram (leader is Booody)
Diablo 3 Borderlands (leader is Booody)
Alien Invasion Trilogie
hell gate is offline   Reply With Quote
Old 02-19-2010, 06:55 PM   #9 (permalink)
Registered User Inferior
"-Dota Suxx-"
 
Inferior's Avatar
 
Join Date: Nov 2008
Posts: 58
Inferior has little to show at this moment (16)Inferior has little to show at this moment (16)
Lol wtf your right, if I just copy the map in the wc3 folder it doesnt work.

But as hellgate said, just open it with JNGP, save it and it then it should work
Inferior is online now   Reply With Quote
Old 02-19-2010, 07:08 PM   #10 (permalink)
Registered User Catch_ya
ALUNDRA
 
Catch_ya's Avatar
 
Join Date: May 2009
Posts: 921
Catch_ya has a spectacular aura about (137)Catch_ya has a spectacular aura about (137)Catch_ya has a spectacular aura about (137)Catch_ya has a spectacular aura about (137)
Quote:
Originally Posted by Inferior View Post
Lol wtf your right, if I just copy the map in the wc3 folder it doesnt work.

But as hellgate said, just open it with JNGP, save it and it then it should work
You need JNPG anyway so its easy to click CTRL + S.
__________________
I hate people who call warcraft stuff for "sexy" or "hot".
Catch_ya is online now   Reply With Quote
Old 02-20-2010, 06:05 AM   #11 (permalink)
Registered User Kingz
Lady Luck is smilin'
 
Kingz's Avatar
 
Join Date: Jun 2008
Posts: 2,255
Kingz is a glorious beacon of light (569)Kingz is a glorious beacon of light (569)Kingz is a glorious beacon of light (569)Kingz is a glorious beacon of light (569)Kingz is a glorious beacon of light (569)Kingz is a glorious beacon of light (569)
It is an upload error, hapens sometimes, just compile the map, exit the editor and reupload it.
__________________
Quote:
Originally Posted by The_Reborn_Devil
You could consider using an indexing system instead of hashtables to make it slightly more efficient
Suck it hashtables.
Kingz is offline   Reply With Quote
Old 02-20-2010, 04:03 PM   #12 (permalink)
Registered User Inferior
"-Dota Suxx-"
 
Inferior's Avatar
 
Join Date: Nov 2008
Posts: 58
Inferior has little to show at this moment (16)Inferior has little to show at this moment (16)
I think has to work now. Try to download again.

And could someone check through the code and tell me what to improve.
Inferior is online now   Reply With Quote
Old 03-11-2010, 03:41 AM   #13 (permalink)
Registered User watermelon_1234
User
 
watermelon_1234's Avatar
 
Join Date: Nov 2007
Posts: 487
watermelon_1234 is a jewel in the rough (191)watermelon_1234 is a jewel in the rough (191)
Very Quick Comments on Coding:
Update GroupUtils if you haven't already. You can substitute GroupEnumUnitsInRange with GroupEnumUnitsInArea.

You should null the local handle variables such as unit dum and effect e.

Why not use xecast for all of your dummy targeting spells? (You used it in Dark Curse but not Deadly Seduction)

Using only
Jass:
IsUnitType(target,UNIT_TYPE_HERO)
won't set the correct duration for units that have Resistant Skin or belong to the Creep race and have a level higher than 5. Why don't you just use IsUnitSpellResistant? (This is about Black Curse)

I don't think it's wise to use TriggerRegisterUnitEvent for every unit that gets affected by the spell as it will be called on units that may already have been registered to the trigger.

I think you should have a configuration function for the damage (When you're using xedamage) so that people who use the spells find it easier to change the spell's damagetype/attacktype/weapontype.

FYI:
Trigger conditions get executed faster than trigger actions.

FirstOfGroup loops are slower than using the filter directly.

I haven't downloaded the spell pack yet; I've only looked at the spell code you posted online.
watermelon_1234 is online now   Reply With Quote
Old 03-11-2010, 05:19 PM   #14 (permalink)
Registered User Inferior
"-Dota Suxx-"
 
Inferior's Avatar
 
Join Date: Nov 2008
Posts: 58
Inferior has little to show at this moment (16)Inferior has little to show at this moment (16)
Quote:
Originally Posted by watermelon_1234 View Post
Update GroupUtils if you haven't already. You can substitute GroupEnumUnitsInRange with GroupEnumUnitsInArea.
Fixed

Quote:
Originally Posted by watermelon_1234 View Post
You should null the local handle variables such as unit dum and effect e.
Fixed

Quote:
Originally Posted by watermelon_1234 View Post
Why not use xecast for all of your dummy targeting spells? (You used it in Dark Curse but not Deadly Seduction)
I dont see the reason to use xecast for Deadly Seduction since i dont use any targeting dummy spell. If you tell me where I'll fix it ASAP.

Quote:
Originally Posted by watermelon_1234 View Post
Using only
Jass:
IsUnitType(target,UNIT_TYPE_HERO)
won't set the correct duration for units that have Resistant Skin or belong to the Creep race and have a level higher than 5. Why don't you just use IsUnitSpellResistant? (This is about Black Curse)
Fixed


Quote:
Originally Posted by watermelon_1234 View Post
I don't think it's wise to use TriggerRegisterUnitEvent for every unit that gets affected by the spell as it will be called on units that may already have been registered to the trigger.
No problem with it since the triggers are destroyed and there is also a checking wheather a unit allready is under effect of the spell (if you mean Dark Curse :P)

Quote:
Originally Posted by watermelon_1234 View Post
I think you should have a configuration function for the damage (When you're using xedamage) so that people who use the spells find it easier to change the spell's damagetype/attacktype/weapontype.
Fixed

Quote:
Originally Posted by watermelon_1234 View Post
FYI:
Trigger conditions get executed faster than trigger actions.
Fixed

Quote:
Originally Posted by watermelon_1234 View Post
FirstOfGroup loops are slower than using the filter directly.
Fixed

Thx for your Feedback watermelon
__________________
My Spellpack
Inferior is online now   Reply With Quote
Old 03-11-2010, 08:46 PM   #15 (permalink)
Registered User War_Golum
Banned
 
Join Date: Jan 2010
Posts: 915
War_Golum is on a distinguished road
awesome visual effects
War_Golum is offline   Reply With Quote
Reply

Bookmarks

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On


All times are GMT. The time now is 07:10 PM.





Powered by vBulletin®
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.1
Copyright©Ralle