- Joined
- Nov 11, 2006
- Messages
- 7,647
Contents |
Introduction |
Dynamic indexing is a technique used to ensure that your spell or code can be ran multiple times without any MUI issues. At first, it is incredibly daunting to look at. This tutorial aims to show it in a better light: de-complicating the complicated. Before we go into dynamic indexing, you should understand its purpose. The main reason is to achieve MUI, the goal that all non-failing spell-makers should hope to achieve. |
MUI |
MUI stands for Multiple Unit Instanceability. That is its only purpose: make a spell able to be cast by multiple units (without undesired behavior). What are these so-called MUI-issues that I speak of? Well, let's consider a simple timed spell that transfers health every 0.1 seconds. |
Seems simple enough. You would start a timer when the spell starts to loop every 0.1 seconds. In the loop, you would damage the target for 2 hit points, and give 2 hit points to the caster:
|
(The circle in the bottom right shows how much time has elapsed) |
But what do you think would happen when another caster comes in? |
Now the original caster doesn't get any HP, and hogger only takes 2 damage per tick instead of 4 (2 + 2). Why? Look at the trigger above. When the spell is cast, SL_Caster is set to the casting unit. Since variables can only point to one thing at a time, the original caster (green) is overwritten. Not only that, but the target is overwritten, and the counter is reset to 0. This illustrates why we need MUI. Without it, hogger doesn't experience as much pain as he should. |
Dynamic Indexing |
There are many ways to achieve MUI. Dynamic indexing is just one way. It involves arrays and one index per spell cast. The first thing to do is to figure out what variables you need to store. In our case, we should store:
during the periodic. If you only need the data when the spell is first cast, you don't need to save it. Instead of making single variables, we will convert them into arrays: |
Now, the goal of dynamic indexing is to have one index per spell cast. In the periodic trigger, you will loop through every active spell cast (known as an instance of a spell). An instance usually refers to one spell cast, and it will be associated with the index that is used. The first instance of a spell will have an index of 1, the second will have an index of 2. When we talk about multi-instanceability, we are basically saying that the spell should work with multiple-spell casts at the same time. For example, if you have 3 spell instances, this is how it will look: |
As you loop through the instances, you'll have a different caster and target to deal with. Here is some pseudo code:
it will refer to the first instance (see picture above). When SL_Loop_Integer is 2, it will refer to the second instance. Same for the third. Now, that code is specific. It loops through only 3 instances. But what if we want 5? Or 10? Or just 1? The point of dynamic indexing is to make a general form that will work for all cases. How do we do that? Simple, we must make an integer variable to keep track of the instances: SL_Index (Name) - Integer (Type) - 0 (Initial Value) So how do we go about setting this up? Well, first we have to worry about allocation. Allocation is the process of getting a new index and assigning the variables we need to. Since we have an order of 1, 2, 3, etc.. we just need to increment the index once each time a spell is cast. Consider the following scenario. The spell is cast by a dark ranger onto a hawk, a blood mage onto a pit lord, a firelord onto a skeleton, and a sea witch onto a clockwerk goblin: |
The above picture will show what it should look like on allocation. When the spell is cast by the dark ranger, the index should be 1. SL_Caster[1] should be the dark ranger. SL_Target[1] should be the hawk. SL_Counter[1] should be 0.0. So forth with the other indexes. Here is the trigger:
for that particular instance. For index 1, the caster will be the dark ranger, the target will be the hawk, and the counter will be 0. Same for the other instances, as shown in the picture above. How about the actual looping? It is the same as we did far above, but instead of looping up to 3, we just loop up to SL_Index. Why? If you think about it, SL_Index actually keeps track of the number of spell instances. When the first spell is cast, the index is set to 1. When the second is cast, the index is 2. When the fourth is cast, the index is 4. etc. As for the last lines, it turns on the periodic loop when the first instance is made. You may wonder why I don't turn it on initially–don't worry about it. That will be important later. Now we will move on to the looping. (This trigger should be initially off)
(Integer A). It loops up to SL_Index, basically going through each instance up until the last one. SL_Caster[SL_Loop_Integer] will be the caster for that instance. Same for the other variables. That trigger will loop through the instance and perform the actions for every spell instance. You may be wondering why I left the "Then" actions empty. What do we do when the spell is over? We must deallocate the instance. Otherwise, the spell will keep running on the finished instance pointlessly. It will also ensure that SL_Index won't keep going up and up (max array index is 8191). So how do we do that? We overwrite the instance-to-delete with the last instance, and then we set the loop and SL_Index back 1 (so that it will run that instance). This is what it will look like: |
As you can see, the blood mage finished his life-sucking (for now). So now the sea witch should take his spot. Our goal: get the sea witch to have index 2 (overwrite blood mage). Then reduce the index and iterator (SL_Loop_Index) by 1. This is how it will look:
|
That takes care of that. But what about reducing the index and the loop integer? Why do we do that? Well, this is how it would look like right after we overwrite instance 2: |
Now that we've overwritten slot 2, we must reduce SL_Index because we don't need instance 4. SL_Index = SL_Index - 1, which is: 4 - 1 = 3. Here is what it will look like: |
Now the problem is that instance 2 is over! The sea witch never got her turn! Thus, we must set SL_Loop_Integer back so that the sea witch's instance will run: |
Finally, we've finished! The spell should work correctly. If you cast another spell, the index will takeslot 4, which we have no issue with. Now the spell works, but there is one thing we can do for efficiency. If there are no active instances, we should turn off the trigger. Otherwise it will loop needlessly. Here are the final triggers:
|
Comparison |
A lot of people ask how dynamic indexing compares to other methods. The important thing to remember that this is a matter of nanoseconds and can vary from situation to situation, but in general:
|
Credits |
|
Attachments
-
Dy.png6 KB · Views: 6,415
-
SiphonTooltip.png50.1 KB · Views: 4,273
-
SiphonHogger.png79.8 KB · Views: 4,165
-
SiphonHogger2.png129 KB · Views: 4,273
-
Variables.png9.6 KB · Views: 4,069
-
Instances.png28.6 KB · Views: 4,148
-
InstanceList.png114.8 KB · Views: 4,226
-
InstanceList2.png110.3 KB · Views: 4,300
-
InstanceList3.png113.1 KB · Views: 4,195
-
InstanceList4.png89.7 KB · Views: 4,243
-
InstanceList5.png86.4 KB · Views: 4,116
-
Deallocate.png59.9 KB · Views: 3,991
Last edited: