Spellpack Thanatos the God of Destruction

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
Thanatos the God of Death

Thanatos
the
God of Death

-------------------------------------
This pack has 4 spells, they are MUI, lagless (for me), leakless (I think), vJass. Also they have a good visual effect. :D
-------------------------------------

First spell: Sword Barrage
- Description:
A barrage of phantom swords that damages enemy units within the target area.
- Screenshot:
swordbarrageei8.jpg
- Code:
JASS:
scope SwordBarrage initializer Init 

globals
    private constant integer AbilId = 'A001' //raw id of the spell
    private constant integer DummyId = 'n002' //raw id of the dummy unit (requires: dummy.mdx )
    private constant string SwordModel = "GreatSwordRibbon.mdx" //an imported attachment model - model of the swords
    private constant string SwordHitSFX = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl" //sfx on hit
    private constant string SwordHitSFX_A = "origin" //attachment point for sfx on hit
    private constant attacktype ATKTYPE = ATTACK_TYPE_CHAOS  
    private constant damagetype DMGTYPE = DAMAGE_TYPE_NORMAL
    private constant weapontype WEPTYPE = WEAPON_TYPE_METAL_HEAVY_SLICE
    //-----------------------------------
    private group HITSFX = CreateGroup()
endglobals

private function GetNumberSwords takes integer lvl returns integer
    return (4+2*lvl)
endfunction

private function GetDamagePerSword takes integer lvl returns real
    return (75.+25*lvl)
endfunction

private function GetBarrageAOE takes integer lvl returns real
    return 250. //if you modify this value, you should also modify the "Stats - Area of Effect" of the ability
endfunction

private function GetSwordDamageAOE takes integer lvl returns real
    return 100. 
endfunction

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

private struct data
    unit c
    unit d
    effect e
    real dx
    real dy
    real x
    real y
    real angle
    real dist
    real dmg
    real aoe
    integer tick
    boolean spread = true
    real sin
endstruct

private function SwordF takes nothing returns boolean
    local data d = TT_GetData()
    local unit f = GetFilterUnit()
    local boolean ok = ( GetWidgetLife(f) > 0.405 and IsUnitEnemy(f,GetOwningPlayer(d.c)))
    set f = null
    return ok
endfunction

private function HitSFXSkip takes unit u returns nothing
    call TriggerSleepAction(0.1)
    call GroupRemoveUnit(HITSFX,u)
endfunction

private function DestroyEffectDelay takes effect e , real wait returns nothing
    call TriggerSleepAction(wait)
    call DestroyEffect(e)
endfunction

private function SwordE takes nothing returns boolean
    local data d = TT_GetData()
    local real x
    local real y
    local real z
    local real x2
    local real y2
    local real z2
    local integer in
    local group g
    local unit p
    if not d.spread then
        if d.tick == 0 then
            set g = GetUnitsInRange( GetUnitX(d.d), GetUnitY(d.d) , d.aoe , Condition( function SwordF ) )
            loop
                set p = FirstOfGroup(g)
                exitwhen p == null
                call GroupRemoveUnit(g,p)
                if not IsUnitInGroup(p,HITSFX) then
                    call DestroyEffect( AddSpecialEffectTarget(SwordHitSFX ,p,SwordHitSFX_A ) )
                    call GroupAddUnit(HITSFX,p)
                    call HitSFXSkip.execute(p)
                endif
                call UnitDamageTarget(d.c,p, d.dmg, false, true, ATKTYPE, DMGTYPE ,ConvertWeaponType(6) )
            endloop
            call ReleaseGroup(g)
            set g = null
            call DestroyEffectDelay.execute(d.e,0.5)
            call KillUnit(d.d)
            call d.destroy()
            return true
        endif
        set d.tick = d.tick - 1
        set x = GetPPX( d.x, -1 * d.dist * Sin( d.sin * (d.tick-1)* bj_DEGTORAD ) , d.angle )
        set y = GetPPY( d.y, -1 * d.dist * Sin( d.sin * (d.tick-1)* bj_DEGTORAD ) , d.angle )
        set x2 = GetPPX( d.x, -1 * d.dist * Sin( d.sin * d.tick * bj_DEGTORAD ) , d.angle )
        set y2 = GetPPY( d.y, -1 * d.dist * Sin( d.sin * d.tick * bj_DEGTORAD ) , d.angle )
        set z = 300. * Sin( (d.sin*2) * (d.tick-1) * bj_DEGTORAD ) + 2.4 * d.tick + 30
        set z2 = 300. * Sin( (d.sin*2) * d.tick * bj_DEGTORAD )  + 2.4 * d.tick + 30
        call SetUnitX(d.d, x2 )
        call SetUnitY(d.d, y2 )
        call SetUnitZ( d.d, z2 )
        
        call SetUnitAnimationByIndex(d.d, R2I(bj_RADTODEG*Atan2((z-z2), SquareRoot((x-x2)*(x-x2) + (y-y2)*(y-y2)) + 0.5) + 90 ) )
    
    else
        if d.tick == 0 then
            set d.angle = AngleLocXY(d.dx, d.dy, d.x,d.y)
            set d.dist = DistanceLocXY(d.dx, d.dy, d.x,d.y)
            call SetUnitFacing(d.d,d.angle)
            call SetUnitBlendTime(d.d,0.15)
            call SetUnitAnimationByIndex(d.d,180)
            call SetUnitVertexColor(d.d,255,255,255,255)
        endif
        if d.tick == -5 then
            set d.spread = false
            call SetUnitBlendTime(d.d,0.0)
            set d.tick = 25
            set d.sin = 90. / d.tick
            call SetUnitVertexColor(d.d,255,255,255,255)
            return false
        endif
        
        set d.tick = d.tick - 1
        
        if d.tick > 0 then
        
            set d.dx = GetPPX( d.dx, 30. , d.angle )
            set d.dy = GetPPY( d.dy, 30. , d.angle )
            
            call SetUnitX(d.d,d.dx)
            call SetUnitY(d.d,d.dy)
        
        endif
        if d.tick >= 0 then
            call SetUnitVertexColor(d.d,255,255,255,R2I(255*(10-d.tick)*0.1))
        endif
        
    endif
    
    return false
endfunction

private function Sword takes unit c,real cx, real cy, real x, real y, real dmg, real aoe, real angle returns nothing
    local data d = data.create()
    set d.c = c
    set d.dx = cx
    set d.dy = cy
    set d.angle = angle
    set d.x = x
    set d.y = y
    set d.dmg = dmg
    set d.aoe = aoe
    set d.d = CreateUnit(Player(15), DummyId ,d.dx ,d.dy , d.angle )
    call SetUnitScale(d.d,0.6,0.6,0.6)
    call SetUnitVertexColor(d.d,255,255,255,0)
    set d.e = AddSpecialEffectTarget( SwordModel ,d.d,"origin")
    
    set d.tick = 10
    call SetUnitZ( d.d, 100. )
    
    call TT_Start( function SwordE , d )
    
endfunction

private function Act takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local location loc = GetSpellTargetLoc()
    local real x = GetLocationX(loc)
    local real y = GetLocationY(loc)
    local real cx = GetUnitX(c)
    local real cy = GetUnitY(c)
    local integer lvl = GetUnitAbilityLevel(c,AbilId)
    local real dmg = GetDamagePerSword(lvl)
    local real aoe = GetSwordDamageAOE(lvl)
    local integer count = GetNumberSwords(lvl)
    local real spreadang = 360. / count
    local real barrAOE = GetBarrageAOE(lvl)
    local real dist
    local real ang
    local integer i = 1
    
    loop
        exitwhen i > count
        set dist = GetRandomReal(50. , barrAOE - 50. )
        set ang = GetRandomReal( 0, 359. )
        call Sword( c, cx, cy, GetPPX(x, dist, ang ), GetPPY(y, dist, ang ), dmg, aoe, spreadang * i )
        set i = i + 1
    endloop
    
    call RemoveLocation(loc)
    set loc = null
    set c = null
endfunction

private function Cond takes nothing returns boolean
    return GetSpellAbilityId() == AbilId
endfunction

public function Init takes nothing returns nothing
    local trigger t = CreateTrigger( )
    
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddAction( t, function Act )
    call TriggerAddCondition( t, Condition( function Cond  ) )
    
    set t = null

endfunction


endscope

Second spell: Infernal Impact (It needs a different name :( )
- Description:
Thanatos channels for 2 seconds and throws his blade spinning toward a direction, damages enemies on a line at 700 range and returns to his hand.
Each enemy units on the effective range being hit increases damage by +10% per target.
- Screenshot:
infernalimpactic9.jpg
- Code:
JASS:
scope InfernalImpact initializer Init 

globals
    private constant integer AbilId = 'A002'//raw id of the spell
    private constant integer SwordAttachementAbilId = 'A000' //ability has the attachment of Thanatos's Sword
    private constant integer DummyId = 'n003' //raw id of the dummy unit (requires: dummy.mdx )
    private constant string SwordModel = "GreatSwordRibbon.mdx" //an imported attachment model - model of the swords
    private constant real SwordDamageAOE = 300. //range for damaging
    private constant string SwordHitSFX = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl" //on hit sfx
    private constant string SwordHitSFX_A = "origin" //attachment point of on hit sfx
    private constant attacktype ATKTYPE = ATTACK_TYPE_CHAOS
    private constant damagetype DMGTYPE = DAMAGE_TYPE_NORMAL
    private constant weapontype WEPTYPE = WEAPON_TYPE_METAL_HEAVY_SLICE
endglobals

private function GetInitialDamage takes integer lvl returns real
    return ( 50. * lvl )
endfunction

private function GetDamageIncrease takes integer lvl returns real 
    return 0.1
endfunction
//======================
private struct data
    unit c
    real cx
    real cy
    
    real ang
    real dmg
    real dmginc
    group g
    group hit
    integer tick
    integer tickmax
endstruct

private struct sdata
    real trans
    effect sfx
    integer index
endstruct

private function InfernalImpactFilter takes nothing returns boolean
    local data d = TT_GetData()
    local unit f = GetFilterUnit()
    local boolean ok = false
    if GetWidgetLife(f) > 0.405 then
        if IsUnitEnemy(f,GetOwningPlayer(d.c)) then
            if not IsUnitInGroup(f,d.hit) then
                set ok = true
            endif
        endif
    endif
    set f = null
    return ok
endfunction

private function InfernalImpactEF takes nothing returns nothing
    local data d = TT_GetData()
    local unit e = GetEnumUnit()
    local sdata sd = GetUnitUserData(e)
    
    set sd.trans = sd.trans - 0.1
    call SetUnitVertexColor( e, 255,255,255, R2I(180 * sd.trans ) )
    if sd.trans <= 0 then
        call DestroyEffect(sd.sfx)
        call sd.destroy()
        call GroupRemoveUnit(d.g,e)
        call KillUnit(e)
    endif
    set e = null
endfunction

private function InfernalImpactE takes nothing returns boolean
    local data d = TT_GetData()
    local sdata sd
    local unit u
    local real cx
    local real cy
    local real cf
    local group g
    local unit p
    local sound soundHandle
    
    if ModuloInteger(d.tick - 7 , 20 ) == 0 then
        set soundHandle = CreateSound("Units\\Orc\\HeroBladeMaster\\BladeMasterWhirlwind.wav", false, true, true, 12700, 12700, "")
        call SetSoundPosition(soundHandle, d.cx, d.cy, 0 )
        call StartSound(soundHandle)
        call KillSoundWhenDone(soundHandle)
        set soundHandle = null
    endif
    
    if d.tick == (d.tickmax-11) + 1 then
        call SetUnitTimeScale(d.c,0.)
    endif
    
    if d.tick > 0 then
    
    
        if d.tick == (d.tickmax-1)/2 + 1 then
            set d.ang = d.ang + 180
        endif
        if d.tick < (d.tickmax-1)/2 + 1 then
            set d.ang = AngleLocXY( d.cx, d.cy, GetUnitX(d.c), GetUnitY(d.c) )
        endif
        
        set d.cx = GetPPX( d.cx, 15, d.ang )
        set d.cy = GetPPY( d.cy, 15, d.ang )
        
        set cf = d.ang+(d.tickmax-d.tick)*20
        set cx = GetPPX( d.cx, 0. , cf )
        set cy = GetPPY( d.cy, 0. , cf )
        
        set u = CreateUnit( GetOwningPlayer(d.c)  , DummyId ,  cx, cy, cf - 90 )
        call SetUnitVertexColor(u,255,255,255,180)
        call SetUnitZ( u , 60. )
        
        set sd = sdata.create()
        set sd.index = d.tick
        set sd.trans = 1
        set sd.sfx = AddSpecialEffectTarget(SwordModel, u, "origin" )
        call SetUnitUserData(u,sd)
        call GroupAddUnit(d.g, u )
        
        set g = GetUnitsInRange(cx,cy,  SwordDamageAOE  ,Condition( function InfernalImpactFilter ) )
        loop
            set p = FirstOfGroup(g)
            exitwhen p == null
            call GroupRemoveUnit(g,p)
            if IsUnitInFront(p,u) then
                call DestroyEffect( AddSpecialEffectTarget(SwordHitSFX ,p,SwordHitSFX_A ) )
                call UnitDamageTarget(d.c, p , d.dmg , false, true, ATKTYPE, DMGTYPE, WEPTYPE )
                call GroupAddUnit(d.hit,p)
                set d.dmg = d.dmg * ( 1 + d.dmginc )
            endif
        endloop
        call ReleaseGroup(g)
        set g = null
        
        set u = null
        //set d.ang = d.ang + 20.
        set d.tick = d.tick - 1
    endif
    
    call ForGroup( d.g, function InfernalImpactEF )
    
    if FirstOfGroup(d.g) == null then
        call SetUnitTimeScale(d.c,1.)
        call UnitAddAbility(d.c,SwordAttachementAbilId)
        call ReleaseGroup(d.g)
        call ReleaseGroup(d.hit)
        call d.destroy()
        return true
    endif
    return false
endfunction

function Act takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local location loc = GetSpellTargetLoc()
    local real tx = GetLocationX(loc)
    local real ty = GetLocationY(loc)
    local integer lvl = GetUnitAbilityLevel(c,AbilId)
    local data d = data.create()
    set d.c = c
    set d.cx = GetUnitX(c)
    set d.cy = GetUnitY(c)
    set d.hit = NewGroup()
    set d.g = NewGroup()
    set d.dmg = GetInitialDamage(lvl)
    set d.dmginc = GetDamageIncrease(lvl)
    call UnitRemoveAbility(c, SwordAttachementAbilId )
    
    set d.ang = AngleLocXY( d.cx, d.cy, tx, ty )
    set d.tick = 96 + 1
    set d.tickmax = d.tick
    
    call TT_StartEx( function InfernalImpactE, d, 0.02 )
    
endfunction

private function Cond takes nothing returns boolean
    return GetSpellAbilityId() == AbilId
endfunction

public function Init takes nothing returns nothing
    local trigger t = CreateTrigger( )
    
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddAction( t, function Act )
    call TriggerAddCondition( t, Condition( function Cond  ) )
    
    set t = null

endfunction


endscope

Third spell: Phantom Swing
- Description:
Every time Thanatos attacks, he has a chance to summon phantom swords that spin around him. Theses swords damages directly into the soul of enemies, destroying their mana and dealing 1.5 damage per destroyed mana point.
Enemies who don't have mana will take damage equal to this amount.
Cooldown: 1 seconds.
- Screenshot:
phantomswingse8.jpg
- Code:
JASS:
scope PhantomSwingCast initializer Init 

globals
    private constant integer AbilId = 'A003' //raw id of the spell
    private constant integer DummyId = 'n003' //raw id of the dummy (requires: dummy.mdx )
    private constant string SwordModel = "GreatSwordRibbon.mdx"  //an imported attachment model - model of the swords
    private constant real SwordDamageAOE = 300. //range for damaging
    private constant string SwordHitSFX = "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl"//on hit sfx with mana break
    private constant string SwordHitSFX_A = "origin" //attachment point for on hit sfx with mana break
    private constant string SwordHitSFX2 = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"//on hit sfx without mana break
    private constant string SwordHitSFX2_A = "origin" //attachment point for on hit sfx without mana break
    private constant attacktype ATKTYPE = ATTACK_TYPE_CHAOS
    private constant damagetype DMGTYPE = DAMAGE_TYPE_NORMAL
    private constant weapontype WEPTYPE = WEAPON_TYPE_METAL_HEAVY_SLICE
    //-----------------------
    private group InCooldown = CreateGroup()
endglobals

private function GetChance takes integer lvl returns integer
    return (8+2*lvl)
endfunction

private function GetManaBreakAmount takes integer lvl returns real
    return (50.+25*lvl)
endfunction

private function GetDamagePerMPBreak takes integer lvl returns real
    return 1.5
endfunction

private function GetCooldown takes integer lvl returns real
    return 1. 
endfunction

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

private struct data
    unit c
    real cx
    real cy
    real dmg
    real mnbr
    real ang
    group g
    group hit
    integer tick
    integer tickmax
endstruct

private struct sdata
    real trans
    effect sfx
endstruct

private function PhantomSwingFilter takes nothing returns boolean
    local data d = TT_GetData()
    local unit f = GetFilterUnit()
    local boolean ok = false
    if GetWidgetLife(f) > 0.405 then
        if IsUnitEnemy(f,GetOwningPlayer(d.c)) then
            if not IsUnitInGroup(f,d.hit) then
                set ok = true
            endif
        endif
    endif
    set f = null
    return ok
endfunction

private function PhantomSwingEF takes nothing returns nothing
    local data d = TT_GetData()
    local unit e = GetEnumUnit()
    local sdata sd = GetUnitUserData(e)
    
    set sd.trans = sd.trans - 0.1
    call SetUnitVertexColor( e, 255,255,255, R2I(160 * sd.trans ) )
    if sd.trans <= 0 then
        call DestroyEffect(sd.sfx)
        call sd.destroy()
        call GroupRemoveUnit(d.g,e)
        call KillUnit(e)
    endif
    set e = null
endfunction

private function PhantomSwingE takes nothing returns boolean
    local data d = TT_GetData()
    local sdata sd
    local unit u
    local real cx
    local real cy
    local real cf
    local group g
    local unit p
    local real pMP
    local real dmg
    
    if d.tick > 0 then
    
        set d.cx = GetUnitX(d.c)
        set d.cy = GetUnitY(d.c)
        set cf = d.ang+(d.tickmax-d.tick)*20
        set cx = GetPPX( d.cx, 50. , cf )
        set cy = GetPPY( d.cy, 50. , cf )
        set u = CreateUnit( GetOwningPlayer(d.c)  , DummyId   ,  cx, cy, cf )
        call SetUnitScale(u,1.,1.,1.)
        call SetUnitZ( u , 60. )
        
        set sd = sdata.create()
        set sd.trans = 1
        set sd.sfx = AddSpecialEffectTarget( SwordModel , u, "origin" )
        call SetUnitVertexColor(u,255,255,255,160)
        call SetUnitUserData(u,sd)
        call GroupAddUnit(d.g, u )
        
        set g = GetUnitsInRange(cx,cy, SwordDamageAOE ,Condition( function PhantomSwingFilter ) )
        loop
            set p = FirstOfGroup(g)
            exitwhen p == null
            call GroupRemoveUnit(g,p)
            if IsUnitInFront(p,u) then
                
                if GetUnitState(p,UNIT_STATE_MAX_MANA) > 0 then
                    call DestroyEffect( AddSpecialEffectTarget(SwordHitSFX ,p,SwordHitSFX_A ) )
                    set pMP = GetUnitState(p,UNIT_STATE_MANA)
                    if pMP > d.mnbr then
                        set dmg = d.mnbr * d.dmg
                        set pMP = pMP - d.mnbr
                    else
                        set dmg = pMP * d.dmg
                        set pMP = 0
                    endif
                    call SetUnitState(p,UNIT_STATE_MANA,pMP)
                    call UnitDamageTarget(d.c, p , dmg , false, true, ATKTYPE, DMGTYPE, WEPTYPE )
                else
                    call DestroyEffect( AddSpecialEffectTarget(SwordHitSFX2 ,p,SwordHitSFX2_A ) )
                    call UnitDamageTarget(d.c, p , d.mnbr , false, true, ATKTYPE, DMGTYPE, WEPTYPE )
                endif
                
                call GroupAddUnit(d.hit,p)
            endif
        endloop
        call ReleaseGroup(g)
        set g = null
        set u = null
        
        set d.tick = d.tick - 1
    endif

    call ForGroup( d.g, function PhantomSwingEF )
    
    if FirstOfGroup(d.g) == null then
        call ReleaseGroup(d.g)
        call ReleaseGroup(d.hit)
        call d.destroy()
        return true
    endif
    return false
endfunction

private function Act takes nothing returns nothing
    local unit c = GetAttacker()
    local integer lvl = GetUnitAbilityLevel(c,AbilId)
    local data d
    local sound soundHandle
    if GetRandomInt( 1, 100 ) > GetChance(lvl) then
        set c = null
        return
    endif
    set soundHandle = CreateSound("Units\\Orc\\HeroBladeMaster\\BladeMasterWhirlwind.wav", false, true, true, 12700, 12700, "")
    call SetSoundPosition(soundHandle, GetUnitX(c), GetUnitY(c), 0 )
    call StartSound(soundHandle)
    call KillSoundWhenDone(soundHandle)
    set soundHandle = null
    set d = data.create()
    set d.c = c
    set d.cx = GetUnitX(c)
    set d.cy = GetUnitY(c)
    set d.mnbr = GetManaBreakAmount(lvl)
    set d.dmg = GetDamagePerMPBreak(lvl)
    set d.ang = GetUnitFacing(c)
    set d.g = NewGroup()
    set d.hit = NewGroup()
    set d.tick = 18 + 1
    set d.tickmax = d.tick
    call TT_StartEx( function PhantomSwingE, d, 0.03 )
    
    call GroupAddUnit(InCooldown,c)
    call TriggerSleepAction( GetCooldown(lvl) )
    call GroupRemoveUnit(InCooldown,c)
    set c = null
endfunction

private function Cond takes nothing returns boolean
    return GetUnitAbilityLevel( GetAttacker(), AbilId ) > 0 and not IsUnitInGroup( GetAttacker() , InCooldown )
endfunction

public function Init takes nothing returns nothing
    local trigger t = CreateTrigger( )
    
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ATTACKED)
    call TriggerAddAction( t, function Act )
    call TriggerAddCondition( t, Condition( function Cond  ) )
    
    set t = null

endfunction


endscope

Ultimate spell: Infernal Stigma
- Description:
With an etremely fast glide, Thanatos moves around the battlefield, damages and engraves enemy units on his wake with Marks of Abyss. He then leap back to previous position with lightning-fast movement and damages all enemy units who bear the Marks of Abyss.
(Should I call it "Marks of Chaos" instead ? )
- Screenshot:
attachment.php
- Code:
JASS:
scope InfernalStigmaCast initializer Init 

globals
    private constant integer AbilId = 'A004' //raw id of the spell
    private constant integer DummyId = 'n001' //raw id of the dummy (requires: dummy.mdx )
    private constant integer SwordAttachementAbilId = 'A000' //ability has the attachment of Thanatos's Sword
    private constant string WeaponAttachmentSFX = "Abilities\\Weapons\\ZigguratMissile\\ZigguratMissile.mdl" //the effect attached to weapon of Thanatos when he's casting this spell
    private constant string MarkofChaosSFXpath = "MarkOfAbyss.mdx" //Mark of Chaos's sfx path
    private constant string MarkofChaosExplodeSFXpath = "MarkOfAbyssExplode.mdx" //Mark of Chaos explosion's sfx path
    private constant integer ThanatosShadowId = 'n004' //raw id of dummy unit - Thanatos's Shaodw
    private constant string StrikeHitSFX = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl" //effect on unit who are struck
    private constant string StrikeHitSFX_A = "origin" //attachment point of the above effect
    private constant string ExplodeHitSFX = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl" //effect on unit who are hit by the explosions
    private constant string ExplodeHitSFX_A = "origin" //attachment point of the above effect
    private constant string MovesSFX = "Abilities\\Spells\\NightElf\\Blink\\BlinkTarget.mdl" //sfx when he moves
    private constant attacktype ATKTYPE = ATTACK_TYPE_CHAOS
    private constant damagetype DMGTYPE = DAMAGE_TYPE_NORMAL
    private constant damagetype DMGTYPE2 = DAMAGE_TYPE_MAGIC
    private constant weapontype WEPTYPE = WEAPON_TYPE_METAL_HEAVY_SLICE
endglobals

private function GetStrikeDamage takes unit c, integer lvl returns real
    return GetHeroAgi(c,true) * ( 1.+lvl )
endfunction

private function GetExplodeDamage takes integer lvl returns real
    return ( 50.+50*lvl )
endfunction

private function GetTargetCount takes integer lvl returns integer
    return 4+2*lvl
endfunction

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

private struct data
    unit c
    unit a
    unit d
    unit u
    real cx
    real cy
    real dx
    real dy
    group g
    effect ef
    unit array m [10]
    unit array md [10]
    effect array me [10]
    integer mk = -1
    integer mkm = -1
    boolean finish = false
    
    real dist
    real angle
    real dmg
    real dmgexp
    integer lvl
    integer tick
    integer count
    boolean pau = false
endstruct

private function InfernalStigmaF takes nothing returns boolean
    local data d = TT_GetData()
    local unit f = GetFilterUnit()
    local boolean ok = false
    if GetWidgetLife(f) > 0.405 then
        if IsUnitEnemy(f,GetOwningPlayer(d.c)) then
            if not IsUnitInGroup(f,d.g) then
                set ok = true
            endif
        endif
    endif
    return ok
endfunction

private function InfernalStigmaE takes nothing returns boolean
    local data d = TT_GetData()
    local integer i
    local integer array ani
    local real dist
    local group g
    local unit p
    if not d.pau then
        call PauseUnit(d.c,true)
        call SetUnitInvulnerable(d.c,true)
        call SetUnitPathing(d.c,false)
        call IssueImmediateOrder(d.c,"stop")
        call SetUnitVertexColor(d.c,255,255,255,127)
        set d.pau = true
    endif
    //----
    if d.finish then
        if d.tick <= -1 then
            if d.tick == -1 then
            call SetUnitX(d.c,d.cx)
            call SetUnitY(d.c,d.cy)
            call SetUnitFacing(d.c, AngleLocXY(d.cx,d.cy,d.dx,d.dy) )
            call SetUnitAnimation(d.c,"Spell")
            call QueueUnitAnimation(d.c,"Ready")
            endif
            if d.tick <= -12 then
            call ReleaseGroup(d.g)
            set g = NewGroup()
            set i = d.mkm
            loop
                exitwhen i <= -1
                call PauseUnit(d.m<i>,false)
                call SetUnitAnimationByIndex(d.md[d.mk],90)
                call DestroyEffect( AddSpecialEffectTarget(MarkofChaosExplodeSFXpath,d.md<i>,&quot;origin&quot;) )
                call DestroyEffect(d.me<i>)
                call UnitApplyTimedLife(d.md<i>,&#039;BTLF&#039;,1.0)
                
                call EnumUnitsInRange( g, GetUnitX(d.m<i>), GetUnitY(d.m<i>), 300. , Condition( function InfernalStigmaF )  )
                loop
                    set p = FirstOfGroup(g)
                    exitwhen p == null
                    call GroupRemoveUnit(g,p)
                    if ExplodeHitSFX != null then
                        call DestroyEffect( AddSpecialEffectTarget(ExplodeHitSFX,p,ExplodeHitSFX_A) ) 
                    endif
                    call UnitDamageTarget(d.c,p,d.dmgexp,false,true,ATKTYPE,DMGTYPE2,null)
                endloop
                set p = null
                set i = i - 1
            endloop
            call ReleaseGroup(g)
            set g = null
            call DestroyEffect(d.ef)
            call PauseUnit(d.c,false)
            call SetUnitTimeScale(d.c,1.0)
            call SetUnitVertexColor(d.c,255,255,255,255)
            call SetUnitInvulnerable(d.c,false)
            call SetUnitPathing(d.c,true)
            call d.destroy()
            return true
            endif
        else
            call SetUnitX(d.c,  GetUnitX(d.m[d.mk]) )
            call SetUnitY(d.c,  GetUnitY(d.m[d.mk]) )
            set d.mk = d.mk - 1
        
        endif
    else
        if d.a != null then
            if d.tick == 10 then
                set d.angle = GetRandomReal(1.,360.)
                call SetUnitFacing(d.c,d.angle+180.)
                call SetUnitX(d.c, GetPPX(GetUnitX(d.a), 150. , d.angle)  )
                call SetUnitY(d.c, GetPPY(GetUnitY(d.a), 150. , d.angle)  )
                call DestroyEffect( AddSpecialEffect(MovesSFX,GetUnitX(d.c),GetUnitY(d.c)) )
                set ani[0] = 1
                set ani[1] = 2
                set ani[2] = 7
                set i = GetRandomInt(0,2)
                
                call SetUnitAnimationByIndex(d.c, ani<i> )
                set d.u = CreateUnit(GetOwningPlayer(d.c),ThanatosShadowId, GetUnitX(d.c), GetUnitY(d.c), GetUnitFacing(d.c) )
                call UnitAddAbility(d.u,SwordAttachementAbilId)
                call SetUnitVertexColor(d.u,255,255,255,0)
                call SetUnitAnimationByIndex(d.u,ani<i>)
                call QueueUnitAnimation(d.u,&quot;Ready&quot;)
            endif
            call SetUnitFacing(d.c, AngleUnits(d.c,d.a) )
            call SetUnitFacing(d.u, AngleUnits(d.u,d.a) )
            
            if d.tick == -2 then
                call DestroyEffect( AddSpecialEffect(MovesSFX,GetUnitX(d.c),GetUnitY(d.c)) )
                set d.mk = d.mk + 1
                set d.mkm = d.mk
                set d.m[d.mk] = d.a
                set d.md[d.mk] = CreateUnit(Player(15), DummyId, GetUnitX(d.a), GetUnitY(d.a) , d.angle)
                call SetUnitAnimationByIndex(d.md[d.mk],30+120*GetRandomInt(0,1))
                call SetUnitScale(d.md[d.mk],2.,2.,2.)
                call SetUnitZ(d.md[d.mk],100.)
                set d.me[d.mk] = AddSpecialEffectTarget(MarkofChaosSFXpath,d.md[d.mk],&quot;origin&quot;)
                call PauseUnit(d.a,true)
                call GroupAddUnit(d.g,d.a)
                call UnitDamageTarget(d.c,d.a,d.dmg,false,true,ATKTYPE,DMGTYPE,WEPTYPE )
                call DestroyEffect( AddSpecialEffectTarget(StrikeHitSFX,d.a,StrikeHitSFX_A) )
            endif
            
            if d.tick == -5 then
              if d.count &gt; 0 then
                set g = GetUnitsInRange( GetUnitX(d.a), GetUnitY(d.a), 500. , Condition( function InfernalStigmaF )  )
                set d.a = GroupPickRandomUnit(g)
                call ReleaseGroup(g)
                set g = null
                set d.count = d.count - 1
              endif
              
                if d.a == null or d.count == 0 then
                    set d.finish = true
                    set d.tick = d.mk
                    set d.mkm = d.mk
                else
                    set d.tick = 11
                endif
                
                call SetUnitVertexColor(d.u,255,255,255,127)
                call UnitApplyTimedLife(d.u,&#039;BTLF&#039;,0.4)
            endif
            
        endif
    endif
    set i = d.mkm
    loop
        exitwhen i &lt;= -1
        call SetUnitX(d.md<i>,GetUnitX(d.m<i>))
        call SetUnitY(d.md<i>,GetUnitY(d.m<i>))
        set i = i - 1
    endloop
            
    set d.tick = d.tick - 1
    return false
endfunction

private function Act takes nothing returns nothing
    local data d = data.create()
    set d.c = GetTriggerUnit()
    set d.a = GetSpellTargetUnit()
    set d.g = NewGroup()
    set d.tick = 10
    set d.cx = GetUnitX(d.c)
    set d.cy = GetUnitY(d.c)
    set d.lvl = GetUnitAbilityLevel(d.c,AbilId)
    set d.dmg = GetStrikeDamage(d.c,d.lvl)
    set d.dmgexp = GetExplodeDamage(d.lvl)
    set d.count = GetTargetCount(d.lvl)
    set d.ef = AddSpecialEffectTarget(WeaponAttachmentSFX,d.c,&quot;weapon&quot;)
    set d.dx = GetUnitX(d.a)
    set d.dy = GetUnitY(d.a)
    call DestroyEffect( AddSpecialEffect(MovesSFX,GetUnitX(d.c),GetUnitY(d.c) ))
    call TT_Start( function InfernalStigmaE , d )
endfunction

private function Cond takes nothing returns boolean
    return GetSpellAbilityId() == AbilId
endfunction

public function Init takes nothing returns nothing
    local trigger t = CreateTrigger( )
    
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddAction( t, function Act )
    call TriggerAddCondition( t, Condition( function Cond  ) )
    
    set t = null

endfunction

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


Import Instruction
-Import all nessessary models
-Go to the Object Editor \ Abilities, copy Thanatos's Sword (A000), Sword Barrage (A001), Infernal Impact (A002), Phantom Swing (A003), Infernal Stigma (A004)
-Then at Object Editor \ Units, copy Lord of Destruction (N000) (if you want), Dummy Unit (n001), Dummy Unit (Alternate Attachment) (n002), Dummy Unit (Alternate Attachment -90 Roll) (n003), Dummy Unit - Thanatos's Shadow) (n004)
-Go to the Trigger Editor and copy TT (if you don't have it already), CSData and CSSafety (copy them if you don't have ), UtilityFuncs (some "BJ-like" functions, copy them if you don't have), SwordBarrage, InfernalImpact, PhantomSwing, InfernalStigma then change the raw id of the abilities, units in the globals.

Credits
- thanks Tinki3 for the test map template
- thanks Vexorian for CSData and CSSafety
- thanks Cohadar for TT
- Sword model by HappyTauren (hiveworkshop) (its original name is Old Sword)
- thanks WILL THE ALMIGHTY (Wc3campaigns) for the explosion effect (it's actually his "Laser" )
- the model ThanatosLoD (I have renamed it :) ), I really don't remember the creator of this, so if anyone know, please tell me.

------------
EDIT: attached the map.
EDIT2: update the ultimate. I have a little trouble with the explosion effect but I think it's fine now :D
EDIT3: update the Import Instruction
 

Attachments

  • Infernal Stigma.JPG
    Infernal Stigma.JPG
    180.2 KB · Views: 451
  • [Spellpack] Thanatos.w3x
    242.7 KB · Views: 282

Kenny

Back for now.
Reaction score
202
These spells look pretty cool. Screenshots looks mad and i cant see anything wrong with codes at first glance.

However, is there a reason why you did this:

JASS:
function PhantomSwingFilter takes nothing returns boolean
    local data d = TT_GetData()
    local unit f = GetFilterUnit()
    local boolean ok = true
    if GetWidgetLife(f) &lt; 0.405 then
        set ok = false
    endif
    if IsUnitAlly(f,GetOwningPlayer(d.c)) then
        set ok = false
    endif
    if IsUnitInGroup(f,d.hit) then
        set ok = false
    endif
    set f = null
    return ok
endfunction


Instead of what you set it out like in the first spell:

JASS:
private function SwordF takes nothing returns boolean
    local data d = TT_GetData()
    local unit f = GetFilterUnit()
    local boolean ok = ( GetWidgetLife(f) &gt; 0.405 and IsUnitEnemy(f,GetOwningPlayer(d.c)))
    set f = null
    return ok
endfunction


Also there are a few functions in your coding that don't have the private prefix. Again, is there a reason?

JASS:
set Int = 0
    call ForGroup( d.g, function PhantomSwingEF )
    
    if Int == 0 then
        call ReleaseGroup(d.g)
        call ReleaseGroup(d.hit)
        call d.destroy()
        return true
    endif
    return false


You could just use a FirstOfGroup(d.g) loop instead.

The above are nothing serious at all, it just comes down to preference as they wont really make a noticable difference.

EDIT:

While testing i came across an error. A double free of sdata in phantom swing.
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
@kenny!, thank you !

those conditional functions. there are no particular reasons. it's just that I didn't make these spells at a time, so different time -> different..... emotion ( lol ) ! :D
I'm gonna fix them now.

and the prefixes, I forgot to add them :p

the double free, I counter it now, but I don't know how did it happen :(

updated the first post :)

P/S: I think I should +rep to you, kenny! :)
 

Psiblade94122

In need of sleep
Reaction score
138
thanatos god of death is fine

i think for the rain of blades you can have it so that the blades are spawned around the AoE then fly into the AoE area, just a graphical suggestion
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
thanatos god of death is fine

i think for the rain of blades you can have it so that the blades are spawned around the AoE then fly into the AoE area, just a graphical suggestion

ok, God of Death :D (+rep)
If you got a better name, please tell me.

about tbe graphical suggestion, hmm.... I will consider it later.
now I'm working on his ultimate.
 

Switch33

New Member
Reaction score
12
- My current trouble is: the spells Infernal Impact and Phantom Swing. Because a unit can't face an angle instantly, so I have to create many units and then fade them over time => many units are created => is that a problem ? ( I refer to the "number of handle" - if I use these spells many times, will I got lag ? )

JASS:
call SetUnitFacing(u, angle)
is instant. . . If your refering to Z type angle facings then i advise using the dummy model found in Vexorian's caster system made by Infrane and Vex's Z angle changing code in his caster system.

Also it's been quite a long time since this has been posted any update in mind soon? I'm curious about what the ultimate will be like.

Love the spells sfx though, coolest sword throw i've seen for wc3 so far!
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
Updated the pack !
added an ultimate spell: Infernal Stigma :D
---
@Switch33, SetUnitFacing isn't instant :(
---
@simonake, [noparse]
<your things>
[/noparse]
 

Switch33

New Member
Reaction score
12
Even if you set turning speed to like 99999.0 ?? Maybe that has an effect on it.
JASS:
call SetUnitTurnSpeed(u, 99999.0)


Btw, like the effect for the ultimate but i dunno i never really liked spells that were "tele and hit everyone and tele away" like omnilash stuff etc. since it seems a bit overpowered but heck it's an ultimate wtever... lol
 

D.V.D

Make a wish
Reaction score
73
I think you should call the last ability mark of chaos. BTW, why isn't this approved? Its easy to edit, it works perfectly,and its cool. Also, how did you change the MaxPitchRollAngle degrees?
 

Tom_Kazansky

--- wraith it ! ---
Reaction score
157
another update :)

now the Marks of Abyss is called Marks of Chaos instead.

update the Import Instruction
---
@Switch33, that does not work :(
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top