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

[Spell] MUI Wait with Points

Status
Not open for further replies.
Level 12
Joined
May 16, 2020
Messages
660
Hi guys

Within this trigger I use a "MUI" wait as described here:
MUI Triggers with Waits

My problem is that I don't think the points can be made MUI here without leaking, right?
Reason being that Point[1] cannot be removed before the wait is over as another unit might use the Point [1] as well... And if I only remove it after the wait, it has already been overwritten by another unit, hence creating a leak.

  • Burrowstrike
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Burrowstrike
    • Actions
      • Set VariableSet Burrowstrike_IndexWrite = (Burrowstrike_IndexWrite + 1)
      • Set VariableSet Burrowstrike_Caster[Burrowstrike_IndexWrite] = (Triggering unit)
      • Set VariableSet Burrowstrike_Level = (Level of Burrowstrike for Burrowstrike_Caster[Burrowstrike_IndexWrite])
      • Set VariableSet Burrowstrike_Point[1] = (Position of Burrowstrike_Caster[Burrowstrike_IndexWrite])
      • Set VariableSet Burrowstrike_Point[2] = (Target point of ability being cast)
      • Set VariableSet Burrowstrike_Point[3] = (Burrowstrike_Point[1] offset by -100.00 towards (Angle from Burrowstrike_Point[1] to Burrowstrike_Point[2]) degrees.)
      • Set VariableSet Burrowstrike_Distance = (Distance between Burrowstrike_Point[1] and Burrowstrike_Point[2])
      • -------- --------
      • Unit - Create 1 Dummy (Ground/Speed 0) for (Owner of Burrowstrike_Caster[Burrowstrike_IndexWrite]) at Burrowstrike_Point[3] facing Default building facing degrees
      • Set VariableSet Burrowstrike_Dummy = (Last created unit)
      • Unit - Add Burrowstrike_Ability[Burrowstrike_Level] to Burrowstrike_Dummy
      • Unit - Set level of Burrowstrike_Ability[Burrowstrike_Level] for Burrowstrike_Dummy to (Integer((Burrowstrike_Distance / 100.00)))
      • Unit - Order Burrowstrike_Dummy to Undead Crypt Lord - Impale Burrowstrike_Point[2]
      • Unit - Add a 0.50 second Generic expiration timer to Burrowstrike_Dummy
      • Custom script: call RemoveLocation(udg_Burrowstrike_Point[2])
      • Custom script: call RemoveLocation(udg_Burrowstrike_Point[3])
      • Wait (Burrowstrike_Distance / 4000.00) seconds
      • Set VariableSet Burrowstrike_IndexRead = (Burrowstrike_IndexRead + 1)
      • Unit - Move Burrowstrike_Caster[Burrowstrike_IndexRead] instantly to Burrowstrike_Point[2]
      • Animation - Play Burrowstrike_Caster[Burrowstrike_IndexRead]'s morph alternate animation
      • Animation - Queue Burrowstrike_Caster[Burrowstrike_IndexRead]'s stand animation
      • Custom script: call RemoveLocation(udg_Burrowstrike_Point[1])
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Burrowstrike_IndexRead Equal to Burrowstrike_IndexWrite
        • Then - Actions
          • Set VariableSet Burrowstrike_IndexWrite = 0
          • Set VariableSet Burrowstrike_IndexRead = 0
        • Else - Actions
 
Last edited:
Level 21
Joined
Dec 4, 2007
Messages
1,477
I think this should work if you index all the data.

Read what Magtheridon wrote in the Mui wait thread (under "Cons") again:
  • The wait time with this method must be a constant. (Thank you IcemanBo for pointing this out)
  • You either store all state and every last bit of event-response data that you want to use after the wait code, or you store absolutely nothing and depend on the current execution context of the trigger.
    (This means that using something like (Triggering Unit) after the wait action will give you incorrect results if you used a buffer to store data for the instances. You either use the buffers to store absolutely everything, or you use no buffers at all.) (Thank you again, IcemanBo for helping me make this realization)

Btw, wouldn't you want a more precise timer for an ability like burrowstrike?
I barely use waits, so i'm not quite sure, but i heard they can be noticably imprecise (especially with higher latency).

Anyway, since you are already using indexing, why not go the full route, like described here: Visualize: Dynamic Indexing.
 
Level 17
Joined
Mar 21, 2011
Messages
1,597
The trick is to use local variables
JASS:
local location yourPoint = ...
// do some stuff
call RemoveLocation(yourPoint)
set yourPoint = null

You have to convert some lines into custom script tho, and in this case, you can use x and y values right away for better performance.

So instead of creating a location..
JASS:
local real x = GetUnitX(udg_someUnit)
local real y = GetUnitY(udg_someUnit)
// do some stuff
 
You also have the option to use more than 1 index for each cast instance by using the array in a 2D Array way.
That is done by adding a secondary Index pre the actual DataIndex. That Pre Index would be the current read/write Index * someSize. The Size is as big as the amount you require for that data Type.
Point[1]
Point[2]
->
Point[IndexWrite*4 + 1]
Point[IndexWrite*4 + 2]

Then you can save more than 1 Location per instance. But this 2D way reduce the maximum instances that can run at the same time from 32k to 10k or 8k.
 
Level 12
Joined
May 16, 2020
Messages
660
Btw, wouldn't you want a more precise timer for an ability like burrowstrike?
I barely use waits, so i'm not quite sure, but i heard they can be noticably imprecise (especially with higher latency).

Anyway, since you are already using indexing, why not go the full route, like described here: Visualize: Dynamic Indexing.

I actually started building the ability with the Dynamic Indexing instruction! But my problem was that I cannot have "individual" run timers, no? For example, for Unit A run the trigger every 0.03 seconds, and for Unit B run it every 0.02 seconds. I need different run timers since the wait time is based on the distance of the Caster position and Target point position, hence dynamic. So I figured I will use "something" which can be individual per unit, i.e. wait.

While writing this I realized... I could do a generic 0.01 sec run, and make it dynamic by waiting 0.02, 0.03 second based on the Integer Count of that unit!


The trick is to use local variables
JASS:
local location yourPoint = ...
// do some stuff
call RemoveLocation(yourPoint)
set yourPoint = null

You have to convert some lines into custom script tho, and in this case, you can use x and y values right away for better performance.

So instead of creating a location..
JASS:
local real x = GetUnitX(udg_someUnit)
local real y = GetUnitY(udg_someUnit)
// do some stuff

Sorry I don't understand. Am I not already defining local variables by adding an array to the caster?
And regarding the performance: So is it always better to define the X and Y instead of simply "set Point = XXX"??


You also have the option to use more than 1 index for each cast instance by using the array in a 2D Array way.
That is done by adding a secondary Index pre the actual DataIndex. That Pre Index would be the current read/write Index * someSize. The Size is as big as the amount you require for that data Type.
Point[1]
Point[2]
->
Point[IndexWrite*4 + 1]
Point[IndexWrite*4 + 2]

Then you can save more than 1 Location per instance. But this 2D way reduce the maximum instances that can run at the same time from 32k to 10k or 8k.

If I understand correctly, in your example it would be
  • Point[IndexWrite*4 + 1] -> Point[5] since 1*4+2
  • Point[IndexWrite*4 + 2] -> Point[10] since 2*4+2
And if yes, then I think I know what you mean. It would still build on the current read/write system, but allows to use dynamic points instead of fixed ones.. thanks!
 
Level 17
Joined
Mar 21, 2011
Messages
1,597
And regarding the performance: So is it always better to define the X and Y instead of simply "set Point = XXX"??
Exactly, real is a primitive data type, which is way better than creating a location handle

While writing this I realized... I could do a generic 0.01 sec run, and make it dynamic by waiting 0.02, 0.03 second based on the Integer Count of that unit!
0.01 peroidic triggers are not recommended, i would go with 0.03 minimum.

Am I not already defining local variables by adding an array to the caster?
No. In gui, there are sadly only global variables, but you can still create locals with custom script usage.
The difference between a local varibale is, that it only lives as long as the function runs, and is unique to the function call. In simple words, it cannot be overwritten by another function call.
 
Status
Not open for further replies.
Top