Template Line Spell Template v4

emjlr3

Change can be a good thing
Reaction score
395
Line Spell Template v4

LST.jpg

Allows you to cast projectiles in a line, which cast abilities on enemies in their path.

This template is really made for GUIers. If you desire more options, such as neat geometric movements, a generic projectile system is more what you are looking for. This is simple, easy to use, and gets the job done efficiently, though is does offer some various advanced functionality.

You may ask, but why just casting spells? Where are the other options? If you think about it, basically anything you would want to do, baring advanced triggered effects, can be done simply using a base blizzard spell cast on an enemy. Stuns, slows, damage, etc. Whatever.

Read Me:
Line Spell Template v4

Importing:
*Copy the LineSpellTemplate trigger to your map.
*Save. If it saves, everything is ready to go, if not, try again.
*Copy the Line Spell Template Dummy to your map, and the model it uses, unless you already have a comparable type of unit
*Configure the options and enjoy!
*Optionally requires the GroupUtils library.

Usage:
All you need to do is call the function LST_Cast()
This can be done in JASS as normal, or in GUI through the "Custom Script" Action

function LST_Cast takes unit cast, string sfx, real range, real angle, real speed, real dist, integer abil, integer lvl, string order returns unit

cast is the caster of your ability
sfx is the effect you want used as your missiles model - remember to use \\ as opposed to just \ as in GUI
range is the range of the effect of the spell around the unit created, or, how close an enemy has to be to get hit
angle is the angle to launch the projectile, in radians
speed is the movement rate the projectile will move at per timer interval
dist is the total distance the projectile moves
abil is the ability to be cast on affected units
lvl is the level of the ability you want casted
string is the string order used to cast said ability
returns the missile unit created

for example:

call LST_Cast( GetTriggerUnit(),"Abilities\\Weapons\\LichMissile\\LichMissile.mdl",200,90.,15.,1000.,'A023',3,"innerfire")

This will, for the caster of the ability, create a missile with the lichs attack as its model, and move it at 15 speed, a total of 1000 distance. Enemies within 200 range will have your caster dummy cast the ability with rawcode 'A023', of level 3, with the string "innerfire", so that an innerfire ability will be cast on effected units.

Extra:
Using an ability rawcode of 0 as the argument abil will cast nothing. This is incase you just want a projectile, and nothing else.
Function returns the created unit, so the user can edit all aspects of it as they so choose.

See the System's comments for advanced JASS use, including interfaces and struct members.

System Code:
JASS:
library LST needs optional GroupUtils

    //=====Line Spell Template v4=====\\

    globals
        public constant  real    TIMEOUT    = .04 // Periodic timer interval, lower=looks better but less efficient, higher=looks worse but more efficient
        private constant integer CASTERID   = 'n000' // Rawcode of your map's dummy caster
        private constant integer MISSILEID  = 'n004' // Rawcode of your map's Line Spell Template Dummy, or comparable dummy unit
    endglobals
    private function Filt takes unit caster, unit target returns boolean
        return true // Custom targeting filter
    endfunction
    
    //=====DON'T TOUCH PAST THIS POINT!!!=====\\
    globals
        private timer T=CreateTimer()
        private integer I=0
        private linespell TEMPD
        private linespell array D
        private unit TARG=null
        private boolexpr B
        private group G=CreateGroup()
    endglobals

    private interface face
    // Every periodic interval
    method onPeriodic takes nothing returns nothing defaults nothing
        // When the line spell is over
        method onEnd takes nothing returns nothing defaults nothing
            // When a unit is collided with
            method onCollision takes unit target returns nothing defaults nothing
                endinterface
                struct linespell extends face
                    unit caster // Caster of the spell
                    unit dummy // Projectile dummy unit
                    group g=null // Units that have been struck
                    player p // Owner of the projectile
                    effect sfx // Effect created on dummy
                    integer abil=0 // Ability to be cast
                    integer lvl // Level of ability to be cast
                    integer ticks // Number of iterations until the spell is over
                    string order // Order for ability to be case
                    real cos // X vector component of movement
                    real sin // Y vector component of movement
                    real angle // Angle of movement in Radians
                    real range // Collision radius around projectile
    
                    method destroy takes nothing returns nothing
                        call .onEnd()
                        // Clean up
                        call DestroyEffect(.sfx)
                        call KillUnit(.dummy)
                        if .abil>0 then
                            static if LIBRARY_GroupUtils then
                            call ReleaseGroup(.g)
                        else
                            call DestroyGroup(.g)
                        endif
                        set .abil=0
                    endif
                endmethod
                private static method filter takes nothing returns boolean
                    local unit dum
                    local linespell this=TEMPD
                    set TARG=GetFilterUnit()
		
                    if Filt(.caster,TARG) and not IsUnitInGroup(TARG,.g) and IsUnitEnemy(TARG,.p) and UnitAlive(TARG) then // Target unit is valid
                        // Cast ability on target
                        set dum=CreateUnit(.p,CASTERID,GetUnitX(TARG),GetUnitY(TARG),0.)
                        call UnitApplyTimedLife(dum,'BTLF',1.)
                        call UnitAddAbility(dum,.abil)
                        call SetUnitAbilityLevel(dum,.abil,.lvl)
                        call IssueTargetOrder(dum,.order,TARG)
                        set dum=null
			
                        // Store unit to eliminate future targeting
                        call GroupAddUnit(.g,TARG)
            
                        call .onCollision(TARG)
                    endif
		
                    return false
                endmethod
                private static method movement takes nothing returns nothing
                    local integer i=1
                    local real x
                    local real y
                    local linespell this
		
                    loop
                        exitwhen i>I
			
                        set this=D<i>
                        if .ticks==0 then // Max distance reached
                            call .destroy()
                            set D<i>=D<i>
                            set I=I-1
                            set i=i-1
                        else // Update position of missile, deal targeting effects
                            set .ticks=.ticks-1
                            set x=GetUnitX(.dummy)+.cos
                            set y=GetUnitY(.dummy)+.sin
                            call SetUnitX(.dummy,x)
                            call SetUnitY(.dummy,y)
                            // Filter through available targets
                            set TEMPD=this
                            call GroupEnumUnitsInRange(G,x,y,.range,B)
				
                            call .onPeriodic()
                        endif
			
                        set i=i+1
                    endloop
		
                    if I==0 then // No more instances currently running
                        call PauseTimer(T)
                    endif
                endmethod
                static method create takes unit cast, string sfx, real range, real angle, real speed, real dist, integer abil, integer lvl, string order returns linespell
                    local linespell this=linespell.allocate()
		
                    set .angle=angle
                    set .caster=cast
                    set .p=GetOwningPlayer(cast)
                    set .cos=speed*Cos(angle)
                    set .sin=speed*Sin(angle)
                    set .dummy=CreateUnit(.p,MISSILEID,GetUnitX(cast)+.cos,GetUnitY(cast)+.sin,.angle*bj_RADTODEG)
                    set .sfx=AddSpecialEffectTarget(sfx,.dummy,&quot;origin&quot;)
                    // Store total timeouts needed for this instance
                    set .ticks=R2I(dist/(speed))
                    set .range=range
		
                    if abil&gt;0 then // User wants an ability cast
                        static if LIBRARY_GroupUtils then
                        set .g=NewGroup()
                    else
                        set .g=CreateGroup()
                    endif
                    set .abil=abil
                    set .lvl=lvl
                    set .order=order
                endif
		
                set I=I+1
                // First instance
                if I==1 then
                    call TimerStart(T,TIMEOUT,true,function linespell.movement)
                endif
                set D<i>=this
		
                return this
            endmethod
    
            //==INITIALIZATION==\\
            private static method onInit takes nothing returns nothing
                set B=Condition(function linespell.filter)
            endmethod
        endstruct

        //==USER FUNCTIONS==\\
        public function Cast takes unit cast, string sfx, real range, real angle, real speed, real dist, integer abil, integer lvl, string order returns unit
            local linespell d=linespell.create(cast,sfx,range,angle,speed,dist,abil,lvl,order)
            return d.dummy
        endfunction

    endlibrary</i></i></i></i>


Release Info.
Version 4:
  • Removed CSData requirement, added GroupUtils optional requirement, and requirement for the UnitAlive native
  • No longer uses dynamic triggers for collision detection
  • Now features interfaces for onEnd, onPeriodic and onCollision
  • Various optimizations
  • Replaced location with angle in base wrapper function
  • Changed the way effects were removed to improve visuals
  • Added a JASS use demonstration featuring interface implementation

Version 3:
  • Now uses CSData to store and retrieve data from dynamic triggers
  • No longer uses the bj_ variable
  • Now uses a dummy missile unit with Vexs model, requiring the syntax to be slightly changed, taking now the effect string wanted as opposed to the dummy unit, and returning the created unit
  • Read Me updated to reflect changes

Version 2:
  • Ported to vJASS
  • System now uses a different execution syntax, read the Read Me for more info.
  • Added a new test spell: Nova

Version 1:
  • Initial release
 

Attachments

  • LST.jpg
    LST.jpg
    249.3 KB · Views: 402
  • Line Spell Template v4 - emjlr3.w3x
    190.7 KB · Views: 385

SFilip

Gone but not forgotten
Reaction score
633
Woah. Excellent idea and even better realization.
Added to the index of course.
The only thing you might wanna do is make a version that takes code function instead of a spell. But then again the people that know how to use those probably wont need the template.
 

emjlr3

Change can be a good thing
Reaction score
395
Argh!!, Delicious.... :D
Nice spell template..

ty

Good job! + rep

You've got to love Vexorian's CS Cache.

yea...it works

Woah. Excellent idea and even better realization.
Added to the index of course.
The only thing you might wanna do is make a version that takes code function instead of a spell. But then again the people that know how to use those probably wont need the template.

say what now?

Nice terrain. It even got my name on it... :D

yes...that it does
 

SFilip

Gone but not forgotten
Reaction score
633
> say what now?
Code:
function Line_Spell_Template takes unit cast, integer dumid, real range, location targ, real speed, real dist, [b]code runfunc[/b] returns nothing
...
    call SetTableObject(strig,"ta",TriggerAddAction(trig,[b]runfunc[/b]))
...
endfunction
This would allow different effects than casting a spell. Dealing the caster's strength * 5 damage to the target for example.
 

Pyrogasm

There are some who would use any excuse to ban me.
Reaction score
134
Carrion swarm deals damage in a cone, not a line...

Shockwave is line-based.
 

emjlr3

Change can be a good thing
Reaction score
395
you get the idea, cone shmone, who cares
 

Hero

─║╣ero─
Reaction score
250
you get the idea, cone shmone, who cares

Well you never know who cares..lol

Carrion swarm deals damage in a cone, not a line...

Cones are easy to make anyways...you just need a loop and a projectile dummy or a spell and then set the angles and let the loop work :D
 

emjlr3

Change can be a good thing
Reaction score
395
another substantial update
 

emjlr3

Change can be a good thing
Reaction score
395
update on the way
 

emjlr3

Change can be a good thing
Reaction score
395
big update

this is improved considerably, and is now a viable option for JASSers too
 
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