• 🏆 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!
  • ✅ The POLL for Hive's Texturing Contest #33 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!

Summoning spell

Status
Not open for further replies.
Level 10
Joined
Dec 12, 2021
Messages
98
I need help with my channeled summoning spell, first I want to clarify that I'm new to triggers and I only know the basics, once they understand that I can move on to the problem.
EThe spell tries to summon 5 orc skeletons at the target point the player has cast but the skeletons will spawn every 2 seconds during the spell channel (The spell lasts 10 seconds in total), The problem is that every time I try to cancel the channel or move the unit to interrupt the spell, more skeletons keep spawning on the caster's starting unit, and that's kind of awkward since I'm supposed to cancel the ability not continue it and make more summoned units appear at X position.
Below I leave the map where the ability is, it is called ChannelingSummon. I hope a quick help, I know that it is a very simple spell and for you it will not take more than 1 minute to do it.
EDIT: Another thing that I need is that you help me to eliminate the leak memory that there is in that and in the other spell that I did and it is in the same map, I need it because later I have a tremendous lag and I can not play anymore.
 

Attachments

  • SpellDeath.w3x
    19.9 KB · Views: 15

Uncle

Warcraft Moderator
Level 68
Joined
Aug 10, 2018
Messages
7,128
Is it supposed to be MUI? MPI? In other words, can only one unit cast Call of the Dead?

Edit:
Attached a map with fixed versions of the spells. These are not MUI/MPI and will only work properly if a single Necromancer (Necromaster) exists at a time.

Also, the HideSpell will have issues if it's Cooldown is shorter than it's Duration since it uses Waits, global variables and no method of indexing. For example, if you cast the spell again while a previous cast is still running, the previous cast will break and lose reference to all of the variables.
 

Attachments

  • SpellDeath 1.w3x
    19.9 KB · Views: 11
Last edited:
Level 22
Joined
Feb 27, 2019
Messages
709
When you turn off a trigger it does not affect active instances of the trigger. That means that when the event has fired, all of the actions will run to completion. Turning the trigger off will stop the trigger from running new instances but wont interrupt already active ones.

You should strive away from using waits in your spell triggers. Waits are not accurate and are not good for your spell or MUI. Lets take your summoning spell as an example, combined with the knowledge that the trigger finishes its active instances, you can see how the waits are bad. To fix it you could add a lot of code using an if/then/else action with a condition that checks if the trigger is on or not after each wait, however that would be a copy paste nightmare. My suggestion is that you learn to start using the Event -> Timer - Periodic Event in your loop. That means that the trigger runs every seconds that you choose in the event.

  • ChannelingSummon
    • Events
      • Unit - A unit Begins channeling an ability
    • Conditions
      • (Ability being cast) Equal to Call of the Dead (Necromaster)
    • Actions
      • Set VariableSet SummonCaster = (Triggering unit)
      • Set VariableSet SummonPoint[0] = (Target point of ability being cast)
      • Set VariableSet SummonUnit = Skeletal Orc
      • Set VariableSet SummonCount = 1
      • Trigger - Turn on ChannelingSummon Loop <gen>
  • ChannelingSummon Loop
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • Set VariableSet SummonCount = (SummonCount + 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • SummonCount Equal to 2
        • Then - Actions
          • Set VariableSet SummonCount = 0
          • Unit - Create 1 SummonUnit for (Owner of SummonCaster) at SummonPoint[0] facing (Facing of SummonCaster) degrees
          • Unit - Add a 25.00 second Generic expiration timer to (Last created unit)
          • Unit - Add classification of Summoned to (Last created unit)
          • Set VariableSet SummonPoint[1] = (Position of (Last created unit))
          • Special Effect - Create a special effect at SummonPoint[1] using Abilities\Spells\Undead\RaiseSkeletonWarrior\RaiseSkeleton.mdl
          • Special Effect - Destroy (Last created special effect)
          • Custom script: call RemoveLocation (udg_SummonPoint[1])
        • Else - Actions
  • ChannelingSummon Cancel
    • Events
      • Unit - A unit Stops casting an ability
    • Conditions
      • (Ability being cast) Equal to Call of the Dead (Necromaster)
    • Actions
      • Set VariableSet SummonCaster = No unit
      • Custom script: call RemoveLocation (udg_SummonPoint[0])
      • Trigger - Turn off ChannelingSummon Loop <gen>

When you start to get a feel of how the trigger functions and have made a few of your own I suggest you take a look at Visualize: Dynamic Indexing which shows and explains MUI spells.

Regarding your hide spell, I dont really see how it causes memory leaks other than it is not MUI. So if many units or players use the spell in short succession it creates leaks, also since the event is wrong, if you cast the spell and immediately press stop the trigger will run anyways. You should use the Event -> Unit - A unit starts the effect of an ability which triggers when the spell is actually cast. I modified your trigger a bit using custom script and local variables. Its a good way to make sure that the spell is MUI and waits wont be more of a problem than being inaccurate. Its also a good way to get started on coding. There are a few limitations with local variables in custom script though. The local variables must be declared at the start of the trigger and they must be contained within the function. To see if they are within the function and also see what code you want put in your custom scripts: Select the trigger -> Edit -> Convert to Custom Text. I recommend always making a copy of the trigger then convert the copied trigger into Custom Text. It is also VERY IMPORTANT to null local variables or else they can create a lot of leaks. You must null most local variables except integers, reals and a few more. Local variables are variables that are created each instance and therefor must be nulled at the same instance otherwise there is no way to reference them. Global variables can be referenced from any function while locals are contained within the function of that specific instance. The genious of local functions is that you can run many instances without getting variable overwrites/conflicts since new variables are created for each instance.

  • HideSpell
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Chain Lightning
    • Actions
      • Custom script: local unit u
      • Custom script: local location p
      • Custom script: local effect array e
      • Custom script: set u = GetSpellTargetUnit()
      • Custom script: set p = GetUnitLoc(u)
      • Custom script: call PauseUnitBJ( true, u)
      • Custom script: call AddSpecialEffectLocBJ( p, "Abilities\\Spells\\Undead\\Darksummoning\\DarkSummonTarget.mdl" )
      • Custom script: set e[0] = GetLastCreatedEffectBJ()
      • Wait 1.50 game-time seconds
      • Custom script: call DestroyEffectBJ(e[0])
      • Custom script: call ShowUnitHide(u)
      • Wait 6.00 game-time seconds
      • Custom script: call AddSpecialEffectLocBJ(p, "Abilities\\Spells\\Undead\\DarkSummoning\\DarkSummonMissile.mdl" )
      • Custom script: set e[1] = GetLastCreatedEffectBJ()
      • Wait 2.00 game-time seconds
      • Custom script: call DestroyEffectBJ(e[1])
      • Custom script: call ShowUnitShow(u)
      • Custom script: call DestroyEffectBJ(e[0])
      • Custom script: call PauseUnitBJ( false, u)
      • Custom script: call RemoveLocation (p)
      • Custom script: set u = null
      • Custom script: set p = null
      • Custom script: set e[0] = null
      • Custom script: set e[1] = null

Edit: I was writing for so long that I didnt see Uncles post. Using a timer and the Event -> Time - Timer expires is more accurate than using the Event - > Time - Periodic event. Timers are basically 100% accurate. They are the meta endgame of accuracy.
 

Attachments

  • SpellDeath2.w3x
    20.5 KB · Views: 8
Last edited:
Level 24
Joined
Mar 29, 2020
Messages
1,386
lol , it seems I came late to the party but here's my version of your spell, this is MUI(multiple units can use it at the same time) made with dynamic indexing:

  • ChannelingSummon
    • Events
      • Unit - A unit Begins channeling an ability
    • Conditions
      • (Ability being cast) Equal to Call of the Dead (Necromaster)
    • Actions
      • Set VariableSet Cotd_Index = (Cotd_Index + 1)
      • Set VariableSet Cotd_Caster[Cotd_Index] = (Triggering unit)
      • Set VariableSet Cotd_CastPoint[Cotd_Index] = (Target point of ability being cast)
      • Set VariableSet Cotd_Counter[Cotd_Index] = 0.20
      • Unit Group - Add (Triggering unit) to Cotd_Casters
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Cotd_Index Equal to 1
        • Then - Actions
          • Trigger - Turn on ChannelingSummon Loop new <gen>
        • Else - Actions
  • ChannelingSummon Loop new
    • Events
      • Time - Every 0.10 seconds of game time
    • Conditions
    • Actions
      • For each (Integer Cotd_LoopNum) from 1 to Cotd_Index, do (Actions)
        • Loop - Actions
          • Set VariableSet Cotd_Counter[Cotd_LoopNum] = (Cotd_Counter[Cotd_LoopNum] + 0.10)
          • Set VariableSet Counter_checker = (Cotd_Counter[Cotd_LoopNum] mod 2.00)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Counter_checker Equal to 0.10
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Cotd_Caster[Cotd_LoopNum] is in Cotd_Casters.) Equal to True
                • Then - Actions
                  • Unit - Create 1 Cotd_SummonUnit for (Owner of Cotd_Caster[Cotd_LoopNum]) at Cotd_CastPoint[Cotd_LoopNum] facing (Facing of Cotd_Caster[Cotd_LoopNum]) degrees
                  • Unit - Add a 25.00 second Generic expiration timer to (Last created unit)
                  • Set VariableSet TempPoint = (Position of (Last created unit))
                  • Special Effect - Create a special effect at TempPoint using Abilities\Spells\Undead\RaiseSkeletonWarrior\RaiseSkeleton.mdl
                  • Special Effect - Destroy (Last created special effect)
                  • Custom script: call RemoveLocation (udg_TempPoint)
                • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Or - Any (Conditions) are true
                    • Conditions
                      • Cotd_Counter[Cotd_LoopNum] Greater than or equal to 10.00
                      • (Cotd_Caster[Cotd_LoopNum] is in Cotd_Casters.) Equal to False
                • Then - Actions
                  • Set VariableSet Cotd_Caster[Cotd_LoopNum] = Cotd_Caster[Cotd_Index]
                  • Custom script: call RemoveLocation (udg_Cotd_CastPoint[(udg_Cotd_LoopNum)])
                  • Set VariableSet Cotd_CastPoint[Cotd_LoopNum] = Cotd_CastPoint[Cotd_Index]
                  • Set VariableSet Cotd_Counter[Cotd_LoopNum] = Cotd_Counter[Cotd_Index]
                  • Set VariableSet Cotd_Index = (Cotd_Index - 1)
                  • Set VariableSet Cotd_LoopNum = (Cotd_LoopNum - 1)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • Cotd_Index Equal to 0
                    • Then - Actions
                      • Trigger - Turn off (This trigger)
                    • Else - Actions
                • Else - Actions
            • Else - Actions
  • Channeling over
    • Events
      • Unit - A unit Stops casting an ability
      • Unit - A unit Finishes casting an ability
    • Conditions
      • (Ability being cast) Equal to Call of the Dead (Necromaster)
    • Actions
      • Unit Group - Remove (Triggering unit) from Cotd_Casters.
the basic idea of indexing is having a way to keep track of units and objects. for instance, when you have a unit start channeling - in a different trigger, or after a "wait" action, you can't just use the same variable you saved the caster as, bc if the spell was cast again meanwhile, that variable will have been overwritten (assuming it's a global GUI variable).

there are a bunch of different ways around this problem. the dynamic indexing that I used here (pretty much just used the template from the tutorial and just changed it accordingly) is one way, but if you have a lot of custom spells on your map this involves a lot of extra variables and lines of code. I would highly suggest learning how to use Bribes amazing unit indexer. this makes life easy when working with GUI.
 

Attachments

  • SpellDeath.w3x
    21.6 KB · Views: 10
Last edited:
Level 10
Joined
Dec 12, 2021
Messages
98
Thanks to everyone who supported me, as I said at the beginning I'm new to triggers so I wouldn't know if my spells are MIU, GUI or Jass, I copied the invocation spell from another map and I did the hide spell me the way I thought was best. After all I don't know which of all the options they gave me I should choose to add it to my map and the spells are complete and without leaks. By the way, I can't open any of the map files that they sent me because the version of W3 that I use is probably very old, even so I need them to tell me which trigger I should put on my map so that they work 100%.
By the way, I don't understand almost anything when they told me about indexers, I had seen them before in other triggers but I didn't even know what they are used for
 
Last edited:
Level 24
Joined
Mar 29, 2020
Messages
1,386
I'll try to simplify.

GUI/Jass -> this is the language your code is written in. custom script is Jass - that is the language wc3 was created in. creating spells in jass means just writing the actual code with your keyboard (example). this requires a higher level of knowledge, but gives you more flexibility and efficiency. GUI = Graphical User Interface - this is what we call coding using the system you used above where you create triggers by selecting events, conditions and actions from a list of options. behind the scenes this is also transformed into jass script that is fed into the computer.

MUI = Multiple Unit Instanceability. It means that a spell is able to be cast by multiple units (without undesired behavior).indexing - this is already a solution to making spells MUI, and solving other problems. both of these concepts (MUI and the need for indexing) are explained very simply at the beginning of this tutorial. (which has been linked earlier in this thread ).

in terms of choosing which spell to use - the first two are not MUI. If there is only one hero in your map who will ever be able to cast that ability - either one of those versions of the spell will work just fine for what you want, and they are probably less work to copy. If you do need it to be MUI, then use what I posted.
 
Level 10
Joined
Dec 12, 2021
Messages
98
I think I already understood those basics of spells, but here I have a question... if the first 2 triggers they gave me are not very, then what are they supposed to be Gui/Jass or some other type of system?
And now, I don't know if you could show me the types of variables that you put for the trigger? I think you can use Ctrl+B, with a screenshot of that I could do it myself to put it on my map, and yes I need it to be MUI.
One more thing, it seems to me that you did not see my second trigger that consists of a hide unit spell, I do not know if you could also help me with it and that it is also MUI, by the way, I would like all the triggers to be well coded and do not have fleeting because I am already suffering enough lag with the map that I have.
 
Level 24
Joined
Mar 29, 2020
Messages
1,386
if the first 2 triggers they gave me are not very, then what are they supposed to be Gui/Jass or some other type of system?
I didn't open uncles map, so I don't know, but the trigger from dbeast is also in GUI (I assume uncle did too, bc it seems he just improved what you already had). so basically everything in this thread is in GUI (except for small snippets of jass that wee put inside the GUI using the "custom script" action). pure Jass looks completely different - take a look at the example I linked in my previous post.

could show me the types of variables that you put for the trigger?
Cotd_Index = integer
Cotd_Caster = unit array
Cotd_CastPoint = point array
Cotd_Counter = real array
TempPoint = point
Cotd_LoopNum = integer
Cotd_Casters = unit group
Cotd_SummonUnit = unit type, with the initial value set as skeletal orc. (could have just directly defined it as skeletal orc in the code without this variable, but I saw you had it saved as a variable, so I kept it that way)

and maybe I'll have time to fix the hide unit ability later unless someone else beats me to it...
 
Level 10
Joined
Dec 12, 2021
Messages
98
I'm almost done but I realized that you didn't specify the "Counter_cheker" variable so I don't know what to put in it, if you could tell me please.

Well then for the HIDE ability I will be waiting for you to try it and have free time so that the best

EDIT: I just realized that the Checker variable was a Real and I tried the spell and it worked correctly for me. I'm just waiting for you to help me with the Hide spell :D By the way, thanks to you and the others who gave me their time C:
 
Last edited:
Level 24
Joined
Mar 29, 2020
Messages
1,386
I'm almost done but I realized that you didn't specify the "Counter_cheker" variable so I don't know what to put in it, if you could tell me please.

Well then for the HIDE ability I will be waiting for you to try it and have free time so that the best

EDIT: I just realized that the Checker variable was a Real and I tried the spell and it worked correctly for me. I'm just waiting for you to help me with the Hide spell :D By the way, thanks to you and the others who gave me their time C:
I just noticed that [db]east already added an MUI version of your hide spell using local variables. so you basically got a nice little buffet of different types of indexing.

I will just stress again that indexing is something you will constantly need to deal with when triggering in GUI, and I highly recommend bribes unit indexer. you copy Paste a few triggers into your map, and then indexing is very simple.
 
Last edited:
Status
Not open for further replies.
Top