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

[Solved] Creating a loop spell

Status
Not open for further replies.
Level 3
Joined
Mar 22, 2021
Messages
10
Hello,

I've been searching on how to create a loop spell in a specific way but I just can't find any tutorials on how to do it (or maybe I'm too dumb to understand).

I'd like to create a volley spell (archer) that fires arrows from the heroes while he's channeling (because making arrow falls from the sky would be too tricky/hard for me). For example, I'd choose Blizzard as the channeling spell and every second, a volley of arrow would fire from the hero position to the target point of ability.

I already know how dummies work but I'm struggling with loops and hashtable (storing the unit position, etc..).

Could someone explain to me (as you would explain to a dumb person) how to create that kind of spell ?
 
Level 24
Joined
Feb 9, 2009
Messages
1,787
Is my go to for creating loop spells, spells explains it out nicely.
If you can go into more detail on your spell we can discuss a plan.


However, a cheaty method that i've used in the past would be to use a combination of dummy units, and the sphere ability (The bloodmage uses.
  • Initial Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Thunder
    • Actions
      • Set VariableSet Caster = (Triggering unit)
      • Set VariableSet Point[0] = (Position of Caster)
      • Set VariableSet Point[1] = (Target point of ability being cast)
      • For each (Integer Loop_IntegerVariable) from 1 to 24, do (Actions)
        • Loop - Actions
          • Set VariableSet Point[2] = (Point[1] offset by (Random real number between 10.00 and 350.00) towards (Random angle) degrees.)
          • Unit - Create 1 Universal Missile Dummy Unit 1 for (Owner of Caster) at Point[0] facing Default building facing degrees
          • Unit - Add Spirit shot to (Last created unit)
          • Unit - Add Sphere to (Last created unit)
          • Unit - Order (Last created unit) to Undead Destroyer - Devour Magic Point[2]
          • Unit - Add a 1.50 second Generic expiration timer to (Last created unit)
          • Custom script: call RemoveLocation(udg_Point[2])
      • Custom script: call RemoveLocation(udg_Point[1])
      • Custom script: call RemoveLocation(udg_Point[0])
  • Dummy Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Spirit shot
    • Actions
      • Set VariableSet Point[3] = (Target point of ability being cast)
      • Special Effect - Create a special effect at Point[3] using Abilities\Spells\Human\SpellSteal\SpellStealTarget.mdl
      • Special Effect - Destroy (Last created special effect)
      • Set VariableSet Dummy = (Triggering unit)
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units within 50.00 of Point[3].) and do (Actions)
        • Loop - Actions
          • Unit - Cause Dummy to damage (Picked unit), dealing 10.00 damage of attack type Pierce and damage type Normal
          • Special Effect - Create a special effect attached to the chest of (Picked unit) using Objects\Spawnmodels\Critters\Albatross\CritterBloodAlbatross.mdl
          • Special Effect - Destroy (Last created special effect)
      • Custom script: call RemoveLocation(udg_Point[3])

Results:
1658115560989.png

Note: tweak The casting dummy's "Animation - Cast Point" in object editor to tweak how fast the projectile is, and Arc on the Sphere ability as well to tweak how far the projectile... well... arcs?
 
Last edited:
Level 3
Joined
Mar 22, 2021
Messages
10
Thank you for the the link to the introduction of Dynamic Indexing and for your example. It helped me understand more.

I managed to create the desired spell, which looks like this:

Whenever the desired hero cast a specific ability:
  • Spell casting
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Blizzard
      • (Unit-type of (Casting unit)) Equal to Perwynn
    • Actions
      • Set VariableSet VF_Unit = (Casting unit)
      • Set VariableSet VF_Point[0] = (Position of VF_Unit)
      • Set VariableSet VF_Point[1] = (Target point of ability being cast)
      • Trigger - Turn on Projectiles <gen>

The loop of the spell:

  • Projectiles
    • Events
      • Time - Every 0.50 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Units within 350.00 of VF_Point[1].) and do (Actions)
        • Loop - Actions
          • Animation - Play VF_Unit's Attack 1 animation
          • Unit - Create 1 Dummy Unit for (Owner of VF_Unit) at (Position of VF_Unit) facing Default building facing degrees
          • Unit - Add a 1.00 second Generic expiration timer to (Last created unit)
          • Unit - Add Dummy Volée de flèches - Perwynn to (Last created unit)
          • Unit - Set level of Dummy Volée de flèches - Perwynn for (Last created unit) to 1
          • Unit - Order (Last created unit) to Human Mountain King - Storm Bolt (Picked unit)

And whenever the desired hero stop casting the ability:

  • Spell ending
    • Events
      • Unit - A unit Stops casting an ability
    • Conditions
      • (Ability being cast) Equal to Blizzard
      • (Unit-type of (Casting unit)) Equal to Perwynn
    • Actions
      • Animation - Play (Triggering unit)'s stand animation
      • Trigger - Turn off Projectiles <gen>
      • Custom script: call RemoveLocation(udg_VF_Point[0])
      • Custom script: call RemoveLocation(udg_VF_Point[1])

I'm open to improvements if it has leaks or else !
 
Level 39
Joined
Feb 27, 2007
Messages
5,010
The triggers you wrote will only work for one cast of the spell at a time. Two simultaneous casts will break the first cast. Do you want it to work for all units, for one unit per player, or just one unit?

The Stops Casting trigger should also have “finishes casting” as an event. Two events. Finishes occurs onlu if the channel is fully completed.

You’re leaking a group every time the periodic trigger runs as well as a point for every unit picked in the leaking group.

Couldn’t Cluster Missiles achieve the visual effect you want here? Dummy cast an invisible blizzard on the location and have the hero channel a long Cluster Rockets ability just for visuals. Change the missile model to something else and it won’t do that swaying side-to-side while moving.
 
Level 3
Joined
Mar 22, 2021
Messages
10
Thank you for the piece of information.

Regarding the leaks, do I have to remove the point and destroy the UnitGroup within the loop trigger or do I have to insert it in the spell ending trigger ? I tried while having it in the loop and even by setting the variables (VF_Point[1] and VF_UnitGroup - that I created) before the UnitGroup event, it doesn't work (the spell doesn't loop anymore). Maybe am I missing something ?

I actually didn't know about the animation of that spell !

Edit: Only one hero of that type would be trained so making arrays isn't needed :)
 
Last edited:
Level 39
Joined
Feb 27, 2007
Messages
5,010
do I have to remove the point and destroy the UnitGroup within the loop trigger or do I have to insert it in the spell ending trigger
You need to 'clean' the leaks by destroy/removing the objects when they are no longer needed by your triggers (a 'leak' is memory permanently allocated with no purpose). In principle you could wait until right before the variable is reassigned, but there's no reason to delay that long. Especially if you use a generic point like TempPoint in many triggers where it might or might not get overwritten/cleaned from somewhere you're not expecting. You are referring to Position of VF_Unit during the Unit Group - Pick, so it needs to be assigned to a variable before the loop and removed after the loop:
  • Set TempPoint = (Position of VF_Unit)
  • Unit Group - Pick every unit in (Units within 350.00 of VF_Point[1].) and do (Actions)
    • Loop - Actions
      • Animation - Play VF_Unit's Attack 1 animation
      • Unit - Create 1 Dummy Unit for (Owner of VF_Unit) at TempPoint facing Default building facing degrees
      • Unit - Add a 1.00 second Generic expiration timer to (Last created unit)
      • Unit - Add Dummy Volée de flèches - Perwynn to (Last created unit)
      • Unit - Set level of Dummy Volée de flèches - Perwynn for (Last created unit) to 1
      • Unit - Order (Last created unit) to Human Mountain King - Storm Bolt (Picked unit)
  • Custom script: call RemoveLocation(udg_TempPoint)
For the sake of example, let's say that you needed to use Position of (Picked Unit) instead for some reason. In that case, the variable would be set (and thus overwritten) for each unit picked in the loop (which is sequential) so you would need to clean its leak inside the loop before the loop loops again to a new unit:
  • Unit Group - Pick every unit in (Units within 350.00 of VF_Point[1].) and do (Actions)
    • Loop - Actions
      • Animation - Play VF_Unit's Attack 1 animation
      • Set TempPoint = (Position of (Picked Unit))
      • Unit - Create 1 Dummy Unit for (Owner of VF_Unit) at TempPoint facing Default building facing degrees
      • Unit - Add a 1.00 second Generic expiration timer to (Last created unit)
      • Unit - Add Dummy Volée de flèches - Perwynn to (Last created unit)
      • Unit - Set level of Dummy Volée de flèches - Perwynn for (Last created unit) to 1
      • Unit - Order (Last created unit) to Human Mountain King - Storm Bolt (Picked unit)
      • Custom script: call RemoveLocation(udg_TempPoint)
However, when the spell was cast,VF_Point[0] and [1] were both assigned, and you can simply refer to those variables in the trigger instead. Then you clean them in the 'spell ending' trigger as you have already done. So to fix this all you need to do is change that one pesky Position of VF_Unit to VF_Point[0].

Edit: Only one hero of that type would be trained so making arrays isn't needed
As long as only one instance of that hero exists on the map and the spell's cooldown is longer than the duration of the spell (so it can't be cast twice simultaneously) this trigger will work. If there are two instances of the hero owned by different players, these triggers will not work properly any more.
 
Level 3
Joined
Mar 22, 2021
Messages
10
That was properly explained and I thank you for that.

I don't think I have more to ask since you helped me fix my trigger and teached me how leaks work and how to clean them.

Thank you for your support :peasant-grin:
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,535
Here are some more improvements you can make to your trigger.

You don't have to create a Dummy unit for each (Picked unit). You can create a single Dummy unit, store it in a variable, and then have it cast Storm Bolt on each (Picked unit) like so:
  • Animation - Play VF_Unit's Attack animation
  • Unit - Create 1 Dummy Unit for (Owner of VF_Unit) at VF_Point[0] facing Default building facing degrees
  • Set Variable VF_Dummy = (Last created unit)
  • Unit - Add a 0.20 second Generic expiration timer to VF_Dummy
  • Unit - Add Dummy Volée de flèches - Perwynn to VF_Dummy
  • Custom script: set bj_wantDestroyGroup = true
  • Unit Group - Pick every unit in (Units within 350.00 of VF_Point[1].) and do (Actions)
    • Loop - Actions
      • Set TempPoint = (Position of (Picked Unit))
      • Unit - Move VF_Dummy to TempPoint
      • Custom script: call RemoveLocation(udg_TempPoint)
      • Unit - Order VF_Dummy to Human Mountain King - Storm Bolt (Picked unit)
This is far more efficient.

Note how the actions inside of Loop - Actions happen once for EACH picked unit. So in your original trigger you were playing the VF_Unit's Attack animation inside of the Loop, which meant that if your spell hit 3 units this would happen:
  • Animation - Play VF_Unit's Attack animation
  • Animation - Play VF_Unit's Attack animation
  • Animation - Play VF_Unit's Attack animation
Also, you have no target filtering. You're ordering your Dummy unit to cast Storm Bolt on every unit within 350 range of that point, regardless of whether they're dead, alive, a structure, etc. You can add an If Then Else statement to check the status of the (Picked unit) -> If (Picked unit) is Alive Equal to True.

Lastly, if your Dummy unit isn't setup properly then this method won't work. Here's what it needs:
Dummy unit requires 0.00 Art - Cast Point / Backswing.
Dummy unit requires 0 Speed and Movement Type = None.
Storm Bolt requires 0 mana cost, 999999 cast range, and 0 cooldown.

I recommend basing your Dummy unit on the Locust and then working from there.
 
Last edited:
Level 39
Joined
Feb 27, 2007
Messages
5,010
Other references:

Lastly, if your Dummy unit isn't setup properly then this method won't work.
@Prostagma These settings allow a properly configured dummy unit to cast instantaneously anywhere on the map with no delay and no 'cool down' after before it may be used again. Without these settings the dummy unit will play a short animation before actually casting the spell (cast backswing) and will turn to face the target (due to speed and movement) before the spell actually is cast. This means that two casts right after each other will fail:
  • Unit - Order DUMMY to Human Mountain King - Storm Bolt TARGET_UNIT_1
  • Unit - Order DUMMY to Human Mountain King - Storm Bolt TARGET_UNIT_2
  • -------- unit 2 didn't get cast on --------
But with the dummy unit properly set it will not fail.
 
Level 3
Joined
Mar 22, 2021
Messages
10
@Uncle Thanks for the improvements. I always thought that a dummy had to be created for each unit picked in a group in order to cast a spell on each unit picked but creating one dummy also works. Less generation of hidden things is always better.

I also thought I wouldn't need any filtering because StormBolt (from the spell itself) cannot be cast on building, dead units or allies. The dummy is set up like you said since the beginning, that's at least one thing that was working properly.

@Pyrogasm Thanks for the references, I'll check them so I'm sure I understand everything about leaks.

Thank you guys for your help :peasant-grin:
 
Status
Not open for further replies.
Top