• 🏆 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!

vJass Spells v1.4b

This Spell uses vJass so it required the Jass New Gen Pack. Get it here.

Live Distortion
Sends out souls which will steal healthpoints and leave a debuff on the target. When returning they heal the caster depending on the dealt damage.
Rank 1 - sends out 6 souls which deal 40 dmg and heal for 30%
Rank 2 - sends out 9 souls which deal 55 dmg and heal for 40%
Rank 3 - sends out 12 souls which deal 70 dmg and heal for 50%
Midn Burst
Sends out two concentrated essences which will move in the target direction. On hit they deal damage, leave a mana draining debuff and if the target has mana it will also transfer a bit of it directly to the caster. Range Increases per level.
Rank 1 - 50 damage, 55 mana debuff, steals 10 mana directly
Rank 2 - 50 damage, 55 mana debuff, steals 15 mana directly
Rank 3 - 90 damage, 100 mana debuff, steals 20 mana directly

Update: Live Distortion v1.01
-made functions constant
-improved documention
-removed leaks in the init function
-other minor improvements of the script

Update: Live Distortion v1.02
-changed SetUnitState to SetWidgetLife
-removed all bj_DEGTORAD as wanted

Update Live Distortion v1.03
-minor bugfix due the remove of bj_DEGTORAD

Update Live Distortion v1.04
-optimizing

UPDATE: added Mind Burst

updated LD 1.05 , MB v1.01
-improved the init function
-improved scripting
-made it easier to modify and read

update LD v1.06 , MB v1.02
-optimized scripting
-deleted NullFilter
-implented a Timer Recycle

update LD v1.07 , MB v1.03
-shortened struct destruction
-made globals constant
-fixed various minor issues

updated LD 1.08 , MB 1.04
-removed dynamic dummy usage
-changed other small things

updated LD 1.08b, MB 1.04b
-removed Group Utilities due the patch
-made it 1.24 compatible


JASS:
/////////////////////////////////////////////////////////////////////////////////////////////////
//                      Live Distortion 1.08b (1.24 compatible)      
//                              Created by JonNny
//
//               °                                        Mapmaking since 2006...
//            °
//          °
//         °
//       °°°ÛÜ
//      °°X°ÛÛÛ                          ÛÛÛÛÛÛÛÛ     ÿÜÛÛÛÛÛÛÛÛÜ
//     °°XX° ÛÛÛ        ßÛÛÛÛÛ        ÛÛÛÛÛÛÛÛÛÛÛÛ   ÛÛÛÛÛÛÛÛÛÛÛÛÛ
//     °XX ° ÛÛÛÛ         ÛÛÛÛÜ     ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ  ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
//     °XX °  ÛÛÛÛÛ        ÛÛÛÛ    ÛÛÛÛÛß    ßÛÛÛÛÛÛ  ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ 
//    °°XXX°° ÛÛÛÛÛÛÜ       ÛÛÛÜ  ÛÛÛÛÛ        ßÛÛÛÛÛ ßÛÛÛÛ    ÛÛÛÛÛÛ 
//   °°°°°°°°  ÛÛÛÛÛÛÛ      ÛÛÛÛ  ÛÛÛÛ                 ÛÛÛÛ      ÛÛÛÛÜ 
//             ÛÛÛÛÛÛÛÛ     ÛÛÛÛ  ÛÛÛÛ        ÛÛÛÛÛÛÛ  ÛÛÛÛÛÜ     ÛÛÛÛ 
//   °°°°°°°°  ÛÛÛÛÛÛÛÛÛ    ÛÛÛÛÜ  ÛÛÛÛÜ     ÛÛÛÛÛÛÛÛ   ÛÛÛÛÛÜ  ÜÛÛÛÛÛÛ 
//   °°XXXXX°   ÛÛÛÛ  ÛÛÛÜ  ÛÛÛÛÛ   ÛÛÛÛÛÛÜ    ßÛÛÛÛÛ   ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ 
//   °°XXXXX °° ÛÛÛÛ   ÛÛÛÛÜ ÛÛÛÛ °°°ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ°°° ÛÛÛÛÛÛÛÛÛÛÛÛÛß 
//   °  XXXXX °°ÛÛÛÛÛ°°°°ÛÛÛÛÛÛÛÛ°°XX ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ XXX°°ÛÛÛÛÛÛÛÛÛÛÛ     ÛÛÛ
//   °°  XXXXX ÜÛÛÛÛÛÛ X ÛÛÛÛÛÛÛÛÛ XXX ÛÛÛÛÛÛÛÛÛÛÛ  XXXXXX  ÛÛÛÛÛÛÛ°      ÛÛÛ
//    °°  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°°   °°°°
//     °°   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°X°°
//      °°°  XXXXXXXXXX  °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° XXXXXXXXXXXXXXXXX°°
//        °°°°°°°°°°°°°°°°                                  °°°°°°°°  XXXXXXX °°°
//                                                                  °°°°°° XX °°
//   ...2009 and still moving on.                                        °°°°°°°
//                                                                             °°
//
// What do you need to import this Spell:
// -Your Ability
// -A missile dummy
// -A Spell for the Buff
// -A simple dummy to cast the Buff
//
//
//1. Create all needed things mentioned above.
//2. Copy the code into your map (also GroupUtils if it does not already exist)
//3. Adjust all globals matching to your created stuff :
//  line 53 - Your missile dummys Rawcode;
//  line 54 - Your Spells Rawcode
//  line 55 - Your cast dummys Rawcode
//  line 56 - Your Effect Spells Rawcode
//  line 59 - The Order ID of the Effect Spell
//
//  After that you should be done :)
//  Thanks to : Hanky for helping to improve this script , Rising_Dusk for Feedback
//////////////////////////////////////Globals with important values////////////////////////////////////////
scope LiveDistortion initializer Init

globals
    //RawCodes
    private constant integer DummyID                   = 'h001'  //The Missile dummy ID (Rawcode)
    private constant integer EssenceSpell              = 'A000'  //Spell ID (Rawcode)
    private constant integer CastDummyID               = 'h002'  //A normal dummy to cast the effect (Rawcode)
    private constant integer LiveDistortionEffectSpell = 'A001'  //The Spell which is casted on each hit enemy (Rawcode)
   
    //Spell Related Constants
    private constant string  EffectOrderID          = "unholyfrenzy" //Order ID of the Spell (LiveDistortionEffectSpell) efect whih should last after being hit
    private constant real    EssenceSpeed           = 0.085          //Defines how fast the missiles are with setting the duration (also faster missiles with longer distance)
    private constant real    PercentageSpeedReduce  = 0.02           //The rate the missiles get slower, a too high value causes the spell not to finish
    private constant real    TimerPeriod            = 0.0275         //How fast the execution is
    private constant real    LDDummyMaxHeight       = 340.00         //Height the missiles reach on their flight
    private constant real    LDDummyMinHeight       = 50.00          //Min. Height of the missiles
    private constant real    SpinRate               = 0.03           //The rate the Missiles begin to spin after reaching 1/2 of the way
    private constant real    HealthStealRange       = 80.00          //the collision of the missile in which it steals damages enemies
    private constant real    MissileStartScale      = 0.7            //The scale the missile has at the beginning
    private constant real    MissileScaleIncrease   = 0.08           //The scale the missile gets bigger when stealing hp
    private constant real    ReleaseDistance        = 10.00          // The Distance the missiled being released of / coming back to the caster
    private constant integer MaxMissiles            = 12
   
    //Effects
    private constant string HealSpecialeffect = "Abilities\\Spells\\Undead\\Darksummoning\\DarkSummonTarget.mdl"   // Special effect when healing the caster
    private constant string LiveStealEffect   = "Abilities\\Weapons\\ChimaeraAcidMissile\\ChimaeraAcidMissile.mdl" // Special effect when hitting an enemy
   
    //System Variables , Do not Change
    private timer    t      = CreateTimer()
    private boolexpr filter = null
    private unit Dummy      = null
    private group ENUM_GROUP = CreateGroup()
endglobals


///////////////////////////////////Defining most relevant Values////////////////////////////////////////////////



private constant function EssencesPerLevel takes integer level returns integer
    return 3 * level + 3 
    // Number of missiles created per level
endfunction

private constant function EssencesRangePerLevel takes integer level returns real
    return 200.00 + 40.00 * level 
    // Max. Range the missiles reach on their flight (also affects their movementspeed)
endfunction
   
private constant function StolenHealthPerLevel takes integer level returns real
    return 25.00 + level * 15.00
    //Defines how much damage the missiles deal/steal
endfunction

private constant function PercentageHealPerLevel takes integer level returns real
    return 0.2 + level * 0.1
endfunction

private function DistanceMovement takes real d  returns real
    return SquareRoot(Sin(d)*Sin(d))
    //defining the movement of the missiles that they also come back , i suggest not to change it
endfunction

private function StealHealthCondition takes unit enemy , unit caster returns boolean
    return  IsPlayerEnemy(GetOwningPlayer(enemy),GetOwningPlayer(caster))  // The condition if a unit is damaged in addition to the UnitFilter
endfunction

private function HeightFunction takes real d returns real
    local real x = 0.4*(3.14159 - d) 
    // Its a matching function for the height movement of the missiles, a parabula would have been too easy :P
    return LDDummyMaxHeight * (Pow(x,-Pow(x,0.8))-1)
endfunction

private function RunCondition takes nothing returns boolean
    return GetSpellAbilityId() == EssenceSpell
    //The condition if the spell is casted
endfunction

private function UnitFilter takes nothing returns boolean
    local boolean ret = false
    if not(IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL)) and not(IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE)) then
        set ret =  IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND) and (GetWidgetLife(GetFilterUnit()) > 0.405)
    endif
   
    return ret
endfunction

///////////////////////////////////Main Struckt//Do not change//////////////////////////////////////////////

private struct Essences
    static integer Index = 0
    static Essences array Data
    unit array EssenceDummy [MaxMissiles]
    real array angle [MaxMissiles]
    group array DamagedUnits [MaxMissiles]
    real array MissileScale [MaxMissiles]
    group GotBuff
    unit Caster
    integer level
    real d = 0.00
    integer EssenceAmount 
    real StolenHealth = 0
   
    static method create takes nothing returns Essences
        local Essences data = Essences.allocate()
        set Essences.Data[Essences.Index] = data
        set Essences.Index = Essences.Index + 1
        return data
    endmethod
endstruct

////////////////////////////////Main script// Do not edit unless you understand it////////////////////////////////

private function callback takes nothing returns nothing
    local Essences data
    local integer i = 0
    local real x = 0.00
    local real y = 0.00
    local integer a = 0
    local unit b = null
    local unit dummy = null
   
    // looping through all structs
    loop
        exitwhen i >= Essences.Index
        set data = Essences.Data[i]
        set data.d = data.d + EssenceSpeed - (PercentageSpeedReduce*data.d)
        set a = 0
       
        // looping through each missile of the struct
        loop 
            exitwhen a >= data.EssenceAmount
            call SetUnitX(data.EssenceDummy[a], GetUnitX(data.Caster) + (ReleaseDistance + EssencesRangePerLevel(data.level) * DistanceMovement(data.d)) * Cos(data.angle[a]))
            call SetUnitY(data.EssenceDummy[a], GetUnitY(data.Caster) + (ReleaseDistance + EssencesRangePerLevel(data.level) * DistanceMovement(data.d)) * Sin(data.angle[a]))
            call GroupEnumUnitsInRange(ENUM_GROUP,GetUnitX(data.EssenceDummy[a]),GetUnitY(data.EssenceDummy[a]),HealthStealRange,filter)
           
            // looping through each unit in range of each missile
            loop
                set b = FirstOfGroup(ENUM_GROUP)
                exitwhen b==null
                call GroupRemoveUnit(ENUM_GROUP,b)
               
                //checking if the unit is damage and stealing its hp °,.,°
                if IsUnitInGroup(b,data.DamagedUnits[a]) == false and data.d <= (3.14159/2) and StealHealthCondition(b,data.Caster) then
                    call GroupAddUnit(data.DamagedUnits[a],b)
                    set data.MissileScale[a] = data.MissileScale[a] + MissileScaleIncrease
                    call SetUnitScale(data.EssenceDummy[a],data.MissileScale[a],data.MissileScale[a],data.MissileScale[a])
                    set data.StolenHealth = data.StolenHealth + StolenHealthPerLevel(data.level)
                    call UnitDamageTarget(data.Caster,b,StolenHealthPerLevel(data.level),true, false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
                    call DestroyEffect(AddSpecialEffectTarget(LiveStealEffect, b, "origin") )
                   
                    //casting the effect after being hit at each unit , using the group to avoid dopling dummies for one enemy
                    if IsUnitInGroup(b,data.GotBuff) == false then
                        call GroupAddUnit(data.GotBuff,b)
                        call SetUnitX(Dummy,GetUnitX(b))
                        call SetUnitY(Dummy,GetUnitY(b))
                        call SetUnitOwner(Dummy,GetOwningPlayer(data.Caster),false)
                        call SetUnitAbilityLevel(Dummy,LiveDistortionEffectSpell,data.level)
                        call IssueTargetOrder( Dummy,  EffectOrderID,b )
                    endif
                endif
            endloop
            call GroupClear(ENUM_GROUP)
           
            //setting the missiles height
            if (HeightFunction(data.d)) >= LDDummyMinHeight then
                set data.angle[a] = data.angle[a] + SpinRate * 1.5 * (data.d-1)
                call SetUnitFlyHeight(data.EssenceDummy[a], HeightFunction(data.d), 1000)
            endif
            set a = a + 1
        endloop
        set a = 0
       
        //Pi is the value the spell is finished
        if data.d >= 3.14159 then
       
            //cleaing all variables
            loop 
                exitwhen a >= data.EssenceAmount
                call RemoveUnit(data.EssenceDummy[a])
                set data.EssenceDummy[a] = null
                call DestroyGroup(data.DamagedUnits[a])
                set data.DamagedUnits[a] = null
                set a = a + 1
            endloop
            call DestroyEffect(AddSpecialEffectTarget(HealSpecialeffect, data.Caster, "origin"))
            call DestroyGroup(data.GotBuff)
            set data.GotBuff = null
           
            //healing the caster
            if GetWidgetLife(data.Caster) > 0.405 then
                // If desired a display of the amount of hp healed can be added here (PercentageHealPerLevel(data.level) * data.StolenHealth)
                call SetWidgetLife(data.Caster,GetWidgetLife(data.Caster)+ PercentageHealPerLevel(data.level) * data.StolenHealth)
            endif
            set data.Caster = null
            call Essences.destroy(data)
            set Essences.Data[i] = Essences.Data[Essences.Index - 1]
            set i = i - 1
            set Essences.Index = Essences.Index - 1
        endif
        set i = i + 1
    endloop
    set b = null
    set dummy = null
endfunction

private function Actions takes nothing returns nothing
    local integer a = 0
    local real angle = 0.00
    local unit caster = GetTriggerUnit()
    local integer level = GetUnitAbilityLevel(caster,EssenceSpell)
    local real x = GetUnitX(caster)
    local real y = GetUnitY(caster)
    local real d = 0.00
    local integer EssencesAmount = EssencesPerLevel(level)
    local real z = (6.2832 / I2R(EssencesAmount)) // 6.2832 = 2Pi
    local integer i = Essences.Index
   
    // Creating the Struct
    call Essences.create()
    set Essences.Data[Essences.Index-1].Caster = caster
    set Essences.Data[Essences.Index-1].level = level
    set Essences.Data[Essences.Index-1].EssenceAmount = EssencesAmount
   
    loop
            exitwhen a >= EssencesAmount
            // Creating the missiles here
            set angle = z * a
            set Essences.Data[i].angle[a] = angle
            set Essences.Data[i].EssenceDummy[a] = CreateUnit(GetOwningPlayer(caster), DummyID , x + ReleaseDistance * Cos(angle),y + ReleaseDistance * Sin(angle) , angle * 57.296)
            set Essences.Data[i].DamagedUnits[a] = CreateGroup()
            set Essences.Data[i].GotBuff = CreateGroup()
            set Essences.Data[i].MissileScale[a] = MissileStartScale
            set a = a + 1
    endloop
    if Essences.Data[Essences.Index-1].Index == 1 then
        call TimerStart(t, TimerPeriod, true, function callback)
    endif
    set caster = null
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger tr = CreateTrigger()
    set Dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),CastDummyID,0,0,0)
    call UnitAddAbility(Dummy,LiveDistortionEffectSpell)
    set filter = Filter(function UnitFilter)
    call TriggerRegisterAnyUnitEventBJ(tr,EVENT_PLAYER_UNIT_SPELL_CAST)
    call TriggerAddCondition( tr, Condition( function RunCondition ) )
    call TriggerAddAction( tr, function Actions )
   
    //Preloading the used effect models
    call Preload(HealSpecialeffect)
    call Preload(LiveStealEffect)   
endfunction

endscope

JASS:
/////////////////////////////////////////////////////////////////////////////////////////////////
//                        Mind Burst 1.04b (1.24 compatible)   
//                             Created by JonNny
//
//               °                                        Mapmaking since 2006...
//            °
//          °
//         °
//       °°°ÛÜ
//      °°X°ÛÛÛ                          ÛÛÛÛÛÛÛÛ     ÿÜÛÛÛÛÛÛÛÛÜ
//     °°XX° ÛÛÛ        ßÛÛÛÛÛ        ÛÛÛÛÛÛÛÛÛÛÛÛ   ÛÛÛÛÛÛÛÛÛÛÛÛÛ
//     °XX ° ÛÛÛÛ         ÛÛÛÛÜ     ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ  ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
//     °XX °  ÛÛÛÛÛ        ÛÛÛÛ    ÛÛÛÛÛß    ßÛÛÛÛÛÛ  ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ 
//    °°XXX°° ÛÛÛÛÛÛÜ       ÛÛÛÜ  ÛÛÛÛÛ        ßÛÛÛÛÛ ßÛÛÛÛ    ÛÛÛÛÛÛ 
//   °°°°°°°°  ÛÛÛÛÛÛÛ      ÛÛÛÛ  ÛÛÛÛ                 ÛÛÛÛ      ÛÛÛÛÜ 
//             ÛÛÛÛÛÛÛÛ     ÛÛÛÛ  ÛÛÛÛ        ÛÛÛÛÛÛÛ  ÛÛÛÛÛÜ     ÛÛÛÛ 
//   °°°°°°°°  ÛÛÛÛÛÛÛÛÛ    ÛÛÛÛÜ  ÛÛÛÛÜ     ÛÛÛÛÛÛÛÛ   ÛÛÛÛÛÜ  ÜÛÛÛÛÛÛ 
//   °°XXXXX°   ÛÛÛÛ  ÛÛÛÜ  ÛÛÛÛÛ   ÛÛÛÛÛÛÜ    ßÛÛÛÛÛ   ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ 
//   °°XXXXX °° ÛÛÛÛ   ÛÛÛÛÜ ÛÛÛÛ °°°ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ°°° ÛÛÛÛÛÛÛÛÛÛÛÛÛß 
//   °  XXXXX °°ÛÛÛÛÛ°°°°ÛÛÛÛÛÛÛÛ°°XX ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ XXX°°ÛÛÛÛÛÛÛÛÛÛÛ     ÛÛÛ
//   °°  XXXXX ÜÛÛÛÛÛÛ X ÛÛÛÛÛÛÛÛÛ XXX ÛÛÛÛÛÛÛÛÛÛÛ  XXXXXX  ÛÛÛÛÛÛÛ°      ÛÛÛ
//    °°  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°°   °°°°
//     °°   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°X°°
//      °°°  XXXXXXXXXX  °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° XXXXXXXXXXXXXXXXX°°
//        °°°°°°°°°°°°°°°°                                  °°°°°°°°  XXXXXXX °°°
//                                                                  °°°°°° XX °°
//   ...2009 and still moving on.                                        °°°°°°°
//                                                                             °°
//
// What do you need to import this Spell:
// -Your Ability
// -A missile dummy
// -A Spell for the Buff
// -A simple dummy to cast the Buff
//
//
//1. Create all needed things mentioned above.
//2. Copy the code into your map (also GroupUtils if it does not already exist)
//3. Adjust all globals matching to your created stuff :
//  line 53 - Your missile dummys Rawcode;
//  line 54 - Your Spells Rawcode
//  line 55 - Your cast dummys Rawcode
//  line 56 - Your Effect Spells Rawcode
//  line 59 - The Order ID of the Effect Spell
//
//  After that you should be done :)
//  Thanks to : Hanky for helping to improve this script , Rising_Dusk for Feedback
//////////////////////////////////////Globals with important values////////////////////////////////////////
scope MindBurst initializer Init

globals
    //Rawcodes
    private constant integer DummyID              = 'h003'  //The Missile dummy ID (Rawcode)
    private constant integer MindBurstSpell       = 'A002'  //Spell ID (Rawcode)
    private constant integer CastDummyID          = 'h002'  //A normal dummy to cast the effect (Rawcode)
    private constant integer MindBurstEffectSpell = 'A004'  //The Spell which is casted on each hit enemy (Rawcode)

    //Spell Related Constants
    private constant string  EffectOrderID         = "rejuvination" //Order ID of the Spell(Mind Burst Buff Effect) effect whih should last after being hit
    private constant real    MissileSpeed          = 9              //Defines how fast the missiles are
    private constant real    TimerPeriod           = 0.0275         //How fast the execution is
    private constant real    MissileHeight         = 80             // Defines the missiles basic height (they spin arround this) should be bigger than SpinStarRadius that they do not touch the ground
    private constant real    SpinStartRadius       = 60             // Sets the spin radius when they are created , why moving it decreases (look below)
    private constant real    SpinEndRadius         = 10             // Sets the spin radius the missiles got at the end
    private constant real    StartScale            = 0.85           // While moving missiles change their scale , this is their start scale (look below)
    private constant real    EndScale              = 0.275          // This is the missiles end scale
    private constant real    SpinRate              = 0.275          // The rate the missiles spin
    private constant real    AdditionalDamageRange = 50             //The additional range for hitting a target , the real range will be the current Spinradius + This value (this case its 110 at the start and 60 at the end)
    private constant real    ReleaseDistance       = 20.00          // The Distance the missiled being released infront of the caster
   
    //Effects
    private constant string  DamageEffect  = "Abilities\\Weapons\\WingedSerpentMissile\\WingedSerpentMissile.mdl" // Special effect when hitting an enemy
    private constant string  HealEffect    = "Abilities\\Spells\\Items\\AIma\\AImaTarget.mdl"                     // Special effect at the caster when being heald (missiles hit a unit with mana)
    private constant string  MissilesDeath = "Abilities\\Spells\\Orc\\LightningBolt\\LightningBoltMissile.mdl"    //Special effect whe the missiles are removed

    //System Variables , Do not change
    private timer    t      = CreateTimer()
    private boolexpr filter = null
    private unit Dummy = null
    private group ENUM_GROUP = CreateGroup()
endglobals

///////////////////////////////////Defining most relevant Values////////////////////////////////////////////////

private constant function MissileRangePerLevel takes real level returns real
    // The range the missiles reach per level
    return 550 + 225 * level
endfunction
   
private constant function StolenManaPerLevel takes integer level returns real
    // Amount of mana stolen directly and transfered to the caster
    return 5.0 + 5.0*level
endfunction   
   
private constant function DamagePerLevel takes integer level returns real
    //Amount of damage dealt when a unit is hit
    return 30.00 + level * 20.00
endfunction

private function DealDamageCondition takes unit enemy , unit caster returns boolean
    // The condition if a unit is damaged
    return   IsPlayerEnemy(GetOwningPlayer(enemy),GetOwningPlayer(caster)) // The condition if a unit is damaged
endfunction

private function ManaDrainCondition takes unit a  returns boolean
    // Additional condition (including DealDamageCondition) if the caster can directly steal mana
    return (GetUnitState(a,UNIT_STATE_MANA) > 0.0)
endfunction

private function RunCondition takes nothing returns boolean
    return GetSpellAbilityId() == MindBurstSpell
    // The condition if the spell is casted
endfunction

private function UnitFilter takes nothing returns boolean
    local boolean ret = false
    if not(IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL)) and not(IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE)) then   
        set ret = IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND) and  (GetWidgetLife(GetFilterUnit()) > 0.405)
    endif
    return ret
endfunction


///////////////////////////////////Main Struckt//Do not change//////////////////////////////////////////////

private struct Missiles
    static integer Index = 0
    static Missiles array Data
    unit array missiles [2] // The 2 missiles
    real angle
    real x
    real y
    real a
    unit caster
    group DamagedUnits // group to avoid damaging a unit twice
    real rangeleft
    integer level
    static method create takes nothing returns Missiles
        local Missiles data = Missiles.allocate()
        set Missiles.Data[Missiles.Index] = data
        set Missiles.Index = Missiles.Index + 1
        return data
    endmethod
endstruct

////////////////////////////////Main script// Do not edit unless you understand it////////////////////////////////

private function callback takes nothing returns nothing
    local Missiles data
    local integer i = 0
    local real x = 0.00
    local real y = 0.00
    local real z = 0
    local integer a = 0
    local unit b = null
    local unit dummy = null
    local real radius
    local real scale
   
    // looping through all structs
    loop
        exitwhen i >= Missiles.Index
        set data = Missiles.Data[i]
        set a = 0     
        set z = data.rangeleft / MissileRangePerLevel(data.level)
        set scale = EndScale+(StartScale-EndScale)*z
        set radius = SpinEndRadius+(SpinStartRadius-SpinEndRadius)*z
       
        // Moving the missiles and setting their scale ect. depending on the left range
        call SetUnitX(data.missiles[0], data.x + MissileSpeed * Cos(data.angle) + Cos(data.angle+1.5708) * Cos(data.a) * radius)
        call SetUnitY(data.missiles[0], data.y + MissileSpeed * Sin(data.angle) + Sin(data.angle+1.5708) * Cos(data.a) * radius)
        call SetUnitFlyHeight(data.missiles[0], MissileHeight + Cos(data.a+1.5708) * radius, 1000)
        call SetUnitScale(data.missiles[0],scale,scale,scale)
        call SetUnitX(data.missiles[1], data.x + MissileSpeed * Cos(data.angle) + Cos(data.angle+1.5708) * Cos(data.a+3.14159) * radius)
        call SetUnitY(data.missiles[1], data.y + MissileSpeed * Sin(data.angle) + Sin(data.angle+1.5708) * Cos(data.a+3.14159) * radius)
        call SetUnitFlyHeight(data.missiles[1], MissileHeight + Cos(data.a-1.5708) * radius, 1000)
        call SetUnitScale(data.missiles[1],scale,scale,scale)
        set data.x = data.x + MissileSpeed * Cos(data.angle)
        set data.y = data.y + MissileSpeed * Sin(data.angle)
        set data.a = data.a + SpinRate
        set data.rangeleft = data.rangeleft - MissileSpeed
        set a = 0
        // looping through all units in range
        call GroupEnumUnitsInRange(ENUM_GROUP, data.x, data.y,radius + AdditionalDamageRange, filter)
        loop
            set b = FirstOfGroup(ENUM_GROUP)
            exitwhen b==null
            call GroupRemoveUnit(ENUM_GROUP,b)
            //checking if they are alrady damaged
            if IsUnitInGroup(b,data.DamagedUnits) == false and DealDamageCondition(b,data.caster) then
                //damaging + casting buff

                call GroupAddUnit(data.DamagedUnits,b)
                call UnitDamageTarget(data.caster,b,DamagePerLevel(data.level),true, false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
                call DestroyEffect(AddSpecialEffectTarget(DamageEffect, b, "chest") )
                call SetUnitX(Dummy,GetUnitX(b))
                call SetUnitY(Dummy,GetUnitY(b))
                call SetUnitAbilityLevel(Dummy,MindBurstEffectSpell,data.level)
                call IssueTargetOrder( Dummy,  EffectOrderID,b )
                // Checking if unit has mana to steal it
                if ManaDrainCondition(b) then
                    call DestroyEffect(AddSpecialEffectTarget(HealEffect, data.caster, "origin") )
                    if (GetUnitState(b,UNIT_STATE_MANA) > StolenManaPerLevel(data.level)) then
                        call SetUnitState(b, UNIT_STATE_MANA,GetUnitState(b,UNIT_STATE_MANA)-StolenManaPerLevel(data.level))
                        call SetUnitState(data.caster, UNIT_STATE_MANA,GetUnitState(data.caster,UNIT_STATE_MANA)+StolenManaPerLevel(data.level))
                    else
                        call SetUnitState(data.caster, UNIT_STATE_MANA,GetUnitState(data.caster,UNIT_STATE_MANA)+GetUnitState(b,UNIT_STATE_MANA))
                        call SetUnitState(b, UNIT_STATE_MANA,0)
                    endif
                endif
            endif
        endloop
        call GroupClear(ENUM_GROUP)
       
        // Checking if the missiles reached their end point
        if data.rangeleft < 0 then
            call DestroyEffect(AddSpecialEffect(MissilesDeath,data.x,data.y) )
            // destryoing the missiles
            call RemoveUnit(data.missiles[0])
            set data.missiles[0] = null
            call RemoveUnit(data.missiles[1])
            set data.missiles[1] = null
            call DestroyGroup(data.DamagedUnits)
            set data.DamagedUnits = null
            set data.caster = null
            call Missiles.destroy(data)
            set Missiles.Data[i] = Missiles.Data[Missiles.Index - 1]
            set i = i - 1
            set Missiles.Index = Missiles.Index - 1
        endif
        set i = i + 1
    endloop
    set b = null
    set dummy = null
   
endfunction

private function Actions takes nothing returns nothing
    local integer i = Missiles.Index
    local unit caster = GetTriggerUnit()
    local integer level = GetUnitAbilityLevel(caster,MindBurstSpell)
    local real angle = Atan2(GetLocationY(GetSpellTargetLoc()) - GetUnitY(caster), GetLocationX(GetSpellTargetLoc()) - GetUnitX(caster))
    local real x = GetUnitX(caster) + ReleaseDistance * Cos(angle)
    local real y = GetUnitY(caster) + ReleaseDistance * Sin(angle)
   
    // Creating the Struct
    call Missiles.create()
    set Missiles.Data[i].caster = caster
    set Missiles.Data[i].angle = angle
    set Missiles.Data[i].rangeleft = MissileRangePerLevel(level)
    set Missiles.Data[i].level = level
    set Missiles.Data[i].x = x
    set Missiles.Data[i].y = y
    set Missiles.Data[i].DamagedUnits = CreateGroup()
    set Missiles.Data[i].missiles[0] = CreateUnit(GetOwningPlayer(caster), DummyID , x , y , angle * 57.296)
    set Missiles.Data[i].missiles[1] = CreateUnit(GetOwningPlayer(caster), DummyID , x , y , angle * 57.296)
    if Missiles.Data[i].Index == 1 then
        call TimerStart(t, TimerPeriod, true, function callback)
    endif
    set caster = null
   
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger tr = CreateTrigger()
    set filter = Filter(function UnitFilter)
    set Dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),CastDummyID,0,0,0)
    call UnitAddAbility(Dummy,MindBurstEffectSpell)
    call TriggerRegisterAnyUnitEventBJ(tr,EVENT_PLAYER_UNIT_SPELL_CAST)
    call TriggerAddCondition( tr,Condition( function RunCondition ) )
    call TriggerAddAction( tr, function Actions )
   
    //Preloading the used effect models
    call Preload(DamageEffect)
    call Preload(HealEffect)
    call Preload(MissilesDeath)
endfunction

endscope

Thanks to Hanky for helping me to improve the script
Thanks to Rising_Dusk for Feedback


Keywords:
Live, Distortion, Mind, Burst, Mana, drain, hp, heal, steal, missile, Essence, JonNny
Contents

Live Distortion (Map)

Reviews
10:33, 21st Jun 2009 Coding: 3.99/5 The coding is good overall, but has a few small errors you probably just overlooked. Oddly, you decrease the struct index in not very ideal places. Since JASS tags are bugged, I guess I'll have to use code tags...

Moderator

M

Moderator

10:33, 21st Jun 2009

Coding: 3.99/5
The coding is good overall, but has a few small errors you probably just overlooked. Oddly, you decrease the struct index in not very ideal places. Since JASS tags are bugged, I guess I'll have to use code tags.
Code:
            set Essences.Data[i] = Essences.Data[Essences.Index - 1]
            set i = i - 1
            set Essences.Index = Essences.Index - 1
I think you'll see how that can easily be re-arranged. The use of your create method could be improved so you would no longer have to subtract 1 from the index in your 'Actions' function. You also use a local integer in your Init functions that you never use. Oh, and what's with the inlined bj_PI?

Originality: 5/5
The effects are great. I haven't see anything quite like them.

Documentation: 5/5
Any more documentation would be excessive, really.

Overall = (Coding * 0.50) + (Originality * 0.30) + (Documentation * 0.20)
Overall: 4.495
Approved with a 4/5 (Recommended) rating.
 
Level 17
Joined
Sep 8, 2007
Messages
994
Wow, awesome spell!!! :)
The code seems good, documentation is good as well.
The only thing I recommend you to fix is the buff tooltip for affected targets :p
I also don't really like the tooltip style for the spell you're having right now but that's a matter of taste so it is your descision!
Anyway, epic spell! 5/5 +rep from me!
 
Last edited:
Level 16
Joined
Feb 22, 2006
Messages
960
nice idea the spell but the script is somehow hmm^^....it's a chaos script :D :D
the documentation is good, but you should set the constant values constant then maybe create a real filter instead of a nullfilter, because then you don't need a if/then construction in your group loop.
Also maybe set 3.14159 as a constant, then why using static counte/stackarray and then not a static timer (just for the overview it would be better)
Then there are some more values you could set as constant global values, like number of missiles, heal and range
My last point: Maybe use a group recycler for your local group :)

But all in all I like the spell the things are just small flaws , realy small^^
4/5
 
Level 15
Joined
Jul 19, 2007
Messages
618
wow nice spell -JonNny!

effects are looking so great awesome idea of what a single spell should do nice a little different math then usuall makes it look even cooler...

ok now to coding OMG something like for the first time no boolexpr table leaks xD
i did not beleve it and must say gj on it really!

k i went future in code and checked out how you coded it seems leakless and MUI for the most of the part but then when i came in that init function!

i saw that you leak 15 -> triggercondition's and 15 -> conditionfunc's thats actually not some of your bugs spell works fine but while coding i am sure you misstyped that TriggerAddCondition in that 16x loop to fix it plz remove it from loop that shall do it.

and the second thing is i would like you to cnp that NullFilter function from map header to your scope and make it private. when i made my recipe system i had problems with people not knowing where map header is even if i wrote how in description but still...

so to make it easier to install just cnp it in your code you could make it private and constant since it returns always same value function can be constant (note: filter functions like yours is not inlined) thats why you could make it constant

ok fix this 2 things and its 5/5 from me then...


now few suggestions:

1. make global boolexpr which will = to Filter(function NullFilter) -> init it in your init function and always use that filter instead of generating it whole the time... do note that if you use that global one just dont destroy or null it

2. in your large loop replace your looping throught units by slow jass loop to fast pointer c++ ForGroup loop

3. maybe add a little documentation for this newbies out there that dont know how to install this spell...

thats all!

the spell is easy editable gj on that as well. this simple globals up there do there work so even GUI people can use this without problem in there map

for now 4.3/5 -> fix first two i pointed and it will be 5/5 suggestions are not needed to be 5/5

~Dark Dragon
 
Level 25
Joined
Jun 5, 2008
Messages
2,572
Really nice idea but you should fix the buff tooltip and maybe add a filter when it defines the units under the effect so that it cannot stack(pretty imba with stacking)...
I liked the eyecandy and the effect is really nice...
[offtop]
I think this was going to be one of the spells for the S&S 18, theme synergy, right?
 
Level 15
Joined
Jan 31, 2007
Messages
502
Really nice idea but you should fix the buff tooltip and maybe add a filter when it defines the units under the effect so that it cannot stack(pretty imba with stacking)...
I liked the eyecandy and the effect is really nice...
[offtop]
I think this was going to be one of the spells for the S&S 18, theme synergy, right?

Hmm.. if thats that important i can add a buff tooltip
I think stacking is not imba, just add a tooltip - this is just a demo for testing

Yep it was started for the contest but i didnt make a second spell, maybe ill add it later
 
Level 2
Joined
May 17, 2009
Messages
16
I would have liked for you to have added variables that users can change in setup to modify the damage dealt and healing/mana recieved, instead of actually changing the numbers in the formulas.

Right now you have them as strict numbers; for instance "return 200.00 + 40.00 * level" in Live Distortion. It would have been more user friendly if you have made numOfMissles,range, and dmg variables.

Good spell though, +rep.
 
Level 6
Joined
Nov 10, 2006
Messages
181
JASS:
private function UnitFilter takes nothing returns boolean
    if not(IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL)) and not(IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE)) then
        return IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND) and  (GetWidgetLife(GetFilterUnit()) > 0.405)
    endif
    return false
endfunction

>=
JASS:
private function UnitFilter takes nothing returns boolean
        return not(IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL)) and not(IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE)) and  IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND) and  (GetWidgetLife(GetFilterUnit()) > 0.405)
endfunction

Handwritten, expect errors but you should know what I mean.
 
Level 6
Joined
Nov 10, 2006
Messages
181
I have no idea why will it not work that way? I'm not familar with IsUnitTypeBug.

I think it would work as I don't have such problems, try testing it?
 
Level 15
Joined
Jan 31, 2007
Messages
502
It does not bug and it never did

Maybe i should have changed that because of the editability of the script
or because of making it less complex
or whatever, because they just want to have it that way...as mentioned - most people on Wc3c are perfectionists
they always find anything about your script which is not really necessary imo
 
Level 15
Joined
Jul 19, 2007
Messages
618
and i cant open it each time i starts it i only comes too wc3 start place where u can chose singelplayer or local game

happend to me to! its coz of different JH version or simply wc version! u know there are 1.23b (beta), 1.24 (beta), 1.24 (full), 1.24b (beta)!

i have 1.24b (beta) and was unable to load the game, but after i compiled his map with my 0.9.I.2 JH compiler it worked... so just compile it twice insted of once (only for the first time)
 
Top