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

Missile [GUI] version 1.6.1

This bundle is marked as awaiting update. A staff member has requested changes to it before it can be approved.
Missile [GUI]

A system made to handle, optimize and ease projectile creation in your map.




The three golden rules for Missile
top
  1. Neither Missile__Origin nor Missile__Impact leak.
    Missile removes both location handles internally.

    ---
  2. All variables storing missile properties such as Missile__Owner or Missile__Damage
    are only valid within a trigger action function fired from the Missile trigger interface.
    Otherwise they will be null, 0 or false. To put it simple invalid.

    ---
  3. Every Missile related variable is prefixed with Missile
    You may only use variables with two underscores __, such as Missile__Source
    or variables with one underscore _, such as Missile_Source[index].
    All other variables are private and strictly reserved for the internal structure of Missile.


Create & destroy missiles
top

Create a missiles via Run Missile Configuration <gen> - Set missile properties - Run Missile <gen> syntax.
For example like here in my Fireball trigger:
  • Fireball Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Fireball
    • Actions
      • Set Missile__TempLoc = (Target point of ability being cast)
      • -------- --------
      • Trigger - Run Missile Configurate <gen> (ignoring conditions)
      • Set Missile__Source = (Triggering unit)
      • Set Missile__Owner = (Triggering player)
      • Set Missile__Origin = (Position of Missile__Source)
      • Set Missile__Impact = (Missile__Origin offset by 550.00 towards (Angle from Missile__Origin to Missile__TempLoc) degrees)
      • Set Missile__ImpactZ = 50.00
      • Set Missile__OriginZ = 50.00
      • Set Missile__Speed = 500.00
      • Set Missile__Model = Abilities\Weapons\FireBallMissile\FireBallMissile.mdl
      • Trigger - Run Missile <gen> (ignoring conditions)
      • -------- --------
      • Custom script: call RemoveLocation(udg_Missile__TempLoc)
A missile can be manually destroyed during each trigger event via
  • Set Missile__WantDestroy = True
or automatically when reaching the impact point.



Missile trigger interface
top

Missile optionally runs the five below listed trigger events.
Each event will upon occurrence run the trigger set to the trigger variable.
In the example below Fireball Actions <gen> would run for all events.

  • Set Missile__OnPeriodic = Fireball Actions <gen>
  • Set Missile__OnCollideUnit = Fireball Actions <gen>
  • Set Missile__OnCollideDestructable = Fireball Actions <gen>
  • Set Missile__OnFinish = Fireball Actions <gen>
  • Set Missile__OnRemove = Fireball Actions <gen>
You can identify the dispatched trigger by evaluating Missile__EventId in an integer comparison with
these constant Missile event variables for example Missile__EventId equals EVENT_MISSILE_FINISH

  • EVENT_MISSILE_PERIODIC runs every timer interval.
  • EVENT_MISSILE_COLLIDE_UNIT runs on unit collision.
  • EVENT_MISSILE_COLLIDE_DEST runs on destructable collision.
  • EVENT_MISSILE_FINISH runs if the impact point is reached. If on finish is defined you must destroy the missile manually.
  • EVENT_MISSILE_REMOVE runs when a missile is irrevocably destroyed.

Missile variables - Documentated in JASS format
top

JASS:
//=============================================================
//  Missile API. 
//=============================================================  
// Syntax for missile creation in GUI:
//    1. Run trigger Missile Configurate <gen> 
//    2. Set properties via scalar variables.
//    3. Run trigger Missile <gen>
// JASS users may call the create and launch function directly.
//
// Missile operates with custom events.
// This means that you have access to 
// a missile's properties within action functions
// of the Missile trigger interface. 
//
// "udg_Missile__EventId" indicates
// which event trigger has been dispatched.
//
// "udg_Missile__EventIndex" is the array index
// of the triggering missile.
//
// Avaliable events are:
//
//   1.) udg_EVENT_MISSILE_COLLIDE_UNIT
//        • Runs when a missile collides with a unit.
//
//   2.) udg_EVENT_MISSILE_COLLIDE_DEST
//        • Runs when a missile collides with a destructable.
//
//   3.) udg_EVENT_MISSILE_PERIODIC
//        • Runs every missile timer interval.
//
//   4.) udg_EVENT_MISSILE_FINISH
//        • Runs when a missile reaches its impact position.
//
//   5.) udg_EVENT_MISSILE_REMOVE
//        • Runs when a missile is destroyed.
//
//   6.) udg_EVENT_MISSILE_NOTHING
//        • Value of udg_Missile__EventId when accessed
//          from outside a trigger action function.
//
// During every missile event you may use the 
// following GUI generated variables.
// Every scalar variable has an equivalent array variable,
// which you can read and use at any time. 
// For exmple: udg_Missile__Source vs. udg_Missile_Source[index]
//
// Trigger variables which fire Missile events:
//
//    trigger udg_Missile__OnCollideUnit            -    trigger array udg_Missile_OnUnit 
//    trigger udg_Missile__OnCollideDestructable    -    trigger array udg_Missile_OnDest
//    trigger udg_Missile__OnPeridoic               -    trigger array udg_Missile_OnPeriodic
//    trigger udg_Missile__OnRemove                 -    trigger array udg_Missile_OnRemove
//    trigger udg_Missile__OnFinish                 -    trigger array udg_Missile_OnFinish
//
// Variables which mimic a function call:
//
//    location udg_Missile__Origin    
//    location udg_Missile__Impact      
//    boolean  udg_Missile__WantDestroy    -    boolean array udg_Missile_WantDestroy
//    boolean  udg_Missile__Recycle        -    boolean array udg_Missile_Recycle
//    real     udg_Missile__Scale          -    real    array udg_Missile_Scale
//    real     udg_Missile__FlyTime        -    real    array udg_Missile_FlyTime ( Converts time in seconds to a vector lenght )
//    real     udg_Missile__Model          -    string  array udg_Missile_Model   ( Converts a string path to a special effect )
//    real     udg_Missile__Arc            -    real    array udg_Missile_Arc     ( Converts an arc in degree to height value )
//    real     udg_Missile__Curve          -    real    array udg_Missile_Curve   ( Converts a curve in degree to an open value )
//
// Variables for read-only:
//
//    integer udg_Missile__EventId     
//    integer udg_Missile__EventIndex  
//    unit    udg_Missile__Dummy           -    unit array udg_Missile_Dummy
//    real    udg_Missile__Angle           -    real array udg_Missile_Angle    ( In radians )
//    real    udg_Missile__Distance        -    real array udg_Missile_Distance ( Total distance traveled )
//
// Variables for read and set.
//
//    unit    udg_Missile__Source          -    unit    array udg_Missile_Source
//    unit    udg_Missile__Target          -    unit    array udg_Missile_Target    ( Enables homing behaviour towards a target unit )
//    player  udg_Missile__Owner           -    unit    array udg_Missile_Owner     ( Pseudo-owner for better onCollide evaluation ) 
//    real    udg_Missile__ImpactZ         -    real    array udg_Missile_ImpactZ
//    real    udg_Missile__OriginZ         -    real    array udg_Missile_OriginZ
//    real    udg_Missile__Damage          -    real    array udg_Missile_Damage
//    real    udg_Missile__Collision       -    real    array udg_Missile_Collision
//    real    udg_Missile__Speed           -    real    array udg_Missile_Speed
//    real    udg_Missile__Acceleration    -    real    array udg_Missile_Acceleration
//    real    udg_Missile__Height          -    real    array udg_Missile_Height    ( Highest point of the parabola )
//    real    udg_Missile__Open            -    real    array udg_Missile_Open      
//    real    udg_Missile__Turn            -    real    array udg_Missile_Turn      ( Turn ratio per second )
//    real    udg_Missile__Data            -    integer array udg_Missile_Data


Example trigger action function
top

Let's see how the event triggers run code in an action function.
We stick to the fireball scenario. This spell is also included in the demo map.

  • Fireball Actions
    • Events
    • Conditions
    • Actions
      • -------- As you can see Missile__EventId allows you --------
      • -------- to identify which event trigger dispatched. --------
      • -------- Therefore you can run all actions from one trigger function. --------
      • -------- Of course you can also seperate triggers into different triggers. --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Missile__EventId Equal to EVENT_MISSILE_REMOVE
        • Then - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Missile__Data Equal to 1
            • Then - Actions
              • -------- Create more fireballs --------
              • -------- Reference to Missile__Dummy will be removed --------
              • -------- Once you call Run Missile Configurate <gen> --------
              • Set Missile__TempLoc = (Position of Missile__Dummy)
              • For each (Integer A) from 1 to 6, do (Actions)
                • Loop - Actions
                  • Trigger - Run Missile Configurate <gen> (ignoring conditions)
                  • Set Missile__Origin = (Point((X of Missile__TempLoc), (Y of Missile__TempLoc)))
                  • Set Missile__Impact = (Missile__Origin offset by 450.00 towards (60.00 x (Real((Integer A)))) degrees)
                  • Set Missile__ImpactZ = 50.00
                  • Set Missile__Height = 350.00
                  • Set Missile__OriginZ = 50.00
                  • Set Missile__Speed = 500.00
                  • Set Missile__Damage = 150.00
                  • Set Missile__Source = Missile_Source[Missile__EventIndex]
                  • Set Missile__Owner = Missile_Owner[Missile__EventIndex]
                  • Set Missile__Model = Abilities\Weapons\FireBallMissile\FireBallMissile.mdl
                  • Set Missile__OnCollideUnit = Fireball Actions <gen>
                  • Set Missile__OnRemove = Fireball Actions <gen>
                  • Set Missile__Data = 2
                  • Trigger - Run Missile <gen> (ignoring conditions)
              • Custom script: call RemoveLocation(udg_Missile__TempLoc)
              • Custom script: set udg_Missile__TempLoc = null
            • Else - Actions
              • Set Missile__TempLoc = (Position of Missile__Dummy)
              • Set Temp_Group = (Units within 128.00 of Missile__TempLoc matching ((((Matching unit) belongs to an enemy of Missile__Owner) Equal to True) and (((Matching unit) is alive) Equal to True)))
              • Unit Group - Pick every unit in Temp_Group and do (Actions)
                • Loop - Actions
                  • Unit - Cause Missile__Source to damage (Picked unit), dealing Missile__Damage damage of attack type Spells and damage type Normal
              • Special Effect - Create a special effect at Missile__TempLoc using Abilities\Spells\Other\Doom\DoomDeath.mdl
              • Special Effect - Destroy (Last created special effect)
              • Custom script: call DestroyGroup(udg_Temp_Group)
              • Custom script: call RemoveLocation(udg_Missile__TempLoc)
              • Custom script: set udg_Missile__TempLoc = null
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Missile__EventId Equal to EVENT_MISSILE_COLLIDE_UNIT
              • (Missile__UnitHit belongs to an enemy of Missile__Owner) Equal to True
            • Then - Actions
              • -------- See how easy damaging got. --------
              • Unit - Cause Missile__Source to damage Missile__UnitHit, dealing Missile__Damage damage of attack type Normal and damage type Normal
              • Set Missile__WantDestroy = True
            • Else - Actions


Keywords:
Missile, Projectile, System
Contents

Just another Warcraft III map (Map)

Reviews
IcemanBo
Submission: Missile [GUI] v1.61 Date: 1 January 2017 Status: Awaiting Update Rating: noneNote: It works actually, but there are some things that needs your attention first. Alone such little things that event ids are different from description is...
Level 19
Joined
Mar 18, 2012
Messages
1,716
So there are 3 possibilies in for event triggers and I'm still unsure which is the best.
Please give me your input.

1. The current design: Shared scalar variables in event / creation.
  • There is a scalar variable for each missile property, which is valid during
    each Missile event for example udg_Missile__Source.
    • Unit - Cause Missile__Source to damage Missile__Target, dealing 500.00 damage of attack type Spells and damage type Normal
    ---
  • These variables are also used / shared for new Missile creation.
    ---
  • You can access the related array via for example Missile_Source[Missile__EventIndex]
    to transfer data from the event triggering missile to a new one.
    ---
  • Pro: Less variables. Easy API.
  • Cons: Requires Run Missile Config trigger -- Set properties -- Run Missile Create trigger syntax.
    Less performant than 2

2. No scalar variables in events.
  • You only get Missile__EventIndex in Missile events and there must access the array instead. For example
    • Unit - Cause Missile_Source[Missile__EventIndex] to damage Missile_Target[Missile__EventIndex], dealing 500.00 damage of attack type Spells and damage type Normal
    --
  • Pros: Best performance ( significant ), as there isn't a transfer process from array to scalar required before an event trigger fires.
    Missiles can be created without running Missile Config trigger.
  • Cons: Less easy API as you have to access the arrays directly.
    For example: udg_Missile_Damage[udg_Missile__EventIndex] instead of udg_Missile__Damage

3. More variables
  • A new seperate set of variables for events and missile creation.
    udg_Missile__Source and udg_Missile__EventSource
  • Pros: Ok API. Missiles can be created without running Missile Config trigger.
  • Cons: Less performant than 2 and double amount of variables.
I like solution 1 and 2. Solution 3 is the worst in my eyes. What do you think?
 
The event ids are a bit mixed up. In the GUI trigger "Missle config" it goes from 0 to 6, but "5" is skipped.
In the JASS readme, it goes from 1 to 6, but without "0".
You probably just changed it with the "Nothing" event and forget to change it at the jass text.

Actually the interface for user and handling of the system looks very awesome.
For a Jass/GUI code, I can't imagine it really better.

Could you elaborate on this functions?
function Missile_UpdateStack takes nothing returns nothing
function Missile_RecycleDummy takes unit dummy returns nothing
I somehow see it as overhead to worry about effect death time.
I'm sure we can use KillUnit() + "not raise, not decay" without any delay,
as killing a unit will still show it's own death animation as also death animations of attached special effects.

JASS:
function Missile_SetRectRectangle takes integer index returns rect
    local real x1 = udg_Missile_PrevX[index] 
    local real y1 = udg_Missile_PrevY[index]
    local real x2 = udg_Missile_PosX[index]
    local real y2 = udg_Missile_PosY[index]
    local real d = udg_Missile_Collision[inde

vs

JASS:
function Missile_SetRectCircle takes integer index returns rect
    local real x = udg_Missile_PosX[index]
    local real y = udg_Missile_PosY[index]
I'm just curious. Why does the max and min x/y of the first function not look similar to the second?
Honest question. I dont even know if it's right or wrong.

In missle core there seems to be a safety check not to fire more than 100 triggers.
Maybe it could throw an ErrorMessage in such a case.

In function Missile_InitNewMissile takes integer index returns nothing
set udg_Missile_Angle[index] = GetUnitFacing(udg_Missile__Dummy)*bj_DEGTORAD
->
set udg_Missile_Angle[index] = face

After your mentioned update I also will rate I think. :)
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
The event ids are a bit mixed up. In the GUI trigger "Missle config" it goes from 0 to 6, but "5" is skipped.
In the JASS readme, it goes from 1 to 6, but without "0".
You probably just changed it with the "Nothing" event and forget to change it at the jass text.
Probably I messed something up here in a version update.
Finally the number doesn't matter much. They just have to be different per event id.

Actually the interface for user and handling of the system looks very awesome.
For a Jass/GUI code, I can't imagine it really better.
Thanks.

Could you elaborate on this functions?
function Missile_UpdateStack takes nothing returns nothing
function Missile_RecycleDummy takes unit dummy returns nothing
I somehow see it as overhead to worry about effect death time.
I'm sure we can use KillUnit() + "not raise, not decay" without any delay,
as killing a unit will still show it's own death animation as also death animations of attached special effects.
I made a lot of tests when I made the big brother Missile from the JASS section.
  • KillUnit() works perfectly, except that it updates the locust effect on a dummy unit.
    After KillUnit() a locust unit can be enumerated via GroupEnumUnitsInRange.
    This messes with the missile collides unit event as there is no locust filter included.
    It also seems that they are also not instantly removed out of game.
    ---
  • Timed life via BTFL somehow had an impact on my fps for many missiles. ( Maybe I'm wrong here and timed life is the best option )
    ---
  • Finally I went with RemoveUnit and a stack which updates every 1 second.

For a circular collision you have to the rect centerX/Y is the position of the missile.

For a rectangle non circular rect you'll need the prevX/Y and the currentX/Y of the missile,
then check which is coordinates are bigger otherwise the paramenters of the rect are incorrect.

The whole rectangle collision was an idea of Zwiebelchen and Wietlol, because
for missiles with high speed and low collision radius the circular collision detection
will leave out many potential targets.
 
You're right that KillUnit() will not instantly remove the unit from game.
However the unit will be removed after the death animation has played properly.
So if it's the wanted effect to play animations after death, then it's probably the most elegant solution.

JASS:
// The cleanest approach appears to be RemoveUnit(unit). Using a stack with timed dummy
// recycling helps us to properly display the attached special effects.
^I fail to see logics for caring to play the animation of attached effects.
What I see is only a delayed "RemoveUnit" which is checked each second at the stack.
And from my understanding the death effect won't play properly then, because the unit will be instantly removed.

Maybe it's intended to destroy the special effect on function Missile_RecycleDummy
so it has 3 seconds to play before the dummy is removed.

But if these are the options I personaly would maybe still go with KillUnit() and add an extra condition at the filter. Maybe just preference.
_______________

And, oh, I see. That rectangle solution is pretty clever to ensure picking really all units.
But on other side this seems to be uncared at function Missile_IsWidgetInRange.
There you "only" pick units in range of current position, which does potentialy leak some units then, if speed is very fast.
Basicly then it would need to share the exactly same rectangle from PREV to CURRENT, as the max and min of the circle will cover all points.
But not 100% the same. At the very start and the very end of the rectangle the shape must be half circled.
So from PREV(x/y) and CURRENT (x/y) it should be checked normaly for range, but all in between should be the same rect as in function Missile_SetRectRectangle.
It would look similar to a cylinder, but with a half-sphered cap at front and at the back.

Like:
JASS:
    local real x1 = udg_Missile_PrevX[index] 
    local real y1 = udg_Missile_PrevY[index]
    local real x2 = udg_Missile_PosX[index]
    local real y2 = udg_Missile_PosY[index]
    local real d = udg_Missile_Collision[index] + Missile_GetMaxCollision()
    // What is min, what is max ...
    if x1 < x2 then
        if y1 < y2 then
            call SetRect(udg_MissileRect, x1 , y1 , x2 , y2 )
        else
            call SetRect(udg_MissileRect, x1 , y2 , x2 , y1 )
        endif
    else
        if y1 < y2 then
            call SetRect(udg_MissileRect, x2 , y1 , x1 , y2 )
        else
            call SetRect(udg_MissileRect, x2 , y2 , x1 , y1 )
        endif
    endif 
    
    // ^ Rect is done without range "d".
    //    So now of current(x/y) and prev (x/y) there needs to be a circular check
    //    for all widgets in range of "d".
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
I think KillUnit() is a risk factor. From an aspect of performance it's however first choice.

First and foremost the collision detection for widgets is not 100% accurate, but it's sufficent.
Consider the resolution of Warcraft. Then consider the required overhead for a perfect result. It's not worth it.

There you "only" pick units in range of current position, which does potentialy leak some units then, if speed is very fast.
If the speed is fast Missile automatically uses the rectangle collision detection.
Actually always when the speed is bigger than the collision.
In general using the rectangle trick is more accurate, but also requires much much more computation.
JASS:
        // Run rectangle collision.
        if udg_Missile_Collision[index] < udg_Missile_Speed[index]*Missile_GetTimerTimeout() then
            set hit = Missile_IsWidgetInRectangleRad(index, d) 
        else
            // Run circular collision.
            set hit = Missile_IsWidgetInRange(index, d, Missile_GetDestructableHeight(d), udg_Missile_Collision[index])
        endif
At the very start and the very end of the rectangle the shape must be half circled.
Of course. It's half circled at both ends.
JASS:
// 
//   ,---------------------.  ,
//  (                       ) | radius
//   `---------------------'  `
//  |<->|         Units which collision circles intersect with this figure.
JASS:
// For a rectangle collision z values are
// very inaccurate, hence they are completly ignored.
function Missile_IsWidgetInRectangleRad takes integer index, widget w returns boolean
    local real wx = GetWidgetX(w)
    local real wy = GetWidgetY(w) 
    local real dx = udg_Missile_PosX[index] - udg_Missile_PrevX[index]
    local real dy = udg_Missile_PosY[index] - udg_Missile_PrevY[index]
    local real s  = (dx*(wx - udg_Missile_PrevX[index]) + dy*(wy - udg_Missile_PrevY[index]))/RMaxBJ(0.0001, (dx*dx + dy*dy))
    if s < 0.00 then
        set s = 0.00
    elseif s > 1.00 then
        set s = 1.00
    endif
    set dx = (udg_Missile_PrevX[index] + s*dx) - wx
    set dy = (udg_Missile_PrevY[index] + s*dy) - wy
    return dx*dx + dy*dy <= udg_Missile_Collision[index]*udg_Missile_Collision[index] 
endfunction
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
In missle core there seems to be a safety check not to fire more than 100 triggers.
Maybe it could throw an ErrorMessage in such a case.
I didn't explain that one yet. Missile has to loop over the entire missile list. Maybe 5 missiles, maybe 500.
To avoid running into an OP limit I divided the action into 100 chunks per trigger evaluate.
I make use of the return value of TriggerEvaluate. When the Missile__Index is 0 the iteration is done for that timer callback.
return udg_Missile__Index == 0.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Well documented and well done!

Here are the things I would nitpick:
  • I see you have a lot of wrapper functions regarding the linked-list, why not inline them directly? Some are critical like Missile_GetListNextNode(index) because it gets called a lot. If you're doing it for readability, most are one-liner
    anyway and won't affect the readability. And since this is for GUI-users, you can't expect users to have JNGP so it won't automatically inline.

  • You could avoid this unnecessary variable local integer loops = 0 // Iteration counter. if you would manipulate integer limit inside the loop instead.

  • If it were up to me, I would have ovewritten udg_Missile_Speed[index] to avoid the repeating multiplication and calling to Missile_GetTimerTimeout(). Same goes for udg_Missile_Turn[index] and udg_Missile_Acceleration[index] so that all are within the Timeout frame.

  • How does your Missile_IsWidgetInRectangleRad work? Is it better than using Distance of a point to a line method?

  • // Delayed dummy recycler. Data structure stack. it doesn't recycle, it removes after a delay. Just sayin.

  • What makes you decide local integer limit = 100 is the right number? Is this tested in the worst case scenario?
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
I see you have a lot of wrapper functions regarding the linked-list, why not inline them directly? Some are critical like Missile_GetListNextNode(index) because it gets called a lot. If you're doing it for readability, most are one-liner
anyway and won't affect the readability. And since this is for GUI-users, you can't expect users to have JNGP so it won't automatically inline.
Indeed it was all about read-ability and the idea that the JassHelper inlines it.

You could avoid this unnecessary variable local integer loops = 0 // Iteration counter. if you would manipulate integer limit inside the loop instead.
True. I'll update it.

If it were up to me, I would have ovewritten udg_Missile_Speed[index] to avoid the repeating multiplication and calling to Missile_GetTimerTimeout(). Same goes for udg_Missile_Turn[index] and udg_Missile_Acceleration[index] so that all are within the Timeout frame.
For speed and acceleration yes, but turn a valid turn value is i.e. 3, which would be
3/32 which is 0,09375 and GUI only allows two decimals.

How does your Missile_IsWidgetInRectangleRad work? Is it better than using Distance of a point to a line method?
I'll explain later.

What makes you decide local integer limit = 100 is the right number? Is this tested in the worst case scenario?
Just an assumption probably 400 would also work.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Indeed it was all about read-ability and the idea that the JassHelper inlines it.
Ok then. But not everyone uses JNGP (I know, ridiculous).

For speed and acceleration yes, but turn a valid turn value is i.e. 3, which would be 3/32 which is 0,09375 and GUI only allows two decimals.
Users will still input in per second and then upon initialization of the missile, you overwrite it to per timeout.

Just an assumption probably 400 would also work.
In my opinion, that value should be the highest possible value that will support the worst case scenario to minimize TriggerEvaluations as possible.
 
In my opinion, that value should be the highest possible value that will support the worst case scenario to minimize TriggerEvaluations as possible.
As it's about operation limit, it's probably good to be more on safe side over being at the very limit.
The problem might be that it can't be pre-calculated how much operation the user will take in action under his own trigger actions/conditions.
So for one 200 might work, for the other one only 100.

From some tests in past with recursive functions I approximatly could agree with the number "100".
I had not a really complex function back then, but had a nested loop logic included. And my number for calls was like "125" iirc. (was the limit, because the operations were static)
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Yes, you are right. He will create a new thread for the user trigger, wich I have ignored.

Still, the operation count is dynamic inside the system, as destuctables, circular range, units in rect, are not being constant and equal for each run.
So how would one define the maximum?

Touché.

However, all missiles applying the rectangle collision is most likely the worst case, for which the only unpredictable part is the number of widgets per rect. The problem now is, how can we know if 100 is even safe? What if some badass yolo user apply a super unrealistically large collision size to all missiles causing a lot of enum and reaching the OP limit before a hundred missiles is enumerated?
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
I'm working on a new approach for projectile motion.
I think it's much better than the one I use here.

I'll update Missile soon.


I've tested a lot. Indeed I found another algorithm for projectile motion,
but it's not that nice for GUI usage. Missile is good as it is now.
 
Last edited:
Level 19
Joined
Mar 18, 2012
Messages
1,716
Basically it works pretty good, but
this still requires a Need Fix status.

Atan function should be replaced with Atan2.
The velocity vector should be 3D not 2D, etc...

I won't be able to work on this in the near future.

EDIT:

I'm re-writing this beauty.
I hope I'll finish it in soon future.
 
Last edited:
Level 5
Joined
Jun 15, 2016
Messages
111
Can it be used for missile projectiles that have one specific target unit only? I'm having the problem of Unit-Starts effect of Ability triggers
 
Can it be used for missile projectiles that have one specific target unit only? I'm having the problem of Unit-Starts effect of Ability triggers

It can be used for "single target Homing spells"
Like this:

Casting

  • Schattenball
    • Ereignisse
      • Einheit - A unit starts an effect of an ability
    • Bedingungen
      • (Ability being cast) = your Spell
    • Aktionen
      • Trigger - Run Missile Configurate <gen> (ignoring conditions)
      • -------- Target Setting --------
      • Set Missile__Source = (Casting unit)
      • Set Missile__Owner = (Triggering player)
      • Set Missile__Origin = (Position of Missile__Source)
      • Set Missile__Target = (Target unit of ability being cast)
      • -------- - --------
      • -------- Z-Offsets --------
      • Set Missile__ImpactZ = 50.00
      • Set Missile__OriginZ = 50.00
      • -------- - --------
      • Set Missile__Speed = 500.00
      • Set Missile__Damage = 400.00
      • -------- - --------
      • Set Missile__Model = Abilities\Weapons\DemonHunterMissile\DemonHunterMissile.mdl
      • Set Missile__Scale = 1.40
      • -------- Set trigger with should run on missile events. --------
      • Set Missile__OnFinish = Schattenball Actions <gen>
      • Trigger - Run Missile <gen> (ignoring conditions)

Hit

  • Schattenball Actions
    • Ereignisse
    • Bedingungen
    • Aktionen
      • Einheit - Cause Missile__Source to damage Missile__Target, dealing Missile__Damage damage of attack type Spell and damage type Magic
      • Set Missile__WantDestroy = True
 
Level 3
Joined
Dec 8, 2013
Messages
51
Well, it seems to be amazing! But I dont fully understand, for now. For example, what is the purpose of Missle_Data?
And yeah, is there a way to make beast-master wild axe like spell ( in my case it should work to unit target skill )?
 
Last edited:
As far as I can tell, Missile_Data is there mostly if you want to store an integer specific to the missile. For instance, if you want to make a spell with a missile that bounces from one target to the other, you can use Missile_Data to store the number of bounces. It's not FOR bouncing missiles specifically, it's just an optional field you can use to store any integer.

As for the Beastmaster axe spell from Dota, you would have to change the udg_Missile__Curve value. I don't actually know if it needs to be set in degrees or radians, so if you find that the curve is going crazy, try converting it to radians and try again. I'd imagine the Beastmaster axes curve around something like 10 degrees (0.174533 radians), but that's just a guesstimate.

NB: I use the vJass version of Missile so hopefully the GUI version is not too different.
 
Level 3
Joined
Dec 8, 2013
Messages
51
As far as I can tell, Missile_Data is there mostly if you want to store an integer specific to the missile. For instance, if you want to make a spell with a missile that bounces from one target to the other, you can use Missile_Data to store the number of bounces. It's not FOR bouncing missiles specifically, it's just an optional field you can use to store any integer.

As for the Beastmaster axe spell from Dota, you would have to change the udg_Missile__Curve value. I don't actually know if it needs to be set in degrees or radians, so if you find that the curve is going crazy, try converting it to radians and try again. I'd imagine the Beastmaster axes curve around something like 10 degrees (0.174533 radians), but that's just a guesstimate.

NB: I use the vJass version of Missile so hopefully the GUI version is not too different.
Thx a lot, man.
And I got something. The curve doesnt work at all, and so is missile speed. I dont know why, I mostly used explosion bomb as an example.
Code:
call TriggerExecute( gg_trg_Missile_Configurate )
        set udg_Missile__Source = tr // yes it travels from target to source,
        set udg_Missile__Owner = GetOwningPlayer(tr)
        set udg_Missile__Target = c
     
     
        set udg_Missile__Origin = GetSpellTargetLoc()
        set udg_Missile__OriginZ = 50.00
     
        set udg_Missile__Impact = GetUnitLoc(c)
        set udg_Missile__ImpactZ = 80.00
        set udg_Missile__FlyTime = 2.00
        set udg_Missile__Speed = 800.
     
        set udg_Missile__Collision = 128.00 //64
        set udg_Missile__Height = GetRandomReal(110,170) //250.00
        set udg_Missile__Damage = 1.00
        set udg_Missile__Curve = -100 //( -70.00 + ( 35.00 * I2R( i4 ) ) ) tried a lot of ways
        set udg_Missile__Model = "Abilities\\Spells\\Other\\BlackArrow\\BlackArrowMissile.mdl"
        set udg_Missile__Scale = 1.10
        set udg_Missile__OnFinish = gg_trg_HHealAction
        set udg_Missile__Data = 1
        // Set trigger with should run on missile events.
        call TriggerExecute( gg_trg_Missile )
 
Oh, right, I forgot to mention, if you assign value to udg_Missile__Target, the system will disregard both udg_Missile__Arc and udg_Missile__Curve and home the Missile in directly. Since the Beastmaster Axe only damage on collision, you really don't need a target for those.

EDIT: Ok, I made an example of the Beastmaster Axes. I haven't gotten the boomerang feature to work quite yet, but it should show you how to make missiles curve. Just don't give it a target and it should be fine.
 

Attachments

  • Missile GUI.w3x
    73.8 KB · Views: 54
Last edited:
Level 3
Joined
Dec 8, 2013
Messages
51
Oh, right, I forgot to mention, if you assign value to udg_Missile__Target, the system will disregard both udg_Missile__Arc and udg_Missile__Curve and home the Missile in directly. Since the Beastmaster Axe only damage on collision, you really don't need a target for those.

EDIT: Ok, I made an example of the Beastmaster Axes. I haven't gotten the boomerang feature to work quite yet, but it should show you how to make missiles curve. Just don't give it a target and it should be fine.
That is nice one man, but me wanted a target one skill ( that goes to target, not to point ). It seems that conflict with system?
 
Yeah, unfortunately, having a missile home in on a target will disable the arc and curve. You can still identify a target with an array variable that with the index of the missile, but the field udg_Missile__Target itself should remain blank.

TankCommander's Master Projectile System can actually have a target and homing and curves and arcs, but I've had trouble using it. I don't really understand how to customise it.
 
Level 3
Joined
Dec 8, 2013
Messages
51
Yeah, unfortunately, having a missile home in on a target will disable the arc and curve. You can still identify a target with an array variable that with the index of the missile, but the field udg_Missile__Target itself should remain blank.

TankCommander's Master Projectile System can actually have a target and homing and curves and arcs, but I've had trouble using it. I don't really understand how to customise it.
Same for me. But me dont even know vjass, eh...
 
Level 39
Joined
Feb 27, 2007
Messages
4,992
  • Events
    • -------- this is run automatically by the system --------
  • Conditions
  • Actions
    • If (All conditions) then (actions) else (actions)
      • If - Conditions
        • Missile__EventId equal to EVENT_MISSILE_PERIODIC
        • Missile__Data equal to 1 //Maybe should be == 0, depends if Missile__Data starts at 0 or 1 by default
        • (YourRegion <gen> contains Missile__Dummy) Equal to True
      • Then - Actions
        • Set Missile__Data = 2 //maybe 1, see above
        • -------- Do your stuff --------
      • Else - Actions
 

Submission:
Missile [GUI] v1.61

Date:
1 January 2017

Status:
Awaiting Update

Rating:
none
Note:

It works actually, but there are some things that needs your attention first.
Alone such little things that event ids are different from description is something unnecessary.
Some other things were mentioned, too, in thread, but you will probably know best when you come back.

What is also for me a lacking missile feature is not being able to define a maximum of duration. Travaled distance is not always enough.
I know you started Projectile library, but I'm still sceptic if we really need to different approaches for similar goals.

No rating yet, and again for all, this system should work, but before being approved I would feel better if BPower steps in again to make the code a round thing.
 
Level 7
Joined
Aug 11, 2010
Messages
269
This looks like a great system, though I'm thoroughly disappointed that the homing feature doesn't work with arcs. It's really easy to use and pretty powerful, I'm definitely interested in seeing this system being worked on more and hopefully be a very simplistic system yet offering great power.
 
Level 11
Joined
Jul 4, 2016
Messages
627
I am getting this error Error Image | HIVE I have a UnitIndexer in the map, thinking that might be the cause. It affects the missile template spells in my map.

P.S. Does anyone know how to make it not continously fire off multiple missiles until the target is dead when used within a damage event (specifically Bribe's damage engine). I tried turning off the Unit Indexer, which did not work.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
I am getting this error Error Image | HIVE I have a UnitIndexer in the map, thinking that might be the cause. It affects the missile template spells in my map.

P.S. Does anyone know how to make it not continously fire off multiple missiles until the target is dead when used within a damage event (specifically Bribe's damage engine). I tried turning off the Unit Indexer, which did not work.
What is the map you're testing it on?
 
Level 11
Joined
Jul 4, 2016
Messages
627
EDIT: This system works fine but when using around 12 units firing off homing missiles for at least 5 mins in the same area, the fps begins to drop severely to nearly 0 permanently. It stays on a steady 39-40 in the beginning. Is it because too many missile dummies staying put around the same area or being made?

This does not appear to happen when its not homing missiles.
 

Attachments

  • Metastasian.w3x
    213.4 KB · Views: 23
Level 11
Joined
Jul 4, 2016
Messages
627
A way you could do this to is to use your own missile dummy that isn't used by the system and launch a new missile with the old missile dummy. This could be done during the Looping event or at the end of the missile duration. Just make to destroy the previous missile duration.
 
Level 6
Joined
Aug 25, 2007
Messages
79
I could see doing something like that, like selecting the missile, removing it, and firing back a new missile. Only problem is I can't figure out a way to select any of this system's missiles in flight. If I try selecting all units owned by Neutral Passive and killing them, that works, but if I try selecting units within X range of a point, that doesn't work with these missiles.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
I could see doing something like that, like selecting the missile, removing it, and firing back a new missile. Only problem is I can't figure out a way to select any of this system's missiles in flight. If I try selecting all units owned by Neutral Passive and killing them, that works, but if I try selecting units within X range of a point, that doesn't work with these missiles.

You can't enumerate a unit with the Locust ability.
 
Level 3
Joined
Mar 11, 2019
Messages
31
Hey idk if you're still here, but I'm having an issue creating a special effect on missile finish. It should run collat on finish(it does, but it doesn't create a special effect...)


Edit: Nevermind, figured it out. I had to change it to MissileLocZ instead of missile__impact. Will leave this up for anyone else.




  • RIFLESHOT Copy
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Snipe
    • Actions
      • Set Missile__TempLoc = (Target point of ability being cast)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • EVENT_MISSILE_COLLIDE_DEST Equal to Missile__EventId
        • Then - Actions
          • Set Missile__WantDestroy = True
          • Animation - Play Missile__DestructableHit's stand hit animation
        • Else - Actions
          • For each (Integer A) from 1 to 1, do (Actions)
            • Loop - Actions
              • Trigger - Run Missile Configurate <gen> (ignoring conditions)
              • Set Missile__Source = (Triggering unit)
              • Set Missile__Owner = (Triggering player)
              • Set Missile__Origin = (Position of Missile__Source)
              • Set Missile__OriginZ = 50.00
              • Set Missile__Impact = (Target point of ability being cast)
              • Set Missile__ImpactZ = 0.00
              • Set Missile__FlyTime = 0.50
              • Set Missile__Speed = 2000.00
              • Set Missile__Collision = 50.00
              • Set Missile__Height = 1.00
              • Set Missile__Damage = 100.00
              • Set Missile__Curve = (-70.00 + (35.00 x (Real((Integer A)))))
              • Set Missile__Model = Abilities\Weapons\HarpyMissile\HarpyMissile.mdl
              • Set Missile__Data = 1
              • -------- Set trigger with should run on missile events. --------
              • Set Missile__OnFinish = collat <gen>
              • Set Missile__OnRemove = collat <gen>
              • Set Missile__OnCollideDestructable = Destruct kill Copy <gen>
              • Set Missile__OnCollideUnit = unithit Copy <gen>
              • Trigger - Run Missile <gen> (ignoring conditions)
              • Custom script: call RemoveLocation(udg_Missile__TempLoc)
              • Custom script: set udg_Missile__TempLoc = null
  • ------------------------------------------------------------------------------------
  • collat
    • Events
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Missile__EventId Equal to EVENT_MISSILE_FINISH
        • Then - Actions
          • Special Effect - Create a special effect at Missile__Impact using Abilities\Spells\Undead\DarkSummoning\DarkSummonMissile.mdl
          • Set Missile__WantDestroy = True
        • Else - Actions
 
Last edited:
Level 2
Joined
Apr 16, 2017
Messages
13
i have a question for you.
how should I do.
Make this skill.
 

Attachments

  • CKV4HRI.gif
    CKV4HRI.gif
    7.4 MB · Views: 57
Top