Powershot ability stops working after using it 2-3 times...

Level 15
Joined
Jul 19, 2007
Messages
855
I have imported the Dota Windrunners "Powershot" ability to my map from a spellpack and it seems like it stops working after I used it 2-3 times. Nothing is happening and I don't know why. Also I would like to increase the range the arrow travels to 2600 range. Anyone can help me?

  • Powershot Casting
    • Events
      • Unit - A unit Begins casting an ability
    • Conditions
      • (Ability being cast) Equal to Powershot
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • PowerInstances Greater than or equal to 1000
        • Then - Actions
          • Set VariableSet FocusFireTargets = 0
        • Else - Actions
      • Set VariableSet PowerCasterPosition = (Position of (Triggering unit))
      • Set VariableSet PowerTargetPoint = (Target point of ability being cast)
      • Set VariableSet PowerAngle[PowerInstances] = (Angle from PowerCasterPosition to PowerTargetPoint)
      • Animation - Change (Triggering unit)'s animation speed to 80.00% of its original speed
      • Unit - Set the custom value of (Triggering unit) to PowerInstances
      • Countdown Timer - Start PowerTimer[PowerInstances] as a One-shot timer that will expire in 1.00 seconds
      • Set VariableSet PowerInstances = (PowerInstances + 1)
      • Custom script: call RemoveLocation(udg_PowerCasterPosition)
      • Custom script: call RemoveLocation(udg_PowerTargetPoint)
  • Powershot Shoot
    • Events
      • Unit - A unit Stops casting an ability
    • Conditions
      • (Ability being cast) Equal to Powershot
    • Actions
      • Animation - Change (Triggering unit)'s animation speed to 100.00% of its original speed
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Elapsed time for PowerTimer[(Custom value of (Triggering unit))]) Greater than 0.30
        • Then - Actions
          • Set VariableSet PowerCasterPosition2 = (Position of (Triggering unit))
          • Unit - Create 1 Powershot Dummy for (Owner of (Triggering unit)) at PowerCasterPosition2 facing PowerAngle[(Custom value of (Triggering unit))] degrees
          • Unit - Add a 0.60 second Generic expiration timer to (Last created unit)
          • Unit - Set the custom value of (Last created unit) to (Custom value of (Triggering unit))
          • Unit Group - Add (Last created unit) to PowerGroup
          • Set VariableSet PowerDamage[(Custom value of (Triggering unit))] = ((40.00 + (80.00 x (Real((Level of Powershot for (Triggering unit)))))) x (Elapsed time for PowerTimer[(Custom value of (Triggering unit))]))
          • Set VariableSet PowerSpeed[(Custom value of (Triggering unit))] = 90.00
          • Unit - Set the custom value of (Triggering unit) to 0
          • Custom script: call RemoveLocation(udg_PowerCasterPosition2)
        • Else - Actions
  • Powershot Arrow
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in PowerGroup and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) is alive) Equal to True
            • Then - Actions
              • Set VariableSet PowerArrow = (Picked unit)
              • Set VariableSet PowerPosition = (Position of PowerArrow)
              • Set VariableSet PowerCustomValue = (Custom value of (Picked unit))
              • Special Effect - Create a special effect at PowerPosition using Tornado.mdx
              • Special Effect - Destroy (Last created special effect)
              • Set VariableSet PowerDamageArea = (Units within 150.00 of PowerPosition matching ((((Matching unit) is A structure) Equal to False) and ((((Matching unit) belongs to an enemy of (Owner of (Picked unit)).) Equal to True) and (((Matching unit) Not equal to (Picked unit)) and ((((Matching unit)
              • Unit Group - Pick every unit in PowerDamageArea and do (Actions)
                • Loop - Actions
                  • Unit Group - Add (Picked unit) to PowerDamagedTargets[PowerCustomValue]
                  • Unit - Cause PowerArrow to damage (Picked unit), dealing PowerDamage[PowerCustomValue] damage of attack type Hero and damage type Magic
                  • Set VariableSet PowerDamage[PowerCustomValue] = (PowerDamage[PowerCustomValue] x 0.90)
                  • Set VariableSet PowerSpeed[PowerCustomValue] = (PowerSpeed[PowerCustomValue] x 0.90)
              • Set VariableSet PowerPosition2 = (PowerPosition offset by PowerSpeed[PowerCustomValue] towards (Facing of (Picked unit)) degrees.)
              • Unit - Move (Picked unit) instantly to PowerPosition2
              • Custom script: call RemoveLocation(udg_PowerPosition)
              • Custom script: call RemoveLocation(udg_PowerPosition2)
              • Custom script: call DestroyGroup(udg_PowerDamageArea)
            • Else - Actions
              • Set VariableSet PowerCustomValue = (Custom value of (Picked unit))
              • Custom script: call DestroyGroup(udg_PowerDamagedTargets[udg_PowerCustomValue])
              • Unit Group - Remove (Picked unit) from PowerGroup.
 
Level 29
Joined
Sep 26, 2009
Messages
2,594
I think the breaking thing can be that this spell completely relies on setting custom value to a unit.
However a unit may have only a single custom value set. So if you have in map other triggers that set unit's custom value and any other trigger happens to run during PowerShot, then it will overwrite the value given by Powershot, breaking the spell.
I would say using dynamic indexing would be the best option here, considering you are most likely using a pool of 1000 timers.

I believe this part of Powershot Casting trigger is wrong:
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • PowerInstances Greater than or equal to 1000
    • Then - Actions
      • Set VariableSet FocusFireTargets = 0
    • Else - Actions
All three triggers use variables called Power<something>, so it is very strange that you set here FocusFireTargets variable.
As I mentioned earlier, I believe you are using a pool of 1000 timers and this IF is supposed to reset value of PowerInstances back to zero if current value is >= 1000.


In Powershot Arrow trigger I see at the end you are destroying unit group in one index of PowerDamagedTargets[] array:
  • Custom script: call DestroyGroup(udg_PowerDamagedTargets[udg_PowerCustomValue])
But I don't see you creating a new group anywhere else. You just try to add to that group.
This will break your spell once PowerInstances have been reset back to 0.
I believe you don't want to destroy the group, but actually empty it (remove all units from it).

Also I would like to increase the range the arrow travels to 2600 range. Anyone can help me?
The Powershot Shoot trigger gives the arrow (Powershot dummy) a 0.60 second lifetime. It also sets its speed (PowerSpeed) to 90.00.
That means the arrow is moved by 90.00 range in your Powershot Arrow trigger every 0.03 seconds.
Since its lifetime is 0.60, then (0.60 / 0.03) * 90.00 = 1800.00 range.
So if you want to increase the range, then you need to increase its speed and/or lifetime.

Finally, you should compare if you have correctly set variables. Unless you did not post some initialization trigger, the PowerTimer[] array will most likely have Size 1000 in Variable Editor.
 
Level 15
Joined
Jul 19, 2007
Messages
855
I think the breaking thing can be that this spell completely relies on setting custom value to a unit.
However a unit may have only a single custom value set. So if you have in map other triggers that set unit's custom value and any other trigger happens to run during PowerShot, then it will overwrite the value given by Powershot, breaking the spell.
I would say using dynamic indexing would be the best option here, considering you are most likely using a pool of 1000 timers.

I believe this part of Powershot Casting trigger is wrong:
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • PowerInstances Greater than or equal to 1000
    • Then - Actions
      • Set VariableSet FocusFireTargets = 0
    • Else - Actions
All three triggers use variables called Power<something>, so it is very strange that you set here FocusFireTargets variable.
As I mentioned earlier, I believe you are using a pool of 1000 timers and this IF is supposed to reset value of PowerInstances back to zero if current value is >= 1000.


In Powershot Arrow trigger I see at the end you are destroying unit group in one index of PowerDamagedTargets[] array:
  • Custom script: call DestroyGroup(udg_PowerDamagedTargets[udg_PowerCustomValue])
But I don't see you creating a new group anywhere else. You just try to add to that group.
This will break your spell once PowerInstances have been reset back to 0.
I believe you don't want to destroy the group, but actually empty it (remove all units from it).


The Powershot Shoot trigger gives the arrow (Powershot dummy) a 0.60 second lifetime. It also sets its speed (PowerSpeed) to 90.00.
That means the arrow is moved by 90.00 range in your Powershot Arrow trigger every 0.03 seconds.
Since its lifetime is 0.60, then (0.60 / 0.03) * 90.00 = 1800.00 range.
So if you want to increase the range, then you need to increase its speed and/or lifetime.

Finally, you should compare if you have correctly set variables. Unless you did not post some initialization trigger, the PowerTimer[] array will most likely have Size 1000 in Variable Editor.
Hmm I tried to remove the custom script
  • Custom script: call DestroyGroup(udg_PowerDamagedTargets[udg_PowerCustomValue])
but it still doesn't work.

Btw I have alot of triggered spells in my map some maybe something conflicts with the trigger?
How should I set the lifetime and range so it will be 2600 range?
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
I notice that PowerTimer and PowerDamagedTargets wasn't set to 1000 when I imported it to my map and I tried to set it to 1000 for both of them but it doesn't let me set it to 1000 because it jumps back to 1 again :nw:
If you mean the Initial Value or Size, you need to modify variables inside of the Variable Editor.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
Note that you should redesign this trigger to fully utilize Unit Indexing, I imagine you already have a Unit Indexer in your map. It's an extremely simple change, you just need to replace the "Set custom value" action with an Integer array variable that does almost the same thing. Then reference that inside of the Loop trigger. I also suggest adding a PowerCaster[] unit array variable that links the Dummy to the caster, and have the Caster deal the damage instead. That way your caster is the (Damage source) and the (Killing unit) in any triggers that care about those Event Responses.

Oh I see. Now it seems to work like it should but I just need help to make the arrow travel 2600 range.
The PowerSpeed variable controls the distance that the projectile moves:
  • Set VariableSet PowerSpeed[(Custom value of (Triggering unit))] = 90.00
Your Periodic Interval controls how often the projectile is moved:
  • Time - Every 0.03 seconds of game time
So it moves the projectile by PowerSpeed units every 0.03 seconds.

Then you can see that PowerSpeed gets multiplied by 0.90 here:
  • Set VariableSet PowerSpeed[PowerCustomValue] = (PowerSpeed[PowerCustomValue] x 0.90)
When you multiply something by 0.90 you're effectively reducing it by 10%.

So 90 becomes 81, 81 becomes 72.9, 72.9 becomes 65.61, and so on. You can see this pattern in your Calculator app (spam = button):
1744217235166.png


The Dummy unit lasts 0.60 seconds before expiring (dying) so it should move 20 times in total -> 0.60 / 0.03.
  • Unit - Add a 0.60 second Generic expiration timer to (Last created unit)
So it has 20 movement cycles, the first moving it 90 distance, the second moving it 72.9 distance, etc.
Asking ChatGPT to calculate this for us, it says that the projectile moves:
"790.58 units total distance traveled over 0.60 seconds. So, to get ~2600 units then Set the initial speed to 296 instead of 90."
So changing the initial speed to 296 will cover roughly 2600 distance. However, that's a huge starting value and will jump right past the first few enemies, never damaging them.

With that in mind I'd suggest changing the initial speed to 99:
  • Set VariableSet PowerSpeed[(Custom value of (Triggering unit))] = 99.00
Then multiply it by 0.99 instead of 0.90:
  • Set VariableSet PowerSpeed[PowerCustomValue] = (PowerSpeed[PowerCustomValue] x 0.99)
Then change the expiration timer to 0.94 seconds:
  • Unit - Add a 0.94 second Generic expiration timer to (Last created unit)
That should get you pretty close to 2600.
 
Last edited:
Level 15
Joined
Jul 19, 2007
Messages
855
Note that you should redesign this trigger to fully utilize Unit Indexing, I imagine you already have a Unit Indexer in your map. It's an extremely simple change, you just need to replace the "Set custom value" action with an Integer array variable that does almost the same thing. Then reference that inside of the Loop trigger. I also suggest adding a PowerCaster[] unit array variable that links the Dummy to the caster, and have the Caster deal the damage instead. That way your caster is the (Damage source) and the (Killing unit) in any triggers that care about those Event Responses.


The PowerSpeed variable controls the distance that the projectile moves:
  • Set VariableSet PowerSpeed[(Custom value of (Triggering unit))] = 90.00
Your Periodic Interval controls how often the projectile is moved:
  • Time - Every 0.03 seconds of game time
So it moves the projectile by PowerSpeed units every 0.03 seconds.

Then you can see that PowerSpeed gets multiplied by 0.90 here:
  • Set VariableSet PowerSpeed[PowerCustomValue] = (PowerSpeed[PowerCustomValue] x 0.90)
When you multiply something by 0.90 you're effectively reducing it by 10%.

So 90 becomes 81, 81 becomes 72.9, 72.9 becomes 65.61, and so on. You can see this pattern in your Calculator app (spam = button):
View attachment 523542

The Dummy unit lasts 0.60 seconds before expiring (dying) so it should move 20 times in total -> 0.60 / 0.03.
  • Unit - Add a 0.60 second Generic expiration timer to (Last created unit)
So it has 20 movement cycles, the first moving it 90 distance, the second moving it 72.9 distance, etc.
Asking ChatGPT to calculate this for us, it says that the projectile moves:

So changing the initial speed to 296 will cover roughly 2600 distance. However, that's a huge starting value and will jump right past the first few enemies, never damaging them.

With that in mind I'd suggest changing the initial speed to 99:
  • Set VariableSet PowerSpeed[(Custom value of (Triggering unit))] = 99.00
Then multiply it by 0.99 instead of 0.90:
  • Set VariableSet PowerSpeed[PowerCustomValue] = (PowerSpeed[PowerCustomValue] x 0.99)
Then change the expiration timer to 0.94 seconds:
  • Unit - Add a 0.94 second Generic expiration timer to (Last created unit)
That should get you pretty close to 2600.
Thank you so much for explanation. It works like I want it now :thumbs_up:
 
Level 29
Joined
Sep 26, 2009
Messages
2,594
The Dummy unit lasts 0.60 seconds before expiring (dying) so it should move 20 times in total -> 0.60 / 0.03.
  • Unit - Add a 0.60 second Generic expiration timer to (Last created unit)
So it has 20 movement cycles, the first moving it 90 distance, the second moving it 72.9 distance, etc.
this isn't exactly right. This reduction in speed happens any time an enemy is hit by the arrow.
So out of the 20 cycles if first 3 did not hit any enemy, then there would be no reduction in speed.
If 4th cycle hit 10 enemies, the speed would be reduced 10 times in that single cycle.

Either the arrow should by default fly up to 2600 range, but less range if it hits targets - in this case you should only take into account the base speed and lifetime.

Or the arrow should always fly 2600 range without being slowed down - in this case again just take into account the base speed and lifetime + remove this part from the Powershot Arrow trigger:
  • Set VariableSet PowerSpeed[PowerCustomValue] = (PowerSpeed[PowerCustomValue] x 0.90)
Or the arrow should always fly 2600 range but also be slowed down when it hits targets - in this case remove lifetime from arrow, track distance travelled and remove arrow once it passed 2600 range.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
this isn't exactly right. This reduction in speed happens any time an enemy is hit by the arrow.
So out of the 20 cycles if first 3 did not hit any enemy, then there would be no reduction in speed.
If 4th cycle hit 10 enemies, the speed would be reduced 10 times in that single cycle.

Either the arrow should by default fly up to 2600 range, but less range if it hits targets - in this case you should only take into account the base speed and lifetime.

Or the arrow should always fly 2600 range without being slowed down - in this case again just take into account the base speed and lifetime + remove this part from the Powershot Arrow trigger:
  • Set VariableSet PowerSpeed[PowerCustomValue] = (PowerSpeed[PowerCustomValue] x 0.90)
Or the arrow should always fly 2600 range but also be slowed down when it hits targets - in this case remove lifetime from arrow, track distance travelled and remove arrow once it passed 2600 range.
Oh shit... WHOOPS. :peasant-neutral:I blame Blizzard.
 
Top