1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. The Lich King demands your service! We've reached the 19th edition of the Icon Contest. Come along and make some chilling servants for the one true king.
    Dismiss Notice
  4. The 4th SFX Contest has started. Be sure to participate and have a fun factor in it.
    Dismiss Notice
  5. The poll for the 21st Terraining Contest is LIVE. Be sure to check out the entries and vote for one.
    Dismiss Notice
  6. The results are out! Check them out.
    Dismiss Notice
  7. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  8. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  9. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

MUI Spells Using Artificial Waits

Discussion in 'Trigger (GUI) Editor Tutorials' started by Tank-Commander, Sep 28, 2012.

  1. Tank-Commander

    Tank-Commander

    Spell Reviewer

    Joined:
    May 26, 2009
    Messages:
    1,539
    Resources:
    44
    Packs:
    1
    Spells:
    41
    Tutorials:
    2
    Resources:
    44
    Introduction

    Creating delayed spell effects that are MUI without the use of waits is fairly
    simple. It just requires two variables and one periodic trigger. The first variable
    is an integer that represents the current spell instance, whereas the second variable
    is an integer that represents the total number of spell instances.

    Avoiding Waits

    This is an example of a spell that uses a Wait action in order to create a delayed effect:

    Example
    • Example
      • Events
        • Unit - A unit Starts the effect of an ability
      • Conditions
        • (Ability being cast) Equal to Example
      • Actions
        • Set TempUnit = (Triggering unit)
        • Set TempPoint = (Target point of ability being cast)
        • Wait 2.00 seconds
        • Set TempGroup = (Units within 300.00 of TempPoint)
        • Unit Group - Pick every unit in TempGroup and do (Actions)
          • Loop - Actions
            • Unit - Cause TempUnit to damage (Picked unit), dealing 50.00 damage of attack type Spells and damage type Normal
        • Custom script: call DestroyGroup(udg_TempGroup)
        • Custom script: call RemoveLocation(udg_TempPoint)


    This spell is not MUI and will give an inaccurate delay. In order to fix this, we
    need to split this spell into two triggers. The first trigger will execute when the
    spell is cast, and it will store spell data such as the caster, the level, the owner
    of the caster, etc... The second trigger is going to have a periodic event. Let's make
    it run every 1 second for simplicity as opposed to the 0.03 seconds used by most spell
    makers. If you're going to make a timed spell, use 0.03. What we're going to do is add
    one spell instance when the spell is cast, and iterate over all the spell instances in
    the periodic trigger. It's basic indexing, and it looks like this:

    Triggers
    • Cast
      • Events
        • Unit - A unit Starts the effect of an ability
      • Conditions
        • (Ability being cast) Equal to Animate Dead
      • Actions
        • Set MaxIndex = (MaxIndex + 1)
        • -------- Here's the bit we had in the first place before the wait --------
        • Set TempUnit[MaxIndex] = (Triggering unit)
        • Set TempPoint[MaxIndex] = (Position of TempUnit[MaxIndex])
        • -------- ----------------- --------
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • MaxIndex Equal to 1
          • Then - Actions
            • Trigger - Turn on Loop <gen>
          • Else - Actions


    • Loop
      • Events
        • Time - Every 1.00 seconds of game time
      • Conditions
      • Actions
        • For each (Integer CurrentIndex) from 1 to MaxIndex, do (Actions)
          • Loop - Actions
            • -------- Here's the bit we had in the first place after the wait --------
            • Set TempGroup = (Units within 200.00 of TempPoint[CurrentIndex])
            • Unit Group - Pick every unit in TempGroup and do (Actions)
              • Loop - Actions
                • Unit - Cause TempUnit[CurrentIndex] to damage (Picked unit), dealing 50.00 damage of attack type Spells and damage type Normal
            • Custom script: call DestroyGroup(udg_TempGroup)
            • -------- This is recycling. It's unimportant in terms of spell effects, but it is important in terms of MU-Instancability --------
            • Custom script: call RemoveLocation(udg_TempPoint[udg_CurrentIndex])
            • Set TempPoint[CurrentIndex] = TempPoint[MaxIndex]
            • Set TempUnit[CurrentIndex] = TempUnit[MaxIndex]
            • Set MaxIndex = (MaxIndex - 1)
            • Set CurrentIndex = (CurrentIndex - 1)
            • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • MaxIndex Equal to 0
              • Then - Actions
                • Trigger - Turn off (This trigger)
              • Else - Actions


    There we go, this is our spell. 100% MUI and functional.

    Using a Counter

    This spell will wait 1 second, not 2. This is a problem that can
    be addressed by using a counter.

    In the caster trigger, we're going to set our counter to 0, and
    in the periodic trigger, we're going to increment our counter by 1.
    If the counter reaches our desired value, we execute the remaining
    code and end the spell instance.

    This is what our final product would look like:

    Final Triggers
    • Cast
      • Events
        • Unit - A unit Starts the effect of an ability
      • Conditions
        • (Ability being cast) Equal to Animate Dead
      • Actions
        • Set MaxIndex = (MaxIndex + 1)
        • -------- Here's the bit we had in the first place before the wait --------
        • Set TempUnit[MaxIndex] = (Triggering unit)
        • Set TempPoint[MaxIndex] = (Position of TempUnit[MaxIndex])
        • Set Counter[MaxIndex] = 0
        • -------- ----------------- --------
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • MaxIndex Equal to 1
          • Then - Actions
            • Trigger - Turn on Loop <gen>
          • Else - Actions


    • Loop
      • Events
        • Time - Every 1.00 seconds of game time
      • Conditions
      • Actions
        • For each (Integer CurrentIndex) from 1 to MaxIndex, do (Actions)
          • Loop - Actions
            • Set Counter[CurrentIndex] = (Counter[CurrentIndex] + 1)
            • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • Counter[CurrentIndex] Equal to 2
              • Then - Actions
                • -------- Here's the bit we had in the first place after the wait --------
                • Set TempGroup = (Units within 200.00 of TempPoint[CurrentIndex])
                • Unit Group - Pick every unit in TempGroup and do (Actions)
                  • Loop - Actions
                    • Unit - Cause TempUnit[CurrentIndex] to damage (Picked unit), dealing 50.00 damage of attack type Spells and damage type Normal
                • Custom script: call DestroyGroup(udg_TempGroup)
                • -------- Recycling --------
                • Custom script: call RemoveLocation(udg_TempPoint[udg_CurrentIndex])
                • Set TempPoint[CurrentIndex] = TempPoint[MaxIndex]
                • Set TempUnit[CurrentIndex] = TempUnit[MaxIndex]
                • Set Counter[CurrentIndex] = Counter[MaxIndex]
                • Set MaxIndex = (MaxIndex - 1)
                • Set CurrentIndex = (CurrentIndex - 1)
                • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  • If - Conditions
                    • MaxIndex Equal to 0
                  • Then - Actions
                    • Trigger - Turn off (This trigger)
                  • Else - Actions
              • Else - Actions


    Overview

    This is a small explanation concerning what will actually happen during the
    execution of the spell to clear things up for you if you didn't get it yet.

    Algorithm
    Let MaxCounter = 2.

    1) The spell has been cast.

    2) After 1 second:
    • Counter is initially 0.
    • Counter = Counter + 1
    • Counter is now 1.
    • Counter < MaxCounter
    • Nothing happens.

    3) After 2 seconds:
    • Counter is initially 1.
    • Counter = Counter + 1
    • Counter is now 2.
    • Counter == MaxCounter
    • Actions execute.
    • Spell instance recycled.

    This spell is now MUI and works for our desired delay duration.


    Wrap-up

    If you still find it hard to understand, feel free to PM me any time.
    Thank you for reading.

    ~Tank-Commander
     
  2. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Thank you for submitting this.

    I replaced the content in my tutorial in the "MUI without Waits" section with a link to this.

    Since my tutorial was approved, I guess this one is supposed to be approved by default as well, but as a form of respect to Purgeandfire111, I'll leave this in the Submissions section for him approve himself :p
     
  3. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,426
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Nice job. It all looks fine to me and is explained well. Approved.
     
  4. T. D. W.

    T. D. W.

    Joined:
    Jul 31, 2012
    Messages:
    1,505
    Resources:
    5
    Spells:
    5
    Resources:
    5
    I am not good at MUI but there is something i know good:

    Loop with 1 second loop is not accurate he does not start looping when you turn it on if he was off

    i knew that by accident when i had a loop trigger every 30 s if i turned it on the 20 s of game time he will execute after 10 seconds

    So the only "accurate loop" is 0.01 s [spells]
     
  5. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    That applies to loop triggers because they are started and turned off I guess, so internally, the code just wouldn't execute while they tick away (If this is even true)
    For timers, it's different because you start them up and pause them, then restart when you want to continue.
     
  6. Tank-Commander

    Tank-Commander

    Spell Reviewer

    Joined:
    May 26, 2009
    Messages:
    1,539
    Resources:
    44
    Packs:
    1
    Spells:
    41
    Tutorials:
    2
    Resources:
    44
    Read context first, then comment
     
  7. MasterTrainer

    MasterTrainer

    Joined:
    Apr 14, 2012
    Messages:
    2,768
    Resources:
    3
    Icons:
    1
    Maps:
    1
    Spells:
    1
    Resources:
    3
    This really helped me; thanks Tank-Commander!
     
  8. BlackShadows

    BlackShadows

    Joined:
    Jun 11, 2013
    Messages:
    2
    Resources:
    0
    Resources:
    0
    do we need to add this?
    • Custom script: call RemoveLocation(udg_TempPoint[Current_Index])

    :vw_wtf:
     
  9. Tank-Commander

    Tank-Commander

    Spell Reviewer

    Joined:
    May 26, 2009
    Messages:
    1,539
    Resources:
    44
    Packs:
    1
    Spells:
    41
    Tutorials:
    2
    Resources:
    44
    That's a line to remove the leak before recycling, that's only necessary if you have a location that needs to be removed (see leak-based tutorials). It's not necessary to specifically artificial waits no.
     
  10. DivineLight

    DivineLight

    Joined:
    Jan 30, 2012
    Messages:
    845
    Resources:
    1
    Spells:
    1
    Resources:
    1
    i tried this and when i use the
    • Custom script: call RemoveLocation(udg_TempPoint[Current_Index])

    and save it, WE rejected it..
    i mean it displaying an error message
    why could that happen? :eekani:
     
  11. Tank-Commander

    Tank-Commander

    Spell Reviewer

    Joined:
    May 26, 2009
    Messages:
    1,539
    Resources:
    44
    Packs:
    1
    Spells:
    41
    Tutorials:
    2
    Resources:
    44
    If you're following the tutorial spell, you should have a variable called udg_TempPoint of type point which is an array, if you have that line -without- a variable to relate it to, WE will reject it
     
  12. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    It's not Current_Index, it's udg_CurrentIndex (or udg_Current_Index if you named the variable Current_Index in the variable editor)

    All variables created with the Variable Editor are referenced in JASS with an udg_ prefix.
     
  13. DivineLight

    DivineLight

    Joined:
    Jan 30, 2012
    Messages:
    845
    Resources:
    1
    Spells:
    1
    Resources:
    1
    so something like this?
    • Custom script: call RemoveLocation(udg_TempPoint[udg_Current_Index])


    hey mag, don't talk about jass please..
    i don't understand any of it :vw_death:
    super confusing............ at least to me :grin:

    back to topic so everything related to variable use the udg_prefix i suppose?
     
    Last edited: Jun 21, 2013
  14. Tank-Commander

    Tank-Commander

    Spell Reviewer

    Joined:
    May 26, 2009
    Messages:
    1,539
    Resources:
    44
    Packs:
    1
    Spells:
    41
    Tutorials:
    2
    Resources:
    44
    if it's done in a custom script line and you're using GUI, then yes.
     
  15. deathismyfriend

    deathismyfriend

    Joined:
    Oct 24, 2012
    Messages:
    6,529
    Resources:
    14
    Spells:
    12
    Tutorials:
    2
    Resources:
    14
    that custom script line is jass thats y he said referenced in jass
     
  16. MasterTrainer

    MasterTrainer

    Joined:
    Apr 14, 2012
    Messages:
    2,768
    Resources:
    3
    Icons:
    1
    Maps:
    1
    Spells:
    1
    Resources:
    3
    Hello Tank_Commander :D
    I know you've told me the answer to this question, but I would really appreciate it again if you or someone else with experience reiterated the answer to me again:

    Your tutorial only tells me how to efficiently use 1 counter in an MUI spell; what if I wanted to use multiple counters to differentiate and separate different stages of my spell?

    Also, I've pondered on this question for a while now:
    In the case that I have to use more than a Cast and a Loop trigger, and I add a Loop 2 trigger, where do I de-index or recycle my variables? Or do most cases in spell making avoid having a Loop 2 trigger because of multiple counters?

    I would love some feedback here, I would really appreciate it.
     
  17. deathismyfriend

    deathismyfriend

    Joined:
    Oct 24, 2012
    Messages:
    6,529
    Resources:
    14
    Spells:
    12
    Tutorials:
    2
    Resources:
    14
    u can use one counter for the whole of ur multistage spell.
    use a counter to count up to 50 then it finishes stage one so u do the actions. then it continues to count to 100 then it finishes stage 2 and u do actions. and so on.

    just remember to structure ur ITE the right way or it wont work properly
     
  18. MasterTrainer

    MasterTrainer

    Joined:
    Apr 14, 2012
    Messages:
    2,768
    Resources:
    3
    Icons:
    1
    Maps:
    1
    Spells:
    1
    Resources:
    3
    Yes I remember one part of TC's messages to me were about the structures of the ITEs; something about nesting and stuff; could you please elaborate more deathismyfriend?
     
  19. deathismyfriend

    deathismyfriend

    Joined:
    Oct 24, 2012
    Messages:
    6,529
    Resources:
    14
    Spells:
    12
    Tutorials:
    2
    Resources:
    14
    im on phone so ill do best i can. basically u just have a few ITEs were ur smallest value is last. this way it will only run once.
    example:
    • Set counter = counter + 1
    • if
      • counter equal to 200
    • then
    • else
      • if
        • counter equal to 150
      • then
      • else
        • if
          • counter equal to 100
        • then
        • else
          • if
            • counter equal to 50
          • then
          • else


    this way the counter counts up and hits the first option selected. i use equal to which means that it will only run when its equal to that number. if u want actions in there then u would need to use greater than or equal to. dont use less than or equal to in this case.
    u can use less than ( notequal to) but u would have to switch the code around so that the smaller numbers go first. then u can use less than
     
  20. MasterTrainer

    MasterTrainer

    Joined:
    Apr 14, 2012
    Messages:
    2,768
    Resources:
    3
    Icons:
    1
    Maps:
    1
    Spells:
    1
    Resources:
    3
    ^ Thanks a lot; I'm going to try it out :D
    +REP