Spell Blaze v2

emjlr3

Change can be a good thing
Reaction score
395
Blaze v2

Explanations:
  • What it does - upon casting the ability, conjures X flaming orbs, which circle the caster, and upon reaching their ascent, careen forth at random targets in the area, exploding upon impact, dealing damage to the unlucky foe.
  • Why I made it - I made it for a tower contest, and actually managed to place, which was kind of neat.
  • Why you should try it - I think it is a pretty neat ability. Makes use of vJASS to move lots of projectiles around, and you may actually find it useful, if not to use in a map, possibly to learn from.
  • Concerns - there is a lot of stuff flying about all at once, so it could get laggy with 10 or less firing at the same time on low end computers. I believe I have updated the trigger to be completely self sufficient, however if I missed something, let me know. Also, do not mind all the other triggers in the map, this was the test map I used for the ability, and I think it is an easy way to demo the spell as it is, simply look in the Spells folder for the abilities trigger.

JASS:
scope Blaze

//******************************************************************************************
//*
//* Blaze v2
//* 
//*
//*  A neat ability which throws homing fireballs all around at random enemies and 
//*  deals damage upon collision with them.
//* 
//*  Requires:
//*    - A blaze dummy and blaze abilty in your map, similar to the ones found here
//*    - This code copied to a trigger in your map
//*
//****************************************************************************************** 

globals
    //Config Options:
    
      //General:
      private constant integer abil_id = 'A001' //blaze ability rawcode
      private constant real int = .025 //timer interval for effect movement
      private constant integer dummy_id = 'n001' //blaze dummy rawcode
      private constant integer max_missiles = 6 //max number of missiles + 1, ever created for an instance of the spell
      
      //Twirl Portion:
      private constant real start_dist = 150. //start distance of missiles before they twirl, away from the caster
      private constant real end_height = 280. //end height of missiles when they reach the top of the twirl
      private constant real twirl_time = 1. //length in seconds of the twirl portion of the ability
      private constant real twirl_speed = 5. //rate of change per timer interval for the angle change of the missiles during the twirl
      
      //Homing Portion:       
      private constant real speed = 15. //missile speed per timer interval while homing in on a target
      private constant boolean new_target = true //whether missiles can get a new target if their original dies while in route
      private constant real height_diff = 35. //difference between targets current fly height and the height you want the missile to lower/raise to
      private constant attacktype a_type = ATTACK_TYPE_MAGIC //attack type for damage done
      private constant damagetype d_type = DAMAGE_TYPE_FIRE //damage type for damage done
endglobals 
private function damage takes integer lvl returns real
      return lvl*25. //damage done per missile
endfunction
private function range takes integer lvl returns real
      return (lvl*50.)+750. //range for missiles to check for targets
endfunction
private function count takes integer lvl returns integer
      return 4+lvl //number of missiles created
endfunction

//******************************************************************************************
//DON"T TOUCH PAST THIS POINT, UNLESS YOU PAIN FOR DEATH!
globals    
    //needed globals:
    private unit U = null
    private group G = CreateGroup()     
    private timer Tball = CreateTimer() 
    private integer Total1 = 0 
    private integer Total2 = 0
    private Blaze_data1 array structArray1
    private Blaze_data2 array structArray2
    
    public trigger Trigger = CreateTrigger()
endglobals

//angle between units
private function ABU takes unit a, unit b returns real
    return bj_RADTODEG * Atan2(GetUnitY(b) - GetUnitY(a), GetUnitX(b) - GetUnitX(a))
endfunction
//distance between units
private function DBU takes unit a, unit b returns real
    return SquareRoot(Pow(GetUnitX(b) - GetUnitX(a), 2) + Pow(GetUnitY(b)-GetUnitY(a),2))
endfunction
//filter for missiles, this can be edited as desired for further configuration
private function Filt takes nothing returns boolean
    return GetWidgetLife(GetFilterUnit())>.405 and IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(U))==true
endfunction

//needed struct 2
struct Blaze_data2
    unit ball = null 
    unit targ = null   
    real height = end_height 
    integer lvl = 0
    
    //init struct
    method Start takes unit ball, integer lvl returns nothing
        //update missile        
        set .ball = ball         
        //grab first target
        set .targ = GroupPickRandomUnit(G)
        set .lvl = lvl
    endmethod
    //move missile towards target
    method Effects takes nothing returns nothing
        local real ang = ABU(.ball,.targ)
        
        call SetUnitX(.ball,GetUnitX(.ball) + speed * Cos(ang * bj_DEGTORAD))
        call SetUnitY(.ball,GetUnitY(.ball) + speed * Sin(ang * bj_DEGTORAD))
        call SetUnitFacing(.ball,ang)
        set .height = .height - 10. //this makes it look pretty fluent IMO
        if .height<GetUnitFlyHeight(.targ)+height_diff then
            set .height = GetUnitFlyHeight(.targ)+height_diff
        endif
        call SetUnitFlyHeight(.ball,.height,0.0)
    endmethod
    //update globals
    method Update takes integer i returns nothing
        set structArray2<i> = structArray2[Total2]
        set Total2 = Total2 - 1
    endmethod
    //end struct
    method onDestroy takes nothing returns nothing         
        //damage target, destroy missile   
        if .targ!=null then 
            call UnitDamageTarget(.ball,.targ,damage(.lvl),false,false,a_type,d_type,null)
        endif
        call KillUnit(.ball)
    endmethod
endstruct
//needed struct 1 
struct Blaze_data1
    integer runs = 0
    unit tower = null
    unit array ball[max_missiles]
    real array ang[max_missiles]
    real xtower
    real ytower
    integer total = 0
    real increment = 0.
    real change = 0.
    real Hchange = 0.
    integer total_runs = 0
    
    //initiate all needed struct data
    method Start takes unit tower returns nothing
        local integer i = 1
        local real x = GetUnitX(tower)
        local real x2 
        local real y = GetUnitY(tower)
        local real y2
        local player p = GetOwningPlayer(tower)
        
        set .total = count(GetUnitAbilityLevel(tower,abil_id))
        set .increment = 360/.total
        set .total_runs = R2I(twirl_time/int) 
        set .change = start_dist/.total_runs
        set .Hchange = end_height/.total_runs
        //loop from 1-total, create balls, store angles
        loop
            exitwhen i&gt;.total
            set .ang<i> = i*.increment
            
            set x2 = x + start_dist * Cos(.ang<i> * bj_DEGTORAD) 
            set y2 = y + start_dist * Sin(.ang<i> * bj_DEGTORAD)
        
            set .ball<i> = CreateUnit(p,dummy_id,x2,y2,0.)
        
            set i = i + 1
        endloop
        
        //store tower and target
        set .tower = tower
        set .xtower = x
        set .ytower = y
    endmethod
    //effects for each run, update angle, move ball, update fly height
    method Effects takes nothing returns nothing
        local integer i = 1
        local real height = .runs * .Hchange 
        local real distance = start_dist-(.runs*.change) //get closer as we twirl up, eventually meeting in the middle
        
        loop
            exitwhen i&gt;.total             
            
            set .ang<i> = .ang<i> + twirl_speed
            call SetUnitX(.ball<i>, .xtower + distance * Cos(.ang<i> * bj_DEGTORAD))
            call SetUnitY(.ball<i>, .ytower + distance * Sin(.ang<i> * bj_DEGTORAD))
            call SetUnitFlyHeight(.ball<i>,height,0.0)   
                   
            set i = i + 1
        endloop
    endmethod
    //update globals
    method Update takes integer i returns nothing
        set structArray1<i> = structArray1[Total1]
        set Total1 = Total1 - 1
    endmethod
    //when our struct is destroyed, loop through balls and possibly destroy
    method onDestroy takes nothing returns nothing
        local integer i = 1
        local Blaze_data2 dat 
        local integer lvl
        
        //tower is dead, end
        if GetWidgetLife(.tower)&lt;.405 then
            loop
                exitwhen i&gt;.total             
                call KillUnit(.ball<i>)          
                set i = i + 1
            endloop 
        else  
            //tower is not dead, add missiles to new struct, and begin the detonation phase 
            set lvl = GetUnitAbilityLevel(.tower,abil_id)
            call GroupClear(G)
            set U = .tower
            call GroupEnumUnitsInRange(G,.xtower,.ytower,range(lvl),Condition(function Filt))          
            loop
                exitwhen i&gt;.total
                set dat = Blaze_data2.create()
                call dat.Start(.ball<i>,lvl)
                set Total2 = Total2 + 1 
                set structArray2[Total2] = dat  
                set i = i + 1
            endloop
        endif          
    endmethod
endstruct 

//filter for attackers
private function Conditions takes nothing returns boolean
    return GetSpellAbilityId()==abil_id
endfunction 
//movement for missiles  
private function Movement takes nothing returns nothing
    local integer i = 1
    local Blaze_data1 dat1
    local Blaze_data2 dat2
    
    loop
        //loop through all current structs 1
        exitwhen i &gt; Total1
        set dat1 = structArray1<i>
       
        //update our runs total
        set dat1.runs = dat1.runs + 1
        //effects are over, remove struct and clean up
        if dat1.runs&gt;dat1.total_runs or GetWidgetLife(dat1.tower)&lt;.405 then               
            call dat1.destroy()            
            call dat1.Update(i)            
            set i = i - 1               
        else
            //runs are not over, continue with effects
            call dat1.Effects()
        endif
       
        set i = i + 1
    endloop
    
    set i = 1
    
    loop
        //loop through all current structs 2
        exitwhen i &gt; Total2
        set dat2 = structArray2<i>
       
        //target is nothing, or is dead
        if dat2.targ==null or GetWidgetLife(dat2.targ)&lt;.405 then
            //if the missile can get another target, try and do so
            if new_target then
                call GroupClear(G)
                set U = dat2.ball
                call GroupEnumUnitsInRange(G,GetUnitX(dat2.ball),GetUnitY(dat2.ball),range(dat2.lvl),Condition(function Filt))
                set dat2.targ = GroupPickRandomUnit(G)
                //no new target available
                if dat2.targ==null then
                    call dat2.destroy()
                    call dat2.Update(i)  
                endif
                //so it runs this missile again, though it is now what was the last missile
                set i = i + 1
            else
                call dat2.destroy()
                call dat2.Update(i)            
                set i = i - 1
            endif
        //unit is close enough to damage, remove struct and clean up
        elseif DBU(dat2.ball,dat2.targ)&lt;speed then //distance between missile and target is less then speed, therefore another movement would most likely carry us past the target               
            call dat2.destroy()             
            call dat2.Update(i)             
            set i = i - 1               
        else
            //runs are not over, continue with effects
            call dat2.Effects()
        endif
       
        set i = i + 1
    endloop
    
    //no more active structs, pause timer
    if Total1==0 and Total2==0 then
        call PauseTimer(Tball)
    endif      
endfunction
//init for missiles
private function Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local Blaze_data1 dat = Blaze_data1.create()
    
    //init struct data, add it to array, start timer if not already done so
    if Total1==0 and Total2==0 then
        call TimerStart(Tball,int,true,function Movement)
    endif 
    call dat.Start(u)
    set Total1 = Total1 + 1 
    set structArray1[Total1] = dat  
    
    set u = null
endfunction

//===========================================================================
public function InitTrig takes nothing returns nothing
    call TriggerRegisterAnyUnitEventBJ( Trigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( Trigger, Condition( function Conditions ) )
    call TriggerAddAction( Trigger, function Actions )
endfunction

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


Updates:
  • v2 -fixed some spelling/grammar errors in my documentation and explanations
    some functions renamed
    added a public global trigger named Blaze_Trigger which is now used at the abilities global trigger
    ported to an active instant cast ability
    updated the Blaze_data1 arrays to a size so it works properly
    changed setunitposition to setunitx/y
    reduced groupenum call from max missiles to 1 when grabbing targets for the missiles
    removed getunitx/y calls for each missile and during every twirl interval, now done only once
    added many configuration parameters
    removed all unneeded systems from map
  • v1 - Initial release

Thoughts? Suggestions? Concerns? Mal contempt?
 

Attachments

  • hreshers.jpg
    hreshers.jpg
    70.4 KB · Views: 831
  • emjlr3 - Blaze v2.w3x
    93.3 KB · Views: 480
R

Rawne87

Guest
Hi i have been browsing these forums for a while, and decided to register because i just can't get your ability to work in my map. I am kindof a newb on jass and such, so it could just be a stupid mistake somewhere.
When i copy the trigger/ability/dummy unit to my map and edit the abilty id and unit id i still get like 50 errors. Any help would be appreciated.
 

emjlr3

Change can be a good thing
Reaction score
395
yea i should have mentioned that in the documentation, my bad
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top