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

MissileCollision v1.1

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

Foreword

Code

Instructions

Demo

Credits

Changelogs

Bugs


An extremely simple missile projectile system that collides and damages on enemy units
or blows on impact when desired distance is reached.

The missile is recycle able so that it will not create different dummies everytime.

JASS:
library MissileCollision /* v1.1
*************************************************************************************
*
*   by mckill2009
*
*************************************************************************************
*
*   An extremely simple missile projectile system that collides and damages on enemy units
*   or blows on impact when desired distance is reached.
*   The missile is recycle able so that it will not create different dummies everytime.
*
*************************************************************************************
*
*   */ uses /*
*   
*       */ T32          /* http://www.thehelper.net/forums/showthread.php/132538-Timer32
*       */ Dummy        /* http://www.hiveworkshop.com/forums/jass-resources-412/system-dummy-213908/
*
************************************************************************************
*
*   Credits
*
*       Vexorian
*       -----------------------
*           For his DUMMY.mdx model
*
*       Jesus4Lyf
*       -----------------------
*           For his Timer32 library
*
*       Nesthaurus
*       -----------------------
*           For his Dummy library
*
************************************************************************************
*   
*   Installation:
*       - Import the DUMMY.mdx model to your map
*       - Copy the DummySfx unit from the object editor to your map and change the model to DUMMY.mdx
*       - Copy ALL the Required Libraries and MissileCollicion folder to your map (except the DEMO)
*       - Change the DUMMY_ID of the Dummy library to your imported DummySfx
*
************************************************************************************
*
*   API:
*       struct MC      
*           static method create takes player owningPlayer, real xWhere, real yWhere, string missileModel returns thistype
*               - owningPlayer is the owner of the missile
*               - xWhere and yWhere is the coordinate where the missile's origin or launched
*
*           method setupCollision takes real aoe, real collision, string collisionEffect returns nothing
*               - aoe is the area of effect damage when missile explodes
*               - collision, missile will explode and deals damage if it collides with the first enemy unit in range
*               - collisionEffect, the effect or eye candy of the explosion
*
*           method setupDamage takes real damage, attacktype attackType, damagetype damageType returns nothing
*               - damage, the damage when missile explodes
*               - attackType and damageType is self explanatory
*
*           method launch takes real facingInRadiants, real distance, real height, real speed returns nothing
*               - facingInRadiants is the angle where the missile goes
*               - distance is how far the missile traver
*               - height and speed is the height of the missile and speed travel of the missile respectively
*
*
************************************************************************************
*/

private struct Delay
    unit missile
    real del
    Dummy remove
endstruct

struct MC
    private unit missile
    private real aoeDamage
    private real collision
    private real distance
    private real damage 
    private real height
    private real speed
    private real cos
    private real sin
    private string collisionEffect
    private effect missileModel
    private player pl
    private attacktype atk
    private damagetype dmg
    private Dummy remove

    private static group g = CreateGroup()
    
    /*
    *
    *   This block is used to delay the dummy to be recycled so that the effects will be
    *   visible from their origin attachment
    *
    */
    private static timer t = CreateTimer()
    private static integer index = 0
    private static integer array indexAR
    
    private static method looper takes nothing returns nothing
        local Delay this
        local integer i = 0
        loop
            set i = i+1
            set this = indexAR[i]
            set this.del = this.del - 0.03125
            if 0 > this.del then
                call this.remove.destroy()
                set this.missile = null
                call this.destroy()
                set indexAR[i] = indexAR[index]
                set i = i - 1
                set index = index - 1    
                if index==0 then
                    call PauseTimer(t)
                endif
            endif          
            exitwhen i==index
        endloop
    endmethod
    
    private method delay takes nothing returns nothing returns nothing
        local Delay m = Delay.create()
        set m.missile = .missile
        set m.del = 2.0
        set m.remove = .remove
        if index==0 then
            call TimerStart(t, 0.03125, true, function thistype.looper)
        endif
        set index = index + 1
        set indexAR[index] = m
    endmethod
    
    /*
    *
    *   End of Delay block
    *
    */
    
    private method stop takes nothing returns nothing
        call .delay()
        call DestroyEffect(.missileModel)
        set .missile = null
        set .missileModel = null        
        call .stopPeriodic()
        call .deallocate()    
    endmethod  
    
    private method damageThem takes real x, real y returns nothing
        local unit first
        if .collisionEffect!="" then
            call DestroyEffect(AddSpecialEffectTarget(.collisionEffect, .missile, "origin"))  
        endif
        call GroupEnumUnitsInRange(g, x, y, .aoeDamage, null)
        loop
            set first = FirstOfGroup(g) 
            exitwhen first==null
            if not IsUnitType(first, UNIT_TYPE_DEAD) and IsUnitEnemy(first, .pl) then
                if .atk==null or .dmg==null then
                    call UnitDamageTarget(.missile, first, .damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
                else
                    call UnitDamageTarget(.missile, first, .damage, false, false, .atk, .dmg, null)
                endif
            endif
            call GroupRemoveUnit(g, first)
        endloop
        call .stop()
    endmethod
    
    private method periodic takes nothing returns nothing
        local unit first
        local real xMissile = GetUnitX(.missile)
        local real yMissile = GetUnitY(.missile)
        if .distance > 0 then
            set .distance = .distance - .speed
            call SetUnitX(.missile, xMissile + .cos)
            call SetUnitY(.missile, yMissile + .sin)
            call GroupEnumUnitsInRange(g, xMissile, yMissile, .collision, null)
            loop
                set first = FirstOfGroup(g) 
                exitwhen first==null
                if not IsUnitType(first, UNIT_TYPE_DEAD) and IsUnitEnemy(first, .pl) then
                    call .damageThem(xMissile, yMissile)
                    exitwhen true                
                endif
                call GroupRemoveUnit(g, first)
            endloop  
        else
            call .damageThem(xMissile, yMissile)
        endif
    endmethod
    
    implement T32x
    
    /*
    *
    *   API:
    *
    */  
    
    static method create takes player owningPlayer, real xWhere, real yWhere, string missileModel returns thistype
        local thistype this = allocate()
        local Dummy d = Dummy.create(xWhere, yWhere, 0)   
        set .missile = d.unit
        set .missileModel = AddSpecialEffectTarget(missileModel, .missile, "origin")
        set .pl = owningPlayer
        set .collisionEffect = ""
        set .remove = d
        if UnitAddAbility(.missile, 'Aloc') then
        endif
        return this
    endmethod
    
    method setupCollision takes real aoe, real collision, string collisionEffect returns nothing
        set .aoeDamage = aoe
        set .collision = collision
        set .collisionEffect = collisionEffect 
    endmethod
    
    method setupDamage takes real damage, attacktype attackType, damagetype damageType returns nothing
        set .damage = damage
        set .atk = attackType
        set .dmg = damageType
    endmethod
    
    method launch takes real facingInRadiants, real distance, real height, real speed returns nothing
        set .distance = distance
        set .height = height
        set .speed = speed
        set .cos = speed * Cos(facingInRadiants)
        set .sin = speed * Sin(facingInRadiants)
        call SetUnitFlyHeight(.missile, height, 0)
        call SetUnitFacing(.missile, facingInRadiants*bj_RADTODEG)
        call .startPeriodic()
    endmethod
endstruct

endlibrary

- Import the DUMMY.mdx model to your map
- Copy the DummySfx unit from the object editor to your map and change the model to DUMMY.mdx
- Copy ALL the Required Libraries and MissileCollicion folder to your map (except the DEMO)
- Change the DUMMY_ID of the Dummy library to your imported DummySfx

  • MC Demo
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • Custom script: local MC m
      • Custom script: set m = m.create(Player(0), GetUnitX(udg_Hero), GetUnitY(udg_Hero), "Abilities\\Weapons\\PoisonArrow\\PoisonArrowMissile.mdl")
      • Custom script: call m.setupCollision(300, 80, "Objects\\Spawnmodels\\Human\\FragmentationShards\\FragBoomSpawn.mdl")
      • Custom script: call m.setupDamage(100, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL)
      • Custom script: call m.launch(GetUnitFacing(udg_Hero)*bj_DEGTORAD, 800, 75, 5)
JASS:
scope MCInsaneTest

globals
    private string array missileSfx
    private string array sfxExplode  
endglobals  
    
struct MCD
    
    static method insaneTest takes nothing returns nothing
        local MC m = MC.create(Player(0), 0, 0, missileSfx[GetRandomInt(1,4)])
        /*
        *   The locals is really not needed, I only put it here to see what are those numbers for
        */
        local real angle = GetRandomReal(1, 6.2)
        local real aoe = GetRandomReal(150, 200)
        local real collision = GetRandomReal(80, 100)
        local real damage = GetRandomReal(50, 150)
        local real distance = GetRandomReal(500, 800)
        local real height = GetRandomReal(75, 150)
        local real speed = GetRandomReal(2, 10)
        local integer randomSfx = GetRandomInt(1, 5)
        call m.setupCollision(aoe, collision, sfxExplode[GetRandomInt(1,5)])
        if GetRandomInt(1, 2)==1 then
            call m.setupDamage(damage, null, null)
        else
            call m.setupDamage(damage, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_COLD)
        endif
        call m.launch(angle, distance, height, speed)
    endmethod
    
    static method onInit takes nothing returns nothing
        set missileSfx[1] = "Abilities\\Weapons\\PoisonArrow\\PoisonArrowMissile.mdl"
        set missileSfx[2] = "Abilities\\Weapons\\CannonTowerMissile\\CannonTowerMissile.mdl"
        set missileSfx[3] = "Abilities\\Weapons\\WingedSerpentMissile\\WingedSerpentMissile.mdl"
        set missileSfx[4] = "Abilities\\Weapons\\DemonHunterMissile\\DemonHunterMissile.mdl"
        set sfxExplode[1] = "Objects\\Spawnmodels\\Human\\FragmentationShards\\FragBoomSpawn.mdl"
        set sfxExplode[2] = "Objects\\Spawnmodels\\NightElf\\EntBirthTarget\\EntBirthTarget.mdl"
        set sfxExplode[3] = "UI\\Feedback\\GoldCredit\\GoldCredit.mdl"
        set sfxExplode[4] = "Objects\\Spawnmodels\\NightElf\\NEDeathMedium\\NEDeath.mdl"
        set sfxExplode[5] = "Objects\\Spawnmodels\\Undead\\UDeathSmall\\UDeathSmall.mdl" 
        call TimerStart(CreateTimer(), 0.1, true, function MCD.insaneTest)
    endmethod
endstruct

endscope
JASS:
scope MCExecutionMode

globals
    private real array y
endglobals  
    
struct MCDE
    
    static method insaneTest takes nothing returns nothing
        local MC m = MC.create(Player(0), -550, y[GetRandomInt(0,5)], "Abilities\\Weapons\\CannonTowerMissile\\CannonTowerMissile.mdl")
        /*
        *   The locals is really not needed, I only put it here to see what are those numbers for
        */
        local real angle = 180*bj_DEGTORAD
        local real aoe = 150
        local real collision = 80
        local real damage = 75
        local real distance = 1200
        local real height = 30
        local real speed = GetRandomReal(2, 10)
        call m.setupCollision(aoe, collision, "Objects\\Spawnmodels\\Undead\\UDeathSmall\\UDeathSmall.mdl")
        call m.setupDamage(damage, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_COLD)
        call m.launch(angle, distance, height, speed)
    endmethod
    
    static method onInit takes nothing returns nothing        
        set y[0] = -790
        set y[1] = -520
        set y[2] = -260
        set y[3] = -8
        set y[4] = 260
        set y[5] = 520       
        call TimerStart(CreateTimer(), 0.1, true, function MCDE.insaneTest)
    endmethod
endstruct

endscope

Vexorian for DUMMY.mdx model
Jesus4Lyf for Timer32
Nesthaurus for Dummy
Adiktuz tips in thsi thread

v1.1
- Effects can now be seen at location Z
- API changed

-



Keywords:
missile, system, collision, enemy, dummy, effect, dota, mckill2009
Contents

MissileCollision (Map)

Reviews
12th Dec 2015 IcemanBo: Too long as NeedsFix. Rejected. 13:21, 17th Aug 2013 Maker: The z-offset of the missiles when created varies based on terrain height

Moderator

M

Moderator

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

13:21, 17th Aug 2013
Maker: The z-offset of the missiles when created varies based on terrain height
 
JASS:
if UnitAddAbility(.missile, 'Arav') then        
endif        
if UnitAddAbility(.missile, 'Aloc') then
endif

Why use if, when you don't have anything inside? The only way I saw them used was when you have a UnitRemoveAbility inside the if-then part

JASS:
if UnitAddAbility(.missile, 'Arav') then      
    call UnitRemoveAbility(.missile, 'Arav') //So that you only remove it, if it was added by the script
endif

I also fail to see the point of this next lines... why not just always run it on the "origin" point?

JASS:
if GetUnitFlyHeight(.missile) > 100 then
    call DestroyEffect(AddSpecialEffectTarget(.sfx, .missile, "origin"))
else
    call DestroyEffect(AddSpecialEffect(.sfx, GetUnitX(.missile), GetUnitY(.missile)))
endif

btw, what does this system do that cannot be done using the several missile systems out there? coz I don't see why we would need more of these missile systems... there are already several out there (both in GUI and JASS/vJASS)...
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Missing some descriptions

JASS:
*           static method create takes player owningPlayer, real xWhere, real yWhere, string missileModel, string attachToWhere returns thistype
*           method operator []= takes real collision, string collisionEffect returns nothing
*           method setupDamage takes real damage, attacktype attackType, damagetype damageType returns nothing
*           method launch takes real facingInRadiants, real distance, real height, real speed returns nothing

dunno what setupDamage and that operator do
 
Even missing a nice "How to Use" instructions... All that the Instructions say is about setting up the system but not on how to use it...

Seeing how simple this looks, I guess its meant for simple users which normally need step by step instructions...

Especially for things like that []= operator... because if I was a normal user that don't understand JASS, what I will think about it is that the number that I put inside the [] is the index of the missile...

If you ask me, that operator is really misleading since we usually use [] for denoting indexes... why not set it up like you did with setupDamage?

btw, what happens if I use .launch on a currently launched missile?
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
1) Why use if, when you don't have anything inside? The only way I saw them used was when you have a UnitRemoveAbility inside the if-then part

2) I also fail to see the point of this next lines... why not just always run it on the "origin" point?

3) btw, what does this system do that cannot be done using the several missile systems out there? coz I don't see why we would need more of these missile systems... there are already several out there (both in GUI and JASS/vJASS)...

1) I learned that from Maker's system, makes sense since you dont need to remove and add the ability all the time, in any case, I think it's best to just add the ability in the object editor for permanent use...

2) Some of my test before fails to 'see' the effects on some units using attachment point like origin, that's why I did that...

3) Other systems do not support recycling missiles, they 'create' everytime and doesnt use first hit collisions...

There's no how to use coz the trigger sample IMO is enough on 'how to use this', I usually give GUI sample so that all systems I made can be accesses through GUI, unlike other systems I know which is very difficult to implement by GUI'ers...

btw, what happens if I use .launch on a currently launched missile?
the T32 start is inside that, so it will reset the parameters or worst cause an error...

I may remove the operator and replace it by methods and add more descriptions...
 
2) it will only fail if the unit has no origin... + I don't see how that will solve the problem since it seems to be linked to unit/model while ur solution is using height as a check... not to mention that ur using only one unit for the base model (the dummy)

It's still nice to put a complete instructions, or comment out your GUI examples...

Yeah replace that operator...

by recycling you mean because it uses the Dummy script?
 
1) You still didn't explain why you have it inside the if-then though... You don't need to determine whether the ability is added or not anyway because there's no action inside the then clause... meaning a simple UnitAddAbility without the if-then clause will suffice...

JASS:
if UnitAddAbility(.missile, 'Arav') then  
    //Useless since this part is blank anyway      
endif     

if UnitAddAbility(.missile, 'Arav') then  
    call UnitRemoveAbility(.missile, 'Arav')
    //Now the if check has a use
endif  

/*

Conclusion? Well, since you don't need to know if ability is added or not, just remove the check

*/

btw, the way you used a first hit collision can also be a flaw, because right now, each missile will only always hit 1 unit on the way it is set-up (it stops once a unit is already damaged)... So it kinda limits it's use...

An option for hitting all enemies around the area is a nice add-on IMO...

PS: You should just make the attachment point as a non-parameter... I don't see why the user will need to use a non-origin point for the missile anyway...
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
it stops once a unit is already damaged
That's why I put the name collision...first time hit, stops...

1) An option for hitting all enemies around the area is a nice add-on IMO...

2) BTW, most users will probably want support for missile arcs... :)

3) PS: You should just make the attachment point as a non-parameter... I don't see why the user will need to use a non-origin point for the missile anyway...
1) An option of hitting an ally unit is another option Im thinking...and it already hits all enemy units but depends on collision size...if Ima add that option, another parameter should be created...

2) No plan for that atm, but all suggestions are welcome...

3) Makes sense, so yeah why not?...

EDIT:
or just make the collision global and AOE for the parameter...

EDIT 2:
Ima change many things once I got home from work XD...
 
and it already hits all enemy units but depends on collision size

1) How will it hit all enemies when you call the .stop method and exit the group loop when you already hit 1 unit?

JASS:
//These two lines effectively stop the missile processing
//upon hitting a unit, so it will always only hit a single unit
call .stop()
exitwhen true

on your edit: no, don't make the collision global...
 
I should have recoded Particle.
Well anyways, nice job!

Okay how about this for auto-flyer:
JASS:
if UnitAddAbility(myUnit, 'Amrf') and UnitRemoveAbility(myUnit, 'Amrf') then
endif

Also, I don't think you need to apply an AutoFlyer, Dummy currently has two, here:
JASS:
static method pop takes thistype this, real x, real y, real facing returns integer
            /*
            *   Retrieve queue and first dummy on queue given angle
            */
            local unit dummyUnit                //dummy unit
            local thistype dummyIndex = next    //dummy index
            local integer unitIndex             //unit idex
            
            local thistype this2
            local thistype node

            local real stamp
            
            /*
            *   If the queue is empty, return new dummy
            */
            if (0 == dummyIndex or dummyIndex.stamp > TimerGetElapsed(stampTimer)) then
                /*
                *   Allocate new dummy
                */
                debug if (dummyCount == 8191) then
                    debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"DUMMY RECYCLER FATAL ERROR: DUMMY OVERLOAD")
                    debug set Dummy.enabled = false
                    debug set this = 1/0
                debug endif
                
                set dummyIndex = dummyCount + 1
                set dummyCount = dummyIndex
                
                /*
                *   Create and initialize new unit handle
                */
                set dummyUnit = CreateUnit(DUMMY_OWNER, DUMMY_ID, x, y, facing)
                set unitIndex = GetUnitUserData(dummyUnit)
                set indexPointer[dummyIndex] = unitIndex
                set dummyPointer[unitIndex] = dummyIndex
                
                set dummies[unitIndex] = dummyUnit
                call UnitAddAbility(dummyUnit, 'Amrf')
                call UnitRemoveAbility(dummyUnit, 'Amrf')
                call PauseUnit(dummyUnit, true)
                
                return dummyIndex
            endif
            
            /*
            *   Remove the dummy from the queue
            */
            set next = dummyIndex.next
            if (0 == next) then
                set last = this
            endif
            
            /*
            *   Only remove from the count if the queue has most dummies in it
            *
            *   If queue doesn't have most dummies in it, take a dummy from the queue
            *   with most dummies in it and keep count the same
            */
            if (count == ArrayStack.max) then
                set count = count - 1
            else
                /*
                *   Retrieve the queue with most dummies in it as well as the
                *   first dummy in that queue
                */
                set this2 = max
                set node = this2.next
                
                /*
                *   Remove first dummy from largest queue
                */
                if (0 == node.next) then
                    set this2.last = this2
                else
                    set this2.next = node.next
                endif
                
                set this2.count = this2.count - 1
                
                /*
                *   Add first dummy to current queue
                */
                set last.next = node
                set last = node
                set node.next = 0
                
                /*
                *   Match unit angle with queue
                */
                call SetUnitFacing(dummies[indexPointer[node]], this - 1)
                
                /*
                *   .73 seconds is how long it takes for a dummy to rotate 180 degrees
                *
                *   Credits to Bribe for these 4 lines of code and the .73 value
                */
                set stamp = TimerGetElapsed(stampTimer) + .73
                if (stamp > node.stamp) then
                    set node.stamp = stamp
                endif
            endif
            
            /*
            *   Move dummy to target position
            */
            set dummyUnit = dummies[indexPointer[dummyIndex]]
            call SetUnitX(dummyUnit, x)
            call SetUnitY(dummyUnit, y)
            call SetUnitFacing(dummyUnit, facing)
            set dummyUnit = null
            
            /*
            *   Return first dummy from current queue
            */
            return dummyIndex
        endmethod

And here:
JASS:
private function Initialize takes nothing returns nothing
        local unit dummy
        local integer last
        local integer angle
        local ArrayStack queue
        local integer count
        
        /*
        *   This timer 
        */
        set stampTimer = CreateTimer()
        call TimerStart(stampTimer, 604800, false, null)
        
        /*
        *   The highest possible angle
        */
        set last = 360/ANGLE_SPACING*ANGLE_SPACING
        if (360 == last) then
            set last = last - ANGLE_SPACING
            if (last < ANGLE_SPACING) then
                set last = 0
            endif
        endif
        
        /*
        *   The lowest possible angle
        */
        set angle = 0
        
        /*
        *   Start dummy count at the last possible angle so that
        *   angles don't overlap with dummy indexes. This is done
        *   to simplify queue algorithm and improve overall performance.
        *   At most 360 possible dummy unit indexes will be lost due to this.
        */
        set dummyCount = last + 1
        
        /*
        *   Initialize ArrayStack
        */
        set ArrayStack.min = PRELOAD_PROJECTILES_PER_ANGLE
        set ArrayStack.max = PRELOAD_PROJECTILES_PER_ANGLE
        set ArrayStack(PRELOAD_PROJECTILES_PER_ANGLE).first = 1
        
        loop
            /*
            *   queue pointer is angle + 1
            */
            set queue = angle + 1
            
            /*
            *   Only add projectiles to queue if MAX_PROJECTILES < 0
            */
            if (0 < PRELOAD_PROJECTILES_PER_ANGLE) then
                set count = PRELOAD_PROJECTILES_PER_ANGLE
                set queue.count_p = PRELOAD_PROJECTILES_PER_ANGLE
                
                set dummyCount = dummyCount + 1
                set Queue(queue).next = dummyCount
                
                /*
                *   Create and add all dummies to queue
                */
                loop
                    /*
                    *   Create and initialize unit handle
                    */
                    set dummy = CreateUnit(DUMMY_OWNER, DUMMY_ID, 0, 0, angle)
                    set indexPointer[dummyCount] = GetUnitUserData(dummy)
                    set dummyPointer[GetUnitUserData(dummy)] = dummyCount
                    set dummies[indexPointer[dummyCount]] = dummy
                    
                    call UnitAddAbility(dummy, 'Amrf')
                    call UnitRemoveAbility(dummy, 'Amrf')
                    call PauseUnit(dummy, true)
                    
                    set count = count - 1
                    exitwhen 0 == count
                    
                    /*
                    *   Point to next
                    */
                    set dummyCount.next = dummyCount + 1
                    set dummyCount = dummyCount + 1
                endloop
                
                set Queue(queue).last = dummyCount
            else
                set Queue(queue).last = queue
            endif
            
            exitwhen last == angle
            
            /*
            *   Go to next angle
            */
            set angle = angle + ANGLE_SPACING
            
            /*
            *   Link queues together
            */
            set queue.next = angle + 1
            set ArrayStack(angle + 1).prev = queue
            
            /*
            *   Go to next queue
            */
            set queue = angle + 1
        endloop
        
        set dummy = null
        
        debug set Dummy.enabled = true
    endfunction

Also, "MC" is a bad struct name :V
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
1) Why are dying objects moved to ground level?
2) The projectiles spawn at different height offset above the hero, depending on terrain height
3) You could recycle the dummies based on their facing

1) There's no dying object but dying effects, origin attachments doesnt work like Adiktuz said...I know how to do the destructableZ trick but I dont want to spam destructabe ID's a lot...

2) Coz I put random heights...

3) Possible but I dont think that's gonna help coz the dummies will still turn once a different facing is set...
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
I wonder why you origin attachment doesn't work... It should work since ur using dummy.mdx
coz of this >>> call SetUnitPosition(dummies[this], 2147483647, 2147483647), that's the main reason why I made a delay struct

Don't put random heights... better yet, allow the user to specify Z offset
it's just in the test, not inside system itself...

and yeah, change the struct name... acronyms are not really a good idea...
ummm, nothing wrong with it so no...

I may add also configurable size and color of the missile (if color is possile)...
 
Level 3
Joined
Jun 13, 2010
Messages
43
MissileCollision . i thought it is a system that support collision between missiles. Try integrate it to your system? otherwise its features not much of a outstanding system compare to those we had now
 
Top