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

{DEPRECATED / OUTDATED} Dynamic Values Storage

Level 25
Joined
Jun 5, 2008
Messages
2,572
Attention!»This system is deprecated, meaning, it is outdated, no longer in use. Hanky's "Dynamic Indexing Template" is the latest standard on fulfilling the purposes of this system; using Hanky's indexing template over this one is recommendable.

Dynamic values storage


One note, this was called Paladon's integer array indexing system but after talking to PurplePoot he explained me why it cannot be named like that.

Contents:

-Introduction

What is Dynamic values storage? It's and easy to use variable system used by spell makers to make Multi Unit instancable spells.
Why use it? It is easy and i found no other way than it, though other ways exist.
What do you need to use it - nothing it isn't a custom script or anything like that it is simply a variable based system.
Can you make any spell in GUI MUI with this - the answer is yes.
Okay without delay i will now introduce you how to set up before using the system.

-Variables

For using the system itself you only need 1 integer array variable, example:
- index[] - this is the integer variable we are going to use for indexing
Now how does it work that is pretty easy once you trigger out the first spell with this system, we are going to use several arrays of the variable index[]
and i will explain the trigger below:

  • Events
    • Unit - A unit Starts the effect of an ability
  • Conditions
    • (Ability being cast) Equal to (==) *spell*
  • Actions
    • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • index[1] Equal to (==) 0
      • Then - Actions
        • Trigger - Turn on loop <gen>
      • Else - Actions
    • Set index[1] = (index[1] + 1)
    • Set index[2] = (index[2] + 1)


Now maybe you are asking yourself why are we using index[1] and index[2] for? Here is why:
-index[1] variable we are going to increase and decrease whenever we initialize or finish the effect of the desired spell so if it is 0 when we begin to cast
it we turn on the loop gen which will be our periodic trigger while when the spell effect finishes we decrease it and if it is 0 again then there are no more instances
of our spells running and we can turn off the periodic trigger and reset the index[2] variable.
-index[2] variable we are going to use for storing variables like units/damage/locations,etc. We are only going to increase it and never decrease it, why?
Imagine you have 2 spells running at the same time and you decrease the index[2] value and the second spells variables get mixed up with the first one.
So how to stop piling up of index[2] value? Easy when the spell effect finishes and we decrease index[1] variable we will if the index[1] is equal to 0(that means no spell instances are running)
and we can reset the index[2] to 0.
Now in loop triggers we are going to use index[n] variable where the n will vary from 2-y.
Example:

  • loop
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • Do Multiple ActionsFor each (Integer index[3]) from 1 to index[2], do (Actions)
        • Loop - Actions

Why are we going to use index[3] variable and not for example LoopIntegerA? Cause IntegerA can cause a strange blizzard bug and it's cleaner this way.
Now what we are doing in the trigger is we are going to cycle through each value of index[2] variable using index[3] variable, in plain words:
you have 3 spell instances running and now each second you want an effect to happen so we cycle through each spell casted and do it's action while not messing up the
other 2 spell instances by using the index through we stored them.

-Making a first MUI spell with Dynamic Values Storage method

Now the first MUI spell we are going to make is a DOT(damage over time) one.
We will base it on storm bolt and rename it to Heart Stab.
Then we prepare the necesary variables we have in mind:
  • unit array variable - target // for storing the target into a variable
  • unit array variable - damage_source // for gold/exp proper gain
  • real array variable - dpi // damage per interval
  • real array variable - duration // spell duration
  • string variable - dpi_effect // string of our damage effect
  • real array variable - damage_interval // damage interval in seconds
  • real array variable - interval_check // this variable will always have a starting value of 0 cause we are going to use it for damage interval checking

Now the initial trigger setup:

  • HS init
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to (==) Heart Stab
    • Actions
      • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • index[1] Equal to (==) 0
        • Then - Actions
          • Trigger - Turn on loop <gen>
        • Else - Actions
      • -------- We check is there an active spell instance running already by the value of index[1] --------
      • -------- --- --------
      • Set index[1] = (index[1] + 1)
      • -------- We increase the index we are going to use for checking is there an active spell going on --------
      • -------- --- --------
      • Set index[2] = (index[2] + 1)
      • -------- We increase the index variable we are going to use for storing variables --------
      • -------- --- --------
      • Set damage_source[index[2]] = (Casting unit)
      • -------- we store the caster for damaging unit refrence --------
      • -------- --- --------
      • Set target[index[2]] = (Target unit of ability being cast)
      • -------- we store the target for the periodic events --------
      • -------- --- --------
      • Set damage_interval[index[2]] = 1.00
      • -------- we define the damage interval --------
      • -------- --- --------
      • Set dpi[index[2]] = 15.00
      • -------- we define the damage dealt per interval to the target --------
      • -------- --- --------
      • Set duration[index[2]] = 10.00
      • -------- we define the spell duration --------
      • -------- --- --------
      • Set dpi_effect = Objects\Spawnmodels\Human\HumanBlood\HumanBloodFootman.mdl
      • -------- on the end we define the periodic damage effect string this shouldn't need to be a array variable if you don't plan on changing it depending on the spell level --------
      • -------- --- --------
      • Set interval_check = 0
      • -------- variable used for damage interval checking --------

That is it, we stored all the values we need into variables which we stored via integer index for future use and now we can make the loop trigger.
Now the most important thing we forgot, we didn't made it multi leveled, but with several modifications we can easily do that.
Spells without multi level support aren't good so if you wish to make MUI spells at least add multi level suport to them.
We are going to modify the values to our desire, i modifed them like this:

  • HS init
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to (==) Heart Stab
    • Actions
      • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • index[1] Equal to (==) 0
        • Then - Actions
          • Trigger - Turn on loop <gen>
        • Else - Actions
      • -------- We check is there an active spell instance running already by the value of index[1] --------
      • -------- --- --------
      • Set index[1] = (index[1] + 1)
      • -------- We increase the index we are going to use for checking is there an active spell going on --------
      • -------- --- --------
      • Set index[2] = (index[2] + 1)
      • -------- We increase the index variable we are going to use for storing variables --------
      • -------- --- --------
      • Set damage_source[index[2]] = (Casting unit)
      • -------- we store the caster for damaging unit refrence --------
      • -------- --- --------
      • Set target[index[2]] = (Target unit of ability being cast)
      • -------- we store the target for the periodic events --------
      • -------- --- --------
      • Set damage_interval[index[2]] = (1.25 - (0.25 x (Real((Level of (Ability being cast) for (Casting unit))))))
      • -------- we define the damage interval --------
      • -------- --- --------
      • Set dpi[index[2]] = (10.00 + (5.00 x (Real((Level of (Ability being cast) for (Casting unit))))))
      • -------- we define the damage dealt per interval to the target --------
      • -------- --- --------
      • Set duration[index[2]] = (5.00 + (5.00 x (Real((Level of (Ability being cast) for (Casting unit))))))
      • -------- we define the spell duration --------
      • -------- --- --------
      • Set dpi_effect = Objects\Spawnmodels\Human\HumanBlood\HumanBloodFootman.mdl
      • -------- on the end we define the periodic damage effect string this shouldn't need to be a array variable if you don't plan on changing it depending on the spell level --------
      • -------- --- --------
      • Set interval_check = 0
      • -------- variable used for damage interval checking --------

And now we set up the settings for a multi leveled spell, the next step is making the loop trigger.
First of all our damage_interval is a multiple of 0.25 so we are going to use a trigger which runs every 0.25 seconds.
Then we are going to cycle through the index[2] values with index[3] variable.
The loop trigger should look like this:

  • loop
    • Events
      • Time - Every 0.25 seconds of game time
    • Conditions
    • Actions
      • Do Multiple ActionsFor each (Integer index[3]) from 1 to index[2], do (Actions)
        • Loop - Actions
          • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • duration[index[3]] Greater than (>) 0.00
            • Then - Actions
              • Set duration[index[3]] = (duration[index[3]] - 0.25)
              • -------- we decrease the spell duration by 0.25 --------
              • -------- --- --------
              • Set interval_check[index[3]] = (interval_check[index[3]] + 0.25)
              • -------- we increase the interval_check variable --------
              • -------- --- --------
                • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  • If - Conditions
                    • interval_check[index[3]] Greater than or equal to (>=) damage_interval[index[3]]
                  • Then - Actions
                    • Set interval_check[index[3]] = 0.00
                    • -------- we reset the interval_check variable --------
                    • -------- --- --------
                      • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (target[index[3]] is alive) Equal to (==) True
                        • Then - Actions
                          • Unit - Cause damage_source[index[3]] to damage target[index[3]], dealing dpi[index[3]] damage of attack type Spells and damage type Normal
                          • -------- we damage the target dealing damage per interval --------
                          • -------- --- --------
                          • Special Effect - Create a special effect attached to the chest of target[index[3]] using dpi_effect
                          • Special Effect - Destroy (Last created special effect)
                          • -------- we create and destroy the periodic damage effect on the unit, i prefer using chest attach point --------
                        • Else - Actions
                          • Set duration[index[3]] = 0.00
                    • -------- if the target is alive we do actions if not we set the spell duration to 0 --------
                  • Else - Actions
              • -------- if the interval_check is equal or larger than damage interval we do actions --------
              • -------- --- --------
                • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  • If - Conditions
                    • duration[index[3]] Equal to (==) 0.00
                  • Then - Actions
                    • Set index[1] = (index[1] - 1)
                    • -------- we reduce the index[1] variable cause one spell instance has ended --------
                    • -------- --- --------
                      • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • index[1] Equal to (==) 0
                        • Then - Actions
                          • Set index[2] = 0
                          • -------- we reset the index[2] to 0 cause there aren't any active spells running --------
                          • -------- --- --------
                          • Trigger - Turn off (This trigger)
                          • -------- we turn off this trigger, it is pointless for it to run if there isn't any spell for it to affect --------
                          • -------- --- --------
                          • Game - Display to (All players) the text: off
                          • -------- we can display a "debug" message to check will the trigger turn off when there aren't any other active spell --------
                        • Else - Actions
                    • -------- if the index[1] is 0 there are no active spell and we do actions --------
                  • Else - Actions
              • -------- if the spell duration is 0 we do actions --------
            • Else - Actions

All parts of the trigger are commented if you don't understand something feel free to pm me or post your question here.
There is a demo map attached which contains the spell we made feel free to test it's MUI-ness and does it bug.
http://www.hiveworkshop.com/forums/attachment.php?attachmentid=52316&stc=1&d=1239785960


-Using loops

Now i am not talking about loop trigger or anything periodic, i am talking about loops used in spells. An example of loop would be:

  • Actions
    • Do Multiple ActionsFor each (Integer A) from 1 to 10, do (Actions)
      • Loop - Actions

Now what can we do with loops? We can easily set up several functions like creating units/special effects and instead of writing a bunch fo lines to create
a circle effect we just run a loop for the desired number of effects.
In this example i will show you how to use loops to make an Incendiary Blast spell.
I suggest everyone to use channel to make custom spells cause it is intended for that.
The spell idea will be:
  • deals x damage to the target
  • if the target dies it will create several fire particles flying away(we will use loops for this)
  • upon fall the fire particles will deal damage in 150 AOE
Okay first of all we are gonna need a dummy unit. What is a dummy unit? It is a unit without a model or with a model acting like a missile.
The dummy we are going to use will use a custom model called dummy.mdx which has no model at all but has attachment points.
Upon importing we set the dummy to use it and we set up our dummy changing:
  • it's abilities(i always add invulnerable and locust ability)
  • it's name
  • it's classification(if it is a worker)
  • change it's attacks enabled to none if attack is enables
  • change it's colision to 0
  • change it's movement type to fly(recommended)
  • change it's food cost to 0

The dummy is prepared and now we make our trigger.
I will comment all the variables i used in the trigger to make it easier to understand.

  • IB init
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to (==) Incendiary Blast
    • Actions
      • -------- First of all the first effect of the spell is instantly used so we can use array variables without indexing. --------
      • -------- - --------
      • Set IB_temp_real[0] = (50.00 + (100.00 x (Real((Level of (Ability being cast) for (Casting unit))))))
      • -------- - --------
      • Set IB_particle_count = 5
      • -------- We are going to use this variable for our loop --------
      • -------- - --------
      • Set IB_owner = (Owner of (Casting unit))
      • -------- - --------
      • Set IB_leak_point[1] = (Position of (Target unit of ability being cast))
      • -------- - --------
      • Unit - Cause (Casting unit) to damage (Target unit of ability being cast), dealing IB_temp_real[0] damage of attack type Spells and damage type Normal
      • Special Effect - Create a special effect attached to the chest of (Target unit of ability being cast) using Abilities\Spells\Other\Incinerate\FireLordDeathExplode.mdl
      • Special Effect - Destroy (Last created special effect)
      • -------- Causes instant damage and creates and destroys the explosion effect --------
      • -------- - --------
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • ((Target unit of ability being cast) is dead) Equal to (==) True
          • Then - Actions
            • Set IB_temp_real[1] = (X of IB_leak_point[1])
            • Set IB_temp_real[2] = (Y of IB_leak_point[1])
            • Set IB_leak_point[2] = (Point(IB_temp_real[1], IB_temp_real[2]))
            • -------- We set up a point at which the particles start to move --------
              • Do Multiple ActionsFor each (Integer A) from 1 to IB_particle_count, do (Actions)
                • Loop - Actions
                  • -------- - --------
                  • -------- Now we are going to set up a dummy(missile) parameters and it's indexing --------
                  • -------- - --------
                    • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                      • If - Conditions
                        • IB_loop_index[1] Equal to (==) 0
                      • Then - Actions
                        • Trigger - Turn on IB loop <gen>
                      • Else - Actions
                  • -------- - --------
                  • Set IB_loop_index[1] = (IB_loop_index[1] + 1)
                  • Set IB_loop_index[2] = (IB_loop_index[2] + 1)
                  • -------- We set up the integers used for indexing cause we will move the dummy unit every 0.03 second so we need indexing --------
                  • -------- - --------
                  • Set IB_loop_angle[IB_loop_index[2]] = (Random angle)
                  • -------- Defines the angle at which the particle moves --------
                  • -------- - --------
                  • Set IB_loop_max_distance[IB_loop_index[2]] = (Random real number between 150.00 and 300.00)
                  • -------- Defines the maximum distance which the missile travels --------
                  • -------- - --------
                  • Set IB_loop_damage_source[IB_loop_index[2]] = (Casting unit)
                  • -------- we store the caster for damage manipulation upon missile death --------
                  • -------- - --------
                  • Set IB_loop_damage[IB_loop_index[2]] = (25.00 + (25.00 x (Real((Level of (Ability being cast) for (Casting unit))))))
                  • -------- we set the damage dealt around the missile upon it's death --------
                  • -------- - --------
                  • Set IB_loop_max_height[IB_loop_index[2]] = (Random real number between 300.00 and 500.00)
                  • -------- - --------
                  • Set IB_loop_speed[IB_loop_index[2]] = 6.00
                  • -------- We define the missile speed, it shouldn't be too high value to ensure a nice look of the spell --------
                  • -------- - --------
                  • Unit - Create 1 Dummy for IB_owner at IB_leak_point[2] facing IB_loop_angle[IB_loop_index[2]] degrees
                  • Unit - Turn collision for (Last created unit) Off
                  • Set IB_loop_missile_unit[IB_loop_index[2]] = (Last created unit)
                  • -------- We create the dummy(missile) and set it to a variable for loop movement --------
                  • -------- - --------
                  • Animation - Change (Last created unit)'s size to (50.00%, 50.00%, 50.00%) of its original size
                  • -------- We can change the dummies size/scale to scale the model attached to it --------
                  • -------- - --------
                  • Special Effect - Create a special effect attached to the chest of (Last created unit) using Abilities\Weapons\RedDragonBreath\RedDragonMissile.mdl
                  • Set IB_loop_gfx[IB_loop_index[2]] = (Last created special effect)
                  • -------- We attach an model to the dummy and set the effect into a variable for later leak removal --------
                  • -------- - --------
                  • Set IB_loop_current_distance[IB_loop_index[2]] = 0.00
            • -------- We cycle through actions using integerA while the cycle number is defined by IB_particle_count variable --------
            • Custom script: call RemoveLocation(udg_IB_leak_point[2])
          • Else - Actions
      • Custom script: call RemoveLocation(udg_IB_leak_point[1])
      • -------- If the target died we create particles via loop --------
      • -------- - --------
      • -------- - --------
      • -------- That is all if the target is alive our spell has ended and there was no need for indexing --------

Now we have set up our initial trigger and used the loop function for creating missile/particles instead of coping the same thing 5 times.
This is quite usefull cause it shortens the time needed to do a lot of things.
Now that we have set up our initial trigger we supose the target unit has died so we have created the dummy and now we need to move it.
Be aware that the model dummy.mdx i used doesn't support Z angle changing but there is a one that does.
I won't complicate the spell with that but i am going to use a parabola function which i will try to explaing better to you.
Here is the parabola code we are going to use:
JASS:
function ParabolaZ takes real h, real d, real x returns real
 return (4 * h / d) * (d - x) * (x / d)
endfunction
Explanation:
The function takes the real h which represents the maximum height we want the missile to achieve.
The function takes the real d which represents the maximum distance we want the missile to be able to reach.
The function takes the real x which represents the current distance the missile has traveled.
Then the function calculates all the data we gave it and returns a height real.
It can also be done via GUI but it will be messy.
I will use a GUI version of parabola calculation.

Here is how the loop trigger will look like:

  • IB loop
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • Do Multiple ActionsFor each (Integer IB_loop_index[3]) from 1 to IB_loop_index[2], do (Actions)
        • Loop - Actions
          • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • IB_loop_missile_unit[IB_loop_index[3]] Not equal to (!=) No unit
            • Then - Actions
              • Set IB_loop_leak_point[1] = (Position of IB_loop_missile_unit[IB_loop_index[3]])
              • Set IB_loop_leak_point[2] = (IB_loop_leak_point[1] offset by IB_loop_speed[IB_loop_index[3]] towards IB_loop_angle[IB_loop_index[3]] degrees)
              • -------- We store the points we are going to use to avoid leaks. --------
              • -------- - --------
              • Unit - Move IB_loop_missile_unit[IB_loop_index[3]] instantly to IB_loop_leak_point[2]
              • -------- We move the dummy to the previously stored point --------
              • -------- - --------
              • Set IB_loop_current_distance[IB_loop_index[3]] = (IB_loop_current_distance[IB_loop_index[3]] + IB_loop_speed[IB_loop_index[3]])
              • -------- We increase the current distance variable which is used for parabola and for distance checking, it's initial value is almost always 0 --------
              • -------- - --------
              • Set IB_loop_temp_real[1] = IB_loop_max_height[IB_loop_index[3]]
              • Set IB_loop_temp_real[2] = IB_loop_max_distance[IB_loop_index[3]]
              • Set IB_loop_temp_real[3] = IB_loop_current_distance[IB_loop_index[3]]
              • -------- These are the variables we are going to use for parabola calculations, i used a IB_loop_temp_real variable to make it as simple as i can --------
              • -------- - --------
              • Custom script: set udg_IB_loop_temp_real[4] = ( 4 * udg_IB_loop_temp_real[1] / udg_IB_loop_temp_real[2]) * ( udg_IB_loop_temp_real[2] - udg_IB_loop_temp_real[3] ) * ( udg_IB_loop_temp_real[3] / udg_IB_loop_temp_real[2] )
              • -------- This variable is the calculation of parabola and it's value it the height we are going to asign to the missile, i used a custom script cause it is much easier than to calculate it in GUI --------
              • -------- - --------
              • Animation - Change IB_loop_missile_unit[IB_loop_index[3]] flying height to IB_loop_temp_real[4] at 0.00
              • -------- We aply the height change to the missile --------
              • -------- - --------
                • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  • If - Conditions
                    • IB_loop_current_distance[IB_loop_index[3]] Greater than (>) IB_loop_max_distance[IB_loop_index[3]]
                  • Then - Actions
                    • Custom script: if udg_IB_loop_tmp_group[udg_IB_loop_index[3]] == null then
                    • Custom script: set udg_IB_loop_tmp_group[udg_IB_loop_index[3]] = CreateGroup()
                    • Custom script: endif
                    • -------- These 3 lines of custom scripts are used to avoid leaks, if IB_loop_tmp_group is equal to nothing we create it, else we do nothing --------
                    • -------- - --------
                    • Set IB_loop_tmp_group[IB_loop_index[3]] = (Units within 200.00 of IB_loop_leak_point[2] matching ((((Matching unit) is A structure) Equal to (==) False) and ((((Matching unit) is alive) Equal to (==) True) and ((((Matching unit) is A flying unit) Equal to (==) False) and ((((Matching unit) is Magic I
                    • -------- Okay i know this looks like a really big complex thing but it's simple, we set the group to match all units within 200 AOE of position of our missile and then we add conditions --------
                    • -------- - --------
                    • Custom script: set bj_wantDestroyGroup = true
                    • -------- This custom script sets the next used group to be destroyed after it is used, i prefer manualy destroying groups with "call DestroyGroup(n)" than this but this is easy to remember --------
                    • -------- - --------
                    • Unit Group - Pick every unit in IB_loop_tmp_group[IB_loop_index[3]] and do (Actions)
                      • Loop - Actions
                        • Unit - Cause IB_loop_damage_source[IB_loop_index[3]] to damage (Picked unit), dealing IB_loop_damage[IB_loop_index[3]] damage of attack type Spells and damage type Normal
                        • Special Effect - Create a special effect attached to the chest of (Picked unit) using Abilities\Weapons\FireBallMissile\FireBallMissile.mdl
                        • Special Effect - Destroy (Last created special effect)
                    • -------- we pick every unit we put in the group previously, damage them and create + destroy a special effect --------
                    • -------- - --------
                    • Unit - Kill IB_loop_missile_unit[IB_loop_index[3]]
                    • -------- We kill the dummy, cause we need it no more --------
                    • -------- - --------
                    • Special Effect - Destroy IB_loop_gfx[IB_loop_index[3]]
                    • -------- we destroy the effect we attached to evade leaks --------
                    • -------- - --------
                    • Special Effect - Create a special effect at IB_loop_leak_point[2] using Abilities\Weapons\RedDragonBreath\RedDragonMissile.mdl
                    • -------- we create a effect at the impact point of the missile just for eyecandy --------
                    • -------- - --------
                    • Special Effect - Destroy (Last created special effect)
                    • -------- we destroy the last created effect to prevent leaks --------
                    • -------- - --------
                    • Custom script: set udg_IB_loop_missile_unit[udg_IB_loop_index[3]] = null
                    • -------- We null the missile_unit to make sure the actions won't repeat even if the effect has ended --------
                    • -------- - --------
                    • Set IB_loop_index[1] = (IB_loop_index[1] - 1)
                      • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • IB_loop_index[1] Equal to (==) 0
                        • Then - Actions
                          • Set IB_loop_index[2] = 0
                          • Trigger - Turn off (This trigger)
                        • Else - Actions
                    • -------- i already explained what we do here before, if you don't know what i am talking about check the first part of the tutorial and the attached map. --------
                    • -------- - --------
                  • Else - Actions
              • -------- - --------
              • Custom script: set udg_IB_loop_temp_real[1] = 0
              • Custom script: set udg_IB_loop_temp_real[2] = 0
              • Custom script: set udg_IB_loop_temp_real[3] = 0
              • Custom script: set udg_IB_loop_temp_real[4] = 0
              • -------- setting the variables to 0 --------
              • -------- - --------
              • Custom script: call RemoveLocation(udg_IB_loop_leak_point[2])
              • Custom script: call RemoveLocation(udg_IB_loop_leak_point[1])
              • -------- removing leaks --------
            • Else - Actions


Now maybe you asked yourself why do we destroy special effects we create instantly? It prevents leaks but is still usefull cause it will make the speical effect play it's death animation.
Note: Some effects don't have death animation so they will play their whole animatiom(thunderclap for example) but this is most usefull for missile effects cause they all have death animations.
You may notice i used some custom scripts where i could have used GUI functions, why? I find it easier, it would be pain in GUI to calculate:
JASS:
( 4 * udg_IB_loop_temp_real[1] / udg_IB_loop_temp_real[2]) * ( udg_IB_loop_temp_real[2] - udg_IB_loop_temp_real[3] ) * ( udg_IB_loop_temp_real[3] / udg_IB_loop_temp_real[2] )
I used custom scripts cause that is JASS codes in GUI, you can manipulate both GUI and JASS like this.
Also the most important thing about custom scripts is that you can't make a decent spell with locations and unit groups without them.
Why? You need them to clean leaks or it will affect the FPS.
Also you may notice i used point variables called IB_leak_point and IB_loop_leak_point and i didn't used indexes on them, only simple values.
I did that cause they are immediatly used and destroyed so there is no point in their indexing.
This also aplies to IB_temp_real and IB_loop_temp_real variables, but as reals cannot be destroyed and don't leak i just set their values to 0.
That concludes our loop part.
http://www.hiveworkshop.com/forums/attachment.php?attachmentid=52317&stc=1&d=1239785960

-Avoiding trigger overflow

What do i mean with this? I recently saw a map with 70-80 triggers and that was a system!
Now what did the maker of the system do, he made a trigger like this:

  • Events
    • Player - Player 1 (Red) Presses the Left Arrow key
  • Conditions
  • Actions

For each player and a 4 periodic triggers for each player.
Now to avoid that you can use array variables but what hapens when you use too much periodic triggers? It is uneficent.
To avoid that you can easily make a trigger that runs each 0.01 second and checks is the time to do actions now.
I wouldn't recommend doing this for all triggers but if you have a spell which uses multiple effects(example fading + location change) you can do the following:

  • Events
    • Time - Every 0.01 seconds of game time
  • Conditions
  • Actions
    • -------- I will comment only the first part of these variable cycles cause the second is the same --------
      • Do Multiple ActionsFor each (Integer General_index1[3]) from 1 to General_index1[2], do (Actions)
        • Loop - Actions
          • Set interval_check1[General_index1[3]] = (interval_check1[General_index1[3]] + 0.01)
          • -------- We increase our real array which we use for interval checking --------
          • -------- - --------
            • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • interval_check1[General_index1[3]] Greater than or equal to (>=) interval1[General_index1[3]]
              • Then - Actions
                • Set interval_check1[General_index1[3]] = 0.00
                • -------- Reseting the interval check variable --------
                • -------- - --------
                • -------- actions here --------
              • Else - Actions
          • -------- if the interval check variable value is equal to the interval variable value we reset the interval check variable value to 0 and do the actions we wanted --------
    • -------- - --------
      • Do Multiple ActionsFor each (Integer General_index2[3]) from 1 to General_index2[2], do (Actions)
        • Loop - Actions
          • Set interval_check2[General_index2[3]] = (interval_check2[General_index2[3]] + 0.01)
            • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • interval_check2[General_index2[3]] Greater than or equal to (>=) interval2[General_index2[3]]
              • Then - Actions
                • Set interval_check2[General_index2[3]] = 0.00
                • -------- actions here --------
              • Else - Actions
          • -------- actions here --------
    • -------- - --------
      • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Multiple ConditionsAnd - All (Conditions) are true
            • Conditions
              • General_index1[1] Equal to (==) 0
              • General_index2[1] Equal to (==) 0
        • Then - Actions
          • -------- If the values of the primary indexes is 0 --------
          • -------- - --------
          • Set General_index1[2] = 0
          • Set General_index2[2] = 0
          • Trigger - Turn off (This trigger)
          • -------- we reset the indexes we use for variables array and turn off the trigger --------
        • Else - Actions
    • -------- What we do here is we check for all indexes we used in the loop if their primary index value is 0 then if it is we set their secondary indexing value to 0 and turn off the trigger --------

And that is that, if all loop effects aren't active we just turn off the trigger and reset their indexes.
This concludes this part of the tutorial.

-PGS(Paladon's General System)

Not tested with latest versions of WC3, may cause issues.
The map contains 3 trigger which are used as the PGS.
It contains:
  • tree revival
  • unit revival
  • other stuff

http://www.hiveworkshop.com/forums/attachment.php?attachmentid=52320&stc=1&d=1239785960

Dynamic values storage with DIR system


First of all what is DIR system? Is an addition to the indexing system which makes the index used for actual indexing get recycled.
To impement it we are going to take example #1.
Now we are going to add several new variables:
  • HS_dyn_index => Integer variable, not array
  • HS_index_selected => Boolean variable, not array
  • HS_index_is_empty => Boolean variable, array

First of all you should know how the the basics i wrote about in the upper section of the tutorial, if you don't know first read the upper part of the tutorial.
Now we are going to make some changes, first of all we won't be using HS_index[2] for indexing, instead we are going to use HS_dyn for indexing.
The second boolean variable is going to be used to make sure that HS_dyn_index carries an value which is not already taken.
The HS_index_is_empty[] we are going to use in the loop trigger for checking if the array is free again.
Now after reworking the initial HS init trigger it looks like this:

  • HS init
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to (==) Heart Stab
    • Actions
      • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • HS_index[1] Equal to (==) 0
        • Then - Actions
          • Trigger - Turn on loop <gen>
        • Else - Actions
      • -------- We check is there an active spell instance running already by the value of index[1] --------
      • -------- --- --------
      • Set HS_index[1] = (HS_index[1] + 1)
      • -------- We increase the index we are going to use for checking is there an active spell going on --------
      • -------- --- --------
      • Set HS_index_selected = False
      • -------- We haven't selected the value of HS_dyn index which we are going to use for indexing so we set this to false --------
      • -------- --- --------
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • HS_dyn_index Less than (<) HS_index[2]
            • HS_index_is_empty[HS_dyn_index] Equal to (==) True
            • HS_dyn_index Not equal to (!=) 0
          • Then - Actions
            • -------- If the conditions are true that mean we already declared a HS_dyn_index in the loop trigger and it's unused so we don't set the HS_dyn index to any other value, we just simply leave it at the current value and set HS_index_selected = true --------
            • Set HS_index_selected = True
          • Else - Actions
            • Do Multiple ActionsFor each (Integer HS_index[0]) from 1 to HS_index[2], do (Actions)
              • Loop - Actions
                • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  • If - Conditions
                    • HS_index_selected Equal to (==) False
                    • HS_index_is_empty[HS_index[0]] Equal to (==) True
                  • Then - Actions
                    • -------- If we have found an unused array and the HS_dyn_index isn't already selected we set the HS_dyn_index to that value and set the HS_index_selected to true to make sure the loop stops --------
                    • Set HS_dyn_index = HS_index[0]
                    • -------- We set the value of the dynamic index to first empty array value and declare that we have selected the index --------
                    • -------- --- --------
                    • Set HS_index_selected = True
                    • -------- We declare that the index is selected so the loop stops --------
                  • Else - Actions
            • -------- We cycle throug HS_index[2] searching for an empty index by using HS_index_is_empy boolean, i am going to use HS_index[0] for cycling in this case --------
            • -------- --- --------
              • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • HS_index_selected Equal to (==) False
                • Then - Actions
                  • -------- If HS_index_selected is false that means we didn't found any free array value so we increase the value of HS_index[2] and set the value of HS_dyn_index to it so we avoid conflicts --------
                  • Set HS_index[2] = (HS_index[2] + 1)
                  • -------- Increasing HS_index[2] value by 1 --------
                  • -------- --- --------
                  • Set HS_dyn_index = HS_index[2]
                  • -------- Setting the HS_dyn_index to the value of HS_index[2] --------
                • Else - Actions
            • -------- If there weren't any free array value when we cycled through the HS_index[2] we increase the HS_index[2] value and set the HS_dyn_index to match the value of HS_index[2] --------
      • Game - Display to (All players) the text: (Debug Message: Storing Index Value: + (String(HS_dyn_index)))
      • -------- Dynamic Index Recycling --------
      • Set HS_index_is_empty[HS_dyn_index] = False
      • -------- We now set the HS_index_is_empty to false cause we are going to use the HS_dyn_index for an array for indexing --------
      • -------- --- --------
      • Set damage_source[HS_dyn_index] = (Casting unit)
      • -------- we store the caster for damaging unit refrence --------
      • -------- --- --------
      • Set target[HS_dyn_index] = (Target unit of ability being cast)
      • -------- we store the target for the periodic events --------
      • -------- --- --------
      • Set damage_interval[HS_dyn_index] = (1.25 - (0.25 x (Real((Level of (Ability being cast) for (Casting unit))))))
      • -------- we define the damage interval --------
      • -------- --- --------
      • Set dpi[HS_dyn_index] = (10.00 + (5.00 x (Real((Level of (Ability being cast) for (Casting unit))))))
      • -------- we define the damage dealt per interval to the target --------
      • -------- --- --------
      • Set duration[HS_dyn_index] = (5.00 + (5.00 x (Real((Level of (Ability being cast) for (Casting unit))))))
      • -------- we define the spell duration --------
      • -------- --- --------
      • Set dpi_effect = Objects\Spawnmodels\Human\HumanBlood\HumanBloodFootman.mdl
      • -------- on the end we define the periodic damage effect string this shouldn't need to be a array variable if you don't plan on changing it depending on the spell level --------
      • -------- --- --------
      • Set interval_check[HS_dyn_index] = 0.00
      • -------- variable used for damage interval checking --------
The trigger is well commented but if you have any additional questions feel free ask in this thread or send me a private message.
Now we aren't finished we still need to dynamicaly free the index arrays when they aren't used we will do so in the loop trigger:
  • loop
    • Events
      • Time - Every 0.25 seconds of game time
    • Conditions
    • Actions
      • Do Multiple ActionsFor each (Integer HS_index[3]) from 1 to HS_index[2], do (Actions)
        • Loop - Actions
          • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • duration[HS_index[3]] Greater than (>) 0.00
            • Then - Actions
              • Set duration[HS_index[3]] = (duration[HS_index[3]] - 0.25)
              • -------- we decrease the spell duration by 0.25 --------
              • -------- --- --------
              • Set interval_check[HS_index[3]] = (interval_check[HS_index[3]] + 0.25)
              • -------- we increase the interval_check variable --------
              • -------- --- --------
                • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  • If - Conditions
                    • interval_check[HS_index[3]] Greater than or equal to (>=) damage_interval[HS_index[3]]
                  • Then - Actions
                    • Set interval_check[HS_index[3]] = 0.00
                    • -------- we reset the interval_check variable --------
                    • -------- --- --------
                      • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (target[HS_index[3]] is alive) Equal to (==) True
                        • Then - Actions
                          • Unit - Cause damage_source[HS_index[3]] to damage target[HS_index[3]], dealing dpi[HS_index[3]] damage of attack type Spells and damage type Normal
                          • -------- we damage the target dealing damage per interval --------
                          • -------- --- --------
                          • Special Effect - Create a special effect attached to the chest of target[HS_index[3]] using dpi_effect
                          • Special Effect - Destroy (Last created special effect)
                          • -------- we create and destroy the periodic damage effect on the unit, i prefer using chest attach point --------
                        • Else - Actions
                          • Set duration[HS_index[3]] = 0.00
                    • -------- if the target is alive we do actions if not we set the spell duration to 0 --------
                  • Else - Actions
              • -------- if the interval_check is equal or larger than damage interval we do actions --------
              • -------- --- --------
                • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  • If - Conditions
                    • duration[HS_index[3]] Less than or equal to (<=) 0.00
                  • Then - Actions
                    • Set HS_index[1] = (HS_index[1] - 1)
                    • -------- we reduce the index[1] variable cause one spell instance has ended --------
                    • -------- --- --------
                    • Set HS_index_is_empty[HS_index[3]] = True
                    • -------- This spell instance has finished it's effect and we "free" the array using this variable --------
                    • -------- --- --------
                      • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • HS_index_selected Equal to (==) False
                        • Then - Actions
                          • Set HS_dyn_index = HS_index[3]
                          • -------- We set the HS_dyn_index to an value of this index so the next time when the spell is cast it has an value of an array that is not taken --------
                          • -------- --- --------
                          • Set HS_index_selected = True
                          • -------- We have just set an value for HS_dyn_index so we have selected the index we are going to use the next time a spell using this indexing is cast --------
                        • Else - Actions
                    • -------- --- --------
                      • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • HS_index[1] Not equal to (!=) 0
                          • HS_index[3] Equal to (==) HS_index[2]
                        • Then - Actions
                          • Set HS_index[2] = (HS_index[2] - 1)
                          • Game - Display to (All players) the text: Debug Message: Loop...
                        • Else - Actions
                    • -------- If this is the spell instance which uses the highest value of HS_index[2] we can reduce the HS_index[2] value to shorten the loop process --------
                    • -------- --- --------
                      • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • HS_index[1] Equal to (==) 0
                        • Then - Actions
                          • Set HS_index[2] = 0
                          • -------- we reset the index[2] to 0 cause there aren't any active spells running --------
                          • -------- --- --------
                          • Set HS_dyn_index = 0
                          • -------- We also reset the HS_dyn_index to 0 --------
                          • -------- --- --------
                          • Trigger - Turn off (This trigger)
                          • -------- we turn off this trigger, it is pointless for it to run if there isn't any spell for it to affect --------
                          • -------- --- --------
                          • Game - Display to (All players) the text: off
                          • -------- we can display a "debug" message to check will the trigger turn off when there aren't any other active spell --------
                        • Else - Actions
                    • -------- if the index[1] is 0 there are no active spell and we do actions --------
                  • Else - Actions
              • -------- if the spell duration is 0 we do actions --------
            • Else - Actions
              • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • HS_index[1] Not equal to (!=) 0
                  • HS_index[3] Equal to (==) HS_index[2]
                • Then - Actions
                  • Set HS_index[2] = (HS_index[2] - 1)
                  • Game - Display to (All players) the text: Debug Message: Loop...
                • Else - Actions
              • -------- If this is the spell instance which uses the highest value of HS_index[2] we can reduce the HS_index[2] value to shorten the loop process and cause it didn't mathc the condition it means it isn't doing anything so we decrease the index --------
To test dynamic indexing recycling i have made a timer and a debug message in the demo map.
This way there is a possibility to exceed maximum array size and to do it you must:
  • Cast the spell every 1 second
  • If we take the spell lasts 15 seconds that means 15 instances per unit max
  • So that means you will exceed the array limit if you have about 550 units casting the spell in the same time every single second
Possible but i think only in theory.
I think the tutorial may be aproved now that i fixed the issue and implanted Dynamic Index Recycling in the tutorial.
Demo Map:
http://www.hiveworkshop.com/forums/attachment.php?attachmentid=52319&stc=1&d=1239786126
NOTE: The name of the map is MUI example 4 cause i deleted a part of my tutorial that had the MUI example 3 map.
Credits:
Moyack for the parabola formula

Now this is where the tutorial ends for now. I may add more informations and chapters but for now this should do.
I hope this helped you^^
 

Attachments

  • MUI_example.w3x
    27.6 KB · Views: 967
  • MUI_example_2.w3x
    32.6 KB · Views: 603
  • MUI_example_4.w3x
    32.3 KB · Views: 611
  • PGS.w3x
    16.8 KB · Views: 819
Last edited by a moderator:
Level 16
Joined
Oct 12, 2008
Messages
1,570
Found one mistake in your whole thing ^^
and we decrease index[1] variable we will if the index[1] is equal to 0
At least i think it should have 'check' between 'will' and 'if'
But whatever! That is a minor thing,,

The tutorial is nice! You really explain how to use the indexing in more ways!
The only thing is readability, I myself would have set the triggers (and one jass function) in (hidden) (/hidden) taggs, since it reads easier and makes the post shorter (à vu, if you know what i mean),,
And i suggest next time you make the triggers and copy them ,cause some things arent like in normal WE (Or did you use a 3rd party tool?),, this is also for readability and for noobs that will ask: 'Where can you find the "(==)" part of that condition?'
But just a suggestion ;)

Other then this: A great tutorial which really explains why GUI isnt that bad after al! =D
+rep
 
Level 12
Joined
Sep 24, 2007
Messages
283
sure that it is impossible?
yes i am sure i tried one spell. It works but in sometime it will not work becouse of max array size(~~8000) so it will bug
i tried to recycle that spell. Well i will send you the spell and you will check if you want ^^


EDIT:
meh:
vBulletin Message
Invalid Attachment specified. If you followed a valid link, please notify the administrator
 
Level 25
Joined
Jun 5, 2008
Messages
2,572
@Yixx
Ah it shows like that to me...
I don't know why, possibly cause of the newgen + UMSWE + WEU it automaticaly adds that....
But i think the users won't have a hard time understanding that "equal to" is "==".

@All
Please tell me for any kind of bugs in the code/maps.
Feedback or suggestion are welcome.
Also i am from Serbia, it's not like my native language is English...
So cut the slack on the typos/grammar please...
 
  • Like
Reactions: Rmx

Rmx

Rmx

Level 19
Joined
Aug 27, 2007
Messages
1,164
BombShell Tutorial actually i learned something about unit Groups.

Also i have been using this system for a long time and it works 10/10.

Kingz GREAT JOB and + REP.

@Nidhogg-Kun and Palaslayer
Yes u can do a meat hook, i have done it and will be uploading it in my newest spellpack, also this system is BULETPROOF u can do everything with ;)

.....to all of ... look at the irony i made Paladon Judgment spell in GUI but not gonna upload it ;) .

Review : DO NOT NEED A REVIEW 10/10 ... OFC ....

BTW why this Parabola u can use Paladon system JUMP also it is 99% Parabola and more easy ;)
 
Level 30
Joined
Dec 6, 2007
Messages
2,228
good toturial but you forgot to say that there is no way to make Meathook ^^
i tried 3 times o_O

I made a meathook in GUI, of course multi unit instancable, some time ago.
Shall i search it for you?

Next to that, the tutorial looks good.

EDIT: Nidd, 8000 array limit, do you really need 8000 projectile (meathook) effects at the same time? o_O
 
Last edited:
Level 10
Joined
Jun 1, 2008
Messages
485
nice tutorial...
now I'm learning how to use (possibly make) MUI index.....
hmm, one question:
if (example) unit cast a long use spell that using this index (like triggered immolation) and there was unit that cast the same spell, and another unit cast it again, the first then finish it, and another cast it, etc.... and by any chance, the index[1] never drop to zero, and when it reach above 80000, it will cause bug, am i right?

and for the parabolic formula, why not use this:
y= (-x^2 + dx)/(d /((mh/d) * 4))

y is your current height and x is the distance from the jumping point that you're currently at. d is the total distance and mh is the max height you want. It's the perfect arc every time and I've already tested it and it works. every time.
he say this can be done in GUI and work.
[thread=18324]see the thread here[/thread]

Overall, great job. +rep
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Blah. Wasteful and doesn't work for a lot of implementations. You should look into how vJass allocates indexes and then implement that algorithm into GUI.

It's a nasty problem though. I wrote a tutorial using aforementioned method but some GUIers found it hard to understand because of that, while others (such as here) write tutorials using significantly worse methods that break down for many things, but are easier to understand.
 

Rmx

Rmx

Level 19
Joined
Aug 27, 2007
Messages
1,164
PurplePoot ur mistaken u like vJass very much but there is alot of GUIers.
And By the way when i learned the index system from Paladon and started to use
indexing and making my spells, after that i saw that JASS is much much easy than GUI.
Now i'm learning Jass and it's much easy to me after i learned GUI alot ;)

this Tutorial is GREAT ! A+ ..... i will accept it and approve it with my eyes closed x)
 
Last edited:
Level 40
Joined
Dec 14, 2005
Messages
10,532
(Kingz's post that I am quoting was posted on my profile, for those who are wondering)

Kingz said:
I really don't get your thinking? So what to write a GUI tutorial is lame but if i would write a vJASS one it would be good? I wrote the tutorial for GUI users not for JASS users...
Rmx said:
PurplePoot ur mistaken u like vJass very much but there is alot of GUIers.

Nowhere did I say you should do a tutorial in vJass. I said you should implement the vJass indexing algorithm in GUI.

Kingz said:
So it's you against the majority...
Apparently it is. And? The majority is not always correct.

Also, nowhere did I say it was awful. I said it was too circumstantial and not particularly well done.

Kingz said:
Anyway if not for a critique or a improvement suggestion i would like to ask you not to post any more of your thoughts...
If I did not have one or both, I would not post at all.
 
Level 10
Joined
Jun 1, 2008
Messages
485
@Mage-Goo

Well even if they cast it alot do u think in any kind of map there will be 8000 HERO with the same spell ???? also u can apply a Recycle system ;) to recycle ur spell so when someone finishes it will recycle him and drop -1 ;)
But, 3 heroes are enough to cause that. See my hidden tags
Imagine there are 3 heroes named 1, 2 and 3

Hero 1 cast
Index[1] = (0) + 1 = 1
Index[2] = (0) + 1 = 1
Given Index = Index [2] = 1

Hero 2 cast
Index[1] = (1) + 1 = 2
Index[2] = (1) + 1 = 2
Given Index = Index [2] = 2

Hero 1 Finish
Index[1] = (2) - 1 = 1
Index[2] = 2 (Not decreased)

Hero 3 cast
Index[1] = (1) + 1 = 2
Index[2] = (2) + 1 = 3
Given Index = Index [2] = 3

Hero 2 Finish
Index[1] = (2) - 1 = 1
Index[2] = (3) + 1 = 4

Going that again and again until many time

Hero 3 Cast
Index[1] = (1) + 1 = 2
Index[2] = (89.891) + 1 = 89.892
Given Index = Index[2] = 89.892 (surpass max array size!)
See? Index[2] need to decreased in some implementation. But, well it's rare to see spell act like this, but in system, it can like act like this.
good toturial but you forgot to say that there is no way to make Meathook ^^
i tried 3 times o_O
It's possible to make a meathook! I've see somebody make it! But from thehelper.net, and use Custom Value system, not indexing. but i think it can changed easily.
See the MeatHook Spell Here

-index[2] variable we are going to use for storing variables like units/damage/locations,etc. We are only going to increase it and never decrease it, why?
Imagine you have 2 spells running at the same time and you decrease the index[2] value and the second spells variables get mixed up with the first one.
So how to stop piling up of index[2] value? Easy when the spell effect finishes and we decrease index[1] variable we will if the index[1] is equal to 0(that means no spell instances are running)
and we can reset the index[2] to 0.
i second this. if you store some of the free index, you can avoid this. Like in [thread=96460]PurplePoot indexing system here.[/thread]
 
Last edited:
Level 40
Joined
Dec 14, 2005
Messages
10,532
Mage_Goo, just a quick comment, the maximum feasible array value is 8,190. 8,191 is possible but does not save via Save Game, and 8,192+ exceed the bounds of the array.

--

Meathook is entirely possible to be fully MUI with many systems. The way I would approach it is linked list-style, but there are other ways to do it as well.

--

Haha, I need to update that tutorial - I completely forgot about it, and the writing is kind of blah. But yeah, that's the current vJass allocator.
 

Rmx

Rmx

Level 19
Joined
Aug 27, 2007
Messages
1,164
@Mage-Goo
But, 3 heroes are enough to cause that. See my hidden tags

Algorithm
Imagine there are 3 heroes named 1, 2 and 3

Hero 1 cast
Index[1] = (0) + 1 = 1
Index[2] = (0) + 1 = 1
Given Index = Index [2] = 1

Hero 2 cast
Index[1] = (1) + 1 = 2
Index[2] = (1) + 1 = 2
Given Index = Index [2] = 2

Hero 1 Finish
Index[1] = (2) - 1 = 1
Index[2] = 2 (Not decreased)

Hero 3 cast
Index[1] = (1) + 1 = 2
Index[2] = (2) + 1 = 3
Given Index = Index [2] = 3

Hero 2 Finish
Index[1] = (2) - 1 = 1
Index[2] = (3) + 1 = 4

Going that again and again until many time

Hero 3 Cast
Index[1] = (1) + 1 = 2
Index[2] = (89.891) + 1 = 89.892
Given Index = Index[2] = 89.892 (surpass max array size!)
See? Index[2] need to decreased in some implementation. But, well it's rare to see spell act like this, but in system, it can like act like this.

Well Mage-Goo if u look at the triger index[2] is when a unit finishes that ability it will be -1 until it reaches 0 then index[1] = 0 so this resets everything ;)
 
Level 10
Joined
Jun 1, 2008
Messages
485
@Mage-Goo
Well Mage-Goo if u look at the triger index[2] is when a unit finishes that ability it will be -1 until it reaches 0 then index[1] = 0 so this resets everything ;)
Well, let me quote it
-index[2] variable we are going to use for storing variables like units/damage/locations,etc. We are only going to increase it and never decrease it, why?
Imagine you have 2 spells running at the same time and you decrease the index[2] value and the second spells variables get mixed up with the first one.
So how to stop piling up of index[2] value? Easy when the spell effect finishes and we decrease index[1] variable we will if the index[1] is equal to 0(that means no spell instances are running)
and we can reset the index[2] to 0.
it only reset when the Index[1] became 0, if not, it will just increasing and increase.

EDIT:
Mage_Goo, just a quick comment, the maximum feasible array value is 8,190. 8,191 is possible but does not save via Save Game, and 8,192+ exceed the bounds of the array.
That's just an example when the Index surpass the limit.
hmm, just question, what will happen when array surpass it?
If and only if index[1] ever hits 0 (for stuff such as long-lasting buffs it is perfectly reasonable for this to fail to occur).

Also, if index[2] starts getting high this system starts slowing quite a bit.
Exactly. This will need a better recycle system to recycle the Index[2]
 
Last edited:
Level 25
Joined
Jun 5, 2008
Messages
2,572
So what about another index instead of index[2] if it's value gets high?
Also i doubt it that people will ever have a problem with this system, i never saw a map with at least one spell instance at the time...
If i am wrong prove it by linking a map that has a spell that will never end or a replay where at least one spells instance is always active...

EDIT:
It's Paladon's integer array indexing system why should i change it's core?
I know JASS indexing rules(structs,scopes and stuff) but this is for GUI users...
I won't make changes cause the system is as it is and changing it would make it an another system, not the one i wrote the tutorial about...
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
hmm, just question, what will happen when array surpass it?
Very, very painful lag. Like, a ~.5 second freeze (depends on the computer really) every interval. Say that interval is less than the freeze. Let the insanely low FPS begin (not to say it isn't horrendously laggy otherwise).

--

We are suggesting you change the focus of the tutorial because the system is not particularly well designed.
 
Level 25
Joined
Jun 5, 2008
Messages
2,572
I won't change a thing...
Why, it never let me down, and i don't force people to use it, it's free choice...
Don't take me wrong i am all for efficency and stuff like laggles possibilities but i really don't have time to rethink the indexing system and rewrite the tutorial...
I barely had time for this + i am learning JASS so if i switch back and forth from GUI to JASS i will need 2x the time to write the tutorial, again...
So it will stay as it is...
 
I won't change a thing...
Why, it never let me down, and i don't force people to use it, it's free choice...
Don't take me wrong i am all for efficency and stuff like laggles possibilities but i really don't have time to rethink the indexing system and rewrite the tutorial...
I barely had time for this + i am learning JASS so if i switch back and forth from GUI to JASS i will need 2x the time to write the tutorial, again...
So it will stay as it is...

I'll graveyard this for now then. PM me when you want it moved back.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,178
Honestly, MUI is easy to do thanks to hash table emulation and the ability to recycle unique indexes in an array system. The problems generally faced is asigning a static index for units that can be freed and recycled. However that is very easy to do as you simply store the freed indexes in a non static system and fetch new indexes from that before adding one onto the end of the static array system. This ends up using quite a number of arrays but concidering modern PCs have GBs of RAM and a full 8192 indexed array (as if it should be anywhere near that) only uses 32KB, who cares.
 
Level 10
Joined
Jun 1, 2008
Messages
485
wow....
Now, it name has changed and the DIR system is awesome.... just great...

But, I'm wondering, What happen if it like this.
Say, there are 3 heroes

Cast
HS_index[1] = HS_index[1](0) + 1 = 1
HS_index[2] = HS_index[2](0) + 1 = 1
HS_dyn_index = HS_index[2] = 1
Array used = 1

Cast
HS_index[1] = HS_index[1](1) + 1 = 2
HS_index[2] = HS_index[2](1) + 1 = 2
HS_dyn_index = HS_index[2] = 2
Array used = 2

Cast
HS_index[1] = HS_index[1](2) + 1 = 3
HS_index[2] = HS_index[2](2) + 1 = 3
HS_dyn_index = HS_index[2] = 3
Array used = 3

Finish (Array 1)
HS_index[1] = HS_index[1](3) - 1 = 2
HS_dyn_index = HS_index[3] / Finished Array = 1
HS_index_is_empty[HS_index[3](1)] = True

Finish (Array 2)
HS_index[1] = HS_index[1](2) - 1 = 1
HS_dyn_index = HS_index[3] / Finished Array = 2
HS_index_is_empty[HS_index[3](2)] = True

Cast
HS_index[1] = HS_index[1](1) + 1 = 2
HS_dyn_index = 2 (has selected)
HS_index_is_empty[HS_dyn_index(2)] = still True!

Cast
HS_index[1] = HS_index[1](2) + 1 = 3
HS_dyn_index = 1 (we search it through array)
HS_index_is_empty[HS_dyn_index(1)] = True! you forgot to set it to false!

Cast
HS_index[1] = HS_index[1](3) + 1 = 4
HS_dyn_index = 1 (we search it through array, this index is in use!)
HS_index_is_empty[HS_dyn_index(1)] = still True!

And, if casted again and again, it will just get 1!

The only problem I've revealed is when you get the Free Index through loop, you still set the HS_index_is_empty to true, just set it to false when you get it.
I don't see another problem. Great Job.
 
Level 25
Joined
Jun 5, 2008
Messages
2,572
When i talked to Pyritie he said that they are existant but invalid cuz the tutorial is in graveyard...
Now it isn't in graveyard and they still don't work and it's a pain to upload stuff with a 56Kb/s speed...
Oh well, uploading again...
EDIT: Reuploaded all my attachments
 
Level 24
Joined
Jun 16, 2008
Messages
1,939
hey, i thought a little about index recycling and i think there is a much better way to recycle used variables though i might not have understood yours so maybe they both are the same ^^

we asign a boolean to each index[2] and if that boolean is true than the index is still in use. ofc the boolean is set to false if the spell for index[2] is set to false when the spell is finished.

then, in the init trigger, we use a loop from 1 to index[2] (should be clear) and check whether it is true or false. if it is false then we assign all normal variables to that index[2] as we do normally and set it to true again.

we will still use the normal indexing though, with index[1] lowering and so on. of course, this is only a raw thought and not worked out yet. think about it.
 
Top