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

MUI and Timers...

Status
Not open for further replies.
Level 5
Joined
Feb 8, 2015
Messages
93
Hello Hive

I'm planning a new spell, "Frozen Eternity" or "Time Freeze" if you wish to be less dramatic.
Any way, the spell is simple enough in getting it to work (I assume)... But I can't come up with a work-around for making it MUI

So any way, the idea is:

Cast upon an area (based on channel), where it will pause/0% animation speed/make invulnerable all units in the target area, then after a set duration the units will become unfrozen and return to combat.

The Single Unit Instance is easy enough; you just start a countdown timer, and when it ends you would un-freeze units from a unit group of targets.

But what if multiple units need to cast the time freeze at the same time? On different units, with different durations?

Can this be done without JASS? Because I honestly have no idea how that stuff works, I just do GUI...
 
Level 38
Joined
Feb 27, 2007
Messages
4,951
Yeah, you're gonna want to use hashtables to save the spell cast data (which units are paused, for how long, etc.) to the timer that runs the 'unpause' trigger. I know that's vague but if you create a new timer whenever the spell is cast and then use the Handle ID (pretty sure you'll have to use a custom script (JASS) for that, but it'll only be a couple lines) of the timer as a key in your hashtable you'll be able to store the data for a while and retrieve it when that timer expires. Look at the hashtable functions and you might get an idea.
 
Level 13
Joined
Mar 24, 2013
Messages
1,105
After looking at the tutorial jondrean posted you'll probably be in good shape in terms of how to get started.

However, keep in mind that when the first person's freeze ends, that someone else's might still be going on so at the end you cannot just simply unpause/remove (stun however you wish to achieve the freeze effect) you'll need to check if that unit is a part of a group in any other instance of the spell and if so leave it paused.

Also consider a check to make sure the unit is still within the AoE in case you have another spell in the map that can move units you'll want the unit to be unpaused when if it leaves the area.
 
Level 7
Joined
Oct 19, 2015
Messages
286
When a spell ends, instead of checking through all other instances to see if a unit is included in any of them, simply use a Table to store, on a per-unit basis, how many instances are affecting it. When an instance starts, add all of its units to a group and increase their value in the Table, if that value was previously 0 then also pause them. When an instance ends, loop through its group and decrease the value in the table for each of the units, if the value reaches 0 for any of them then unpause those units.
 
Level 5
Joined
Feb 8, 2015
Messages
93
Thanks for all the replies people, but I did neglect to mention: I already am using Unit Indexing, seeing as I downloaded Bribe's "GUI Unit Indexer" from here on the Hive

Also; my issue is how would I run the timer?
Like

Unit Starts the Effect of An Ability

Ability = Freeze Time

Set Tempp = target point
Set UnitGroup[Custom Value of Caster Unit] to Units with Range of Target Point, etc. etc.
Pause Units, make invulnerable, etc.
Start Timer[Custom Value of Caster Unit] as a One-shot timer that expires in Duration

Now the trigger that makes the units normal again, you can't make an event retrieve the custom value of the caster from the other trigger, can you?

When a spell ends, instead of checking through all other instances to see if a unit is included in any of them, simply use a Table to store, on a per-unit basis, how many instances are affecting it. When an instance starts, add all of its units to a group and increase their value in the Table, if that value was previously 0 then also pause them. When an instance ends, loop through its group and decrease the value in the table for each of the units, if the value reaches 0 for any of them then unpause those units.
Could you be persuaded to give some more concrete *cough*triggerscript*cough* info on this?
 
Level 38
Joined
Feb 27, 2007
Messages
4,951
Now the trigger that makes the units normal again, you can't make an event retrieve the custom value of the caster from the other trigger, can you?
No, you can't. You have to save <Custom Value of Caster Unit> as an integer (the data) in a hashtable with the key (the address) <Handle ID of Timer[Custom Value of Caster Unit]>. Then when the timer expires you can look up the address <Handle Id of (Expired timer)> which will be the integer corresponding to the unit's index (because you saved it before!). You can then compare the units in groups as you were thinking of doing. I don't have a GUI example of the hashtable stuff because I'm not sure what the GUI functions for it are, but rest assured they DO exist (I have guessed at their syntax below)

Anitarf is correct that if you're gonna use a hashtable anyway it would simply be better to just keep track of how many separate instances a unit is a part of and store that information in the table too.
  • -------- in cast trigger --------
  • Set INDEX = (Custom Value of Caster Unit)
  • Unit Group - Pick every unit in UnitGroup[INDEX] and do (Actions)
    • Loop - Actions
      • Set INSTANCES = Hashtable - Load value (String(Handle ID of (Picked Unit))) from YOUR_HASHTABLE
      • Set INSTANCES = INSTANCES + 1
      • If (all conditions are true) then do (then actions) else do (else actions)
        • If - Conditions
          • INSTANCES greater than 0
        • Then - Actions
          • Unit - Pause/invulnerability/whatever the unit
        • Else - Actions
      • Hashtable - Save value INSTANCES using key (String(Handle ID of (Picked Unit))) in YOUR_HASHTABLE
  • Timer - start blah blah blah
  • Hashtable - Save value INDEX using key (String(Handle ID of (Last started timer???? this might be a thing I don't remember))) in YOUR_HASHTABLE
  • -------- --------
  • -------- --------
  • -------- in timer expiration trigger --------
  • Set TIMER = (Expired timer)
  • Set HID = Handle ID of (TIMER) //an integer variable
  • Set INDEX = Hashtable - Load value (String(HID)) from YOUR_HASHTABLE //Custom Value of Caster Unit, also an integer
  • Unit Group - Pick every unit in UnitGroup[INDEX] and do (Actions)
    • Loop - Actions
      • Set INSTANCES = Hashtable - Load value (String(Handle ID of (Picked Unit))) from YOUR_HASHTABLE
      • Set INSTANCES = INSTANCES - 1
      • If (all conditions are true) then do (then actions) else do (else actions)
        • If - Conditions
          • INSTANCES less than or equal to 0
        • Then - Actions
          • Unit - Unpause/uninvulnerability/unwhatever the unit
        • Else - Actions
      • Hashtable - Save value INSTANCES using key (String(Handle ID of (Picked Unit))) in YOUR_HASHTABLE
  • Unit Group - Clear UnitGroup[INDEX]
 
Level 5
Joined
Feb 8, 2015
Messages
93
Sorry for being slow on the replies, been busy. I tried making the trigger, but it bugs out the map (pressing 'start' just returns to previous screen).

I'll post my trigger here, would any of you mind trying to figure out what's wrong? I can't seem to spot the issue, I'm not all that experienced with hashtables, really.
  • SekrHero Frozen Eternity Activate
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Sekr: Frozen Eternity (FallenDragonE - Channel)
    • Actions
      • Set FrozEter_caster = (Triggering unit)
      • Set FrozEter_INDEX = (Custom value of FrozEter_caster)
      • Set FrozEter_AbilLvl = (Level of (Ability being cast) for FrozEter_caster)
      • Set FrozEter_dur = (0.00 + (5.00 x (Real(FrozEter_AbilLvl))))
      • Set FrozEter_Tempp = (Target point of ability being cast)
      • Set FrozEter_ug[FrozEter_INDEX] = (Units within 250.00 of FrozEter_Tempp matching ((((Matching unit) is A structure) Equal to False) and ((((Matching unit) is Magic Immune) Equal to False) and (((Matching unit) Not equal to FrozEter_caster) and ((((Matching unit) is An Ancient) Equal to False
      • Unit Group - Pick every unit in FrozEter_ug[FrozEter_INDEX] and do (Actions)
        • Loop - Actions
          • Set FrozEter_INSTANCES = (Load FrozEter_INSTANCES of (Key (Picked unit)) from FrozEter_hash)
          • Set FrozEter_INSTANCES = (FrozEter_INSTANCES + 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • FrozEter_INSTANCES Greater than 0
            • Then - Actions
              • Set FrozEter_Tempu = (Picked unit)
              • Unit - Pause FrozEter_Tempu
              • Unit - Make FrozEter_Tempu Invulnerable
              • Animation - Change FrozEter_Tempu's animation speed to 0.00% of its original speed
              • Animation - Change FrozEter_Tempu's vertex coloring to (50.00%, 50.00%, 50.00%) with 50.00% transparency
            • Else - Actions
          • Hashtable - Save FrozEter_INSTANCES as 1 of (Key (Picked unit)) in FrozEter_hash
      • Countdown Timer - Start (FrozEter_Timer) as a One-shot timer that will expire in FrozEter_dur seconds
      • Hashtable - Save FrozEter_INDEX as 2 of (Key (Last started timer)) in FrozEter_hash
  • SekrHero Frozen Eternity Timer
    • Events
      • Time - FrozEter_Timer expires
    • Conditions
    • Actions
      • Set FrozEter_Timer = (Expiring timer)
      • Set FrozEter_TimerIndex = (Key (Expiring timer))
      • Set FrozEter_INDEX = (Load FrozEter_TimerIndex of 2 from FrozEter_hash)
      • Unit Group - Pick every unit in FrozEter_ug[FrozEter_INDEX] and do (Actions)
        • Loop - Actions
          • Set FrozEter_INSTANCES = (Load FrozEter_INSTANCES of (Key (Picked unit)) from FrozEter_hash)
          • Set FrozEter_INSTANCES = (FrozEter_INSTANCES - 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • FrozEter_INSTANCES Less than or equal to 0
            • Then - Actions
              • Set FrozEter_Tempu = (Picked unit)
              • Unit - Unpause FrozEter_Tempu
              • Unit - Make FrozEter_Tempu Vulnerable
              • Animation - Change FrozEter_Tempu's animation speed to 100.00% of its original speed
              • Animation - Change FrozEter_Tempu's vertex coloring to (100.00%, 100.00%, 100.00%) with 0.00% transparency
            • Else - Actions
          • Hashtable - Save FrozEter_INSTANCES as 1 of (Key (Picked unit)) in FrozEter_hash
 
Level 12
Joined
Jan 2, 2016
Messages
973
I can see why this isn't working. And even if it was - it wouldn't be MUI. You can make it a MPI at best this way.
You should try a different approach:
  • Frozen Eternity
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Silence
    • Actions
      • Set TempPoint = (Target point of ability being cast)
      • Set TempUnit = (Triggering unit)
      • Set TempGroup = (Units within 250.00 of TempPoint matching (((((Matching unit) is A structure) Equal to False) and (((Matching unit) is Magic Immune) Equal to False)) and (((Matching unit) Not equal to TempUnit) and (((Matching unit) is An Ancient) Equal to False))))
      • Custom script: call RemoveLocation(udg_TempPoint)
      • Set FE_Count = (FE_Count + 1)
      • Hashtable - Save Handle OfTempGroup as FE_Count of 0 in Table
      • Hashtable - Save (5.00 x (Real((Level of Silence for TempUnit)))) as FE_Count of 1 in Table
      • Unit Group - Pick every unit in TempGroup and do (Actions)
        • Loop - Actions
          • Set TempUnit = (Picked unit)
          • Unit - Pause TempUnit
          • Unit - Make TempUnit Invulnerable
          • Animation - Change TempUnit's animation speed to 0.00% of its original speed
          • Animation - Change TempUnit's vertex coloring to (50.00%, 50.00%, 50.00%) with 0.00% transparency
  • Frozen Eternity Loop
    • Events
      • Time - Every 0.25 seconds of game time
    • Conditions
      • FE_Count Greater than 0
    • Actions
      • For each (Integer TempInteger) from 1 to FE_Count, do (Actions)
        • Loop - Actions
          • Set TempReal = ((Load TempInteger of 1 from Table) - 0.25)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • TempReal Less than or equal to 0.00
            • Then - Actions
              • Set TempGroup = (Load TempInteger of 0 in Table)
              • Unit Group - Pick every unit in TempGroup and do (Actions)
                • Loop - Actions
                  • Set TempUnit = (Picked unit)
                  • Unit - Unpause TempUnit
                  • Unit - Make TempUnit Vulnerable
                  • Animation - Change TempUnit's animation speed to 100.00% of its original speed
                  • Animation - Change TempUnit's vertex coloring to (100.00%, 100.00%, 100.00%) with 0.00% transparency
                  • Unit Group - Remove TempUnit from TempGroup
              • Custom script: call DestroyGroup(udg_TempGroup)
              • Set TempReal = (Load FE_Count of 1 from Table)
              • Set TempGroup = (Load FE_Count of 0 in Table)
              • Hashtable - Save Handle OfTempGroup as TempInteger of 0 in Table
              • Hashtable - Save TempReal as TempInteger of 1 in Table
              • Custom script: call RemoveSavedReal(udg_Table, 1, udg_FE_Count)
              • Custom script: call RemoveSavedHandle(udg_Table, 0, udg_FE_Count)
              • Set TempInteger = (TempInteger - 1)
              • Set FE_Count = (FE_Count - 1)
            • Else - Actions
              • Hashtable - Save TempReal as TempInteger of 1 in Table
Do have in mind, that doing it thisway may have weird results when overlaping (same units are affected by multiple instances of this spell)
 
Level 13
Joined
Oct 16, 2010
Messages
731
How I would personally do it is rather than having a unit group for each spell cast I would use 1 unit group just to tell what is frozen and what isn't. When you use the spell check whether they are in the group or not, if they are then you add to their loop otherwise you place them in the index and add them to the group.

That's how I did a freeze type spell in one of my maps and it did function!
 
Level 5
Joined
Feb 8, 2015
Messages
93
I can see why this isn't working. And even if it was - it wouldn't be MUI. You can make it a MPI at best this way.
You should try a different approach:

Did as you wrote and it works just like I want it to! Thank you so much!

+rep for everyone, jolly good day!
 
Status
Not open for further replies.
Top