• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Zephyr Contest #11 - My aura, Your aura

Status
Not open for further replies.
Level 23
Joined
Apr 16, 2012
Messages
4,041
in fact, there are plenty natives that you can get your hands on using JNGP.

Here is the entire list:

http://jass.sourceforge.net/doc/api/common_ai-functions.shtml

the most notable are GetUnitGold/WoodCost and UnitAlive

they are all in the file that game has access to, but for some reason world editor doesnt. However, you can forward declare the natives even if they are not in the common.j or blizzard.j(like the ones from common.ai)

You would have to ban quite a few resources if you wanted to make natives undeclarable. Many resources use UnitAlive
 
Well, since the script is imported with the import editor, the map can be opened and saved.

I am kind of torn here. However, I feel that you are taking too much advantage of utilities. You're already allowed to use any kind of system (unlike the first Zephyr contests), which is something I changed :)goblin_yeah:) and it is more than enough. It's just a spell!
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
I think he means writing the code outside of the editor and importing it, like if I had library in folder in JNGP and used //! import "myScript.j". You dont get new natives or anything, you just get the possibility to create it outside of the world editor
 
Version 2, tooltip;

Once enemy heroes within 700 range drop below 40% health, the Shadow Wolf goes into stealth with a fade rate of 1 second. He then gains 20% movement speed, while stalked enemies lose half the percentage.

When attacking stalked heroes, the Shadow Wolf gains 20% lifesteal.

I scrapped the evasion feeling life steal + evasion combo was too much. How is the spell as an ultimate right now? Underpowered?
 

Attachments

  • ShadowStalk - Zephyr11.w3x
    139.1 KB · Views: 49

Deleted member 219079

D

Deleted member 219079

Either GUI or JASS may be used to create your spell; you will not be penalized if you use GUI over JASS.
This means no vJASS? (I just read the OP if you've already discussed about this I'm sorry, but there's 4 pages..)
 

Deleted member 219079

D

Deleted member 219079

mk, then if I assume right that I can use Table by Bribe, PUI and TimerUtils,
you can count me in
 
Just posting code listing WIP, move along


JASS:
///////////////////////////////////////////////////////////////////
//  Configuration                                                //
///////////////////////////////////////////////////////////////////
constant function STA_AbilityID takes nothing returns integer
    return 'A000'
endfunction 

constant function STA_DummyID takes nothing returns integer
    return 'u000'
endfunction

constant function STA_TimerRate takes nothing returns real
    return 0.03125
endfunction

constant function STA_DummyRemovalDelay takes nothing returns real
    return 2.
endfunction

constant function STA_EffectReductionDelay takes nothing returns real
    return 0.5
endfunction

constant function STA_AuraEffect takes nothing returns string
    return "Abilities\\Spells\\Undead\\RegenerationAura\\ObsidianRegenAura.mdl"
endfunction

constant function STA_SoulFragmentEffect takes nothing returns string
    return "Abilities\\Spells\\Undead\\Curse\\CurseTarget.mdl"
endfunction

constant function STA_SoulFragmentProjectileEffect takes nothing returns string
    return "Abilities\\Spells\\Undead\\Possession\\PossessionMissile.mdl"
endfunction

constant function STA_InitialDamageEffect takes nothing returns string
    return "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
endfunction

constant function STA_DeathDamageEffect takes nothing returns string
    return "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
endfunction

constant function STA_BonusDamageEffect takes nothing returns string
    return "Abilities\\Spells\\Items\\AIil\\AIilTarget.mdl"
endfunction

constant function STA_HealEffect takes nothing returns string
    return "Abilities\\Spells\\Human\\DispelMagic\\DispelMagicTarget.mdl"
endfunction

constant function STA_AuraAttachmentPoint takes nothing returns string
    return "origin"
endfunction

constant function STA_SoulFragmentAttachmentPoint takes nothing returns string
    return "overhead"
endfunction

constant function STA_SoulFragmentProjectileAttachmentPoint takes nothing returns string
    return "chest"
endfunction

constant function STA_InitialDamageAttachmentPoint takes nothing returns string
    return "chest"
endfunction

constant function STA_DeathDamageAttachmentPoint takes nothing returns string
    return "chest"
endfunction

constant function STA_BonusDamageAttachmentPoint takes nothing returns string
    return "chest"
endfunction

constant function STA_HealEffectAttachmentPoint takes nothing returns string
    return "chest"
endfunction

constant function STA_SoulFragmentProjectileScaleBase takes nothing returns real
    return .9
endfunction

constant function STA_SoulFragmentProjectileScalePerLevel takes nothing returns real
    return .05
endfunction

constant function STA_AOEBase takes nothing returns real
    return 400.
endfunction

constant function STA_AOEPerLevel takes nothing returns real
    return 100.
endfunction

constant function STA_SearchAOEBase takes nothing returns real
    return 100.
endfunction

constant function STA_SearchAOEPerLevel takes nothing returns real
    return 90.
endfunction

constant function STA_ImpactAOEBase takes nothing returns real
    return 100.
endfunction

constant function STA_ImpactAOEPerLevel takes nothing returns real
    return 0.
endfunction

constant function STA_SoulFragmentProjectileSpeedBase takes nothing returns real
    return 9.
endfunction

constant function STA_SoulFragmentProjectileSpeedPerLevel takes nothing returns real
    return 6.
endfunction

constant function STA_SoulFragmentProjectileHitTimeBase takes nothing returns real
    return 2.
endfunction

constant function STA_SoulFragmentProjectileHitTimePerLevel takes nothing returns real
    return -0.3
endfunction

constant function STA_SoulFragmentMovementType takes nothing returns boolean
    return false
endfunction

constant function STA_SoulFragmentHeightStartOffset takes nothing returns real
    return 90.
endfunction

constant function STA_SoulFragmentHeightEndOffset takes nothing returns real
    return 45.
endfunction

constant function STA_InitialEffectHealthDamageBase takes nothing returns real
    return 25.
endfunction

constant function STA_InitialEffectHealthDamagePerLevel takes nothing returns real
    return 10.
endfunction

constant function STA_InitialEffectManaDamageBase takes nothing returns real
    return 0.
endfunction

constant function STA_InitialEffectManaDamagePerLevel takes nothing returns real
    return 0.
endfunction

constant function STA_DeathHealthDamageBase takes nothing returns real
    return 50.
endfunction

constant function STA_DeathHealthDamagePerLevel takes nothing returns real
    return 25.
endfunction

constant function STA_DeathManaDamageBase takes nothing returns real
    return 0.
endfunction

constant function STA_DeathManaDamagePerLevel takes nothing returns real
    return 0.
endfunction

constant function STA_BonusHealthDamagePercentBase takes nothing returns real
    return 0.1
endfunction

constant function STA_BonusHealthDamagePercentPerLevel takes nothing returns real
    return 0.05
endfunction

constant function STA_BonusManaDamagePercentBase takes nothing returns real
    return 0.
endfunction

constant function STA_BonusManaDamagePercentPerLevel takes nothing returns real
    return 0.
endfunction

constant function STA_HeroHealthHealBase takes nothing returns real
    return 100.
endfunction

constant function STA_HeroHealthHealPerLevel takes nothing returns real
    return 50.
endfunction

constant function STA_HeroManaHealBase takes nothing returns real
    return 0.
endfunction

constant function STA_HeroManaHealPerLevel takes nothing returns real
    return 0.
endfunction

constant function STA_AttackType takes nothing returns attacktype
    return ATTACK_TYPE_MAGIC
endfunction

constant function STA_DamageType takes nothing returns damagetype
    return DAMAGE_TYPE_MAGIC
endfunction

constant function STA_WeaponType takes nothing returns weapontype
    return null
endfunction

constant function STA_CollisionSize takes nothing returns real
    return 50.
endfunction
///////////////////////////////////////////////////////////////////
//  This marks the end of the configuration section, it is not   //
//  recommended to go beyond this point unless you know what     //
//  you are doing and have programming experience yourself       //
///////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////
//  Function used to get the z height of locations needed by the //
//  spell, since it can only be done with locations, this one    //
//  is reused throughout, instead of creating/destroying them    //
///////////////////////////////////////////////////////////////////
function STA_GetZ takes real x, real y returns real

    //Gets the location Z of the selected location
    call MoveLocation(udg_STA_ZLoc, x, y)
    return GetLocationZ(udg_STA_ZLoc)
    
endfunction

///////////////////////////////////////////////////////////////////
//  Function used to recycle instances, so that they can used    //
//  again later, keeping the total array sizes smaller           //
///////////////////////////////////////////////////////////////////
function STA_Recycle takes integer Node, timer T returns nothing
            
        if (udg_STA_LastNode == Node) then
            set udg_STA_LastNode = udg_STA_PrevNode[Node]
        endif
           
        //Recycles the node
        set udg_STA_RecycleNodes[udg_STA_RecyclableNodes] = Node
        set udg_STA_RecyclableNodes = udg_STA_RecyclableNodes + 1
        set udg_STA_NextNode[udg_STA_PrevNode[Node]] = udg_STA_NextNode[Node]
        set udg_STA_PrevNode[udg_STA_NextNode[Node]] = udg_STA_PrevNode[Node]
        set udg_STA_AbilityCounter = udg_STA_AbilityCounter - 1

        if (udg_STA_AbilityCounter == 0) then
            call DestroyTimer(T)
        endif

endfunction

////////////////////////////////////////////////////////////////////
//  Target filter function - passed units and players and checks  //
//  if the unit is allowed to be targetted by this ability        //
////////////////////////////////////////////////////////////////////
function STA_TargetFilter takes unit u, player pl returns boolean

    //Checks if the unit can be used as a target
    if (not IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)) and (IsUnitEnemy(u, pl)) and (GetUnitTypeId(u) != STA_DummyID()) and (not IsUnitType(u, UNIT_TYPE_DEAD)) then
        return true
    endif
    
    return false

endfunction

///////////////////////////////////////////////////////////////////
//  This function handles the damage dealt to units by the       //
//  projectiles, including health and mana in one function,      //
//  since both forms of projectile use the same damage method    //
///////////////////////////////////////////////////////////////////
function STA_SoulProjectileDamage takes integer Node returns nothing
     //Declare Locals
    local real x = GetUnitX(udg_STA_Unit[Node])
    local real y = GetUnitY(udg_STA_Unit[Node])
    local unit u
    local player pl = GetOwningPlayer(udg_STA_Caster[Node])

    call GroupEnumUnitsInRange(udg_STA_TempGroup, x, y, udg_STA_ImpactAOE[udg_STA_CasterNode[Node]], null) 
    set pl = GetOwningPlayer(udg_STA_Caster[Node])
                
    loop
       //Scanning through
       set u = FirstOfGroup(udg_STA_TempGroup)
       exitwhen u == null
                           
       //Select all the units which are to be damaged
       if (STA_TargetFilter(u, pl)) then
            call UnitDamageTarget(udg_STA_Caster[Node], u, udg_STA_HealthDamage[Node], false, false, STA_AttackType(), STA_DamageType(), STA_WeaponType())
            call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - udg_STA_ManaDamage[Node])
       endif

       //Remove the unit from the unit group
       call GroupRemoveUnit(udg_STA_TempGroup, u)
    endloop
    
    //Null variables
    set pl = null
endfunction

///////////////////////////////////////////////////////////////////
//  Function used to create each projectile and set up all the   //
//  information they need to run, since both the caster and the  //
//  affected units can produce these projectiles                 //
///////////////////////////////////////////////////////////////////
function STA_CreateProjectile takes real x, real y, real z, real zSpeed, real Speed, real Angle, real Distance, real HealthDamage, real ManaDamage, integer Node, boolean Type, integer Target returns nothing
    local integer TempNode
    
    set udg_STA_AbilityCounter = udg_STA_AbilityCounter + 1
    
    //Checking for recycleable Nodes
    if (udg_STA_RecyclableNodes == 0) then
        set udg_STA_NodeNumber = udg_STA_NodeNumber + 1
        set TempNode = udg_STA_NodeNumber
    else
        set udg_STA_RecyclableNodes = udg_STA_RecyclableNodes - 1
        set TempNode = udg_STA_RecycleNodes[udg_STA_RecyclableNodes]
    endif

    set udg_STA_NextNode[TempNode] = 0
    set udg_STA_NextNode[udg_STA_LastNode] = TempNode
    set udg_STA_PrevNode[TempNode] = udg_STA_LastNode
    set udg_STA_LastNode = TempNode
    set udg_STA_Caster[TempNode] = udg_STA_Caster[Node]
    set udg_STA_CasterNode[TempNode] = udg_STA_CasterNode[Node]
    
    set udg_STA_Unit[TempNode] = CreateUnit(Player(14), STA_DummyID(), x, y, Angle)
    if UnitAddAbility(udg_STA_Unit[TempNode], 'Amrf') and UnitRemoveAbility(udg_STA_Unit[TempNode], 'Amrf') then
    endif
    set udg_STA_CurrentEffect[TempNode] = AddSpecialEffectTarget(STA_SoulFragmentProjectileEffect(), udg_STA_Unit[TempNode], STA_SoulFragmentProjectileAttachmentPoint())
    call SetUnitScale(udg_STA_Unit[TempNode], udg_STA_SoulFragmentScale[Node],0.,0.)
    call SetUnitFlyHeight(udg_STA_Unit[TempNode], z, 0)
    
    set udg_STA_StageID[TempNode] = 3
    set udg_STA_ZSpeed[TempNode] = zSpeed
    set udg_STA_Speed[TempNode] = Speed
    set udg_STA_HealthDamage[TempNode] = HealthDamage
    set udg_STA_ManaDamage[TempNode] = ManaDamage
    set udg_STA_FragmentType[TempNode] = Type
    
    set udg_STA_DistanceTravelled[TempNode] = 0.
    
    if (Type == true) then
        set udg_STA_Target[TempNode] = udg_STA_Unit[Target]
        set udg_STA_TargetID[TempNode] = Target
    else
        set udg_STA_MaxDistance[TempNode] = Distance
        set udg_STA_TargetID[TempNode] = 0
        set udg_STA_Target[TempNode] = null
    endif
    
endfunction
///////////////////////////////////////////////////////////////////
//  Function used to update the stats for Heros generating the   //
//  aura, so that level ups are in effect instantly              //
///////////////////////////////////////////////////////////////////
function STA_UpdateAura takes integer Node returns nothing

    set udg_STA_SoulFragmentScale[Node] = STA_SoulFragmentProjectileScaleBase() + (STA_SoulFragmentProjectileScalePerLevel() * udg_STA_Level[Node])
    set udg_STA_AOE[Node] = STA_AOEBase() + (STA_AOEPerLevel() * udg_STA_Level[Node])
    set udg_STA_SearchAOE[Node] = STA_SearchAOEBase() + (STA_SearchAOEPerLevel() * udg_STA_Level[Node])
    set udg_STA_ImpactAOE[Node] = STA_ImpactAOEBase() + (STA_ImpactAOEPerLevel() * udg_STA_Level[Node])
    set udg_STA_SoulProjectileSpeed[Node] = STA_SoulFragmentProjectileSpeedBase() + (STA_SoulFragmentProjectileSpeedPerLevel() * udg_STA_Level[Node])
    set udg_STA_SoulProjectileHitTime[Node] = STA_SoulFragmentProjectileHitTimeBase() + (STA_SoulFragmentProjectileHitTimePerLevel() * udg_STA_Level[Node])
    set udg_STA_InitialEffectHealthDamage[Node] = STA_InitialEffectHealthDamageBase() + (STA_InitialEffectHealthDamagePerLevel() * udg_STA_Level[Node])
    set udg_STA_InitialEffectManaDamage[Node] = STA_InitialEffectManaDamageBase() + (STA_InitialEffectManaDamagePerLevel() * udg_STA_Level[Node])
    set udg_STA_DeathHealthDamage[Node] = STA_DeathHealthDamageBase() + (STA_DeathHealthDamagePerLevel() * udg_STA_Level[Node])
    set udg_STA_DeathManaDamage[Node] = STA_DeathManaDamageBase() + (STA_DeathManaDamagePerLevel() * udg_STA_Level[Node])
    set udg_STA_BonusHealthDamagePercent[Node] = STA_BonusHealthDamagePercentBase() + (STA_BonusHealthDamagePercentPerLevel() * udg_STA_Level[Node])
    set udg_STA_BonusManaDamagePercent[Node] = STA_BonusManaDamagePercentBase() + (STA_BonusManaDamagePercentPerLevel() * udg_STA_Level[Node])
    set udg_STA_HeroHealthHeal[Node] = STA_HeroHealthHealBase() + (STA_HeroHealthHealPerLevel() * udg_STA_Level[Node])
    set udg_STA_HeroManaHeal[Node] = STA_HeroManaHealBase() + (STA_HeroManaHealPerLevel() * udg_STA_Level[Node])
    
endfunction

///////////////////////////////////////////////////////////////////
//  The main loop function of the spell, it handles the main     //
//  operations of the ability such as assigning new units,       //
//  moving projectiles and dealing bonus damage to units         //
///////////////////////////////////////////////////////////////////
function STA_Loop takes nothing returns nothing
    //Declare Locals
    local integer Node = 0
    local integer TempNode = 0
    local integer TempInt = 0
    local integer TempInt2 = 0
    local real TempReal
    local real TempReal2
    local real TempReal3
    local real x
    local real y
    local real x2
    local real y2
    local real z
    local real z2
    local real Angle
    local unit u
    local player pl
    
    loop
        //Moves to the next node
        set TempInt = TempInt + 1
        exitwhen TempInt > udg_STA_AbilityCounter
        set Node = udg_STA_NextNode[Node]

        if (udg_STA_StageID[Node] == 3) then
            set x = GetUnitX(udg_STA_Unit[Node])
            set y = GetUnitY(udg_STA_Unit[Node])
                        
            call SetUnitX(udg_STA_Unit[Node], x + udg_STA_Speed[Node] * Cos(GetUnitFacing(udg_STA_Unit[Node]) * bj_DEGTORAD))
            call SetUnitY(udg_STA_Unit[Node], y + udg_STA_Speed[Node] * Sin(GetUnitFacing(udg_STA_Unit[Node]) * bj_DEGTORAD))
            call SetUnitFlyHeight(udg_STA_Unit[Node], GetUnitFlyHeight(udg_STA_Unit[Node]) + udg_STA_ZSpeed[Node], 0.)
            set udg_STA_DistanceTravelled[Node] = udg_STA_DistanceTravelled[Node] + udg_STA_Speed[Node]

            if (udg_STA_FragmentType[Node] == true) then
            
                set x2 = GetUnitX(udg_STA_Target[Node])
                set y2 = GetUnitY(udg_STA_Target[Node])
                set TempReal = SquareRoot(Pow(x - x2, 2) + Pow(y - y2, 2))
                
                if (TempReal > STA_CollisionSize()) then
                    set Angle = Atan2(y2 - y, x2 - x)
                    call SetUnitFacing(udg_STA_Unit[Node], bj_RADTODEG * Angle)

                    set z = STA_GetZ(x,y) + GetUnitFlyHeight(udg_STA_Unit[Node])
                    set z2 = STA_GetZ(x2, y2) + GetUnitFlyHeight(udg_STA_Target[Node]) + STA_SoulFragmentHeightEndOffset()
                    
                    //Calculate Speed
                    if (STA_SoulFragmentMovementType() == true) then
                        set udg_STA_Speed[Node] = (TempReal + udg_STA_DistanceTravelled[Node] / udg_STA_SoulProjectileHitTime[udg_STA_CasterNode[Node]]) * STA_TimerRate()
                    endif
                    
                    set udg_STA_ZSpeed[Node] = (z2 - z) / (TempReal / udg_STA_Speed[Node])
                else
                    set udg_STA_Disabled[udg_STA_TargetID[Node]] = false
                    call STA_SoulProjectileDamage(Node)
                    set udg_STA_StageID[Node] = 4
                    call DestroyEffect(udg_STA_CurrentEffect[Node])
                    call DestroyEffect(AddSpecialEffectTarget(STA_InitialDamageEffect(), udg_STA_Unit[Node], STA_InitialDamageAttachmentPoint()))
                endif
            elseif (udg_STA_DistanceTravelled[Node] >= udg_STA_MaxDistance[Node]) then
                call STA_SoulProjectileDamage(Node)
                set udg_STA_StageID[Node] = 4
                call DestroyEffect(udg_STA_CurrentEffect[Node])
                call DestroyEffect(AddSpecialEffectTarget(STA_DeathDamageEffect(), udg_STA_Unit[Node], STA_DeathDamageAttachmentPoint()))
            endif
               

            
        elseif (udg_STA_StageID[Node] == 2) and (udg_STA_Disabled[Node] == false) then
            set TempReal = GetUnitState(udg_STA_Unit[Node], UNIT_STATE_LIFE)
            set TempReal2 = GetUnitState(udg_STA_Unit[Node], UNIT_STATE_MANA)
            set udg_STA_EffectDelayTimer[Node] = udg_STA_EffectDelayTimer[Node] + STA_TimerRate()

            if (TempReal < udg_STA_CurrentHealth[Node]) or (TempReal2 < udg_STA_CurrentMana[Node]) then
            
                if (udg_STA_EffectDelayTimer[Node] >= STA_EffectReductionDelay()) then
                    set udg_STA_EffectDelayTimer[Node] = 0.
                    call DestroyEffect(AddSpecialEffectTarget(STA_BonusDamageEffect(), udg_STA_Unit[Node], STA_BonusDamageAttachmentPoint()))
                endif
                
                if (TempReal < udg_STA_CurrentHealth[Node]) then
                    set TempReal = (udg_STA_CurrentHealth[Node] - TempReal) * udg_STA_BonusHealthDamagePercent[udg_STA_CasterNode[Node]]
                    call UnitDamageTarget(udg_STA_Caster[Node], udg_STA_Unit[Node], TempReal, false, false, STA_AttackType(), STA_DamageType(), STA_WeaponType())
                    set udg_STA_CurrentHealth[Node] = GetUnitState(udg_STA_Unit[Node], UNIT_STATE_LIFE)
                else
                    set TempReal2 = (udg_STA_CurrentMana[Node] - TempReal2) * udg_STA_BonusManaDamagePercent[udg_STA_CasterNode[Node]]
                    call SetUnitState(udg_STA_Unit[Node], UNIT_STATE_MANA, TempReal2)
                endif
                
            endif
            
            set x = GetUnitX(udg_STA_Unit[Node])
            set y = GetUnitY(udg_STA_Unit[Node])
            set x2 = GetUnitX(udg_STA_Caster[Node])
            set y2 = GetUnitY(udg_STA_Caster[Node])
            set TempReal = SquareRoot(Pow(x - x2, 2) + Pow(y - y2, 2))
            
            if (TempReal > udg_STA_AOE[udg_STA_CasterNode[Node]]) then
                call DestroyEffect(udg_STA_CurrentEffect[Node])
                call GroupRemoveUnit(udg_STA_AffectedUnits,udg_STA_Unit[Node])
                call STA_Recycle(Node, GetExpiredTimer())
                set TempInt = TempInt - 1
            
            else
            
                if (IsUnitType(udg_STA_Unit[Node], UNIT_TYPE_DEAD)) then
                
                    set TempInt2 = 0
                    set TempNode = 0

                    loop
                        //Moves to the next node
                        set TempInt2 = TempInt2 + 1
                        exitwhen TempInt2 > udg_STA_AbilityCounter
                        set TempNode = udg_STA_NextNode[TempNode]
                        
                        if (udg_STA_Target[TempNode] == udg_STA_Unit[Node]) and (udg_STA_StageID[TempNode] == 3) then
                            call DestroyEffect(udg_STA_CurrentEffect[TempNode])
                            call DestroyEffect(AddSpecialEffectTarget(STA_DeathDamageEffect(), udg_STA_Unit[TempNode], STA_DeathDamageAttachmentPoint()))
                            set udg_STA_StageID[TempNode] = 4
                        endif

                    endloop
                    call GroupEnumUnitsInRange(udg_STA_TempGroup, x, y, udg_STA_SearchAOE[udg_STA_CasterNode[Node]], null) 
                    set pl = GetOwningPlayer(udg_STA_Caster[Node])
                    
                    loop
                        //Scanning through
                        set u = FirstOfGroup(udg_STA_TempGroup)
                        exitwhen u == null
                               
                        //Select all the units which are to be damaged
                        if (STA_TargetFilter(u, pl)) and (IsUnitInGroup(u, udg_STA_AffectedUnits)) then
                            //Set up data for the Soul Fragment Projectile
                            set x2 = GetUnitX(u)
                            set y2 = GetUnitY(u)
                            set z = STA_GetZ(x,y) + GetUnitFlyHeight(udg_STA_Unit[Node]) + STA_SoulFragmentHeightStartOffset()
                            set z2 = STA_GetZ(x2, y2) + GetUnitFlyHeight(u) + STA_SoulFragmentHeightEndOffset()
                            set TempReal = SquareRoot(Pow(x - x2, 2) + Pow(y - y2, 2))
                            
                            //Calculate Speed
                            if (STA_SoulFragmentMovementType() == true) then
                                set TempReal2 = (TempReal / udg_STA_SoulProjectileHitTime[udg_STA_CasterNode[Node]]) * STA_TimerRate()
                            else
                                set TempReal2 = udg_STA_SoulProjectileSpeed[udg_STA_CasterNode[Node]]
                            endif
                            
                            set TempReal3 = (z2 - z) / (TempReal / TempReal2)
                            set Angle = bj_RADTODEG * Atan2(y2 - y, x2 - x)

                            //Create Projectile
                            call STA_CreateProjectile(x, y, z, TempReal3, TempReal2, Angle, TempReal, udg_STA_DeathHealthDamage[udg_STA_CasterNode[Node]], udg_STA_DeathManaDamage[udg_STA_CasterNode[Node]], udg_STA_CasterNode[Node], false, 0)
                        endif

                        //Remove the unit from the unit group
                        call GroupRemoveUnit(udg_STA_TempGroup, u)
                    endloop

                    call DestroyEffect(udg_STA_CurrentEffect[Node])
                    call GroupRemoveUnit(udg_STA_AffectedUnits,udg_STA_Unit[Node])
                    call STA_Recycle(Node, GetExpiredTimer())
                    set TempInt = TempInt - 1
                    
                    //Null variables
                    set pl = null
                endif

            endif

        elseif (udg_STA_StageID[Node] == 1) then
        
            if (IsUnitType(udg_STA_Caster[Node], UNIT_TYPE_DEAD)) then

                set TempInt2 = 0
                set TempNode = 0

                loop
                    //Moves to the next node
                    set TempInt2 = TempInt2 + 1
                    exitwhen TempInt2 > udg_STA_AbilityCounter
                    set TempNode = udg_STA_NextNode[TempNode]
                    
                    if (udg_STA_Caster[TempNode] == udg_STA_Caster[Node]) then

                        if (udg_STA_StageID[TempNode] == 2) then
                            call DestroyEffect(AddSpecialEffectTarget(STA_HealEffect(), udg_STA_Unit[TempNode], STA_HealEffectAttachmentPoint()))
                            call SetUnitState(udg_STA_Unit[TempNode], UNIT_STATE_LIFE, GetUnitState(udg_STA_Unit[TempNode], UNIT_STATE_LIFE) + udg_STA_HeroHealthHeal[Node])
                            call SetUnitState(udg_STA_Unit[TempNode], UNIT_STATE_MANA, GetUnitState(udg_STA_Unit[TempNode], UNIT_STATE_MANA) + udg_STA_HeroManaHeal[Node])
                            call DestroyEffect(udg_STA_CurrentEffect[TempNode])
                            call GroupRemoveUnit(udg_STA_AffectedUnits,udg_STA_Unit[TempNode])
                            call STA_Recycle(TempNode, GetExpiredTimer())
                            set TempInt2 = TempInt2 - 1
                        elseif (udg_STA_StageID[TempNode] == 3) then
                            call DestroyEffect(udg_STA_CurrentEffect[TempNode])
                            call DestroyEffect(AddSpecialEffectTarget(STA_DeathDamageEffect(), udg_STA_Unit[TempNode], STA_DeathDamageAttachmentPoint()))
                            set udg_STA_StageID[TempNode] = 4
                        endif
                    endif

                endloop
                
            else
                set TempReal = I2R(GetUnitAbilityLevel(udg_STA_Caster[Node], STA_AbilityID()))
                
                if (TempReal > udg_STA_Level[Node]) then
                    set udg_STA_Level[Node] = TempReal
                    call STA_UpdateAura(Node)
                endif
                
                set x = GetUnitX(udg_STA_Caster[Node])
                set y = GetUnitY(udg_STA_Caster[Node])
                set pl = GetOwningPlayer(udg_STA_Caster[Node])
                call GroupEnumUnitsInRange(udg_STA_TempGroup, x, y, udg_STA_AOE[Node], null) 
                
                loop
                    //Scanning through
                    set u = FirstOfGroup(udg_STA_TempGroup)
                    exitwhen u == null
                           
                    //Select all the units which are to be damaged
                    if (STA_TargetFilter(u, pl)) and (not(IsUnitInGroup(u, udg_STA_AffectedUnits))) then
                        
                        //Prevent this unit from being selected again
                        call GroupAddUnit(udg_STA_AffectedUnits,u)
                            
                        set udg_STA_AbilityCounter = udg_STA_AbilityCounter + 1
                            
                        //Checking for recycleable Nodes
                        if (udg_STA_RecyclableNodes == 0) then
                            set udg_STA_NodeNumber = udg_STA_NodeNumber + 1
                            set TempNode = udg_STA_NodeNumber
                        else
                            set udg_STA_RecyclableNodes = udg_STA_RecyclableNodes - 1
                            set TempNode = udg_STA_RecycleNodes[udg_STA_RecyclableNodes]
                        endif

                        //Sets up this Node
                        set udg_STA_NextNode[TempNode] = 0
                        set udg_STA_NextNode[udg_STA_LastNode] = TempNode
                        set udg_STA_PrevNode[TempNode] = udg_STA_LastNode
                        set udg_STA_LastNode = TempNode
                        //Sets up data for this unit
                        set udg_STA_Caster[TempNode] = udg_STA_Caster[Node]
                        set udg_STA_CasterNode[TempNode] = Node
                        set udg_STA_Unit[TempNode] = u
                        set udg_STA_CurrentEffect[TempNode] = AddSpecialEffectTarget(STA_SoulFragmentEffect(), u, STA_SoulFragmentAttachmentPoint())
                        set udg_STA_Disabled[TempNode] = true
                        set udg_STA_StageID[TempNode] = 2
                        set udg_STA_CasterNode[TempNode] = Node
                        set udg_STA_CurrentHealth[TempNode] = GetUnitState(u, UNIT_STATE_LIFE)
                        set udg_STA_CurrentMana[TempNode] = GetUnitState(u, UNIT_STATE_MANA)
    
                        //Set up data for the Soul Fragment Projectile
                        set x2 = GetUnitX(u)
                        set y2 = GetUnitY(u)
                        set z = STA_GetZ(x,y) + GetUnitFlyHeight(udg_STA_Caster[Node]) + STA_SoulFragmentHeightStartOffset()
                        set z2 = STA_GetZ(x2, y2) + GetUnitFlyHeight(u) + STA_SoulFragmentHeightEndOffset()
                        set TempReal = SquareRoot(Pow(x - x2, 2) + Pow(y - y2, 2))
                            
                        //Calculate Speed
                        if (STA_SoulFragmentMovementType() == true) then
                            set TempReal2 = (TempReal / udg_STA_SoulProjectileHitTime[Node]) * STA_TimerRate()
                        else
                            set TempReal2 = udg_STA_SoulProjectileSpeed[Node]
                        endif
                            
                        set TempReal = (z2 - z) / (TempReal / TempReal2)
                        set Angle = bj_RADTODEG * Atan2(y2 - y, x2 - x)

                        //Create Projectile
                        call STA_CreateProjectile(x, y, z, TempReal, TempReal2, Angle, 0, udg_STA_InitialEffectHealthDamage[Node], udg_STA_InitialEffectManaDamage[Node], Node, true, TempNode)
                        
                    endif
                    //Remove the unit from the unit group
                    call GroupRemoveUnit(udg_STA_TempGroup, u)
                           
                endloop
                
                //Null variables
                set pl = null
            endif
            
        elseif (udg_STA_StageID[Node] == 4) and (udg_STA_CurrentDeathTimer[Node] >= STA_DummyRemovalDelay()) then
            set udg_STA_CurrentDeathTimer[Node] = 0.00
            
            //Removes the projectile
            call RemoveUnit(udg_STA_Unit[Node])
            call STA_Recycle(Node, GetExpiredTimer())
            set TempInt = TempInt - 1
        
        else
            set udg_STA_CurrentDeathTimer[Node] = udg_STA_CurrentDeathTimer[Node] + STA_TimerRate()
        endif
        
    endloop
    
endfunction

///////////////////////////////////////////////////////////////////
//  Caster assignment function, when a new unit fits any         //
//  requirement to become a caster, this function is called      //
//  passing the unit to add, the system then checks if the       //
//  caster already exists in the system (this is for if they     //
//  meet multiple requirements to call the function) in order    //
//  to prevent dubplications of information                      //
///////////////////////////////////////////////////////////////////
function STA_NewAura takes nothing returns boolean
    //Set up locals
    local integer TempInt = 0
    local integer Node = 0
    local boolean scan = false
    local unit u
    
    if (GetLearnedSkill() == STA_AbilityID()) then
        set u = GetTriggerUnit()

        loop
            //Moves to the next node
            set TempInt = TempInt + 1
            exitwhen TempInt > udg_STA_AbilityCounter
            set Node = udg_STA_NextNode[Node]
        
            if (u == udg_STA_Caster[Node]) then
                set scan = true
            endif

        endloop

        if (scan == false) then
            set udg_STA_AbilityCounter = udg_STA_AbilityCounter + 1
            
            //Checking for recycleable Nodes
            if (udg_STA_RecyclableNodes == 0) then
                set udg_STA_NodeNumber = udg_STA_NodeNumber + 1
                set Node = udg_STA_NodeNumber
            else
                set udg_STA_RecyclableNodes = udg_STA_RecyclableNodes - 1
                set Node = udg_STA_RecycleNodes[udg_STA_RecyclableNodes]
            endif

            //Sets up this Node
            set udg_STA_NextNode[Node] = 0
            set udg_STA_NextNode[udg_STA_LastNode] = Node
            set udg_STA_PrevNode[Node] = udg_STA_LastNode
            set udg_STA_LastNode = Node
            
            //Set up the data needed for the Aura
            set udg_STA_Level[Node] = I2R(GetUnitAbilityLevel(u, STA_AbilityID()))
            set udg_STA_StageID[Node] = 1
            set udg_STA_Caster[Node] = u
            set udg_STA_CasterNode[Node] = Node
            set udg_STA_CurrentEffect[Node] = AddSpecialEffectTarget(STA_AuraEffect(), u, STA_AuraAttachmentPoint())

            call STA_UpdateAura(Node)
            
            //Applies timer if this is the only instance of the aura
            if (udg_STA_AbilityCounter == 1) then
                call TimerStart(CreateTimer(), STA_TimerRate(), true, function STA_Loop)
            endif
        
        endif

        //Null variables
        set u = null   
    endif

    return false

endfunction

///////////////////////////////////////////////////////////////////
//  Initialisation trigger, applies the conditions to triggers   //
//  and sets up the global location used to get location Z's     //
///////////////////////////////////////////////////////////////////
function InitTrig_Soul_Tear_Aura takes nothing returns nothing
    //Set up locals
    local trigger STA
    local integer index = 0
    
    set STA = CreateTrigger()

    //Initialise the event for every player
    loop
        call TriggerRegisterPlayerUnitEvent(STA, Player(index), EVENT_PLAYER_HERO_SKILL, null)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop

    call TriggerAddCondition(STA, Condition(function STA_NewAura))
    
    //Set up the location used to find Z heights
    set udg_STA_ZLoc = Location(0,0)
    //Nulls trigger variable
    set STA = null
    
endfunction
///////////////////////////////////////////////////////////////////
// End of the spell                                              //
///////////////////////////////////////////////////////////////////


Next on the to-do-list is comment everything and write up a nice API

Edit: and a couple more Wips because why not
Wip4 is the aura just starting to take effect on nearby enemies
Wip5 is when a chain reaction has started, killing large volumes of the enemies
Wip6 is of units being healed when the hero using the aura dies
 

Attachments

  • Wip4.png
    Wip4.png
    248.4 KB · Views: 103
  • Wip5.png
    Wip5.png
    531.5 KB · Views: 113
  • Wip6.png
    Wip6.png
    244.6 KB · Views: 95
Last edited:
Level 25
Joined
Jul 10, 2006
Messages
3,315
oh its AURA ENTRY... maybe its difficult to make this :/

Look carefully at the OP:
Create an aura ability, which is either passive, active or toggle. The aura can affect yourself and your allies, your enemies or everyone in your presence.

So you can also make an active/toggled self-buff (like Avatar, Immolation, Metamorphosis) or something, which shouldn't be too difficult.

Tank-Commander is just being excessively cool with his aura... it's well above the benchmark so don't be intimidated that you have to make something so intense.
 
Look carefully at the OP:


So you can also make an active/toggled self-buff (like Avatar, Immolation, Metamorphosis) or something, which shouldn't be too difficult.

Tank-Commander is just being excessively cool with his aura... it's well above the benchmark so don't be intimidated that you have to make something so intense.

Sorry to intervene again, but you have some false information there. Metamorphosis and Avatar, unless they affect nearby units, they are not auras. In other words, self-buffs are not auras.
yourself and your allies
and != or :)
 

Kyrbi0

Arena Moderator
Level 45
Joined
Jul 29, 2008
Messages
9,495
Alright, I got 2 solid ideas for this, and both need to be done for my personal projects to boot (nothing like getting work done for a Contest). One's a vile Trollish malediction, while the other is a valiant Human benediction. I can't decide yet... So I may just make both & then ask you guys which I should submit. Lol.

"Pick the lame one!"
 
Entry: Soul Tear Aura

[TD]
Spell: Soul Tear Aura
Tootip:

Soul Tear Aura
Spirits strike nearby enemies damaging them, once struck attacks deal additional Magic damage to enemies. Enemies that die with this effect deal damage to other nearby enemies. Dying restores health to affected enemies

Level 1 - 35 strike damage, 7.5% additional damage, 30 damage done to nearby enemies, 150 Health restored on death
Level 2 - 45 strike damage, 10% additional damage, 50 damage done to nearby enemies, 200 Health restored on death
Level 3 - 55 strike damage, 12.5% additional damage, 70 damage done to nearby enemies, 250 Health restored on death
Code

JASS:
////////////////////////////////////////////////////////////////////
//                      SOUL TEAR AURA V1.00                      //
//                                                                //
//  Author: Tank-Commander                                        //
//  Requires: Dummy.mdl                                           //
//  Purpose: Tide-turner                                          //
//                                                                //
//  Notes:                                                        //
//    -  Read the readme before you try modifying the config      //
//    -  Use the "Helpful files" to help you import the spell     //
//                                                                //
//  Credits:                                                      //
//    -  (Dummy.mdl) Vexorian                                     //
//                                                                //
//                                                                //
//  If you have used this spell in your map, you are required     //
//  to give credits to Tank-Commander for the creation of it      //
//  If you would like to use snippets of code from this for       //
//  whatever, getting permission and crediting the source/linking //
//  would be much appreciated.                                    //
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  README:                                                       //
//    Before modifying this spell a few things need to be         //
//    understood and read, this is one of those things, while     //
//    most modification can be considered intuitive, it still     //
//    helps to read through these intstructions, as they will     //
//    inform you about how to configure this spell to your        //
//    desire.                                                     //
//----------------------------------------------------------------//
//  Initial importing: The variable creator trigger can be        //
//  imported first and if you have the correct settings (file,    //
//  preferences, General, automatically create unknown variables  //
//  checked, then when you paste in the variable creator it       //
//  will automatically give you all the variables you need for    //
//  this spell                                                    //
//----------------------------------------------------------------//
//  Effect Sets: The simple trigger comment "Effect Sets" is for  //
//  temporarily storing effect strings so that they can be added  //
//  to the spell more easily, as well as for storing multiple     //
//  sets without having to re-find the effect strings, largely    //
//  for finding the set you wish to use and trying out various    //
//  combinations                                                  //
//----------------------------------------------------------------//
//  This configuration is ordered by category of use, and not     //
//  alphabetically, the ones you're most likely to want to        //
//  change, are earlier in the readme, the most essential being   //
//  first. These categories are:                                  //
//                                                                //
//  - Data Values: The most essential to change, otherwise the    //
//                 spell will simply not function                 //
//                                                                //
//  - ChronoKinetic: Fancy word for affecting the flow of time    //
//                 Contains things like the duration of the       //
//                 spell, the Timer speed and Fragment removal    //
//                                                                //
//  - Aesthetics: Controls the Appearences of the ability - the   //
//                 models used, the scales of those models and    //
//                 so on                                          //
//                                                                //
//  - Damage: Controls the AOE and damage (health and mana)       //
//                 values each section of the spell has/uses      //
//                 as well as projectile speeds and movement      //
//                 (since it affects how effective the aura is)   //
//                                                                //
//  - Damage Information: Contains things like weapontypes and    //
//                 damage types, etc.                             //
//                                                                //
//  - Other Attributes: Contains the collision size of the        //
//                 Fragments, causes them to detonate             //
//----------------------------------------------------------------//
//                        DATA VALUES                             //
//----------------------------------------------------------------//
//  Ability ID: This is the raw data of the Aura ability, to see  //
//  raw data in the object editor, press Ctrl + D, doing this     //
//  again will switch it back, if you want to change this Spell   //
//  follow as displayed (use the first 4 characters in the raw    //
//  data and put them in ' markers)                               //
constant function STA_AbilityID takes nothing returns integer
    return 'A000'
endfunction
//----------------------------------------------------------------//
//  Buff Ability ID: This is the ability used to apply the buff   //
//  icon/description to affected units, in order to make the      //
//  aura function near-exactly to normal Warcraft 3 auras, also   //
//  unlike most Auras, this enabled magic-immunes to be filtered  //
//  out from being effected, while not giving them the buff icon  //
//  it also removes dependance on the the dummy ability having    //
//  any range, so the dummy Ability used for the aura can be any  //
//  passive spell, or even an active one with it's own effect.    //
//  This Buff ability should be based off Slow Aura (Tornado) as  //
//  it does not display on the command panel of units which have  //
//  it as an ability, this is to improve visuals, it should have  //
//  all values which affect units set to 0, though if you want a  //
//  slowing effect added (attack &/or movespeed) to the aura      //
//  then these values can be modified to add it, set the buff     //
//  you want displayed on units set as it's buff, it should also  //
//  have AOE set to 0 just in case.                               //
constant function STA_BuffAbilityID takes nothing returns integer
    return 'A001'
endfunction
//----------------------------------------------------------------//
//  Dummy ID: This is done in the same manner as the Ability ID   //
//  except that this time, you're doing it with unit raw date     //
//  see the dummy unit if you do not know already how to view     //
//  raw data                                                      //
constant function STA_DummyID takes nothing returns integer
    return 'u000'
endfunction
//----------------------------------------------------------------//
//                        CHRONOKINETIC                           //
//----------------------------------------------------------------//
//  Timer Speed: The default for this is ~0.03, it determines how //
//  many times per second these triggers are ran, normally you    //
//  want to leave this at ~0.03, but 0.04 and prehaps 0.05        //
//  would be good options if you computer lags a bit.             //
constant function STA_TimerRate takes nothing returns real
    return 0.031250000
endfunction
//----------------------------------------------------------------//
//  Check Timer Rate: The default value for this is 0.25, this    //
//  timer is used for checking the map for all units which have   //
//  the aura, and primarily serves to initialise these units      //
//  which wouldn't be picked up by the standard "learn" method    //
//  this includes units which are created at runtime through      //
//  trigger actions, ones already placed on the map and those     //
//  which are trained, starting with the aura                     //
constant function STA_CheckTimerRate takes nothing returns real
    return 0.25
endfunction
//----------------------------------------------------------------//
//  Check Timer Periodic: Determines whether or not the Check     //
//  Timer runs constantly all the time without stopping, thus     //
//  allowing it to pick up more than pre-placed units, this       //
//  should always be set to false if no units will gain this      //
//  ability through any means other than learning it, or being    //
//  preplaced unit on the map, as it would just be wasteful       //
constant function STA_CheckTimerPeriodic takes nothing returns boolean
    return false
endfunction
//----------------------------------------------------------------//
//  Dummy Removal Delay: Determines how long after the death of a //
//  fragment, for it be removed from the game completely, this is //
//  so death effects, can finish playing before the unit is       //
//  removed, 1.8 is default, 2 is probably excessive and in some  //
//  cases it's possible that 1 could be too little                //
constant function STA_DummyRemovalDelay takes nothing returns real
    return 1.8
endfunction
//----------------------------------------------------------------//
//  Effect Reduction Delay: Determines how long between each      //
//  bonus damage effect, before another one can be created, this  //
//  is because without this the effect would spam causing         //
//  a significant FPS drop, 0.5 is the defaults value of this     //
constant function STA_EffectReductionDelay takes nothing returns real
    return 0.5
endfunction
//----------------------------------------------------------------//
//                        AESTHETICS                              //
//----------------------------------------------------------------//
//  Note: Effects must have valid pathnames and must not be set   //
//  to null values, otherwise graphical errors are likely to      //
//  occur, if an effect can be left null, it will be marked       //
//----------------------------------------------------------------//
//  Aura Effect: This determines the model used for your main     //
//  aura, you want to use the model path and paste it into the    //
//  double quotes or " markers, if the path has only single       //
//  slashes (\) you'll need to changeb it to double slash (\\)    //
//  before you save, the spell will not work if you do not do     //
//  this (if you acidentally save with the single slash (\) it    //
//  will still save but you may find yourself having a lingering  //
//  progress bar at full percentage, you can ignore it  for the   //
//  most part, but if you have it, you probably haven't entered   //
//  this field correctly. Get the model paths from the Object     //
//  editor - find the model you want (the model, not the unit,    //
//  in the models list, select it and hit enter twice, then       //
//  select the path (will look similar to this default value,     //
//  and paste in it here) I suggest doing this with a unit of no  //
//  value (changing the model to get the model path) and then     //
//  reset the field afterwards to get the unit back to normal,    //
//  this function must return a valid value, to make "remove"     //
//  effects from the spell (for those without "Use" functions     //
//  to disable them) you can enter the path of dummy.mdl (this    //
//  can differ from map to map depending on how you imported it)  //
//  and this will cause the system to create invisible effects    //
//  so that the spell can still run properly                      //
constant function STA_AuraEffect takes nothing returns string
    return "Abilities\\Spells\\Undead\\RegenerationAura\\ObsidianRegenAura.mdl"
endfunction
//----------------------------------------------------------------//
//  Soul Fragment Effect:This determines the effect displayed on  //
//  enemies who are within the AOE of the aura, it is the buff    //
//  effect of the spell, and therefore must have a valid value    //
constant function STA_SoulFragmentEffect takes nothing returns string
    return "Abilities\\Spells\\Undead\\Curse\\CurseTarget.mdl"
endfunction
//----------------------------------------------------------------//
//  Soul Fragment Projectile Effect: This is the effect used for  //
//  the projectiles or "spirits" that strike enemy targets which  //
//  activate the effect of the aura on impact, the same effect    //
//  is used for "spirits" that appear on unit death.              //
constant function STA_SoulFragmentProjectileEffect takes nothing returns string
    return "Abilities\\Weapons\\GreenDragonMissile\\GreenDragonMissile.mdl"
endfunction
//----------------------------------------------------------------//
//  Initial Damage Effect: This determines the effect used when   //
//  a unit is hit by the homing spirits and activate the initial  //
//  effect, this is one of the few effects that can be null but   //
//  only if "Use Initial Damage Effect" is set to false           //
constant function STA_InitialDamageEffect takes nothing returns string
    return "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
endfunction
//----------------------------------------------------------------//
//  Death Damage Effect: This determines the effect used when     //
//  a spirit created by a dying unit detonates dealing damage     //
//  typically this will be the same as "Initial Damage Effect"    //
//  and can also be null if "Use Death Damage Effect" is false    //
constant function STA_DeathDamageEffect takes nothing returns string
    return "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
endfunction
//----------------------------------------------------------------//
//  Bonus Damage Effect: This determines the effect created when  //
//  a unit takes bonus magic damage from the aura, it's limited   //
//  by the "Effect Reduction Delay" value, it cannot be set to    //
//  null, however                                                 //
constant function STA_BonusDamageEffect takes nothing returns string
    return "Abilities\\Spells\\Items\\AIil\\AIilTarget.mdl"
endfunction
//----------------------------------------------------------------//
//  Heal Effect: This is the effect used when the hero creating   //
//  the aura effect dies and nearby enemies are healed afterward  //
//  this should have a positive look unless the value you give    //
//  for the damage value of the heal effect is set to a negative  //
//  if "Use Heal Effect" is false, then this can be set to null   //
constant function STA_HealEffect takes nothing returns string
    return "Abilities\\Spells\\Human\\DispelMagic\\DispelMagicTarget.mdl"
endfunction
//----------------------------------------------------------------//
//  Aura Attachment Point: Set this to the desired attachment     //
//  point of the aura, typically this will be "origin" as most    //
//  warcraft 3 auras use it for this effect valid attachment      //
//  points include: "origin", "overhead", "head", "chest", and    //
//  "left, [limb]", "right, [limb]" limbs: "foot", "hand"         //
constant function STA_AuraAttachmentPoint takes nothing returns string
    return "origin"
endfunction
//----------------------------------------------------------------//
//  Soul Fragment Attachment Point: This is the attachment point  //
//  of where the buff of being effected will appear, typically    //
//  this will be set to "overhead" as most Warcraft 3 auras use   //
constant function STA_SoulFragmentAttachmentPoint takes nothing returns string
    return "overhead"
endfunction
//----------------------------------------------------------------//
//  Soul Fragmnet Projectile Attachment Point: The attachment     //
//  point for the projectile on the dummy unit, what this is set  //
//  to doesn't particularly make much difference so long as it's  //
//  valid, try various settings to get one you like the look of   //
//  typically, it'll be set to chest, just to centre it           //
constant function STA_SoulFragmentProjectileAttachmentPoint takes nothing returns string
    return "origin"
endfunction
//----------------------------------------------------------------//
//  Initial Damage Attachment Point: This is the attachment       //
//  point of the effect created when the "Spirits" hit units to   //
//  activate the aura effect on them, this also doesn't normally  //
//  make any difference, typically it will be set to the same     //
//  value as "Soul Fragment Projectile Attachment Point"          //
constant function STA_InitialDamageAttachmentPoint takes nothing returns string
    return "chest"
endfunction
//----------------------------------------------------------------//
//  Death Damage Attachment Point: Determines the attachment      //
//  point for the effect created when "Spirits" made by a unit    //
//  dying impact, this is typically set to the same value as      //
//  "Soul Fragment Projectile Attachment Point" but it doesn't    //
//  really make any difference so long as it's valid              //
constant function STA_DeathDamageAttachmentPoint takes nothing returns string
    return "chest"
endfunction
//----------------------------------------------------------------//
//  BonusDamageAttachmentPoint: Determines the attachment point   //
//  of the effect generated when a unit takes bonus damage as a   //
//  result of the aura, "origin", "chest", and "overhead" all     //
//  suit this effect depending on the model used, for most it     //
//  looks/works best with "chest", however any can be used        //
constant function STA_BonusDamageAttachmentPoint takes nothing returns string
    return "chest"
endfunction
//----------------------------------------------------------------//
//  Heal Effect Attachment Point: Controls the attachment point   //
//  of the heal effect created when the unit/hero with the aura   //
//  has died, similar to the bonus damage "origin", "chest" and   //
//  "overhead" are all good matches for this attachment point     //
//  for the same reason                                           //
constant function STA_HealEffectAttachmentPoint takes nothing returns string
    return "chest"
endfunction
//----------------------------------------------------------------//
//  Soul Fragment Projectile Scale Base: This determines the      //
//  size of the projectiles created by the aura, the value is a   //
//  percentage, so 1 = 100%, and thus the default size of the     //
//  effect, depending on the effect used this will often need to  //
//  be a fractional value. Default is 0.6 or .6                   //
constant function STA_SoulFragmentProjectileScaleBase takes nothing returns real
    return .6
endfunction
//----------------------------------------------------------------//
//  Soul Fragment Projectile Scale Per Level: The extra size      //
//  given to projectiles for every level of the spell, this is    //
//  normally 0, but available if users wish to alter the size     //
//  to make the spell appear more menacing as it levels up        //
constant function STA_SoulFragmentProjectileScalePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  Soul Fragment Height Start Offset: This is the height added   //
//  on to the base height of the unit creating the effect, that   //
//  projectiles start at, 0 will be at their feet, 30 will often  //
//  be chets height, and 60 overhead, try out various heights to  //
//  see what you feel fits best                                   //
constant function STA_SoulFragmentHeightStartOffset takes nothing returns real
    return 100.
endfunction
//----------------------------------------------------------------//
//  Soul Fragment Height End Offset: The same as above but for    //
//  the height added onto the target's fly height that will be    //
//  reached when the "Spirit"/Projectile hits the target rather   //
//  than start at, again 0 is foot height, 30 is chest and 60 is  //
//  overhead, typically this value is lower than the start height //
constant function STA_SoulFragmentHeightEndOffset takes nothing returns real
    return 90.
endfunction
//----------------------------------------------------------------//
//  Use Initial Damage Effect: This boolean value determines if   //
//  the effect generated by the "spirits" or projectiles hitting  //
//  their target to start the effect of the ability is used,      //
//  setting to false will remove it, and thus the model used for  //
//  the effect can be null, as giving it a value will not make    //
//  any difference                                                //
constant function STA_UseInitialDamageEffect takes nothing returns boolean
    return true
endfunction
//----------------------------------------------------------------//
//  Use Death Damage Effect: Similar to the above boolean but     //
//  this one is for the effect created when projectiles made by   //
//  units dying impact and detonate, again setting it to false    //
//  removes the effect and thus enabled the value to be set to    //
//  null for the model string                                     //
constant function STA_UseDeathDamageEffect takes nothing returns boolean
    return true
endfunction
//----------------------------------------------------------------//
//  Use Heal Effect: Once again the same as above, however in     //
//  this case for the effect generated when units are healed from //
//  the Hero/Unit with the aura dying. unless the feature is      //
//  removed (setting the amount healed to 0) it makes sense for   //
//  this value to be set to true                                  //
constant function STA_UseHealEffect takes nothing returns boolean
    return true
endfunction
//----------------------------------------------------------------//
//                            DAMAGE                              //
//----------------------------------------------------------------//
//  AOE Base: This is your basic area of effect for your ability  //
//  it should be the highest AOE of the ability as such,          //
//  typically, this value should be at least 200, units in this   //
//  area will have Fragment launched at them and begin the bonus  //
//  damage effect                                                 //
constant function STA_AOEBase takes nothing returns real
    return 275.
endfunction
//----------------------------------------------------------------//
//  AOE Per Level: This is the amount of extra AOE given on top   //
//  of the basic AOE for each level of the spell that the hero    //
//  has,this will also be applied for level one                   //
constant function STA_AOEPerLevel takes nothing returns real
    return 75.
endfunction
//----------------------------------------------------------------//
//  Search AOE Base: Determines how far away from the location    //
//  of a dying unit effected by the aura, will be considered a    //
//  valid target, keep in mind, targets which are effected by     //
//  the aura, even if a different unit is the source, are valid   //
//  If this is set to 0, alone with "Search AOE Per Level", the   //
//  effect of damage being done by units dying will be removed    //
constant function STA_SearchAOEBase takes nothing returns real
    return 90.
endfunction
//----------------------------------------------------------------//
//  Search AOE Per Level: The Per Level value of the Search AOE   //
//  Base value, typically this will be a fraction of the base     //
//  value between 1/2 and 1/4 of the base value for balance       //
//  if this is set to 0, as well as "Search AOE Base", the effect //
//  of extra damage being done by units dying will be removed     //
constant function STA_SearchAOEPerLevel takes nothing returns real
    return 35.
endfunction
//----------------------------------------------------------------//
//  Impact AOE Base: Determines the AOE of the damaging effect    //
//  when a "Spirit" inflicts damage, this applies for both the    //
//  initial, homing projectiles, and the non-homing ones created  //
//  by unit death, this should be higher than the collision size  //
//  in order to avoid damageless impacts, and should be between   //
//  values of 50-100 typically, default is 75                     //
constant function STA_ImpactAOEBase takes nothing returns real
    return 75.
endfunction
//----------------------------------------------------------------//
//  Impact AOE Per Level: Determines how much extra AOE damage    //
//  effects have on top of the Impact AOE Base, and applies at    //
//  level one, as with all Per Level values, typically this is    //
//  set between 0-20 for balancing reasons and to reduce chain    //
//  killing becoming too common/likely to take out huge sections  //
//  of enemies                                                    //
constant function STA_ImpactAOEPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  Soul Fragment Projectile Speed Base: This is the true value   //
//  speed of projectiles, and how far the projectiles will move   //
//  per second, having a particularly high value (over 1000) will //
//  likely cause accuracy issues and overshooting with the spell  //
//  a value between 200-500 is typical, default value is 288      //
constant function STA_SoulFragmentProjectileSpeedBase takes nothing returns real
    return 288.
endfunction
//----------------------------------------------------------------//
//  Soul Fragment Projectile Speed Per Level: The per level       //
//  counterpart of "Soul Fragment Projectile Speed Base", when    //
//  combined with that value, the total should not exceed 1200    //
//  for the reasons described above, remember that this applies   //
//  even on the first level, a value between 0-200 is typical     //
//  default value is 192                                          //
constant function STA_SoulFragmentProjectileSpeedPerLevel takes nothing returns real
    return 192.
endfunction
//----------------------------------------------------------------//
//  Soul Fragment Projectile Hit Time Base: This is the optional  //
//  movement type of the projectiles, which alters the velocity   //
//  based on how long it takes for them to hit their target in    //
//  seconds, creating a rather different effect from using true   //
//  speed, this value in combination with the per level size      //
//  should not become lower than 1/6th of a second if inaccuracy  //
//  issues are to be avoided (units farther away with a short     //
//  hit time, generate much higher true speeds on the projectile) //
//  WARNING: if the sum of this value and its per level side end  //
//  up with values less than 0.5, depending on the impact AOE     //
//  used by the spell, not only may inaccuracy occur, but the     //
//  game may crash due to projectiles getting too fast. This      //
//  normally occurs because the real speed applied to the         //
//  projectile exceeds the AOE of the impact area; with the       //
//  default set up, this means that the projectile has to be      //
//  moving at over 2500m/s, while applying this value to the real //
//  speed option for the spell is unlikely to cause crashing;     //
//  it cannot be done here as if targets move away from the aura  //
//  projectiles speed up (in order to maintain the hit time)      //
//  meaning that if a projectile overshoots, it will only get     //
//  even faster, and typically leave the map (causing crash)      //
constant function STA_SoulFragmentProjectileHitTimeBase takes nothing returns real
    return 2.
endfunction
//----------------------------------------------------------------//
//  Soul Fragment Projectile Hit Time Per Level: One of the only  //
//  values which is typically negative, this is so that the time  //
//  taken to hit targets is reduced every level, so that they     //
//  move faster, making this a positive value will makes them     //
//  slower, remember; this applies to level 1, as well. default   //
//  value is -0.4. Keep in mind that if the total becomes very    //
//  small, inaccuracy issues may occur (and possibly game crash)  //
constant function STA_SoulFragmentProjectileHitTimePerLevel takes nothing returns real
    return -0.5
endfunction
//----------------------------------------------------------------//
//  Soul Fragment Movement Type: Determines the form of movement  //
//  used by the projectiles, true activated the Hit Time values   //
//  while false enables the Projectile Speed values or true       //
//  speed, the effect generated by the different movement types   //
//  are very different, so try out both if you're unsure          //
constant function STA_SoulFragmentMovementType takes nothing returns boolean
    return false
endfunction
//----------------------------------------------------------------//
//  Initial Effect Health Damage Base: This is the amount of hp   //
//  damage dealt when the "Spirits"/Projectiles first hit enemy   //
//  units and start the effect of the aura on them reducing it    //
//  to 0 removes all damage and makes the first stage simply an   //
//  activation effect. The true damage dealt by this effect is    //
//  affected by type of damage used by the aura                   //
constant function STA_InitialEffectHealthDamageBase takes nothing returns real
    return 25.
endfunction
//----------------------------------------------------------------//
//  Initial Effect Health Damage Per Level: The per level side    //
//  to the base health damage, added on to the base value even    //
//  at level 1 as with all per level values. to remove the        //
//  effect this should also be set to 0                           //
constant function STA_InitialEffectHealthDamagePerLevel takes nothing returns real
    return 10.
endfunction
//----------------------------------------------------------------//
//  Initial Effect Mana Damage Base: Determines how much mana     //
//  damage is done by the initial activation effect of the aura   //
//  typically this is 0, but is available if users wish to have   //
//  it, this is a true value and is thus unaffected by the type   //
//  of damage used by the aura if set to a negative value, it     //
//  will restore mana to targets rather than remove it            //
constant function STA_InitialEffectManaDamageBase takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  Initial Effect Mana Damage Per Level: Determines how much     //
//  extra mana damage is dealt by the spell per level, typically  //
//  also set to 0, but again available if users wish to have it   //
constant function STA_InitialEffectManaDamagePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  Death Health Damage Base: This is the amount of Hp damage     //
//  dealt by "Spirits"/Projectiles created by units dying with    //
//  the aura affecting them, actual damage dealt by this is       //
//  altered by the type of damage used by the spell rather than   //
//  a fixed value, typically this is the main damage dealing part //
//  of the ability and causes chain-kills even with low values    //
constant function STA_DeathHealthDamageBase takes nothing returns real
    return 10.
endfunction
//----------------------------------------------------------------//
//  Death Health Damage Per Level: The extra amount of Hp damage  //
//  dealt by the "Spirits"/Projectiles created by units dying     //
//  with the aura affecting them, very similar to the Base part   //
constant function STA_DeathHealthDamagePerLevel takes nothing returns real
    return 20.
endfunction
//----------------------------------------------------------------//
//  Death Mana Damage Base: The Base mana damage dealt by the     //
//  "Spirits"/Projectiles created by units dying with the aura    //
//  affecting them, this is true damage and is thus unaffected    //
//  by the type of damage used by the spell, setting this to a    //
//  negative value will restore mana rather than damage enemies   //
constant function STA_DeathManaDamageBase takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  Death Mana Damage Per Level: The per level counterpart to     //
//  "Death Mana Damage Base", also true damage and added on to    //
//  all levels (multiplied by the level of the ability)           //
constant function STA_DeathManaDamagePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  Bonus Health Damage Percent Base: Determines the amount of    //
//  bonus Hp damage dealt by all damage sources on the affected   //
//  units, only activated after they have been hit by the         //
//  initial "Spirit"/Projectile. This is a percentage value thus  //
//  setting this value to 1 = 100% damage increase, typically     //
//  this should be a low percentage, as damage adds up quickly    //
//  the resulting damage of this is affected by the damage type   //
//  used by the ability, default value is 0.1 or .1 (10%)         //
constant function STA_BonusHealthDamagePercentBase takes nothing returns real
    return .05
endfunction
//----------------------------------------------------------------//
//  Bonus Health Damage Percent Per Level: The Per Level side to  //
//  The "Bonus Health Damage Percent Base", typically a lower     //
//  fractional number, 0.05 or .5 is the default (5%)             //
constant function STA_BonusHealthDamagePercentPerLevel takes nothing returns real
    return .025
endfunction
//----------------------------------------------------------------//
//  Bonus Mana Damage Percent Base: Determines the amount of      //
//  bonus Mana damage dealt by all mana damage sources to the     //
//  affected units, only starts applying once they have been hit  //
//  by the initial "Spirit"/Projectile. Also a percentage value   //
//  but a True value, thus unaffected by the damage type of the   //
//  ability, setting it to a negative value will restore mana     //
//  instead of destroying it                                      //
constant function STA_BonusManaDamagePercentBase takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  Bonus Mana Damage Percent Per Level: A Per Level counterpart  //
//  to the Base value, typically lower than that Base value, and  //
//  even then often less than 10% or 0.1 (.1)                     //
constant function STA_BonusManaDamagePercentPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  Hero Health Heal Base: This is the amount of health restored  //
//  to enemy units when the hero generating the aura has been     //
//  slain, default value is 100, this is a true value and thus    //
//  ingores damage type used by the spell, unlike all other       //
//  health damage dealt by this aura. Setting this to a negative  //
//  value will cause it to deal damage rather than heal enemies   //
//  WARNING: This damage does not recognise the damage source,    //
//  Units killed by this effect will NOT give gold to the owner   //
//  of the unit with the aura, nor count as them having killed    //
//  those units                                                   //
constant function STA_HeroHealthHealBase takes nothing returns real
    return 100.
endfunction
//----------------------------------------------------------------//
//  Hero Health Heal Per Level: The extra health given to units   //
//  when the unit/hero generating the aura has been slain, this   //
//  is added on to the Base value (multiplied by the level of     //
//  the aura) and is a true value                                 //
constant function STA_HeroHealthHealPerLevel takes nothing returns real
    return 50.
endfunction
//----------------------------------------------------------------//
//  Hero Mana Heal Base: Determines the amount of mana given to   //
//  units when the unit/hero creating the aura is slain, it is a  //
//  true value thus unaffected by the damagetype used by the      //
//  aura, setting this to a negative value will remove mana       //
//  rather than add it                                            //
constant function STA_HeroManaHealBase takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  Hero Mana Heal Per Level: The extra amount of mana given to   //
//  units when the unit/hero creating the aura is slain, also a   //
//  true value and added on (multiplied by the level of the aura) //
//  to the base value, setting this to a negative value will      //
//  remove mana rather than add it                                //
constant function STA_HeroManaHealPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//                    DAMAGE INFORMATION                          //
//----------------------------------------------------------------//
//  Damage Type: These determine the damagetypes, changing this   //
//  will modify the damage multiplyers vs certain enemies         //
//  the standard is DAMAGE_TYPE_MAGIC, note that this spell       //
//  automatically discludes magic immunes, so changing this       //
//  damage type will not make them start taking damage            //
constant function STA_AttackType takes nothing returns attacktype
    return ATTACK_TYPE_MAGIC
endfunction
//----------------------------------------------------------------//
//  Attack Type: This is very much so basically the same as       //
//  Damage Type, generally you'll want this to match with it      //
//  as such the default is ATTACK_TYPE_MAGIC, though Damagetype   //
//  is a key factor for determining bonuses rather than this      //
//  but unlike weapontype, you cannot have null as a setting      //
constant function STA_DamageType takes nothing returns damagetype
    return DAMAGE_TYPE_MAGIC
endfunction
//----------------------------------------------------------------//
//  Weapon Type: This alters what kind of weapon type is used by  //
//  the spell, those without knowledge of weapontypes don't       //
//  worry, you're not missing much, this spell doesn't really     //
//  use it, hence the default of null, but if you want to use     //
//  them, no reason to not.                                       //
constant function STA_WeaponType takes nothing returns weapontype
    return null
endfunction
//----------------------------------------------------------------//
//                     OTHER ATTRIBUTES                           //
//----------------------------------------------------------------//
//  Collision Size: Used for determining at what point has a      //
//  Fragment hit a target, you typically want this value above    //
//  30 but below 90, and it should always be larger than the      //
//  Damage AOE of the spell, otherwise the system will register   //
//  a collision, and then fail to deal any damage to the units    //
constant function STA_CollisionSize takes nothing returns real
    return 30.
endfunction
//----------------------------------------------------------------//
//  You have now reached the end of the configuration, below are  //
//  the functions used to run the spell, beyond this point if     //
//  you find any constant values (indicated in Blue like the      //
//  other constants here if you have standard syntax highlighting //
//  they're there for a reason and don't fiddle with them, to     //
//  actually make any modifications I hope you're an experienced  //
//  programmer, though do not hassle for help because I don't     //
//  take responcibility for other people's programming skills     //
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  Function used to get the z height of locations needed by the  //
//  spell, since it can only be done with locations, this one     //
//  is reused throughout, instead of creating/destroying them     //
////////////////////////////////////////////////////////////////////
function STA_GetZ takes real x, real y returns real

    //Gets the location Z of the selected location
    call MoveLocation(udg_STA_ZLoc, x, y)
    return GetLocationZ(udg_STA_ZLoc)
    
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to calculate the speed of which any given       //
//  projectile must travel based on the form of movement that     //
//  has been selected in the configuration by the user            //
////////////////////////////////////////////////////////////////////
function STA_GetSpeed takes integer Node, real Distance returns real
    
    //Calculate Speed
    if (STA_SoulFragmentMovementType()) then
        return (Distance / udg_STA_SoulProjectileHitTime[Node]) * STA_TimerRate()
    else
        return udg_STA_SoulProjectileSpeed[Node] * STA_TimerRate()
    endif

endfunction

////////////////////////////////////////////////////////////////////
//  Function used to recycle instances, so that they can used     //
//  again later, keeping the total array sizes smaller            //
////////////////////////////////////////////////////////////////////
function STA_Recycle takes integer Node, timer T returns nothing
            
        if (udg_STA_LastNode == Node) then
            set udg_STA_LastNode = udg_STA_PrevNode[Node]
        endif
           
        //Recycles the node
        set udg_STA_RecycleNodes[udg_STA_RecyclableNodes] = Node
        set udg_STA_RecyclableNodes = udg_STA_RecyclableNodes + 1
        set udg_STA_NextNode[udg_STA_PrevNode[Node]] = udg_STA_NextNode[Node]
        set udg_STA_PrevNode[udg_STA_NextNode[Node]] = udg_STA_PrevNode[Node]
        set udg_STA_AbilityCounter = udg_STA_AbilityCounter - 1

        //Checks if there are no iterations of the aura left
        //this is ,mostly an "in-case" part of the script, as it
        //is unlikely that this ever returns true (only if a unit unlearns the ability)
        if (udg_STA_AbilityCounter == 0) then
            call DestroyTimer(T)
        endif

endfunction

/////////////////////////////////////////////////////////////////////
//  Target filter function - passed units and players and checks   //
//  if the unit is allowed to be targetted by this ability         //
/////////////////////////////////////////////////////////////////////
function STA_TargetFilter takes unit u, player pl returns boolean

    //Checks if the unit can be used as a target
    if (not IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)) and (IsUnitEnemy(u, pl)) and (GetUnitTypeId(u) != STA_DummyID()) and (GetWidgetLife(u) > 0.405) then
        return true
    endif
    
    return false

endfunction

////////////////////////////////////////////////////////////////////
//  This function handles the damage dealt to units by the        //
//  projectiles, including health and mana in one function,       //
//  since both forms of projectile use the same damage method     //
////////////////////////////////////////////////////////////////////
function STA_SoulProjectileDamage takes real x, real y, integer Node returns nothing
     //Declare Locals
    local unit u
    local player pl = GetOwningPlayer(udg_STA_Caster[Node])

    //Finds units within the AOE of the impact point which may be damaged
    call GroupEnumUnitsInRange(udg_STA_TempGroup, x, y, udg_STA_ImpactAOE[udg_STA_CasterNode[Node]], null) 
    set pl = GetOwningPlayer(udg_STA_Caster[Node])
                
    loop
       //Scanning through
       set u = FirstOfGroup(udg_STA_TempGroup)
       exitwhen u == null
                           
       //Select all the units which are to be damaged
       if (STA_TargetFilter(u, pl)) then
            call UnitDamageTarget(udg_STA_Caster[Node], u, udg_STA_HealthDamage[Node], false, false, STA_AttackType(), STA_DamageType(), STA_WeaponType())
            call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - udg_STA_ManaDamage[Node])
       endif

       //Remove the unit from the unit group
       call GroupRemoveUnit(udg_STA_TempGroup, u)
    endloop
    
    //Null variables
    set pl = null

endfunction

////////////////////////////////////////////////////////////////////
//  Function used to create each projectile and set up all the    //
//  information they need to run, since both the caster and the   //
//  affected units can produce these projectiles                  //
////////////////////////////////////////////////////////////////////
function STA_CreateProjectile takes real x, real y, real z, real zSpeed, real Speed, real Angle, real Distance, real HealthDamage, real ManaDamage, integer Node, boolean Type, integer Target returns nothing
    //Create Locals
    local integer TempNode
    
    //Adds a new instance to the linked list
    set udg_STA_AbilityCounter = udg_STA_AbilityCounter + 1
    
    //Checking for recycleable Nodes
    if (udg_STA_RecyclableNodes == 0) then
        set udg_STA_NodeNumber = udg_STA_NodeNumber + 1
        set TempNode = udg_STA_NodeNumber
    else
        set udg_STA_RecyclableNodes = udg_STA_RecyclableNodes - 1
        set TempNode = udg_STA_RecycleNodes[udg_STA_RecyclableNodes]
    endif

    //Adds a new instance
    set udg_STA_NextNode[TempNode] = 0
    set udg_STA_NextNode[udg_STA_LastNode] = TempNode
    set udg_STA_PrevNode[TempNode] = udg_STA_LastNode
    set udg_STA_LastNode = TempNode
    set udg_STA_Caster[TempNode] = udg_STA_Caster[Node]
    set udg_STA_CasterNode[TempNode] = udg_STA_CasterNode[Node]
    
    //Creates the unit and sets up aesthetics
    set udg_STA_Unit[TempNode] = CreateUnit(Player(14), STA_DummyID(), x, y, Angle)
    if UnitAddAbility(udg_STA_Unit[TempNode], 'Amrf') and UnitRemoveAbility(udg_STA_Unit[TempNode], 'Amrf') then
    endif
    set udg_STA_CurrentEffect[TempNode] = AddSpecialEffectTarget(STA_SoulFragmentProjectileEffect(), udg_STA_Unit[TempNode], STA_SoulFragmentProjectileAttachmentPoint())
    call SetUnitScale(udg_STA_Unit[TempNode], udg_STA_SoulFragmentScale[Node],0.,0.)
    call SetUnitFlyHeight(udg_STA_Unit[TempNode], z - STA_GetZ(x, y), 0)
    
    //Sets up the values it needs to run properly
    set udg_STA_StageID[TempNode] = 3
    set udg_STA_ZSpeed[TempNode] = zSpeed
    set udg_STA_Speed[TempNode] = Speed
    set udg_STA_HealthDamage[TempNode] = HealthDamage
    set udg_STA_ManaDamage[TempNode] = ManaDamage
    set udg_STA_FragmentType[TempNode] = Type
    
    set udg_STA_DistanceTravelled[TempNode] = 0.
  
    //Checks if it's an initial projectile
    //or one made when a unit dies  
    if (Type) then
        //Sets up the target of the projectile
        set udg_STA_Target[TempNode] = udg_STA_Unit[Target]
        set udg_STA_TargetID[TempNode] = Target
    else
        //Set the distance the projectile can travel
        set udg_STA_MaxDistance[TempNode] = Distance
        //Resets projectile data (prevents errors when recycling)
        set udg_STA_TargetID[TempNode] = 0
        set udg_STA_Target[TempNode] = null
    endif
    
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to find all units associated with a caster and  //
//  remove the effects, apply healing to units that have ceased   //
//  to be affected, and destroy projectiles that were created by  //
//  the aura (they do not deal damage when this occurs            //
////////////////////////////////////////////////////////////////////
function STA_AuraEnd takes integer Node returns nothing
    //Declare locals
    local integer TempInt = 0
    local integer TempNode = 0

    //Begin search for units
    loop
        //Moves to the next node
        set TempInt = TempInt + 1
        exitwhen TempInt > udg_STA_AbilityCounter
        set TempNode = udg_STA_NextNode[TempNode]
                    
        //Finds units which "belong" to this instance
        if (udg_STA_Caster[TempNode] == udg_STA_Caster[Node]) then

            //Checks the type of unit (2 = affected unit, 3 = Projectile)
            if (udg_STA_StageID[TempNode] == 2) then

                //Checks if the heal effect is in use
                if (STA_UseHealEffect()) then
                    call DestroyEffect(AddSpecialEffectTarget(STA_HealEffect(), udg_STA_Unit[TempNode], STA_HealEffectAttachmentPoint()))
                endif

                //Heals the units
                call SetWidgetLife(udg_STA_Unit[TempNode], udg_STA_CurrentHealth[TempNode] + udg_STA_HeroHealthHeal[Node])
                call SetUnitState(udg_STA_Unit[TempNode], UNIT_STATE_MANA, udg_STA_CurrentMana[TempNode] + udg_STA_HeroManaHeal[Node])
                //Recycles the instance and enables reselection as a target
                call DestroyEffect(udg_STA_CurrentEffect[TempNode])
                call UnitRemoveAbility(udg_STA_Unit[TempNode], STA_BuffAbilityID())
                call GroupRemoveUnit(udg_STA_AffectedUnits,udg_STA_Unit[TempNode])
                call STA_Recycle(TempNode, GetExpiredTimer())
                set TempInt = TempInt - 1
            elseif (udg_STA_StageID[TempNode] == 3) then

                //Checks if the death damage effect is enabled
                if (STA_UseDeathDamageEffect()) then
                    call DestroyEffect(AddSpecialEffectTarget(STA_DeathDamageEffect(), udg_STA_Unit[TempNode], STA_DeathDamageAttachmentPoint()))
                endif

                //Destroys the effect and starts the recycling process for projectiles
                call DestroyEffect(udg_STA_CurrentEffect[TempNode])
                set udg_STA_StageID[TempNode] = 4
            endif

        endif

    endloop

endfunction
////////////////////////////////////////////////////////////////////
//  Function used to update the stats for Heros generating the    //
//  aura, so that level ups are in effect instantly               //
////////////////////////////////////////////////////////////////////
function STA_UpdateAura takes integer Node returns nothing

    //Updates all the stat values of the hero when it levels up
    set udg_STA_SoulFragmentScale[Node] = STA_SoulFragmentProjectileScaleBase() + (STA_SoulFragmentProjectileScalePerLevel() * udg_STA_Level[Node])
    set udg_STA_AOE[Node] = STA_AOEBase() + (STA_AOEPerLevel() * udg_STA_Level[Node])
    set udg_STA_SearchAOE[Node] = STA_SearchAOEBase() + (STA_SearchAOEPerLevel() * udg_STA_Level[Node])
    set udg_STA_ImpactAOE[Node] = STA_ImpactAOEBase() + (STA_ImpactAOEPerLevel() * udg_STA_Level[Node])
    set udg_STA_SoulProjectileSpeed[Node] = STA_SoulFragmentProjectileSpeedBase() + (STA_SoulFragmentProjectileSpeedPerLevel() * udg_STA_Level[Node])
    set udg_STA_SoulProjectileHitTime[Node] = STA_SoulFragmentProjectileHitTimeBase() + (STA_SoulFragmentProjectileHitTimePerLevel() * udg_STA_Level[Node])
    set udg_STA_InitialEffectHealthDamage[Node] = STA_InitialEffectHealthDamageBase() + (STA_InitialEffectHealthDamagePerLevel() * udg_STA_Level[Node])
    set udg_STA_InitialEffectManaDamage[Node] = STA_InitialEffectManaDamageBase() + (STA_InitialEffectManaDamagePerLevel() * udg_STA_Level[Node])
    set udg_STA_DeathHealthDamage[Node] = STA_DeathHealthDamageBase() + (STA_DeathHealthDamagePerLevel() * udg_STA_Level[Node])
    set udg_STA_DeathManaDamage[Node] = STA_DeathManaDamageBase() + (STA_DeathManaDamagePerLevel() * udg_STA_Level[Node])
    set udg_STA_BonusHealthDamagePercent[Node] = STA_BonusHealthDamagePercentBase() + (STA_BonusHealthDamagePercentPerLevel() * udg_STA_Level[Node])
    set udg_STA_BonusManaDamagePercent[Node] = STA_BonusManaDamagePercentBase() + (STA_BonusManaDamagePercentPerLevel() * udg_STA_Level[Node])
    set udg_STA_HeroHealthHeal[Node] = STA_HeroHealthHealBase() + (STA_HeroHealthHealPerLevel() * udg_STA_Level[Node])
    set udg_STA_HeroManaHeal[Node] = STA_HeroManaHealBase() + (STA_HeroManaHealPerLevel() * udg_STA_Level[Node])
    
endfunction

////////////////////////////////////////////////////////////////////
//  The main loop function of the spell, it handles the main      //
//  operations of the ability such as assigning new units,        //
//  moving projectiles and dealing bonus damage to units          //
////////////////////////////////////////////////////////////////////
function STA_Loop takes nothing returns nothing
    //Declare Locals
    local integer Node = 0
    local integer TempNode = 0
    local integer TempInt = 0
    local integer TempInt2 = 0
    local real TempReal
    local real TempReal2
    local real TempReal3
    local real x
    local real y
    local real x2
    local real y2
    local real z
    local real z2
    local real Angle
    local unit u
    local player pl
    
    //Main loop
    loop
        //Moves to the next node
        set TempInt = TempInt + 1
        exitwhen TempInt > udg_STA_AbilityCounter
        set Node = udg_STA_NextNode[Node]

        //Checks which node the unit belongs to
        //Ordered to be more efficient and labelled
        //In order of occurence:
        //StageID = 3, Projectiles
        if (udg_STA_StageID[Node] == 3) then
            set x = GetUnitX(udg_STA_Unit[Node])
            set y = GetUnitY(udg_STA_Unit[Node])
                        
            //Calculate the next position
            set x2 = x + udg_STA_Speed[Node] * Cos(GetUnitFacing(udg_STA_Unit[Node]) * bj_DEGTORAD)
            set y2 = y + udg_STA_Speed[Node] * Sin(GetUnitFacing(udg_STA_Unit[Node]) * bj_DEGTORAD)
            //Check the difference in height between it's current point and next point
            set TempReal = STA_GetZ(x, y)
            set TempReal2 = STA_GetZ(x2, y2)
            
            //Account for height difference
            if not(TempReal == TempReal2) then
                set TempReal = TempReal - TempReal2
            else
                set TempReal = 0                
            endif

            //Move the projectile
            call SetUnitX(udg_STA_Unit[Node], x2)
            call SetUnitY(udg_STA_Unit[Node], y2)
            call SetUnitFlyHeight(udg_STA_Unit[Node], GetUnitFlyHeight(udg_STA_Unit[Node]) + udg_STA_ZSpeed[Node] + TempReal, 0.)
            set udg_STA_DistanceTravelled[Node] = udg_STA_DistanceTravelled[Node] + udg_STA_Speed[Node]

            //Checks the kind of projectile that it is
            if (udg_STA_FragmentType[Node] == true) then
            
                //Checks the distance from the target
                set x2 = GetUnitX(udg_STA_Target[Node])
                set y2 = GetUnitY(udg_STA_Target[Node])
                set TempReal = SquareRoot(Pow(x - x2, 2) + Pow(y - y2, 2))

                //Checks for a collision
                if (TempReal > STA_CollisionSize()) then
                    //No collision, recalculate movement
                    set Angle = Atan2(y2 - y, x2 - x)
                    call SetUnitFacing(udg_STA_Unit[Node], bj_RADTODEG * Angle)

                    //Calculate Z heights
                    set z = STA_GetZ(x,y) + GetUnitFlyHeight(udg_STA_Unit[Node])
                    set z2 = STA_GetZ(x2, y2) + GetUnitFlyHeight(udg_STA_Target[Node]) + STA_SoulFragmentHeightEndOffset()
                    
                    //Calculate Speed
                    if (STA_SoulFragmentMovementType() == true) then
                        set udg_STA_Speed[Node] = (TempReal + udg_STA_DistanceTravelled[Node] / udg_STA_SoulProjectileHitTime[udg_STA_CasterNode[Node]]) * STA_TimerRate()
                    endif
                    
                    //Calculate change is Z speed needed
                    set udg_STA_ZSpeed[Node] = (z2 - z) / (TempReal / udg_STA_Speed[Node])
                else
                    //Collision occured, enable aura effect
                    set udg_STA_Disabled[udg_STA_TargetID[Node]] = false
                    call STA_SoulProjectileDamage(x,y,Node)
                    set udg_STA_StageID[Node] = 4
                    call DestroyEffect(udg_STA_CurrentEffect[Node])
                    
                    //Check if the death damage effect is in use
                    if (STA_UseInitialDamageEffect()) then
                        call DestroyEffect(AddSpecialEffectTarget(STA_InitialDamageEffect(), udg_STA_Unit[Node], STA_InitialDamageAttachmentPoint()))
                    endif

                endif
            //If not homing, check if it's reached it's destination
            elseif (udg_STA_DistanceTravelled[Node] >= udg_STA_MaxDistance[Node]) then
                //Cause Damage
                call STA_SoulProjectileDamage(x,y,Node)
                set udg_STA_StageID[Node] = 4
                call DestroyEffect(udg_STA_CurrentEffect[Node])
  
                //Check if the death damage effect is in use
                if (STA_UseDeathDamageEffect()) then
                    call DestroyEffect(AddSpecialEffectTarget(STA_DeathDamageEffect(), udg_STA_Unit[Node], STA_DeathDamageAttachmentPoint()))
                endif 

            endif
               
        //StageID = 2, Affected units
        elseif (udg_STA_StageID[Node] == 2) and (not udg_STA_Disabled[Node]) then
            //Find the units current stats
            set TempReal = GetWidgetLife(udg_STA_Unit[Node])
            set TempReal2 = GetUnitState(udg_STA_Unit[Node], UNIT_STATE_MANA)
            //Increase the effect delay timer
            set udg_STA_EffectDelayTimer[Node] = udg_STA_EffectDelayTimer[Node] + STA_TimerRate()

            //Check if either of the values have been reduced since the last iteration
            if (TempReal < udg_STA_CurrentHealth[Node]) or (TempReal2 < udg_STA_CurrentMana[Node]) then
            
                //Check if the effect is able to be used
                if (udg_STA_EffectDelayTimer[Node] >= STA_EffectReductionDelay()) then
                    set udg_STA_EffectDelayTimer[Node] = 0.
                    call DestroyEffect(AddSpecialEffectTarget(STA_BonusDamageEffect(), udg_STA_Unit[Node], STA_BonusDamageAttachmentPoint()))
                endif
                
                //Check if a health reduction has occured
                if (TempReal < udg_STA_CurrentHealth[Node]) then
                    //Apply bonus damage
                    set TempReal = (udg_STA_CurrentHealth[Node] - TempReal) * udg_STA_BonusHealthDamagePercent[udg_STA_CasterNode[Node]]
                    call UnitDamageTarget(udg_STA_Caster[Node], udg_STA_Unit[Node], TempReal, false, false, STA_AttackType(), STA_DamageType(), STA_WeaponType())
                    set udg_STA_CurrentHealth[Node] = GetWidgetLife(udg_STA_Unit[Node])
                endif

                //Check if a mana reduction has occured
                if (TempReal2 < udg_STA_CurrentMana[Node]) then
                    //Apply bonus damage
                    set TempReal2 = (udg_STA_CurrentMana[Node] - TempReal2) * udg_STA_BonusManaDamagePercent[udg_STA_CasterNode[Node]]
                    call SetUnitState(udg_STA_Unit[Node], UNIT_STATE_MANA, TempReal2)
                endif
                
            endif
            
            //Set up positions
            set x = GetUnitX(udg_STA_Unit[Node])
            set y = GetUnitY(udg_STA_Unit[Node])
            set x2 = GetUnitX(udg_STA_Caster[Node])
            set y2 = GetUnitY(udg_STA_Caster[Node])
            set TempReal = SquareRoot(Pow(x - x2, 2) + Pow(y - y2, 2))
            
            //Check if the unit is still close enough to be affected by the aura
            if (TempReal > udg_STA_AOE[udg_STA_CasterNode[Node]]) then
                //Outside range, deallocate unit
                call DestroyEffect(udg_STA_CurrentEffect[Node])
                call UnitRemoveAbility(udg_STA_Unit[Node], STA_BuffAbilityID())
                call GroupRemoveUnit(udg_STA_AffectedUnits,udg_STA_Unit[Node])
                call STA_Recycle(Node, GetExpiredTimer())
                set TempInt = TempInt - 1
            
            else
            
                //Check if the unit is still alive
                if (udg_STA_CurrentHealth[Node] <= 0.405) then
                
                    //Remove units related to this aura and end the effect
                    set TempInt2 = 0
                    set TempNode = 0

                    loop
                        //Moves to the next node
                        set TempInt2 = TempInt2 + 1
                        exitwhen TempInt2 > udg_STA_AbilityCounter
                        set TempNode = udg_STA_NextNode[TempNode]
                        
                        //Finds projectiles that are homing in on this unit
                        if (udg_STA_Target[TempNode] == udg_STA_Unit[Node]) and (udg_STA_StageID[TempNode] == 3) then
                            //Destroy them (without damage) and recycle
                            call DestroyEffect(udg_STA_CurrentEffect[TempNode])
                            call DestroyEffect(AddSpecialEffectTarget(STA_DeathDamageEffect(), udg_STA_Unit[TempNode], STA_DeathDamageAttachmentPoint()))
                            set udg_STA_StageID[TempNode] = 4
                        endif

                    endloop

                    //Find units nearby which can be targets
                    call GroupEnumUnitsInRange(udg_STA_TempGroup, x, y, udg_STA_SearchAOE[udg_STA_CasterNode[Node]], null) 
                    set pl = GetOwningPlayer(udg_STA_Caster[Node])
                    
                    loop
                        //Scanning through
                        set u = FirstOfGroup(udg_STA_TempGroup)
                        exitwhen u == null
                               
                        //Select all the units to create projectiles to attack
                        if (STA_TargetFilter(u, pl)) and (IsUnitInGroup(u, udg_STA_AffectedUnits)) then
                            //Set up data for the Soul Fragment Projectile
                            set x2 = GetUnitX(u)
                            set y2 = GetUnitY(u)
                            set z = STA_GetZ(x,y) + GetUnitFlyHeight(udg_STA_Unit[Node]) + STA_SoulFragmentHeightStartOffset()
                            set z2 = STA_GetZ(x2, y2) + GetUnitFlyHeight(u) + STA_SoulFragmentHeightEndOffset()
                            set TempReal = SquareRoot(Pow(x - x2, 2) + Pow(y - y2, 2))
                            
                            //Calculate Speed
                            set TempReal2 = STA_GetSpeed(udg_STA_CasterNode[Node], TempReal)
                            
                            //Calculate Z Speed and angle
                            set TempReal3 = (z2 - z) / (TempReal / TempReal2)
                            set Angle = bj_RADTODEG * Atan2(y2 - y, x2 - x)

                            //Create Projectile
                            call STA_CreateProjectile(x, y, z, TempReal3, TempReal2, Angle, TempReal, udg_STA_DeathHealthDamage[udg_STA_CasterNode[Node]], udg_STA_DeathManaDamage[udg_STA_CasterNode[Node]], udg_STA_CasterNode[Node], false, 0)
                        endif

                        //Remove the unit from the unit group
                        call GroupRemoveUnit(udg_STA_TempGroup, u)
                    endloop

                    //Remove effect
                    call DestroyEffect(udg_STA_CurrentEffect[Node])
                    //Recycle instance and enable re-selection as a target
                    call GroupRemoveUnit(udg_STA_AffectedUnits,udg_STA_Unit[Node])
                    call STA_Recycle(Node, GetExpiredTimer())
                    set TempInt = TempInt - 1
                    
                    //Null variables
                    set pl = null
                endif

            endif

        //StageID = 1, Aura source units/heros
        elseif (udg_STA_StageID[Node] == 1) then
        
            //Check if the unit has died
            if (GetWidgetLife(udg_STA_Caster[Node]) <= 0.405) then
                //The Hero is Dead, end the aura
                call STA_AuraEnd(Node)          
            else              
                //Find the position of the unit
                set x = GetUnitX(udg_STA_Caster[Node])
                set y = GetUnitY(udg_STA_Caster[Node])
                //Select potential targets of the aura
                set pl = GetOwningPlayer(udg_STA_Caster[Node])
                call GroupEnumUnitsInRange(udg_STA_TempGroup, x, y, udg_STA_AOE[Node], null) 
                
                loop
                    //Scanning through
                    set u = FirstOfGroup(udg_STA_TempGroup)
                    exitwhen u == null
                           
                    //Select all the units which are to be affected and create projectiles
                    if (STA_TargetFilter(u, pl)) and (not(IsUnitInGroup(u, udg_STA_AffectedUnits))) then
                        
                        //Prevent this unit from being selected again
                        call GroupAddUnit(udg_STA_AffectedUnits,u)
                            
                        //Adds instance to the linked list
                        set udg_STA_AbilityCounter = udg_STA_AbilityCounter + 1
                            
                        //Checking for recycleable Nodes
                        if (udg_STA_RecyclableNodes == 0) then
                            set udg_STA_NodeNumber = udg_STA_NodeNumber + 1
                            set TempNode = udg_STA_NodeNumber
                        else
                            set udg_STA_RecyclableNodes = udg_STA_RecyclableNodes - 1
                            set TempNode = udg_STA_RecycleNodes[udg_STA_RecyclableNodes]
                        endif

                        //Sets up this Node
                        set udg_STA_NextNode[TempNode] = 0
                        set udg_STA_NextNode[udg_STA_LastNode] = TempNode
                        set udg_STA_PrevNode[TempNode] = udg_STA_LastNode
                        set udg_STA_LastNode = TempNode
                        //Sets up data for this unit
                        set udg_STA_Caster[TempNode] = udg_STA_Caster[Node]
                        set udg_STA_CasterNode[TempNode] = Node
                        set udg_STA_Unit[TempNode] = u
                        set udg_STA_CurrentEffect[TempNode] = AddSpecialEffectTarget(STA_SoulFragmentEffect(), u, STA_SoulFragmentAttachmentPoint())
                        set udg_STA_Disabled[TempNode] = true
                        set udg_STA_StageID[TempNode] = 2
                        set udg_STA_CasterNode[TempNode] = Node
                        set udg_STA_CurrentHealth[TempNode] = GetWidgetLife(u)
                        set udg_STA_CurrentMana[TempNode] = GetUnitState(u, UNIT_STATE_MANA)
    
                        //Add buff ability
                        call UnitAddAbility(u, STA_BuffAbilityID())
                        call SetUnitAbilityLevel(u, STA_BuffAbilityID(), R2I(udg_STA_Level[Node]))
                        
                        //Set up data for the Soul Fragment Projectile
                        set x2 = GetUnitX(u)
                        set y2 = GetUnitY(u)
                        set z = STA_GetZ(x,y) + GetUnitFlyHeight(udg_STA_Caster[Node]) + STA_SoulFragmentHeightStartOffset()
                        set z2 = STA_GetZ(x2, y2) + GetUnitFlyHeight(u) + STA_SoulFragmentHeightEndOffset()
                        set TempReal = SquareRoot(Pow(x - x2, 2) + Pow(y - y2, 2))
                            
                        //Calculate Speed
                        set TempReal2 = STA_GetSpeed(Node, TempReal)
                            
                        //Calculate the needed z change
                        set TempReal = (z2 - z) / (TempReal / TempReal2)
                        //Find the facing angle needed
                        set Angle = bj_RADTODEG * Atan2(y2 - y, x2 - x)

                        //Create Projectile
                        call STA_CreateProjectile(x, y, z, TempReal, TempReal2, Angle, 0, udg_STA_InitialEffectHealthDamage[Node], udg_STA_InitialEffectManaDamage[Node], Node, true, TempNode)
                        
                    endif
                    //Remove the unit from the unit group
                    call GroupRemoveUnit(udg_STA_TempGroup, u)
                           
                endloop
                
                //Find the level of the aura ability
                set TempReal = I2R(GetUnitAbilityLevel(udg_STA_Caster[Node], STA_AbilityID()))
                
                //Check if the level has changed
                if (TempReal != udg_STA_Level[Node]) then

                    if (TempReal == 0) then
                        //The unit has forgotten the ability, end it's instance
                        call DestroyEffect(udg_STA_CurrentEffect[Node])
                        call STA_AuraEnd(Node)
                        //Recycle the index
                        call STA_Recycle(Node, GetExpiredTimer())
                        set TempInt = TempInt - 1
                    else
                        //Update the aura
                        set udg_STA_Level[Node] = TempReal
                        call STA_UpdateAura(Node)
                    endif

                endif

                //Null variables
                set pl = null
            endif
          
        //StageID = 4, Projectiles to clear up (so death animations can play)  
        elseif (udg_STA_StageID[Node] == 4) and (udg_STA_CurrentDeathTimer[Node] >= STA_DummyRemovalDelay()) then
            set udg_STA_CurrentDeathTimer[Node] = 0.00
            
            //Removes the projectile
            call RemoveUnit(udg_STA_Unit[Node])
            //Recycles the instance
            call STA_Recycle(Node, GetExpiredTimer())
            set TempInt = TempInt - 1
        
        else
            //Increases the death delay timer
            set udg_STA_CurrentDeathTimer[Node] = udg_STA_CurrentDeathTimer[Node] + STA_TimerRate()
        endif
        
    endloop
    
endfunction

////////////////////////////////////////////////////////////////////
//  Caster assignment function, when a new unit learns an ability //
//  or if the unit is found to have the ability through the       //
//  STA_EnableUnits function, this function is then called and    //
//  the unit is passed to potentially add it to the system        //
//  this  then checks if the unit is registered as a caster in    //
//  the linked list, if it is, then it doesn't need to be added   //
//  however, if it doesn't exist as a caster, then the unit will  //
//  be assigned to a node and added to the spell                  //
////////////////////////////////////////////////////////////////////
function STA_NewAura takes unit u returns nothing
    //Set up locals
    local integer TempInt = 0
    local integer Node = 0
    local boolean scan = false

    //Scans to check if the unit is already part of the system
    loop
        //Moves to the next node
        set TempInt = TempInt + 1
        exitwhen TempInt > udg_STA_AbilityCounter
        set Node = udg_STA_NextNode[Node]
        
        //If the unit exists as a caster in the linked list, don't add it
        if (u == udg_STA_Caster[Node]) then
            set scan = true
        endif

    endloop

    //If the unit wasn't found as a caster, add it as one
    if not(scan) then
        set udg_STA_AbilityCounter = udg_STA_AbilityCounter + 1
            
        //Checking for recycleable Nodes
        if (udg_STA_RecyclableNodes == 0) then
            set udg_STA_NodeNumber = udg_STA_NodeNumber + 1
            set Node = udg_STA_NodeNumber
        else
            set udg_STA_RecyclableNodes = udg_STA_RecyclableNodes - 1
            set Node = udg_STA_RecycleNodes[udg_STA_RecyclableNodes]
        endif

        //Sets up this Node
        set udg_STA_NextNode[Node] = 0
        set udg_STA_NextNode[udg_STA_LastNode] = Node
        set udg_STA_PrevNode[Node] = udg_STA_LastNode
        set udg_STA_LastNode = Node
            
        //Set up the data needed for the Aura
        set udg_STA_Level[Node] = I2R(GetUnitAbilityLevel(u, STA_AbilityID()))
        set udg_STA_StageID[Node] = 1
        set udg_STA_Caster[Node] = u
        set udg_STA_CasterNode[Node] = Node
        set udg_STA_CurrentEffect[Node] = AddSpecialEffectTarget(STA_AuraEffect(), u, STA_AuraAttachmentPoint())

        call STA_UpdateAura(Node)
            
        //Applies timer if this is the only instance of the aura
        if (udg_STA_AbilityCounter == 1) then
            call TimerStart(CreateTimer(), STA_TimerRate(), true, function STA_Loop)
        endif
        
    endif

endfunction

////////////////////////////////////////////////////////////////////
//  This function runs whenever a unit learns an ability, it      //
//  checks if the learnt ability is the one used for the aura,    //
//  if it turns out that it is, then it passed the unit to the    //
//  STA_NewAura function to potentially add it to the system      //
////////////////////////////////////////////////////////////////////
function STA_LearnAbility takes nothing returns boolean
    //Create Locals
    local unit u
    
    //Checks if the learnt ability by the triggering unit is the aura ability
    if (GetLearnedSkill() == STA_AbilityID()) then
        //Attempts to add the unit
        set u = GetTriggerUnit()
        call STA_NewAura(u)
        //Nulls variables
        set u = null
    endif
    
    //return a false value as there is no point returning anything else
    return false

endfunction

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

        //Checks that the selected unit has the aura as an ability
        if (GetUnitAbilityLevel(u, STA_AbilityID()) > 0) then
            //Attempts to add the unit
            call STA_NewAura(u)
        endif
  
        call GroupRemoveUnit(udg_STA_TempGroup, u)
    endloop
    
    //Checks if this function will run constantly, if not then destroy the trigger
    if (not(STA_CheckTimerPeriodic())) then
        call DestroyTrigger(GetTriggeringTrigger())
    endif

    //return a false value as there is no point returning anything else
    return false

endfunction
////////////////////////////////////////////////////////////////////
//  Initialisation trigger, applies the conditions to triggers    //
//  and sets up the global location used to get location Z's      //
////////////////////////////////////////////////////////////////////
function InitTrig_Soul_Tear_Aura takes nothing returns nothing
    //Set up locals
    local trigger STA = CreateTrigger()
    local integer index = 0

    //Set up hero learning trigger
    loop
        //Applies the even to each player in turn
        call TriggerRegisterPlayerUnitEvent(STA, Player(index), EVENT_PLAYER_HERO_SKILL, null)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop

    //Applies the function to add new units to the linked list when they learn abilities
    call TriggerAddCondition(STA, Condition(function STA_LearnAbility))
    
    //Set up initial hero enabling trigger
    set STA = CreateTrigger()
    //Sets up the event listener, if the function is periodic, then it will run constantly instead of just at the start
    call TriggerRegisterTimerEvent(STA, STA_CheckTimerRate(), STA_CheckTimerPeriodic())
    call TriggerAddCondition(STA, Condition(function STA_EnableUnits))

    //Set up the location used to find Z heights
    set udg_STA_ZLoc = Location(0,0)

    //Nulls trigger variable
    set STA = null

endfunction
////////////////////////////////////////////////////////////////////
// End of the spell                                               //
////////////////////////////////////////////////////////////////////

Aura Information:

- Pure JASS: Over 1400 lines of code (including commenting/readme/etc.)
- Runs on standard world editor without compile errors when saving
- ~60 configurable aspects giving high level user control which reach every aspect of the aura, including removing parts of the spell
- Extensive guide on how to configure the aura to your liking
- Enough Effects to last you a lifetime
- Damage Bonus applies to mana as well as health damage
- Damage Bonus applies to all sources of damage, including the damage dealt by a nearby unit dying
- Configuration enables users to add mana damage to any of the stages of the aura
- Can work on Flying and Ground units as both casters and targets without graphical errors/inconsistencies
- Smooth across different terrain heights including cliffs
- Fully MUI, Recycles correctly
- Fully commented code
- Unique functions, including a drawback effect if your unit dies quickly
- Because the Buff ability is based off the Tornado slow ability, applying object editor values to it, can add the effect of changing the movement speed of affected units as well, however this is not done in the test map to prevent the ability from feeling too "crowded" with effects
[rainbow] - The ability can be stacked onto any other ability without changing the aura's effect

- Taunt
- Divine Shield
- True Sight
- War Stomp
- Roar
- Critical Strike
- Another Aura!
- Another custom ability!

- Somebody Else's contest entry!

[/rainbow]
Aura interaction:
- When two units which generate the aura come into contact, the one which started its effect first on the units takes precedence
- Chain effects can be carried across by units affected by another instance of the aura - this is the aura's form of "stacking", making chains able to stretch across the AOE of multiple auras rather than limited to just one, so long as they are in "contact" with eachother
Helpful files:

- Variable Creator: Copy and paste into your map, you now have all the variables needed for the spell to run
- Effect Sets: Temporary storage space for different effects, so that they can be easily accessed/swapped out at will when looking for good combinations
- Manual Addition: Explains how to manually add new Auras to the system if you don't want to rely on the inbuilt systems to do it, particularly for use when creating units with the aura later via triggers - while they can be handled by the system, it's more efficient to utilise the manual addition method.


  • Variable Creator
    • Events
    • Conditions
    • Actions
      • Set STA_AOE[0] = 0.00
      • Set STA_AbilityCounter = 0
      • Set STA_AffectedUnits = STA_TempGroup
      • Set STA_BonusHealthDamagePercent[0] = 0.00
      • Set STA_BonusManaDamagePercent[0] = 0.00
      • Set STA_Caster[0] = STA_Target[0]
      • Set STA_CasterNode[0] = STA_LastNode
      • Set STA_CurrentDeathTimer[0] = 0.00
      • Set STA_CurrentEffect[0] = STA_CurrentEffect[0]
      • Set STA_CurrentHealth[0] = 0.00
      • Set STA_CurrentMana[0] = 0.00
      • Set STA_DeathHealthDamage[0] = 0.00
      • Set STA_DeathManaDamage[0] = 0.00
      • Set STA_Disabled[0] = False
      • Set STA_DistanceTravelled[0] = 0.00
      • Set STA_EffectDelayTimer[0] = 0.00
      • Set STA_FragmentType[0] = False
      • Set STA_HealthDamage[0] = 0.00
      • Set STA_HeroHealthHeal[0] = 0.00
      • Set STA_HeroManaHeal[0] = 0.00
      • Set STA_ImpactAOE[0] = 0.00
      • Set STA_InitialEffectHealthDamage[0] = 0.00
      • Set STA_InitialEffectManaDamage[0] = 0.00
      • Set STA_Level[0] = 0.00
      • Set STA_ManaDamage[0] = 0.00
      • Set STA_MaxDistance[0] = 0.00
      • Set STA_NextNode[0] = 0
      • Set STA_NodeNumber = 0
      • Set STA_PrevNode[0] = 0
      • Set STA_RecyclableNodes = 0
      • Set STA_RecycleNodes[0] = 0
      • Set STA_SearchAOE[0] = 0.00
      • Set STA_SoulFragmentScale[0] = 0.00
      • Set STA_SoulProjectileHitTime[0] = 0.00
      • Set STA_SoulProjectileSpeed[0] = 0.00
      • Set STA_Speed[0] = 0.00
      • Set STA_StageID[0] = 0
      • Set STA_Target[0] = STA_Unit[0]
      • Set STA_TargetID[0] = 0
      • Set STA_ZLoc = STA_ZLoc
      • Set STA_ZSpeed[0] = 0.00



JASS:
Default Set:
Aura Effect: "Abilities\\Spells\\Undead\\RegenerationAura\\ObsidianRegenAura.mdl"
Soul Fragment Effect: "Abilities\\Spells\\Undead\\Curse\\CurseTarget.mdl"
Soul Fragment Projectile Effect: "Abilities\\Weapons\\GreenDragonMissile\\GreenDragonMissile.mdl"
Initial Damage Effect: "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
Death Damage Effect: "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
Bonus Damage Effect: "Abilities\\Spells\\Items\\AIil\\AIilTarget.mdl"
Heal Effect: "Abilities\\Spells\\Human\\DispelMagic\\DispelMagicTarget.mdl"

Fire Set:
Aura Effect: "Abilities\\Spells\\Items\\VampiricPotion\\VampPotionCaster.mdl"
Soul Fragment Effect: "Abilities\\Spells\\Other\\SoulBurn\\SoulBurnbuff.mdl"
Soul Fragment Projectile Effect: "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl"
Initial Damage Effect: "Abilities\\Spells\\Human\\Feedback\\SpellBreakerAttack.mdl"
Death Damage Effect: "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl"
Bonus Damage Effect: "Abilities\\Spells\Human\\Feedback\\SpellBreakerAttack.mdl"
Heal Effect: "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl"

//Blank set for users to temporarily store strings they wish for their sets
Store Set:
Aura Effect:
Soul Fragment Effect:
Soul Fragment Projectile Effect:
Initial Damage Effect:
Death Damage Effect:
Bonus Damage Effect:
Heal Effect:



JASS:
// This Line can be used to manually enter new units into the system
// instead of relying on the inbuilt system
// "unit" should reference whatever unit you want to add, or enter the 
// variable name of a variable set to your desired unit
call STA_NewAura(unit)

// Note: The unit you add through this way should already have the ability before doing this
// This means if the unit is a Hero, that it has already learnt at least level 1

// doing this requires this to be added to the map header if you're using the Vanilla WE:
function EnableScriptUsage takes nothing returns nothing
endfunction
Images

Gif

Screenshot

Tooltip

Alternate Theme

Heal on Death

Uneven Terrain Demo

136650d1404414053-zephyr-contest-11-my-aura-your-aura-soul-tear-aura.gif
136642d1404408267-zephyr-contest-11-my-aura-your-aura-soul-tear-aura-chain-kill.png
136660d1404418539-zephyr-contest-11-my-aura-your-aura-soul-tear-aura-tooltip.png
136711d1404507375-zephyr-contest-11-my-aura-your-aura-soul-tear-aura-fire-theme.png
137492d1406219515-zephyr-contest-11-my-aura-your-aura-soul-tear-aura-heal-death.png
137400d1406036290-zephyr-contest-11-my-aura-your-aura-smooth-across-multiple-terrain-heights.png
[tr]
 

Attachments

  • Soul Tear Aura Chain Kill.png
    Soul Tear Aura Chain Kill.png
    431.4 KB · Views: 2,626
  • Soul Tear Aura.gif
    Soul Tear Aura.gif
    5.3 MB · Views: 2,888
  • Soul Tear Aura Tooltip.png
    Soul Tear Aura Tooltip.png
    124.6 KB · Views: 2,576
  • Soul Tear Aura Fire Theme.png
    Soul Tear Aura Fire Theme.png
    363.3 KB · Views: 2,597
  • Smooth across multiple terrain heights.png
    Smooth across multiple terrain heights.png
    495.9 KB · Views: 2,529
  • Soul Tear Aura Heal on Death.png
    Soul Tear Aura Heal on Death.png
    410.8 KB · Views: 2,540
  • Soul Tear Aura V1.00.w3x
    105 KB · Views: 77
Last edited:

Kyrbi0

Arena Moderator
Level 45
Joined
Jul 29, 2008
Messages
9,495
^Holy cow... Well, I've lost. xD

Do neither! Actually, you can start by telling us what malediction or benediction auras do.
I was gonna do this big fancy colored etymology breakdown, but lacking time...


ben/mal
ediction

'good/bad'
statement ("edict")'word/language/sound/say/etc'indicating action/condition'

Basically, a "Benediction" (commonly heard as the closing prayer at a church service) is a blessing or "good statement/saying". "Malediction" is simply the opposite; a "bad statement/saying", often associated with a malevolent sorceror or whatever (think "Maledict" in DotA's Witch Doctor).

Also reference "Verdict" (the "e-dict" is in there)
 
^Holy cow... Well, I've lost. xD


I was gonna do this big fancy colored etymology breakdown, but lacking time...


ben/mal
ediction

'good/bad'
statement ("edict")'word/language/sound/say/etc'indicating action/condition'

Basically, a "Benediction" (commonly heard as the closing prayer at a church service) is a blessing or "good statement/saying". "Malediction" is simply the opposite; a "bad statement/saying", often associated with a malevolent sorceror or whatever (think "Maledict" in DotA's Witch Doctor).

Also reference "Verdict" (the "e-dict" is in there)

I don't know about your source, but since I had an exam lately on Human Language, morphology-wise, "e" would be a morpheme, without any meaning of its own. Hence it shouldn't be separated from ben-/mal- prefixes.
 
Level 25
Joined
Jun 5, 2008
Messages
2,572
Well Tank-Commander makes it flashy again, so much for no eyecandy wins this time xd

On a more serious note, the aura is overpowered.
You should:
a) Reduce it's AoE
b) Reduce damage to nearby enemies
c) Reduce damage amplification (seeing as MAGIC damage rips units with heavy armor to shreds)

Maybe nerfing all 3 is too much, but c) is a must.
But it's up to you.
 
Certainly, the key thing I've been playing with is getting it balanced, in the end it'll probably a be a lot weaker than it's currently set up to be, really the current stats were to just get a showcasing look to it, particularly for the gif

current changes I'm doing:
Main AOE Base 400 -> 275
Main AOE Per Level 100 -> 75
Death Health Damage Base 50 -> 10
Death Health Damage Per Level 25 -> 20
Bonus Health Damage Percent Base 10% -> 5%
Bonus Health Damage Percent Per Level 5% -> 2.5%

Think that should just about remove the insane chaining likelyhood and make it a bit more of a balanced aura

Edit: balance changes made, think I've sufficiently hindered the power of the aura to make it more realistic (to see it's actual effectiveness, dl and test ingame)
 

Kyrbi0

Arena Moderator
Level 45
Joined
Jul 29, 2008
Messages
9,495
I don't know about your source, but since I had an exam lately on Human Language, morphology-wise, "e" would be a morpheme, without any meaning of its own. Hence it shouldn't be separated from ben-/mal- prefixes.
Caveat #1: I'm no etymology expert; merely an enthusiast.
Caveat #2: I haven't taken any classes (except for one Linguistics class, but that's not quite the same (though related)).

That being said, I apologize for my unclear table/graph/chart thing; like I said, I was intending on creating a better-looking colored diagram for the word, to break it up.

If I had done so, it would've been clear(er) that I intended the "edict" section to stand together" (rather than for the "e" to stand alone), indicating what I said in the cell below it ("statement", esp. an "official" one, like a "decree").

Lo siento.
 
Caveat #1: I'm no etymology expert; merely an enthusiast.
Caveat #2: I haven't taken any classes (except for one Linguistics class, but that's not quite the same (though related)).

That being said, I apologize for my unclear table/graph/chart thing; like I said, I was intending on creating a better-looking colored diagram for the word, to break it up.

If I had done so, it would've been clear(er) that I intended the "edict" section to stand together" (rather than for the "e" to stand alone), indicating what I said in the cell below it ("statement", esp. an "official" one, like a "decree").

Lo siento.

You did well actually, don't apologize for that. I have had a lot of ideas in the past, solely due to breaking words down to a literal or metaphorical meaning. :)

That was an off-topic note, nothing to be taken seriously!
 
Hi!
Can i enter this contest using WurstScript?

Wasn't there a big debate about this? to my knowledge it ended in favour of no wurst (The debate about it just sort of disappeared after it being stated not to be included one last time)
Sources:
http://www.hiveworkshop.com/forums/2495424-post56.html
http://www.hiveworkshop.com/forums/2493634-post37.html
http://www.hiveworkshop.com/forums/2493659-post39.html

Doesn't appear to be any "official" verdict on it though
 
My Aura's Tooltip

Aura
Frozen Ground

Active: Empowers the aura, freezing all affected enemy units for 5 seconds and slowing them by 50% for 5 more seconds after thawing.

Passive (State 1): All enemy units that enter the area of effect for the aura are frozen for 1 second.

Passive (State 2): All enemy units that leave the area of effect for the aura are frozen for 1 second.

Right-click to toggle the passive effect.
Configurables
  • Length of passive freezing.
  • Length of active freezing.
  • Radius of area of effect.
  • And of course; all the object data of the spell (cooldown, mana cost, etc.)
The spell object is based off of "Restore" which is the unused ability of the Undead's Obsidian Statue, which has the life and mana variants. This spell's base is supposed to be for both. It is an autocast ability that has no target when clicked, allowing for a state based activated ability. The activated aspect of this is taken from Diablo III's Crusaders' auras and their ability to empower them with a cooldown for additional effect. Only passive state is shown at a time, as the tooltip adjusts itself to show which passive effect is displayed based on if the spell's autocast aspect is turned on or off. I haven't finished it yet so I don't know what the autocast AI will do for the spell, since it is ment to target allies and the spell can't target allies it might not function with AI (which is my goal) versus casting it at the wrong moment.A simple spell with a neat twist on passive in my opinion. Hopefully my supporting aura code will allow for a higher coding score.Nice spell Tank-Commander.Edit:
Systems Used
  • Spell Handler - Zeatherann
  • Order Handler - Zeatherann
  • Aura Handler - Zeatherann
~ Note: While I've written some of these systems before, I rewrote them for this map as well ~
Edit 2
JASS:
//====================================================================================================
//
//   Order Handler System
//
//   Author: Zeatherann
//   Description: Catches anytime a unit is issued any order and handles triggers listening for those
//                orders in O(log n) time.
// 
//====================================================================================================
//****************************************************************************************************
//*
//*  Global Variables
//*
//****************************************************************************************************
globals
    // Non-system specific globals.
    hashtable Hash=InitHashtable()
    // System globals.
    constant trigger Event_Ordered=CreateTrigger()
    constant integer EVENT_UNIT_ORDERED=2
endglobals
//****************************************************************************************************
//*
//*  Order Handler System
//*
//****************************************************************************************************
// RegisterOrder
//    takes integer  Order_Id - The orderid to listen for.
//          boolexpr Function - The code to run when a unit is issued the order.
//    returns nothing
//
//    Attaches the given order to a trigger to be called in O(log n) time.
function RegisterOrder takes integer Order_Id,boolexpr Function returns nothing
    local trigger Order=CreateTrigger()
    call TriggerAddCondition(Order,Function)
    call SaveTriggerHandle(Hash,EVENT_UNIT_ORDERED,Order_Id,Order)
    set Order=null
endfunction
//====================================================================================================
//   Registered Orders.
//====================================================================================================
//====================================================================================================
//   Order Handler Functions - Called and handled internally.
//====================================================================================================
function RegisterOrders takes nothing returns nothing
    local timer Caller=GetExpiredTimer()
    call DestroyTimer(Caller)
    set Caller=null
    // ***** Register all orders ***** //
endfunction

function Event_OrderedFunction takes nothing returns nothing
    call TriggerEvaluate(LoadTriggerHandle(Hash,EVENT_UNIT_ORDERED,GetIssuedOrderId()))
endfunction
// OrderHandler_Initialization
//    takes nothing
//    returns nothing
//
//    Call this once on map initialization.
function OrderHandler_Initialization takes nothing returns nothing
    call TimerStart(CreateTimer(),0,false,function RegisterOrders)
    call TriggerAddCondition(Event_Ordered,Filter(function Event_OrderedFunction))
    call TriggerRegisterAnyUnitEventBJ(Event_Ordered,EVENT_PLAYER_UNIT_ISSUED_ORDER)
    call TriggerRegisterAnyUnitEventBJ(Event_Ordered,EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
    call TriggerRegisterAnyUnitEventBJ(Event_Ordered,EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
endfunction
JASS:
//====================================================================================================
//
//   Spell Handler System
//
//   Author: Zeatherann
//   Description: Catches any spell cast event and maps it to a hashtable of saved functions for given
//                spells. Works in O(log n) time. Currently supports EVENT_PLAYER_UNIT_SPELL_CAST and
//                EVENT_PLAYER_UNIT_SPELL_EFFECT events, but can be easily modified to add support for
//                the other events.
// 
//====================================================================================================
//****************************************************************************************************
//*
//*  Global Variables
//*
//****************************************************************************************************
globals
    // Non-system specific globals.
    hashtable Hash=InitHashtable()
    // System globals.
    constant trigger Event_SpellCast=CreateTrigger()
    constant trigger Event_SpellEffect=CreateTrigger()
    constant integer EVENT_SPELL_CAST=0
    constant integer EVENT_SPELL_EFFECT=1
endglobals
//****************************************************************************************************
//*
//*  Spell Handler System
//*
//****************************************************************************************************
// RegisterSpell
//    takes integer  SpellId  - The spell's object id to attach a function to.
//          integer  Event    - The event to listen for.
//          boolexpr Function - The code to run when the spell's event is triggered.
//    returns nothing
//
//    Attaches the given spell to a trigger to be called in O(log n) time.
function RegisterSpell takes integer SpellId,integer Event,boolexpr Function returns nothing
    local trigger Spell=CreateTrigger()
    call TriggerAddCondition(Spell,Function)
    call SaveTriggerHandle(Hash,Event,SpellId,Spell)
    set Spell=null
endfunction
//====================================================================================================
//   Registered Spells.
//====================================================================================================
//====================================================================================================
//   Spell Handler Functions - Called and handled internally.
//====================================================================================================
function RegisterSpells takes nothing returns nothing
    local timer Caller=GetExpiredTimer()
    call DestroyTimer(Caller)
    set Caller=null
    // ***** Register all spells ***** //
endfunction

function Event_SpellCastFunction takes nothing returns nothing
    call TriggerEvaluate(LoadTriggerHandle(Hash,EVENT_SPELL_CAST,GetSpellAbilityId()))
endfunction

function Event_SpellEffectFunction takes nothing returns nothing
    call TriggerEvaluate(LoadTriggerHandle(Hash,EVENT_SPELL_EFFECT,GetSpellAbilityId()))
endfunction
// SpellHandler_Initialization
//    takes nothing
//    returns nothing
//
//    Call this once on map initialization.
function SpellHandler_Initialization takes nothing returns nothing
    call TimerStart(CreateTimer(),0,false,function RegisterSpells)
    call TriggerAddCondition(Event_SpellCast,Filter(function Event_SpellCastFunction))
    call TriggerAddCondition(Event_SpellEffect,Filter(function Event_SpellEffectFunction))
    call TriggerRegisterAnyUnitEventBJ(Event_SpellCast,EVENT_PLAYER_UNIT_SPELL_CAST)
    call TriggerRegisterAnyUnitEventBJ(Event_SpellEffect,EVENT_PLAYER_UNIT_SPELL_EFFECT)
endfunction
 
Last edited:
Level 16
Joined
Oct 17, 2009
Messages
1,580
We got some nice entries here.
As for me, I'm gonna make a freezing aura. It gradually slows down attack speed/movement speed if you're not attacking/moving. Once the slow reaches a certain point, it will freeze and you will not be able to attack or cast/move. When in the AOE, the enemy has the choice to either run(sacrificing damage), attack(take the danger of being rooted), or alternate between moving and attacking(Balance out the slows).
 

Kyrbi0

Arena Moderator
Level 45
Joined
Jul 29, 2008
Messages
9,495
Lotta "freezing auras", guys, lol. :p That being said...

The spell object is based off of "Restore" which is the unused ability of the Undead's Obsidian Statue, which has the life and mana variants. This spell's base is supposed to be for both. It is an autocast ability that has no target when clicked, allowing for a state based activated ability. The activated aspect of this is taken from Diablo III's Crusaders' auras and their ability to empower them with a cooldown for additional effect. Only passive state is shown at a time, as the tooltip adjusts itself to show which passive effect is displayed based on if the spell's autocast aspect is turned on or off. I haven't finished it yet so I don't know what the autocast AI will do for the spell, since it is ment to target allies and the spell can't target allies it might not function with AI (which is my goal) versus casting it at the wrong moment.A simple spell with a neat twist on passive in my opinion. Hopefully my supporting aura code will allow for a higher coding score.
This is downright fascinating; I've heard of abilities that are able to be used like this (toggled-state Active abilities with different effects per state), but never truly contemplated the possibilities! Even greater kudos for finding & utilizing an un(der)-used in-game ability for your base; too many people base off of Channel & call it a day, in my opinion. :p

So I'm curious; does this trick work with any Autocast ability (i.e. Searing/Black/Cold Arrows? Raise Dead? Abolish Magic? Orb of Annihilation?), or is this hidden "Restore" unique (OK, it's a no-target Autocast, but aside from that; could I have used Spirit Touch or Essence of Blight (the actual Obsidian Statue abilities) instead?)?

Neat-o.
 
Level 25
Joined
Jun 5, 2008
Messages
2,572
too many people base off of Channel & call it a day, in my opinion. :p

It's because it's a consensus that all (if possible) custom spells should use Channel because you can change Channels OrderId to avoid conflicts. (And not to mention the options it further allows).

So unless you are doing something different like the shown here (Autocast), all custom spells should use channel, no exceptions.

Also afaik there is a way to detect Autocast activation/deactivation by catching unit orders (Activation/Deactivation will proc a unit order event) so you can do that with probably any autocast. Major difference between autocast spells is when it is cast.

I haven't finished it yet so I don't know what the autocast AI will do for the spell, since it is ment to target allies and the spell can't target allies it might not function with AI (which is my goal) versus casting it at the wrong moment.

It certainly won't proc on enemies. It will most certainly proc when allies nearby lose health and/or mana in the AoE if it can target them.
Edit:

You can try basing it on Frenzy (Neutral Hostile, looks like Bloodlust) and then it will proc when it comes into range of enemies. Or base it on Phase Shift maybe to proc on taking damage.
Problem is then it will proc for users at that time also, i would say that you shouldn't worry about AI using it, it's not a requirement. (A lot of custom spells don't get used by melee AI, you need a custom AI or a scripted AI system for that)
 
Last edited:
Restore is one of the few auto cast abilities that don't have a target, and can be clicked with no valid targets in the AoE. Raise Dead requires a corpse, though you don't explicitly target the corpse. I hope that since my version of the Restore doesn't target allies the AI will not cast it automatically.The hard part here is getting proper aura handling, which isn't specific to any aura ability. My hope is to create a fluid enough of a system to fulfill the coding requirements, and have the spell itself be the creative part. I have a ton of time to do this, so I have no worries.Happy Fourth!
 

Kyrbi0

Arena Moderator
Level 45
Joined
Jul 29, 2008
Messages
9,495
It's because it's a consensus that all (if possible) custom spells should use Channel because you can change Channels OrderId to avoid conflicts. (And not to mention the options it further allows).

So unless you are doing something different like the shown here (Autocast), all custom spells should use channel, no exceptions.
Yeah yeah, I'm aware... Lol, I'm sorry if I sounded serious. I was being somewhat facetious. I know how useful Channel is (though to be honest, the OrderID things never really made sense to me; I've not really had problems with that, I should say). But yeah, it's a standard for a reason. I just sometimes wish people would utilize in-game abilities more & depend on completely coding them less.

Restore is one of the few auto cast abilities that don't have a target, and can be clicked with no valid targets in the AoE. Raise Dead requires a corpse, though you don't explicitly target the corpse. I hope that since my version of the Restore doesn't target allies the AI will not cast it automatically.The hard part here is getting proper aura handling, which isn't specific to any aura ability. My hope is to create a fluid enough of a system to fulfill the coding requirements, and have the spell itself be the creative part. I have a ton of time to do this, so I have no worries.Happy Fourth!
I looked it up; do you mean "Replenish"? Because the only "Restore" is the Acolyte's "building repair" ability. "Replenish" looks just like Essence of Blight/Spirit Touch, but is unused AFAIK.

Anyway, super-cool. I'm gonna have to find a use for that. Somewhere.

~~~

On a spell-related note, did some testing, and YEAH my "malediction" idea is solid gold (i.e. the base ability I tested, it works). Unfortunately my "benediction" idea is a little shaky; apparently reversing the fields on Cleaving Attack does not create a "Heal nearby Allies upon Attack (for a Percentage of Attack Damage)" ability naturally. :< Should've figured. However, there may still be a work-around I have cooked up (though it'll be a bit clunky & perhaps lose me points for configurability (not a word?)). That being the case, even if I get both to work, I'll likely go with the former.

Trolls are better anyhow. :p
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
WIP :)
JASS:
scope StaticWard

    /************************************************************************************
    *                                                                                   *
    *                            'Static Ward' v1.0                                     *
    *                                      *****                                        *
    *                                    by Dalvengyr                                   *
    *                                                                                   *
    *  A. Descriptions                                                                  *
    *      Summons an immobilizing static ward. The ward sends shockbolt to every enemy *
    *  units nearby. They will deal minor damage and slows their victims down. Affected *
    *  unit will obtain another negative effects.                                       *
    *                                                                                   *
    *  B. Requirements                                                                  *
    *       - JNGP                                                                      *
    *       - UnitIndexer                                                               *
    *       - StunEngine                                                                *
    *       - WorldBounds                                                               *
    *                                                                                   *
    ************************************************************************************/
    
    globals
        private constant integer    SPELL_ID        = 'A000'
        private constant integer    DUMMY_ID        = 'h000'
        private constant integer    SLOW_ID         = 'A000'
        private constant real       ACCURACY        = 0.03125
        private constant real       EFFECT_DECAY    = 5.0
        private constant real       MISSILE_SPEED   = 15.0
        private constant real       MISSILE_Z       = 0.0
        private constant real       MISSILE_ARC     = 0.9
        private constant real       ARC_FACTOR      = 0.15
        private constant real       ARC_MAX         = 300.0
        private constant boolean    ENABLE_VISION   = true
        private constant string     MISSILE_SFX     = "war3mapImported\\LightningArrow1.mdx"
        private constant string     WARD_SFX        = "war3mapImported\\ManaWard.mdx"
    endglobals
    
    private function getDamage takes integer level returns real
        return 40.0 + (30.0 * level)
    endfunction
    
    private function getAoE takes integer level returns real
        return 200.0 + (50.0 * level)
    endfunction
    
    private function getWardDuration takes integer level returns real
        return 8.0
    endfunction
    
    private function getEffectDuration takes integer level returns real
        return 3.0
    endfunction
    
    private function getMinorEffectDuration takes integer level returns real
        return 1.25
    endfunction
    
    private function getStunDuration takes integer level returns real
        return 0.35
    endfunction
    
    private function filterTarget takes unit target returns boolean
        return not (IsUnitType(target, UNIT_TYPE_DEAD) or IsUnitType(target, UNIT_TYPE_STRUCTURE) or IsUnitType(target, UNIT_TYPE_MECHANICAL) or IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE))
    endfunction
    
    globals
        private integer array This
        private integer array This2
        private integer Total = -1
        private integer Total2 = -1
        private timer WardTimer = CreateTimer()
        private timer BoltTimer = CreateTimer()
    endglobals
    
    private function getDistance takes real x, real y, real xt, real yt returns real
        return SquareRoot((xt - x) * (xt - x) + (yt - y) * (yt - y))
    endfunction
    
    private function getRadian takes real x, real y, real xt, real yt returns real
        return Atan2(yt - y, xt - x)
    endfunction
    
    private function IsInBound takes real x, real y returns boolean
        return x < WorldBounds.maxX and x > WorldBounds.minX and y < WorldBounds.maxY and y > WorldBounds.minY
    endfunction
    
    private struct ShockBolt
    
        private unit Missile
        private unit Target
        
        private real ArcReal
        private real Dx
        private real Dc
        private real Ax
        private real Angle
        private real X
        private real Y
        
        private boolean TargetState
        
        private integer Level
        
        static method onPeriodic takes nothing returns nothing
            
            local integer i = 0
            local real x
            local real y
            local real h
            local thistype this
            
            loop
                exitwhen i > Total2
                set this = This2[i]
                if .TargetState then
                else
                    set h = ((4. * .Ax) / .Dx) * (.Dx - .Dc) * (.Dc / .Dx)
                    if h > ARC_MAX then
                        set h = ARC_MAX
                    endif
                    set .X = .X + MISSILE_SPEED * Cos(.Angle)
                    set .Y = .Y + MISSILE_SPEED * Sin(.Angle)
                    set x = .X + h * Cos(.Angle + ((90. * .ArcReal) * bj_DEGTORAD))
                    set y = .Y + h * Sin(.Angle + ((90. * .ArcReal) * bj_DEGTORAD))
                    if IsInBound(x, y) then
                        call SetUnitX(.Missile, x)
                        call SetUnitY(.Missile, y)
                    endif
                    set .Dc = .Dc + MISSILE_SPEED
                    if .Dc >= .Dx then
                        set .Dc = 0.
                        set .Dx = getDistance(.X, .Y, GetUnitX(.Target), GetUnitY(.Target)) * ARC_FACTOR
                        set .ArcReal = .ArcReal * -1.
                    endif
                endif
                set i = i + 1
            endloop
            
        endmethod
        
        static method launch takes player p, real x, real y, unit target, integer level returns nothing
        
            local thistype this = allocate()
            
            set Total2 = Total2 + 1
            set This2[Total2] = this
            set .ArcReal = 1.
            set .TargetState = false
            set .Angle = getRadian(x, y, GetUnitX(target), GetUnitY(target))
            set .Missile = CreateUnit(p, DUMMY_ID, x, y, .Angle * bj_RADTODEG)
            set .Target = target
            set .Level = level
            set .Dc = 0.
            set .Dx = getDistance(x, y, GetUnitX(target), GetUnitY(target)) * ARC_FACTOR
            set .X = x
            set .Y = y
            if UnitAddAbility(.Missile, 'Amrf') and UnitRemoveAbility(.Missile, 'Amrf') then
            endif
            call SetUnitFlyHeight(.Missile, MISSILE_Z, 0.)
            if Total2 == 0 then
                call TimerStart(BoltTimer, ACCURACY, true, function ShockBolt.onPeriodic)
            endif
            
        endmethod
        
    endstruct
    
    private struct Ward
    
        private real Dur
        private real X
        private real Y
        
        private unit Ward
        
        private player Owner
        
        private integer Level
        
        private fogmodifier Vision
        
        private effect Sfx
        
        static method onPeriodic takes nothing returns nothing
            
            local integer i = 0
            local group g
            local unit u
            local thistype this
            
            loop
                exitwhen i > Total
                set this = This[i]
                if .Dur > ACCURACY then
                    set .Dur = .Dur - ACCURACY
                    set g = CreateGroup()
                    call GroupEnumUnitsInRange(g, .X, .Y, getAoE(.Level), null)
                    loop
                        set u = FirstOfGroup(g)
                        exitwhen u == null
                        if filterTarget(u) then
                            call ShockBolt.launch(.Owner, .X, .Y, u, .Level)
                        endif
                        call GroupRemoveUnit(g, u)
                    endloop
                else
                    call UnitApplyTimedLife(.Ward, 'BTLF', EFFECT_DECAY)
                    call DestroyEffect(.Sfx)
                    call DestroyFogModifier(.Vision)
                    call destroy()
                    set This[i] = This[Total]
                    set Total = Total - 1
                    if Total < 0 then
                        call PauseTimer(WardTimer)
                    else
                        set i = i - 1
                    endif
                endif
                set i = i + 1
            endloop
            
        endmethod
        
        static method summon takes player p, real x, real y, real a, integer level returns nothing
        
            local thistype this = allocate()
            
            set Total = Total + 1
            set This[Total] = this
            set .Dur = getWardDuration(level)
            set .X = x
            set .Y = y
            set .Level = level
            set .Owner = p
            set .Ward = CreateUnit(p, DUMMY_ID, x, y, a)
            set .Sfx = AddSpecialEffectTarget(WARD_SFX, .Ward, "origin")
            static if ENABLE_VISION then
                set .Vision = CreateFogModifierRadius(p, FOG_OF_WAR_VISIBLE, x, y, getAoE(level), true, true)
                call FogModifierStart(.Vision)
            endif
            if Total == 0 then
                call TimerStart(WardTimer, ACCURACY, true, function Ward.onPeriodic)
            endif
            
        endmethod
        
    endstruct
    
    private struct SummonStaticWard
    
        private static method onCast takes nothing returns boolean
        
            if GetSpellAbilityId() == SPELL_ID then
                call Ward.summon(GetTriggerPlayer(), GetSpellTargetX(), GetSpellTargetY(), 270., GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID))
            endif
            
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            
            local trigger t = CreateTrigger()
            
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function SummonStaticWard.onCast))
            
        endmethod
        
    endstruct
    
endscope

This spell is inspired from Torchlight II's shock effect. It works just like TankCommander's entry.
 
Level 13
Joined
Jun 20, 2014
Messages
479
Hi everyone, sorry it took so long for me to find out how to hide spell icons. Now its done.

The spell is now called "Savior's Aura", taunt is added to the aura itself so we have an active icon and still emit an aura so we may see how far the aura can reach. here is the new tooltip:



Emits an aura that heals nearby allied units whenever the bearer of the aura is attacked. Also allows you to force nearby enemy units to attack you for a duration.

|cffffcc00Level 1|r - Heals nearby units based on 30% of the bearer's |cffffcc00Strength|r.
|cffffcc00Level 2|r - Heals nearby units based on 60% of the bearer's |cffffcc00Strength|r.
|cffffcc00Level 3|r - Heals nearby units based on 90% of the bearer's |cffffcc00Strength|r.
|cffffcc00Level 4|r - Heals nearby units based on 120% of the bearer's |cffffcc00Strength|r.

Area of Effect: 500
|cffffcc00Units that has this ability will not be healed by this aura.|r


EDIT: by the way the code stays the same.



  • SaviorAuraTrigConfig
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- set the ability that will be the basis for the aura --------
      • -------- - --------
      • Set SA_A_PassiveAbility = Savior's Aura (Container)
      • Set SA_A_ActiveAbility = Savior's Aura (Active)
      • -------- - --------
      • -------- set the buff that the ability will emit --------
      • -------- - --------
      • Set SA_BF_Buff = Savior's Aura
      • -------- - --------
      • -------- if set to true, the amount healed will be based on the percentage of strength of the hero --------
      • -------- if set to false, the number will directly heal units --------
      • -------- please note that 20% is 20.00 and not 0.2 --------
      • -------- - --------
      • Set SA_B_UseStat = True
      • -------- - --------
      • Set SA_R_Heal[1] = 30.00
      • Set SA_R_Heal[2] = 60.00
      • Set SA_R_Heal[3] = 90.00
      • Set SA_R_Heal[4] = 120.00
      • -------- - --------
      • -------- special effects configurables --------
      • -------- attachment point --------
      • -------- - --------
      • Set SA_S_Attach = origin
      • -------- - --------
      • -------- special effects attached to unit --------
      • -------- - --------
      • Set SA_S_SFX = Abilities\Spells\Undead\VampiricAura\VampiricAuraTarget.mdl
      • -------- - --------
      • -------- if true, it will heal structures only if they have the buff from the aura --------
      • -------- - --------
      • Set SA_B_HealStructures = False
      • -------- - --------
      • -------- if true, it will heal magic immunes only if they have the buff from the aura --------
      • -------- - --------
      • Set SA_B_HealImmune = False
      • -------- - --------
      • -------- Area of effect of the aura --------
      • -------- - --------
      • Set SA_R_AoE[1] = 500.00
      • Set SA_R_AoE[2] = 500.00
      • Set SA_R_AoE[3] = 500.00
      • Set SA_R_AoE[4] = 500.00
      • -------- - --------
      • -------- list abilities that unlearns all hero skills --------
      • -------- - --------
      • Set SA_I_Total = 1
      • -------- - --------
      • Set SA_A_Unlearn[1] = Tome of Retraining
      • -------- - --------
      • -------- Disable spellbook --------
      • -------- - --------
      • For each (Integer SA_I_TempInt) from 1 to 12, do (Actions)
        • Loop - Actions
          • Player - Disable SA_A_PassiveAbility for (Player(SA_I_TempInt))


  • SaviorAuraEffect
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • (Level of SA_A_ActiveAbility for (Attacked unit)) Greater than 0
      • ((Attacking unit) belongs to an enemy of (Owner of (Attacked unit))) Equal to True
    • Actions
      • Set SA_U_AtkUnit = (Attacked unit)
      • Set SA_PL_Player = (Owner of SA_U_AtkUnit)
      • Set SA_I_Level = (Level of SA_A_ActiveAbility for SA_U_AtkUnit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • SA_B_UseStat Equal to True
        • Then - Actions
          • Set SA_R_HealAmt = ((Real((Strength of SA_U_AtkUnit (Include bonuses)))) x (SA_R_Heal[SA_I_Level] x 0.01))
        • Else - Actions
          • Set SA_R_HealAmt = SA_R_Heal[SA_I_Level]
      • Set SA_P_AtkPos = (Position of (Attacked unit))
      • Set SA_UG_UnitGroup = (Units within SA_R_AoE[SA_I_Level] of SA_P_AtkPos matching ((((Matching unit) is alive) Equal to True) and ((((Matching unit) belongs to an ally of SA_PL_Player) Equal to True) and ((((Matching unit) is A structure) Equal to SA_B_HealStructures) and ((((Match
      • Game - Display to (All players) the text: (String(SA_R_HealAmt))
      • Unit Group - Pick every unit in SA_UG_UnitGroup and do (Actions)
        • Loop - Actions
          • Set SA_U_Picked = (Picked unit)
          • Unit - Set life of SA_U_Picked to ((Life of SA_U_Picked) + SA_R_HealAmt)
          • Special Effect - Create a special effect attached to the SA_S_Attach of SA_U_Picked using SA_S_SFX
          • Special Effect - Destroy (Last created special effect)
      • Unit Group - Remove all units from SA_UG_UnitGroup
      • Custom script: call DestroyGroup(udg_SA_UG_UnitGroup)
      • Custom script: call RemoveLocation(udg_SA_P_AtkPos)



other triggers are for adding and removing the spell when unlearned.
 

Attachments

  • Saviors Aura.png
    Saviors Aura.png
    478.5 KB · Views: 98
  • Savior's Aura testing.png
    Savior's Aura testing.png
    490.4 KB · Views: 85
Last edited:
Level 13
Joined
Jun 20, 2014
Messages
479
Really nice idea SallyAnna, keep it up!

Thank you!

EDIT: i changed my mind its OP.

Here is my final output for now.



Emits an aura that heals nearby allied units whenever the bearer of the aura is attacked. Also allows you to force nearby enemy units to attack you for a duration.

|cffffcc00Level 1|r - Heals nearby units based on 30% of the bearer's |cffffcc00Strength|r.
|cffffcc00Level 2|r - Heals nearby units based on 60% of the bearer's |cffffcc00Strength|r.
|cffffcc00Level 3|r - Heals nearby units based on 90% of the bearer's |cffffcc00Strength|r.
|cffffcc00Level 4|r - Heals nearby units based on 120% of the bearer's |cffffcc00Strength|r.

Area of Effect: 500
|cffffcc00Units that has this ability will not be healed by this aura.|r




  • SaviorAuraTrigConfig
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- set the ability that will be the basis for the aura --------
      • -------- - --------
      • Set SA_A_PassiveAbility = Savior's Aura (Container)
      • Set SA_A_ActiveAbility = Savior's Aura (Active)
      • -------- - --------
      • -------- set the buff that the ability will emit --------
      • -------- - --------
      • Set SA_BF_Buff = Savior's Aura
      • -------- - --------
      • -------- if set to true, the amount healed will be based on the percentage of strength of the hero --------
      • -------- if set to false, the number will directly heal units --------
      • -------- please note that 20% is 20.00 and not 0.2 --------
      • -------- - --------
      • Set SA_B_UseStat = True
      • -------- - --------
      • Set SA_R_Heal[1] = 30.00
      • Set SA_R_Heal[2] = 60.00
      • Set SA_R_Heal[3] = 90.00
      • Set SA_R_Heal[4] = 120.00
      • -------- - --------
      • -------- special effects configurables --------
      • -------- attachment point --------
      • -------- - --------
      • Set SA_S_Attach = origin
      • -------- - --------
      • -------- special effects attached to unit --------
      • -------- - --------
      • Set SA_S_SFX = Abilities\Spells\Undead\VampiricAura\VampiricAuraTarget.mdl
      • -------- - --------
      • -------- if true, it will heal structures only if they have the buff from the aura --------
      • -------- - --------
      • Set SA_B_HealStructures = False
      • -------- - --------
      • -------- if true, it will heal magic immunes only if they have the buff from the aura --------
      • -------- - --------
      • Set SA_B_HealImmune = False
      • -------- - --------
      • -------- Area of effect of the aura --------
      • -------- - --------
      • Set SA_R_AoE[1] = 500.00
      • Set SA_R_AoE[2] = 500.00
      • Set SA_R_AoE[3] = 500.00
      • Set SA_R_AoE[4] = 500.00
      • -------- - --------
      • -------- list abilities that unlearns all hero skills --------
      • -------- - --------
      • Set SA_I_Total = 1
      • -------- - --------
      • Set SA_A_Unlearn[1] = Tome of Retraining
      • -------- - --------
      • -------- Disable spellbook --------
      • -------- - --------
      • For each (Integer SA_I_TempInt) from 1 to 12, do (Actions)
        • Loop - Actions
          • Player - Disable SA_A_PassiveAbility for (Player(SA_I_TempInt))


  • SaviorAuraEffect
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • (Level of SA_A_ActiveAbility for (Attacked unit)) Greater than 0
      • ((Attacking unit) belongs to an enemy of (Owner of (Attacked unit))) Equal to True
    • Actions
      • Set SA_U_AtkUnit = (Attacked unit)
      • Set SA_PL_Player = (Owner of SA_U_AtkUnit)
      • Set SA_I_Level = (Level of SA_A_ActiveAbility for SA_U_AtkUnit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • SA_B_UseStat Equal to True
        • Then - Actions
          • Set SA_R_HealAmt = ((Real((Strength of SA_U_AtkUnit (Include bonuses)))) x (SA_R_Heal[SA_I_Level] x 0.01))
        • Else - Actions
          • Set SA_R_HealAmt = SA_R_Heal[SA_I_Level]
      • Set SA_P_AtkPos = (Position of (Attacked unit))
      • Set SA_UG_UnitGroup = (Units within SA_R_AoE[SA_I_Level] of SA_P_AtkPos matching ((((Matching unit) is alive) Equal to True) and ((((Matching unit) belongs to an ally of SA_PL_Player) Equal to True) and ((((Matching unit) is A structure) Equal to SA_B_HealStructures) and ((((Match
      • Game - Display to (All players) the text: (String(SA_R_HealAmt))
      • Unit Group - Pick every unit in SA_UG_UnitGroup and do (Actions)
        • Loop - Actions
          • Set SA_U_Picked = (Picked unit)
          • Unit - Set life of SA_U_Picked to ((Life of SA_U_Picked) + SA_R_HealAmt)
          • Special Effect - Create a special effect attached to the SA_S_Attach of SA_U_Picked using SA_S_SFX
          • Special Effect - Destroy (Last created special effect)
      • Unit Group - Remove all units from SA_UG_UnitGroup
      • Custom script: call DestroyGroup(udg_SA_UG_UnitGroup)
      • Custom script: call RemoveLocation(udg_SA_P_AtkPos)

 
Last edited:
Level 30
Joined
Nov 29, 2012
Messages
6,637
Thank you!

EDIT: i changed my mind its OP.

Here is my final output for now.



Emits an aura that heals nearby allied units whenever the bearer of the aura is attacked. Also allows you to force nearby enemy units to attack you for a duration.

|cffffcc00Level 1|r - Heals nearby units based on 30% of the bearer's |cffffcc00Strength|r.
|cffffcc00Level 2|r - Heals nearby units based on 60% of the bearer's |cffffcc00Strength|r.
|cffffcc00Level 3|r - Heals nearby units based on 90% of the bearer's |cffffcc00Strength|r.
|cffffcc00Level 4|r - Heals nearby units based on 120% of the bearer's |cffffcc00Strength|r.

Area of Effect: 500
|cffffcc00Units that has this ability will not be healed by this aura.|r




  • SaviorAuraTrigConfig
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- set the ability that will be the basis for the aura --------
      • -------- - --------
      • Set SA_A_PassiveAbility = Savior's Aura (Container)
      • Set SA_A_ActiveAbility = Savior's Aura (Active)
      • -------- - --------
      • -------- set the buff that the ability will emit --------
      • -------- - --------
      • Set SA_BF_Buff = Savior's Aura
      • -------- - --------
      • -------- if set to true, the amount healed will be based on the percentage of strength of the hero --------
      • -------- if set to false, the number will directly heal units --------
      • -------- please note that 20% is 20.00 and not 0.2 --------
      • -------- - --------
      • Set SA_B_UseStat = True
      • -------- - --------
      • Set SA_R_Heal[1] = 30.00
      • Set SA_R_Heal[2] = 60.00
      • Set SA_R_Heal[3] = 90.00
      • Set SA_R_Heal[4] = 120.00
      • -------- - --------
      • -------- special effects configurables --------
      • -------- attachment point --------
      • -------- - --------
      • Set SA_S_Attach = origin
      • -------- - --------
      • -------- special effects attached to unit --------
      • -------- - --------
      • Set SA_S_SFX = Abilities\Spells\Undead\VampiricAura\VampiricAuraTarget.mdl
      • -------- - --------
      • -------- if true, it will heal structures only if they have the buff from the aura --------
      • -------- - --------
      • Set SA_B_HealStructures = False
      • -------- - --------
      • -------- if true, it will heal magic immunes only if they have the buff from the aura --------
      • -------- - --------
      • Set SA_B_HealImmune = False
      • -------- - --------
      • -------- Area of effect of the aura --------
      • -------- - --------
      • Set SA_R_AoE[1] = 500.00
      • Set SA_R_AoE[2] = 500.00
      • Set SA_R_AoE[3] = 500.00
      • Set SA_R_AoE[4] = 500.00
      • -------- - --------
      • -------- list abilities that unlearns all hero skills --------
      • -------- - --------
      • Set SA_I_Total = 1
      • -------- - --------
      • Set SA_A_Unlearn[1] = Tome of Retraining
      • -------- - --------
      • -------- Disable spellbook --------
      • -------- - --------
      • For each (Integer SA_I_TempInt) from 1 to 12, do (Actions)
        • Loop - Actions
          • Player - Disable SA_A_PassiveAbility for (Player(SA_I_TempInt))


  • SaviorAuraEffect
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • (Level of SA_A_ActiveAbility for (Attacked unit)) Greater than 0
      • ((Attacking unit) belongs to an enemy of (Owner of (Attacked unit))) Equal to True
    • Actions
      • Set SA_U_AtkUnit = (Attacked unit)
      • Set SA_PL_Player = (Owner of SA_U_AtkUnit)
      • Set SA_I_Level = (Level of SA_A_ActiveAbility for SA_U_AtkUnit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • SA_B_UseStat Equal to True
        • Then - Actions
          • Set SA_R_HealAmt = ((Real((Strength of SA_U_AtkUnit (Include bonuses)))) x (SA_R_Heal[SA_I_Level] x 0.01))
        • Else - Actions
          • Set SA_R_HealAmt = SA_R_Heal[SA_I_Level]
      • Set SA_P_AtkPos = (Position of (Attacked unit))
      • Set SA_UG_UnitGroup = (Units within SA_R_AoE[SA_I_Level] of SA_P_AtkPos matching ((((Matching unit) is alive) Equal to True) and ((((Matching unit) belongs to an ally of SA_PL_Player) Equal to True) and ((((Matching unit) is A structure) Equal to SA_B_HealStructures) and ((((Match
      • Game - Display to (All players) the text: (String(SA_R_HealAmt))
      • Unit Group - Pick every unit in SA_UG_UnitGroup and do (Actions)
        • Loop - Actions
          • Set SA_U_Picked = (Picked unit)
          • Unit - Set life of SA_U_Picked to ((Life of SA_U_Picked) + SA_R_HealAmt)
          • Special Effect - Create a special effect attached to the SA_S_Attach of SA_U_Picked using SA_S_SFX
          • Special Effect - Destroy (Last created special effect)
      • Unit Group - Remove all units from SA_UG_UnitGroup
      • Custom script: call DestroyGroup(udg_SA_UG_UnitGroup)
      • Custom script: call RemoveLocation(udg_SA_P_AtkPos)


Looks good but I don't know if it's intended but you should use BB Codes for tooltip, not the standard code in Warcraft tooltips for colors.

Anyway, to all of you, may the best one wins, good luck!
 
Level 13
Joined
Jun 20, 2014
Messages
479
Looks good but I don't know if it's intended but you should use BB Codes for tooltip, not the standard code in Warcraft tooltips for colors.

Anyway, to all of you, may the best one wins, good luck!


Emits an aura that heals nearby allied units whenever the bearer of the aura is attacked. Also allows you to force nearby enemy units to attack you for a duration.

Level 1 - Heals nearby units based on 30% of the bearer's Strength.
Level 2 - Heals nearby units based on 60% of the bearer's Strength.
Level 3 - Heals nearby units based on 90% of the bearer's Strength.
Level 4 - Heals nearby units based on 120% of the bearer's Strength.

Area of Effect: 500
Units that has this ability will not be healed by this aura.


EDIT: Epic fail!
haha
 
Level 30
Joined
Nov 29, 2012
Messages
6,637

Emits an aura that heals nearby allied units whenever the bearer of the aura is attacked. Also allows you to force nearby enemy units to attack you for a duration.

[color]cffffcc00Level 1|r[/color] - Heals nearby units based on 30% of the bearer's [color]|cffffcc00Strength|r[/color].
[color]|cffffcc00Level 2|r[/color] - Heals nearby units based on 60% of the bearer's [color]|cffffcc00Strength|r[/color].
[color]|cffffcc00Level 3|r[/color] - Heals nearby units based on 90% of the bearer's [color]|cffffcc00Strength|r[/color].
[color]|cffffcc00Level 4|r[/color] - Heals nearby units based on 120% of the bearer's [color]|cffffcc00Strength|r[/color].

Area of Effect: 500
[color]|cffffcc00Units that has this ability will not be healed by this aura.|r [/color]


EDIT: Epic fail!
haha


Emits an aura that heals nearby allied units whenever the bearer of the aura is attacked. Also allows you to force nearby enemy units to attack you for a duration.

Level 1 - Heals nearby units based on 30% of the bearer's Strength.
Level 2 - Heals nearby units based on 60% of the bearer's Strength.
Level 3 - Heals nearby units based on 90% of the bearer's Strength.
Level 4 - Heals nearby units based on 1200% of the bearer's Strength.

Area of Effect: 500
Units that has this ability will not be healed by this aura.

Code:
[plain]Emits an aura that heals nearby allied units whenever the bearer of the aura is attacked. Also allows you to force nearby enemy units to attack you for a duration.

[color=yellow]Level 1[/color] - Heals nearby units based on 30% of the bearer's [color=red]Strength[/color].
[color=yellow]Level 2[/color] - Heals nearby units based on 60% of the bearer's [color=red]Strength[/color].
[color=yellow]Level 3[/color] - Heals nearby units based on 90% of the bearer's [color=red]Strength[/color].
[color=yellow]Level 4[/color] - Heals nearby units based on 120% of the bearer's [color=red]Strength[/color].

Area of Effect: 500
[color=yellow]Units that has this ability will not be healed by this aura.[/color][/plain]
 
Status
Not open for further replies.
Top