• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[Solved] Sorceress Channel Summon Water Elemental

Level 22
Joined
Dec 3, 2020
Messages
576
Hi,

I need the help of the hive once again!
So I have this edited channel ability for the Sorceress unit, which works the following way: the player uses the ability on the ground (point target) and the Sorceress begins channeling the spell for 75 seconds.
A water elemental is created on the point target, and a mana drain lightning effect is created between the sorceress and her water elemental (note that there can be dozens of dozens of sorceresses controlled by the player).
I need the following things:
  • when the 75 seconds of the spell channel/duration run out, to kill the water elemental of the specific sorceress.
  • when the sorceress dies, to kill her water elemental
  • when the sorceress stops channeling the spell by any means (either moving, casting another spell, attacking or being silenced etc...), to kill her water elemental
  • the lightning effect to move to from each channeling sorceress, to her water elemental (worst case scenario I can make a dummy unit at the position of the channeling sorceress that casts drain life which will drain 0 life and kill it when necessary) as long as it lives. For example: the mana drain lightning effect is created but then remains there forever (static, not moving). I want it to follow the water elemental and disappear when it dies.

And obviously to remove all the special/lightning effects upon the water elemental's death.

Thanks for reading!

PS: note that I am on patch 1.29.2
 
Level 26
Joined
Sep 26, 2009
Messages
2,414
You can use either dynamic indexing or a hashtable to achieve what you want.
Dynamic indexing will require 3 arrays - one unit array for casters, second unit array for elementals and third lightning array for all your lightning effects.
On the other hand hashtable can be just one, but reading and writing from/to the hashtable is more painful to set up.

Let's say you use dynamic indexing. So you have the three array variables mentioned earlier. Plus you will need an integer variable to keep track of last index (more on dynamic indexing can be found here: Visualize: Dynamic Indexing )

Your cast trigger should do the following:
  • Increase index by one
  • Store sorceress in casters array.
  • Create elemental, store it in elementals array.
  • Create lightning effect between the two, store it in the lightning array.
  • All three objects should use same index value.
  • Turn on looping trigger if it is off/if index == 1 (see below on what that trigger is for)

Moving lightning effect requires a separate trigger. You will need a trigger that runs every 0.03 seconds and loops through every lightning effect in the lightning array. Inside this loop you get the position of the caster and the target and move the lightning to those positions using Doc - MoveLightningEx. This function does not have a GUI action, so it will have to be done via Custom Script action.
The annoying thing here is that you will need to get the X/Y/Z coordinates of a locations of caster and elemental. It should look something like this:
JASS:
// udg_casterLoc and udg_targetLoc = point variables created and assigned via GUI
// udg_efx = "efx" lightning variable
call MoveLightningEx(udg_efx, true, GetLocationX(udg_casterLoc), GetLocationY(udg_casterLoc), GetLocationZ(udg_casterLoc) + 50, GetLocationX(udg_targetLoc), GetLocationY(udg_targetLoc), GetLocationZ(udg_targetLoc) + 50)
You may notice that the Z coordinates are offset by +50, that is done in order to move lightning effect up from the ground by 50 points.

As for these things:
  • when the 75 seconds of the spell channel/duration run out...
  • when the sorceress dies...
  • when the sorceress stops channeling the spell by any means...
All of these can be resolved by a single event:
  • Unit - A unit Stops casting an ability
When spell finishes naturally, it runs above event. When unit is interrupted, it runs this event. When unit dies, it first stops casting ability, triggering above event, and then it fires "Unit dies" event.
So for this, you just need a single trigger with the above event. Loop through the caster's array to determine the index of the caster. Once you find the caster, remove the lightning effect and kill the water elemental.
Don't forget to deindex the whole thing and turn off the looping trigger if index == 0.

As for stopping the spell because water elemental dies, you will need a separate trigger for this with event
  • Unit - A unit Dies
So create a trigger that reacts to water elemental's death. Loop through the array with elementals to find its index. Once you find it, get the sorceress with same index from the casters array and order it to stop.

So over all, you will need four triggers:
  • First to detected when sorceress casts the spell. This creates the elemental and lightning effect
  • Second, a looping trigger that updates locations of all lightning effects
  • Third that reacts to sorceress stopping the spell
  • Fourth that reacts to water elemental's death.

There is one thing to be aware of. If done exactly as I wrote and sorceress stops casting the spell, then that will fire the third trigger, which will kill elemental, which will fire the fourth trigger, which will find the index of the sorceress and order it to stop, firing again the third trigger :D
One can resolve that by using for example a boolean variable "IsRemoving":
  • In fourth trigger add condition "IsRemoving == false"
  • In third trigger, right before action to kill elemental set "IsRemoving = true" and immedaitely after killing elemental set "IsRemoving = false".
 
Level 26
Joined
Sep 26, 2009
Messages
2,414
Check below. I cannot post map since I am on latest version.

1715765571339.png


  • Starts
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Summon Bound Elemental
    • Actions
      • Set VariableSet loc1 = (Position of (Triggering unit))
      • Set VariableSet loc2 = (Target point of ability being cast)
      • -------- ----- --------
      • Unit - Create 1 Water Elemental (Level 1) for (Triggering player) at loc2 facing Default building facing degrees
      • Lightning - Create a Drain Mana lightning effect from source loc1 to target loc2
      • -------- ----- --------
      • Custom script: call RemoveLocation(udg_loc1)
      • Custom script: call RemoveLocation(udg_loc2)
      • -------- ----- --------
      • Set VariableSet Index = (Index + 1)
      • Set VariableSet Casters[Index] = (Triggering unit)
      • Set VariableSet Elementals[Index] = (Last created unit)
      • Set VariableSet LightningEffects[Index] = (Last created lightning effect)
      • -------- ----- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Index Equal to 1
        • Then - Actions
          • Trigger - Turn on Loop <gen>
        • Else - Actions

  • Loop
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • For each (Integer LoopInt) from 1 to Index, do (Actions)
        • Loop - Actions
          • Set VariableSet loc1 = (Position of Casters[LoopInt])
          • Set VariableSet loc2 = (Position of Elementals[LoopInt])
          • -------- ----- --------
          • Custom script: set udg_x[1] = GetLocationX(udg_loc1)
          • Custom script: set udg_y[1] = GetLocationY(udg_loc1)
          • Custom script: set udg_z[1] = GetLocationZ(udg_loc1)
          • Custom script: set udg_x[2] = GetLocationX(udg_loc2)
          • Custom script: set udg_y[2] = GetLocationY(udg_loc2)
          • Custom script: set udg_z[2] = GetLocationZ(udg_loc2)
          • -------- ----- --------
          • Custom script: call MoveLightningEx(udg_LightningEffects[udg_LoopInt], true, udg_x[1], udg_y[1], udg_z[1] + 50, udg_x[2], udg_y[2], udg_z[2] + 50)
          • -------- ----- --------
          • Custom script: call RemoveLocation(udg_loc1)
          • Custom script: call RemoveLocation(udg_loc2)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Index Equal to 0
        • Then - Actions
          • Trigger - Turn off (This trigger)
        • Else - Actions

  • Stops
    • Events
      • Unit - A unit Stops casting an ability
    • Conditions
      • (Ability being cast) Equal to Summon Bound Elemental
    • Actions
      • For each (Integer LoopInt) from 1 to Index, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Triggering unit) Equal to Casters[LoopInt]
            • Then - Actions
              • Lightning - Destroy LightningEffects[LoopInt]
              • Set VariableSet IsRemoving = True
              • Unit - Kill Elementals[LoopInt]
              • Set VariableSet IsRemoving = False
              • -------- ----- --------
              • Set VariableSet Casters[LoopInt] = Casters[Index]
              • Set VariableSet Elementals[LoopInt] = Elementals[Index]
              • Set VariableSet LightningEffects[LoopInt] = LightningEffects[Index]
              • Set VariableSet Index = (Index - 1)
              • -------- ----- --------
              • Skip remaining actions
            • Else - Actions

  • Dies
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Water Elemental (Level 1)
      • IsRemoving Equal to False
    • Actions
      • For each (Integer LoopInt) from 1 to Index, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Triggering unit) Equal to Elementals[LoopInt]
            • Then - Actions
              • Unit - Order Casters[LoopInt] to Stop.
              • Skip remaining actions
            • Else - Actions
 
Level 22
Joined
Dec 3, 2020
Messages
576
Check below. I cannot post map since I am on latest version.

  • Starts
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Summon Bound Elemental
    • Actions
      • Set VariableSet loc1 = (Position of (Triggering unit))
      • Set VariableSet loc2 = (Target point of ability being cast)
      • -------- ----- --------
      • Unit - Create 1 Water Elemental (Level 1) for (Triggering player) at loc2 facing Default building facing degrees
      • Lightning - Create a Drain Mana lightning effect from source loc1 to target loc2
      • -------- ----- --------
      • Custom script: call RemoveLocation(udg_loc1)
      • Custom script: call RemoveLocation(udg_loc2)
      • -------- ----- --------
      • Set VariableSet Index = (Index + 1)
      • Set VariableSet Casters[Index] = (Triggering unit)
      • Set VariableSet Elementals[Index] = (Last created unit)
      • Set VariableSet LightningEffects[Index] = (Last created lightning effect)
      • -------- ----- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Index Equal to 1
        • Then - Actions
          • Trigger - Turn on Loop <gen>
        • Else - Actions

  • Loop
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • For each (Integer LoopInt) from 1 to Index, do (Actions)
        • Loop - Actions
          • Set VariableSet loc1 = (Position of Casters[LoopInt])
          • Set VariableSet loc2 = (Position of Elementals[LoopInt])
          • -------- ----- --------
          • Custom script: set udg_x[1] = GetLocationX(udg_loc1)
          • Custom script: set udg_y[1] = GetLocationY(udg_loc1)
          • Custom script: set udg_z[1] = GetLocationZ(udg_loc1)
          • Custom script: set udg_x[2] = GetLocationX(udg_loc2)
          • Custom script: set udg_y[2] = GetLocationY(udg_loc2)
          • Custom script: set udg_z[2] = GetLocationZ(udg_loc2)
          • -------- ----- --------
          • Custom script: call MoveLightningEx(udg_LightningEffects[udg_LoopInt], true, udg_x[1], udg_y[1], udg_z[1] + 50, udg_x[2], udg_y[2], udg_z[2] + 50)
          • -------- ----- --------
          • Custom script: call RemoveLocation(udg_loc1)
          • Custom script: call RemoveLocation(udg_loc2)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Index Equal to 0
        • Then - Actions
          • Trigger - Turn off (This trigger)
        • Else - Actions

  • Stops
    • Events
      • Unit - A unit Stops casting an ability
    • Conditions
      • (Ability being cast) Equal to Summon Bound Elemental
    • Actions
      • For each (Integer LoopInt) from 1 to Index, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Triggering unit) Equal to Casters[LoopInt]
            • Then - Actions
              • Lightning - Destroy LightningEffects[LoopInt]
              • Set VariableSet IsRemoving = True
              • Unit - Kill Elementals[LoopInt]
              • Set VariableSet IsRemoving = False
              • -------- ----- --------
              • Set VariableSet Casters[LoopInt] = Casters[Index]
              • Set VariableSet Elementals[LoopInt] = Elementals[Index]
              • Set VariableSet LightningEffects[LoopInt] = LightningEffects[Index]
              • Set VariableSet Index = (Index - 1)
              • -------- ----- --------
              • Skip remaining actions
            • Else - Actions

  • Dies
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Water Elemental (Level 1)
      • IsRemoving Equal to False
    • Actions
      • For each (Integer LoopInt) from 1 to Index, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Triggering unit) Equal to Elementals[LoopInt]
            • Then - Actions
              • Unit - Order Casters[LoopInt] to Stop.
              • Skip remaining actions
            • Else - Actions
Thank you so so much!
I will do the triggers a little bit later today and let you know what's what!
 
Top