1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Head to the 33rd Modeling Contest Poll and drink to your heart's desire.
    Dismiss Notice
  3. Choose your means of doom in the 17th Mini Mapping Contest Poll.
    Dismiss Notice
  4. A slave to two rhythms, the 22nd Terraining Contest is here.
    Dismiss Notice
  5. The heavens smile on the old faithful. The 16th Techtree Contest has begun.
    Dismiss Notice
  6. The die is cast - the 6th Melee Mapping Contest results have been announced. Onward to the Hive Cup!
    Dismiss Notice
  7. The glory of the 20th Icon Contest is yours for the taking!
    Dismiss Notice
  8. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Trigger Viewer

Metaversal Spell Pack v1.03.w3x
Variables
Libraries
LibraryDT
Logarithm
ArmorUtils
Balminess v1.01
Balminess
Foltern v1.01
Foltern
Hiatus v1.01
Hiatus
Impairment v1.02
Impairment
Stunning Ward v1.01
Stunning Ward
Sweltering Blaze v1.01
Sweltering Blaze
Initialization (Ignore This)
Spawn
Stop Spawn
Start Spaw
Spawn Type
Spawn move up
Restore
Kill
Revive
Remove Unit Up
Remove Unit Down
Map Intialization
Text 2
//TESH.scrollpos=27
//TESH.alwaysfold=0
//************************ GENERAL DOCUMENTATION ************************
//*                                                                     *
//*                        Metaversal Spell Pack                        *
//*                            By: Deuterium                            *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Spell Pack Description:                                             *
//*                                                                     *
//*     A spell pack with some useful and simple spell ideas.           *
//*     The spells are coded in vJass and thus require JNGP to be       *
//*     edited or saved.                                                *
//*                                                                     *
//*     JNGP can be downloaded here:                                    *
//*     http://www.wc3c.net/showthread.php?t=90999                      *
//*                                                                     *
//*     Questions, bug repots, and advice are always welcome.           *
//*                                                                     *
//***********************************************************************
//* Spells:                                                             *
//*                                                                     *
//*     - Balminess v1.01                                               *
//*     - Foltern v1.01                                                 *
//*     - Hiatus v1.01                                                  *
//*     - Impairment v1.02                                              *
//*     - Stunning Ward v1.01                                           *
//*     - Sweltering Blaze v1.01                                        *
//*                                                                     *
//***********************************************************************
//* Changelog:                                                          *
//*                                                                     *
//*     v1.00 (August 13, 2009):                                        *
//*         - Released                                                  *
//*                                                                     *
//*     v1.01 (September 11, 2009):                                     *
//*         - Reworked most of the spells and LibraryDT                 *
//*                                                                     *
//*     v1.02 (August 29, 2011):                                        *
//*         - Removed the spell: Maze                                   *
//*         - Fixed a bug in Impairment                                 *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Importing other libraries:                                          *
//*                                                                     *
//*     In each spell documentation, in the "How to import" I mention   *
//*     the required libraries. Simply copy them into your trigger      *
//*     editor. You might want to check the libraries' own              *
//*     documentation in case there is something you might want to      *
//*     tweak.                                                          *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//*  - A little note on how to adjust:                                  *
//*     when using dummy abilites, I name them using the following      *
//*     structure: <ability's two initials>_<what ability does/affects>.*
//*     This enables the user to easily understand and adjust dummy     *
//*     abilities.                                                      *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Credit is appreciated.                                              *
//*                                                                     *
//***********************************************************************
Name Type Is Array Initial Value
EA_AbilityId abilcode No
EA_AngularCounter real Yes
EA_ArealSFXMaxHeight real No
EA_AreaSFX1Id unitcode No
EA_AreaSFX2Id unitcode No
EA_AreaSFXId modelfile No
EA_Boolean boolean Yes
EA_BuffId buffcode No
EA_Damage real Yes
EA_DamageInterval real No
EA_DummyId unitcode No
EA_FirstAngSpeed real No
EA_Group group Yes
EA_GroupCheckTimer real Yes
EA_HeightCounter real Yes
EA_HeightSpeed real No
EA_Index integer Yes
EA_InitFlyHeight real No
EA_InitOffset real No
EA_IntervalCounter integer Yes
EA_Intervals integer Yes
EA_InvisAbilityId abilcode No
EA_InvisBoolean boolean Yes
EA_Missile1 unit Yes
EA_Missile2 unit Yes
EA_Missile3 unit Yes
EA_Missile4 unit Yes
EA_Missle1Id unitcode No
EA_Missle2Id unitcode No
EA_Missle3Id unitcode No
EA_MUIGroup group Yes
EA_OwningPlayer player Yes
EA_PauseAbilityId abilcode No
EA_PauseBuffId buffcode No
EA_Polar1 location Yes
EA_Polar2 location Yes
EA_Polar3 location Yes
EA_Polar4 location Yes
EA_Random real Yes
EA_SFXInterval real No
EA_SFXTimer real Yes
EA_SlowAbilityId abilcode No
EA_SpreadCounter real Yes
EA_SpreadOutHeight real No
EA_SpreadOutRange real No
EA_SpreadOutSpeed real No
EA_TimeCounter real Yes
EA_TrigUnit unit Yes
EA_TrigUnitLoc location Yes
fsf handle No
hash hashtable No
IM_AbilityID abilcode Yes
IM_Boolean boolean Yes
IM_HitPoint real Yes
IM_Index integer Yes
IM_LoopIsOn boolean Yes
IM_ManaPercentage real Yes
IM_Missile unit Yes
IM_MissileDummy unitcode Yes
IM_MissileLoc location Yes
IM_MissileRange real Yes
IM_MissileSpeed real Yes
IM_PolarLoc location Yes
IM_TargUnit unit Yes
IM_TargUnitLoc location Yes
IM_TrigUnit unit Yes
IM_TrigUnitLoc location Yes
SW_AbilityID abilcode Yes
SW_Index integer Yes
SW_LoopIsOn boolean Yes
SW_MiniStunID abilcode Yes
SW_Range real Yes
SW_RefreshRate real Yes
SW_StunnerID unitcode Yes
SW_TargPoint location Yes
SW_Timer real Yes
SW_TimerExpiry real Yes
SW_TrigUnit unit Yes
SW_UnitsInRange group Yes
SW_WardID unitcode Yes
Y_Map_Point location Yes
Y_Map_Region rect Yes
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//***********************************************************************
//*                                                                     *
//*                              LibraryDT                              *
//*                            By: Deuterium                            *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Import LibraryDT:                                                   *
//*                                                                     *
//*     1. Copy and paste the unit "General Dummy" in the Object Editor *
//*        into your map.                                               *
//*                                                                     *
//*     2. Import dummy.mdl present between the imports of this map.    *
//*                                                                     *
//*     3. Copy and paste the trigger "LibraryDT" in the Trigger Editor *
//*        into your map.                                               *
//*                                                                     *
//*     4. Adjust the DummyDT ID present at the top of the library.     *
//*                                                                     *
//***********************************************************************
//* Changelog:                                                          *
//*                                                                     *
//*     v1.00:                                                          *
//*         - Released                                                  *
//*                                                                     *
//*     v1.01:                                                          *
//*         - Full re-do of the library                                 *
//*                                                                     *
//*     v1.02:                                                          *
//*         - Improved a few functions                                  *
//*                                                                     *
//***********************************************************************


library LibraryDT initializer Init

//= Adjustables =============================================================
       
    ////////////////////////////////////
    //          ADJUSTABLES           //
    ////////////////////////////////////
     
    globals
   
        constant integer DummyDT = 'h000'       // The ID of the General Dummy

    endglobals

    ////////////////////////////////////
    //        ADJUSTABLES END         //
    ////////////////////////////////////



//***************************************************************************
//*                        GENERAL PURPOSE FUNCTIONS                        *
//***************************************************************************

//= Spell Init ==============================================================

// call SpellInitDT(pue, action, condition)
function SpellInitDT takes playerunitevent pue, code action, code condition returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0
    loop
        call TriggerRegisterPlayerUnitEvent(t, Player(i), pue, null)
        exitwhen i >= 15
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Condition(condition))
    call TriggerAddAction(t, action)
    set t = null
endfunction


//= Timer User Data (works for handles too) ================================

// call SetTimerUserData(whichTimer, whichStruct)
function SetTimerUserData takes handle whichTimer, integer whichStruct returns nothing
    call SaveInteger(HASHTABLE_DT, 1, GetHandleId(whichTimer), whichStruct)
endfunction

// call GetTimerUserData(whichTimer)
function GetTimerUserData takes handle whichTimer returns integer
    return LoadInteger(HASHTABLE_DT, 1, GetHandleId(whichTimer))
endfunction

// call FlushTimerUserData(whichTimer)
function FlushTimerUserData takes handle whichTimer returns nothing
    call FlushChildHashtable(HASHTABLE_DT, GetHandleId(whichTimer))
endfunction


//= Preload =================================================================

globals
    private constant real PRELOAD_X = GetRectCenterX(bj_mapInitialPlayableArea)
    private constant real PRELOAD_Y = GetRectCenterY(bj_mapInitialPlayableArea)
endglobals

// call PreloadSpecialEffectDT(SFX)
function PreloadSpecialEffectDT takes string whichSFX returns nothing
    call Preload(whichSFX)
    call PreloadStart()
endfunction

// call PreloadUnitDT(whichUnit)
function PreloadUnitDT takes integer unitid returns nothing
    set bj_lastCreatedUnit = CreateUnit(Player(15), unitid, PRELOAD_X, PRELOAD_Y, 0.)
    call RemoveUnit(bj_lastCreatedUnit)
endfunction

//= General Initializer =====================================================
globals
    hashtable HASHTABLE_DT
endglobals

private function Init takes nothing returns nothing
    set HASHTABLE_DT = InitHashtable()

    call PreloadUnitDT(DummyDT)

    debug call BJDebugMsg("|cffffcc00LibraryDT Initiated|r")
endfunction



//***************************************************************************
//*                             MATH FUNCTIONS                              *
//***************************************************************************

//= Distance ================================================================

globals
    private real dx
    private real dy
endglobals

// call GetDistanceBetweenPointsDT(ax, ay, bx, by)
function GetDistanceBetweenPointsDT takes real ax, real ay, real bx, real by returns real
    set dx = bx - ax
    set dy = by - ay

    return SquareRoot(dx * dx + dy * dy)
endfunction

// call GetDistanceBetweenUnitsDT(unita, unitb)
function GetDistanceBetweenUnitsDT takes unit a, unit b returns real
    return GetDistanceBetweenPointsDT(GetUnitX(a), GetUnitY(a), GetUnitX(b), GetUnitY(b))
endfunction



//***************************************************************************
//*                            DUMMY FUNCTIONS                              *
//***************************************************************************

//= Cast Target =============================================================

// call CastTargetDT(aster, targer, abil, order, level)
function CastTargetDT takes unit caster, unit target, integer abilcode, string order, integer level returns nothing
    call UnitAddAbility(caster, abilcode)
    call SetUnitAbilityLevel(caster, abilcode, level)
    call IssueTargetOrder(caster, order, target)
endfunction

// call DummyCastTargetDT(id, target, abil, order, level)
function DummyCastTargetDT takes player id, unit target, integer abilcode, string order, integer level returns nothing
    set bj_lastCreatedUnit = CreateUnit(id, DummyDT, GetUnitX(target), GetUnitY(target), 0.)
    call CastTargetDT(bj_lastCreatedUnit, target, abilcode, order, level)
    call UnitApplyTimedLife(bj_lastCreatedUnit, 'BTLF', .5)
endfunction



//***************************************************************************
//*                          TEXTTAG FUNCTIONS                              *
//***************************************************************************

//= TextTag Unit ============================================================

// call TextTagUnitDT(u, tag, fade, size, height, vel, red, green, blue, trans)
function TextTagUnitDT takes unit u, string tag, real fade, real size, real heightoffset, real vel, integer red, integer green, integer blue, integer visibility returns nothing
    set bj_lastCreatedTextTag = CreateTextTag()
    call SetTextTagText(bj_lastCreatedTextTag, tag, size)
    call SetTextTagPosUnit(bj_lastCreatedTextTag, u, heightoffset)
    call SetTextTagColor(bj_lastCreatedTextTag, red, green, blue, visibility)
    call SetTextTagPermanent(bj_lastCreatedTextTag, false)
    call SetTextTagVelocity(bj_lastCreatedTextTag, 0., vel)
    call SetTextTagLifespan(bj_lastCreatedTextTag, fade)
    call SetTextTagFadepoint(bj_lastCreatedTextTag, fade)
    call SetTextTagVisibility(bj_lastCreatedTextTag, true)
endfunction



//***************************************************************************
//*                          MISSILE FUNCTIONS                              *
//***************************************************************************

//= Move Missile ============================================================
globals
    private real xm
    private real ym
    private real an
endglobals

// call MoveMissileDT(missile, tx, ty, speed)
function MoveMissileDT takes unit missile, real tx, real ty, real speed returns nothing
    set xm = GetUnitX(missile)
    set ym = GetUnitY(missile)
    set an = Atan2(ty - ym, tx - xm)

    call SetUnitPosition(missile, xm + speed * Cos(an), ym + speed * Sin(an))
    call SetUnitFacing(missile, (bj_RADTODEG * an))
endfunction

// call MoveMissileTargetDT(missile, target, speed)
function MoveMissileTargetDT takes unit missile, unit target, real speed returns nothing
    call MoveMissileDT(missile, GetUnitX(target), GetUnitY(target), speed)
endfunction


//= Create Missile ==========================================================

globals
    private effect array MissileModel
endglobals

// call CreateMissileDT(owner, x, y, facing, offset, model, attachmentpt, height, size)
function CreateMissileDT takes player owner, real x, real y, real facing, real offset, string model, string attachmentpt, real height, real size returns unit
    set bj_lastCreatedUnit = CreateUnit(owner, DummyDT, x + offset * Cos(facing), y + offset * Sin(facing), facing)
    if size != 1. then
        call SetUnitScale(bj_lastCreatedUnit, size, size, size)
    endif
    if height != 0. then
        call UnitAddAbility(bj_lastCreatedUnit, 'Arav')
        call SetUnitFlyHeight(bj_lastCreatedUnit, height, 0.)
        call UnitRemoveAbility(bj_lastCreatedUnit, 'Arav')
    endif
    call SaveEffectHandle(HASHTABLE_DT, 1, GetHandleId(bj_lastCreatedUnit), AddSpecialEffectTarget(model, bj_lastCreatedUnit, attachmentpt))
    return bj_lastCreatedUnit
endfunction

// call CreateFiredMissileDT(firingunit, offset, model, attachmentpt, height, size)
function CreateFiredMissileDT takes unit firingunit, real offset, string model, string attachmentpt, real height, real size returns unit
    return CreateMissileDT(GetOwningPlayer(firingunit), GetUnitX(firingunit), GetUnitY(firingunit), GetUnitFacing(firingunit), offset, model, attachmentpt, height, size)
endfunction

// call DestroyMissileDT(whichMissile)
function DestroyMissileDT takes unit whichMissile returns nothing
    call DestroyEffect(LoadEffectHandle(HASHTABLE_DT, 1, GetHandleId(whichMissile)))
    call UnitApplyTimedLife(whichMissile, 'BTLF', .01)
endfunction


//===========================================================================

endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library Logarithm

   globals
       private constant integer ITERATIONS=20
   endglobals

    function Log takes real x returns real
     local real min=-88.0
     local real max= 88.0
     local real mid
     local integer i=ITERATIONS

        loop
            set mid=(min+max)/2
            exitwhen(i<=0)
            set i=i-1
            if (Pow(bj_E,mid)>=x) then
                set max=mid
            else
                set min=mid
            endif
        endloop
     return mid
    endfunction

    function Logarithm takes real base, real x returns real
     local real min=-88.0
     local real max= 88.0
     local real mid
     local integer i=ITERATIONS

        loop
            set mid=(min+max)/2
            exitwhen(i<=0)
            set i=i-1
            if (Pow(base,mid)>=x) then
                set max=mid
            else
                set min=mid
            endif
        endloop
     return mid
    endfunction

endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library ArmorUtils needs Logarithm
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This is used to get the exact real-value for armor of a given unit. It
//* deals damage to the unit in order to determine armor, meaning that damage
//* detection systems can detect it. However, the code disables the triggering
//* trigger, so this will not cause any problems so long as only one DAMAGED
//* event is registered to your units at a time. Hopefully all standardized
//* damage detection systems these days only register units once, so this should
//* handle it perfectly.
//*
//* Also, it should be noted that changing the ATTACK_TYPE_CHAOS table in
//* gameplay constants will make this return weird values. Chaos is used because
//* it deals 100% to all types, so either keep it as is or use another type with
//* 100% damage.
//*
//* The GetUnitArmor function will return ARMOR_INVULNERABLE as the value for
//* the unit's armor if it is invulnerable. The reason invulnerability isn't
//* removed from the unit is that not all sources of invulnerability come from
//* the 'Avul' ability and in those cases it cannot be removed. A check can be
//* made against ARMOR_INVULNERABLE to see if the function returned such. The
//* value is about as random as I could think of at the time in the hopes that
//* no one will actually give any of their heroes armor coinciding with it.
//* (since only heroes can have decimal armor)
//*
//* Negative armor in WC3 is treated differently than positive armor. Also, WC3
//* has a negative damage reduction cap at -71%, which corresponds to -20 armor.
//* If you use GetUnitArmor on a unit with less armor than -20, it will always
//* return -20, since WC3 caps there. This is an unfortunate but unavoidable
//* limitation of WC3's armor system.
//*
//* The most important value that you change for this code coincides with the
//* Game Constant 'Armor Damage Reduction Multiplier' and for this system is
//* called ARMOR_REDUCTION_MULTIPLIER. This value typically ranges from 0.05 to
//* 0.10, but really depends on your map. Be sure to change it in this code to
//* match your map or it will not return correct armor values.
//*
//* The other variables in the code do not ever need to be changed. DAMAGE_LIFE
//* must only be large enough to survive a hit with DAMAGE_TEST damage dealt.
//* (Also factoring in negative armor damage bonus) NATLOG_094 is necessary for
//* the calculation of negative armor values.
//*
//* Other functions available for use are GetFullDamage and GetReducedDamage.
//* GetFullDamage, when passed the actual damage a unit takes (In most cases,
//* GetEventDamage from EVENT_UNIT_DAMAGED event callbacks) and a unit's armor,
//* it will return how much damage was dealt before armor reduction. Similarly,
//* GetReducedDamage, when given the base damage and armor, will return how much
//* damage will be dealt after armor is considered. These functions DO NOT
//* consider armor types in their calculations, so any further reductions or
//* bonuses due to that will need to be considered BEFORE using these functions.
//* I recommend using your damage detection system to modify and build your own
//* armor types anyways.
//*
//* You can use the ObjectMerger call below in order to generate the ability for
//* keeping units with maximum life lower than DAMAGE_TEST from dying when
//* using GetUnitArmor on them. If you do not plan on editing the 'AIlz' ability
//* in your map, you can keep the ObjectMerger call commented out and replace
//* 'lif&' in the configuration constants with 'AIlz'. The 'AIlz' ability adds
//* 50 max life, which is plenty for the script.
//*
//* Function Listing --
//*     function GetUnitArmor takes unit u returns real
//*     function GetReducedDamage takes real baseDamage, real armor returns real
//*     function GetFullDamage takes real damage, real armor returns real
//*
globals
    //Values that should be changed for your map
    private constant real    ARMOR_REDUCTION_MULTIPLIER = 0.06
    private constant integer LIFE_BONUS_SPELL_ID        = 'lif&'
   
    //Values that do not need to be changed
            constant real    ARMOR_INVULNERABLE         = 917451.519
    private constant real    DAMAGE_TEST                = 16.
    private constant real    DAMAGE_LIFE                = 30.
    private constant real    NATLOG_094                 =-0.061875
endglobals

////! external ObjectMerger w3a AIlz lif& anam "GetUnitArmorLifeBonus" ansf "" Ilif 1 30 aite 0

function GetUnitArmor takes unit u returns real
    local real    life = GetWidgetLife(u)
    local real    test = life
    local real    redc = 0.
    local boolean enab = false
    local trigger trig = GetTriggeringTrigger()
    if u != null and life >= 0.405 then
        if GetUnitState(u, UNIT_STATE_MAX_LIFE) <= DAMAGE_TEST then
            //Add max life to keep it alive
            call UnitAddAbility(u, LIFE_BONUS_SPELL_ID)
        endif
        if life <= DAMAGE_LIFE then
            //If under the threshold, heal it for the moment
            call SetWidgetLife(u, DAMAGE_LIFE)
            set test = DAMAGE_LIFE
        endif
        if trig != null and IsTriggerEnabled(trig) then
            //Disable the trigger to prevent it registering with damage detection systems
            call DisableTrigger(trig)
            set enab = true
        endif
        call UnitDamageTarget(u, u, DAMAGE_TEST, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
        set redc = (DAMAGE_TEST-test+GetWidgetLife(u))/DAMAGE_TEST
        if enab then
            //Re-enable the trigger
            call EnableTrigger(trig)
        endif
        //Remove the max life ability
        call UnitRemoveAbility(u, LIFE_BONUS_SPELL_ID)
        call SetWidgetLife(u, life)
        set trig = null
        if redc >= 1. then
            //Invulnerable
            return ARMOR_INVULNERABLE
        elseif redc < 0. then
            //Negative Armor
            return -Log(redc+1.)/NATLOG_094
        else
            //Positive Armor
            return redc/(ARMOR_REDUCTION_MULTIPLIER*(1.-redc))
        endif
    endif
    set trig = null
    return 0.
endfunction

function GetReducedDamage takes real baseDamage, real armor returns real
    if armor >= 0. then
        return baseDamage*(1.-((armor*ARMOR_REDUCTION_MULTIPLIER)/(1.+ARMOR_REDUCTION_MULTIPLIER*armor)))
    else
        return baseDamage*(2.-Pow(0.94,-armor))
    endif
endfunction

function GetFullDamage takes real damage, real armor returns real
    if armor >= 0. then
        return damage/(1.-((armor*ARMOR_REDUCTION_MULTIPLIER)/(1.+ARMOR_REDUCTION_MULTIPLIER*armor)))
    else
        return damage/(2.-Pow(0.94,-armor))
    endif
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//***********************************************************************
//*                                                                     *
//*                              Balminess                              *
//*                            By: Deuterium                            *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Spell Description:                                                  *
//*                                                                     *
//*     The caster throws a ball of fire towards an enemy unit which    *
//*     burns the target for 20 damage and overheats its armor dealing  *
//*     extra damage depending on the target's armor every 1 second.    *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* How to adjust and customize:                                        *
//*                                                                     *
//*     Simply adjust the settings found between the two tags:          *
//*     ADJUSTABLES/ADJUSTABLES END                                     *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* How to import (requires LibraryDT, Armor Utils, and Logarithm):     *
//*                                                                     *
//*     1. Copy and paste the abilities "Balminess" and "BA_Burn" in    *
//*        the Object Editor into your map.                             *
//*                                                                     *
//*     2. Copy and paste the buff "BA_Burn" in the Object Editor into  *
//*        your map.                                                    *
//*                                                                     *
//*     3. Copy and paste the trigger "Balminess" in the Trigger Editor *
//*        into your map.                                               *
//*                                                                     *
//*     4. Adjust the ID's present among the adjustable globals.        *
//*                                                                     *
//***********************************************************************
//* Changelog:                                                          *
//*                                                                     *
//*     v1.00:                                                          *
//*         - Released                                                  *
//*                                                                     *
//*     v1.01:                                                          *
//*         - Reworked                                                  *
//*                                                                     *
//***********************************************************************
//* Credits:                                                            *
//*                                                                     *
//*     Dark_Dragon:                                                    *
//*         - Fixing a few mistakes                                     *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Credit is appreciated.                                              *
//*                                                                     *
//***********************************************************************



scope Balminess

globals
    private integer array DAMAGE_INTERVALS
    private real array DAMAGE_INTERVAL_TIME_GAP
    private real array BASE_DAMAGE
    private real array DAMAGE_MULTIPLIER
endglobals

//===========================================================================
       
    ////////////////////////////////////
    //          ADJUSTABLES           //
    ////////////////////////////////////
     
    globals
   
        // --- IDs ---
        private constant integer    ABILITY_ID                      = 'A008'            // The ID of the Balminess ability
        private constant integer    BUFF_ABILITY_ID                 = 'A009'            // The ID of the BA_Burn ability
        private constant integer    BUFF_ID                         = 'B002'            // The ID of the BA_Burn buff
       
        // --- Missile settings ---
        private constant string     MISSILE_MODEL                   = "Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl"       // The model of the missile
        private constant real       MISSILE_SPEED                   = 30.               // The speed of the missile
        private constant real       MISSILE_COLLISION_RANGE         = 30.               // The collision range of the missile
        private constant real       MISSILE_HEIGHT                  = 80.               // The height of missile
        private constant real       MISSILE_SIZE                    = 1.                // The size of the missile
        private constant real       MISSILE_OFFSET                  = 0.                // The missile's offset from the caster at creation
       
        // --- Damage and attack types settings ---
        private constant attacktype ATTACK_TYPE                     = ATTACK_TYPE_CHAOS // The attack type of the damage dealt
        private constant damagetype DAMAGE_TYPE                     = DAMAGE_TYPE_FIRE  // The damage type of the damage dealt
       
        // --- Special effects settings ---
        private constant string     TARGET_SFX                      = "Abilities\\Spells\\Other\\BreathOfFire\\BreathOfFireDamage.mdl"  // The special effect attached to the target being damaged
        private constant string     TARGET_SFX_ATTACHMENT_PT        = "chest"           // The attachment point for the special effect on the target being damaged
       
        // --- Core settings ---
        private constant real       TIMEOUT                         = .03               // The time gap at which the main timer runs
       
    endglobals

    private function Setup takes nothing returns nothing
       
        // General Setup note:
        //      the array integer refers to the level of the intended ability
       
       
        // --- Damage properties ---
       
        // Damage formula would be:
        //      BASE_DAMAGE + (DAMAGE_MULTIPLIER x Target's armor)
       
        // The number of intervals for the damage to occur
        set DAMAGE_INTERVALS[1] = 10
        set DAMAGE_INTERVALS[2] = 10
        set DAMAGE_INTERVALS[3] = 10
        set DAMAGE_INTERVALS[4] = 10
       
        // The number of the time gap between each damage interval
        set DAMAGE_INTERVAL_TIME_GAP[1] = 1.
        set DAMAGE_INTERVAL_TIME_GAP[2] = 1.
        set DAMAGE_INTERVAL_TIME_GAP[3] = 1.
        set DAMAGE_INTERVAL_TIME_GAP[4] = 1.
       
        // The base damage dealt regardless of the target's armor
        set BASE_DAMAGE[1] = 20.
        set BASE_DAMAGE[2] = 20.
        set BASE_DAMAGE[3] = 20.
        set BASE_DAMAGE[4] = 20.
       
        // The factor to which the targer's armor is multiplied and whose product is then dealt in damage
        set DAMAGE_MULTIPLIER[1] = 1.
        set DAMAGE_MULTIPLIER[2] = 2.
        set DAMAGE_MULTIPLIER[3] = 3.
        set DAMAGE_MULTIPLIER[4] = 4.
       
    endfunction

    ////////////////////////////////////
    //        ADJUSTABLES END         //
    ////////////////////////////////////

//===========================================================================
   
private struct BA

//= Struct Variables ========================================================

    unit tr     // Triggering unit
    player pt   // Owner of the triggering unit
    integer lvl // Level of the ability
   
    unit ta     // Target unit
    real tx     // Target's X
    real ty     // Target's Y
    effect e    // Effect attached to target

    unit m      // Missile
   
    real f      // Armor info
   
    real tco    // Timer counter
    integer ico // Interval counter
   
    timer time  // Timer variable
   
    debug boolean bool
   
//= destroy ================================================================

    private method destroy takes nothing returns nothing
        call PauseTimer(this.time)
        call FlushTimerUserData(this.time)
        call DestroyTimer(this.time)
       
        call UnitRemoveAbility(this.ta, BUFF_ID)
       
        call DestroyEffect(this.e)
       
        set this.tr     = null
        set this.pt     = null
        set this.ta     = null
        set this.e      = null
        set this.m      = null
        set this.time   = null
        set this.ico    = 0
       
        debug call BJDebugMsg("|cffc3dbffBalminess:|r Struct instance |cffff0000" + I2S(this) + "|r destroyed")
        debug call BJDebugMsg(" ")
        debug set this.bool = false
       
        call .deallocate()
    endmethod
   
//= Damage Over Time ========================================================

    private static method DoT takes nothing returns nothing
       
    // --- Announcing struct instance and running time counter ---
        local BA d = BA(GetTimerUserData(GetExpiredTimer()))
        set d.tco = d.tco + TIMEOUT
       
    // --- Debug ---
        debug if d.bool == false then
        debug      call BJDebugMsg("|cffc3dbffBalminess:|r Target hit")
        debug      call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
        debug      call BJDebugMsg(" ")
        debug      set d.bool = true
        debug endif
       
    // --- Checking if the target is dead to terminate the instance ---
        if IsUnitType(d.ta, UNIT_TYPE_DEAD) then
            debug call BJDebugMsg("|cffc3dbffBalminess:|r Target died")
            debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
            debug call BJDebugMsg(" ")
           
            set d.tco = 0.
            call d.destroy()
            return
        endif
       
    // --- Checking if it's time to damage ---
        if d.tco >= DAMAGE_INTERVAL_TIME_GAP[d.lvl] then
            set d.tco = 0.
            set d.ico = d.ico + 1
           
            debug call BJDebugMsg("|cffc3dbffBalminess:|r Target damaged -- Damage instance: " + I2S(d.ico))
            debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
            debug call BJDebugMsg(" ")
           
    // --- Getting target's armor ---
            if GetUnitArmor(d.ta) > 0. then
                set d.f = GetUnitArmor(d.ta)
            else
                set d.f = 0.
            endif
   
    // --- Damaging target ---
            call UnitDamageTarget(d.tr, d.ta, (BASE_DAMAGE[d.lvl] + (DAMAGE_MULTIPLIER[d.lvl] * d.f)), true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE_WHOKNOWS)
           
    // --- Checking if all intervals ran to terminate the instance ---
            if d.ico >= DAMAGE_INTERVALS[d.lvl] then
                debug call BJDebugMsg("|cffc3dbffBalminess:|r All intervals ran")
                debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
                debug call BJDebugMsg(" ")
               
                call d.destroy()
            endif
        endif
    endmethod
   
//= Missile's Motion ========================================================

    private static method Loop takes nothing returns nothing
   
    // --- Announcing struct instance ---
        local BA d = BA(GetTimerUserData(GetExpiredTimer()))
   
    // --- Debug ---
        debug if d.bool == false then
        debug      call BJDebugMsg("|cffc3dbffBalminess:|r Missile is moving")
        debug      call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
        debug      call BJDebugMsg(" ")
        debug      set d.bool = true
        debug endif
       
    // --- Moving missile ---
        set d.tx = GetUnitX(d.ta)
        set d.ty = GetUnitY(d.ta)
        call MoveMissileDT(d.m, d.tx, d.ty, MISSILE_SPEED)
       
    // --- Checking if missile collided with target to detroy missile ---
        if GetDistanceBetweenPointsDT(GetUnitX(d.m), GetUnitY(d.m), d.tx, d.ty) <= MISSILE_COLLISION_RANGE then
            call CastTargetDT(d.m, d.ta, BUFF_ABILITY_ID, "curse", d.lvl)
            call DestroyMissileDT(d.m)
            set d.e = AddSpecialEffectTarget(TARGET_SFX, d.ta, TARGET_SFX_ATTACHMENT_PT)
           
            debug set d.bool = false
   
    // --- Running damage over time ---
            call PauseTimer(d.time)
            call TimerStart(d.time, TIMEOUT, true, function BA.DoT)
        endif
    endmethod
   
//= Initial Actions =========================================================

    private static method Create takes nothing returns nothing
   
    // --- Allocating new struct instance ---
        local BA d = BA.allocate()
   
    // --- Debug ---
        debug call BJDebugMsg("|cffc3dbffBalminess:|r Initiated")
        debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
        debug call BJDebugMsg(" ")
       
    // --- Setting some variables ---
        set d.tr = GetTriggerUnit()
        set d.pt = GetOwningPlayer(d.tr)
        set d.lvl = GetUnitAbilityLevel(d.tr, ABILITY_ID)
       
        set d.ta = GetSpellTargetUnit()
       
        set d.m = CreateMissileDT(d.pt, GetUnitX(d.tr), GetUnitY(d.tr), GetUnitFacing(d.tr), MISSILE_OFFSET, MISSILE_MODEL, "origin", MISSILE_HEIGHT, MISSILE_SIZE)
   
    // --- Creating and running timer to move missile ---
        set d.time = CreateTimer()
        call SetTimerUserData(d.time, integer(d))
        call TimerStart(d.time, TIMEOUT, true, function BA.Loop)
    endmethod

//= Condition and Initializer ===============================================

    private static method ConditionCheck takes nothing returns boolean
        return GetSpellAbilityId() == ABILITY_ID
    endmethod

    private static method onInit takes nothing returns nothing
        call SpellInitDT(EVENT_PLAYER_UNIT_SPELL_EFFECT, function BA.Create, function BA.ConditionCheck)
       
        call Setup()
       
        call PreloadSpecialEffectDT(MISSILE_MODEL)
        call PreloadSpecialEffectDT(TARGET_SFX)
    endmethod

endstruct
   
endscope
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//***********************************************************************
//*                                                                     *
//*                               Foltern                               *
//*                            By: Deuterium                            *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Spell Description:                                                  *
//*                                                                     *
//*     The caster tends to let his target in on his pain dealing       *
//*     damage proportional to the caster's lost health over time.      *
//*     Every instance at which the target get's damage, it loses       *
//*     armor. If the target dies under the effect of Foltern, the      *
//*     caster tends to gain a certain percentage of his lost health.   *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* How to adjust and customize:                                        *
//*                                                                     *
//*     Simply adjust the settings found between the two tags:          *
//*     ADJUSTABLES/ADJUSTABLES END                                     *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* How to import (requires LibraryDT):                                 *
//*                                                                     *
//*     1. Copy and paste the abilities "Foltern" and "HP_Armor" in the *
//*        Object Editor into your map.                                 *
//*                                                                     *
//*     2. Copy and paste the trigger "Foltern" in the Trigger Editor   *
//*        into your map.                                               *
//*                                                                     *
//*     3. Adjust the ID's present among the adjustable globals.        *
//*                                                                     *
//***********************************************************************
//* Changelog:                                                          *
//*                                                                     *
//*     v1.00:                                                          *
//*         - Released                                                  *
//*                                                                     *
//*     v1.01:                                                          *
//*         - Reworked                                                  *
//*                                                                     *
//***********************************************************************
//* Credits:                                                            *
//*                                                                     *
//*     Dark_Dragon:                                                    *
//*         - Improving the onDestroy method                            *
//*                                                                     *
//*     -BerZeKeR-:                                                     *
//*         - The idea of decreasing the target's armor                 *
//*         - The advice on special effects                             *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Credit is appreciated.                                              *
//*                                                                     *
//***********************************************************************



scope Foltern

globals
    private integer array DAMAGE_INTERVALS
    private real array DAMAGE_INTERVAL_TIME_GAP
    private real array DAMAGE_RATIO
    private real array BASE_DAMAGE
endglobals

//===========================================================================
       
    ////////////////////////////////////
    //          ADJUSTABLES           //
    ////////////////////////////////////
     
    globals
   
        // --- IDs ---
        private constant integer    ABILITY_ID                      = 'A000'            // The ID of the Balminess ability
        private constant integer    ARMOR_ABILITY_ID                = 'A001'            // The ID of the FO_Armor ability
       
        // --- Damage and attack types settings ---
        private constant attacktype ATTACK_TYPE                     = ATTACK_TYPE_NORMAL// The attack type of the damage dealt
        private constant damagetype DAMAGE_TYPE                     = DAMAGE_TYPE_DEATH // The damage type of the damage dealt
       
        // --- Special effects settings ---
        private constant string     RUN_THROUGH_SFX                 = "Abilities\\Spells\\Human\\Banish\\BanishTarget.mdl"              //The special effect attached to the target throughout the whole cast
        private constant string     RUN_THROUGH_SFX_ATTACHMENT_PT   = "origin"           // Attachment point  
       
        private constant string     INIT_SFX_1                      = "Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl"   //The special effect attached to the target when the spell starts
        private constant string     INIT_SFX_1_ATTACHMENT_PT        = "origin"          // Attachment point
       
        private constant string     INIT_SFX_2                      = "units\\nightelf\\SpiritOfVengeance\\SpiritOfVengeance.mdl"       //The special effect attached to the  target when the spell starts
        private constant string     INIT_SFX_2_ATTACHMENT_PT        = "origin"          // Attachment point
       
        private constant string     DAMAGE_SFX                      = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"          //The special effect attached to the target every instance it gets damaged
        private constant string     DAMAGE_SFX_ATTACHMENT_PT        = "chest"           // Attachment point
       
        private constant string     DEATH_SFX_1                     = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"   //The special effect attached to the target and caster when the caster dies
        private constant string     DEATH_SFX_1_ATTACHMENT_PT       = "origin"          // Attachment point
       
        private constant string     DEATH_SFX_2                     = "units\\nightelf\\SpiritOfVengeance\\SpiritOfVengeance.mdl"       //The special effect attached to the target and caster when the caster dies
        private constant string     DEATH_SFX_2_ATTACHMENT_PT       = "origin"          // Attachment point

        // --- Texttag settings ---
        private constant boolean    TEXTAG_BOOLEAN                  = true              // If true, shows texttag, and if false, doesn't
        private constant integer    TEXTAG_COLOR_RED                = 75                // Texttag's red coloring (ranges from 0 to 255)
        private constant integer    TEXTAG_COLOR_GREEN              = 0                 // Texttag's green coloring (ranges from 0 to 255)
        private constant integer    TEXTAG_COLOR_BLUE               = 100               // Texttag's blue coloring (ranges from 0 to 255)
        private constant real       TEXTAG_FADE_TIME                = 1.                // Texttag's fading time
        private constant real       TEXTAG_SIZE                     = .025              // Texttag's size
        private constant real       TEXTAG_HEIGHT_OFFSET            = 32.               // Texttag's height offset
        private constant real       TEXTAG_VELOCITY                 = .036              // Texttag's upwards velocity
       
        // --- Core settings ---
        private constant real       TIMEOUT                         = .03               // The time gap at which the main timer runs
    endglobals
   
    private function Setup takes nothing returns nothing
   
        // General Setup note:
        //      the array integer refers to the level of the intended ability
       
       
        // --- Damage properties ---
       
        // Damage formula would be:
        //      BASE_DAMAGE + (DAMAGE_RATIO x Triggering unit's lost life)
       
        // The number of intervals for the damage to occur
        set DAMAGE_INTERVALS[1] = 4
        set DAMAGE_INTERVALS[2] = 5
        set DAMAGE_INTERVALS[3] = 6
        set DAMAGE_INTERVALS[4] = 7
       
        // The number of the time gap between each damage interval
        set DAMAGE_INTERVAL_TIME_GAP[1] = 4.
        set DAMAGE_INTERVAL_TIME_GAP[2] = 4.
        set DAMAGE_INTERVAL_TIME_GAP[3] = 4.
        set DAMAGE_INTERVAL_TIME_GAP[4] = 4.
       
        // The percentage of the triggering unit's lost life dealt in damage
        set DAMAGE_RATIO[1] = .10
        set DAMAGE_RATIO[2] = .10
        set DAMAGE_RATIO[3] = .10
        set DAMAGE_RATIO[4] = .10
       
        // The base damage dealt regardless of the triggering unit's life
        set BASE_DAMAGE[1] = 25.
        set BASE_DAMAGE[2] = 25.
        set BASE_DAMAGE[3] = 25.
        set BASE_DAMAGE[4] = 25.
       
    endfunction
   
    //! objectediting
   
        // Armor lost per damage interval (Ability Editor -- FO_Armor):
        //      Adjust "Level # - Data - Defense Bonus" to the required values.
        //      The level number stands for the number of the damage instance
        //      and the inserted value stands for then sum of the lost armor at that instance.
   
    //! endobjectediting
   
    ////////////////////////////////////
    //        ADJUSTABLES END         //
    ////////////////////////////////////
   
//===========================================================================

private struct FO

//= Struct Variables ========================================================

    unit tr     // Triggering unit
    player pt   // Owner of the triggering unit
    integer lvl // Level of the ability
   
    unit ta     // Target unit
    effect e    // Special effect
   
    real h      // Damage to be dealt
   
    real tco    // Timer counter
    integer ico // Interval Counter
   
    timer time  // Timer variable
   
    debug boolean bool

//= onDestroy ===============================================================

    private method destroy takes nothing returns nothing
        call PauseTimer(this.time)
        call FlushTimerUserData(this.time)
        call DestroyTimer(this.time)
       
        call UnitRemoveAbility(this.ta, ARMOR_ABILITY_ID)
       
        call DestroyEffect(this.e)
       
        set this.tr     = null
        set this.pt     = null
        set this.ta     = null
        set this.e      = null
        set this.time   = null
        set this.tco    = 0.
        set this.ico    = 0
       
        debug call BJDebugMsg("|cffc3dbffFoltern:|r Struct instance |cffff0000" + I2S(this) + "|r destroyed")
        debug call BJDebugMsg(" ")
        debug set this.bool = false
       
        call .deallocate()
    endmethod
   
//= Damaging =========================================================

    private static method Loop takes nothing returns nothing
   
    // --- Announcing struct instance and running time counter ---
        local FO d = FO(GetTimerUserData(GetExpiredTimer()))
        set d.tco = d.tco + TIMEOUT
       
    // --- Debug ---
        debug if d.bool == false then
        debug      call BJDebugMsg("|cffc3dbffFoltern:|r Target damage pending")
        debug      call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
        debug      call BJDebugMsg(" ")
        debug      set d.bool = true
        debug endif
   
        // --- Checking if it's time to damage ---
        if d.tco >= DAMAGE_INTERVAL_TIME_GAP[d.lvl] then
            set d.tco = 0.
            set d.ico = d.ico + 1
            set d.h = ((GetUnitState(d.tr, UNIT_STATE_MAX_LIFE) - GetUnitState(d.tr, UNIT_STATE_LIFE)) * DAMAGE_RATIO[d.lvl]) + BASE_DAMAGE[d.lvl]
           
        // --- Debug ---
            debug call BJDebugMsg("|cffc3dbffFoltern:|r Target damaged -- Damage instance: " + I2S(d.ico))
            debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
            debug call BJDebugMsg(" ")
           
        // --- Reducing armor ---
            if d.ico == 1 then
                call UnitAddAbility(d.ta, ARMOR_ABILITY_ID)
            endif
            call SetUnitAbilityLevel(d.ta, ARMOR_ABILITY_ID, d.ico)
           
        // --- Dealing damage ---
            call UnitDamageTarget(d.tr, d.ta, d.h, true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE_WHOKNOWS)
           
        // --- Special effect ---
            call DestroyEffect(AddSpecialEffectTarget(DAMAGE_SFX, d.ta, DAMAGE_SFX_ATTACHMENT_PT))
           
        // --- Texttag ---
            if TEXTAG_BOOLEAN then
                call TextTagUnitDT(d.ta, I2S(R2I(d.h))+"!", TEXTAG_FADE_TIME, TEXTAG_SIZE, TEXTAG_HEIGHT_OFFSET, TEXTAG_VELOCITY, TEXTAG_COLOR_RED, TEXTAG_COLOR_GREEN, TEXTAG_COLOR_BLUE, 255)
            endif
           
        // --- Checking if all intervals ran to terminate the instance ---
            if d.ico >= DAMAGE_INTERVALS[d.lvl] then
                call d.destroy()
            endif
        endif
       
        // --- Checking if target died to heal triggering unit and terminate the instance ---
        if IsUnitType(d.ta, UNIT_TYPE_DEAD) then
            debug call BJDebugMsg("|cffc3dbffFoltern:|r Target died")
            debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
            debug call BJDebugMsg(" ")
           
            call SetUnitState(d.tr, UNIT_STATE_LIFE, (GetUnitState(d.tr, UNIT_STATE_LIFE) + d.h))
            call DestroyEffect(AddSpecialEffectTarget(DEATH_SFX_1, d.tr, DEATH_SFX_1_ATTACHMENT_PT))
            call DestroyEffect(AddSpecialEffectTarget(DEATH_SFX_2, d.tr, DEATH_SFX_2_ATTACHMENT_PT))
            call d.destroy()
        endif
    endmethod

//= Initial Actions =========================================================

    private static method Create takes nothing returns nothing

    // --- Allocating new struct instance ---
        local FO d = FO.allocate()
       
    // --- Debug ---
        debug call BJDebugMsg("|cffc3dbffFoltern:|r Initiated")
        debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
        debug call BJDebugMsg(" ")
       
    // --- Setting some variables ---
        set d.tr = GetTriggerUnit()
        set d.pt = GetOwningPlayer(d.tr)
        set d.lvl = GetUnitAbilityLevel(d.tr, ABILITY_ID)
       
        set d.ta = GetSpellTargetUnit()
       
    // --- Special effects ---
        set d.e = AddSpecialEffectTarget(RUN_THROUGH_SFX, d.ta, RUN_THROUGH_SFX_ATTACHMENT_PT)
        call DestroyEffect(AddSpecialEffectTarget(INIT_SFX_1, d.ta, INIT_SFX_1_ATTACHMENT_PT))
        call DestroyEffect(AddSpecialEffectTarget(INIT_SFX_2, d.ta, INIT_SFX_2_ATTACHMENT_PT))
       
    // --- Creating and running timer to move missile ---
        set d.time = CreateTimer()
        call SetTimerUserData(d.time, integer(d))
        call TimerStart(d.time, TIMEOUT, true, function FO.Loop)
    endmethod

//= Condition and Initializer ===============================================

    private static method ConditionCheck takes nothing returns boolean
        return GetSpellAbilityId() == ABILITY_ID
    endmethod

    private static method onInit takes nothing returns nothing
        call SpellInitDT(EVENT_PLAYER_UNIT_SPELL_EFFECT, function FO.Create, function FO.ConditionCheck)
       
        call Setup()
       
        call PreloadSpecialEffectDT(RUN_THROUGH_SFX)
        call PreloadSpecialEffectDT(DAMAGE_SFX)
        call PreloadSpecialEffectDT(DEATH_SFX_1)
        call PreloadSpecialEffectDT(DEATH_SFX_2)
        call PreloadSpecialEffectDT(INIT_SFX_1)
        call PreloadSpecialEffectDT(INIT_SFX_2)
    endmethod
   
endstruct

endscope
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//***********************************************************************
//*                                                                     *
//*                                Hiatus                               *
//*                            By: Deuterium                            *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Spell Description:                                                  *
//*                                                                     *
//*     The caster uses black magic upon his enemy rendering his target *
//*     unable of regenerating life through any possible approach.      *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* How to adjust and customize:                                        *
//*                                                                     *
//*     Simply adjust the settings found between the two tags:          *
//*     ADJUSTABLES/ADJUSTABLES END                                     *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* How to import (requires LibraryDT):                                 *
//*                                                                     *
//*     1. Copy and paste the ability "Hiatus" Object Editor into your  *
//*        map.                                                         *
//*                                                                     *
//*     2. Copy and paste the buff "HI_Hiatus" in the Object Editor     *
//*        into your map.                                               *
//*                                                                     *
//*     3. Copy and paste the trigger "Hiatus" in the Trigger Editor    *
//*        into your map.                                               *
//*                                                                     *
//*     4. Adjust the ID's present among the adjustable globals.        *
//*                                                                     *
//***********************************************************************
//* Changelog:                                                          *
//*                                                                     *
//*     v1.00:                                                          *
//*         - Released                                                  *
//*                                                                     *
//*     v1.01:                                                          *
//*         - Reworked                                                  *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Credit is appreciated.                                              *
//*                                                                     *
//***********************************************************************



scope Hiatus

globals
    private real array BUFF_DURATION
endglobals

//===========================================================================
       
    ////////////////////////////////////
    //          ADJUSTABLES           //
    ////////////////////////////////////
     
    globals
   
        // --- IDs ---
        private constant integer    ABILITY_ID                      = 'A010'            // The ID of the Hiatus ability
        private constant integer    BUFF_ID                         = 'B003'            // The Id of the HI_Hiatus buff
       
        // --- Special effect settings ---
        private constant string     TARGET_BUFF_SFX                 = "Abilities\\Spells\\Undead\\Curse\\CurseTarget.mdl"       // The effect attached to the unit which has the buff
        private constant string     TARGET_BUFF_SFX_ATTACHMENT_PT   = "overhead"        // Special effect attachment point
       
        // --- Core settings ---
        private constant real       TIMEOUT                         = .03               // The time gap at which the main timer runs
       
    endglobals
   
    private function Setup takes nothing returns nothing
   
        // General Setup note:
        //      the array integer refers to the level of the intended ability
       
        // --- The duration of the buff on the enemy target ---
        set BUFF_DURATION[1] = 5.
        set BUFF_DURATION[2] = 7.
        set BUFF_DURATION[3] = 9.
        set BUFF_DURATION[4] = 11.
       
    endfunction
   
    ////////////////////////////////////
    //        ADJUSTABLES END         //
    ////////////////////////////////////
   
//===========================================================================
private struct HI

//= Struct Variables ========================================================

    player pt   // Owner of the triggering unit
    integer lvl // Level of the ability
   
    unit ta     // Target unit
    effect e    // Special effect
   
    real life   // Life variable
    real check  // Life checker
   
    real tco    // Time counter
   
    timer time  // Timer variable
   
    debug boolean bool
   
//= onDestroy ===============================================================

    private method destroy takes nothing returns nothing
        call PauseTimer(this.time)
        call FlushTimerUserData(this.time)
        call DestroyTimer(this.time)
       
        call DestroyEffect(this.e)
       
        set this.pt     = null
        set this.ta     = null
        set this.e      = null
        set this.time   = null
        set this.tco    = 0
       
        debug call BJDebugMsg("|cffc3dbffHiatus:|r Struct instance |cffff0000" + I2S(this) + "|r destroyed")
        debug call BJDebugMsg(" ")
        debug set this.bool = false
       
        call .deallocate()
    endmethod

//= Preventing Regen =================================================

    private static method Loop takes nothing returns nothing
   
    // --- Announcing struct instance and running timer counter ---
        local HI d = HI(GetTimerUserData(GetExpiredTimer()))
        set d.tco = d.tco + TIMEOUT
       
    // --- Debug ---
        debug if d.bool == false then
        debug      call BJDebugMsg("|cffc3dbffHiatus:|r Regen paused")
        debug      call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
        debug      call BJDebugMsg(" ")
        debug      set d.bool = true
        debug endif
   
    // --- Ending instance target is dead or duration is over ---
        if (d.tco >= BUFF_DURATION[d.lvl]) or IsUnitType(d.ta, UNIT_TYPE_DEAD) then
            debug if d.tco >= BUFF_DURATION[d.lvl] then
            debug      call BJDebugMsg("|cffc3dbffHiatus:|r Duration ended")
            debug elseif IsUnitType(d.ta, UNIT_TYPE_DEAD) then
            debug      call BJDebugMsg("|cffc3dbffHiatus:|r Target died")
            debug endif
            debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
            debug call BJDebugMsg(" ")
           
            call d.destroy()
        endif
       
    // --- Preventing Regeneration ---
        set d.check = GetUnitState(d.ta, UNIT_STATE_LIFE)
        if d.check > d.life then
            call SetUnitState(d.ta, UNIT_STATE_LIFE, d.life)
        elseif d.check < d.life then
            set d.life = d.check
        endif
    endmethod

//= Initial Actions =========================================================

    private static method Create takes nothing returns nothing
   
    // --- Allocating new struct instance ---
        local HI d = HI.allocate()
       
    // --- Debug ---
        debug call BJDebugMsg("|cffc3dbffHiatus:|r Initiated")
        debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
        debug call BJDebugMsg(" ")
       
    // --- Setting some variables ---
        set d.pt = GetOwningPlayer(GetTriggerUnit())
        set d.lvl = GetUnitAbilityLevel(GetTriggerUnit(), ABILITY_ID)
       
        set d.ta = GetSpellTargetUnit()
        set d.life = GetUnitState(d.ta, UNIT_STATE_LIFE)
       
    // --- Special effects ---
        set d.e = AddSpecialEffectTarget(TARGET_BUFF_SFX, d.ta, TARGET_BUFF_SFX_ATTACHMENT_PT)
       
    // --- Creating and running timer to prevent life regeneration ---
        set d.time = CreateTimer()
        call SetTimerUserData(d.time, integer(d))
        call TimerStart(d.time, TIMEOUT, true, function HI.Loop)
    endmethod

//= Condition and Initializer ===============================================

    private static method ConditionCheck takes nothing returns boolean
        return GetSpellAbilityId() == ABILITY_ID
    endmethod

    private static method onInit takes nothing returns nothing
        call SpellInitDT(EVENT_PLAYER_UNIT_SPELL_EFFECT, function HI.Create, function HI.ConditionCheck)
       
        call Setup()
       
        call PreloadSpecialEffectDT(TARGET_BUFF_SFX)
    endmethod
   
endstruct

endscope
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//***********************************************************************
//*                                                                     *
//*                              Impairment                             *
//*                            By: Deuterium                            *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Spell Description:                                                  *
//*                                                                     *
//*     The caster hurls an ancient orb of magic which deals certain    *
//*     damage to the target and fills up with a certaion percentage of *
//*     the target's maximum mana to carry it back to teh caster.       *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* How to adjust and customize:                                        *
//*                                                                     *
//*     Simply adjust the settings found between the two tags:          *
//*     ADJUSTABLES/ADJUSTABLES END                                     *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* How to import:                                                      *
//*                                                                     *
//*     1. Copy and paste the ability "Impairment" and in the Object    *
//*        Editor into your map.                                        *
//*                                                                     *
//*     2. Copy and paste the trigger "Impairment" in the Trigger       *
//*        Editor into your map.                                        *
//*                                                                     *
//*     3. Adjust the ID's present among the adjustable variables.      *
//*                                                                     *
//***********************************************************************
//* Changelog:                                                          *
//*                                                                     *
//*     v1.00:                                                          *
//*         - Released                                                  *
//*                                                                     *
//*     v1.01:                                                          *
//*         - Converted from GUI to vJass                               *
//*                                                                     *
//*     v1.02:                                                          *
//*         - Fixed a bug                                               *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Credit is appreciated.                                              *
//*                                                                     *
//***********************************************************************



scope Impairment

globals
    private real array MANA_STEAL_RATIO
    private real array DAMAGE
endglobals

//===========================================================================
       
    ////////////////////////////////////
    //          ADJUSTABLES           //
    ////////////////////////////////////
     
    globals
       
        // --- IDs ---
        private constant integer    ABILITY_ID                      = 'A007'                // The ID of the Impairment ability
       
        // --- Missile settings ---
        private constant string     MISSILE_MODEL                   = "Abilities\\Spells\\Undead\\AbsorbMana\\AbsorbManaBirthMissile.mdl"   // The model of the missile
        private constant real       MISSILE_SIZE                    = 2.                    // The size of the missile
        private constant real       MISSILE_HEIGHT                  = 50.                    // The height of the missile
        private constant real       MISSILE_SPEED                   = 15.                   // The speed of the missile
        private constant real       MISSILE_COLLISION_RANGE         = 20.                   // The collision size of the missile
        private constant real       MISSILE_OFFSET                  = 50.                   // The missile's offset from the caster at creation

        private constant string     MISSILE_COLLISION_SFX           = "Abilities\\Spells\\Undead\\AbsorbMana\\AbsorbManaBirthMissile.mdl"   // The special effect attached at the target at collision
        private constant string     MISSILE_COLLISION_SFX_ATTACH    = "origin"              // Attachment point
       
        // --- Damage and attack types
        private constant attacktype ATTACK_TYPE                     = ATTACK_TYPE_NORMAL    // Attack type of the damage dealt
        private constant damagetype DAMAGE_TYPE                     = DAMAGE_TYPE_MAGIC     // Damage type of the damage dealt
       
        // --- Core settings ---
        private constant real       TIMEOUT                         = .03                   // The time gap at which the main timer runs
       
    endglobals
   
    private function Setup takes nothing returns nothing
   
        // General Setup note:
        //      the array integer refers to the level of the intended ability
       
        // --- Mana setting ---
       
        // The percentage of the mana stolen from the target (ex: 10.00 as in 10.00%)
        set MANA_STEAL_RATIO[1] = 10.
        set MANA_STEAL_RATIO[2] = 12.
        set MANA_STEAL_RATIO[3] = 14.
        set MANA_STEAL_RATIO[4] = 16.
       
       
        // --- Damage setting ---
       
        // The damage dealt to the target at missile collision
        set DAMAGE[1] = 80.
        set DAMAGE[2] = 100.
        set DAMAGE[3] = 120.
        set DAMAGE[4] = 140.
       
    endfunction

    ////////////////////////////////////
    //        ADJUSTABLES END         //
    ////////////////////////////////////
   
//===========================================================================

private struct IM

//= Struct Variables ========================================================

    unit tr     // Triggering unit
    integer lvl // Ability level
   
    unit ta     // Target unit
   
    unit m      // Missile Dummy
   
    timer time  // Timer
   
    real mana
    real manaratio
   
    debug boolean bool

//= onDestroy ===============================================================

    private method onDestroy takes nothing returns nothing
        call PauseTimer(this.time)
        call FlushTimerUserData(this.time)
        call DestroyTimer(this.time)
       
        call DestroyMissileDT(this.m)
       
        set this.tr     = null
        set this.ta     = null
        set this.m      = null
        set this.time   = null
       
        debug call BJDebugMsg("|cffc3dbffImpairment:|r Struct instance |cffff0000" + I2S(this) + "|r destroyed")
        debug call BJDebugMsg(" ")
        debug set this.bool = false
    endmethod

//= Moving Missile Towards Caster ===========================================

    private static method BackwardLoop takes nothing returns nothing
   
        // --- Announcing struct instance ---
        local IM d = IM(GetTimerUserData(GetExpiredTimer()))
       
        // --- Debug ---
        debug if d.bool == false then
        debug      call BJDebugMsg("|cffc3dbffImpairment:|r Missile moving towards caster")
        debug      call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
        debug      call BJDebugMsg(" ")
        debug      set d.bool = true
        debug endif

        // --- Moving Missile ---
        call MoveMissileTargetDT(d.m, d.tr, MISSILE_SPEED)
       
        // --- Checking for collision ---
        if GetDistanceBetweenUnitsDT(d.m, d.tr) <= MISSILE_COLLISION_RANGE then
            debug call BJDebugMsg("|cffc3dbffImpairment:|r Missile collided with the caster")
            debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
            debug call BJDebugMsg(" ")
       
            call SetUnitState(d.tr, UNIT_STATE_MANA, GetUnitState(d.tr, UNIT_STATE_MANA) + d.manaratio)
            call d.destroy()
        endif
    endmethod

//= Moving Missile Towards Target ===========================================

    private static method ForwardLoop takes nothing returns nothing
   
        // --- Announcing struct instance ---
        local IM d = IM(GetTimerUserData(GetExpiredTimer()))
       
        // --- Debug ---
        debug if d.bool == false then
        debug      call BJDebugMsg("|cffc3dbffImpairment:|r Missile moving towards target")
        debug      call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
        debug      call BJDebugMsg(" ")
        debug      set d.bool = true
        debug endif
   
        // --- Moving Missile ---
        call MoveMissileTargetDT(d.m, d.ta, MISSILE_SPEED)
       
        // --- Checking for collision ---
        if GetDistanceBetweenUnitsDT(d.m, d.ta) <= MISSILE_COLLISION_RANGE then
       
        // --- Debug ---
        debug call BJDebugMsg("|cffc3dbffImpairment:|r Missile collided with the target")
        debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
        debug call BJDebugMsg(" ")
        debug set d.bool = false
       
        // --- Damaging target ---
            call UnitDamageTarget(d.m, d.ta, DAMAGE[d.lvl], true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE_WHOKNOWS)
       
        // --- Reducing mana ---
            set d.mana = GetUnitState(d.ta, UNIT_STATE_MANA)
            set d.manaratio = d.mana * MANA_STEAL_RATIO[d.lvl]/100.
            if d.mana >= d.manaratio then
                call SetUnitState(d.ta, UNIT_STATE_MANA, d.mana - d.manaratio)
            else
                call SetUnitState(d.ta, UNIT_STATE_MANA, 0.)
                set d.manaratio = d.mana
            endif
           
        // --- Special effect ---
            call DestroyEffect(AddSpecialEffectTarget(MISSILE_COLLISION_SFX, d.ta, MISSILE_COLLISION_SFX_ATTACH))
       
        // --- Setting timer to move the missile back towards the triggering unit ---
            call PauseTimer(d.time)
            call TimerStart(d.time, TIMEOUT, true, function IM.BackwardLoop)
        endif
    endmethod

//= Initial Actions =========================================================

    private static method Create takes nothing returns nothing
   
        // --- Allocation new struct instance ---
        local IM d = IM.allocate()
       
        // --- Debug ---
        debug call BJDebugMsg("|cffc3dbffImpairment:|r Initiated")
        debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
        debug call BJDebugMsg(" ")
       
        // --- Setting some variables
        set d.tr = GetTriggerUnit()
        set d.lvl = GetUnitAbilityLevel(d.tr, ABILITY_ID)
       
        set d.ta = GetSpellTargetUnit()
       
        // --- Creating missile ---
        set d.m = CreateFiredMissileDT(d.tr, MISSILE_OFFSET, MISSILE_MODEL, "origin", MISSILE_HEIGHT, MISSILE_SIZE)
       
        // --- Starting timer to move missile towards target ---
        set d.time = CreateTimer()
        call SetTimerUserData(d.time, integer(d))
        call TimerStart(d.time, TIMEOUT, true, function IM.ForwardLoop)
    endmethod

//= Condition and Initializer ===============================================

    private static method ConditionCheck takes nothing returns boolean
        return GetSpellAbilityId() == ABILITY_ID
    endmethod

    private static method onInit takes nothing returns nothing
        call SpellInitDT(EVENT_PLAYER_UNIT_SPELL_EFFECT, function IM.Create, function IM.ConditionCheck)
        call Setup()
       
        call PreloadSpecialEffectDT(MISSILE_MODEL)
    endmethod
   
endstruct

endscope
//TESH.scrollpos=132
//TESH.alwaysfold=0
//***********************************************************************
//*                                                                     *
//*                            Stunning Ward                            *
//*                            By: Deuterium                            *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Spell Description:                                                  *
//*                                                                     *
//*     The caster creates a temporal ward which mini-stuns enemy units *
//*     at a certain range.                                             *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* How to adjust and customize:                                        *
//*                                                                     *
//*     Simply adjust the settings found between the two tags:          *
//*     ADJUSTABLES/ADJUSTABLES END                                     *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* How to import:                                                      *
//*                                                                     *
//*     1. Copy and paste the abilities "Stunning Ward" and             *
//*        "SW_MiniStun" in the Object Editor into your map.            *
//*                                                                     *
//*     2. Copy and paste the unit "SW_Ward" in the Object Editor into  *
//*        your map.                                                    *
//*                                                                     *
//*     3. Copy and paste the trigger "Stunning Ward" and in the        *
//*        Trigger Editor into your map.                                *
//*                                                                     *
//*     4. Adjust the ID's present among the adjustable variables.      *
//*                                                                     *
//***********************************************************************
//* Changelog:                                                          *
//*                                                                     *
//*     v1.00:                                                          *
//*         - Released                                                  *
//*                                                                     *
//*     v1.01:                                                          *
//*         - Converted from GUI to vJass                               *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Credit is appreciated.                                              *
//*                                                                     *
//***********************************************************************



scope StunningWard

globals
    private real array STUN_INTERVAL_TIME
    private real array STUN_INTERVALS
    private real array STUN_RADIUS
endglobals

//===========================================================================
       
    ////////////////////////////////////
    //          ADJUSTABLES           //
    ////////////////////////////////////
     
    globals
       
        // --- IDs ---
        private constant integer    ABILITY_ID                      = 'A005'            // The ID of the Balminess ability
        private constant integer    STUN_ABILITY_ID                 = 'A006'            // The ID of the SW_MiniStun ability
        private constant integer    WARD_ID                         = 'h001'            // The ID of the SW_Ward unit
   
        // --- Spell setting ---
        private constant boolean    WARD_INVULNERABLE               = false              // If set to true, ward is invulnerable
                                                                                        // If set to false, ward isn't invulnerable
       
    endglobals
   
    private function Setup takes nothing returns nothing
   
        // General Setup note:
        //      the array integer refers to the level of the intended ability
       
       
        // --- Stun settings ---
       
        // The time gap between each stun instance
        set STUN_INTERVAL_TIME[1] = 1.
        set STUN_INTERVAL_TIME[2] = 1.
        set STUN_INTERVAL_TIME[3] = 1.
        set STUN_INTERVAL_TIME[4] = 1.
       
        // The number of stun intervals plus the initial stun
        set STUN_INTERVALS[1] = 6
        set STUN_INTERVALS[2] = 8
        set STUN_INTERVALS[3] = 10
        set STUN_INTERVALS[4] = 12
       
        // The radius around the ward at which stunning takes effect
        set STUN_RADIUS[1] = 400.
        set STUN_RADIUS[2] = 400.
        set STUN_RADIUS[3] = 400.
        set STUN_RADIUS[4] = 400.
       
    endfunction

    //! objectediting
   
        // Stun duration (Ability Editor -- SW_MiniStun):
        //      Adjust "Level # - Stats - Duration" to the required values.
   
           
        // AoE targetting image size (Ability Editor -- Stunning Ward):
        //      Adjust "Level # - Area of Effect" to the required values.
   
    //! endobjectediting    
   
    ////////////////////////////////////
    //        ADJUSTABLES END         //
    ////////////////////////////////////
   
//===========================================================================

private struct SW

//= Struct Variables ========================================================

    unit tr     // Triggering unit
    player pt   // Triggering player
    integer lvl // Ability level
   
    unit w      // Ward
    real x      // Ward's X
    real y      // Ward's Y
   
    group g     // Group
   
    integer ico  // Interval counter
   
    timer time  // Timer
   
    static SW Temp

//= onDestroy ===============================================================

    private method destroy takes nothing returns nothing
        call PauseTimer(this.time)
        call FlushTimerUserData(this.time)
        call DestroyTimer(this.time)
       
        call DestroyGroup(this.g)
       
        set this.tr     = null
        set this.pt     = null
        set this.w      = null
        set this.g      = null
        set this.time   = null
        set this.ico     = 0
       
        debug call BJDebugMsg("|cffc3dbffStunning Ward:|r Struct instance |cffff0000" + I2S(this) + "|r destroyed")
        debug call BJDebugMsg(" ")
       
        call .deallocate()
    endmethod
   
//= Stun ==================================================================    

    private static method FilterOut takes nothing returns boolean
        set bj_lastCreatedUnit = GetFilterUnit()
        return (IsUnitEnemy(bj_lastCreatedUnit, SW.Temp.pt) == true) and (IsUnitType(bj_lastCreatedUnit, UNIT_TYPE_STRUCTURE) == false) and (IsUnitType(bj_lastCreatedUnit, UNIT_TYPE_MECHANICAL) == false) and (IsUnitType(bj_lastCreatedUnit, UNIT_TYPE_MAGIC_IMMUNE) == false) and (IsUnitType(bj_lastCreatedUnit, UNIT_TYPE_DEAD) == false)
    endmethod
   
    private static method GroupLoop takes nothing returns nothing
        call DummyCastTargetDT(SW.Temp.pt, GetEnumUnit(), STUN_ABILITY_ID, "thunderbolt", SW.Temp.lvl)
    endmethod

    private static method RunStun takes integer i returns nothing
        local SW d = i
        call GroupEnumUnitsInRange(d.g, d.x, d.y, STUN_RADIUS[d.lvl], Condition(function SW.FilterOut))
        call ForGroup(d.g, function SW.GroupLoop)
        call GroupClear(d.g)
        call DestroyCondition(Condition(function SW.FilterOut))
    endmethod

//= Timed Actions =========================================================

    private static method Loop takes nothing returns nothing
   
        // --- Announcing instance and running timer counter ---
        local SW d = SW(GetTimerUserData(GetExpiredTimer()))
        set SW.Temp = integer(d)
        set d.ico = d.ico + 1
       
        // --- Debug ---
        debug call BJDebugMsg("|cffc3dbffStunning Ward:|r Stunned -- Stun instance: " + I2S(d.ico))
        debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
        debug call BJDebugMsg(" ")
       
        // --- Checking if ward is dead ---
        if IsUnitType(d.w, UNIT_TYPE_DEAD) then
            debug call BJDebugMsg("|cffc3dbffStunning Ward:|r Ward died")
            debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
            debug call BJDebugMsg(" ")
           
            call d.destroy()
            return
        endif
       
        // --- Stunning ---
        call SW.RunStun(d)
       
        // --- Checking if all intervals ran ---
        if d.ico >= STUN_INTERVALS[d.lvl] then
            debug call BJDebugMsg("|cffc3dbffStunning Ward:|r All intervals ran")
            debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
            debug call BJDebugMsg(" ")
       
            call d.destroy()
        endif
    endmethod

//= Initial Actions =========================================================

    private static method Create takes nothing returns nothing
   
        // --- Allocating new instance ---
        local SW d = SW.allocate()
        set SW.Temp = integer(d)
       
        // --- Debug ---
        debug call BJDebugMsg("|cffc3dbffStunning Ward:|r Initiated")
        debug call BJDebugMsg("|cffffcc00Struct instance:|r |cffff0000" + I2S(d) + "|r")
        debug call BJDebugMsg(" ")
       
        // --- Setting some variables ---
        set d.tr = GetTriggerUnit()
        set d.pt = GetOwningPlayer(d.tr)
        set d.lvl = GetUnitAbilityLevel(d.tr, ABILITY_ID)
       
        // --- Creating ward ---
        set d.w = CreateUnit(d.pt, WARD_ID, GetSpellTargetX(), GetSpellTargetY(), bj_UNIT_FACING)
       
        set d.x = GetUnitX(d.w)
        set d.y = GetUnitY(d.w)
       
        call UnitApplyTimedLife(d.w, 'BTLF', STUN_INTERVALS[d.lvl] * STUN_INTERVAL_TIME[d.lvl])
        if WARD_INVULNERABLE then
            call SetUnitInvulnerable(d.w, true)
        endif
       
        // --- Running stun ---
        set d.g = CreateGroup()
        call SW.RunStun(d)
       
        // --- Running timer ---
        set d.time = CreateTimer()
        call SetTimerUserData(d.time, integer(d))
        call TimerStart(d.time, STUN_INTERVAL_TIME[d.lvl], true, function SW.Loop)
    endmethod

//= Condition and Initializer ===============================================

    private static method ConditionCheck takes nothing returns boolean
        return GetSpellAbilityId() == ABILITY_ID
    endmethod

    private static method onInit takes nothing returns nothing
        call SpellInitDT(EVENT_PLAYER_UNIT_SPELL_EFFECT, function SW.Create, function SW.ConditionCheck)
        call Setup()
       
        call PreloadUnitDT(WARD_ID)
    endmethod
   
endstruct

endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
//***********************************************************************
//*                                                                     *
//*                           Sweltering Blaze                          *
//*                            By: Deuterium                            *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Spell Description:                                                  *
//*                                                                     *
//*     The caster emits a blazing flash out of his inner core, leaving *
//*     those who face him blinded and damaged.                         *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* How to adjust and customize:                                        *
//*                                                                     *
//*     Simply adjust the settings found between the two tags:          *
//*     ADJUSTABLES/ADJUSTABLES END                                     *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* How to import (requires LibraryDT):                                 *
//*                                                                     *
//*     1. Copy and paste the abilities "Sweltering Blaze" and          *
//*        "SB_Blind" in the Object Editor into your map.               *
//*                                                                     *
//*     2. Copy and paste the buff "SB_Blind" in the Object Editor into *
//*        your map.                                                    *
//*                                                                     *
//*     3. Copy and paste the trigger "Sweltering Blaze" in the Trigger *
//*        Editor into your map.                                        *
//*                                                                     *
//*     4. Adjust the ID's present among the adjustable globals.        *
//*                                                                     *
//***********************************************************************
//* Changelog:                                                          *
//*                                                                     *
//*     v1.00:                                                          *
//*         - Released                                                  *
//*                                                                     *
//*     v1.01:                                                          *
//*         - Minor edits                                               *
//*                                                                     *
//***********************************************************************
//*                                                                     *
//* Credit is appreciated.                                              *
//*                                                                     *
//***********************************************************************



scope SwelteringBlaze initializer Init

globals
    private real array DAMAGE
endglobals

//===========================================================================
       
    ////////////////////////////////////
    //          ADJUSTABLES           //
    ////////////////////////////////////
     
    globals

        // --- IDs ---
        private constant integer    ABILITY_ID                      = 'A002'            // The ID of the Balminess ability
        private constant integer    BLIND_ABILITY_ID                = 'A003'            //The ID of the SB_Blind ability
       
        // --- Spell settings ---
        private constant real       SIGHT_RANGE                     = 60.               //The sight angle of the target in degrees
        private constant real       RADIUS                          = 500.              //The area of effect
       
        private constant attacktype ATTACK_TYPE                     = ATTACK_TYPE_CHAOS // The attack type of the damage dealt
        private constant damagetype DAMAGE_TYPE                     = DAMAGE_TYPE_FIRE  // The damage type of the damage dealt
       
        // --- Special effects ---
        private constant string     CASTER_SFX                      = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl"       //The effect created on the caster
        private constant string     CASTER_SFX_ATTACHMENT_PT        = "chest"           // Attachment point
       
        private constant string     TARGET_SFX                      = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl"  //The effect created on the target
        private constant string     TARGET_SFX_ATTACHMENT_PT        = "head"           // Attachment point

    endglobals
   
    private function Setup takes nothing returns nothing
   
        // General Setup note:
        //      the array integer refers to the level of the intended ability
       
       
        // --- Damage setting ---
       
        // The damage dealt to each unit who matches the conditions
        set DAMAGE[1] = 35.
        set DAMAGE[2] = 50.
        set DAMAGE[3] = 65.
        set DAMAGE[4] = 80.
       
    endfunction

    //! objectediting
   
        // Chance to miss (Ability Editor -- SB_Blind):
        //      Adjust "Level # - Data - Chance to Miss" to the required values.
   
        // Blind duration (Ability Editor -- SB_Blind):
        //      Adjust "Level # - Stats - Duration" to the required values.
   
    //! endobjectediting

    ////////////////////////////////////
    //        ADJUSTABLES END         //
    ////////////////////////////////////
   
//= Global variables ========================================================

globals
        private unit t      // Triggering unit
        private player p    // Owner of triggering unit
        private integer i   // Ability level
       
        private unit u      // Filter & enum units
       
        private real x
        private real y
        private real a
        private real f
       
        private constant group g = CreateGroup()
endglobals
   
//= Group functions =========================================================

private function FilterOut takes nothing returns boolean
    set u = GetFilterUnit()
    set f = GetUnitFacing(u)
    set a = bj_RADTODEG * Atan2((y) - GetUnitY(u), x - GetUnitX(u))
    return (((f <= (a + SIGHT_RANGE)) and (f >= (a - SIGHT_RANGE))) or ((f <= (a + 360. + SIGHT_RANGE)) and (f >= (a + 360. - SIGHT_RANGE)))) and  (IsUnitType(u, UNIT_TYPE_STRUCTURE) == false) and (IsUnitType(u, UNIT_TYPE_MECHANICAL) == false) and (IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) == false) and (IsUnitEnemy(u, p) == true) and (IsUnitType(u, UNIT_TYPE_DEAD) == false)
endfunction

private function GroupActions takes nothing returns nothing
    // --- Damaging & Blinding ---
    set u = GetEnumUnit()
    call DummyCastTargetDT(p, u, BLIND_ABILITY_ID, "curse", i)
    call UnitDamageTarget(bj_lastCreatedUnit, u, DAMAGE[i], true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE_WHOKNOWS)

    // --- Targets' special effect ---
    call DestroyEffect(AddSpecialEffectTarget(TARGET_SFX, u, TARGET_SFX_ATTACHMENT_PT))
endfunction

//= Actions =================================================================

private function Action takes nothing returns nothing
       
    // --- Debug ---
    debug call BJDebugMsg("|cffc3dbffSweltering Blaze:|r Spell effect occured")
    debug call BJDebugMsg("|cffffcc00Instance is instant|r")
    debug call BJDebugMsg(" ")
       
    // --- Setting some variables ---
    set t = GetTriggerUnit()
    set x = GetUnitX(t)
    set y = GetUnitY(t)
    set p = GetOwningPlayer(t)
    set i = GetUnitAbilityLevel(t, ABILITY_ID)
   
    // --- Picking group ---
    call GroupEnumUnitsInRange(g, x, y, RADIUS, Condition(function FilterOut))
    call ForGroup(g, function GroupActions)
    call DestroyCondition(Condition(function FilterOut))
    call GroupClear(g)
   
    // --- Caster's special effect ---
    call DestroyEffect(AddSpecialEffectTarget(CASTER_SFX, t, CASTER_SFX_ATTACHMENT_PT))
   
    // --- Slight cleaning ---
    set t = null
    set u = null
    set p = null
endfunction

//= Condition and Initializer ===============================================

private function ConditionCheck takes nothing returns boolean
    return GetSpellAbilityId() == ABILITY_ID
endfunction

private function Init takes nothing returns nothing
    call SpellInitDT(EVENT_PLAYER_UNIT_SPELL_EFFECT, function Action, function ConditionCheck)
    call Setup()
   
    call PreloadSpecialEffectDT(CASTER_SFX)
    call PreloadSpecialEffectDT(TARGET_SFX)
endfunction

endscope
Spawn
  Events
    Time - Every 25.00 seconds of game time
  Conditions
  Actions
    For each (Integer A) from 1 to 4, do (Actions)
      Loop - Actions
        Unit - Create 1.Footman for Player 1 (Red) at (Center of Region_000 <gen>) facing Default building facing degrees
        Unit - Order (Last created unit) to Attack-Move To.(Center of Region_001 <gen>)
        Unit - Create 1.Footman for Player 7 (Green) at (Center of Region_002 <gen>) facing Default building facing degrees
        Unit - Order (Last created unit) to Attack-Move To.(Center of Region_001 <gen>)
    Unit - Create 1.Druid of the Talon (Night Elf Form) for Player 1 (Red) at (Center of Region_000 <gen>) facing Default building facing degrees
    Unit - Order (Last created unit) to Attack-Move To.(Center of Region_001 <gen>)
    Unit - Create 1.Druid of the Talon (Night Elf Form) for Player 7 (Green) at (Center of Region_002 <gen>) facing Default building facing degrees
    Unit - Order (Last created unit) to Attack-Move To.(Center of Region_001 <gen>)
Stop Spawn
  Events
    Player - Player 1 (Red) types a chat message containing -stopspawn (stringnoformat) as An exact match
  Conditions
  Actions
    Trigger - Turn off Spawn <gen>
Start Spaw
  Events
    Player - Player 1 (Red) types a chat message containing -startspawn (stringnoformat) as An exact match
  Conditions
  Actions
    Trigger - Turn on Spawn <gen>
    For each (Integer A) from 1 to 4, do (Actions)
      Loop - Actions
        Unit - Create 1.Footman for Player 1 (Red) at (Center of Region_000 <gen>) facing Default building facing degrees
        Unit - Order (Last created unit) to Attack-Move To.(Center of Region_001 <gen>)
        Unit - Create 1.Footman for Player 7 (Green) at (Center of Region_002 <gen>) facing Default building facing degrees
        Unit - Order (Last created unit) to Attack-Move To.(Center of Region_001 <gen>)
    Unit - Create 1.Druid of the Talon (Night Elf Form) for Player 1 (Red) at (Center of Region_000 <gen>) facing Default building facing degrees
    Unit - Order (Last created unit) to Attack-Move To.(Center of Region_001 <gen>)
    Unit - Create 1.Druid of the Talon (Night Elf Form) for Player 7 (Green) at (Center of Region_002 <gen>) facing Default building facing degrees
    Unit - Order (Last created unit) to Attack-Move To.(Center of Region_001 <gen>)
Spawn Type
  Events
    Player - Player 1 (Red) types a chat message containing -spawn (stringnoformat) as An exact match
  Conditions
  Actions
    For each (Integer A) from 1 to 4, do (Actions)
      Loop - Actions
        Unit - Create 1.Footman for Player 1 (Red) at (Center of Region_000 <gen>) facing Default building facing degrees
        Unit - Order (Last created unit) to Attack-Move To.(Center of Region_001 <gen>)
        Unit - Create 1.Footman for Player 7 (Green) at (Center of Region_002 <gen>) facing Default building facing degrees
        Unit - Order (Last created unit) to Attack-Move To.(Center of Region_001 <gen>)
    Unit - Create 1.Druid of the Talon (Night Elf Form) for Player 1 (Red) at (Center of Region_000 <gen>) facing Default building facing degrees
    Unit - Order (Last created unit) to Attack-Move To.(Center of Region_001 <gen>)
    Unit - Create 1.Druid of the Talon (Night Elf Form) for Player 7 (Green) at (Center of Region_002 <gen>) facing Default building facing degrees
    Unit - Order (Last created unit) to Attack-Move To.(Center of Region_001 <gen>)
Spawn move up
  Events
    Unit - A unit enters Region_003 <gen>
  Conditions
    ((Unit-type of (Triggering unit)) Equal to Footman) or ((Unit-type of (Triggering unit)) Equal to Druid of the Talon (Night Elf Form))
  Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Owner of (Triggering unit)) Equal to Player 1 (Red)
      Then - Actions
        Unit - Order (Triggering unit) to Attack-Move To.(Center of Region_002 <gen>)
      Else - Actions
        Unit - Order (Triggering unit) to Attack-Move To.(Center of Region_000 <gen>)
Restore
  Events
    Player - Player 1 (Red) skips a cinematic sequence
  Conditions
  Actions
    Unit Group - Pick every unit in (Units in (Playable map area) owned by Player 1 (Red)) and do (Actions)
      Loop - Actions
        Unit - Set mana of (Picked unit) to 100%
        Unit - Set life of (Picked unit) to 100%
        Unit - Reset ability cooldowns for (Picked unit).
Kill
  Events
    Player - Player 1 (Red) types a chat message containing -kill (stringnoformat) as An exact match
  Conditions
  Actions
    Unit Group - Pick every unit in (Units in (Playable map area) matching (((Matching unit) is A Hero) Equal to False)) and do (Actions)
      Loop - Actions
        Unit - Remove (Picked unit) from the game
        Special Effect - Create a special effect at (Position of (Picked unit)) using Abilities\Spells\Orc\MirrorImage\MirrorImageDeathCaster.mdl
A simple hero respawn system
Revive
  Events
    Unit - A unit Dies
  Conditions
    ((Owner of (Dying unit)) Equal to Player 1 (Red)) and (((Dying unit) is A Hero) Equal to True)
  Actions
    Wait 5.00 game-time seconds
    Game - Display to (All players) the text: Hero has respawned.
    Hero - Instantly revive (Dying unit) at (Player 1 (Red) start location), Show revival graphics
    Special Effect - Create a special effect at (Player 1 (Red) start location) using Abilities\Spells\Human\Resurrect\ResurrectCaster.mdl
    Special Effect - Destroy (Last created special effect)
Remove Unit Up
  Events
    Unit - A unit enters Region_004 <gen>
  Conditions
    (Owner of (Triggering unit)) Equal to Player 1 (Red)
  Actions
    Unit - Remove (Triggering unit) from the game
    Special Effect - Create a special effect at (Position of (Triggering unit)) using Abilities\Spells\Orc\MirrorImage\MirrorImageDeathCaster.mdl
Remove Unit Down
  Events
    Unit - A unit enters Region_005 <gen>
  Conditions
    (Owner of (Triggering unit)) Equal to Player 7 (Green)
  Actions
    Unit - Remove (Triggering unit) from the game
    Special Effect - Create a special effect at (Position of (Triggering unit)) using Abilities\Spells\Orc\MirrorImage\MirrorImageDeathCaster.mdl
Map Intialization
  Events
    Map initialization
  Conditions
  Actions
    Visibility - Disable fog of war
    Visibility - Disable black mask
    Game - Display to (All players) for 10.00 seconds the text: |cffffcc00-----------------------------------------------------------------------------------------------------Metaversal Spell Pack v1.03By Deuterium-----------------------------------------------------------------------------------------------------|rTo reset cooldowns and regen mana and life, press ESC.
Text 2
  Events
    Time - Elapsed game time is 0.01 seconds
  Conditions
  Actions
    Game - Display to (All players) for 10.00 seconds the text: To kill all spawned units, type: -killTo stop spawning units, type: -stopspawnTo restart spawning units, type: -startspawnTo spawn once, type: -spawnFeel free to ask questions, report any bugs, or give advice.