Spellpack Dread Coil, Carneval of Evil Spirits and Vampiric Soul

Hatebreeder

So many apples
Reaction score
381
Alright, so I was bored, and I wanted to play around with some vJass.
Sooooooo... I came up with this Spell Pack:
DREAD COIL: Summons a Coil, which Holds the First Unit it encounters, and pulls it back to the Caster. A Somewhat Pseudo version of the Meat Hook.
JASS:
scope DreadCoil
globals
private unit CASTER
private constant integer DUMMY = 'u001'
private group GROUP = CreateGroup()
private group DEGROUP = CreateGroup()
endglobals

private struct Dread
unit Dummy
unit PickedUnit
real Angle
real CasterX
real CasterY
real TargetX
real TargetY
real DummyX
real DummyY
real Distance
boolean Bool
lightning Zap
endstruct

function Dread_Coil_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function Dread_Coil_Filter takes nothing returns boolean
    return IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_DEAD) == false and IsUnitType(GetFilterUnit(),UNIT_TYPE_MAGIC_IMMUNE) == false and IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(CASTER)) == true
endfunction

function Dread_Coil_Timer takes nothing returns nothing
local timer Timer = GetExpiredTimer()
local Dread Data = GetTimerStructA(Timer)

    if Data.Bool == false then
        set Data.CasterX = GetUnitX( CASTER )
        set Data.CasterY = GetUnitY( CASTER )
        set Data.DummyX = GetUnitX(Data.Dummy) + 12 * Cos(Data.Angle * bj_DEGTORAD)
        set Data.DummyY = GetUnitY(Data.Dummy) + 12 * Sin(Data.Angle * bj_DEGTORAD)
        set Data.Distance = Data.Distance + 12
        call SetUnitPosition(Data.Dummy,Data.DummyX,Data.DummyY)
        call MoveLightning(Data.Zap,false,Data.CasterX,Data.CasterY,Data.DummyX,Data.DummyY)
        call GroupEnumUnitsInRange(GROUP,Data.DummyX,Data.DummyY,100,Condition(function Dread_Coil_Filter))
        set Data.PickedUnit = FirstOfGroup(GROUP)
            if Data.PickedUnit != null then
            set Data.Bool = true
            endif
            endif
                if Data.Bool == true then
                set Data.CasterX = GetUnitX( CASTER )
                set Data.CasterY = GetUnitY( CASTER )
                set Data.Angle = bj_RADTODEG * Atan2( Data.TargetY - Data.CasterY, Data.TargetX - Data.CasterX )
                set Data.DummyX = GetUnitX(Data.Dummy) - 12 * Cos(Data.Angle * bj_DEGTORAD)
                set Data.DummyY = GetUnitY(Data.Dummy) - 12 * Sin(Data.Angle * bj_DEGTORAD)
                call MoveLightning(Data.Zap,false,Data.CasterX,Data.CasterY,Data.DummyX,Data.DummyY)
                call SetUnitPosition(Data.Dummy,Data.DummyX,Data.DummyY)
                call SetUnitPosition(Data.PickedUnit,Data.DummyX,Data.DummyY)
                set Data.Distance = Data.Distance - 12
                if IsUnitInGroup(Data.PickedUnit,DEGROUP) == false then
                call SetUnitPathing(Data.PickedUnit,false)
                call UnitDamageTarget(CASTER,Data.PickedUnit,Data.Distance,false,true,ATTACK_TYPE_HERO,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
                call GroupAddUnit(DEGROUP,Data.PickedUnit)
                endif
                endif
                    if Data.Distance <= 0 or IsUnitType(Data.PickedUnit,UNIT_TYPE_DEAD) == true or Data.Distance >= 400 + 200 * GetUnitAbilityLevel(CASTER,'A000') then
                    call SetUnitPathing(Data.PickedUnit,true)
                    call DestroyLightning(Data.Zap)
                    call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl",Data.DummyX,Data.DummyY))
                    call KillUnit(Data.Dummy)
                    call GroupClear(DEGROUP)
                    call GroupClear(GROUP)
                    call ClearTimerStructA(Timer)
                    call PauseTimer(Timer)
                    call DestroyTimer(Timer)
                    set Timer = null
                endif
endfunction
    
function Dread_Coil_Actions takes nothing returns nothing
local Dread Data = Dread.create()
local timer Timer = CreateTimer()

set Data.Bool = false
set CASTER = GetTriggerUnit()
set Data.Distance = 1
set Data.CasterX = GetUnitX( CASTER )
set Data.CasterY = GetUnitY( CASTER )
set Data.TargetX = GetLocationX( GetSpellTargetLoc() )
set Data.TargetY = GetLocationY( GetSpellTargetLoc() )
set Data.Angle = bj_RADTODEG * Atan2( Data.TargetY - Data.CasterY, Data.TargetX - Data.CasterX )
set Data.Dummy = CreateUnit(GetOwningPlayer(CASTER),DUMMY, Data.CasterX, Data.CasterY, Data.Angle)
set Data.DummyX = GetUnitX(Data.Dummy) + 12 * Cos(Data.Angle * bj_DEGTORAD)
set Data.DummyY = GetUnitY(Data.Dummy) + 12 * Sin(Data.Angle * bj_DEGTORAD)
call SetUnitPosition(Data.Dummy,Data.DummyX,Data.DummyY)
set Data.Zap = AddLightning("MBUR",false,Data.CasterX,Data.CasterY,Data.DummyX,Data.DummyY)

call SetTimerStructA(Timer,Data)
call TimerStart(Timer,0.02,true,function Dread_Coil_Timer)

set Timer = null
endfunction

//===========================================================================
function InitTrig_Dread_Coil takes nothing returns nothing
    local trigger Dread_Coil = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( Dread_Coil, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( Dread_Coil, Condition( function Dread_Coil_Conditions ) )
    call TriggerAddAction( Dread_Coil, function Dread_Coil_Actions )
endfunction
endscope

Screeny2.jpg

VAMPIRIC SOUL: A passive which enables the attacker to leech apon an opponents life. Damage is based on 50% of the Damage recieved, Leech is based on 50% of the Damage Dealt.
JASS:
scope Vampric

private struct Vamp
unit Attacker
unit Attacked
real Damage
real Leech
endstruct

private function Trig_Vampric_Soul_Conditions takes nothing returns boolean
    return GetUnitAbilityLevel(GetAttacker(), 'A001') != 0
endfunction

private function Trig_Vampric_Soul_Actions takes nothing returns nothing
local Vamp Data = Vamp.create()

if GetRandomInt(0,100) <= GetUnitAbilityLevel(GetAttacker(),'A001') * 7 then
    set Data.Attacker = GetAttacker()
    set Data.Attacked = GetTriggerUnit()
    set Data.Damage = (GetUnitState(Data.Attacker,UNIT_STATE_MAX_LIFE) - GetUnitState(Data.Attacker,UNIT_STATE_LIFE)) * 0.5
    set Data.Leech = Data.Damage * 0.5
    call UnitDamageTarget(Data.Attacker,Data.Attacked,Data.Damage,true,false,ATTACK_TYPE_HERO,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
    call SetUnitLifeBJ(Data.Attacker,GetUnitState(Data.Attacker,UNIT_STATE_LIFE) + Data.Leech)
    call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\VampiricAura\\VampiricAuraTarget.mdl",Data.Attacker,"origin"))
endif
call Data.destroy()
endfunction

//===========================================================================
function InitTrig_Vampric_Soul takes nothing returns nothing
    local trigger Vampric_Soul = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( Vampric_Soul, EVENT_PLAYER_UNIT_ATTACKED )
    call TriggerAddCondition( Vampric_Soul, Condition( function Trig_Vampric_Soul_Conditions ) )
    call TriggerAddAction( Vampric_Soul, function Trig_Vampric_Soul_Actions )
endfunction
endscope

Screeny is hard to get, and the effect isn't that Flashy.

CARNEVAL OF EVIL SOULS: Launches 12 Evil Spirits in all Directions. Any Unit that collides with one of the Spirits freezes in Time. They Break free once the Spirits Vanish
JASS:
scope Soul

globals
constant integer CARN_ANGLES = 12
constant integer CARN_DUMMY = 'u001'
private unit CARN_CASTER
private group CARN_GROUP = CreateGroup()
private group CARN_DEGROUP = CreateGroup()
endglobals

private struct Carn
unit array Soul[100]
integer Count
boolean Bool
real Distance
real Angle
real CasterX
real CasterY
real SoulX
real SoulY
endstruct

private function Trig_Carneval_of_Evil_Souls_Filter takes nothing returns boolean
    return IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(),UNIT_TYPE_MAGIC_IMMUNE) == false and IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD) == false and IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(CARN_CASTER)) == true and IsUnitInGroup(GetFilterUnit(),CARN_DEGROUP) == false
endfunction

private function Trig_Carneval_of_Evil_Souls_Group takes nothing returns nothing
    local unit Carn_Picked = GetEnumUnit()
    call PauseUnit(Carn_Picked,true)
    call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Items\\SpellShieldAmulet\\SpellShieldCaster.mdl",Carn_Picked,"chest"))
    call GroupAddUnit(CARN_DEGROUP,Carn_Picked)
    call UnitDamageTarget(CARN_CASTER,Carn_Picked,80 * GetUnitAbilityLevel(CARN_CASTER,'A002'),false,true,ATTACK_TYPE_HERO,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
    set Carn_Picked = null
endfunction

private function Trig_Carneval_of_Evil_Souls_DeGroup takes nothing returns nothing
    local unit Carn_Picked = GetEnumUnit()
    call PauseUnit(Carn_Picked,false)
    call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Items\\SpellShieldAmulet\\SpellShieldCaster.mdl",Carn_Picked,"chest"))
    set Carn_Picked = null
endfunction

private function Trig_Caneval_of_Evil_Souls_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A002'
endfunction

private function Trig_Carneval_of_Evil_Souls_Timer takes nothing returns nothing
local timer Timer = GetExpiredTimer()
local Carn Data = GetTimerStructA(Timer)
set Data.Count = 0

if Data.Bool == false then
loop
    exitwhen Data.Count >= CARN_ANGLES
    set Data.Count = Data.Count + 1
    set Data.SoulX = GetUnitX(Data.Soul[Data.Count]) + 12 * Cos(Data.Angle * bj_DEGTORAD * Data.Count)
    set Data.SoulY = GetUnitY(Data.Soul[Data.Count]) + 12 * Sin(Data.Angle * bj_DEGTORAD * Data.Count)
    call SetUnitPosition(Data.Soul[Data.Count],Data.SoulX,Data.SoulY)
    call GroupEnumUnitsInRange(CARN_GROUP,Data.SoulX,Data.SoulY,100,Condition(function Trig_Carneval_of_Evil_Souls_Filter))
    call ForGroup(CARN_GROUP,function Trig_Carneval_of_Evil_Souls_Group)
endloop
set Data.Distance = Data.Distance + 12
endif

if Data.Distance >= 500 then
    set Data.Bool = true
endif

if Data.Bool == true then
loop
    exitwhen Data.Count >= CARN_ANGLES
    set Data.Count = Data.Count + 1
    set Data.SoulX = GetUnitX(Data.Soul[Data.Count]) - 12 * Cos(Data.Angle * bj_DEGTORAD * Data.Count)
    set Data.SoulY = GetUnitY(Data.Soul[Data.Count]) - 12 * Sin(Data.Angle * bj_DEGTORAD * Data.Count)
    call SetUnitPosition(Data.Soul[Data.Count],Data.SoulX,Data.SoulY)
    call GroupEnumUnitsInRange(CARN_GROUP,Data.SoulX,Data.SoulY,100,Condition(function Trig_Carneval_of_Evil_Souls_Filter))
    call ForGroup(CARN_GROUP,function Trig_Carneval_of_Evil_Souls_Group)
endloop
set Data.Distance = Data.Distance - 12
endif

if Data.Distance <= 0 or IsUnitType(CARN_CASTER,UNIT_TYPE_DEAD) == true then
set Data.Count = 0
loop
    exitwhen Data.Count >= CARN_ANGLES
    set Data.Count = Data.Count + 1
    call KillUnit(Data.Soul[Data.Count])
endloop
call ForGroup(CARN_DEGROUP,function Trig_Carneval_of_Evil_Souls_DeGroup)
call GroupClear(CARN_GROUP)
call GroupClear(CARN_DEGROUP)
call ClearTimerStructA(Timer)
call PauseTimer(Timer)
call DestroyTimer(Timer)
call Data.destroy()
endif
endfunction

private function Trig_Caneval_of_Evil_Souls_Actions takes nothing returns nothing
local Carn Data = Carn.create()
local timer Timer = CreateTimer()

set CARN_CASTER = GetTriggerUnit()
set Data.CasterX = GetUnitX(CARN_CASTER)
set Data.CasterY = GetUnitY(CARN_CASTER)
set Data.Bool = false
set Data.Distance = 1
set Data.Angle = 360/CARN_ANGLES
set Data.Count = 0
loop
    exitwhen Data.Count >= CARN_ANGLES
    set Data.Count = Data.Count + 1
    set Data.Soul[Data.Count] = CreateUnit(GetOwningPlayer(CARN_CASTER),CARN_DUMMY,Data.CasterX,Data.CasterY,Data.Angle * Data.Count)
endloop

call SetTimerStructA(Timer,Data)

call TimerStart(Timer,0.03,true,function Trig_Carneval_of_Evil_Souls_Timer)
set Timer = null
endfunction

//===========================================================================
function InitTrig_Caneval_of_Evil_Souls takes nothing returns nothing
    local trigger Caneval_of_Evil_Souls = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( Caneval_of_Evil_Souls, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( Caneval_of_Evil_Souls, Condition( function Trig_Caneval_of_Evil_Souls_Conditions ) )
    call TriggerAddAction( Caneval_of_Evil_Souls, function Trig_Caneval_of_Evil_Souls_Actions )
endfunction
endscope

Screeny1.jpg

I hope you like them =)
Please Comment on Code, if possible =)

EDIT* Thankss to Tinki3 for his Spell Test Map =)
 

Attachments

  • Spell Test Map Template - GRASSY.w3x
    69.1 KB · Views: 258

sjakie

Cookie Be Awesome!
Reaction score
127
Looks okay to me :D
But shouldnt u use the ghost or banshee model for your carnaval of evil souls spell?
When I opened the screenie I expected to see souls, but I saw that skull again. Cant you use the skull less often and replace it with ghosts in that spell?
 

Hatebreeder

So many apples
Reaction score
381
Looks okay to me :D
But shouldnt u use the ghost or banshee model for your carnaval of evil souls spell?
When I opened the screenie I expected to see souls, but I saw that skull again. Cant you use the skull less often and replace it with ghosts in that spell?

Ghosts can also look like Skulls, no?
Also, if you want Ghosts, just change the Dummies Model File :p
 

0zaru

Learning vJASS ;)
Reaction score
60
The first one is nice, but the Lightning effect is horrible, maybe adjust its height.
Maybe do the constant globals, privates too.
You forgot to null most triggers in InitTrig functions.
Why uses this BJ? SetUnitLifeBJ.

Don't ever use this warcraft attack detection events! They are evil the fire before the damage is deal!
Use a DamageDetect engine (There are a lot and work fine)
 

Hatebreeder

So many apples
Reaction score
381
The first one is nice, but the Lightning effect is horrible, maybe adjust its height.
Maybe do the constant globals, privates too.
You forgot to null most triggers in InitTrig functions.
Why uses this BJ? SetUnitLifeBJ.

Don't ever use this warcraft attack detection events! They are evil the fire before the damage is deal!
Use a DamageDetect engine (There are a lot and work fine)

Well, the SFX, in this Case the Death Coil floats a bit over the ground... If you use a different Model, then It'll work out.
I used that bj, because I don't understand the Native. In the Native, there is something called bjMax(...) or something. I don't know what that stands for, if someone could explain that to me, that'd be nice =)
Triggers leak?
Can you tell me how to null the "Triggers"? I don't seem to understand that...:eek:
I'll make the constants private, just need a summary of what I need to improve, then I'll update the whole Spell Pack.
Thanks Ozaru for taking your Time looking though my Code.

@Flare,
Well, the ability works like this:
Say you have 1000 Max HP. and your current HP is 800. You lost 200 HP in total. 50% of 200 is 100, so if deals 100 bonus Damage, and from the 100 bonus damage you get 50% in life back, so you gain 50 HP as Leech =)
 

0zaru

Learning vJASS ;)
Reaction score
60
You simple forgot to null them, you are creating a local for them so you can must null the local NOT destroy it.


It's easy:
set <Name>=null

RMaxBJ is just used to know if the value that you put in there is hight than 0, else set it to 0. (As the name says it Returns the Max value)

call SetUnitState(whichUnit,UNIT_STATE_LIFE,<your value>)

It's 0zaru :p
 

Hatebreeder

So many apples
Reaction score
381
You simple forgot to null them, you are creating a local for them so you can must null the local NOT destroy it.


It's easy:
set <Name>=null

RMaxBJ is just used to know if the value that you put in there is hight than 0, else set it to 0. (As the name says it Returns the Max value)

call SetUnitState(whichUnit,UNIT_STATE_LIFE,<your value>)

It's 0zaru :p

Hmmmmz... I will see If I understand that function :p
Alright, so I must do this?
JASS:
function InitTrig_Dread_Coil takes nothing returns nothing
    local trigger Dread_Coil = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( Dread_Coil, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( Dread_Coil, Condition( function Dread_Coil_Conditions ) )
    call TriggerAddAction( Dread_Coil, function Dread_Coil_Actions )
    set Dread_Coil = null
endfunction
 

Hatebreeder

So many apples
Reaction score
381
for Dread Coil

how can we set the damage dealt?

btw the spells are cool

Well, the Damage is based on "Data.Distance" so the further the Target is, the more Damage it deals.
Just change the line
call UnitDamageTarget(...)
change Data.Distance to a Value you want
 

Flare

Stops copies me!
Reaction score
662
just thought of an idea to make the dread coil special effect to look better with the lightning effect. give it a negative flying height, and that should bring it closer to the ground (or have you already done this or has it alredy been suggested). negative fly height definitely works, ive tried it before but that was with a normal unit model, so im unsure on how it would affect a unit with SFX model
 

Hatebreeder

So many apples
Reaction score
381
just thought of an idea to make the dread coil special effect to look better with the lightning effect. give it a negative flying height, and that should bring it closer to the ground (or have you already done this or has it alredy been suggested). negative fly height definitely works, ive tried it before but that was with a normal unit model, so im unsure on how it would affect a unit with SFX model

Should work out. I'll consider this Idea
 
General chit-chat
Help Users

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top