• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Fire Spiral 1.1.1 (vJass Version)

This spell was inspired by Blaxor's Fire Spiral.

03/24/2009 - Version 1.0.0
- initial release

04/19/2009 - Version 1.1.0
- moved effects to xe
- removed DelFX (as i updated DelFX with an incompatible Version)
- the spiral can now have an initial radius

08/07/2009 - Version 1.1.1
- Compatibility with 1.24


JASS:
//Credits:
//    - Blaxor for the inspiration
//    - cohadar for his PUI library
//    - Rising_Dusk for his GroupUtils library
//    - Vexorian for JassHelper and TimerUtils
//    - PipeDream for Grimoire and all his help with spirals
//    - PitzerMike for JassNewGenPack
//    - SFilip for TESH

// How to import:
//    - Copy the code into a trigger on your map, adjust the constants below (especially AID) and youre done.
//    - Note that you have to copy over the required libraries as well

library FireSpiral uses TimerUtils, GroupUtils, PUI, xefx
    
    globals
        private constant    integer                 AID                     = 'A000' // rawcode of the triggering abiltiy (press Ctrl+D to display the rawcode of objects, in the object editor)
        private constant    real                    FX_INTERVAL             = 0.15 // effects are spawned in this interval
        private constant    string                  FIRE_FX                 = "Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeEmbers.mdl" // this is the effect the spiral consits of
        private constant    real                    FIRE_FX_RADIUS          = 24. // collision size of the beforementioned effect
        private constant    real                    FIRE_FX_SCALE           = 1. // scale of beforementioned effect
        private             real            array   FIRE_DMG                // Units receive this much damage per second
        private constant    real                    FIRE_DMG_RADIUS         = 64 // this is the radius in which units around the effects get receive damage
        private constant    real                    FIRE_DMG_TICK           = 1./32 // this is the granulation of damage
        private constant    string                  FIRE_DMG_FX             = "Environment\\LargeBuildingFire\\LargeBuildingFire2.mdl" // this is the effect spawned on units receiving damage by the spiral
        private constant    string                  FIRE_DMG_FX_ATTPT       = "head" // this is the attachmentpoint where the beforementioned effect gets attached to
        private constant    real                    FIRE_DMG_FX_STAY        = 2. // the beforementioned effect stays on units this long after they receive no more damage
        private constant    attacktype              FIRE_DMG_ATTACKTYPE     = ATTACK_TYPE_MAGIC // attacktype of the damage units receive
        private constant    damagetype              FIRE_DMG_DAMAGETYPE     = DAMAGE_TYPE_MAGIC // damagetype of the damage units receive
        private             real            array   SPIRAL_INITIAL_RADIUS   // initial radius of the spiral
        private             real            array   SPIRAL_END_RADIUS       // radius of the spiral
        private             real            array   SPIRAL_CIRCLES          // how often does a spiral reach ((angle) modulo (2*PI))==0
        private             integer         array   SPIRAL_ENDINGS          // number of spirals spawned
        private             real            array   DURATION                // Duration of the spiral after all effects have been spawned
        
        private constant    integer                 MAX_FIRE_FX_PER_INSTANCE = 255
    endglobals
    
    private function SetUpFIRE_DMG takes nothing returns nothing
        set FIRE_DMG[1]=50.
        set FIRE_DMG[2]=75.
        set FIRE_DMG[3]=100.
    endfunction
    
    private function SetUpSPIRAL_INITIAL_RADIUS takes nothing returns nothing
        set SPIRAL_INITIAL_RADIUS[1]=200
        set SPIRAL_INITIAL_RADIUS[2]=200
        set SPIRAL_INITIAL_RADIUS[3]=200
    endfunction
    
    private function SetUpSPIRAL_END_RADIUS takes nothing returns nothing
        set SPIRAL_END_RADIUS[1]=400.
        set SPIRAL_END_RADIUS[2]=500.
        set SPIRAL_END_RADIUS[3]=600.
    endfunction
    
    private function SetUpSPIRAL_CIRCLES takes nothing returns nothing
        set SPIRAL_CIRCLES[1]=0.6
        set SPIRAL_CIRCLES[2]=0.8
        set SPIRAL_CIRCLES[3]=1.0
    endfunction
    
    private function SetUpSPIRAL_ENDINGS takes nothing returns nothing
        set SPIRAL_ENDINGS[1]=3
        set SPIRAL_ENDINGS[2]=3
        set SPIRAL_ENDINGS[3]=3
    endfunction
    
    private function SetUpDURATION takes nothing returns nothing
        set DURATION[1]=5.
        set DURATION[2]=7.
        set DURATION[3]=9.
    endfunction
    
    // proxy functions
    // if you want to use formulae, edit these
    
    private function Fire_Dmg takes integer level returns real
        return FIRE_DMG[level]
    endfunction
    
    private function Spiral_Initial_Radius takes integer level returns real
        return SPIRAL_INITIAL_RADIUS[level]
    endfunction
    
    private function Spiral_End_Radius takes integer level returns real
        return SPIRAL_END_RADIUS[level]
    endfunction
    
    private function Spiral_Circles takes integer level returns real
        return SPIRAL_CIRCLES[level]
    endfunction
    
    private function Spiral_Endings takes integer level returns integer
        return SPIRAL_ENDINGS[level]
    endfunction
    
    private function Duration takes integer level returns real
        return DURATION[level]
    endfunction
    
    // I wouldnt edit anything below this line, if i were you
    
    private struct Data
        unit c
        integer level
        integer i
        timer t
        real x
        real y
        real a
        real b
        real f
        real d
        integer fxcount
        xefx array FX[MAX_FIRE_FX_PER_INSTANCE]
        real array FXX[MAX_FIRE_FX_PER_INSTANCE]
        real array FXY[MAX_FIRE_FX_PER_INSTANCE]
        
        static Data array Structs
        static integer Count=0
        static timer T=CreateTimer()
        static Data tmps
        static boolexpr FireDmg
        
        static timer array ImmoT
        static effect array ImmoFX
        
        static method ImmoCallback takes nothing returns nothing
        local timer t=GetExpiredTimer()
        local integer i=GetTimerData(t)
            call DestroyEffect(Data.ImmoFX[i])
            set Data.ImmoFX[i]=null
            call ReleaseTimer(t)
        endmethod
        
        static method FireDmgFunc takes nothing returns boolean
        local unit u=GetFilterUnit()
        local integer i
        local timer t
            if IsUnitEnemy(u, GetOwningPlayer(Data.tmps.c)) and (not IsUnitInGroup(u, ENUM_GROUP)) and IsUnitType(u, UNIT_TYPE_DEAD)==false and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)==false and IsUnitType(u, UNIT_TYPE_STRUCTURE)==false then
                call UnitDamageTarget(Data.tmps.c, u, Fire_Dmg(Data.tmps.level)*FIRE_DMG_TICK, false, false, FIRE_DMG_ATTACKTYPE, FIRE_DMG_DAMAGETYPE, WEAPON_TYPE_WHOKNOWS)
                set i=GetUnitIndex(u)
                if Data.ImmoFX[i]==null then
                    set Data.ImmoFX[i]=AddSpecialEffectTarget(FIRE_DMG_FX, u, FIRE_DMG_FX_ATTPT)
                    set t=NewTimer()
                    call SetTimerData(t, i)
                    call TimerStart(t, FIRE_DMG_FX_STAY, false, function Data.ImmoCallback)
                    set Data.ImmoT[i]=t
                else
                    call TimerStart(Data.ImmoT[i], FIRE_DMG_FX_STAY, false, function Data.ImmoCallback)
                endif
                set u=null
                return true
            endif
            set u=null
            return false
        endmethod
        
        method onDestroy takes nothing returns nothing
            set .c=null
            call ReleaseTimer(.t)
            set Data.Count=Data.Count-1
            set Data.Structs[.i]=Data.Structs[Data.Count]
            set Data.Structs[.i].i=.i
            if Data.Count==0 then
                call PauseTimer(Data.T)
            endif
        endmethod
        
        static method EndingCB takes nothing returns nothing
        local Data s=GetTimerData(GetExpiredTimer())
        local integer i=0
            loop
                exitwhen i>=Spiral_Endings(s.level)
                set s.fxcount=s.fxcount-1
                call s.FX[s.fxcount].destroy()
                set i=i+1
            endloop
            if s.fxcount<=0 then
                call s.destroy()
            endif
        endmethod
        
        static method Ending takes nothing returns nothing
            call TimerStart(GetExpiredTimer(), FX_INTERVAL, true, function Data.EndingCB)
        endmethod
        
        static method SpawnCB takes nothing returns nothing
        local Data s=GetTimerData(GetExpiredTimer())
        local integer i=0
        local real d=2*bj_PI/Spiral_Endings(s.level)
        local real f=s.a+(bj_PI/2)
            loop
                exitwhen i>=Spiral_Endings(s.level)
                debug if s.fxcount>=MAX_FIRE_FX_PER_INSTANCE then
                debug     call BJDebugMsg("FireSpiral: Array overflow! Try increasing MAX_FIRE_FX_PER_INSTANCE!")
                debug     exitwhen true
                debug endif
                set s.FXX[s.fxcount]=s.x+(s.d*Cos(s.f+s.a+(i*d)))
                set s.FXY[s.fxcount]=s.y+(s.d*Sin(s.f+s.a+(i*d)))
                set s.FX[s.fxcount]=xefx.create(s.FXX[s.fxcount], s.FXY[s.fxcount], f)
                set s.FX[s.fxcount].fxpath=FIRE_FX
                set s.FX[s.fxcount].scale=FIRE_FX_SCALE
                set s.fxcount=s.fxcount+1
                set i=i+1
            endloop
            set s.a=2*Asin((2*FIRE_FX_RADIUS)/(2*s.d))+s.a
            set s.d=s.b*s.a
            if s.d>Spiral_End_Radius(s.level) then
                call TimerStart(s.t, Duration(s.level), false, function Data.Ending)
            endif
        endmethod
        
        static method Callback takes nothing returns nothing
        local Data s
        local integer i=0
        local integer j=0
            loop
                exitwhen i>=Data.Count
                set s=Data.Structs[i]
                loop
                    exitwhen j>=s.fxcount
                    set Data.tmps=s
                    call GroupEnumUnitsInRange(ENUM_GROUP, s.FXX[j], s.FXY[j], FIRE_DMG_RADIUS, Data.FireDmg)
                    set j=j+1
                endloop
                call GroupClear(ENUM_GROUP)
                set i=i+1
            endloop
        endmethod
        
        static method Cond takes nothing returns boolean
            return GetSpellAbilityId()==AID
        endmethod
        
        static method Create takes nothing returns nothing
        local Data s=Data.allocate()
        local real d
        local integer i=0
        local real f
            set s.c=GetTriggerUnit()
            set s.level=GetUnitAbilityLevel(s.c, AID)
            set s.t=NewTimer()
            set s.f=GetUnitFacing(s.c)*bj_DEGTORAD
            set s.x=GetUnitX(s.c)
            set s.y=GetUnitY(s.c)
            set s.b=(Spiral_End_Radius(s.level)-Spiral_Initial_Radius(s.level))/(2*bj_PI*Spiral_Circles(s.level))
            set s.d=Spiral_Initial_Radius(s.level)
            set s.a=s.d/s.b
            set d=2*bj_PI/Spiral_Endings(s.level)
            set f=s.a+(bj_PI/2)
            loop
                exitwhen i>=Spiral_Endings(s.level)
                set s.FXX[s.fxcount]=s.x+(s.d*Cos(s.f+s.a+(i*d)))
                set s.FXY[s.fxcount]=s.y+(s.d*Sin(s.f+s.a+(i*d)))
                set s.FX[s.fxcount]=xefx.create(s.FXX[s.fxcount], s.FXY[s.fxcount], f)
                set s.FX[s.fxcount].fxpath=FIRE_FX
                set s.FX[s.fxcount].scale=FIRE_FX_SCALE
                set s.fxcount=s.fxcount+1
                set i=i+1
            endloop
            if s.d==0 then
                set s.a=2*FIRE_FX_RADIUS/s.b
            else
                set s.a=2*Asin((2*FIRE_FX_RADIUS)/(2*s.d))+s.a
            endif
            set s.d=s.b*s.a
            call SetTimerData(s.t, s)
            call TimerStart(s.t, FX_INTERVAL, true, function Data.SpawnCB)
            set Data.Structs[Data.Count]=s
            set s.i=Data.Count
            if Data.Count==0 then
                call TimerStart(Data.T, FIRE_DMG_TICK, true, function Data.Callback)
            endif
            set Data.Count=Data.Count+1
        endmethod
        
        static method onInit takes nothing returns nothing
        local trigger t=CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddAction(t, function Data.Create)
            call TriggerAddCondition(t, Condition(function Data.Cond))
            
            set Data.FireDmg=Condition(function Data.FireDmgFunc)
            
            call SetUpFIRE_DMG()
            call SetUpSPIRAL_INITIAL_RADIUS()
            call SetUpSPIRAL_END_RADIUS()
            call SetUpSPIRAL_CIRCLES()
            call SetUpSPIRAL_ENDINGS()
            call SetUpDURATION()
        endmethod
    endstruct
    
endlibrary

Keywords:
Fire, Spiral, Archimedean, AOE
Contents

FireSpiral 1.1.1 (Map)

Reviews
18:25, 15th Oct 2009 The_Reborn_Devil: The triggering looks good, but the spell was kinda boring. Also, you need to fix the tooltip. It's Approved, but I won't give it a rating before you fix the tooltip and make a test map with some enemies...

Moderator

M

Moderator

18:25, 15th Oct 2009
The_Reborn_Devil:

The triggering looks good, but the spell was kinda boring.
Also, you need to fix the tooltip.
It's Approved, but I won't give it a rating before you fix the tooltip and make a test map with some enemies and stuff. Also, some more interesting effects would be nice too, which could potentially increase the rating.
 
Top