Spellpack Lightning Spirit Spellpack + LightningMissle Model

Hatebreeder

So many apples
Reaction score
381

Requirements:
- Jass New Gen Package
- Cohadars TT (Timer Ticker)


Static Discharge
Imbues ones attacks with a static charge. Static charge discharges apon impact, dealing damage to all units in a 225 AOE, knocking all other units but the target itself away from the impact.
Level 1: adds 25 Damage to each attack
Level 2: adds 50 Damage to each attack
Level 3: adds 75 Damage to each attack
Level 4: adds 100 Damage to each attack
Code:
JASS:
scope StaticDischarge initializer Init
    globals
        private constant integer ID     = 'A000' //Spell ID
        private constant integer LIMIT  = 8191   //Limit of Unit register (initiates reset after it hits limit).
        
        private constant real AOE       = 225.   //Area of Effect of the Spell
        private constant real DISTANCE  = 200.   //Knockback Distance
        private constant real SPEED     = 12.    //Knockback Dpeed
        
        private constant group GROUP    = CreateGroup()
        
        private constant string ORDERID = "flamingarrows"  // Order Id for activation
        private constant string ORDERIDOFF = "unflamingarrows" // Order Id for deactivation
        private constant string FX      = "Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl" //Knockback Dust
        private constant string SFX     = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl" //OnDamage Effect
        
        private trigger array TRIG
        private integer COUNT           = 0
    endglobals
    
    private constant function DamageAmount takes integer Level returns real
        return 25. * Level
    endfunction
    
    private function SetUnitXY takes unit u, real x, real y returns nothing
        if x<GetRectMaxX(bj_mapInitialPlayableArea) and x>GetRectMinX(bj_mapInitialPlayableArea) and y<GetRectMaxY(bj_mapInitialPlayableArea) and y>GetRectMinY(bj_mapInitialPlayableArea) then
            call SetUnitX(u,x)
            call SetUnitY(u,y)
        endif
    endfunction

    private struct Data
        unit Target
        real Dist = DISTANCE
        real Angle
            static method Timer takes nothing returns boolean
                local Data this = TT_GetData()
                local real TX   = GetUnitX(.Target)
                local real TY   = GetUnitY(.Target)
                local real X    = TX + SPEED * Cos(.Angle * bj_DEGTORAD)
                local real Y    = TY + SPEED * Sin(.Angle * bj_DEGTORAD)
                
                set .Dist = .Dist - SPEED
                call DestroyEffect(AddSpecialEffect(FX,X,Y))
                call SetUnitXY(.Target,X,Y)
                
                if .Dist <= 0 or IsUnitType(.Target,UNIT_TYPE_DEAD) == true then
                    call .destroy()
                        return true
                endif
                
                    return false
            endmethod
        
            static method create takes unit u, unit t returns Data
                local Data this = Data.allocate()
                local unit Damager = u
                local real DX = GetUnitX(Damager)
                local real DY = GetUnitY(Damager)
                local real TX
                local real TY
                
                set .Target = t
                set TX      = GetUnitX(.Target)
                set TY      = GetUnitY(.Target)
                set .Angle  = bj_RADTODEG * Atan2(TY - DY,TX - DX)
                
                set Damager = null
                
                if IsUnitType(.Target,UNIT_TYPE_DEAD) == false then
                    call TT_Start(function Data.Timer,this)
                else
                    call .destroy()
                endif
                
                    return this
            endmethod
    endstruct
        
    
private function Conditions takes nothing returns boolean
    if GetIssuedOrderId() == OrderId(ORDERID) then
        call GroupAddUnit(GROUP,GetOrderedUnit())
    endif
    
    if GetIssuedOrderId() == OrderId(ORDERIDOFF) then
        call GroupRemoveUnit(GROUP,GetOrderedUnit())
    endif
    
// Spell Detection
    if GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_EFFECT and GetSpellAbilityId() == ID then
        return true
    endif
//Attack Detection
    if GetTriggerEventId() == EVENT_PLAYER_UNIT_ATTACKED and GetUnitAbilityLevel(GetAttacker(),ID) != 0 and IsUnitInGroup(GetAttacker(),GROUP) then
        return true
    endif

        return false
endfunction

private function DamageConditions takes nothing returns boolean
    return GetUnitAbilityLevel(GetEventDamageSource(),ID) != 0
endfunction
            
private function DamageActions takes nothing returns nothing
    local Data array Dat
    local unit Damaged    = GetTriggerUnit()
    local unit Damager    = GetEventDamageSource()
    local unit Picked
    local integer Count   = 0
    local integer CountEx = 0
    local integer Level   = GetUnitAbilityLevel(Damager,ID)
    local real Damage     = GetEventDamage()
    local real X          = GetUnitX(Damaged)
    local real Y          = GetUnitY(Damaged)
    local group Group     = CreateGroup()
                
        loop
            exitwhen Count >= COUNT
                set Count = Count + 1
                    if GetTriggeringTrigger() == TRIG[Count] then
                        call TriggerClearActions(TRIG[Count])
                        call TriggerClearConditions(TRIG[Count])
                        call DestroyTrigger(TRIG[Count])
                        
                        set TRIG[Count] = null
                        
                        call DestroyEffect(AddSpecialEffect(SFX,X,Y))
                        call UnitDamageTarget(Damager,Damaged,DamageAmount(Level),true,true,ATTACK_TYPE_HERO,DAMAGE_TYPE_NORMAL,null)
                        call GroupEnumUnitsInRange(Group,X,Y,AOE,null)
                        
                            loop
                                set Picked = FirstOfGroup(Group)
                                    exitwhen Picked == null
                                        if IsUnitEnemy(Picked,GetOwningPlayer(Damager)) == true and IsUnitType(Picked,UNIT_TYPE_DEAD) == false and IsUnitType(Picked,UNIT_TYPE_STRUCTURE) == false and IsUnit(Picked,Damaged) == false then
                                            set CountEx = CountEx + 1
                                            set Dat[CountEx] = Dat[CountEx].create(Damaged,Picked)
                                            call UnitDamageTarget(Damager,Picked,DamageAmount(Level) + Damage,true,true,ATTACK_TYPE_HERO,DAMAGE_TYPE_NORMAL,null)
                                        endif
                                    call GroupRemoveUnit(Group,Picked)
                            endloop
                    endif
        endloop

    set Picked = null
    set Damager = null
    set Damaged = null
    call DestroyGroup(Group)
    set Group = null
endfunction

private function Actions takes nothing returns nothing
    local unit Target
    local integer Count = 0
    
if GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_EFFECT then
    set Target = GetSpellTargetUnit()
endif

if GetTriggerEventId() == EVENT_PLAYER_UNIT_ATTACKED then
    set Target = GetTriggerUnit()
endif
    
    set COUNT = COUNT + 1
    
if TRIG[COUNT] == null then
    set TRIG[COUNT] = CreateTrigger()
    
    call TriggerRegisterUnitEvent(TRIG[COUNT],Target,EVENT_UNIT_DAMAGED)
    call TriggerAddCondition(TRIG[COUNT], Condition(function DamageConditions))
    call TriggerAddAction(TRIG[COUNT],function DamageActions)
endif
    
if COUNT >= LIMIT then
    loop
        exitwhen Count >= LIMIT
            set Count = Count + 1
                call TriggerClearActions(TRIG[Count])
                call TriggerClearConditions(TRIG[Count])
                call DestroyTrigger(TRIG[Count])
                set TRIG[Count] = null
    endloop

debug           call BJDebugMsg("You have reached the Limit. Resetting Trigger Count.")

    set COUNT = 0
    set COUNT = COUNT + 1
endif
    
    set Target = null
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger Trig = CreateTrigger(  )
    
    call Preload(FX)
    call Preload(SFX)
    
    call TriggerRegisterAnyUnitEventBJ( Trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerRegisterAnyUnitEventBJ( Trig, EVENT_PLAYER_UNIT_ATTACKED )
    call TriggerRegisterAnyUnitEventBJ( Trig, EVENT_PLAYER_UNIT_ISSUED_ORDER )
    call TriggerAddCondition( Trig, Condition( function Conditions ) )
    call TriggerAddAction( Trig, function Actions )
    set Trig = null
endfunction
endscope
Morbid Doctrine
Launches 5 Coils of death towards a target location in a fan-like arc. Any enemy unit a coil encounters, causes the Coil to burst apon impact, dealing damage to that unit. If a allied unit encounters a coil, it will be healed for 75% of the damage it would deal to an enemy unit.
Level 1: Deals 75 Damage
Level 2: Deals 150 Damage
Level 3: Deals 225 Damage
Level 4: Deals 300 Damage
Code:
JASS:
scope MorbidDoctrine initializer Init
    globals
        private constant integer ID    = 'A001' // Spell ID
        private constant integer DUMMY = 'u001' // Dummy Raw Code
        
        private constant integer BOLTS = 5      //Number of coils
        
        private constant real RADIUS   = 110.   //effective damage radius of coil
        private constant real ARC      = 90.    //effective arc, in which each coil will be launched (any number between 45 and 180 is possible for a nice arc)
        private constant real EDGES    = ARC / BOLTS //Edges of an Arc (don't change this)
        private constant real BAIL     = 45.    //range of the creation of the coils infront of the caster
        private constant real DISTANCE = 750.   // max. distance that the coils move
        private constant real SPEED    = 18.    //speed of the coils
        
        private constant string SFX    = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl" // impact effect
    endglobals

    private constant function Damage takes integer Level returns real
        return 75. * Level //Damage of each coil
    endfunction
    
    private constant function Heal takes real Amount returns real
        return Amount * 0.75 //heal percentage
    endfunction
    
    private function SetUnitXY takes unit u, real x, real y returns nothing
        if x<GetRectMaxX(bj_mapInitialPlayableArea) and x>GetRectMinX(bj_mapInitialPlayableArea) and y<GetRectMaxY(bj_mapInitialPlayableArea) and y>GetRectMinY(bj_mapInitialPlayableArea) then
            call SetUnitX(u,x)
            call SetUnitY(u,y)
        endif
    endfunction
    
    private struct Data
        unit Caster
        unit array Dummys[BOLTS]
        real array Angles[BOLTS]
        real array Dists [BOLTS]
        boolean array IsHit[BOLTS]
        group Group = CreateGroup()
        group Check = CreateGroup()

        static method Timer takes nothing returns boolean
            local Data this = TT_GetData()
                local real DX
                local real DY
                local real X
                local real Y
                local integer Count = 0
                local group Group = CreateGroup()
                local unit Picked
                    
                    loop
                        exitwhen Count >= BOLTS
                            set Count = Count + 1
                                if IsUnitType(.Dummys[Count],UNIT_TYPE_DEAD) == false then
                                    set DX = GetUnitX(.Dummys[Count])
                                    set DY = GetUnitY(.Dummys[Count])
                                    set X  = DX + SPEED * Cos(.Angles[Count] * bj_DEGTORAD)
                                    set Y  = DY + SPEED * Sin(.Angles[Count] * bj_DEGTORAD)
                                    call SetUnitXY(.Dummys[Count],X,Y)
                                    set .Dists[Count] = .Dists[Count] - SPEED
                                    
                                    if .Dists[Count] <= 0 then
                                        call DestroyEffect(AddSpecialEffect(SFX,X,Y))
                                        call KillUnit(.Dummys[Count])
                                        call GroupRemoveUnit(.Check,.Dummys[Count])
                                    endif
                                    
                                        call GroupEnumUnitsInRange(Group,X,Y,RADIUS,null)
                                            
                                            set Picked = FirstOfGroup(Group)
                                            
                                        if Picked != null then
                                            loop
                                                set Picked = FirstOfGroup(Group)
                                                    exitwhen Picked == null or .IsHit[Count] == true
                                                        if IsUnitType(Picked,UNIT_TYPE_DEAD) == false and IsUnitType(Picked,UNIT_TYPE_STRUCTURE) == false and IsUnitInGroup(Picked,.Group) == false and IsUnit(Picked,.Caster) == false then
                                                            if IsUnitEnemy(Picked,GetOwningPlayer(.Caster)) == true then
                                                                call UnitDamageTarget(.Caster,Picked,Damage(GetUnitAbilityLevel(.Caster,ID)),true,true,ATTACK_TYPE_HERO,DAMAGE_TYPE_NORMAL,null)
                                                                set .IsHit[Count] = true
                                                            endif
                                                            if IsUnitEnemy(Picked,GetOwningPlayer(.Caster)) == false then
                                                                call SetUnitState(Picked,UNIT_STATE_LIFE,GetUnitState(Picked,UNIT_STATE_LIFE) + Heal(Damage(GetUnitAbilityLevel(.Caster,ID))))
                                                                set .IsHit[Count] = true
                                                            endif
                                                        endif
                                                    call GroupAddUnit(.Group,Picked)
                                                    call GroupRemoveUnit(Group,Picked)
                                            endloop
                                            
                                            if .IsHit[Count] == true then
                                                call DestroyEffect(AddSpecialEffect(SFX,X,Y))
                                                call KillUnit(.Dummys[Count])
                                                call GroupRemoveUnit(.Check,.Dummys[Count])
                                            endif
                                        endif
                                endif
                    endloop
                    
                set Picked = FirstOfGroup(.Check)
                
                    if Picked == null then
                        call GroupClear(Group)
                        call DestroyGroup(Group)
                        set Group = null
                        set Picked = null
                        call .destroy()
                            return true
                    endif
                
                set Picked = null
                call GroupClear(Group)
                call DestroyGroup(Group)
                set Group = null
                    return false
        endmethod
                                                
        static method create takes unit C, unit T returns Data
            local Data this = Data.allocate()
            local unit Target = T
            local real CasterX
            local real CasterY
            local real X
            local real Y
            local real TargetX
            local real TargetY
            local real Angle
            local integer Count = 0
            
            set .Caster = C
            set CasterX = GetUnitX(.Caster)
            set CasterY = GetUnitY(.Caster)
            set TargetX = GetUnitX(Target)
            set TargetY = GetUnitY(Target)
            set Angle   = bj_RADTODEG * Atan2(TargetY - CasterY, TargetX - CasterX)
            set X       = CasterX + BAIL * Cos(Angle * bj_DEGTORAD)
            set Y       = CasterY + BAIL * Sin(Angle * bj_DEGTORAD)
            
                loop
                    exitwhen Count >= BOLTS
                        set Count = Count + 1
                            set .Angles[Count] = ( Angle - ARC / 2 ) + ( EDGES * Count )
                            set .Dummys[Count] = CreateUnit(GetOwningPlayer(.Caster),DUMMY,X,Y,.Angles[Count])
                            set .Dists [Count] = DISTANCE
                            set .IsHit [Count] = false
                            call GroupAddUnit(.Check,.Dummys[Count])
                endloop
            
            set Target = null
            
            return this
        endmethod
    endstruct
    
        private function Conditions takes nothing returns boolean
            return GetSpellAbilityId() == ID
        endfunction
        
        private function Actions takes nothing returns nothing
            local Data this = Data.create(GetTriggerUnit(),GetSpellTargetUnit())
            call TT_Start(function Data.Timer,this)
        endfunction
    
        private function Init takes nothing returns nothing
            local trigger Trig = CreateTrigger(  )
            
            call Preload(SFX)
            
            call TriggerRegisterAnyUnitEventBJ( Trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
            call TriggerAddCondition( Trig, Condition( function Conditions ) )
            call TriggerAddAction( Trig, function Actions )
            set Trig = null
        endfunction
endscope
MorbidDoctrineCcast.jpg

MorbidDoctrineEnd.jpg

I was a long time since i last submitted something to TheHelper.net, therefore I thought: "Hey, Summer Vacation is nearly over and I should at least do something non contra-productive to end this." So i came up with these two spells.
Both Spells are rather dry on the Eye candy, but nevertheless, they are fun IMO.
Implementation Instructions are listed in the trigger section.

I present you...
Lightning Missle
LightningMissle.jpg


It doesn't look very decent in the picture, but In-Game it looks very decent, just take a look.
Thanks to Tinki3 for the Spell Template Map.

Sorry for the Zip thing. My Computer won't let me attach files to Zip Folders due to some weird error.
Could someone do this for me?

Hope you like this Spellpack + Model.
Please comment and rate =)
 

Attachments

  • LightningMissle.mdx
    10.4 KB · Views: 214
  • Lightning Spirit.w3x
    69.9 KB · Views: 255

Renendaru

(Evol)ution is nothing without love.
Reaction score
309
After using Static Discharge next to the map bounds the unit was pushed outside. That shouldn't happen should it.
 

Renendaru

(Evol)ution is nothing without love.
Reaction score
309
It's not a triggering issue, but Morbid Doctrine should instead take a point location...
 

Hatebreeder

So many apples
Reaction score
381
Implemented the changes Rendaru suggested (concerning the SetUnitXY with boarder safty).
I'll add annother Version of Morbid Doctrine, just wait a minute.

UPDATED: Now with a Unit target and a Point target Version of Morbid Doctrine
 

Romek

Super Moderator
Reaction score
963
Screenshots of the spells? :)
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
Not bad, I was doubtful about having knockback on every attack but it looks cool and has a solid "feel", plus the missile looks great. :)

Morbid Doctrine seems like an enhanced version of a spell from my RSR demo map. ;) Not like I think you copied; it's a pretty straightforward idea for a spell...

A few problems:
Your attack detection can be glitched. This is, of course, since you're setting up a damage trigger on attack to wait for the shot to hit, but what if some other damage comes from the unit in the meanwhile (like a spell projectile already on the way?). Fire a Morbid Doctrine at an enemy and then immediately attack it with Static Discharge active, and the knockback trigger will activate when Morbid Doctrine deals damage.

Collision detection for Morbid Doctrine seems a little inconsistent, but it might just be because it's a very wide fan. Your enum area is large enough it doesn't really matter, but it'd be nice if you used IsUnitInRange in the collision detection, so a unit's collision size would be taken into account. A snippet that handles this can be found here.
 

black.sheep

Active Member
Reaction score
24
Yeah.
You could replace the static discharge main spell with a bluff giving one, so you trigger the discharge when the unit takes damage AND has the bluff. Then you simply remove the bluff.
 

Hatebreeder

So many apples
Reaction score
381
Yeah.
You could replace the static discharge main spell with a bluff giving one, so you trigger the discharge when the unit takes damage AND has the bluff. Then you simply remove the bluff.

I don't like using buffs.
I actually wanted to Implement Rising Dusk's Damage Detection System, but, i didn't want people having to end up implementing serveral systems, so i tried to create it on my own damage detection.
Well, it only triggers once, regardless of hitting and using spells at the same time.

I will change the damage detect system once i come up with an idea to detect attack damage without having to use buffs.

It's just too easy to use buff detection =P

Thanks for the review Weep.
About the collision: you can change the collision in the globals variables. I didn't implement a Destructable destroy snipplet, since i didn't feel that the missles destroy trees, rather they fly through them, like a kind of Ghost/Ectoplasm kinda thing... Can you follow me?

EDIT: Slightly updated Code, concerning Angles in Morbid Doctrine.
Reuploaded the Map.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      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