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

Projectile System 2 v1.3

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.

Zeatherann Presents:

An Anthro-Vixen System


Projectile System 2


Reason for Making

To make the creation and use of projectile like spells/abilities/ect easy, and maybe fun. It used to require a lot of trouble to make a projectile system, usually a map contains a few, each for a different spell. While not ineffective, it certainly could be improved. This system improves that by making a easy to configure universal system.


Configurables
  • Angle of projectile
  • Explosion size.
  • Whether or not to die on first collision with a unit.
  • How many sub units, or projectiles to create on collision.
  • SFX created every collision.
  • Radius checked for collision.
  • Unit type to create on collision.
  • Custom interger value that is passed from a projectile to all Col and Trail units it creates.
  • Damage on collision.
  • Damage to deal to the explosion area.
  • How far a projecitile moves before dying.
  • Speed a projectile moves.
  • Percent (0-100) chance of a projectile to create a Trail Unit.
  • Number of Trail Units to make.
  • SFX to create each step.
  • Unit type to create for a Trail Unit.
  • Rotation in degrees to add to the angle.
  • Random ammount (+-) to add to the angle.
Tehnical Side
  • Ability to keep last projectile values for easier spell making.
  • Uses two variables to count, avoiding BJs.
  • Uses a hashtable to store data, being MUI.
  • Projectiles added to a single unitgroup.
  • A global real value to change the 'rate of time' for all projectiles. Useful for ie; slowing time.
  • Global item id for pathing testing.
  • A terrain type that kills any projectiles on it. (set to an unused terrain type to not use)
Installing
  1. Open this map, open your map.
  2. Copy the trigger folder 'Projectile System' into your map, making sure 'create unknown variables' is checked.
  3. copy the map's global functions in header into your maps. These make life easier, and is used in the system aswell.
  4. Copy the test item, and fix the id of the global udg_PSG_TestItem.
  5. copy the blank projectile unit to base your projectiles off of as that unit's art and stuff is set to use the system.
  6. Done! Enjoy.
JASS:
/////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////PROJECTILE SYSTEM 2////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
constant function PS_Accel takes nothing returns integer
    return 0
endfunction
constant function PS_Angle takes nothing returns integer
    return 1
endfunction
constant function PS_Attach takes nothing returns integer
    return 2
endfunction
constant function PS_ColColSize takes nothing returns integer
    return 3
endfunction
constant function PS_ColDeath takes nothing returns integer
    return 4
endfunction
constant function PS_ColNum takes nothing returns integer
    return 5
endfunction
constant function PS_ColSFX takes nothing returns integer
    return 6
endfunction
constant function PS_ColSize takes nothing returns integer
    return 7
endfunction
constant function PS_ColUnit takes nothing returns integer
    return 8
endfunction
constant function PS_Custom takes nothing returns integer
    return 9
endfunction
constant function PS_Dmg takes nothing returns integer
    return 10
endfunction
constant function PS_DmgAoE takes nothing returns integer
    return 11
endfunction
constant function PS_Filter takes nothing returns integer
    return 12
endfunction
constant function PS_Height takes nothing returns integer
    return 13
endfunction
constant function PS_HeightE takes nothing returns integer
    return 14
endfunction
constant function PS_HeightS takes nothing returns integer
    return 15
endfunction
constant function PS_Life takes nothing returns integer
    return 16
endfunction
constant function PS_MaxLife takes nothing returns integer
    return 17
endfunction
constant function PS_Rate takes nothing returns integer
    return 18
endfunction
constant function PS_Speed takes nothing returns integer
    return 19
endfunction
constant function PS_TrailChance takes nothing returns integer
    return 20
endfunction
constant function PS_TrailNum takes nothing returns integer
    return 21
endfunction
constant function PS_TrailSFX takes nothing returns integer
    return 22
endfunction
constant function PS_TrailUnit takes nothing returns integer
    return 23
endfunction
constant function PS_Turn takes nothing returns integer
    return 24
endfunction
constant function PS_TypeAttack takes nothing returns integer
    return 25
endfunction
constant function PS_TypeDamage takes nothing returns integer
    return 26
endfunction
constant function PS_Wiggle takes nothing returns integer
    return 27
endfunction
function PS_Reset takes nothing returns nothing
    set udg_PS_Accel=0
    set udg_PS_Angle=0
    set udg_PS_Attach="origin"
    set udg_PS_ColColSize=0
    set udg_PS_ColDeath=true
    set udg_PS_ColNum=0
    set udg_PS_ColSFX=""
    set udg_PS_ColSize=0
    set udg_PS_ColUnit=-1
    set udg_PS_CurProjectile=null
    set udg_PS_Custom=0
    set udg_PS_Dmg=0
    set udg_PS_DmgAoE=0
    set udg_PS_Filter=1
    set udg_PS_Height=0
    set udg_PS_HeightE=0
    set udg_PS_HeightS=0
    set udg_PS_Keep=false
    set udg_PS_Life=0
    set udg_PS_MaxLife=0
    set udg_PS_Player=Player(0)
    set udg_PS_Projectile=-1
    set udg_PS_Rate=1
    set udg_PS_Speed=0
    set udg_PS_TrailChance=0
    set udg_PS_TrailNum=0
    set udg_PS_TrailSFX=""
    set udg_PS_TrailUnit=-1
    set udg_PS_Turn=0
    set udg_PS_TypeAttack=0
    set udg_PS_TypeDamage=4
    set udg_PS_Wiggle=0
    set udg_PS_X=0
    set udg_PS_Y=0
endfunction
function PS_New takes nothing returns nothing
    local unit u=CreateUnit(udg_PS_Player,udg_PS_Projectile,udg_PS_X,udg_PS_Y,udg_PS_Angle)
    local integer id=GetHandleId(u)
    call GroupAddUnit(udg_PSG_Projectiles,u)
    call SaveReal(   udg_PSG_Hash,id,PS_Accel(),      udg_PS_Accel)
    call SaveReal(   udg_PSG_Hash,id,PS_Angle(),      udg_PS_Angle)
    call SaveReal(   udg_PSG_Hash,id,PS_Wiggle(),     udg_PS_Wiggle)
    call SaveReal(   udg_PSG_Hash,id,PS_Turn(),       udg_PS_Turn)
    call SaveReal(   udg_PSG_Hash,id,PS_Speed(),      udg_PS_Speed)
    call SaveReal(   udg_PSG_Hash,id,PS_ColSize(),    udg_PS_ColSize)
    call SaveReal(   udg_PSG_Hash,id,PS_ColColSize(), udg_PS_ColColSize)
    call SaveReal(   udg_PSG_Hash,id,PS_Dmg(),        udg_PS_Dmg)
    call SaveReal(   udg_PSG_Hash,id,PS_DmgAoE(),     udg_PS_DmgAoE)
    call SaveReal(   udg_PSG_Hash,id,PS_Rate(),       udg_PS_Rate)
    call SaveInteger(udg_PSG_Hash,id,PS_TrailUnit(),  udg_PS_TrailUnit)
    call SaveInteger(udg_PSG_Hash,id,PS_ColUnit(),    udg_PS_ColUnit)
    call SaveInteger(udg_PSG_Hash,id,PS_TrailChance(),udg_PS_TrailChance)
    call SaveInteger(udg_PSG_Hash,id,PS_TrailNum(),   udg_PS_TrailNum)
    call SaveInteger(udg_PSG_Hash,id,PS_Height(),     udg_PS_Height)
    call SaveInteger(udg_PSG_Hash,id,PS_HeightE(),    udg_PS_HeightE)
    call SaveInteger(udg_PSG_Hash,id,PS_HeightS(),    udg_PS_HeightS)
    call SaveInteger(udg_PSG_Hash,id,PS_Life(),       udg_PS_Life)
    call SaveInteger(udg_PSG_Hash,id,PS_MaxLife(),    udg_PS_MaxLife)
    call SaveInteger(udg_PSG_Hash,id,PS_ColNum(),     udg_PS_ColNum)
    call SaveInteger(udg_PSG_Hash,id,PS_Custom(),     udg_PS_Custom)
    call SaveInteger(udg_PSG_Hash,id,PS_Filter(),     udg_PS_Filter)
    call SaveInteger(udg_PSG_Hash,id,PS_TypeAttack(), udg_PS_TypeAttack)
    call SaveInteger(udg_PSG_Hash,id,PS_TypeDamage(), udg_PS_TypeDamage)
    call SaveBoolean(udg_PSG_Hash,id,PS_ColDeath(),   udg_PS_ColDeath)
    call SaveStr(    udg_PSG_Hash,id,PS_TrailSFX(),   udg_PS_TrailSFX)
    call SaveStr(    udg_PSG_Hash,id,PS_ColSFX(),     udg_PS_ColSFX)
    call EnableTrigger(gg_trg_PS)
    if udg_PS_Keep==false then
        call PS_Reset()
    else
        set udg_PS_Keep=false
    endif
    set u=null
endfunction
function IsPathableEnum takes nothing returns boolean
    local unit u=GetFilterUnit()
    local boolean b=not(IsUnitType(u,UNIT_TYPE_STRUCTURE))or not(IsUnitInGroup(u,udg_PSG_Projectiles))
    set u=null
    if b then
        set udg_PSG_Count2=udg_PSG_Count2+1
    endif
    return b
endfunction
function IsPathable takes real x,real y,integer id returns boolean
    local item I=CreateItem(id,x,y)
    local boolean B=false
    local group g=CreateGroup()
    local integer i
    local boolexpr filter=Condition(function IsPathableEnum)
    set udg_PSG_Count2=0
    call GroupEnumUnitsInRange(g,x,y,24,filter)
    call DestroyBoolExpr(filter)
    set filter=null
    set i=udg_PSG_Count2
    if (((GetItemX(I)-x)*(GetItemX(I)-x)+(GetItemY(I)-y)*(GetItemY(I)-y))>=1024)and i==0then
        set B=true
    endif
    call DestroyGroup(g)
    set g=null
    call RemoveItem(I)
    set I=null
    return B
endfunction
function Trig_PS_TargetFilter takes nothing returns boolean
    local unit u=GetFilterUnit()
    local boolean b=GetWidgetLife(u)>0.405and IsUnitEnemy(u,GetOwningPlayer(udg_PS_CurProjectile)) and IsUnitInGroup(u,udg_PSG_Projectiles)==false and IsUnitType(u,UNIT_TYPE_DEAD)==false
    set u=null
    if b then
        set udg_PSG_Count2=udg_PSG_Count2+1
    endif
    return b
endfunction
function Trig_PS_Target takes nothing returns nothing
    call UnitDamageTarget(udg_PS_CurProjectile,GetEnumUnit(),udg_PS_Dmg,true,false,ConvertAttackType(udg_PS_TypeAttack),ConvertDamageType(udg_PS_TypeDamage),null)
endfunction
function Trig_PS_Target2 takes nothing returns nothing
    call UnitDamageTarget(udg_PS_CurProjectile,GetEnumUnit(),udg_PS_DmgAoE,true,false,ConvertAttackType(udg_PS_TypeAttack),ConvertDamageType(udg_PS_TypeDamage),null)
endfunction
function GetHeight takes real y0, real y1, real h, real d, real x returns real
    local real A = (2*(y0+y1)-4*h)/(d*d)
    local real B = (y1-y0-A*d*d)/d
    return A*x*x + B*x + y0
endfunction
function Trig_PS_Loop takes nothing returns nothing
    local unit u=GetEnumUnit()
    local integer id=GetHandleId(u)
    local real array xy
    local boolean Boom=false
    local boolean Die=false
    local boolean grounded=true
    local real height=0
    local group g=CreateGroup()
    local integer i
    local integer I
    local player p=GetOwningPlayer(u)
    local real an
    local unit U
    local boolexpr filter=Condition(function Trig_PS_TargetFilter)
    //Reals
    set udg_PS_Rate=LoadReal(udg_PSG_Hash,id,PS_Rate())
    set udg_PS_Accel=LoadReal(udg_PSG_Hash,id,PS_Accel())
    set udg_PS_Wiggle=LoadReal(udg_PSG_Hash,id,PS_Wiggle())*udg_PS_Rate
    set udg_PS_Turn=LoadReal(udg_PSG_Hash,id,PS_Turn())*udg_PS_Rate
    set udg_PS_Angle=LoadReal(udg_PSG_Hash,id,PS_Angle())+udg_PS_Turn+GetRandomReal(-udg_PS_Wiggle,udg_PS_Wiggle)
    set udg_PS_Speed=LoadReal(udg_PSG_Hash,id,PS_Speed())*udg_PS_Rate+udg_PS_Accel*udg_PS_Rate
    set udg_PS_ColSize=LoadReal(udg_PSG_Hash,id,PS_ColSize())
    set udg_PS_ColColSize=LoadReal(udg_PSG_Hash,id,PS_ColColSize())
    set udg_PS_Dmg=LoadReal(udg_PSG_Hash,id,PS_Dmg())
    set udg_PS_DmgAoE=LoadReal(udg_PSG_Hash,id,PS_DmgAoE())
    //Integers
    //Ids
    set udg_PS_TrailUnit=LoadInteger(udg_PSG_Hash,id,PS_TrailUnit())
    set udg_PS_ColUnit=LoadInteger(udg_PSG_Hash,id,PS_ColUnit())
    //Ints
    set udg_PS_Height=LoadInteger(udg_PSG_Hash,id,PS_Height())
    set udg_PS_TrailChance=LoadInteger(udg_PSG_Hash,id,PS_TrailChance())
    set udg_PS_TrailNum=LoadInteger(udg_PSG_Hash,id,PS_TrailNum())
    set udg_PS_Life=LoadInteger(udg_PSG_Hash,id,PS_Life())-R2I(RAbsBJ(udg_PS_Speed))
    call DisplayTextToPlayer(Player(0),0,0,R2S(udg_PS_Life))
    set udg_PS_MaxLife=LoadInteger(udg_PSG_Hash,id,PS_MaxLife())
    set udg_PS_ColNum=LoadInteger(udg_PSG_Hash,id,PS_ColNum())
    set udg_PS_Custom=LoadInteger(udg_PSG_Hash,id,PS_Custom())
    set udg_PS_Filter=LoadInteger(udg_PSG_Hash,id,PS_Filter())
    set udg_PS_TypeAttack=LoadInteger(udg_PSG_Hash,id,PS_TypeAttack())
    set udg_PS_TypeDamage=LoadInteger(udg_PSG_Hash,id,PS_TypeDamage())
    set udg_PS_HeightS=LoadInteger(udg_PSG_Hash,id,PS_HeightS())
    set udg_PS_HeightE=LoadInteger(udg_PSG_Hash,id,PS_HeightE())
    //Booleans
    set udg_PS_ColDeath=LoadBoolean(udg_PSG_Hash,id,PS_ColDeath())
    //Strings
    set udg_PS_TrailSFX=LoadStr(udg_PSG_Hash,id,PS_TrailSFX())
    set udg_PS_ColSFX=LoadStr(udg_PSG_Hash,id,PS_ColSFX())
    set udg_PS_Attach=LoadStr(udg_PSG_Hash,id,PS_Attach())
    //System
    if udg_PS_Filter==0 then
        set udg_PS_Filter=1
    endif
    set udg_PS_CurProjectile=u
    set xy[0]=GetUnitX(udg_PS_CurProjectile)+udg_PS_Speed*Cos(udg_PS_Angle*.01745)
    set xy[1]=GetUnitY(udg_PS_CurProjectile)+udg_PS_Speed*Sin(udg_PS_Angle*.01745)
    call SetUnitX(udg_PS_CurProjectile,xy[0])
    call SetUnitY(udg_PS_CurProjectile,xy[1])
    call SetUnitFacing(udg_PS_CurProjectile,udg_PS_Angle)
    /////////////////////////
    //Parabolic Height, if needed
    /////////////////////////
    if udg_PS_Height>0then
        set height=GetHeight(udg_PS_HeightS,udg_PS_HeightE,udg_PS_Height,udg_PS_MaxLife,udg_PS_MaxLife-udg_PS_Life)
        call SetUnitFlyHeight(udg_PS_CurProjectile,height,1000000)
        if height>50then
            set grounded=false
        endif
    endif
    /////////////////////////
    set udg_PSG_Count2=0
    call GroupEnumUnitsInRange(g,xy[0],xy[1],udg_PS_ColSize,filter)
    if udg_PSG_Count2>0and grounded then
        set Boom=true
        call ForGroup(g,function Trig_PS_Target)
        if udg_PS_ColDeath then
            set udg_PS_Life=0
        endif
    endif
    call DestroyGroup(g)
    call GroupClear(g)
    set g=null
    /////////////////////////
    //Trail SFX and units
    /////////////////////////
    call DestroyEffect(AddSpecialEffectTarget(udg_PS_TrailSFX,udg_PS_CurProjectile,udg_PS_Attach))
    if udg_PS_TrailChance>0and udg_PS_TrailUnit!=0and udg_PS_TrailNum>0then
        if GetRandomInt(1,100)<=udg_PS_TrailChance then
            set i=0
            set I=GetRandomInt(0,360)
            loop
                exitwhen i==udg_PS_TrailNum
                set i=i+1
                if udg_PS_TrailNum==1then
                    set an=GetRandomReal(0,360)
                else
                    set an=360/udg_PS_TrailNum*i+I
                endif
                set U=CreateUnit(p,udg_PS_TrailUnit,xy[0],xy[1],an)
                call SaveInteger(udg_PSG_Hash,GetHandleId(U),PS_Custom(),udg_PS_Custom)
                set U=null
            endloop
        endif
    endif
    /////////////////////////
    //Save the values we change
    /////////////////////////
    call SaveReal(udg_PSG_Hash,id,PS_Angle(),udg_PS_Angle)
    call SaveInteger(udg_PSG_Hash,id,PS_Life(),udg_PS_Life)
    call SaveReal(udg_PSG_Hash,id,PS_Speed(),udg_PS_Speed)
    /////////////////////////
    //If out of life or on Death Terrain->die
    /////////////////////////
    if IsTerrainPathable(xy[0],xy[1],PATHING_TYPE_WALKABILITY) or IsTerrainPathable(xy[0],xy[1],ConvertPathingType(udg_PS_Filter))or IsPathable(xy[0],xy[1],udg_PSG_TestItem) then
        if grounded then
            set Die=true
            set Boom=true
        endif
    endif
    if GetTerrainType(xy[0],xy[1])==udg_PSG_Terrain or udg_PS_Life<=0then
        set Die=true
        set Boom=true
    endif
    /////////////////////////
    //If collide with unit or die->boom
    /////////////////////////
    if Boom then
        set g=CreateGroup()
        call GroupEnumUnitsInRange(g,xy[0],xy[1],udg_PS_ColColSize,filter)
        call ForGroup(g,function Trig_PS_Target2)
        call DestroyGroup(g)
        set g=null
        call DestroyEffect(AddSpecialEffectTarget(udg_PS_ColSFX,udg_PS_CurProjectile,udg_PS_Attach))
        if udg_PS_ColUnit!=0and udg_PS_ColNum>0then
            set i=0
            set I=GetRandomInt(0,360)
            loop
                exitwhen i==udg_PS_ColNum
                set i=i+1
                if udg_PS_ColNum==1then
                    set an=GetRandomReal(0,360)
                else
                    set an=360/udg_PS_ColNum*i
                endif
                set U=CreateUnit(p,udg_PS_ColUnit,xy[0],xy[1],an)
                call SaveInteger(udg_PSG_Hash,GetHandleId(U),PS_Custom(),udg_PS_Custom)
                set U=null
            endloop
        endif
    endif
    if Die then
        call KillUnit(udg_PS_CurProjectile)
        call GroupRemoveUnit(udg_PSG_Projectiles,udg_PS_CurProjectile)
        call FlushChildHashtable(udg_PSG_Hash,id)
    endif
    //clear locals
    call DestroyBoolExpr(filter)
    set filter=null
    set p=null
    set u=null
    //reset globals
    call PS_Reset()
    set udg_PSG_Count=udg_PSG_Count+1
endfunction
function Trig_PS_Actions takes nothing returns nothing
    set udg_PSG_Count=0
    call ForGroup(udg_PSG_Projectiles,function Trig_PS_Loop)
    if udg_PSG_Count<1then
        call DisableTrigger(gg_trg_PS)
    endif
endfunction
function InitTrig_PS takes nothing returns nothing
    set gg_trg_PS=CreateTrigger()
    call DisableTrigger(gg_trg_PS)
    call TriggerRegisterTimerEvent(gg_trg_PS,0.04,true)
    call TriggerAddAction(gg_trg_PS,function Trig_PS_Actions)
endfunction


1.0
  • Spell Uploaded!
1.1
  • Changed the hash table to make it faster running.
1.2
  • Fixed coding errors and optimized code.
  • added support for parabolic movement. If a projectile is over 50 in the air it will not collide with units or terrain. Death-terrain kills it still.
1.3
  • Added more globals to simplify custom func call.
  • Added support for advanced parabolic movement.
  • Added Acceleration.
  • Made udg_PSG_Rate into a 'local' real to change the time-rate of each projectile individually.


Note: Documentation is included in the trigger PS INFO, This documentation isn't updated for v1.3!

Spell is made in JASS.

Keywords:
projectile, system, missile, rocket
Contents

Projectile System 2 (Map)

Reviews
12th Dec 2015 IcemanBo: Too long as NeedsFix. Rejected. 29 Aug 2011 Bribe: Elapsed game time is 0.00 seconds should be Map Initialization. gg_trg_PS should be a timer not a trigger. localVariablesAreWrittenLikeThis not like This or like...

Moderator

M

Moderator

12th Dec 2015
IcemanBo: Too long as NeedsFix. Rejected.

29 Aug 2011
Bribe: Elapsed game time is 0.00 seconds should be Map Initialization.

gg_trg_PS should be a timer not a trigger.

localVariablesAreWrittenLikeThis not like This or like THIS, in JASS convention.

local group g=CreateGroup() should not be created each time the loop is run, you should be using one static group that never gets destroyed.

JASS:
    local real A = (2*(y0+y1)-4*h)/(d*d)
    local real B = (y1-y0-A*d*d)/d
    return A*x*x + B*x + y0

Why did you create the two local variables when you don't need them?

You also should not be using ConvertDamage/AttackType natives, use the global constants instead.

Can be improved if you use a static item and a static group instead of creating/destroying them throughout the game. You don't need to destroy boolexprs any more thanks to patch 1.24.
 
Level 13
Joined
Jun 9, 2009
Messages
1,129
OH CMONNNNNN!!!! I JUST WANTED TO UPLOAD SOMETHING SO SIMILIAR :'( :D 5/5 +REP ofc. I think you read my brain. But anyway my system was in GUI ;) Does this system checks Z ??? if not, you're gonna get really low rating from moderators. (i'm not at home currently) Anyway, these are my options:
!CheckDestrutible (on/off)
!CheckUnits (on/off)
!Growup (on/off) (when projectile gets collision to destrutible or unit, projectile starts to grow up and will explode, after it gets X,X,X size)
!Flyover (on/off) (this will turn on,off option to arrow flies straight <--if is on, if is off ---> Arrow will start falling down from begin)
!FollowTarget (on/off) (will projectile be locked to targeted unit or not, or will it follow an unit in range that comes first to it)
!AftergrowAOEdamage (on/off) (will projectile deal AOE dmg after growing up and exploding)
!AOEdamagenogrow (on/off) (will projectile deal AOE dmg if doesn't collides with something, that means no growing up or exploding)
!AOEDamage (real, amount of damage)
All other things you have... so i don't need to tell you (all what you have i have too, only no illusion) ;)
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
This is among the better of the GUI friendly ones, I guess. Few points though.

Why are you using the GetGroup BJ? Just use GroupEnumUnitsInRange and just use your function where the boolexpr is.

Also there is no need to create and destroy a group all the time, make a small group recycler for your system to handle your needs, much more efficient that way.

Also don't use locations except for the native GetLocationZ which should be used and also be a global location which is "moved" with the native MoveLocation. Learn to use coordinates you have instead.

The target filer is a bit meh, why not have the user to use a custom filter that they can change? As the filter is a bit hidden. Also use GetWidgetLife instead of GetUnitState, it's faster. Also add an extra check if the unit is dead with "IsUnitType(yourunit, UNIT_TYPE_DEAD) == false"

There also a flaw in your script, why can't the user change the attacktype and damagetype? Weapontype is fine to have as null though. Also when we're already on it, shouldn't you be possible to change the "boolean melee" and boolean range in the UnitDamageTarget too? Just sayin'.

Why are you using UnitDamagePoint?! Gosh change that into a enum group and call ForGroup.

Anyway, just schimmed the code, make your own GroupRecycler, it's not that hard, just tell me if you need any help with that. Keep it up.
 
@88WaRCraFT3; LOL, sorry i guess, but my system isn't in vjass so for me to do some things i would have to really work at it (or maybe not). I do have an AoE damaging; it's when the projectile hits something or dies.

@baassee; I currently use the getgroup bj because i tried using the native and for some reason it didn't work, I will check it again for the next update (should be today). I only use one location, which is to clean the leak in the BJ. adding the ability to make a custom filter would be nice, but it's supposed to be GUI friendly. As that stands i am trying to make a way to make custom filters using a string, but no guarantees. I also use damagepoint because it's an easy way to deal damage to all units in an explosion. Attack and damage type should be easy to add.
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
show me an example of the JASS and I'll check it out, yeah point and point, sometimes you only want to damage enemies and/or allies etc. Maybe you can take a function as argument that will be fired when the explosion occours although no gui user can do that ...
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Instead of: StringHash("Caster") and all those other stringhashes, you should do:

JASS:
constant function PS_Caster takes nothing returns integer
    return 1
endfunction

And have a unique integer for each. This way it maintains readability but doesn't sacrifice performance (especially if using JNGP or the optimizer as those functions would inline).

Also, you don't need GroupUnitsInRangeLocAll or whatever that crazy BJ is called. Just use a static group (bj_lastCreatedGroup) and run a GroupEnumUnitsInRange native.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
JNGP is no requirement for using this...

JASS:
constant function PS_Caster takes nothing returns integer
    return 1
endfunction
...
call SaveInteger(ht, 0, PS_Caster(), 1)

Is a lot faster than call SaveInteger(ht, 0, StringHash("Caster"), 1) because StringHash is much slower than a simple function return.

The "inlining" behavior just makes that timeframe even smaller as it just turns it into call SaveInteger(ht, 0, (1), 1)
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
Some stuff are really necessary to fix here.

-For the pathing, create a static item and set it into a variable instead of recreating. Remember that moving the item will make it visible so just hide it afterwards.

-Location for enum? No way. First of all, why the BJ? Second, You have coordinates, why not use them? Ever heard of GroupEnumUnitsInRange native? Seems like it as you used it a bit further in the code.

-Make a quick group recycler or make the enum group into a static one set into a variable because this is unacceptable creating and destroying. GroupEnumUnitsInRange is good in this case as it clears the group when its called.

-Don't use SquareRoot, it's slow. Instead make the if compare to 32^2 - 1024.

-GetWidgetLife(u)>0 -> > 0.405 . And I don't care what the IsUnitDeadBJ tells you. Also might add another death check IsUnitType(u, UNIT_TYPE_DEAD) == false

-==true Remove that. If the function returns true it will work.

-ConvertAttackType(udg_PS_TypeAttack)? Why not store the attacktype directly instead of using an integer? Same goes for damagetype.

-GetWidgetX -> GetUnitX It's faster than the GetWidget. GetWidgetLife is faster than GetUnitState though.

-Same goes for the loop. Use a static group.

-Have you seen your doubled calls here?

JASS:
    call DestroyGroup(g)//here
    set g=null
    if udg_PSG_Count2>0then
        set Boom=true
        call ForGroup(g,function Trig_PS_Target)
        if udg_PS_ColDeath then
            set udg_PS_Life=0
        endif
    endif
    call DestroyGroup(g) //here
    call GroupClear(g)
    set g=null
 
Yes, i will update the system with a how to use as well as implement the system.

Dummy Item; will change to move and hide.

I did change the group functions to use coords.

Can you explain the square root thing?

forgot about the magic life number, but why the extra check?

Which function for the "==true" part?

I use integers and convert it to an attacktype and damagetype so it's more GUI friendly.

Thought widgetx and y was faster, will change back to unitx/y.

Will look into removing double calls..

Thanks for your suggestions/bug fixes, I'll apply them later tonight and update the system.
 
seems nice, not that extremely customizable but at least fine for a vanilla JASS... good luck... ^_^

the other death check is just for double checking...

some suggestions:
-maybe you could put more spaces to the code, specially between the functions for readability

there's just one thing I don't like about this system, it uses lots of global variables... maybe its just my preference but I like it better to add them to the function call so that it doesn't use any global variable, since even GUI users can use custom scripts...

question: does the missiles die when it hit higher ground?
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
Can you explain the square root thing?

forgot about the magic life number, but why the extra check?

Which function for the "==true" part?

I use integers and convert it to an attacktype and damagetype so it's more GUI friendly.

1. It's slower than just ^2 the other comparison.

2. Because it's better. Changing life's with SetWidgetLife can screw up this (and you don't use UnitAlive native because of the bug it causes with the optimizer) so instead you add something more, to make it more safe.

3. All of them that has ==true, the ==true should be deleted. So if
if function() == true then

should be

if function() then

Isn't it more GUI friendly to use attacktype and damagetype? Just use some temporary variables when calling the call. In matter of fact. What's the API for this :p
 
well, the missile itself is customizable but the others like what happens when a missile hit isn't, but I think that is the limitation of vanilla JASS... ^_^ anyway this is for GUI users I think so the usage of global variables for settings is fine...

saw this on the first post:
"a global real to change the rate of all projectiles"

maybe you could make it such that we can slow down specific projectiles only?
 
Oh yea missal ballistics... totally was going to add that but forgot hehe. Well I'll update this with the various changed earlier mentioned and the parabolas.

For the square root thing, how could i do that without using the function call? not like i can say ^.5 can i?

Will make each projectile able to be changed in the 'time' multiplier instead of global.
 
oh yea, never thought of it that way hehe, thanks

edit: TO prove that this system is flexible i'll make around 7 spells that will or should be unique of each other and do different things. Now then, it may take two or three triggers, depends on how 'deep' i go into the layering*. Also note that it's finals week at school and next week i have off so i can finish said spells and stuff, i plan on uploading this sytem with a few changed tonight though.

*Layer: How many sub-projectiles a spell has triggered, a recycled 'layer' doesn't count as a new one.*


Edit 2: Can someone help me with the parabolic movement?

It works in the system, but i want to know the formula 'more'
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
The item and the first three spells do absolutely nothing when I use them. Only the fireball spell actually works and it creates a little fireball that causes considerable lag to my computer (likely because of the debug messages you forgot to remove). All tooltips say something about an infinite loop for some reason. The test map seems to be broken - or is it just me with this problem?
 
Level 2
Joined
Mar 20, 2009
Messages
21
I've been playing with this for the past few days, and really like it. I have little to no experience with triggers, but I found this very easy to use. (Though, as Bribe said previously, your test map's abilities are mostly not working.)

Two questions, though. Firstly, is there any way to remove the text that shows up when you cast the spell? I'm referring to how whenever you use an ability with it, numbers flow up the side with something either to do with speed or distance. They are somewhat hindering, and I couldn't find any evident way to remove them.

Also, is there any way to add buffs to the projectile? For example, it hits somebody, and they get poisoned?
 
Top