Spellpack Earth Panda Spellpack

Kenny

Back for now.
Reaction score
202
Earth Panda Spellpack
by kenny!
v1

Introduction:

These are some spells i have been working on due to my boredom the past couple of weeks. Alone they were nothing special, however they make a pretty cool spellpack.

This spellpack includes:

  • Seismic Slam;
  • Stone Guardians;
  • Stone Skin; and
  • Earth Prison.

Technical Details:

  • These spells are done in vJASS, therefore need NewGen World Editor.
  • They are MUI/MPI and all that.
  • They are leakless and lagless (expect for some first cast lag which i may fix).
  • They do not require any other systems.
  • They have been built around a theme (Earth / Interruption spells) and therefore they work pretty well together.
  • They are pretty cool.

The Spells:

Seismic Slam:

Import Difficulty: Easy-Medium

Description:

Leaps forward, spinning in the air at a tremendous rate towards a target location. Upon impact, enemy ground units in the area are dealt damage and stunned.

Level 1 - Deals 50 Damage, 0.45 second stun. Leap takes 1.30 seconds. Maximum distance of 300.

Level 2 - Deals 100 Damage, 0.60 second stun. Leap takes 1.15 seconds. Maximum distance of 450.

Level 3 - Deals 150 Damage, 0.75 second stun. Leap takes 1.00 seconds. Maximum distance of 600.

Level 4 - Deals 200 damage, 0.90 second stun. Leap takes 0.85 seconds. Maximum distance of 750.

Cooldown: 18 seconds

Screenshot:

He's jumping not lying down...
SeismicSlam.jpg

The script

JASS:
scope SeismicSlam initializer Init

globals
// Configurables:

// Skills:
    private constant integer Abil_id = 'A000'
    // Raw code of the main hero ability.
    private constant integer Abil2_id = 'A007'
    // Raw code of the stomp used at the end.
    private constant integer Flytrick = 'Amrf'
    // Raw code for "Crow Form". Does not need to be changed in most cases.
    
// Units:
    private constant integer Dummy_id = 'u001'
    // Raw code of the dummy "spinning" unit used for the leap.
    private constant integer Treedummy_id = 'u000'
    // Raw code of the dummy unit used to destroy trees.

// Others:
    private constant real Interval = 0.04   // Interval for periodic timer.
    private constant real Diff = 0.00       // Distance from cast point that the unit will land.
    private constant real Timescale = 3.00  // How fast the unit spins.
    private constant string End_anim = "spell slam"
    // End animation of the unit.
    private constant string Dirt_sfx = "NewDirtEXNofire.mdx"
    // Effect made at the end of the spell on land.
    private constant string Water_sfx = "Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl"
    // Same as above but for landing on water.
    private constant boolean Destroytrees = true
    // Whether or not to destroy trees.
    private constant boolean AllowPreload = true
    // Whether or not to allow preloading of the effects.
endglobals

//=======================================================================
private function Area takes integer lvl returns real
    return 225.00 // Area of effect for destroying trees.
endfunction

private function Airtime takes integer lvl returns real
    return 1.45-(0.15*lvl) // Air time of the leap.
endfunction

//=======================================================================//
//  DO NOT TOUCH PAST THIS POINT UNLESS YOU KNOW WHAT YOUR ARE DOING!!   //
//=======================================================================//

private keyword Data

globals
    private integer Total = 0                   
    private Data array D
    private timer Timer = null
    private rect Rect1 = null
    private boolexpr Treefilt = null
    private boolexpr Truefilt = null
    private unit Treedummy = null
    private real Game_maxX = 0.00
    private real Game_minX = 0.00
    private real Game_maxY = 0.00
    private real Game_minY = 0.00
endglobals

//=======================================================================
private function KillEnumDestructables takes nothing returns nothing
    call KillDestructable(GetEnumDestructable())
endfunction

private function TreeCheck takes nothing returns boolean
    local destructable dest = GetFilterDestructable()
    local boolean result
    
    if GetDestructableLife(dest) > 0.405 then
        call ShowUnit(Treedummy,true)
        call SetUnitX(Treedummy,GetWidgetX(dest))
        call SetUnitY(Treedummy,GetWidgetY(dest))
        
        set result = IssueTargetOrder(Treedummy,"harvest",dest)
        call IssueImmediateOrder(Treedummy,"stop")
        call ShowUnit(Treedummy,false)

        return result
    endif
    
    set dest = null
    return false
endfunction

//=======================================================================
private function SafeX takes real x returns real
    if x<Game_minX then
        return Game_minX
    elseif x>Game_maxX then
        return Game_maxX
    endif
    return x
endfunction

private function SafeY takes real y returns real
    if y<Game_minY then
        return Game_minY
    elseif y>Game_maxY then
        return Game_maxY
    endif
    return y
endfunction

//=======================================================================
private function MoveDist takes real Maxdist, integer lvl returns real
    return Maxdist/(Airtime(lvl)/Interval)
endfunction

private function ConvertCount takes integer i, integer lvl returns real
    return (50.00/(Airtime(lvl)/Interval))*i
endfunction

//=======================================================================
private struct Data
    unit cast
    unit dum
    real castx
    real casty
    real cos
    real sin
    real maxdist
    real movedist
    integer i = 1
    integer lvl
    
    static method create takes nothing returns Data
        local Data d = Data.allocate()
        local location loc
        local real angle
        local real targx
        local real targy
        
        set d.cast = GetTriggerUnit()
        set d.castx = GetUnitX(d.cast)
        set d.casty = GetUnitY(d.cast)
        set loc = GetSpellTargetLoc()
        set angle = Atan2((GetLocationY(loc)-d.casty),(GetLocationX(loc)-d.castx))
        set d.cos = Cos(angle)
        set d.sin = Sin(angle)
        set targx = GetLocationX(loc)-Diff*d.cos
        set targy = GetLocationY(loc)-Diff*d.sin
        set d.lvl = GetUnitAbilityLevel(d.cast,Abil_id)
        set d.maxdist = SquareRoot((targx-d.castx)*(targx-d.castx)+(targy-d.casty)*(targy-d.casty))
        set d.movedist = MoveDist(d.maxdist,d.lvl)
        
        set d.dum = CreateUnit(GetOwningPlayer(d.cast),Dummy_id,d.castx,d.casty,angle*bj_RADTODEG)
        call UnitAddAbility(d.dum,Flytrick)
        call UnitRemoveAbility(d.dum,Flytrick)
        call SetUnitTimeScale(d.dum,Timescale)    
        call SetUnitPathing(d.dum,false) 
        call PauseUnit(d.dum,true)
        call ShowUnit(d.cast,false)
        
        set Total = Total + 1
        if Total == 1 then
            call TimerStart(Timer,Interval,true,function Data.Update)
        endif
        set D[Total] = d
        
        call RemoveLocation(loc)
        set loc = null
            
        return d
    endmethod
    
    static method Update takes nothing returns nothing
        local integer i = 1
        local real count
        local real height
        local real speed
        local real newx
        local real newy
        
        loop
            exitwhen i > Total
            
            if D<i>.i &lt; (Airtime(D<i>.lvl) / Interval) then
                set count = ConvertCount(D<i>.i,D<i>.lvl)
                set height = (count-25.00) * (count-25.00)
                set speed = D<i>.i * D<i>.movedist
                set newx = D<i>.castx + speed * D<i>.cos
                set newy = D<i>.casty + speed * D<i>.sin
                call SetUnitPosition(D<i>.dum,SafeX(newx),SafeY(newy))
                call SetUnitPosition(D<i>.cast,SafeX(newx),SafeY(newy))
                call SetUnitFlyHeight(D<i>.dum,625.00-height,0.00)
                call SetUnitFlyHeight(D<i>.cast,625.00-height,0.00)
                set D<i>.i = D<i>.i + 1
            else
                call D<i>.destroy()
                set D<i> = D[Total]
                set Total = Total - 1
                set i = i - 1
            endif
            
            set i = i + 1
        endloop
        
        if Total &lt;= 0 then
            call PauseTimer(Timer)
            set Total = 0
        endif
    endmethod
    
    private method onDestroy takes nothing returns nothing
        local real newx = GetUnitX(.dum) + Diff * .cos
        local real newy = GetUnitY(.dum) + Diff * .sin
        local unit u = CreateUnit(GetOwningPlayer(.cast),Treedummy_id,newx,newy,0.00)
        
        call SetUnitFlyHeight(.dum,GetUnitDefaultFlyHeight(.cast),0.00)
        call PauseUnit(.dum,false)
        call SetUnitPathing(.dum,true)
        
        if Destroytrees then
            call SetRect(Rect1,newx-Area(.lvl),newy-Area(.lvl),newx+Area(.lvl),newy+Area(.lvl))
            call EnumDestructablesInRect(Rect1,Treefilt,function KillEnumDestructables)
        endif
        
        call UnitAddAbility(u,Abil2_id)
        call SetUnitAbilityLevel(u,Abil2_id,.lvl)
        call IssueImmediateOrder(u,&quot;stomp&quot;)
        call UnitApplyTimedLife(u,&#039;BTLF&#039;,1.00)
        if IsTerrainPathable(GetUnitX(u),GetUnitY(u),PATHING_TYPE_FLOATABILITY) then
            call DestroyEffect(AddSpecialEffect(Dirt_sfx,newx,newy))
        elseif not IsTerrainPathable(GetUnitX(u),GetUnitY(u),PATHING_TYPE_WALKABILITY) then
            call DestroyEffect(AddSpecialEffect(Water_sfx,newx,newy))
        endif
        
        call RemoveUnit(.dum)
        call SetUnitPosition(.cast,newx,newy)
        call ShowUnit(.cast,true)
        call SetUnitAnimation(.cast,End_anim)
        
        if GetLocalPlayer() == GetOwningPlayer(.cast) then
            call ClearSelection()
            call SelectUnit(.cast,true)
        endif
        
        set .cast = null
        set .dum = null
        set u = null
    endmethod                
endstruct
    
//=======================================================================
private function Actions takes nothing returns nothing 
    call Data.create()
endfunction    

//=======================================================================
private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == Abil_id
endfunction

//=======================================================================
private function TrueFilt takes nothing returns boolean
    return true
endfunction

//=======================================================================
private function Init takes nothing returns nothing
    local trigger trig = CreateTrigger()
    local integer i = 0
    
    set Timer = CreateTimer()
    set Rect1 = Rect(0.00,0.00,1.00,1.00)
    set Treefilt = Filter(function TreeCheck)
    
    set Game_maxX = GetRectMaxX(bj_mapInitialPlayableArea)-64.00
    set Game_maxY = GetRectMaxY(bj_mapInitialPlayableArea)-64.00
    set Game_minX = GetRectMinX(bj_mapInitialPlayableArea)+64.00
    set Game_minY = GetRectMinY(bj_mapInitialPlayableArea)+64.00
    
    set Truefilt = Filter(function TrueFilt)
    
    loop
        call TriggerRegisterPlayerUnitEvent(trig,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,Truefilt)
        set i = i + 1
        exitwhen i == bj_MAX_PLAYER_SLOTS
    endloop
    
    call TriggerAddCondition(trig,Condition(function Conditions))
    call TriggerAddAction(trig,function Actions)
    
    set Treedummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),Treedummy_id,0.00,0.00,0.00)
    call SetUnitPathing(Treedummy,false)
    call ShowUnit(Treedummy,false)
    
    if AllowPreload then
        call KillUnit(CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),Dummy_id,0.00,0.00,0.00))
        call DestroyEffect(AddSpecialEffect(Dirt_sfx,0.00,0.00))
        call DestroyEffect(AddSpecialEffect(Water_sfx,0.00,0.00))
    endif
endfunction

endscope</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>



Stone Guardians:

Import Difficulty: Easy-Medium

Credits: emjlr3 for formula help.

Description:

Calls forth stone guardians to protect the target unit. These guardians will damage any enemy unit that comes near the target, knocking them back in the process. The target unit gets +2 armour for each stone guardian if the Stone Panda has at least one level into Stone Skin.

Lasts 12 seconds.

Level 1 - Summons 2 guardians, each guardian deals 45 damage and knocks a unit back a very short distance.

Level 2 - Summons 3 guardians, each guardian deals 55 damage and knocks a unit back a very short distance.

Level 3 - Summons 4 guardians, each guardian deals 65 damage and knocks a unit back a short distance.

Level 4 - Summons 5 guardians, each guardian deals 75 damage and knocks a unit back a short distance.

Cooldown: 28/24/20/16 seconds

Screenshot:

StoneGuardians.jpg

The script:

JASS:
scope StoneGuardians initializer Init

globals
// Configurables:

// Skills:
    private constant integer Abil_id = &#039;A008&#039;
    // Raw code for the main hero ability.
    private constant integer Abil2_id = &#039;A00B&#039;
    // Raw code for the Stone Skin hero ability.
    private constant integer Abil3_id = &#039;A00C&#039;
    // Raw code for the SG Armour Bonus ability.

// Units:
    private constant integer Dummy_id = &#039;u002&#039;
    // Raw code for the stone guardian dummy unit.

// Others:
    private constant real Interval = 0.04   // Interval for periodic timer.
    private constant real Height = 30.00    // height of the stones.
    private constant real Collision = 60.00 // How close a unit must be to get hit by a stone.
    private constant real Distance = 150.00 // Distance from the target at which units are created.
    
    private constant string Start_sfx = &quot;Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl&quot; 
    // Special effect used when the stones are created.
    private constant string Dirt_sfx = &quot;Dust.mdx&quot;
    // Special effect used for when units are knocked back.
    private constant string Water_sfx = &quot;SlideWater.mdx&quot;
    // Same as above but for when units are on water.
    private constant string Point = &quot;origin&quot;
    // Attachment point for Dirt_sfx and Water_sfx.
    private constant boolean Allowmove = false
    // Whether or not units are allowed to move while being knocked back.
    private constant boolean AllowPreload = false
    // Whether or not to allow preloading of the effects.
    
    // Attack/Damage/Weapon types of damage dealt.
    private constant attacktype A_type = ATTACK_TYPE_CHAOS
    private constant damagetype D_type = DAMAGE_TYPE_UNIVERSAL
    private constant weapontype W_type = WEAPON_TYPE_WHOKNOWS
endglobals

//=======================================================================
private function MaxDuration takes integer lvl returns real
    return 12.00 // Duration of the stone guardians.
endfunction

private function KnockDuration takes integer lvl returns real
    return 1.00 // Knockback duration.
endfunction

private function KnockDistance takes integer lvl returns real
    return 100.00+(25.00*lvl) // Knockback distance.
endfunction

private function StoneNumber takes integer lvl returns integer
    return 1+(1*lvl) // Number of stones per level. Try to keep it under 9 if you dont know how to change it.
endfunction

private function Damage takes integer lvl returns real
    return 35.00+(10.00*lvl) // Damage dealt when stones hit units.
endfunction

private function Speed takes integer lvl returns real
    return 325.00-(25.00*lvl) // The speed at which the stones rotate around the target.
endfunction
    
//=======================================================================//
//  DO NOT TOUCH PAST THIS POINT UNLESS YOU KNOW WHAT YOUR ARE DOING!!   //
//=======================================================================//

private keyword Data
private keyword Knock
    
globals
    private boolexpr Enemyfilt
    private boolexpr Truefilt
    private timer Timer = null
    private integer DT = 0
    private integer KT = 0
    private Data array D
    private Knock array K
    private real Game_maxX = 0.00
    private real Game_minX = 0.00
    private real Game_maxY = 0.00
    private real Game_minY = 0.00
endglobals

//=======================================================================
private function IsPointOutside takes real x, real y returns boolean
    return (x &gt; Game_maxX or y &gt; Game_maxY or x &lt; Game_minX or y &lt; Game_minY)
endfunction

private function TerrainType takes unit u returns integer
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
        
    if IsTerrainPathable(x,y,PATHING_TYPE_FLOATABILITY) then
        return 1
    elseif not IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
        return 2
    endif
        
    return 0
endfunction

//=======================================================================
private struct Data
    unit cast
    unit targ
    unit array stone[10]
    integer stones = 0
    integer alive = 0
    integer dead = 0
    integer lvl = 0
    real time = 0.00
    real speed = 0.00
    real array ang[10]
    group g = CreateGroup()
    
    private method onDestroy takes nothing returns nothing
        local integer i = 1
        
        loop
            exitwhen i &gt; .stones
            if GetWidgetLife(.stone<i>) &gt; 0.405 then
                call KillUnit(.stone<i>)
                set .stone<i> = null
            endif
            set i = i + 1
        endloop
        
        if GetUnitAbilityLevel(.targ,Abil3_id) &gt; 0 then
            call UnitRemoveAbility(.targ,Abil3_id)
        endif
        
        set .cast = null
        call GroupClear(.g)
        call DestroyGroup(.g)
    endmethod
endstruct

//=======================================================================
private struct Knock
    unit targ
    real speed = 0.00
    real decrease = 0.00
    real cos = 0.00
    real sin = 0.00
    effect sfx
    integer sfxmode
    
    private method onDestroy takes nothing returns nothing
        set .targ = null
        if .sfx != null then
            call DestroyEffect(.sfx)
            set .sfx = null
        endif
    endmethod
endstruct

//=======================================================================
private function FilterEnemies takes nothing returns boolean
    return GetWidgetLife(GetFilterUnit()) &gt; 0.405 and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) == false
endfunction

//=======================================================================
private function Update takes nothing returns nothing
    local integer h = 1
    local integer i = 1
    local integer j = 1
    local Knock k = 0
    local integer newmode
    local real targx
    local real targy
    local real newx
    local real newy
    local real dist
    local real ang
    local real diff
    local unit u
    
    loop
        exitwhen i &gt; DT
        
        if D<i>.time &gt; MaxDuration(D<i>.lvl) or D<i>.dead == D<i>.stones or GetWidgetLife(D<i>.targ) &lt; 0.405 then
            call D<i>.destroy()
            set D<i> = D[DT]
            set DT = DT - 1
            set i = i - 1
        else 
            set targx = GetUnitX(D<i>.targ)
            set targy = GetUnitY(D<i>.targ)
            
            if GetUnitAbilityLevel(D<i>.targ,Abil3_id) &gt; 0 then
                call SetUnitAbilityLevel(D<i>.targ,Abil3_id,D<i>.alive)
            elseif GetUnitAbilityLevel(D<i>.targ,Abil3_id) == 0 and GetUnitAbilityLevel(D<i>.cast,Abil2_id) &gt; 0 then
                call UnitAddAbility(D<i>.targ,Abil3_id)
                call SetUnitAbilityLevel(D<i>.targ,Abil3_id,D<i>.alive)
            endif
            
            loop
                exitwhen j &gt; D<i>.stones
                if GetWidgetLife(D<i>.stone[j]) &gt; 0.405 then
                    call SetUnitX(D<i>.stone[j],targx + Distance * Cos(D<i>.ang[j]*bj_DEGTORAD))
                    call SetUnitY(D<i>.stone[j],targy + Distance * Sin(D<i>.ang[j]*bj_DEGTORAD))
                    call SetUnitFlyHeight(D<i>.stone[j],GetUnitFlyHeight(D<i>.targ)+Height,0.00)
                    set D<i>.ang[j] = D<i>.ang[j] + D<i>.speed
                    
                    call GroupEnumUnitsInRange(D<i>.g,GetUnitX(D<i>.stone[j]),GetUnitY(D<i>.stone[j]),Collision,Enemyfilt)
                    loop
                        set u = FirstOfGroup(D<i>.g)
                        exitwhen u == null
                        call GroupRemoveUnit(D<i>.g,u)
                        if IsUnitEnemy(u,GetOwningPlayer(D<i>.cast)) and (GetUnitFlyHeight(u) &gt;= (GetUnitFlyHeight(D<i>.stone[j])-(Height*2.00)) and GetUnitFlyHeight(u) &lt;= (GetUnitFlyHeight(D<i>.stone[j])+(Height*2.00))) then
                            call UnitDamageTarget(D<i>.cast,u,Damage(D<i>.lvl),false,false,A_type,D_type,W_type)
                            set k = Knock.create()
                            set k.targ = u
                            set ang = Atan2(GetUnitY(k.targ)-GetUnitY(D<i>.stone[j]),GetUnitX(k.targ)-GetUnitX(D<i>.stone[j]))
                            set k.speed = (2.00*KnockDistance(D<i>.lvl)) / (KnockDuration(D<i>.lvl)/Interval)
                            set k.decrease = k.speed / (KnockDuration(D<i>.lvl)/Interval)
                            set k.sfxmode = TerrainType(k.targ)
                            if k.sfxmode == 1 then
                                set k.sfx = AddSpecialEffectTarget(Dirt_sfx,k.targ,Point)
                            elseif k.sfxmode == 2 then
                                set k.sfx = AddSpecialEffectTarget(Water_sfx,k.targ,Point)
                            endif                                
                            set k.cos = Cos(ang)
                            set k.sin = Sin(ang)
                            
                            set KT = KT + 1
                            set K[KT] = k
                            
                            call KillUnit(D<i>.stone[j])
                            set D<i>.dead = D<i>.dead + 1
                            set D<i>.alive = D<i>.alive - 1
                            set u = null
                        endif
                    endloop
                endif
                
                set j = j + 1
            endloop
            
            set j = 1
            
            // Thanks to emjlr3 for his help with this. Below is basically his idea.
            loop
                exitwhen j &gt; D<i>.stones
                
                if GetWidgetLife(D<i>.stone[j]) &gt; 0.405 then
                    if j != D<i>.stones and D<i>.alive != 1 then
                        set h = j + 1
                        loop
                            exitwhen h == j or GetWidgetLife(D<i>.stone[h]) &gt; 0.405
                            if h &gt; D<i>.stones then
                                set h = 1
                            else
                                set h = h + 1
                            endif
                        endloop
                        if h != j then
                            if h &gt; j then
                                set diff = D<i>.ang[h] - D<i>.ang[j]
                            else
                                set diff = D<i>.ang[j] - D<i>.ang[h]
                            endif
                            if diff &gt; (360.00 / D<i>.alive) then
                                set D<i>.ang[j] = D<i>.ang[j] + 1.00
                            elseif diff &lt; (360.00 / D<i>.alive) then
                                set D<i>.ang[j] = D<i>.ang[j] - 1.00
                            endif
                        endif
                    endif
                endif
                    
                set j = j + 1
            endloop
            
            set D<i>.time = D<i>.time + Interval
            set j = 1
        endif
        
        set i = i + 1
    endloop
    
    set i = 1

    loop
        exitwhen i &gt; KT
        set newmode = K<i>.sfxmode
        
        set newx = GetUnitX(K<i>.targ)
        set newy = GetUnitY(K<i>.targ)
        
        set K<i>.sfxmode = TerrainType(K<i>.targ)
        
        if K<i>.sfxmode == 1 and newmode == 2 then
            call DestroyEffect(K<i>.sfx)
            set K<i>.sfx = AddSpecialEffectTarget(Dirt_sfx,K<i>.targ,Point)
        elseif K<i>.sfxmode == 2 and newmode == 1 then
            call DestroyEffect(K<i>.sfx)
            set K<i>.sfx = AddSpecialEffectTarget(Water_sfx,K<i>.targ,Point)
        endif
        
        if K<i>.speed &lt;= 0.00 or IsPointOutside(newx,newy) or GetWidgetLife(K<i>.targ) &lt; 0.405 then
            call K<i>.destroy()
            set K<i> = K[KT]
            set KT = KT - 1
            set i = i - 1
        else
            set newx = newx + K<i>.speed * K<i>.cos
            set newy = newy + K<i>.speed * K<i>.sin
            
            if Allowmove then
                call SetUnitX(K<i>.targ,newx)
                call SetUnitY(K<i>.targ,newy)
            else
                call SetUnitPosition(K<i>.targ,newx,newy)
            endif
            
            set K<i>.speed = K<i>.speed - K<i>.decrease
        endif
        
        set i = i + 1
    endloop
    
    if DT &lt;= 0 and KT &lt;= 0 then
        call PauseTimer(Timer)
        set DT = 0
        set KT = 0
    endif
endfunction

//=======================================================================
private function Actions takes nothing returns nothing
    local Data d = Data.create()
    local integer i = 1
    local real targx
    local real targy
    local real newx
    local real newy
    local real ang
    
    set d.cast = GetTriggerUnit()
    set d.targ = GetSpellTargetUnit()
    set targx = GetUnitX(d.targ)
    set targy = GetUnitY(d.targ)
    set d.lvl = GetUnitAbilityLevel(d.cast,Abil_id)
    set d.speed = Speed(d.lvl) / (1.00/Interval)
    set d.stones = StoneNumber(d.lvl)
    set d.alive = d.stones
    set ang = 360.00 / d.stones
    
    loop
        exitwhen i &gt; d.stones
        set newx = targx + Distance * Cos((ang*i)*bj_DEGTORAD)
        set newy = targy + Distance * Sin((ang*i)*bj_DEGTORAD)
        set d.stone<i>= CreateUnit(GetOwningPlayer(d.cast),Dummy_id,newx,newy,0.00)
        call DestroyEffect(AddSpecialEffect(Start_sfx,newx,newy))
        call SetUnitFlyHeight(d.stone<i>,GetUnitFlyHeight(d.targ)+Height,0.00)
        set d.ang<i> = ang * i
        set i = i + 1
    endloop
    
    if GetUnitAbilityLevel(d.cast,Abil2_id) &gt; 0 then
        call UnitAddAbility(d.targ,Abil3_id)
        call SetUnitAbilityLevel(d.targ,Abil3_id,d.stones)
    endif
    
    set DT = DT + 1
    if DT == 1 and KT == 0 then
        call TimerStart(Timer,Interval,true,function Update)
    endif
    set D[DT] = d
    
endfunction

//=======================================================================
private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == Abil_id
endfunction

//=======================================================================
private function TrueFilt takes nothing returns boolean
    return true
endfunction

//=======================================================================
private function Init takes nothing returns nothing
    local trigger trig = CreateTrigger()
    local integer i = 0
    local unit dum = null
    
    set Timer = CreateTimer()
    set Enemyfilt = Filter(function FilterEnemies)
    set Truefilt = Filter(function TrueFilt)
    
    set Game_maxX = GetRectMaxX(bj_mapInitialPlayableArea)-64.00
    set Game_maxY = GetRectMaxY(bj_mapInitialPlayableArea)-64.00
    set Game_minX = GetRectMinX(bj_mapInitialPlayableArea)+64.00
    set Game_minY = GetRectMinY(bj_mapInitialPlayableArea)+64.00
    
    loop
        call TriggerRegisterPlayerUnitEvent(trig,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,Truefilt)
        set i = i + 1
        exitwhen i == bj_MAX_PLAYER_SLOTS
    endloop

    call TriggerAddCondition(trig,Condition(function Conditions))
    call TriggerAddAction(trig,function Actions)
    
    if AllowPreload then
        set dum = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),Dummy_id,0.00,0.00,0.00)
        call UnitAddAbility(dum,Abil3_id)
        call KillUnit(dum)
        call DestroyEffect(AddSpecialEffect(Start_sfx,0.00,0.00))
    endif
    
    set dum = null
endfunction

endscope</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>




Change Log:

  • 2nd Feb 09 - Updated the spells to include preloading, which helps a little. Also made a few minor improvements to the coding of the spell.
 

Attachments

  • Stone Panda.w3x
    62.9 KB · Views: 439
  • Earth Panda [v2].w3x
    76.8 KB · Views: 598

Kenny

Back for now.
Reaction score
202
The Spells Continued:

Stone Skin:

Import Difficulty: Easy

Description:

When damaged, there is a percent chance that the Earth Panda's body is imbued with the power of stone, allowing him to absorb a certain amount of damage and release it in a power tremor that damages surrounding enemy units. Also mini-stuns units in the area of effect.

Level 1 - Absorbs 30% of incoming damage and deals 70% of that damage to enemy units within a 300 area of effect. Damage dealt to surrounding units caps at 75 damage.

Level 2 - Absorbs 45% of incoming damage and deals 80% of that damage to enemy units within a 400 area of effect. Damage dealt to surrounding units caps at 100 damage.

Level 3 - Absorbs 60% of incoming damage and deals 90% of that damage to enemy units within a 500 area of effect. Damage dealt to surrounding units caps at 125 damage.

Level 4 - Absorbs 75% of incoming damage and deals 100% of that damage to enemy units within a 600 area of effect. Damage dealt to surrounding units caps at 150 damage.

Passive

Screenshot:

Pointless for this spell.


The script:

JASS:
scope StoneSkin initializer Init

globals
// Configurables:

// Skills:
    private constant integer Abil_id = &#039;A00B&#039;
    // Raw code of the main hero ability.
    private constant integer Abil2_id = &#039;A001&#039;
    // Raw code of the mini-stun unit ability.
    private constant integer Dummy_id = &#039;u000&#039;
    // Raw code of the dummy unit that casts war stomp.
    private constant real MinDamage = 1.00
    // Minimum damage that can trigger the spell.
    private constant real MinHp = 25.00
    // If the hero is under this hp, the spell will not trigger.
    private constant string Absorb_sfx = &quot;SandWaveDamage.mdx&quot; 
    // Special effect created on the hero when triggered.
    private constant string Absorb_point = &quot;origin&quot;
    // Attachment point of the above effect.
    private constant string DamageDirt_sfx = &quot;SandWaveDamage.mdx&quot; 
    // Special effect created on each damaged unit when they are on land.
    private constant string DamageWater_sfx = &quot;Abilities\\Spells\\Other\\CrushingWave\\CrushingWaveDamage.mdl&quot; 
    // Same as above but for when units are on shallow water.
    private constant string Damage_point = &quot;origin&quot;
    // Attachment point of the above effects.
    private constant boolean AllowPreload = true
    // Whether or not to allow preloading of the effects.
    
    // Attack/Damage/Weapon types of damage dealt.
    private constant attacktype A_type = ATTACK_TYPE_CHAOS
    private constant damagetype D_type = DAMAGE_TYPE_UNIVERSAL
    private constant weapontype W_type = WEAPON_TYPE_WHOKNOWS 
    
    // Do not touch these.
    private boolexpr Truefilt = null
    private boolexpr Enemyfilt = null
    private group Group = null
    private unit Dummy = null
endglobals

//=======================================================================
private function Radius takes integer lvl returns real
    return 150.00+(50.00*lvl) // Area of effect in which units are damaged.
endfunction

private function AbsorbPercent takes integer lvl returns real
    return 0.15+(0.15*lvl) // Percentage of damage absorbed.
endfunction

private function DamagePercent takes integer lvl returns real
    return 0.60+(0.10*lvl) // Percentage of absorbed damage dealt to units.
endfunction

private function DamageCap takes integer lvl returns real
    return 50.00+(25.00*lvl) // Damage cap of above damage.
endfunction

//=======================================================================//
//  DO NOT TOUCH PAST THIS POINT UNLESS YOU KNOW WHAT YOUR ARE DOING!!   //
//=======================================================================//

private function Chance takes unit u returns real
    return (GetUnitState(u,UNIT_STATE_LIFE) / GetUnitState(u,UNIT_STATE_MAX_LIFE)) / 2.00
endfunction

private function EnemyFilt takes nothing returns boolean
    return GetWidgetLife(GetFilterUnit()) &gt; 0.405 and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) == false 
endfunction
    
//=======================================================================
private function Update takes nothing returns boolean
    local unit cast = GetTriggerUnit()
    local integer lvl = GetUnitAbilityLevel(cast,Abil_id)
    local real dam = GetEventDamage()*AbsorbPercent(lvl)
    local unit u = null
    
    if dam &gt; MinDamage and GetWidgetLife(cast) &gt; MinHp then
        if GetRandomReal(0.00,1.00) &lt;= Chance(cast) then
            call SetUnitAnimation(cast,&quot;spell slam&quot;)
            call SetWidgetLife(cast,GetWidgetLife(cast)+dam)
            call DestroyEffect(AddSpecialEffectTarget(Absorb_sfx,cast,Absorb_point))
            
            set dam = dam*DamagePercent(lvl)
            if dam &gt; DamageCap(lvl) then
                set dam = DamageCap(lvl)
            endif
            
            set Dummy = CreateUnit(GetOwningPlayer(cast),Dummy_id,GetUnitX(cast),GetUnitY(cast),0.00)
            call UnitAddAbility(Dummy,Abil2_id)
            call SetUnitAbilityLevel(Dummy,Abil2_id,lvl)
            call IssueImmediateOrder(Dummy,&quot;stomp&quot;)
            call RemoveUnit(Dummy)
            set Dummy = null
            
            call GroupEnumUnitsInRange(Group,GetUnitX(cast),GetUnitY(cast),Radius(lvl),Enemyfilt)
            loop
                set u = FirstOfGroup(Group)
                exitwhen u == null
                call GroupRemoveUnit(Group,u)
                if IsUnitEnemy(u,GetOwningPlayer(cast)) then
                    call UnitDamageTarget(cast,u,dam,false,false,A_type,D_type,W_type)
                    if IsTerrainPathable(GetUnitX(u),GetUnitY(u),PATHING_TYPE_FLOATABILITY) then
                        call DestroyEffect(AddSpecialEffectTarget(DamageDirt_sfx,u,Damage_point))
                    elseif not IsTerrainPathable(GetUnitX(u),GetUnitY(u),PATHING_TYPE_WALKABILITY) then
                        call DestroyEffect(AddSpecialEffectTarget(DamageWater_sfx,u,Damage_point))
                    endif
                endif
            endloop
        endif
    endif
    
    set cast = null
    
    return false
endfunction

//=======================================================================
private function Actions takes nothing returns nothing
    local unit cast = GetTriggerUnit()
    local trigger trig
    
    if GetLearnedSkill() == Abil_id and GetUnitAbilityLevel(cast,Abil_id) == 1 and IsUnitIllusion(cast) == false then
        set trig = CreateTrigger()
        call TriggerRegisterUnitEvent(trig,cast,EVENT_UNIT_DAMAGED)
        call TriggerAddCondition(trig,Condition(function Update))
    endif
    
    set cast = null
    set trig = null
endfunction

//=======================================================================
private function TrueFilt takes nothing returns boolean
    return true
endfunction

//=======================================================================
private function Init takes nothing returns nothing
    local trigger trig = CreateTrigger()
    local integer i = 0
    local unit dum = null
    
    set Group = CreateGroup()
    set Truefilt = Filter(function TrueFilt)
    set Enemyfilt = Filter(function EnemyFilt)

    loop
        call TriggerRegisterPlayerUnitEvent(trig,Player(i),EVENT_PLAYER_HERO_SKILL,Truefilt)
        set i = i + 1
        exitwhen i == bj_MAX_PLAYER_SLOTS
    endloop

    call TriggerAddAction(trig,function Actions)
    
    if AllowPreload then
        set dum = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),Dummy_id,0.00,0.00,0.00)
        call UnitAddAbility(dum,Abil2_id)
        call IssueImmediateOrder(dum,&quot;stomp&quot;)
        call UnitApplyTimedLife(dum,&#039;BTLF&#039;,1.00)
        call DestroyEffect(AddSpecialEffect(DamageDirt_sfx,0.00,0.00))
        call DestroyEffect(AddSpecialEffect(DamageWater_sfx,0.00,0.00))
    endif
    
    set dum = null
endfunction

endscope



Earth Prison:

Import Difficulty: Hard

Description:

Conjures an impenetrable circle of stone surrounding the caster. The stone pillars are imbued with dense mana, creating a void in which no one can escape.

Level 1
- Creates a circle with 400 radius. Explosions happen once every second. Units within 250 area of effect of the explosions are tossed. Toss lasts 1.00 second and deals 20 damage and to all enemy units in a 200 area of effect upon impact, also mini-stuns the enemies. Enemy units who get too close to the wall are knocked back into the centre and are dealt 40 damage. The attack speed of enemy units is reduced by 15% while in the prison.

The prison takes 1 second to be created and destroyed.

Lasts 8 seconds not including creation and destruction time

Level 2 - Creates a circle with 450 radius. Explosions happen twice every second. Units within 250 area of effect of the explosions are tossed. Toss lasts 1.00 second and deals 40 damage and to all enemy units in a 200 area of effect upon impact, also mini-stuns the enemies. Enemy units who get too close to the wall are knocked back into the centre and are dealt 80 damage. The attack speed of enemy units is reduced by 20% while in the prison.

The prison takes 1 second to be created and destroyed.

Lasts 10 seconds not including creation and destruction time

Level 3 - Creates a circle with 500 radius. Explosions happen three times every second. Units within 250 area of effect of the explosions are tossed. Toss lasts 1.00 second and deals 60 damage and to all enemy units in a 200 area of effect upon impact, also mini-stuns the enemies. Enemy units who get too close to the wall are knocked back into the centre and are dealt 120 damage. The attack speed of enemy units is reduced by 25% while in the prison.

The prison takes 1 second to be created and destroyed.

Lasts 12 seconds not including creation and destruction time.

Cooldown: 80 seconds

Screenshot:
EarthPrison.jpg

The script:
JASS:
scope EarthPrison initializer Init

globals
// Configurables:
    
// Skills:
    private constant integer Abil_id = &#039;A009&#039;
    // Raw code of the main hero ability (Earth Prison).
    private constant integer Abil2_id = &#039;AURA&#039;
    // Raw code of the  Aura ability that slows enemy units and stops them using escape spells.
    private constant integer Stomp_id = &#039;A00A&#039;
    // Raw code of the &quot;War Stomp&quot; ability used when units hit the ground.
    private constant integer Flytrick = &#039;Amrf&#039;
    // Raw code of the &quot;Crow Form&quot; ability used to change fly height. Does not need to be changed in most cases.
    
// Buffs:
    private constant integer Buff_id = &#039;BUFF&#039;
    // Raw code for the Buff of the Aura ability (Abil2_id).

// Units:
    private constant integer Wall_id = &#039;u003&#039;
    // Raw code of the wall unit that makes up the circle.
    private constant integer Aura_id = &#039;u000&#039;
    // Raw code of the unit that destroys trees and has the Aura ability (Abil2_id)
    
// Destructables:
    private constant integer Block_id = &#039;YTfb&#039;
    // Raw code for the Pathing Blocker (Both). Does not need to be changed in most cases.
    
// Others:
    private constant real Interval = 0.04      // Interval for periodic timer.
    private constant real Airtime = 1.00       // Air time of the tosses.
    private constant real Area = 250.00        // Area of effect for explosion to toss units
    private constant real PercentDist = 1.00   // Percentage of distance between tossed unit and middle of circle for the unit to travel.
    private constant integer MaxUnits = 25     // Number of units to make the wall. Minimum must be 25 if all units have 32 collision size.
    
    private constant string ExplodeDirt_sfx = &quot;SandWaveDamage.mdx&quot;
    // Special effect created for explosions and for units landing and getting hit by the wall.
    private constant string ExplodeWater_sfx = &quot;Abilities\\Spells\\Other\\CrushingWave\\CrushingWaveDamage.mdl&quot;
    // Same as above but for when units are on water.
    private constant string Dirt_sfx = &quot;Dust.mdx&quot;
    // Special effect added to units getting knocked back or tossed.
    private constant string Water_sfx = &quot;SlideWater.mdx&quot;
    // Same as above but for units on water.
    private constant string Point = &quot;origin&quot;
    // Attachment point for Dirt_sfx and Water_sfx.
    
    // Attack/Damage/Weapon types:
    private constant attacktype A_type = ATTACK_TYPE_CHAOS
    private constant damagetype D_type = DAMAGE_TYPE_UNIVERSAL
    private constant weapontype W_type = WEAPON_TYPE_WHOKNOWS
    
    private constant boolean Allowmove = false
    // If you want to allow units to move while being knocked back.
    private constant boolean AllowPreload = true
    // Whether or not to allow preloading of the effects.
    private constant string Error_msg = &quot;You can&#039;t escape.&quot;
    // Error message for when units try to escape by means of a spell.
endglobals

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

// Here is where you add abilities used to escape if you dont want them used if the unit is trapped.
globals
    private constant integer Blink_id = &#039;AEbl&#039;
    private constant integer Blink2_id = &#039;----&#039;
    private constant integer Blink3_id = &#039;----&#039;
endglobals

private function Conditions2 takes nothing returns boolean
    return (GetSpellAbilityId() == Blink_id or GetSpellAbilityId() == Blink2_id or GetSpellAbilityId() == Blink3_id) and GetUnitAbilityLevel(GetTriggerUnit(),Buff_id) &gt; 0
endfunction

//=======================================================================
private function MaxDuration takes integer lvl returns real
    return 8.00+(2.00*lvl) // Duration of the prison.
endfunction // Note: the wall takes 1 second to make, and 1 second to destroy. Make sure you remember that.

private function ExplodeTime takes integer lvl returns real
    return 1.332-(0.333*lvl) // How often explosions are made.
endfunction

private function Radius takes integer lvl returns real
    return 350.00+(50.00*lvl) // The radius of the prison.
endfunction

private function KnockDuration takes integer lvl returns real
    return 1.50 // Duration of knockback.
endfunction

private function KnockDamage takes integer lvl returns real
    return 40.00*lvl // Damage dealt if a unit is knocked back.
endfunction

//=======================================================================//
//  DO NOT TOUCH PAST THIS POINT UNLESS YOU KNOW WHAT YOUR ARE DOING!!   //
//=======================================================================//

private keyword Data
private keyword Jump
private keyword Knock

globals       
    private Data array D
    private Jump array J
    private Knock array K
    private integer DT = 0
    private integer JT = 0
    private integer KT = 0
    private rect Rect1 = null
    private timer Timer = null
    private sound Error = null
    private unit Treedummy = null
    private real Game_maxX = 0.00
    private real Game_minX = 0.00
    private real Game_maxY = 0.00
    private real Game_minY = 0.00
    private boolexpr Truefilt = null
    private boolexpr Treefilt = null
    private boolexpr Enemyfilt = null
    private constant integer Units = MaxUnits + 2
endglobals

//=======================================================================
private function SafeX takes real x returns real
    if x&lt;Game_minX then
        return Game_minX
    elseif x&gt;Game_maxX then
        return Game_maxX
    endif
    return x
endfunction

private function SafeY takes real y returns real
    if y&lt;Game_minY then
        return Game_minY
    elseif y&gt;Game_maxY then
        return Game_maxY
    endif
    return y
endfunction

//===========================================================================
private function KillEnumDestructables takes nothing returns nothing
    call KillDestructable(GetEnumDestructable())
endfunction

private function TreeCheck takes nothing returns boolean
    local destructable dest = GetFilterDestructable()
    local boolean result
    
    if GetDestructableLife(dest) &gt; 0.405 then
        call ShowUnit(Treedummy,true)
        call SetUnitX(Treedummy,GetWidgetX(dest))
        call SetUnitY(Treedummy,GetWidgetY(dest))
        
        set result = IssueTargetOrder(Treedummy,&quot;harvest&quot;,dest)
        call IssueImmediateOrder(Treedummy,&quot;stop&quot;)
        call ShowUnit(Treedummy,false)

        return result
    endif
    
    set dest = null
    return false
endfunction

//=======================================================================
private function SimError takes player Whichplayer, string Message returns nothing
    set Message = &quot;\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cffffcc00&quot;+Message+&quot;|r&quot;
    if (GetLocalPlayer() == Whichplayer) then
        call ClearTextMessages()
        call DisplayTimedTextToPlayer(Whichplayer,0.5125,0.97120,2.00,Message)
        call StartSound(Error)
    endif
endfunction

//=======================================================================
private function MoveDist takes real Maxdist returns real
    return Maxdist/(Airtime/Interval)
endfunction

private function ConvertCount takes integer i returns real
    return (50.00/(Airtime/Interval))*i
endfunction

private function FilterEnemies takes nothing returns boolean
    return GetWidgetLife(GetFilterUnit()) &gt; 0.405 and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(),UNIT_TYPE_FLYING) == false
endfunction

private function DistanceXY takes real x1, real y1, real x2, real y2 returns real
    return SquareRoot((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1))
endfunction

//=======================================================================
private function IsPointOutside takes real x, real y returns boolean
    return (x &gt; Game_maxX or y &gt; Game_maxY or x &lt; Game_minX or y &lt; Game_minY)
endfunction

private function TerrainType takes unit u returns integer
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
        
    if IsTerrainPathable(x,y,PATHING_TYPE_FLOATABILITY) then
        return 1
    elseif not IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
        return 2
    endif
        
    return 0
endfunction

//=======================================================================
private struct Data
    unit cast
    unit aura
    unit array wall[Units]
    destructable array dest[Units]
    real castx = 0.00
    real casty = 0.00
    real time = 0.00
    real exptime = 0.00
    real scale = 0.00
    boolean building = true
    integer noaura = 0
    integer lvl = 0
    effect array sfx[Units]
    group g1 = CreateGroup()
    group g2 = CreateGroup()
    
    private method onDestroy takes nothing returns nothing
        local integer i = 1
        
        loop
            exitwhen i &gt; MaxUnits
            call ShowUnit(.wall<i>,false)
            call KillUnit(.wall<i>)
            call RemoveDestructable(.dest<i>)
            call DestroyEffect(.sfx<i>)
            set .wall<i> = null
            set .dest<i> = null
            set .sfx<i> = null
            set i = i + 1
        endloop
        
        set .cast = null
        call GroupClear(.g2)
        call DestroyGroup(.g2)
    endmethod
endstruct

//=======================================================================
private struct Jump
    unit cast
    unit u
    real ux = 0.00
    real uy = 0.00
    real cos = 0.00
    real sin = 0.00
    real maxdist = 0.00
    real movedist = 0.00
    integer i = 1
    integer lvl = 0
    effect sfx
    
    private method onDestroy takes nothing returns nothing  
        local real x = GetUnitX(.u)
        local real y = GetUnitY(.u)
        local unit u = CreateUnit(GetOwningPlayer(.cast),Aura_id,x,y,0.00)
        
        call DestroyEffect(.sfx)
        set .sfx = null
        
        call SetUnitFlyHeight(.u,GetUnitDefaultFlyHeight(.u),0.00)
        call SetUnitPathing(.u,true)

        call UnitAddAbility(u,Stomp_id)
        call SetUnitAbilityLevel(u,Stomp_id,.lvl)
        call IssueImmediateOrder(u,&quot;stomp&quot;)
        call UnitApplyTimedLife(u,&#039;BTLF&#039;,1.00)
        if IsTerrainPathable(x,y,PATHING_TYPE_FLOATABILITY) then
            call DestroyEffect(AddSpecialEffect(ExplodeDirt_sfx,x,y))
        elseif not IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
            call DestroyEffect(AddSpecialEffect(ExplodeWater_sfx,x,y))
        endif

        set u = null
        set .u = null
        set .cast = null
    endmethod
endstruct

//=======================================================================
private struct Knock
    unit targ
    real speed = 0.00
    real decrease = 0.00
    real cos = 0.00
    real sin = 0.00
    effect sfx
    integer sfxmode
    
    private method onDestroy takes nothing returns nothing
        set .targ = null
        if .sfx != null then
            call DestroyEffect(.sfx)
            set .sfx = null
        endif
    endmethod
endstruct

//=======================================================================
private function IsUnitSliding takes unit Target returns boolean
    local integer i = 1
    
    loop
        exitwhen i &gt; KT
        if K<i>.targ == Target then
            return true
        endif
        set i = i + 1
    endloop
    
    return false
endfunction

private function IsUnitJumping takes unit Target returns boolean
    local integer i = 1
    
    loop
        exitwhen i &gt; JT
        if J<i>.u == Target then
            return true
        endif
        set i = i + 1
    endloop
    
    return false
endfunction

//=======================================================================
private function Update takes nothing returns nothing
    local Jump j = 0
    local Knock k = 0
    local integer i = 1
    local integer t = 1
    local integer newmode
    local real x
    local real y
    local real tmpang
    local real tmpdist
    local real count
    local real height
    local real speed
    local unit u
    
    loop
        exitwhen i &gt; DT
        
        if D<i>.time &gt;= MaxDuration(D<i>.lvl) then
            call D<i>.destroy()
            set D<i> = D[DT]
            set DT = DT - 1
            set i = i - 1
        elseif D<i>.time &gt;= MaxDuration(D<i>.lvl) - 1.00 then
            set tmpang = 360.00 / MaxUnits
                
            loop
                exitwhen t &gt; MaxUnits
                call SetUnitScale(D<i>.wall[t],D<i>.scale,D<i>.scale,D<i>.scale)
                set t = t + 1
            endloop
            
            if D<i>.scale == 1.00 then
                set t = 1
                loop
                    exitwhen t &gt; MaxUnits
                    set x = D<i>.castx + Radius(D<i>.lvl) * Cos((tmpang * t) * bj_DEGTORAD)
                    set y = D<i>.casty + Radius(D<i>.lvl) * Sin((tmpang * t) * bj_DEGTORAD)
                    if IsTerrainPathable(x,y,PATHING_TYPE_FLOATABILITY) then
                        set D<i>.sfx[t] = AddSpecialEffect(Dirt_sfx,SafeX(x),SafeY(y))
                    elseif not IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
                        set D<i>.sfx[t] = AddSpecialEffect(Water_sfx,SafeX(x),SafeY(y))
                    endif
                    set t = t + 1
                endloop
            endif
                
            set D<i>.scale = D<i>.scale - 0.04
            set D<i>.time = D<i>.time + Interval
        else
            if D<i>.building then
                if D<i>.scale == 1 then
                    set D<i>.building = false
                endif

                set D<i>.scale = D<i>.scale + 0.04
                
                loop
                    exitwhen t &gt; MaxUnits
                    call SetUnitScale(D<i>.wall[t],D<i>.scale,D<i>.scale,D<i>.scale)
                    set t = t + 1
                endloop
            else
                loop
                    exitwhen t &gt; MaxUnits
                    call DestroyEffect(D<i>.sfx[t])
                    set D<i>.sfx[t] = null
                    set t = t + 1
                endloop
                
                if D<i>.noaura == 0 then
                    set D<i>.aura = CreateUnit(GetOwningPlayer(D<i>.cast),Aura_id,D<i>.castx,D<i>.casty,0.00)
                    call UnitAddAbility(D<i>.aura,Abil2_id)
                    call SetUnitAbilityLevel(D<i>.aura,Abil2_id,D<i>.lvl)
                    set D<i>.noaura = 1
                endif
                
                if D<i>.time &gt;= MaxDuration(D<i>.lvl) - 3.00 and D<i>.aura != null then
                    call KillUnit(D<i>.aura)
                    set D<i>.aura = null
                endif
                
                call GroupEnumUnitsInRange(D<i>.g1,D<i>.castx,D<i>.casty,Radius(D<i>.lvl),Enemyfilt)
                call GroupRemoveUnit(D<i>.g1,D<i>.cast)
                loop
                    set u = FirstOfGroup(D<i>.g1)
                    exitwhen u == null
                    call GroupRemoveUnit(D<i>.g1,u)
                    set tmpdist = DistanceXY(D<i>.castx,D<i>.casty,GetUnitX(u),GetUnitY(u))
                    if IsUnitEnemy(u,GetOwningPlayer(D<i>.cast)) and (tmpdist &gt; Radius(D<i>.lvl) - 125.00 ) and IsUnitSliding(u) == false and IsUnitJumping(u) == false then
                        call UnitDamageTarget(D<i>.cast,u,KnockDamage(D<i>.lvl),false,false,A_type,D_type,W_type)
                        call DestroyEffect(AddSpecialEffect(ExplodeDirt_sfx,GetUnitX(u),GetUnitY(u)))
                        set k = Knock.create()
                        set k.targ = u
                        set tmpang = ((Atan2(GetUnitY(k.targ)-D<i>.casty,GetUnitX(k.targ)-D<i>.castx)*bj_RADTODEG)+180.00)*bj_DEGTORAD
                        set k.speed = (2.00*(Radius(D<i>.lvl)/2.00)) / (KnockDuration(D<i>.lvl)/Interval)
                        set k.decrease = k.speed / (KnockDuration(D<i>.lvl)/Interval)
                        set k.sfxmode = TerrainType(k.targ)
                        if k.sfxmode == 1 then
                            set k.sfx = AddSpecialEffectTarget(Dirt_sfx,k.targ,Point)
                        elseif k.sfxmode == 2 then
                            set k.sfx = AddSpecialEffectTarget(Water_sfx,k.targ,Point)
                        endif                                
                        set k.cos = Cos(tmpang)
                        set k.sin = Sin(tmpang)
                        
                        set KT = KT + 1
                        set K[KT] = k
                    endif
                endloop
            
                if D<i>.exptime &gt;= ExplodeTime(D<i>.lvl) then
                    set D<i>.exptime = 0.00
                    set x = D<i>.castx + GetRandomReal(0.00,(Radius(D<i>.lvl)-125.00)) * Cos(GetRandomReal(0.00,360.00) * bj_DEGTORAD)
                    set y = D<i>.casty + GetRandomReal(0.00,(Radius(D<i>.lvl)-125.00)) * Sin(GetRandomReal(0.00,360.00) * bj_DEGTORAD)
                    if IsTerrainPathable(x,y,PATHING_TYPE_FLOATABILITY) then
                        call DestroyEffect(AddSpecialEffect(ExplodeDirt_sfx,SafeX(x),SafeY(y)))
                    elseif not IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
                        call DestroyEffect(AddSpecialEffect(ExplodeWater_sfx,SafeX(x),SafeY(y)))
                    endif
                    
                    call GroupEnumUnitsInRange(D<i>.g2,SafeX(x),SafeY(y),(Area/2.00),Enemyfilt)
                    loop
                        set u = FirstOfGroup(D<i>.g2)
                        exitwhen u == null
                        call GroupRemoveUnit(D<i>.g2,u)
                        if IsUnitEnemy(u,GetOwningPlayer(D<i>.cast)) and IsUnitSliding(u) == false and IsUnitJumping(u) == false then
                            set j = Jump.create()
                            set j.cast = D<i>.cast
                            set j.u = u
                            set j.ux = GetUnitX(j.u)
                            set j.uy = GetUnitY(j.u)
                            set tmpang = Atan2((D<i>.casty - j.uy),(D<i>.castx - j.ux))
                            set j.cos = Cos(tmpang)
                            set j.sin = Sin(tmpang)
                            set j.maxdist = SquareRoot((D<i>.castx-j.ux)*(D<i>.castx-j.ux)+(D<i>.casty-j.uy)*(D<i>.casty-j.uy))*PercentDist
                            set j.movedist = MoveDist(j.maxdist)
                            set j.lvl = D<i>.lvl
                            if IsTerrainPathable(x,y,PATHING_TYPE_FLOATABILITY) then
                                set j.sfx = AddSpecialEffectTarget(Dirt_sfx,j.u,Point)
                            elseif not IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
                                set j.sfx = AddSpecialEffectTarget(Water_sfx,j.u,Point)
                            endif
                            
                            call UnitAddAbility(j.u,Flytrick)
                            call UnitRemoveAbility(j.u,Flytrick)
                            call SetUnitPathing(j.u,false)
                            
                            set JT = JT + 1
                            set J[JT] = j
                        endif
                    endloop
                endif
            endif
            
            set D<i>.time = D<i>.time + Interval
            set D<i>.exptime = D<i>.exptime + Interval
            set t = 1
        endif
        
        set i = i + 1
    endloop
    
    set i = 1
    
    loop
        exitwhen i &gt; JT
        
        if J<i>.i &lt; (Airtime / Interval) then
            set count = ConvertCount(J<i>.i)
            set height = (count - 25.00) * (count - 25.00)
            set speed = J<i>.i * J<i>.movedist
            set x = J<i>.ux + speed * J<i>.cos
            set y = J<i>.uy + speed * J<i>.sin
            call SetUnitPosition(J<i>.u,SafeX(x),SafeY(y))
            call SetUnitFlyHeight(J<i>.u,625.00-height,0.00)
            set J<i>.i = J<i>.i + 1
        else
            call J<i>.destroy()
            set J<i> = J[JT]
            set JT = JT - 1
            set i = i - 1
        endif
        
        set i = i + 1
    endloop
    
    set i = 1
    
    loop
        exitwhen i &gt; KT
        set newmode = K<i>.sfxmode
        
        set x = GetUnitX(K<i>.targ)
        set y = GetUnitY(K<i>.targ)
        
        set K<i>.sfxmode = TerrainType(K<i>.targ)
        
        if K<i>.sfxmode == 1 and newmode == 2 then
            call DestroyEffect(K<i>.sfx)
            set K<i>.sfx = AddSpecialEffectTarget(Dirt_sfx,K<i>.targ,Point)
        elseif K<i>.sfxmode == 2 and newmode == 1 then
            call DestroyEffect(K<i>.sfx)
            set K<i>.sfx = AddSpecialEffectTarget(Water_sfx,K<i>.targ,Point)
        endif
        
        if K<i>.speed &lt;= 0.00 or IsPointOutside(x,y) or GetWidgetLife(K<i>.targ) &lt; 0.405 then
            call K<i>.destroy()
            set K<i> = K[KT]
            set KT = KT - 1
            set i = i - 1
        else
            set x = x + K<i>.speed * K<i>.cos
            set y = y + K<i>.speed * K<i>.sin
            
            if Allowmove then
                call SetUnitX(K<i>.targ,x)
                call SetUnitY(K<i>.targ,y)
            else
                call SetUnitPosition(K<i>.targ,x,y)
            endif
            
            set K<i>.speed = K<i>.speed - K<i>.decrease
        endif
        
        set i = i + 1
    endloop
    
    if DT &lt;= 0 and JT &lt;= 0 and KT &lt;= 0 then
        call PauseTimer(Timer)
        set DT = 0
        set JT = 0
        set KT = 0
    endif
    
    set u = null
endfunction
        
//=======================================================================
private function Actions takes nothing returns nothing
    local Data d = Data.create()
    local integer i = 1
    local real x
    local real y
    local real ang
    
    set d.cast = GetTriggerUnit()
    set d.castx = GetUnitX(d.cast)
    set d.casty = GetUnitY(d.cast)
    set d.lvl = GetUnitAbilityLevel(d.cast,Abil_id)
    set ang = 360.00 / MaxUnits
    set d.scale = 0.00
    
    call SetRect(Rect1,d.castx-Radius(d.lvl),d.casty-Radius(d.lvl),d.castx+Radius(d.lvl),d.casty+Radius(d.lvl))
    call EnumDestructablesInRect(Rect1,Treefilt,function KillEnumDestructables)
    
    loop
        exitwhen i &gt; MaxUnits
        set x = d.castx + Radius(d.lvl) * Cos((ang * i) * bj_DEGTORAD)
        set y = d.casty + Radius(d.lvl) * Sin((ang * i) * bj_DEGTORAD)
        set d.wall<i> = CreateUnit(GetOwningPlayer(d.cast),Wall_id,SafeX(x),SafeY(y),0.00)
        set d.dest<i> = CreateDestructable(Block_id,SafeX(x),SafeY(y),(ang * i),1.00,0)
        if IsTerrainPathable(x,y,PATHING_TYPE_FLOATABILITY) then
            set d.sfx<i> = AddSpecialEffect(Dirt_sfx,SafeX(x),SafeY(y))
        elseif not IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
            set d.sfx<i> = AddSpecialEffect(Water_sfx,SafeX(x),SafeY(y))
        endif
        call SetUnitScale(d.wall<i>,d.scale,d.scale,d.scale)
        set i = i + 1
    endloop
    
    set DT = DT + 1
    if DT == 1 and JT == 0 and KT == 0 then
        call TimerStart(Timer,Interval,true,function Update)
    endif
    set D[DT] = d
    
endfunction
    
//=======================================================================
private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == Abil_id
endfunction

//=======================================================================
private function Actions2 takes nothing returns nothing
    local unit cast = GetTriggerUnit()
    
    call PauseUnit(cast,true)
    call IssueImmediateOrder(cast,&quot;stop&quot;)
    call PauseUnit(cast,false)
    call SimError(GetOwningPlayer(cast),Error_msg)
    
    set cast = null
endfunction

//=======================================================================
private function TrueFilt takes nothing returns boolean
    return true
endfunction

//=======================================================================
private function Init takes nothing returns nothing
    local trigger trig1 = CreateTrigger()
    local trigger trig2 = CreateTrigger()
    local integer i = 0
    local unit dum = null
    
    set Timer = CreateTimer()
    set Rect1 = Rect(0.00,0.00,1.00,1.00)
    set Truefilt = Filter(function TrueFilt)
    set Treefilt = Filter(function TreeCheck)
    set Enemyfilt = Filter(function FilterEnemies)
    set Error = CreateSoundFromLabel(&quot;InterfaceError&quot;,false,false,false,10,10)
    
    set Game_maxX = GetRectMaxX(bj_mapInitialPlayableArea)-64.00
    set Game_maxY = GetRectMaxY(bj_mapInitialPlayableArea)-64.00
    set Game_minX = GetRectMinX(bj_mapInitialPlayableArea)+64.00
    set Game_minY = GetRectMinY(bj_mapInitialPlayableArea)+64.00
    
    loop
        call TriggerRegisterPlayerUnitEvent(trig1,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,Truefilt)
        set i = i + 1
        exitwhen i == bj_MAX_PLAYER_SLOTS
    endloop

    call TriggerAddCondition(trig1,Condition(function Conditions))
    call TriggerAddAction(trig1,function Actions)
    
    set i = 0
    
    loop
        call TriggerRegisterPlayerUnitEvent(trig2,Player(i),EVENT_PLAYER_UNIT_SPELL_CAST,Truefilt)
        set i = i + 1
        exitwhen i == bj_MAX_PLAYER_SLOTS
    endloop
    
    call TriggerAddCondition(trig2,Condition(function Conditions2))
    call TriggerAddAction(trig2,function Actions2)
    
    set Treedummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),Aura_id,0.00,0.00,0.00)
    call SetUnitPathing(Treedummy,false)
    call ShowUnit(Treedummy,false)
    
    if AllowPreload then
        call KillUnit(CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),Wall_id,0.00,0.00,0.00))
        set dum = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),Aura_id,0.00,0.00,0.00)
        call UnitAddAbility(dum,Abil2_id)
        call UnitAddAbility(dum,Stomp_id)
        call IssueImmediateOrder(dum,&quot;stomp&quot;)
        call UnitApplyTimedLife(dum,&#039;BTLF&#039;,1.00)
        call DestroyEffect(AddSpecialEffect(ExplodeDirt_sfx,0.00,0.00))
        call DestroyEffect(AddSpecialEffect(ExplodeWater_sfx,0.00,0.00))
        call RemoveDestructable(CreateDestructable(Block_id,0.00,0.00,0.00,0.00,0))
    endif
    
    set dum = null
endfunction

endscope</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>
 

WolfieeifloW

WEHZ Helper
Reaction score
372
What's with all these "Coming Soon!"'s...
This is more of a WIP instead of a spellpack ;) .
Just glanced over, last spell looks cool.
 

Kenny

Back for now.
Reaction score
202
What's with all these "Coming Soon!"'s...

I reached the maximum character limit for a post (50,000), so i can't fit the descriptions and the script to two of the spells, lol. I need about 75,000.

The last spell is probably my favourite, plus its probably the most complicated one i've done in a while.
 

WolfieeifloW

WEHZ Helper
Reaction score
372
I actually might use a variant of the last spell.
Do you want credits or anything for original spell idea once I modify it?
 

Kenny

Back for now.
Reaction score
202
Credits would be nice, just as long as you don't claim it as 100% your spell then i'll be happy.
 

WolfieeifloW

WEHZ Helper
Reaction score
372
Alrighty.
And of course I wouldn't claim it as all mine.
I'm a spell maker too, I know how it feels ;) .
I'd just put a little "Original spell by kenny!" after "Spell modified by <ME>" :) !
Anyways, nice looking pack, +rep.
 

Kenny

Back for now.
Reaction score
202
Updated the pack. Very few minor updates, nothing big.

Feedback would be awesome, as it seems my spells aren't getting much lately.

Also, still waiting for a reply by a mod to see if they can increase the max character limit for my post.

Also, wondering if the threads name can be changed to Earth Panda Spellpack, cause i think it fits in better with the whole Storm, Earth and Fire thingo.
 

Andrewgosu

The Silent Pandaren Helper
Reaction score
715
The max character limit is something that can be changed only by administrators, I think.

You should split your spells into two posts.

I deleted the first reply (sorry vypur85), so you now have consecutive posts in a row.
 

Kenny

Back for now.
Reaction score
202
Ah thanks for the changes AndrewGosu.

I will make the changes as soon as possible.

Changes have been made. Descriptions and scripts are up for each spell.

Now get to commenting! :p
 

Sim

Forum Administrator
Staff member
Reaction score
534
Wow, I love these spells. :) Very original and fun to use!

Approved!
 

Kenny

Back for now.
Reaction score
202
Wow, thanks for the approval Daxtreme! It came a bit faster than i thought. Still i wouldn't mind some people commenting on the scripts themselves, seeing as there are really no comments at all on them.
 

Sim

Forum Administrator
Staff member
Reaction score
534
There's one thing I noticed. It seems like, in a map which has constantly changing height, the Stone Guardians spell seems to bug.

As in, it keeps the maximum height it was set to, and simply always go higher, and higher... :p

Here, look:

JASS:
call SetUnitFlyHeight(d.stone<i>,GetUnitFlyHeight(d.targ)+Height,0.00)</i>


For some reason, GetUnitFlyHeight seems to always return a buggy flying height, as Flare said in another thread. The function returns a value not based on the current terrain's height, but the unit's flying height which never changes.

GetLocationZ might help, but it can cause desyncs (unverified, anyone can confirm?).
 

Flare

Stops copies me!
Reaction score
662
GetLocationZ might help, but it can cause desyncs (unverified, anyone can confirm?).
I recall someone saying that GetLocationZ could only cause a desync on deformed terrain. Whether it's true or not, I don't really know (and can't really test, WC3 has a habit of making me lag out completely at random :p), but as long as you can stay away from Thunder Clap/War Stomp, and the deformation functions, you would probably be fairly safe
 

Sim

Forum Administrator
Staff member
Reaction score
534
That's the problem, actually :p

Every skills in the spellpack creates terrain deformations!

@kenny!

It might be caused by the other setheight function:

JASS:
call SetUnitFlyHeight(D<i>.stone[j],GetUnitFlyHeight(D<i>.targ)+Height,0.00)</i></i>


I'm a bit lost into the variables and I gotta eat, but I'll edit later.

EDIT

http://www.wc3jass.com/viewtopic.php?t=2388&highlight=getlocationz

GetLocationZ only desyncs when there is Local Terrain Deformation at the position of the Z point.

Thus, it wouldn't be a problem in this situation I believe. Are the terrain deformations you created local, kenny?

EDIT

After extensive testing I've came to the conclusion that this is causing problems too:

JASS:
private constant real Height = 30.00    // height of the stones.
//...
call SetUnitFlyHeight(D<i>.stone[j],GetUnitFlyHeight(D<i>.targ)+Height,0.00)</i></i>


It seems that every further casting of the spell increases the heights of the stone by 30... odd. So at first cast it is equal to 30, then 60, then 90, etc.

But only in a terrain-height-varying map.

EDIT

Alright, found the TRUE problem. Seismic Slam. The unit flying in the air or w/e directly causes the Stone Guardians skill to bug entirely. Nothing else. Testing proved it without doubt.

A rapid guess would be this line:

JASS:
                call SetUnitFlyHeight(D<i>.cast,625.00-height,0.00)
</i>


which changes the caster's flying height unless I'm lost in variables. That would completely alter the Stone Guardians skill up to a bug point, because it relies on the flying height of the caster.

EDIT (AGAIN?)

So, simply deleting this line doesn't change at all Seismic Slam, but completely gets rid of the bug.

Thanks, testing! :D

===================================

As a conclusion, edit out the line in the Seismic Slam spell which I just quoted above.

It will effectively get rid of all bugs.

:)
 

Kenny

Back for now.
Reaction score
202
Thanks for bringing that to my attention Daxtreme. However, i have not been able to recreate this bug?

If you could give me some more information so that i can verify this for myself, it would be much appreciated.

I have used the "Noise" terraining tool to create terrain that constantly changes, yet nothing happens? Is that what you meant, or was it something else?
 

Sim

Forum Administrator
Staff member
Reaction score
534
Use the Leap spell.

Then try using Stone Guardians on yourself and hit nearby enemies.
 

Kenny

Back for now.
Reaction score
202
I've tried that, numerous times. It seems to work just fine for me. But seeing as the error that is occuring for you seems to happen when you use leap before stone guardians, it may have something to do with this line:

JASS:
if IsUnitEnemy(u,GetOwningPlayer(D<i>.cast)) and (GetUnitFlyHeight(u) &gt;= (GetUnitFlyHeight(D<i>.stone[j])-(Height*2.00)) and GetUnitFlyHeight(u) &lt;= (GetUnitFlyHeight(D<i>.stone[j])+(Height*2.00))) then

</i></i></i>


Change it to:

JASS:
if IsUnitEnemy(u,GetOwningPlayer(D<i>.cast)) then

</i>


And see if you still get the error. If that is the problem, i will eventually update this spellpack, with that change, and some other formatting changes.
 

Romek

Super Moderator
Reaction score
963
That's fine. As long as the spell works.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top