Relativistic Missiles [vJASS][LUA]

This bundle is marked as approved. It works and satisfies the submission rules.
Relativistic Missiles
v1.9 by Chopinski
Introduction
First of all, Credits and thanks to BPower, Dirac, and Vexorian for their missile systems at which I based this system upon, and to AGD for the help with effect orientation methods.

This is a Missile system that I put together initially to fulfill my resources needs. Very often while I was creating system, spells and maps I found myself in need of a such systems, but all the available options usually have a little flaw that forced me to used something else.

For example, let's say I wanted a missile that can arc and homing to a target, well there goes BPower's system. It can arc/curve but can't do homing with arc/curve natively. So the options left are Vexorian xemissile which can arc and do homing but cant curve, and Dirac's Missile system. Then again more problems with those, because Vexorian system do not have a lot of the useful events like Dirac's and BPower's systems. Dirac's system can arc/curve and do homing but it's T32 timer is never stopped and it do not have some useful events that the BPower system has. So I decided to get all three system together and build my own system with the stuff I think is useful and with the syntax I think is the most friendly, because I'm not a genius of vJASS myself.

What's different in this system? (read if you dare, muahhaaa)
Ok, so why it's called "Relativistic Missiles"? Well because mid development I realize that the way missiles were being processed could be optimized and the Einstein postulates about Time Dilation by Gravity gave the idea behind the implementation. Yeah, I know, WTH?

When it comes to Missile systems, performance is everything, and all missiles systems do basically the same thing when processing missiles instances, they loop every set period, which is usually 1/32, through all instances and do their calculations and event calls. The problem with it, is that the more instances existing at a given moment the greater will be the tanking of the game frame rate because the game will lower its fps so all that's need to be done before the next frame gets drawn have time to do so, and that's where the Einstein postulates gave me an idea.

See, when we study Relativity, we learn that gravity dilates time, the greater the gravitational potential (more or less mass) the slower time passes relative to an outside point of reference. Gravity in this analogy would be the amount of missiles instances currently existing, so instead of letting the game frame rate drops drastically to move all those instances, I make the missile instances have their time dilated.

Ok, but how?? Simple, first we need to find what I'll be calling the system Sweet Spot, which is the amount of missiles the game can handle without dropping to much performance per given period, which I found out to be between 150 and 200 missiles. Then we limit the amount of missiles processed per period to this sweet spot, and move the next missile in the line to be processed and all other behind it to the front, In terms of data structures, think of a circular list with a head and tail, and we move the head and tail to change the initial and final positions. I did it with arrays because they are a bit faster and because I'm lazy :p.

But that's not all, because by limiting the amount of missiles processed, we delay their next process call by (total amount)/(sweet spot), so now their speed needs to be corrected and relativity comes full circle now, because time dilation has it's relation with Length Contraction, so we increment the missiles speed by this factor.

Also, something very important is that this system is using only effects as missiles, thanks to the new natives introduced in 1.31, so no dummy units, no CreateUnit() and SetUnitFacing() blasphemy. I've included in the test map a version of this system that do use the dummy method for those that do not have the newer versions of the game. I Also included a version of this system that uses the usual process method, so processing all missiles in a single blow.

Results
I've taken the liberty to test this system against the king of Missile systems for some time, BPower's System. Below, there are 3 videos I make for stress test. The first from the left is BPower's Missile System reworked by AGD. Amazing job btw. You will be able to notice what I was talking about earlier about the sweet spot, when there are more than 150 or so missiles being processed, the fps goes basically to 0 and it freezes until the missiles are finished.

The video in the middle is my system in its normal version (not relativistic). It performs a little better (I've build it a little differently), but in the same way, when the missile count near 250, the fps starts to go down hill real quick.

The video in the right is the relativistic version, notice the missile count and fps compared to the 2 other system. At about 600 missiles fps get really low, but not so much because of the amount of missiles being processed but because of the amount of visual effects in the screen. If the screen was moved to the side where not so many stuff is visible, fps goes up. In my internal tests I was reaching more than 1200 missiles with about 16 fps but with no screen freezes.

And Last but not Least, a video with the examples.

vJASS:
event onHit takes unit hit returns boolean
    -> if declared and collision is greater than 0
    -> will run whenever the missile collides with a unit

event onMissile takes Missiles missile returns boolean
    -> if declared and collision is greater than 0
    -> will run whenever the missile collides with another missile

event onItem takes item i returns boolean
    -> if declared and collision is greater than 0
    -> will run whenever the missile collides with an item

event onDestructable takes destructable dest returns boolean
    -> if declared and collision is greater than 0
    -> will run whenever the missile collides with a destructable

event onTerrain takes nothing returns boolean
    -> if declared, will run whenever the missile collides with terrain

event onFinish takes nothing returns boolean
    -> if declared, will run when the missiles reaches its destination

event onBoundaries takes nothing returns boolean
    -> if declared, will run whenever the missile tries to go out
    -> of the map boundaries.

event onRemove takes nothing returns nothing
    -> if declared, will run when the missile is removed
vJASS:
(readonly)x             -> The current x coordinate of the missile
(readonly)y             -> The current y coordinate of the missile
(readonly)z             -> The current z coordinate of the missile
(readonly)prevX         -> The previous x coordinate of the missile
(readonly)prevY         -> The previous y coordinate of the missile
(readonly)prevZ         -> The previous z coordinate of the missile
(readonly)travel        -> The current traveled distance of the missile
(optional)source        -> The source unit for the missile
(optional)target        -> The target unit for the missile. If set the missile will be roaming
(optional)owner         -> The owning player of the missile
(optional)collideZ      -> If true, the missile will take into consideration the unit collision size, destructable oclusion height and item size when running the onHit, onDestructable, onItem events
(optional)collision     -> The collision size of the missile. If not set, the events onHit, onDestructable, onItem and onMissile will no run
(optional)damage        -> Stores the amount of damage to be used inside an event
(optional)acceleration  -> The missile acceleration
(optional)data          -> Stores information to be used inside any event
(optional)model         -> The model of the missile
(optional)curve         -> The curve of the missile
(optional)arc           -> The Arc of the missile
(optional)scale         -> The scale of the missile
(optional)speed         -> The speed of the missile
(optional)duration      -> Set the speed of the missile to match a duration
impact                  -> The object representing the impact coordinates (x, y, z, angle, distance, square, slope, alpha)
origin                  -> The object representing the origin coordinates (x, y, z, angle, distance, square, slope, alpha)
effect                  -> The object representing the missile (size, yaw, pitch, roll, path, effect, attachments), and attachments has (x, y, z, size, yaw, pitch, roll, path, effect)
vJASS:
method bounce takes nothing returns nothing
    -> Bounces the missile, reseting angles

method deflect takes real x, real y returns nothing
    -> Deflects the missile to the x and y coordinates

method deflectZ takes real x, real y, real z returns nothing
    -> Deflects the missile to the x, y and z coordinates

method flushAll takes nothing returns nothing
    -> Flushes the hit group for the missile

method flush takes widget w returns nothing
    -> Remove a unit, destructable, item or missile from the hit group

method hitted takes widget w returns boolean
    -> Returns true if the unit, destructable or item was hit by the missile

method attach takes string model, real dx, real dy, real dz, real scale returns effect
    -> Attach an effect to the missile and return the effect attached
    -> dx, dy, and dz are offsets from the main missile coordinates

method detach takes effect attachment returns nothing
    -> Detach an effect attached to the missile

  • BPower
  • Dirac
  • Vexorian
  • AGD
  • emjlr3
  • AceHart
  • Nestharus
  • Maghteridon96
  • Bribe
  • Flux
  • Forsakn

(v1.0)
  • Release
(v1.1)
  • Merged Normal and Relativistic code for both Legacy and Current versions.
  • You can use the SWEET_SPOT constant to determine the system behavior
    • SWEET_SPOT <= 0 -> normal method
    • SWEET_SPOT > 0 -> relativistic method
  • Included support for DummyRecycler by Flux for the Legacy version. This should improve its performance even further.
(v1.2)
  • Fixed a bug for homing missiles height
  • New configuration member boolean collideZ -> set to true to make the new missile consider z collisions
  • New Global Configuration constant boolean ROLL -> If true missile will consider roll in orientation. Roll can look really fishy for some users and was never possible until patch 1.31, so if you want it set it to true in the globlas block (1.31+ version only).
  • You can now attach effects to the main missile effect with an offset through 2 new methods (1.31+ version only)
    • // dx, dy, and dz are offsets from the main missile coordinates
      method attach takes string model, real dx, real dy, real dz, real scale returns effect
    • method detach takes effect attachment returns nothing
  • Few minor optmizations.
(v1.3)
  • Fix a minor rect leak
(v1.4)
  • Minor optmizations.
  • WorldBounds not required anymore.
(v1.5)
  • WorldBounds now is required (Centralized requirements and outsourced)
  • New optional event (See Available Events for more info)
    • method onBoundaries takes nothing returns boolean
  • Fixed a spelling mistake on the detach functionality.
(v1.6)
  • MissileEffect library updated to use the BlzSetSpecialEffectOrientation native. (v1.31+ only)
(v1.7)
  • Standardized getting and setting of the members speed, arc and curve. They now read and write in degrees.
(v1.8)
  • Made a system function (GetLocZ) private to avoid conflict with other resources.
(v1.9)
  • System ported to LUA (Credits to Forsakn for the first port).
  • Added instant facing when creating missiles instances.
  • Included a version of Missiles that uses the dummy method and a Dummy Pool utilizing the new natives. This version by default will not let missiles clip through terrain.
  • Code formatting and cleaning.
Contents

Missiles (Map)

Missiles (Map)

Level 17
Joined
Aug 13, 2013
Messages
1,680
So instance-processing gets different on a relativistic version by also changing
missile velocities to compensate when a certain instance peaks the maximum.
Perhaps, one of the clever ways to gain performance and it's naked to the eye.

While you nailed the performance, can you use the sweet spot value of 0 to
merge the two libraries? Although it may just cause extra checks for this lol.
(Which I think you'll probably not consider it)

Also, you may incorporate our unit recyclers here for the legacy variant.
(I can only recommend Flux's DummyRecycler or Bribe's MissileRecycler)
I think just make it a requirement rather than optional if you implement.

I'll make some further suggestions and recommendations soon after testings. ;)
 
Level 11
Joined
May 16, 2012
Messages
517
You sir make me want to learn JASS.

Do it man, srly. Not because JASS is a great language, cuz it ain't, but for the sheer fun it is to mess around in Warcraft. 8 months ago I started in GUI and now, even doing College and Work I'm doing vJass. Also, vJass has the most sweet syntax in my opinion, its just good to read it.

So instance-processing gets different on a relativistic version by also changing
missile velocities to compensate when a certain instance peaks the maximum.
Perhaps, one of the clever ways to gain performance and it's naked to the eye.

Cool right. Oh i forgot, Big credits to Albert Einstein!!

While you nailed the performance, can you use the sweet spot value of 0 to
merge the two libraries? Although it may just cause extra checks for this lol.
(Which I think you'll probably not consider it)

Unfortunately no because SWEET_SPOT is in the condition to exit the loop as well, and if its 0 no instances are processed because it exits immediately.

Also, you may incorporate our unit recyclers here for the legacy variant.
(I can only recommend Flux's DummyRecycler or Bribe's MissileRecycler)
I think just make it a requirement rather than optional if you implement.

Initially I was using MissileRecycler by Bribe but I found out during the development of Mannoroth Hero Concept that it's leaking dummys, and they are never destroyed for some reason when the system call for UnitAddTimedLife(), which for a missile system is a nono. Dont know if it is because of Reforged. I will try DummyRecycler, because indeed, a unit recycler for the legacy can do wonders.

I'll make some further suggestions and recommendations soon after testings.

I'll do what i can to make this system as complete as possible to everyone.
 
Level 17
Joined
Aug 13, 2013
Messages
1,680
Unfortunately no because SWEET_SPOT is in the condition to exit the loop as well, and if its 0 no instances are processed because it exits immediately.
I mean if it's configured zeroed by the user. It just means to disable the instance-processing you made and just use the normal instead.
In this way, you can merge the two variant in one library for convenience. (or even one library at all by the use of one flag and static if)
But it's up to your preference as it only matters to my case. (where I'll be forced to mix the two libraries in my demo-maps)
I will try DummyRecycler, because indeed, a unit recycler for the legacy can do wonders.
I'm excited to try it out, I think I'll just wait for a DummyRecycler to be implemented first before using it.
 
Level 11
Joined
May 16, 2012
Messages
517
I mean if it's configured zeroed by the user. It just means to disable the instance-processing you made and just use the normal instead.
In this way, you can merge the two variant in one library for convenience. (or even one library at all by the use of one flag and static if)
But it's up to your preference as it only matters to my case. (where I'll be forced to mix the two libraries in my demo-maps)

I'm excited to try it out, I think I'll just wait for a DummyRecycler to be implemented first before using it.

Oh, got it, will do. Will release a version with the recycler by tomorrow or today very late, bot soon.
 
Level 17
Joined
Aug 13, 2013
Messages
1,680
Alright, I'll be waiting.

Besides, @AGD could be notified by this. He may borrow this kind of implementation if he sees no flaw of it.
His coding-efforts were also remarkable with the new reworked Missile system. Although, I'll prefer this as it
have an updated legacy support which is a big deal for me. Otherwise, both of the submissions are worth it.
 
Level 11
Joined
May 16, 2012
Messages
517
Alright, I'll be waiting.

Besides, @AGD could be notified by this. He may borrow this kind of implementation if he sees no flaw of it.
His coding-efforts were also remarkable with the new reworked Missile system. Although, I'll prefer this as it
have an updated legacy support which is a big deal for me. Otherwise, both of the submissions are worth it.

Yeah, @AGD is an absolute genius, he's a much better programmer than me and maybe be able to improve it even further.

Such performance, much wow.

And, this was done in vJASS, imagine the performance gain if this was written in Lua as well.

If only I knew it ahha, one day for sure. But feel free to convert it people, don't wait for the mountain.
 

AGD

AGD

Level 13
Joined
Mar 29, 2016
Messages
677
This is a nice trick imo. So with this, you can essentially cap the operations being done per period to a certain amount, regardless of the number of Missiles you have in the map. The results, atleast according to your benchmarks showed a huge gap in performance. Good job.

Even though this is done in exchange of some precision, I think it's still a good trade-off (Also considering that this feature can also be turned off). It's just a matter of finding the right 'sweet spot' to balance the performance and precision depending on your map.

But y'know I personally prefer BPower's handling of callback methods using modules instead of using interfaces like this one. This literally creates a duplicate of each of your callback methods, plus other extra stuff (again, for each callback) neccessary for polymorphism. Using modules like BPower's atleast gives you better control of the code that would be generated in the implementing struct and you can therefore make it very minimal. But I understand that not everyone cares about this and prefers the more straightforward OOP API, so you don't need to change yours.

Nevertheless, it's amazing to see the amount of missiles you can have simultaneously using this technique. I would like to borrow this ;D (if you'd agree) for BPower's Missile update and see if the technique can still be improved (Had no idea yet right now).

You too are free to take what you can from BPower's updated library. I can see yours doesn't factor in elevation for collision yet, as well as the collision size of units/destructables/items but only Missile collision size. This also doesn't have a roll incorporated for the special effects yet. Or if you just prefer to make this as lite as possible - your call.
 
Level 17
Joined
Aug 13, 2013
Messages
1,680
Can you also consider providing multiple effects handling per missile. I think this feature shouldn't be missed too.

EDIT:

Adapting missile speed for the relativistiy system might compensate the travelling that happened during the not-processing, but doesn't an important feature get lost - the events that would have happened on collision?
Yes, sacrificing a bit of precision to gain performance. :D
However, it's not visible (lots of iterations per second) and only happens if it reaches the threshold for the
system to consider this 'not-processing' the missiles in a whole. (good thing it's configurable for this sake)
I can see yours doesn't factor in elevation for collision yet, as well as the collision size of units/destructables/items but only Missile collision size.
You might want to consider this also instead of manually factoring them on collision. (from your examples)
 
Last edited:
Level 11
Joined
May 16, 2012
Messages
517
Liked because you talked about relativity in your description.

Standing in the shoulders of giants :p

Adapting missile speed for the relativistiy system might compensate the travelling that happened during the not-processing, but doesn't an important feature get lost - the events that would have happened on collision?

Yeah, that's a trade-off that can be fine tuned for each map maker in their maps like AGD and JAKEZINC brilliantly pointed out. I can make it so that compensation for time dilation be an option as well if you require it. Below is a video of the relativistic method without compensation, it also another demonstration of how many missiles it can handle. At some point in there there was 3000 missiles existing and when i'm not looking at 3000 stuff at the screen the fps is pretty high.

But y'know I personally prefer BPower's handling of callback methods using modules instead of using interfaces like this one. This literally creates a duplicate of each of your callback methods, plus other extra stuff (again, for each callback) neccessary for polymorphism. Using modules like BPower's atleast gives you better control of the code that would be generated in the implementing struct and you can therefore make it very minimal. But I understand that not everyone cares about this and prefers the more straightforward OOP API, so you don't need to change yours.

I know that interfaces can generate a lot of stuff that a lot would consider garbage, but I just wanted it to be a little more friendly syntactically. Sure BPower's implementation is more professional but as far as performance goes, interfaces don't seem to be such a problem.

Nevertheless, it's amazing to see the amount of missiles you can have simultaneously using this technique. I would like to borrow this ;D (if you'd agree) for BPower's Missile update and see if the technique can still be improved (Had no idea yet right now).

Absolutely, go ahead and use/tweak/change it however you like it. You helped me a lot with other stuff as well!

I can see yours doesn't factor in elevation for collision yet, as well as the collision size of units/destructables/items but only Missile collision size. This also doesn't have a roll incorporated for the special effects yet. Or if you just prefer to make this as lite as possible - your call.

Can you also consider providing multiple effects handling per missile. I think this feature shouldn't be missed too.

Sure, why not, I'll add all that. Although, for the missiles attachments it might take some more time.

I already have some minor optimizations ideas that I want to try out.
 
Level 8
Joined
Jun 13, 2008
Messages
337
Is this practically ever needed though? Mostly likely no one ever requires to utilize hundreds of missile instances simultaneously in a real map. Even if you rework all of the native projectile based spells and attacks to use this system and play a 12vs12 melee map, even in a very complex scenario the amount of missile instances would still be below your estimated threshold value I think.

I can see the benefits of this to create very eye-candy crazy spells though:)
 
That one can adjust "sweet spot" doesn't really change the design that comes with it. The thing is, that "so many" missiles can be processed is because the system actually only processes a fixed amount of missiles and ignores rest. Perhaps I'm a party pooper here, but also the idea of theory of relativity seems quite misleading for it. Don't get me wrong, it's at least some approach if many missiles are in use, but it's also not the holy grail and the not-processing definitely comes with a worth to be mentioned donwside imo. Missiles are prioritized, in meaning they get operation time while others simply don't. Missiles can't catch up collisions they maybe had, and adjusting speed-factor can also have influence on gameplay. It's sure not majority of cases, but definitely brings some unbalance factor with it.

It should be probably an integer, btw
public constant real SWEET_SPOT = 133
 
Level 11
Joined
May 16, 2012
Messages
517
Is this practically ever needed though? Mostly likely no one ever requires to utilize hundreds of missile instances simultaneously in a real map. Even if you rework all of the native projectile based spells and attacks to use this system and play a 12vs12 melee map, even in a very complex scenario the amount of missile instances would still be below your estimated threshold value I think.

Then the system will behave like the compensation never existed and have a good performance, and that's the good thing about it.

That one can adjust "sweet spot" doesn't really change the design that comes with it. The thing is, that "so many" missiles can be processed is because the system actually only processes a fixed amount of missiles and ignores rest. Perhaps I'm a party pooper here, but also the idea of theory of relativity seems quite misleading for it. Don't get me wrong, it's at least some approach if many missiles are in use, but it's also not the holy grail and the not-processing definitely comes with a worth to be mentioned donwside imo. Missiles are prioritized, in meaning they get operation time while others simply don't. Missiles can't catch up collisions they maybe had, and adjusting speed-factor can also have influence on gameplay. It's sure not majority of cases, but definitely brings some unbalance factor with it.

You are not a party pooper, constructive criticism is always welcome. You are right when saying that there is downsides to this method, but i think it is still better than doing nothing, and there might be some adjustments possible to compensate for this loss of precision. For example, i thought of creating a configuration constant to limit the amount of compensation, like a compression or threshold, i thought about increasing collision size proportionally to the compensation factor as well, that might solve some of this problems. Playing around with acceleration instead of velocity might produce better precision as well, I'm open to all ideas, so if you have any, please tell me and I'll try them out.

It should be probably an integer, btw
public constant real SWEET_SPOT = 133

You are absolutely right, didn't notice that, will fix.

Edit: Surprisingly enough, changing SWEET_SPOT to integer changes the behavior of the compensation, probably because the difference of dividing an integer by a real and integer by an integer resulting as a factor that is always round (1, 2, 3...), so to save 2 function calls per missile I'll keep it as a real.
 
Last edited:
Level 2
Joined
Aug 22, 2018
Messages
18
Q ability will deflect if clicked on a cliff but
If you click on a unit on a cliff, it will go high in the air and still kill the targeted unit
 
Level 11
Joined
May 16, 2012
Messages
517
Q ability will deflect if clicked on a cliff but
If you click on a unit on a cliff, it will go high in the air and still kill the targeted unit

Yeah, that`s because the homing and terrain interaction. onTerrain detects when the missiles is trying to go inside terrain, but when you use the ability on the unit, the system interprets that you want that missile to go to the unit, so it compensates its travel path height so it wont collide with terrain, That was something intentional in the implementation. You will have a similar behavior when casting the ability targeting high ground, it will try to compensate the path to actually go to the higher ground target point without colliding with the terrain, although, for that if the angle is to steep it might collide.
 
Level 3
Joined
Aug 12, 2010
Messages
29
I'm having an issue with the system (Using the special effect version). Whenever a missile is launched, it flies straight into the air, but still finishes as it deals damage. I've tried tweaking different numbers, but with no luck. I attached a gif + code.

https://i.gyazo.com/fdb398d2a7bea3f960ac2af6ffccb2c3.mp4

vJASS:
//! zinc
library RangedAttack requires DamageEngine, Missiles{

    public{
        struct Projectile extends Missiles{
            method onFinish() -> boolean{

                Damage.apply(source, target, damage, true, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_FORCE, WEAPON_TYPE_WHOKNOWS);
                return false;
            }
        }

        function onFilter() -> boolean{

            return udg_IsDamageAttack
            && BlzGetEventAttackType() != ATTACK_TYPE_CHAOS
            && BlzGetEventDamageType() != DAMAGE_TYPE_FORCE;
        }

        function onAttack(){
            real damage = Damage.amount;
            real sx = GetUnitX(Damage.source), sy = GetUnitY(Damage.source), sz = GetUnitFlyHeight(Damage.source) + 50.0;
            real tx = GetUnitX(Damage.target), ty = GetUnitY(Damage.target), tz = GetUnitFlyHeight(Damage.target) + 50.0;
            Projectile this = Projectile.create(sx, sy, sz, tx, ty, tz);

            Damage.amount = 0.00;
            udg_DamageEventOverride = true;
            this.source = Damage.source;
            this.target = Damage.target;
            this.damage = damage;
            this.model  = "Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl";
            this.speed  = 1000;
            this.scale  = 1.30;
            this.arc  = 15.0;
            this.launch();
        }


        function onInit(){
            trigger t = CreateTrigger();
   
            TriggerRegisterDamageEngine(t, "Mod", 4.00);
            TriggerAddCondition(t, Condition(function onFilter));
            TriggerAddAction(t, function onAttack);
            t = null;
        }
    }
}
//! endzinc
 
Last edited:
Level 11
Joined
May 16, 2012
Messages
517
I'm having an issue with the system (Using the special effect version). Whenever a missile is launched, it flies straight into the air, but still finishes as it deals damage. I've tried tweaking different numbers, but with no luck. I attached a gif + code.

https://i.gyazo.com/fdb398d2a7bea3f960ac2af6ffccb2c3.mp4

vJASS:
//! zinc
library RangedAttack requires DamageEngine, Missiles{

    public{
        struct Projectile extends Missiles{
            method onFinish() -> boolean{

                Damage.apply(source, target, damage, true, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_FORCE, WEAPON_TYPE_WHOKNOWS);
                return false;
            }
        }

        function onFilter() -> boolean{

            return udg_IsDamageAttack
            && BlzGetEventAttackType() != ATTACK_TYPE_CHAOS
            && BlzGetEventDamageType() != DAMAGE_TYPE_FORCE;
        }

        function onAttack(){
            real damage = Damage.amount;
            real sx = GetUnitX(Damage.source), sy = GetUnitY(Damage.source), sz = GetUnitFlyHeight(Damage.source) + 50.0;
            real tx = GetUnitX(Damage.target), ty = GetUnitY(Damage.target), tz = GetUnitFlyHeight(Damage.target) + 50.0;
            Projectile this = Projectile.create(sx, sy, sz, tx, ty, tz);

            Damage.amount = 0.00;
            udg_DamageEventOverride = true;
            this.source = Damage.source;
            this.target = Damage.target;
            this.damage = damage;
            this.model  = "Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl";
            this.speed  = 1000;
            this.scale  = 1.30;
            this.arc  = 15.0;
            this.launch();
        }


        function onInit(){
            trigger t = CreateTrigger();
  
            TriggerRegisterDamageEngine(t, "Mod", 4.00);
            TriggerAddCondition(t, Condition(function onFilter));
            TriggerAddAction(t, function onAttack);
            t = null;
        }
    }
}
//! endzinc

Oh, hold tight for the next version. This is a bug i already found out about in my internal test and fixed it, It happens when there`s a a homing missile going up a higher ground.
 
Level 11
Joined
May 16, 2012
Messages
517
This is a nice list of spells you got here!

Can't really comment on vJass but the missiles' height goes bananas on cliffs.

Yeah, I'm aware of that bug and already fixed it. It happen for homing missiles, next version will have all of that sorted out.

How easy would be be to make a bouncing missile ala night elf huntress or this: Chain Spell Template ?

Pretty easy i would say. Just deflect the missile on the onFinish event and set a new target after it.
 
Level 2
Joined
Aug 22, 2018
Messages
18
Returning true on an onHit makes it instantly vanishes
Also can vanish on corpses when true
 
Level 10
Joined
Oct 18, 2013
Messages
548
I'm on the latest patch WC3 put out before dropping classic support, and SetSFX X/Y don't work...So they work on live now? nvm answered myself

Good implementation of the concept of relativity, Einstein would be impressed haha!
 
Last edited:
Level 11
Joined
May 16, 2012
Messages
517
Returning true on an onHit makes it instantly vanishes
Also can vanish on corpses when true

Returning true is the main method for destroying the missile, it will call DestroyEffect(), so it will play the death animation of your model if it has one. onHit Event do not check if a unit is alive or not, you must do it yourself inside your own declaration of the method. I think it's better this way because someone might want to do something if it collides with a corpse.
 

MyPad

Spell Reviewer
Level 18
Joined
May 9, 2014
Messages
1,575
As it is right now, "excellent" would be an insult when describing this missile system. The sheer number of fireballs in the test map sing an ode of blazing death, a hauntingly beautiful melody that brings about the embrace of death and the inevitability of it. This majestic spectacle of fury that no one shall lay eyes upon and live, is in itself a harbinger of a fiery apocalypse.

Spectacular, phenomenal, this system definitely deserves more recognition. Despite a few rect leaks (upon which I have confidence of a fix), this system deserves to be approved.

JASS:
struct Missiles extends MissileEvents
    static method move takes nothing returns nothing
        // Miscellaneous code
        // onDestructable Event
        if .onDestructable.exists then
            if allocated and collision > 0 then
                set dx = collision
                set RECT = Rect(x - dx, y - dx, x + dx, y + dx)
                call EnumDestructablesInRect(RECT, null, function thistype.onDest)
            endif
        endif
        // onItem Event
        if .onItem.exists then
            if allocated and collision > 0 then
                set dx = collision
                set RECT = Rect(x - dx, y - dx, x + dx, y + dx)
                call EnumItemsInRect(RECT, null, function thistype.onItems)
            endif
        endif
        // Miscellaneous code
    endmethod
endstruct

set RECT = Rect(x - dx, y - dx, x + dx, y + dx) can be replaced with call SetRect(RECT, x - dx, y - dx, x + dx, y + dx)
 
Level 11
Joined
May 16, 2012
Messages
517
As it is right now, "excellent" would be an insult when describing this missile system. The sheer number of fireballs in the test map sing an ode of blazing death, a hauntingly beautiful melody that brings about the embrace of death and the inevitability of it. This majestic spectacle of fury that no one shall lay eyes upon and live, is in itself a harbinger of a fiery apocalypse.

Spectacular, phenomenal, this system definitely deserves more recognition. Despite a few rect leaks (upon which I have confidence of a fix), this system deserves to be approved.

JASS:
struct Missiles extends MissileEvents
    static method move takes nothing returns nothing
        // Miscellaneous code
        // onDestructable Event
        if .onDestructable.exists then
            if allocated and collision > 0 then
                set dx = collision
                set RECT = Rect(x - dx, y - dx, x + dx, y + dx)
                call EnumDestructablesInRect(RECT, null, function thistype.onDest)
            endif
        endif
        // onItem Event
        if .onItem.exists then
            if allocated and collision > 0 then
                set dx = collision
                set RECT = Rect(x - dx, y - dx, x + dx, y + dx)
                call EnumItemsInRect(RECT, null, function thistype.onItems)
            endif
        endif
        // Miscellaneous code
    endmethod
endstruct

set RECT = Rect(x - dx, y - dx, x + dx, y + dx) can be replaced with call SetRect(RECT, x - dx, y - dx, x + dx, y + dx)

I'm blushing now! Thank You, and that's some next level poetry right there. I was not aware of the SetRect native, will fix it as soon as I can.
 
Level 22
Joined
Mar 15, 2012
Messages
2,652
I really recommend you go from GUI to at least JASS and optimally vJASS. With it you will be able to create stuff that are much more efficient take advantage of a lot of stuff that already exists, like this missile library and much more.
I know all three but I dislike vjass so I either learn how to remake it in a hybrid of gui/jass or I convert it back into JASS. I Would be interested in how you'd make it with that GUI part but the worst thing is being unable to open/test the system as it is currently. Though if it was a standalone system I didn't want to edit then I probably would of just used it as vjass.
 
Last edited:
Level 11
Joined
May 16, 2012
Messages
517
being unable to open/test the system as it is currently

You cant open the test map in your world editor? What version are you trying to open it?

I Would be interested in how you'd make it with that GUI part

I was thinking about a few public JASS functions that GUI users can call using the custom script, and when they want to do something in one of the events they can create a trigger to be evaluated on an specific event. But I've not dived into it yet, still busy with other stuff.
 
Level 17
Joined
Aug 13, 2013
Messages
1,680
Have you already mentioned why you're doing this;
JASS:
            call BlzSetSpecialEffectYaw(effect, yaw)
            call BlzSetSpecialEffectPitch(effect, pitch)
            call BlzSetSpecialEffectRoll(effect, roll)
instead of call BlzSetSpecialEffectOrientation(effect, yaw, pitch, roll)?

EDIT:

You might want to share the problems here with the native just in case...

update to JASS_MAX_ARRAY_SIZE for Sevion's outdated Alloc module.

WorldBounds library is made not just for an idea but also for convenience,
minimizing a bit of work to create the same variables just for calculating the initial map bounds,
in your case probably you want to initialize your own bounds to discard a requirement...

You could've just make it an optional requirement and then put your own bounds if it's not found.
(which reduces the same operations/variables onInit in case WorldBounds is already present)

RectContainsCoords can be avoided by using your own bounds. (if WorldBounds doesn't exist)

Yeah, you can neglect those things but just for the sake of minor improvements.
 
Last edited:
Level 11
Joined
May 16, 2012
Messages
517
Have you already mentioned why you're doing this;

instead of
call BlzSetSpecialEffectOrientation(effect, yaw, pitch, roll)
?

EDIT:

You might want to share the problems here with the native just in case...

I'm using Dirac's method for orientation that i tweaked myself to be able to work with these new natives, the problem is that by using BlzSetSpecialEffectOrientation the orientations gets messed up, probably because it uses global orientation instead of local, that's why i'm using the direct yaw, pitch and roll ones. Performance wise, i don't think it's relevant, BlzSetSpecialEffectOrientation probably have to do more stuff than setting it directly.

update to
JASS_MAX_ARRAY_SIZE
for Sevion's outdated Alloc module.

Will do, thx for reminding me of that.

WorldBounds library is made not just for an idea but also for convenience,
minimizing a bit of work to create the same variables just for calculating the initial map bounds,
in your case probably you want to initialize your own bounds to discard a requirement...

You could've just make it an optional requirement and then put your own bounds if it's not found.
(which reduces the same operations/variables onInit in case WorldBounds is already present)

RectContainsCoords
can be avoided by using your own bounds. (if WorldBounds doesn't exist)

Yeah, you can neglect those things but just for the sake of minor improvements.

I did initialize my own bounds for the 1.31+ version of the system, just not for the legacy one. I will add that since you requested it. It will also make the system have one less requirement, which is good as well.
 
Level 17
Joined
Aug 13, 2013
Messages
1,680
I did initialize my own bounds for the 1.31+ version of the system, just not for the legacy one. I will add that since you requested it. It will also make the system have one less requirement, which is good as well.
No, that contradicts my point. ^^

Requirements shouldn't always be avoided (at least: just make it optional) as long as they're
fundamentals to make your resource better, convenient, and efficient. (outsourcing is the key)

They were made on purpose not just for your own but for everyone...

I'm stating this in general not just for the WorldBounds library and your resource,
As I'm also a bit concerned for those who even use hashtables in (v)JASS without
incorporating at least an optional Table for it: is just like discarding its existence.
(At least from my point of view)

From your reforged version just make WorldBounds an optional here
so it would only generate these kind of operations if it doesn't exist;
JASS:
// static if not LIBRARY_WorldBounds then <-
        // world bounds
        readonly static integer maxX
        readonly static integer maxY
        readonly static integer minX
        readonly static integer minY
        //Credits to Nestharus for WorldBounds idea.
        static method onInit takes nothing returns nothing
            local rect world = GetWorldBounds()

            set maxX = R2I(GetRectMaxX(world))
            set maxY = R2I(GetRectMaxY(world))
            set minX = R2I(GetRectMinX(world))
            set minY = R2I(GetRectMinY(world))

            call RemoveRect(world)
            set world = null
        endmethod
// endif <-
^ do the same thing with legacy version where you could deprecate: RectContainsCoords
JASS:
        static if LIBRARY_WorldBounds then
            if not (x > WorldBounds.maxX or x < WorldBounds.minX or y > WorldBounds.maxY or y < WorldBounds.minY) then
                call SetUnitX(dummy, x)
                call SetUnitY(dummy, y)
            endif
        else
         // if x < maxX or x > minX or y < maxY or y > minY then <- use your constant bounds instead
            if RectContainsCoords(bj_mapInitialPlayableArea, x, y) then
                call SetUnitX(dummy, x)
                call SetUnitY(dummy, y)
            endif
        endif
I'm not sure why you're including 'not' operators for the comparisons where you could've just inversed the operators. (which is straightforward)

EDIT:
Regarding the natives for orientations, I'll take a look on it using 1.31.1 patch. (as it might've been a problem in reforged patches only, maybe)
 
Last edited:

AGD

AGD

Level 13
Joined
Mar 29, 2016
Messages
677
I second JAKEZINC in the issue of library requirements. Using external libraries should be the primary choice rather than reimplementing them (and with the same features) as you need them.

Imagine different people making their own library that basically solves the same problem, but with different implementation and API, for a resource that they are making. When the user now imports the main resource made by those different people, he would also need to import the custom requirements that comes with them, which would create redundancy in the user's resource collection.

Another benefit of having a singular resource would be that the ideas and improvements would be more centralized. Different people will be contributing their ideas and making suggestions for how to improve as a help to the author. In the case of a clearly outdated resource and the author is long gone/inactive, that's the time where someone should take the torch and decide to either improve the original one or to make a reimplementation, and give credits to the original author.

In your MissileEffect library for example, I'm curious why you used an internal library, especially when all of its features can already be found in this resource: [vJASS] - SpecialEffect . It also have some more subtle but necessary features like 'keeping motion during sfx death', because that's how the previous dummy method also behaves. And in case you have found problems/bugs/suggestions, you can most openly share it in the resource thread. Not guaranteed that all suggestions will be implemented but that's how it is. That way, improvements will be centralized.

Also, in your MissileEffect library you included an internal Alloc and a custom LinkedList. Those names are very generic but at the same time, only intended to be used inside the library and are not encapsulated properly.


Regarding the boundary checking, I think it should not be implemented by default. Atleast make it configurable or better yet just expose it as an event for the user that calls for example onBoundaryCollide(). The reason why boundary checking was included in the older versions is because the dummy unit can crash the game, but with the new method of pure special effects, it does not.


Btw, @IcemanBo got a good point on the possible unbalanced factor introduced by the Missile processing adjustment, specifically in its collision. But I can't also think of other possible factors that could break the gameplay so much aside from collision.
As for collision, what I found in BPower's is that he actually uses a line segment with thickness to check for collision, not a circular area (except in certain cases where the circular area is enough). In other words, no matter the delta displacement both in space and time, doesn't affect the accuracy of his Missile collision checking.
 
In other words, no matter the delta displacement both in space and time, doesn't affect the accuracy of his Missile collision checking.
Except units specifics change during that time frame which brings different result. (position, attributes, death, mana, ... ) Missles that are processed are prioritized. Such cases would be rare of course.
 

AGD

AGD

Level 13
Joined
Mar 29, 2016
Messages
677
But as long as the user is aware and has a way to limit the max delay or non-processing, I think it's a bit similar to users adjusting the <TIMEOUT> of a spell or a system for example when 32fps would already cause lag for them, so they will set the timeout to 0.05 or something. But in this case, it's just a flexible and automated way of adjusting.
 
Level 17
Joined
Aug 13, 2013
Messages
1,680
The reason why boundary checking was included in the older versions is because the dummy unit can crash the game, but with the new method of pure special effects, it does not.
A notable benefit, I might double check it and ensure if it's 100% safe. ^^ (even though I'm surprised, it already sounds logical and obvious)
In your MissileEffect library for example, I'm curious why you used an internal library, especially when all of its features can already be found in this resource: [vJASS] - SpecialEffect . It also have some more subtle but necessary features like 'keeping motion during sfx death', because that's how the previous dummy method also behaves. And in case you have found problems/bugs/suggestions, you can most openly share it in the resource thread. Not guaranteed that all suggestions will be implemented but that's how it is. That way, improvements will be centralized.
Honestly, one of the reasons why I'm hesitating to incorporate this system for my upcoming resources. It just gives me that 50/50 vibes.
AGD, I think chopinski avoided the library because of the orientation problems he's having with
call BlzSetSpecialEffectOrientation(effect, yaw, pitch, roll)
native.
^ You might want to check it out as I've already tested it on my end and couldn't find any problems with it using the 1.31.1 game patch.
As for collision, what I found in BPower's is that he actually uses a line segment with thickness to check for collision, not a circular area (except in certain cases where the circular area is enough). In other words, no matter the delta displacement both in space and time, doesn't affect the accuracy of his Missile collision checking.
Yeah, I think he left out rectangular collisions to keep much of its code simple and lightweight. (even though It can be implemented optionally)
I second JAKEZINC in the issue of library requirements. Using external libraries should be the primary choice rather than reimplementing them (and with the same features) as you need them.

Imagine different people making their own library that basically solves the same problem, but with different implementation and API, for a resource that they are making. When the user now imports the main resource made by those different people, he would also need to import the custom requirements that comes with them, which would create redundancy in the user's resource collection.

Another benefit of having a singular resource would be that the ideas and improvements would be more centralized. Different people will be contributing their ideas and making suggestions for how to improve as a help to the author. In the case of a clearly outdated resource and the author is long gone/inactive, that's the time where someone should take the torch and decide to either improve the original one or to make a reimplementation, and give credits to the original author.
@chopinski I've also noticed you updated the resource which is contrary to what I mean. ;_;
I think AGD perfectly delivered my point on this than from what I've tried to explain for you.
 

AGD

AGD

Level 13
Joined
Mar 29, 2016
Messages
677
AGD, I think chopinski avoided the library because of the orientation problems he's having with call BlzSetSpecialEffectOrientation(effect, yaw, pitch, roll) native.
^ You might want to check it out as I've already tested it on my end and couldn't find any problems with it using the 1.31.1 game patch.
I've also tested it at the time when making the SpecialEffect lib but found no difference. It could be a reforged problem, but I also don't have reforged as well.
 
Level 11
Joined
May 16, 2012
Messages
517
I second JAKEZINC in the issue of library requirements. Using external libraries should be the primary choice rather than reimplementing them (and with the same features) as you need them.

Imagine different people making their own library that basically solves the same problem, but with different implementation and API, for a resource that they are making. When the user now imports the main resource made by those different people, he would also need to import the custom requirements that comes with them, which would create redundancy in the user's resource collection.

Another benefit of having a singular resource would be that the ideas and improvements would be more centralized. Different people will be contributing their ideas and making suggestions for how to improve as a help to the author. In the case of a clearly outdated resource and the author is long gone/inactive, that's the time where someone should take the torch and decide to either improve the original one or to make a reimplementation, and give credits to the original author.

Never thought it would be such a big deal. I was just thinking of making it as much plug and play as possible and more friendly towards entry level JASSERS than other missile systems. I'll just make WorldBounds a requirement instead of implementing my own or optional.

In your MissileEffect library for example, I'm curious why you used an internal library, especially when all of its features can already be found in this resource: [vJASS] - SpecialEffect . It also have some more subtle but necessary features like 'keeping motion during sfx death', because that's how the previous dummy method also behaves. And in case you have found problems/bugs/suggestions, you can most openly share it in the resource thread. Not guaranteed that all suggestions will be implemented but that's how it is. That way, improvements will be centralized.

I have a few issues with your API. It's great don't get me wrong, but a few things made me implement my own method instead of just using yours. First, like JAKEZINC said is the orientation problem, it produces wrong results with the method i implemented. I did suggested it in the thread for you to add a orientation method that would use the direct yaw, pitch and roll alongside the one already there, but you didn't add it. Second is ease of use, as i said i wanted this system to be as friendly as possible to entry level users, and your system, although very sophisticated, looks somewhat scary, specially for those who never seen a struct or are just beginning to learn it. I also think it could be more intuitive to use, for example, in my own, although very simple, method names are straight to the point, "attach", "detach" and effects are matched by handle instead of by model name, which is also a downside since your system only allows for 1 model of a type. Finally i wanted it to be as lightweight as possible, and when the user wanted a more sophisticated functionality he/she could implement him/herself for a specific missile.

Also, in your MissileEffect library you included an internal Alloc and a custom LinkedList. Those names are very generic but at the same time, only intended to be used inside the library and are not encapsulated properly.

private modules are working correctly? I remember some time ago they were not, i will add the private to them so it will not conflict with external libs.

Regarding the boundary checking, I think it should not be implemented by default. Atleast make it configurable or better yet just expose it as an event for the user that calls for example onBoundaryCollide(). The reason why boundary checking was included in the older versions is because the dummy unit can crash the game, but with the new method of pure special effects, it does not.

I like the idea of a out of bounds event, and its simple enough.

Btw, @IcemanBo got a good point on the possible unbalanced factor introduced by the Missile processing adjustment, specifically in its collision. But I can't also think of other possible factors that could break the gameplay so much aside from collision.

Trade-offs that the user can configure, still think it still better than doing nothing regarding the most obvious problem of every system, but that's a good think, the more options the better.

As for collision, what I found in BPower's is that he actually uses a line segment with thickness to check for collision, not a circular area (except in certain cases where the circular area is enough). In other words, no matter the delta displacement both in space and time, doesn't affect the accuracy of his Missile collision checking.

Yeah, and that's also responsible for a performance hit, again trade-offs.

Yeah, I think he left out rectangular collisions to keep much of its code simple and lightweight.

accurate.
 
Last edited:
Top