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 Triggers with Waits

Discussion in 'Trigger (GUI) Editor Tutorials' started by Magtheridon96, Jun 26, 2012.

  1. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    MUI Triggers with Waits

    Disclaimer: This is not an acceptable form for Spell/System resources.
    It is only meant for map-making.

    Go here instead.

    Table of Contents

    Introduction

    Good morning reader, or if it's not morning at the moment
    while you're reading this, good evening! Then again, it might
    be just around noon, so in that case, Good day! What I'm
    trying to say is... Bah, how about a simple "Hello"? That
    applies to all readers in all timezones and places at all times.

    Hello. :)

    Since you might be new here, I'm going to explain to you exactly
    why I made this tutorial. If you've never made a spell or a system
    before (Yes! You can actually make custom spells with Warcraft III
    and custom systems. Cool, right?), then you're probably psyched
    right about now after reading the previous text in parenthesis.

    Before I move on, if your understanding of the French language is
    far more developed than your understanding of English, I'd recommend
    this made by our very own Troll-Brain.

    What is 'MUI'?

    MUI is an acronym for "Melons United International". It is a secret
    organization bent on the annihilation of the human race so that
    melons may take over and CLAIM POWER THEN VOYAGE TO THE STA-

    Oh, sorry, forget everything I said, I didn't know we were talking
    about JASS. Anyway, MUI means "Multi-unit Instanceability". It's
    an attribute we give to a spell or a system indicating that it can
    actually work for more than one unit. In the spell case, it means
    that two units can cast the spell at the same time and still have
    it working. In the systems case, it means that it can handle two
    units or more.

    MPI means the same thing, except it refers to player-handling.
    (And certainly not Mango world domination or anything like that.
    What a silly thought, why are you even asking? LET'S MOVE ON
    SHALL WE?)

    An example of a system that needs to be MPI is a Custom Fullscreen
    Inventory system. (If you're new here and you're reading this, you
    probably need new pants right about now. It's okay, I'll reserve the
    rest of the information for the next section. Go on, you may discard
    your current pair, I'M CERTAINLY NOT WATCHING YOU.)

    ... Well? Move along now.

    The Problem

    As a 14-year old child with a dream to become the best spell-writer
    ever, I came to Hive so I can submit a resource of mine. That day,
    I learned of a new dark side to something I've loved for a very long
    time.

    I started Warcraft III modding when I was an 11-year old child. One
    of my favorite GUI actions was the "Wait" action. I used it excessively,
    but on that day, I learned that it's one of the worst things you could
    use in a trigger.

    If you're new, this is probably news for you:
    Using waits can make a trigger Non-MUI in a lot of cases

    Terrible, right? Crying won't help, and isn't very necessary, after all,
    I didn't make this tutorial to speak of the problem, I made it to address
    and fix the problem.

    Yes! There's hope!

    The Solution

    I'm going to teach you how to make YOUR triggers MUI in 3 easy steps!
    Sorry, I didn't mean to make it sound like a Penal Enlarging Ad, this is a GUI
    tutorial, so let's get back on topic, shall we?

    Okay, for new users, this is going to seem difficult, but it's actually
    very simple. I'm going to introduce you to the concept of the solution
    first.

    Do you know what a buffer is?
    A buffer is basically an array of data. I can write data to a buffer,
    then read it in the same order that I wrote it.

    What we're going to do in order to address the Wait-MUI problem is
    use a buffer for all the data. The main reason this problem arises is
    because of data modifications. There are certain things in GUI that
    remain unchanged after waits, and others that change depending on
    what's going on in the map.

    An example of something that remains constant: (Triggering unit)
    An example of something that changes: (Last created unit)

    The triggering unit is different for each trigger execution, so it remains
    constant, but the last created unit is pretty much a variable that gets
    set every time you create a unit with the BJ function (meaning the GUI
    create unit action).

    Using (Triggering unit) as is will work after a "Wait", but since you're
    often going to store that into a unit variable, it's not going to work well.

    Let's begin.

    Non-MUI
    • Bad Trigger
      • Events
        • Unit - A unit starts the effects of a spell
      • Conditions
        • (Ability being cast) Equal to MyDerpyAbility
      • Actions
        • Set caster = (Triggering unit)
        • Wait 5.00 seconds
        • Unit - Remove caster from the game


    This trigger will not work correctly if our ability is cast twice in a row with an interval less than 5 seconds.
    Let's investigate why, shall we?

    What's going on?

    Imagine we have two units on the map, just hanging out, smoking weed,
    and appreciating the beauty of nature high-poly models.

    The first unit decides to cast a spell (MyDerpyAbility)

    Thus, currently, in the trigger, caster is equal to the first unit because
    he casted the spell.

    3 seconds later, the trigger is still waiting because of the 5-second wait.
    Suddenly, the second unit decides to cast the spell in an attempt to troll
    the first unit.

    Guess what happens! The caster variable in the trigger is going to be equal
    to the second unit!

    After 2 more seconds, the 5-second wait for the first cast finishes, so the
    trigger is going to remove the unit stored in the caster variable from the game!
    This is why spells are not MUI when you use waits in them and include variables.

    The second unit's trolling scheme fails as he is removed from the game.

    After 3 seconds, the second 5-second wait will finish and the unit stored in the
    caster variable will be removed from the game. (And it happens to be the second
    unit too). So nothing actually happens because he was already removed.

    See how that doesn't work?
    This is pretty much what happens in almost every other case.

    The solution is to make the data read on each execution a different source.
    But how do we do that? The answer, my friend, is an array, which we will use as a buffer.

    MUI
    • Pro Trigger
      • Events
        • Unit - A unit starts the effects of an ability
      • Conditions
        • (Ability being cast) Equal to MyDerpyAbility
      • Actions
        • -------- WriteIndex and ReadIndex are integer variables --------
        • Set WriteIndex = (WriteIndex + 1)
        • Set caster[WriteIndex] = (Triggering unit)
        • Wait 5.00 seconds
        • Set ReadIndex = (ReadIndex + 1)
        • Unit - Remove caster[ReadIndex] from the game
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • ReadIndex Equal to WriteIndex
          • Then - Actions
            • Set ReadIndex = 0
            • Set WriteIndex = 0
          • Else - Actions


    This trigger will execute perfectly.

    What's going on?

    Let's imagine that the two units are in the same state.
    Just hanging around, smoking weed, etc...

    The first unit decides to cast the spell.
    At this moment, the WriteIndex variable will be equal to 1.

    Hence, caster[1] will be equal to the first unit.

    After 3 seconds, the second unit decides to cast the spell.
    At this moment, the WriteIndex variable will be equal to 2.

    Hence, caster[2] will be equal to the second unit.

    After 2 seconds, the 5-second wait for the first unit's spellcast
    ends. The ReadIndex variable is increased by 1, so it becomes 1.

    Thus, caster[1] will be removed from the game.

    The trigger continues to check if ReadIndex is equal to WriteIndex.
    Currently, WriteIndex is 2 and ReadIndex is 1. When this happens,
    it means that one of the units is still waiting.

    After 3 more seconds, the 5-second wait for the second unit's
    spellcast ends. The ReadIndex will be increased by 1 and become 2.

    Thus, caster[2] will be removed from the game.

    The trigger continues to check if ReadIndex is equal to WriteIndex.
    Both of them equal 2, so they are both reset to 0.

    We don't really need to check if they're equal so we can set them
    to 0, but we're doing this because, well, you may or may not know this,
    but arrays have a limit. The highest index you could use for an array is
    8191. And due to a bug with Game-saving, that limit is cranked down
    to 8190. So for all of you who've been trying to use 9001 as an index,
    I'M SORRY, BUT THAT'S NEVER GOING TO WORK ;_;.

    How-to

    • For every piece of data you want to store and retrieve after the wait, you need to use an array.
    • You need two integers, one to increase and use as an index before the wait and before setting the variables,
      and one to increase and use after the wait and before reading the variables. (WriteIndex and ReadIndex were used in the examples)
    • Don't forgot to check if these two integers are equal at the end of the trigger so you can reset them to 0.

    Pros and Cons

    Waits have both pros and cons:

    Pros
    • They are easy-to-use and clear.

    Cons
    • They are inaccurate (The actual wait time depends on the latency meaning that waits on Garena take much longer than waits on LAN
      :3
      )
    • Wait times vary with an offset range of [+0.098 ... +0.2] seconds in the best case.
    • Waits don't 'wait' when the game is paused. (Disputable)
    • In JASS, when called inside Conditions, they crash the thread.
    • The wait time with this method must be a constant. (Thank you IcemanBo for pointing this out)
    • You either store all state and every last bit of event-response data that you want to use after the wait code, or you store absolutely nothing and depend on the current execution context of the trigger.
      (This means that using something like (Triggering Unit) after the wait action will give you incorrect results if you used a buffer to store data for the instances. You either use the buffers to store absolutely everything, or you use no buffers at all.) (Thank you again, IcemanBo for helping me make this realization)

    As you can see, the cons outweigh the pros.
    This is why I only recommend using the method outlined in this
    tutorial for map-making only. Public resources using this may be
    rejected for using this method.

    (Melon United International has absolutely nothing to do with this, I can assure you.
    THEY DON'T EXIST I SWEAR.)

    Delayed MUI Spells Without Waits

    Quick Tutorial by Tank-Commander


    Wrap-Up

    I hope this tutorial has helped you with any difficulties you're facing. If you have any
    questions, feel free to ask. Also, I wouldn't recommend using this method very often in
    public resources. This method is only for map-making. The cons that waits have outweigh
    the pros, hence it's up to the map-maker to decide what he wants to do. Thank you for
    reading this tutorial. I hope you learned a thing or two. (Actually, I hope you learned
    nothing, and that's a compliment because it implies that I believe you know a lot :3).

    ~Magtheridon96
     
    Last edited: Sep 20, 2013
  2. Geries

    Geries

    Joined:
    Sep 13, 2010
    Messages:
    497
    Resources:
    7
    Models:
    6
    Packs:
    1
    Resources:
    7
    You are still 15 :> BTW this is a nice tutorial. It will be nicer if you explain what is the actual danger with waits :>
     
  3. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Well, I'm going to be 16 in 5 days now D:

    I did indicate the pros and cons of waits, but if you want me to mention how they affect JASS too, then sure.
     
  4. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,426
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    A pretty entertaining tutorial. :) And it is a useful technique.

    I don't see anything wrong with it, so I'll approve.
     
  5. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Thank you PurgeandFire :D

    Updated to fix a typo and I lengthened the Wrap-Up in order to make it even more entertaining. :p
     
  6. Troll-Brain

    Troll-Brain

    Joined:
    Apr 27, 2008
    Messages:
    2,372
    Resources:
    1
    JASS:
    1
    Resources:
    1
    You are actually really bored, aren't you ?

    Here is for you a simple "tutorial" about GUI MUI stuff in french.
    I link it because i've tried all GUI response events to know if they are MUI or not.
    Yes, all of them ! And it was back to the days where i was really accurate, ofc i'm just an human after a troll, so some nasty errors/lacks could still be hidden somewhere.
    If you don't understand something i will traduct it for you.

    And about TSA, iirc it depends the delay, a TSA in a solo game should be faster than the same TSA in a multiplayer game (even lan game).
     
  7. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,426
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Yes, all event responses are local to the scope.

    However, that doesn't mean this technique is useless. In his examples, it probably is because you can just use triggering unit instead. :p However, for things that don't deal with event responses (timed effects are a good example of this), you could benefit form this technique. ;)
     
  8. mckill2009

    mckill2009

    Joined:
    Mar 10, 2009
    Messages:
    4,696
    Resources:
    34
    Maps:
    5
    Spells:
    27
    JASS:
    2
    Resources:
    34
    no, we're talking about MUI Triggers with Waits...XD...

    =====
    The What's going on is really confusing for the new user, just put it in a trigger example like;

    If 2 units casting;
    • Set caster = (Triggering unit)
    • Wait 5.00 seconds
    • Comment "The second unit will be removed, the first will probably live forever (good for him)"
    • Unit - Remove caster from the game


    well someone claim in http://www.hiveworkshop.com/forums/spells-569/simple-timed-sfx-system-v1-2-gui-218338/ that TriggerSleepAction does obey the Game Pause.
     
  9. Troll-Brain

    Troll-Brain

    Joined:
    Apr 27, 2008
    Messages:
    2,372
    Resources:
    1
    JASS:
    1
    Resources:
    1
    I've never said the opposite, but it's not true, if you call a function from within the local scope, the event response function should still return the right value.

    Sure, but if the native response event is MUI by itself, no need to overcomplicate it just because it's GUI :p
    That's why i've tested all responses event available in GUI.
     
  10. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Oh, right.
    Sorry, when I made this, it was 1:50 AM and I was pretty tired that day.

    True. TSA is a Sync-class native (You know, like all those other silly willy Sync natives Nestharus and geries are yammerin' about).

    Yeah, I saw that post the other day. Hence, I wrote (Disputable) next to that con, and I'm going to test it today when I get home.

    I guess I /can/ make it a bit easier for new users.

    Why yes.

    edit
    Okay, updated.
    It's now 3% cooler \o/
    That number is totally made up :bitchplease:
     
    Last edited: Jun 28, 2012
  11. Troll-Brain

    Troll-Brain

    Joined:
    Apr 27, 2008
    Messages:
    2,372
    Resources:
    1
    JASS:
    1
    Resources:
    1
    What i meant is that the 0.27 minimum value seems a magic value from nowhere, how it was determined ?
    More, in a solo game at least iirc sometimes a TriggerSleepAction is randomly quite ligthning fast, like a Timer(0) or near, but again tests are needed.

    If i remember correctly the actual wait (already started) still end when the game is paused but not new ones (which would start during the pause), ofc a test is definetely needed.
    Also in some case you need a TSA, like if you want to pause the game for X seconds, you can't use a timer.

    Only few gui reponse events (Get...) are not MUI, despite everybody say the opposite, i've listed all of them in the link i've given.
    So basically in GUI most of time you even don't need to use a variable for these responses, it's not like efficiency really does matter in GUI, or it wouldn't be GUI, simplicity is the GUI leitmotiv.
    So you should really mention them.

    Because you're making a GUI tutorial :ogre_hurrhurr:

    Add the list of the not MUI response events available in GUI and it will be 100 % cooler :thumbs_up:
     
  12. -Kobas-

    -Kobas-

    Joined:
    Jan 17, 2010
    Messages:
    5,896
    Resources:
    28
    Icons:
    1
    Tools:
    2
    Maps:
    10
    Spells:
    4
    Template:
    5
    Tutorials:
    6
    Resources:
    28
    This will be useful to starters for sure ^_^
    Damn I lol'd when I finished with first 2 paragraphs.
     
  13. Geries

    Geries

    Joined:
    Sep 13, 2010
    Messages:
    497
    Resources:
    7
    Models:
    6
    Packs:
    1
    Resources:
    7
    The functions which are non-MUI in GUI:

    Everything... I repeat: EVERYTHING whose name do not start with "Event Response - " are surely not safe to use after a Sleep Action or an Execute Trigger( Yes those can cause troubles too ). I think everything else( including "Conversion - " stuff ) can be used safely.
     
  14. defskull

    defskull

    Joined:
    Mar 27, 2008
    Messages:
    7,978
    Resources:
    17
    Spells:
    17
    Resources:
    17
    And when my statement was debated somewhere else, I didn't get noted :(
    I don't know, for me (that thread situation) the Wait does really obey the game pause, I don't really need to explain it all the procedure of how I do it, you can read it on that thread.

    Also, I don't wanna say that the statement is a fact, because perhaps I did some mistakes in that test ?

    You guys should test it, and should vote for majority whether that is a fact or not.
     
  15. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Okay, tonight, I will test it.
     
  16. defskull

    defskull

    Joined:
    Mar 27, 2008
    Messages:
    7,978
    Resources:
    17
    Spells:
    17
    Resources:
    17
    Why not now ?
    Just a few seconds :)

    Oh wait, you're writing a softwareeee haha jokin`
     
  17. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Yes, I am. I'm at work at the moment.
     
  18. defskull

    defskull

    Joined:
    Mar 27, 2008
    Messages:
    7,978
    Resources:
    17
    Spells:
    17
    Resources:
    17
    You already got a job ?
    15-years old, seriously ?
     
  19. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    It's a summer-job :p
    Plus, I'm making a loooot of money :D (My grandfather owns the company)
     
  20. mckill2009

    mckill2009

    Joined:
    Mar 10, 2009
    Messages:
    4,696
    Resources:
    34
    Maps:
    5
    Spells:
    27
    JASS:
    2
    Resources:
    34
    This tutorial helps the new user a lot about waits and they will probably say, "to hell with indexing and hashtables,
    I'm too lazy to learn to it, waits are simple and provides less code"...

    wow!...I hope I see a donation icon below your name Mags, joke :)...