Template Projectile Template!

Vestras

Retired
Reaction score
248
I created this because many people asked how to make a projectile explode when it got into range of enemy units. Well, I created this to show how easy it is.

Uses CSSafety and ABC.
Requires NewGen and little-medium JASS experience.

Code:
JASS:
library PST

globals
// Below: Needed for the code, don't edit.
private unit GLOBALUNIT
private real Range
private attacktype Atype
private damagetype Dtype
private real dmg
private string sfx
endglobals

private struct Data
     timer t
     timer ti
     unit dummy
     unit caster
     real facing
     real createx
     real createy
     location currentloc
     player owner
     trigger dietrig
     
        private method onDestroy takes nothing returns nothing
        call ReleaseTimer(.t)
        call ReleaseTimer(.ti)
        call ClearTimerStructA(.t)
        call ClearTimerStructA(.ti)
        call RemoveLocation(.currentloc)
        set .currentloc = null
        set .dummy = null
        set .owner = null
        set .createy = 0.00
        set .createx = 0.00
        set .facing = 0.00
        set .t = null
        set .ti = null
        call DestroyTimer(.t)
        call DestroyTimer(.ti)
        endmethod
endstruct

private function Move takes nothing returns nothing
   local Data d = GetTimerStructA(GetExpiredTimer())
   local real x
   local real y
   
   set x = GetLocationX(d.currentloc) + 5.00 * Cos(d.facing * bj_DEGTORAD)
   set y = GetLocationY(d.currentloc) + 5.00 * Sin(d.facing * bj_DEGTORAD)
   
        call SetUnitPosition(d.dummy, x, y)
        set d.currentloc = GetUnitLoc(d.dummy)
        
        set x = 0.00
        set y = 0.00
endfunction

private function Group takes nothing returns nothing
local unit u = GetEnumUnit()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
   call DestroyEffect(AddSpecialEffect(sfx, x, y))
   call UnitDamageTarget(GLOBALUNIT, u, dmg, false, true, Atype, Dtype, WEAPON_TYPE_WHOKNOWS)
endfunction

private function InRangeConds takes nothing returns boolean
    return ( IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GLOBALUNIT)) == true ) and ( IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false ) and ( GetWidgetLife(GetFilterUnit())>.405 )
endfunction

private function InRange takes nothing returns boolean
    local Data d = GetTimerStructA(GetExpiredTimer())
    local real x = GetLocationX(d.currentloc)
    local real y = GetLocationY(d.currentloc)
    local group g = CreateGroup()
    
    call GroupEnumUnitsInRange(g, x, y, Range, Filter(function InRangeConds))
    call ForGroup(g, function Group)
    
      if CountUnitsInGroup(g) >= 1 then
        call ClearTriggerStructA(d.dietrig)
        call DestroyTrigger(d.dietrig)
        set d.dietrig = null
        call KillUnit(d.dummy)
        call d.destroy()
    endif
    return false
endfunction

private function GroupConds takes nothing returns boolean
   return ( IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GLOBALUNIT)) == true ) and ( IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false ) and ( GetWidgetLife(GetFilterUnit())<.405 )
endfunction

private function DummyDie takes nothing returns boolean
    local Data d = GetTriggerStructA(GetTriggeringTrigger())
    local real x = GetUnitX(d.dummy)
    local real y = GetUnitY(d.dummy)
    local unit u
    local group g = CreateGroup()
    call GroupEnumUnitsInRange(g, x, y, 256.0, Filter(function GroupConds))
    
        call DestroyEffect(AddSpecialEffect(sfx, x, y))
        call KillUnit(d.dummy)
        loop
            set u = FirstOfGroup(g)
            exitwhen CountUnitsInGroup(g) <= 0
               call UnitDamageTarget(d.caster, u, dmg, false, true, Atype, Dtype, WEAPON_TYPE_WHOKNOWS)
            call GroupRemoveUnit(g, u)
        endloop
        call d.destroy()
    
    call DestroyGroup(g)
    set g = null
    set u = null
    return false
endfunction

public function Create takes integer DummyID, string FX, real Damage, real r, real LivingTime, attacktype attype, damagetype datype returns nothing
     local Data d = Data.create()
     set d.caster = GetTriggerUnit()
     set d.owner = GetOwningPlayer(d.caster)
     set d.facing = GetUnitFacing(d.caster)
     set d.createx = GetUnitX(d.caster) + 35.00 * Cos(d.facing * bj_DEGTORAD)
     set d.createy = GetUnitY(d.caster) + 35.00 * Sin(d.facing * bj_DEGTORAD)
     set d.dummy = CreateUnit(d.owner, DummyID, d.createx, d.createy, d.facing)
     set d.currentloc = GetUnitLoc(d.dummy)
     set sfx = FX
     set GLOBALUNIT = d.caster
     set Range = r
     set Atype = attype
     set Dtype = datype
     set dmg = Damage
     
    call UnitApplyTimedLife(d.dummy, 'BTLF', LivingTime)
     
    set d.t = NewTimer()
    call SetTimerStructA(d.t, d)
    call TimerStart(d.t, 0.01, true, function Move)
    
    set d.ti = NewTimer()
    call SetTimerStructA(d.ti, d)
    call TimerStart(d.ti, 0.01, true, function InRange)
    
    set d.dietrig = CreateTrigger()
    call TriggerRegisterUnitEvent(d.dietrig, d.dummy, EVENT_UNIT_DEATH)
    call TriggerAddCondition(d.dietrig, Filter(function DummyDie))
    call SetTriggerStructA(d.dietrig, d)
endfunction

endlibrary


Screenshot:
Not needed, it's just a fireball being fired of.

Well, enjoy.
 

Flare

Stops copies me!
Reaction score
662
Does entering unit work for InRange?

Also, how does this help people with very little JASS experience? I doubt they can even read it, so how can they use it effectively? Wouldn't it be much simpler to allow you call the function with a given max distance, dummy unit, angle, damage, speed etc? Makes it easier for the end-user (even though it can result in a long function call :p)

You should make the Damage into a function that takes a unit argument (so people can deal stat-based damage, or scaling damage, for example)

Also, I don't see where .inrangetrig is destroyed :p
 

Vestras

Retired
Reaction score
248
Does entering unit work for InRange?

Also, how does this help people with very little JASS experience? I doubt they can even read it, so how can they use it effectively? Wouldn't it be much simpler to allow you call the function with a given max distance, dummy unit, angle etc? Makes it easier for the end-user (even though is can result in a long function call :p)

Also, I don't see where .inrangetrig is destroyed :p

Does a trigger need to be destroyed? I just nulled it.

Uhm.. Well, maybe I should change it to little-medium JASS experience. Hehe.

And yes, entering unit works for InRange.
 

Trollvottel

never aging title
Reaction score
262

Insane!

Shh I didn't edit this, go away.
Reaction score
122
When copying into your map, remember to delete the line in the function "InRangeConds"! There is text beside the line you should delete.


you may want to mention that its somewere in the middle of your code, else newbs may try and look up top were the object id's are placed.

Edit:
how would we set the damage in a range (say 1 - 100)? i belive adding that would make your trigger more usefull.
 

Larcenist

REP: Respect, Envy, Prosperity?
Reaction score
211
I can't see why anyone with limited JASS knowledge would know how to use this properly. A SetUnitXY function with arguments would be a lot easier to use for any GUI user.
 

PurgeandFire

zxcvmkgdfg
Reaction score
509
There are a few leaks, and it desyncs for Macs (I think... Well it should :p )..

I'll optimize it and fix the stuff for joo, hold on a sec.
 

Vestras

Retired
Reaction score
248
There are a few leaks, and it desyncs for Macs (I think... Well it should :p )..

I'll optimize it and fix the stuff for joo, hold on a sec.

No, please, I'll do it myself.


I am gonna make it so that you will only need to call a function. Like;

JASS:
call PST_Actions('h000', "(My fx string)")


Would that be better?

And trollvottel, I'm not blind :p

What does indent mean?
 

Flare

Stops copies me!
Reaction score
662
What does indent mean?

If you take a look at dictionary.com's meaning of indentation
the leaving of space or the amount of space left between a margin and the start of an indented line

Link (but that's just how I go about indenting code, I'm sure other users have different ways of doing it)

If you can't see the difference between the indentation and no indentation there... and incase you think your current code is indented, it is, but not very well at all.

And you are gonna need a much longer function call than that :p (I can see at least 6 or 7 arguments being required)
 

PurgeandFire

zxcvmkgdfg
Reaction score
509
Ok, fine I won't. :p

Anyway, I've heard that UnitDamagePoint desyncs for macs (I think, something along those lines) so you should instead use a group and loop through each unit, dealing damage. It is a simple technique. You can probably use FirstOfGroup() looping, it might be a bit of a hassle doing otherwise.
 

Vestras

Retired
Reaction score
248
Ok, fine I won't. :p

Anyway, I've heard that UnitDamagePoint desyncs for macs (I think, something along those lines) so you should instead use a group and loop through each unit, dealing damage. It is a simple technique. You can probably use FirstOfGroup() looping, it might be a bit of a hassle doing otherwise.

I will.

Why isn't it MUI? couldn't I just use PUI, then?
 
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