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

GUI MUI Spell

Status
Not open for further replies.
Level 6
Joined
Jul 2, 2013
Messages
151
Hello, basically I need this, ADD ability to casting unit, wait X seconds, remove ability.
 
Level 12
Joined
May 22, 2015
Messages
1,051
If you use GUI waits, this is super easy. Triggering unit is the same throughout.

Though it gets more complex if you want to avoid the waits, and avoiding the waits is usually a good thing.
 
Level 14
Joined
Jul 1, 2008
Messages
1,314
then, just use a timer.

This would be like:

1. Create a function in your map header:
function DestroyGivenAbility takes nothing returns nothing
local timer temp = GetExpiredTimer()
local unit u = LoadUnitHandle( udg_Cache, GetHandleId(temp), 0)
call UnitRemoveAbility(u, 'YOURABILITYINTEGER')
call DestroyTimer(temp)
set u = null
set temp=null
endfunction
2. Create a HashCache in variables and create a hashcache at map init and save it to the variable hashcache.
3. Custom script: local timer temptimer
4. Add the ability to your unit of choice.
5. Custom script: call TimerStart( temptimer, x seconds, false, function DestroyGivenAbility)
6. Custom script: call SaveUnitHandle( udg_Cache, GetHandleId(temptimer), 0, YOURUNITOFCHOICE)
7. Custom script: set temptimer = null

This is not in functional form, but it is basicly the script u need for this without using waits. It uses a HashCache, just look for a tutorial to learn how to init it at map init!
 
Level 7
Joined
Nov 19, 2015
Messages
283
Pretty much chose a way to pass the data across.
For my GUI spells I usually used hashtables and unit groups for this sort of stuff. You could also use arrays.

If you know how to use hashtables.
When you cast the spell
-You need to save the following as the key of the unit
-Save the ability ID as an integer. (saving the ability bugs for some reason)
-Save the duration as a real/integer
-Add the unit to a unit group

Periodic timer
-Load the duration from the key
-If the duration <= 0 then
-Load the ability and remove it
-Remove the unit from the group

  • Hashtable - Save ([YOUR_VARIABLE]) as (Key [STRING]) of key[YOUR_UNIT] in [YOUR_HASHTABLE]
 
This is a simple dynamic "i"ndexing issue.

Config Trigger
X=whatever duration you want

Cast Trigger
Event - Unit Casts
i = i + 1
set ability = (ability being cast)
set unit = (triggering unit)
Remove Ability
Turn on Loop Trigger

Loop Trigger
Periodic
Loop for ineger Z from 1 to (i)
t[z]=t[z]+1
Condition - t[z] = X
Add Ability[z] to unit[z]
set t[z]=t
set unit[z]=unit
set ability[z]=ability
set z = i
set i = i - 1
If i = 0 then turn off this trigger

Ok, minght have messed that all up, just read this:
http://www.hiveworkshop.com/forums/...orials-279/visualize-dynamic-indexing-241896/
 
Last edited:
Level 6
Joined
Jul 2, 2013
Messages
151
Killcide - it was a half request sort of.
Legal - I've read this tutorial before, now yes, it helped me create the spell and it works. But i have no idea why.

  • Defender HP
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Summon Water Elemental
    • Actions
      • Set Defender_Index = (Defender_Index + 1)
      • Set Defender_Caster[Defender_Index] = (Triggering unit)
      • Set Defender_Counter[Defender_Index] = 0
      • Unit - Add Item Life Bonus (Greater) to Defender_Caster[Defender_Index]
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Defender_Index Equal to 1
        • Then - Actions
          • Trigger - Turn on DefenderLOOp <gen>
        • Else - Actions
  • DefenderLOOp
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • For each (Integer DefenderLoopInteger) from 1 to Defender_Index, do (Actions)
        • Loop - Actions
          • Set Defender_Counter[DefenderLoopInteger] = (Defender_Counter[DefenderLoopInteger] + 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Defender_Counter[DefenderLoopInteger] Greater than or equal to 10
            • Then - Actions
              • Unit - Remove Item Life Bonus (Greater) from Defender_Caster[DefenderLoopInteger]
              • Set Defender_Caster[DefenderLoopInteger] = Defender_Caster[Defender_Index]
              • Set Defender_Counter[DefenderLoopInteger] = Defender_Counter[Defender_Index]
              • Set Defender_Index = (Defender_Index - 1)
              • Set DefenderLoopInteger = (DefenderLoopInteger - 1)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Defender_Index Equal to 0
                • Then - Actions
                  • Trigger - Turn off (This trigger)
                • Else - Actions
            • Else - Actions
Question - Why is array size 1!? Why not 10 or 20 ?
 
Level 37
Joined
Jul 22, 2015
Messages
3,485
The spell looks good. My only recommendation for you is to use smaller loop times if your spell has more advanced stuff (ex: moving effects). For this spell, one second will do just fine since all you are doing is removing and adding an ability.

Why is array size 1!? Why not 10 or 20 ?

The variables that you make get initialized when you start the game. So an integer-type variable with a default value of 0 and array size of 1 means that the integer variable (Integer[0] or Integer[1], I'm not quite sure) will be holding the number 0. This does not matter at all because you are going to be constantly changing it when units start using your spell. Leave the default values as they are, and if you need to change anything, just use the Set variable function.
 
Legal - I've read this tutorial before, now yes, it helped me create the spell and it works. But i have no idea why.

Hmmm, I don't know what to tell you. You made it correctly. It saves a unit and an ability as variables. If the event happens again before the first spell ends then it saves it again as the same variable but with a new index number. i.e. variable[1] and variable[2]. Once the first instance is finished, then it renames variable[2] to now be variable[1]. This is done so that it does not keep running the first instance. Deindexing is just a way to prevent extra instances of the trigger from checking conditions after it has finished. This way no more instances run than necessary to complete the task.

I don't know if that helps, but it's the best way I know how to explain it.
 
Level 12
Joined
May 22, 2015
Messages
1,051
The variables that you make get initialized when you start the game. So an integer-type variable with a default value of 0 and array size of 1 means that the integer variable (Integer[0] or Integer[1], I'm not quite sure) will be holding the number 0. This does not matter at all because you are going to be constantly changing it when units start using your spell. Leave the default values as they are, and if you need to change anything, just use the Set variable function.

To expand on this:
Arrays start at 0 and end at 8191 - they start at 0 in basically all programming languages and usually you have to tell it what size to make, but they are always size 8192 in warcraft 3. Setting the size in the trigger editor just initialises the values in that many indexes of the array (size = 20 mean 0-19 will all be set to the initial value). It creates a loop in the map script when you save that will fill in the array and this can be a big waste of time in some cases - not exactly something you want to be doing during map load.

I am not certain, but I feel like they did this so that people using the editor would be very unlikely to crash their map by going off the end of an array (this actually causes the code to try to do something with an unknown piece of memory, so you will get a crash).

Anyway, the only time it is really necessary to set the initial values is if you will use them before setting them to something. Since you are only using them as you set them in your spell, it is safe to not initialise the arrays.

There's also a bigger problem with looping over the array during map load - there is an operation limit that, when reached, will kill the thread. Basically, if some trigger is running away and looping forever or just doing way too much, the game automatically stops it. This can happen during your map load script. Since variables are initialised first, you will start to miss out on trigger creation (they are built after the variables are initialised). If your triggers get skipped, very strange things start to happen and it can be very hard to know what's happening.
 
Status
Not open for further replies.
Top