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

Metaversal Spell Pack v1.03 [Deuterium]

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.

Deuterium's Metaversal Spellpack


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.
v1.00
- Released

v1.01
- Reworked

Dark_Dragon
- Fixing a few mistakes

- LibraryDT (Deuterium)
- ArmorUtils (Rising_Dusk)

JASS:
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
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.
v1.00
- Released

v1.01
- Reworked

- LibraryDT (Deuterium)

Dark_Dragon
- Improving the onDestroy method

-BerZeKeR-
- The idea of decreasing the target's armor
- The advice on special effects

JASS:
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
Spell Description
The caster uses black magic upon his enemy rendering his target unable of regenerating life through any possible approach.
v1.00
- Released

v1.01
- Reworked

- LibraryDT (Deuterium)

JASS:
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
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.
v1.00
- Released

v1.01
- Converted from GUI to vJass

v1.02
- Fixed a bug

- LibraryDT (Deuterium)

JASS:
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
Spell Description
The caster creates a temporal ward which mini-stuns enemy units at a certain range.
v1.00
- Released

v1.01
- Converted from GUI to vJass

- LibraryDT (Deuterium)

JASS:
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
Spell Description
The caster emits a blazing flash out of his inner core, leaving those who face him blinded and damaged.
v1.00
- Released

v1.01
- Minor edits

- LibraryDT (Deuterium)

JASS:
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
v1.00
- Released

v1.01
- Full re-do of the library

v1.02
- Improved the library

JASS:
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
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

v1.03 (August 31, 2011)
- Improved LibraryDT


The vJass spells require Jass New Gen Pack.

Feel free to ask questions, report problems, or/and give advice.
Credit is appreciated.
Contents

Metaversal Spell Pack v1.03 (Map)

Reviews
12th Dec 2015 IcemanBo: Too long as NeedsFix. Rejected. 12 Nov 2011 Bribe: This needs a number of updates and revisions. "SpellInitDT" should just be replaced with RegisterPlayerUnitEvent by Magtheridon96. Missiles should use...
Level 22
Joined
Nov 14, 2008
Messages
3,256
Alright here we go :)

Review

Impaiment

First of all you should check your documentation! :mad: it made me mad that a such good documentator did a big mistake ^^

check the how to adjust and customize able box

also you have two spell mistakes in your description but it's not much to complain about :) " fills up with a certaion" "carry it back to teh caster."

also I think the description about the spell is a little bit confusing, my points

*fills up should in my opinion should be change to steal and also skip the carrying back the orb to the caster stuff
* cause if the orb fills up with mana to return back, it should be used as fuel and shouldnt be given to the caster right? ^^

Proof
//***********************************************************************
//* *
//* 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: *
//* *
//* 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 the caster. *
//* *
//***********************************************************************
alright else impaiment docu trigger seems fine, moving on to casting trigger

dislikes using facings, use angle between points between casting and target current point :)

im a bit confused about the expload missile variable, cause if you set the speed to a high value like 50 and the expload value to 1 it can in some cases expload behind the target or maybe I'm just talking ;)

else it's very good, proper documentation, not in my level but very good as always :)

loop trigger

resize the sfx part, it's to small and not so noticeable if you dont look for it

else I couldnt find any flaws that could improve it to the better ;)

next spell comming up
stunning ward

in the documentation, you should mention that the stun lenght can be changed in the dummy spell in object editor! very heavy point! ^^

also, change the casting spell so you can actually see the aoe instead of just a point targeter :)

main trigger

expire variable doesnt need to be indexed cause only use it 1 time and it's in the casting trigger which is instant

if you make as I tipped you with see the aoe you should mention about that when you set the aoe variable ;)

else very good

loop trigger

I dont see anything that I should complain about, perfect!

summary


yes I didnt check the vJass spells, dont got time nor I want to check code to lazy but as you see I kind of scanned those two thought I might missed something but you've seen my cons now

fix some of them :p

as usual I can say that seed is the second best documentater after the documentation master, me :)

not bad spells at all but we all have our own tastes and yes as you said the stun ward is a bit simple but yeap, simple spells can be good to, just look at berzerks simple pack!!! thought YES I SAID THOUGHT ^^ those are instant but they are at a high level of triggering :)

my last stand spell was also very simple too :D

regards

an old friend

~baassee
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
Wow very detailed review! :)

baassee said:
im a bit confused about the expload missile variable, cause if you set the speed to a high value like 50 and the expload value to 1 it can in some cases expload behind the target or maybe I'm just talking ;)
Yes right, but I mean, doing that would make no sense :p
Maybe I should include that in the documentation...

And actually there's alot more to be added into documentation, but it takes alot of time! :p

baassee said:
in the documentation, you should mention that the stun lenght can be changed in the dummy spell in object editor! very heavy point! ^^
I sort of mentioned something about the object editor dummy spells in the general documentation.

Thanks! And I'll be going through the triggers when I'm to update it... but I'm too lazy nowadays to do anything related to coding... so it'll take some time.

THANKS!
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
1. Wow very detailed review! :)

2. Yes right, but I mean, doing that would make no sense :p
Maybe I should include that in the documentation...

3. And actually there's alot more to be added into documentation, but it takes alot of time! :p

4. I sort of mentioned something about the object editor dummy spells in the general documentation.

1. "friends only" ;)

2. making no sense is a part of my life style, finding them is another part :)

3. yeap I know but lifes a bitch sometimes ^^

4. crap, seems that I didnt read it all
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
Updated!
Version 1.01


Basically, there is nothing new spell-wise. All fixes were coding related.

I converted all GUI's to vJass... and did minor fixes on spells.
I also reworked most vJass spells.

Now spells are way more configurable and adjustable.


I saved the map on debug mode for testing purposes, but once saved by the user under normal mode, all the text that appears on the screen wouldn't show up anymore.

All feedback is welcome!

Enjoy!
 
Level 15
Joined
Jan 31, 2007
Messages
502
nice to see an update
but i wonder why i never really checked the script
then ill take a look at your reworked library


JASS:
function RegisterEventDT takes trigger t, playerunitevent pue returns nothing
    call TriggerRegisterPlayerUnitEvent(t, Player(0), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(1), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(2), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(3), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(4), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(5), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(6), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(7), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(8), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(9), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(10), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(11), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(12), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(13), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(14), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(15), pue, TrueFilterDT)
endfunction

o_O why dont you use a loop? it saves alot lines here


JASS:
function PreloadSpecialEffectDT takes string whichSFX returns nothing
    call Preload(whichSFX)
    call PreloadStart()

    call DestroyEffect(AddSpecialEffect(whichSFX, PRELOAD_X, PRELOAD_Y))
endfunction
im not sure but is it really necessary to create the spell after preloading it?
I always use Preload() only and everything is fine


JASS:
function PreloadUnitDT takes integer unitid returns nothing
    set bj_lastCreatedUnit = CreateUnit(Player(15), unitid, PRELOAD_X, PRELOAD_Y, 0.)
    call UnitApplyTimedLife(bj_lastCreatedUnit, 'BTLF', .5)
endfunction

=> call RemoveUnit(CreateUnit(Player(15), unitid, PRELOAD_X, PRELOAD_Y, 0.)) ?




JASS:
function GetDistanceDT 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

I guess that can be simply inlined, but im not sure if its really better
return SquareRoot((bx - ax) * (bx - ax) + (by - ay) * (by - ay))
 
Level 15
Joined
Jul 19, 2007
Messages
618
nice to see an update
but i wonder why i never really checked the script
then ill take a look at your reworked library


JASS:
function RegisterEventDT takes trigger t, playerunitevent pue returns nothing
    call TriggerRegisterPlayerUnitEvent(t, Player(0), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(1), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(2), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(3), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(4), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(5), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(6), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(7), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(8), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(9), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(10), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(11), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(12), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(13), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(14), pue, TrueFilterDT)
    call TriggerRegisterPlayerUnitEvent(t, Player(15), pue, TrueFilterDT)
endfunction

o_O why dont you use a loop? it saves alot lines here


JASS:
function PreloadSpecialEffectDT takes string whichSFX returns nothing
    call Preload(whichSFX)
    call PreloadStart()

    call DestroyEffect(AddSpecialEffect(whichSFX, PRELOAD_X, PRELOAD_Y))
endfunction
im not sure but is it really necessary to create the spell after preloading it?
I always use Preload() only and everything is fine


JASS:
function PreloadUnitDT takes integer unitid returns nothing
    set bj_lastCreatedUnit = CreateUnit(Player(15), unitid, PRELOAD_X, PRELOAD_Y, 0.)
    call UnitApplyTimedLife(bj_lastCreatedUnit, 'BTLF', .5)
endfunction

=> call RemoveUnit(CreateUnit(Player(15), unitid, PRELOAD_X, PRELOAD_Y, 0.)) ?




JASS:
function GetDistanceDT 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

I guess that can be simply inlined, but im not sure if its really better
return SquareRoot((bx - ax) * (bx - ax) + (by - ay) * (by - ay))

reason why he did not use loop is because of large amount of speed! loops are the only thing in jass that will cause quick timers to lag! most of the time! simply calling custom functions is fine but loops are very slow...

that preload is like you said not needed to be done like that! for example preload effect is enough to just use DestroyEffect(AddSpec...)

if you use Preload its faster and does not leak but one thing special about Preload is that you need to Preload model, texture and any other things that model uses, icons...

for example Terror Blade from my spell pack!

JASS:
// ---------------------------
		// *** Preload used files ***
		call Preload(CORRUPTION_EFFECT)
		call Preload(DARKNESS_EFFECT)
		call Preload(TERROR_EFFECT)
		call Preload("Textures\\firering2A.blp")
		call Preload("Textures\\GenericGlow2b.blp")
		call Preload("Textures\\GenericGlowFaded.blp")
		call Preload("Abilities\\Weapons\\AvengerMissile\\Ghost1Mod.blp")
		call Preload("Abilities\\Spells\\Other\\HowlOfTerror\\Skull1.blp")
		call Preload("Abilities\\Spells\\Other\\HowlOfTerror\\HowlOfTerror.wav")
		call Preload("Abilities\\Weapons\\AvengerMissile\\DestroyerMissile.wav")

note that all needs to be preloaded but its fast coz it directly injects this in Load Screen!

about GetDist... it cant get inlined coz arguments are used more then once!

now rules about inlining are here:

  • The function is a one-liner
  • If the function is called by call the function's contents must begin with set or call or be a return of a single function.
  • If the inlined function is an assigment (set) it should not assign one of its arguments.
  • Every argument must be evaluated once and only once by the function, in the same order as they appear in the arguments list.
  • If the function contains function calls, they should all be evaluated after the arguments UNLESS the function is marked as non-state changing, at the moment some very few native functions and also return bug exploiters are considered as non-state changing.

anyway nice update out there :)
 
Level 11
Joined
Apr 29, 2007
Messages
826
EDIT:
Struct members don't need to be nulled, but nulling them is slightly more efficient :) basically removing leaks until same struct array is used, or removing the leaks of the arrays that happen to not be used anymore throughout the game...

yeah, you're like 0.00001 second faster when nulling them by yourself.

Well looked at the spells, they seemed to be very nice. The ideas are creative, I've only flown over the code but it seemed to work pretty efficient.
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
YourNameHere said:
yeah, you're like 0.00001 second faster when nulling them by yourself.
Well I didn't do that cause of the sake of speed, but for the sake of saving 4 bytes per unrecycled global. That's why I said slightly since it's not really much of a big deal :)

@ - JonNny:
DD explains all :p the reason I manually looped however like that is somehow cause of what DD says, and also cause I usually loop using textmacros, but since it's one lined, it's useless using textmacros :p

The preload makes sense... I just thought it'll be better that way. Why?
Well, use an effect such as phoenix missile's death animation. Even if it's preloaded, it might still freeze for like .7 seconds (it does on my laptop :p) when it shows for the first time on the screen. However, from there one, no more freezing even if you have a spam of that effect :p So I just thought that the way I do it might be slightly better...

@ Anachron:
Man I had no idea who you were since you killed Fred! :p
Haha anyways, I'd love seeing a review, I bet there are tons of stupid mistakes done by me :p

@ DD:
Thanks for the explanation, as usual =)
 



Concept (30):

Idea
7 /10
Complexity
5 /10
Style
9 /10
Comment:
This spell is ok. Its easy but fits to the package.
Effects (10):

All:
10 /10
Comment:
Not very eyecandy. Atleast it works.
Scripting (30):

Speach:
10 /10
Leakage:
10 /10
Effective Coding:
8 /10
Comment:
One point drain cause:
JASS:
if (d.tco >= BUFF_DURATION[d.lvl]) or IsUnitType(d.ta, UNIT_TYPE_DEAD) then
You should also check for the unit having the buff.
That would make it able to use purge without needing to trigger the remove.
Also, its still a bit.. Um.. Basic.
Score: 59/70
Final Score: 4,2 / 5

The spell was ok. Wouldn't use it either. [4/5] vote

[X] +Rep
[ ] Report
(Blank box means no action)





Concept (30):

Idea
6 /10
Complexity
6 /10
Style
10 /10
Comment:
This spell is ok. Its easy but fits to the package. Just as the other one.
Effects (10):

All:
8 /10
Comment:
Special effect fitted.
Scripting (30):

Speach:
10 /10
Leakage:
10 /10
Effective Coding:
10 /10
Comment:
Nothing to complain about
Score: 60/70
Final Score: 4,2 / 5

Reminds me of AoM. Kewl one. Definitly useful. [4/5] vote

[X] +Rep
[ ] Report
(Blank box means no action)





Concept (30):

Idea
8 /10
Complexity
8 /10
Style
10 /10
Comment:
Really like this one. Nice one. Could be still better (Bouncing?)
Effects (10):

All:
9 /10
Comment:
Effects were good.
Scripting (30):

Speach:
10 /10
Leakage:
10 /10
Effective Coding:
6 /10
Comment:
Just combine backward and forward loop and set a boolean whether its back or forward.
Score: 61/70
Final Score: 4,2 / 5

Creative and new. Might use this. [4/5] vote

[X] +Rep
[ ] Report
(Blank box means no action)





Concept (30):

Idea
10 /10
Complexity
9 /10
Style
9 /10
Comment:
Nice one. Perfect in my eyes. You did an excellent job here.
Effects (10):

All:
10 /10
Comment:
Fits, super, thats awesome.
Scripting (30):

Speach:
10 /10
Leakage:
10 /10
Effective Coding:
10 /10
Comment:
Nothing to complain about. You used TimerUtils, Table and coded very well. Goob job!
Score: 68/70
Final Score: 4,9 / 5

Creative and new. Might use this. [5/5] vote

[X] +Rep
[ ] Report
(Blank box means no action)





Concept (30):

Idea
6 /10
Complexity
7 /10
Style
8 /10
Comment:
I somehow dislike the idea. The miss doesn't fit to the damage and the hero itself. Also I think AOE + miss is not very good.
Effects (10):

All:
10 /10
Comment:
Effects were well chosen, nothing to complain about.
Scripting (30):

Speach:
8 /10
Leakage:
10 /10
Effective Coding:
10 /10
Comment:
Effective coding. Still, you might want to change this too:
JASS:
call DummyCastTargetDT(p, u, BLIND_ABILITY_ID, "curse", i)
Allow the user to change a constant to change the order string.
JASS:
call UnitDamageTarget(bj_lastCreatedUnit
I personally dislike bj_lastCreatedUnit, since you could set it
through triggers aswell.
Score: 59/70
Final Score: 4,2 / 5

Creative and new. Might use this. [4/5] vote

[X] +Rep
[ ] Report
(Blank box means no action)





Concept (30):

Idea
6 /10
Complexity
5 /10
Style
5 /10
Comment:
What the fuck? I highly disapprove this idea. Massive AOE stun, how small it ever is, is totally imba. It breakes spellcasts, and is stupid out of ideas.
Effects (10):

All:
10 /10
Comment:
Effects were good.
Scripting (30):

Speach:
9/10
Leakage:
10 /10
Effective Coding:
10 /10
Comment:
JASS:
 call UnitApplyTimedLife(d.w, 'BTLF', STUN_INTERVALS[d.lvl] * STUN_INTERVAL_TIME[d.lvl])
You could aswell add a new constant which is configureable in the header of the spell.
Score: 55/70
Final Score: 3,92 / 5

I don't like this spell. Its good coded nontheless. [4/5] vote

[X] +Rep
[ ] Report
(Blank box means no action)





Concept (30):

Idea
7 /10
Complexity
8 /10
Style
9 /10
Comment:
I think the idea is quite ok.
Effects (10):

All:
9 /10
Comment:
Effects were good.
Scripting (30):

Speach:
10 /10
Leakage:
10 /10
Effective Coding:
10 /10
Comment:
Nothing to complain about.
Score: 63/70
Final Score: 4,5 / 5

Basic but ok. Well coded aswell. [5/5] vote

[X] +Rep
[ ] Report
(Blank box means no action)





Concept (30):

Idea
9 /10
Complexity
9 /10
Style
10 /10
Comment:
Very nice package of spells man.
Effects (10):

All:
9 /10
Comment:
Effects fit to the spells in general very good.
Scripting (30):

Speach:
9 /10
Leakage:
10 /10
Effective Coding:
9/10
Comment:
Coding is mostly superb.
Score: 65/70
Final Score: 4,64 / 5

Might use some of the spells. Definitly worth an approval. [5/5] vote

[X] +Rep
[ ] Report
(Blank box means no action)
 
Last edited:
Level 17
Joined
Mar 17, 2009
Messages
1,349
Wow lovely review Anachron! =)

Well yes some spells are basic, they were created during the period where I was learning Jass. I mean 2 of them were even GUI :p

Stunning ward seemed stupid to me - it was only for practice - but I thought it might be useful to someone (I mean, if set to ministun at 4 second intervals, it might become useful, a channel stopper :p).

Also, I'm too lazy to work on something complicated, since complicated = more bugs = more fixing. What's more, I've barely seen complicated spells being major spells of a game.

And I didn't user TimerUtils or Table :p (I actually don't even know what Table is :p)
I make my own functions... I enjoy that more than importing :)

* Hiatus:
Yes I think I understand what you mean ;)

* Maze:
One of my random ideas :p

* Impairment:
Making it bounce would make almost exactly like DotA's spell, although not the same. And I'm sure someone on some forum has already made those new DotA spells.

* Balminess:
Yes one of the ideas that I'm proud of :) totally original and one of a kind...

* Sweltering Blaze:
Well somehow I was thinking of how flashbangs function, and this idea came to me. All spells can be adjusted to be "balanced". And since I though that AoE miss is unbalanced, that's why I made it so that it's only units looking at caster. I mean, if all are looking, then the caster is in big trouble and REALLY needs that miss :p

* Stunning Ward:
This case is clear...

* Foltern:
My official first vJass, as you can see in the credit's, DD helped me here :p it was a practice DoT, but then some ideas here and some ideas there... it's something new :)



Btw, I love your review template =) I might use something like it ;)
Oh, and thanks for the review!
And I'll let you in onto the fact that I'm working on a new spell now, and definitely complicated... if it doesn't gimme a pain in the ass, I might end up finishing it up ;) It's like a "two-spells-in-one" spell :)


EDIT:
Allow the user to change a constant to change the order string.
Senseless since you can't change the order string of a spell ;) but it would make sense in case you want me to enable the idea of totally changing the dummy ability :p

I personally dislike bj_lastCreatedUnit, since you could set it through triggers aswell.
I like recycling :p and it wouldn't bug for instant usage.


And in Stunning Ward, what should the constant be for?
 
reason why he did not use loop is because of large amount of speed! loops are the only thing in jass that will cause quick timers to lag! most of the time! simply calling custom functions is fine but loops are very slow...

that preload is like you said not needed to be done like that! for example preload effect is enough to just use DestroyEffect(AddSpec...)

if you use Preload its faster and does not leak but one thing special about Preload is that you need to Preload model, texture and any other things that model uses, icons...

for example Terror Blade from my spell pack!

JASS:
// ---------------------------
		// *** Preload used files ***
		call Preload(CORRUPTION_EFFECT)
		call Preload(DARKNESS_EFFECT)
		call Preload(TERROR_EFFECT)
		call Preload("Textures\\firering2A.blp")
		call Preload("Textures\\GenericGlow2b.blp")
		call Preload("Textures\\GenericGlowFaded.blp")
		call Preload("Abilities\\Weapons\\AvengerMissile\\Ghost1Mod.blp")
		call Preload("Abilities\\Spells\\Other\\HowlOfTerror\\Skull1.blp")
		call Preload("Abilities\\Spells\\Other\\HowlOfTerror\\HowlOfTerror.wav")
		call Preload("Abilities\\Weapons\\AvengerMissile\\DestroyerMissile.wav")

note that all needs to be preloaded but its fast coz it directly injects this in Load Screen!

about GetDist... it cant get inlined coz arguments are used more then once!

now rules about inlining are here:

  • The function is a one-liner
  • If the function is called by call the function's contents must begin with set or call or be a return of a single function.
  • If the inlined function is an assigment (set) it should not assign one of its arguments.
  • Every argument must be evaluated once and only once by the function, in the same order as they appear in the arguments list.
  • If the function contains function calls, they should all be evaluated after the arguments UNLESS the function is marked as non-state changing, at the moment some very few native functions and also return bug exploiters are considered as non-state changing.

anyway nice update out there :)

1. Loops ARE NOT slow AT ALL. So they might be a TINY bit slower because of evaluating the exitwhen and increasing the counter at the end each loop, but they definately wouldn't cause a periodic function to lag - the actions inside them which are repeated over and over are the things that cause lag.

2. You DO NOT need to preload each texture the model uses. Preloading the model loads the textures too...

3. "Directly injecting" into the load screen just makes the map take longer to load. It's not any faster.
 
Senseless since you can't change the order string of a spell ;) but it would make sense in case you want me to enable the idea of totally changing the dummy ability :p
That was my idea.

I like recycling :p and it wouldn't bug for instant usage.
bj_lastCreatedUnit is for me dead. I saw it bugged sometimes.


And in Stunning Ward, what should the constant be for?
To change the ID of the drain life?? I mean thats a buffID, so it has to go within the customisation area.
 
Level 15
Joined
Jul 19, 2007
Messages
618
@ Element of Water

1) Loops in jass are extremely slow, that what you said is not correct at all! functions are slow but not as loops so if one spell would not use a loops at all and just natives and BJ-s in timer with interval of 0.01 secs it would not cause lag! ofc it depends what does actions do if BJ-s or natives cause some kind of loop it will again be slow. native loops are fast but still take some time like ForGroup! in jass ones are main reason why something may get slow and cause lag. for CPU its easy to start and read actions i am sure you know that but whats hard is that for loops every time it gets at loop it must put an mark at that memory place, then continue until endloop is found and then it checks that exitwhen , if its false it must stop current execution and start all over again from the marked place by loop! process of traveling again at that top and stoping "thread" is in jass extremely slow... all loops in VM are very slow and thats why jass ones are like that. if you put no actions in loop and make it loop a lot of times delay will occure or loop will quit because Blizzard made limited amount of loops or simply limited amount of time it can take from CPU, meaning that some slow loops may never finish through that loop... thats why ForGroup is always much better choice then loop/endloop

ForGroup uses foreach (*var[]) where var is group pointer array units stack! its much faster then one in VM

2.) Yes you must preload everything that model needs if you want that no lag is caused by first cast, if you dont preload this little textures and other stuff lag might be minor but will be...

3.) Thats the point of preload to put it in load screen so that in-game lag is not caused! it is faster then "creating handle and destroying it" as well no handle will be completely removed from the memory thats why i said preload is leakless and faster. "creating effect and destroying" must be put at map startup and everything which is in map startap is loaded during load-screen and preload will took less time then "add-destroy" effect stuff would.
 
  • Like
Reactions: Rmx
1. Lol. You are completely wrong. The actual loops are no slower than in c++. The only thing that makes them slightly slower is the exitwhen check. You say a periodic timer with no loops but loads of BJs/natives won't lag - that's because when you have a loop, the number of function calls is multiplied. The actual loops are not slow. You say it's slow when a loop ends because it has to restart the thread...
  • Where's your proof
  • That would only happen once per loop, so it can't be that slow.

And wtf is VM?

2. Preloading the model automatically preloads the textures. Textures are generally the things with the most file size in models, and preloading stops the lag, therefore it must load everything.

3. Since when did I say you should create/destroy the effects?
 
Last edited:
Level 15
Joined
Jul 19, 2007
Messages
618
@ Element of Water

well i really dont know how to explain why loops are slow... i tried to but well i know that at beginning it was hard for me to understand as well until i did not went and try to understand alone! it is hard to understand what all CPU has to do when you know language like jass or c++, to learn asm is a little different but teaches you most of stuff! i must say i like asm but i never tried to learn it. overall some basics and logical things i do know but else nop.

as well i am not trying to force you to belive anything i say if you think loops are like in c++ well then use them ofc there are situations where loops are a must and ofc i use them as well but i avoid them if possible or cut them to increase speed.

exitwhen is not to slow! its fine at map init write this code:

JASS:
loop
endloop

at load screen you will see an delay thats the same delay that would be caused in-game but would be cut by Blizzard's engine.

no natives nor BJ-s are called do note that if you dont put exitwhen blizzard will put it and after some small amount of time exitwhen will return true and thread will end. thats simple to expalin it to u.

once again you dont have to belive anything i say in future if you will still be programmer you might understand what i was now saying.

as well i went to much off-topic and i dont like when such a comments are in my spells so i would not want to do that to other people, so if you still have future questions please pm me or post visitor msg!

Greets!
~DD
 
Level 12
Joined
Jul 27, 2008
Messages
1,181
Malfunctioned how? You may still be able to save the data.

Try using the excellent freeware.... Ubuntu!

Yup, that's right. Install it on a flash and see if it can copy the data. It copied all the stuff from a disk of mine which caused every boot-program to crash.
 
Level 3
Joined
Mar 29, 2009
Messages
23
So using a system thats not from open source, although since he uploaded it in a spell it technically is open source now.

Using a public system somehow makes it more effective than using a 'non-standard' library that does the same thing as effectively . . .

WEIRD AND WRONG!!! IT IS JUST WARCRAFT PEOPLE NOT SOMETHING SUPER IMPORTANT LOL

JASS has no importance whatsoever, it is used only in warcraft and nothing else haha, again nice spells Deut!
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
Wow... ModWar :S

I'll try to make it short...

To start with Anachron:
You know how I'm always open for improvements and you know I seek maximum efficiency in spells, but this was reviewed by TriggerHappy some months after I became inactive. If this happened when I was here I would have rapidly changed the library - and I most probably will once I get some free time from university. But that doesn't mean it should be rejected 'cause of the DD library, which I actually use in only one very basic spell out of seven. RIGHT?

@ the other guys:
Thanks for understanding my point.

@ Kingz:
LOL :p

@ The_Reborn_Devil:
Thanks for trying! :D

@ TriggerHappy:
Dude, whatever I say next is not me trying to offend you in any way, but it could sound like that. You are trying to act all Mr. Perfect and smart... but meh... that doesn't make you right. I've never read DD's libraries but as for the Damage Detection, it never had a glitch during the 100's of times that I tested the spell. Plus it's pretty ignorant of you to reject the whole pack 'cause of one basic spell which uses a damage detection system which you don't consider 'standard'. Why is it so? First of all, it's a pack of 7 spells that work TOTALLY fine, but you don't PERSONALLY like one of them... Second of all, any 'coder' that really minds using one standard library for all his spell would be smart enough to edit all spells in his map to satisfy his needs. I'm pretty sure different spells may use various libraries - yet considered standard - for the same functionality.
What's more, I told you in a personal message that I would change the library once I get some time, and even asked you politely if you could help me by giving me a link to one. You simply replied by something like 'check wc3c'.
So come on and be reasonable and approve the pack. Trying to act smart and above all is just a sign of obliviousness and nothing more...

And again I say whenever I get a pinch of free time I WILL change the libraries... but that doesn't mean it should stay as rejected until then!


Take care guys! :)
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
why is this spell rejected while it's recommended?

Well there was an issue between me & one of the mods after i became inactive where he didn't like one of the libraries i used (the one by Dark_Dragon) and so it got rejected...
But in the same time it's recommended by another mod...

Sooo... yea :p


EDIT:
& honestly i just remember that i found it unfair that it got rejected over me using one function from that library for one spell, specially since it was approved when i was active in the hive and it got rejected after i left the hive (i.e. i wasn't able of re-coding the spell or deleting it since i didn't have the software on my pc anymore)
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
Spell Pack Updated:

- Removed the spell over which the modwar started on whether to reject or accept, so now this should be accepted.
- Fixed the Impairment spell


Anyways, in case anyone hunts down any bugs or has any comments or ideas, feel welcome to share them. :)

EDIT:
Sorry for the double post but the previous post was days ago...
 
Here's a tip for a huge efficiency boost:

Make the struct extend an array,
Add these members to it:
JASS:
private static integer ic = 0
private static integer ir = 0
private thistype rn

Then, instead of setting this = .allocate(),
do this:
JASS:
if 0==ir then
    set ic=ic+1
    set this=ic
else
    set this=ir
    set ir=.rn
endif

And instead of calling .deallocate(), do this:
JASS:
set .rn=ir
set ir=this

Trust me, this is MUCH faster and more efficient since vJASS normal structs generate tons of shit-code. :p
 
Top