• 🏆 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!

[JASS] Triggered Spell Overlap

Status
Not open for further replies.
Level 16
Joined
Mar 3, 2006
Messages
1,564
JASS:
scope FireNova initializer Init
    private keyword NovaData
    private keyword MislData
 
    globals
        // Constants
        private constant integer ABILTY_ID = 'A000' // rawcode of the Dummy Spell
        private constant integer M_UNIT_ID = 'e000' // rawcode of the Missile Unit
        private constant integer N_UNIT_ID = 'e001' // rawcode of the Nova Unit
        private constant integer NOVA_SIZE = 36     // number of the Nova Units
        private constant real M_TIMER_INTERVAL = 0.03
        private constant real N_TIMER_INTERVAL = 0.015
        private constant real M_DIST = 32.00
        private constant real N_DIST = 16.00
        private constant real NOVA_RADIUS = 544.00  // radius of the Nova
        private constant real dA = 360/NOVA_SIZE
        private constant real AB_CONST_FACTOR = 50.00
        private constant real AB_LEVEL_FACTOR = 50.00
        private constant real AB_PREV_LVL_FACTOR = 1
        private constant attacktype ATKTYPE = ATTACK_TYPE_MAGIC
        private constant damagetype DMGTYPE = DAMAGE_TYPE_FIRE
        // Variables
        private timer mtm = CreateTimer()
        private timer ntm = CreateTimer()
        private MislData array temp_mdat
        private NovaData array temp_ndat
        private integer mindex = 0
        private integer nindex = 0
        private NovaData iFilter // Filter Data
        private boolexpr fFilter // Filter function
        private group TempGroup = CreateGroup()
    endglobals
    function NovaDamage takes integer al returns real
        local real prevDmg
        if al == 1 then
            set prevDmg = 0
        else
            set prevDmg = NovaDamage.evaluate(al -1)
        endif
        return AB_CONST_FACTOR + AB_LEVEL_FACTOR * al + AB_PREV_LVL_FACTOR * prevDmg
    endfunction
    private struct NovaData
        unit Caster
        unit array Nova[NOVA_SIZE]
        real expand
        real Cx
        real Cy
        player Owner
        group dGroup = CreateGroup() // Damaged Units Group
        real dmg
        static method NovaExpand takes nothing returns nothing
            local thistype dat
            local integer i = 0
            local integer j
            local real x
            local real y
            local real a
            local unit u
            loop // this loop cycles through all the casters which have cast the spell
                exitwhen i >= nindex
                set dat = temp_ndat[i]
                // Nova Expanding
                set j = 0
                set a = 0
                set dat.expand = dat.expand + N_DIST
                loop
                    exitwhen j >= NOVA_SIZE
                    set x = dat.Cx + dat.expand * Cos( a * bj_DEGTORAD )
                    set y = dat.Cy + dat.expand * Sin( a * bj_DEGTORAD )
                    call SetUnitX( dat.Nova[j] , x )
                    call SetUnitY( dat.Nova[j] , y )
                    set j = j + 1
                    set a = a + dA
                endloop
                // Damage Units that the nova has reached
                set iFilter = dat
                call GroupEnumUnitsInRange(TempGroup, dat.Cx, dat.Cy, dat.expand, fFilter)
                loop
                    set u = FirstOfGroup(TempGroup)
                    exitwhen u == null
                    call GroupAddUnit(dat.dGroup, u)
                    call UnitDamageTarget(dat.Caster, u, dat.dmg, false, false, ATKTYPE, DMGTYPE, null)
                    call GroupRemoveUnit(TempGroup, u)
                endloop
                if dat.expand >= NOVA_RADIUS then // check if the nova has reached its max AoE
                    set nindex = nindex - 1
                    set temp_ndat[i] = temp_ndat[nindex]
                    set i = i - 1
                    call dat.destroy()
                endif
                set i = i + 1
            endloop
            set u = null
        endmethod
        static method create takes unit caster , real damage , real posX, real posY returns NovaData
            local thistype dat = thistype.allocate()
            local integer i = 0
            local real A = 0.00
            set dat.Caster = caster
            set dat.Owner = GetOwningPlayer(dat.Caster)
            set dat.Cx = posX
            set dat.Cy = posY
            set dat.dmg = damage
            call DisplayTimedTextToPlayer(dat.Owner,0,0,10,"|cffff0000" + R2S(dat.dmg) + "|r")
            loop
                exitwhen i >= NOVA_SIZE
                set dat.Nova[i] = CreateUnit( dat.Owner , N_UNIT_ID , dat.Cx , dat.Cy , A )
                set A = A + dA
                set i = i + 1
            endloop
            if nindex == 0 then
                call TimerStart(ntm,N_TIMER_INTERVAL,true,function NovaData.NovaExpand)
            endif
            set temp_ndat[nindex] = dat
            set nindex = nindex + 1
            return dat
        endmethod
        static method FilterUnit takes nothing returns boolean
            return GetWidgetLife(GetFilterUnit()) >= .305 and IsUnitEnemy(GetFilterUnit(),iFilter.Owner) and not IsUnitType(GetFilterUnit(),UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitInGroup(GetFilterUnit(),iFilter.dGroup)
        endmethod
        method onDestroy takes nothing returns nothing
            local integer i = 0
            loop
                exitwhen i >= NOVA_SIZE
                call KillUnit(.Nova[i])
                set .Nova[i] = null
                set .expand = 0
                set i = i + 1
            endloop
            if nindex == 0 then
                call PauseTimer(ntm)
            endif
        endmethod
    endstruct
 
    private struct MislData
        unit Caster
        unit Missile
        location CastPoint
        real Distance
        real Damage
        real face
 
        static method MoveMissile takes nothing returns nothing
            local MislData dat
            local integer i = 0
            local real X = 0
            local real Y = 0
            loop
                exitwhen i >= mindex
                set dat = temp_mdat[i]
                set dat.Distance = dat.Distance - M_DIST
                set X = GetUnitX(dat.Missile)
                set Y = GetUnitY(dat.Missile)
                set X = X + M_DIST * Cos(dat.face)
                set Y = Y + M_DIST * Sin(dat.face)
                if DistanceBetweenPoints(GetUnitLoc(dat.Missile),dat.CastPoint) < M_DIST then
                //if dat.Distance < M_DIST * 0.75 then
                    set mindex = mindex - 1
                    set temp_mdat[i] = temp_mdat[mindex]
                    set i = i - 1
                    call NovaData.create(dat.Caster , dat.Damage , GetUnitX(dat.Missile) , GetUnitY(dat.Missile))
                    call dat.destroy()
                else
                    call SetUnitPosition(dat.Missile,X,Y)
                endif
                set i = i + 1
            endloop
        endmethod
        static method create takes unit u , location target returns MislData
            local MislData dat = MislData.allocate()
            local real x1
            local real y1
            local real x2
            local real y2
            local real dx
            local real dy
            set temp_mdat[mindex] = dat
            set dat.Caster = u
            set x1 = GetUnitX(dat.Caster)
            set y1 = GetUnitY(dat.Caster)
            set dat.CastPoint = target
            set x2 = GetLocationX(dat.CastPoint)
            set y2 = GetLocationY(dat.CastPoint)
            set dat.Distance = 0
            set dx = x2 - x1
            set dy = y2 - y1
            set dat.Distance = SquareRoot(dx * dx + dy * dy)
            //call DisplayTimedTextToPlayer(Player(0),0,0,10,"|cffff0000" + R2S(dat.Distance) + "|r")
            set dat.face = Atan2(y2 - y1, x2 - x1)
            set dat.Missile = CreateUnit(GetOwningPlayer(dat.Caster),M_UNIT_ID,x1,y1,dat.face)
            call SetUnitPosition(dat.Missile,x1,y1)
            set dat.Damage = NovaDamage(GetUnitAbilityLevel(u , ABILTY_ID))
            if mindex == 0 then
                call TimerStart(mtm,M_TIMER_INTERVAL,true,function MislData.MoveMissile)
            endif
            set mindex = mindex + 1
            return dat
        endmethod
 
        method onDestroy takes nothing returns nothing
            call KillUnit(.Missile)
            set .Missile = null
            set .face = 0
            call RemoveLocation(.CastPoint)
            if mindex == 0 then
                call PauseTimer(mtm)
            endif
        endmethod
    endstruct
        private function FBConditions takes nothing returns boolean
            return GetSpellAbilityId() == ABILTY_ID
        endfunction
 
        private function Actions takes nothing returns nothing
            call MislData.create(GetTriggerUnit(), GetSpellTargetLoc())
        endfunction
 
        private function Init takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t,Condition(function FBConditions))
            call TriggerAddAction(t,function Actions)
            set fFilter = Filter(function NovaData.FilterUnit)
        endfunction
endscope
JASS:
scope FireShield initializer Init
    private keyword Data
    globals
        private constant integer ABIL_ID = 'A002'
        private constant integer UNIT_ID = 'e002'
        private constant integer N = 3
        private constant real shift = 360.00 / N
        private constant real r = 128.00
        private constant real dA = 5
        private constant real INTERVAL = 0.03
        private timer tmr = CreateTimer()
        private integer index = 0
        private Data array temp_data
    endglobals
 
    private function Duration takes integer aldur returns real
        return aldur*6.
    endfunction
 
    private function Damage takes integer aldam returns real
        return aldam*10.
    endfunction
    private struct Data
        unit Caster
        unit array Charge[N]
        real A
        real temp_A
        real durtime
        timer dur = CreateTimer()
        static method rotate takes nothing returns nothing
            local Data d
            local integer i = 0
            local integer j
            local real X
            local real Y
            loop
                exitwhen i >= index
                set d = temp_data[i]
                if TimerGetRemaining(d.dur) > 0.00 then
                    set d.A = d.A + dA
                    if d.A >= 360 then
                        set d.A = d.A - 360
                    endif
                    set d.temp_A = d.A
                    set j = 0
                    loop
                        exitwhen j >= N
                        set X = GetUnitX(d.Caster) + r * Cos(d.temp_A * bj_DEGTORAD)
                        set Y = GetUnitY(d.Caster) + r * Sin(d.temp_A * bj_DEGTORAD)
                        call SetUnitPosition(d.Charge[j],X,Y)
                        call SetUnitFacing(d.Charge[j],d.temp_A + 90)
                        set d.temp_A = d.temp_A + shift
                        set j = j + 1
                    endloop
                else
                    set index = index - 1
                    set temp_data[i] = temp_data[index]
                    set i = i - 1
                    call d.destroy()
                endif
                set i = i + 1
            endloop
        endmethod
        static method create takes unit u returns Data
            local Data d = Data.allocate()
            local integer i = 0
            local real temp_A = 0
            local real X
            local real Y
            set d.Caster = u
            set d.durtime = Duration(GetUnitAbilityLevel(d.Caster,ABIL_ID))
            loop    
                exitwhen i >= N
                set X = GetUnitX(d.Caster) + r * Cos(temp_A * bj_DEGTORAD)
                set Y = GetUnitY(d.Caster) + r * Sin(temp_A * bj_DEGTORAD)
                set d.Charge[i] =CreateUnit(GetOwningPlayer(d.Caster),UNIT_ID,X,Y,temp_A + 90)
                set i = i + 1
                set temp_A = temp_A + shift
            endloop
            call TimerStart(d.dur,d.durtime,false,null)
            if index == 0 then
                call TimerStart(tmr,INTERVAL,true,function Data.rotate)
            endif
            set temp_data[index] = d
            set index = index + 1
            return d
        endmethod
 
        method onDestroy takes nothing returns nothing
            local integer i = 0
            if index == 0 then
                call PauseTimer(tmr)
            endif
            loop
                exitwhen i >= N
                call KillUnit(.Charge[i])
                set.Charge[i] = null
                set i = i + 1
            endloop
        endmethod
    endstruct
    private function FSConditions takes nothing returns boolean
        return GetSpellAbilityId() == ABIL_ID
    endfunction
    private function FSActions takes nothing returns nothing
        call Data.create(GetTriggerUnit())
    endfunction
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t,Condition(function FSConditions))
        call TriggerAddAction(t,function FSActions)
    endfunction
endscope

'A000' and 'A002' are both based on Channel Spell but with different raw code.

There is an overlap occurrs when I cast the "first spell"; it fires the second one but when I cast the "second spell" the first don't overlap. Why do they overlap ?

Thanks & Reward
Thanks in advance and +rep for any help
 
Status
Not open for further replies.
Top