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

Zephyr Contest #13 - Deception

Status
Not open for further replies.
the%20hive%20workshop.png


zephyr.png
contest.png
number.png
1.png
3.png



Deception
Create a spell which focuses on tricking your opponents. It should mislead the enemies to make bad decisions.

contest%20rules%20and%20conditions.png

  • No submission may violate any of the Site Rules.
  • If a submission does not follow the Spell Submission Rules the creator may/will be disqualified.
  • Your submission must be posted before the deadline. The post containing your final submission must also contain the following:
    • An in game screenshot showing your submission in action.
    • The file in the appropriate format. It must be openable with vanilla WorldEditor.
    • File name must be: "<username> + <spell name>".
  • You must show at least one unfinished preview of your submission (Wip), before the deadline, as proof that it’s yours.
  • Your submission may not be started/made before the official launch of the contest.
  • Judges may not participate.
  • Teamwork is not allowed. Finding testers to help you with your submission is not considered as teamwork.
  • Imports may be used in the map, however they must all be credited.
  • You will not be penalized if you use GUI over JASS.
  • Convenience over effort won't be an excuse to make use of third party programs (exception: Jass New Gen Pack). GUI actions that do not exist in the vanilla editor's database may lead to disqualification. WEU (World Editor Unlimited) and UMSWE fall into this category.
  • You can use any enhancing system (xe, IsDestructableTree, Damage detection systems, etc.), as long as the judge(s) and/or host give(s) consent to its usage.
  • All code must have decent documentation. This should ensure easy understanding of code, and simple test conditions.
  • An infraction of any of the rules stated above may result in a disqualification.
Attention: Your spell should only trick enemies, not your allies!

prizes.png





    • First Place: 45 reputation points and your entry on the award icon
    • Second Place: 30 reputation points and an award icon
    • Third Place: 15 reputation points and an award icon
    • Remaining entries: 5 reputation points
    • Judge: 10 reputation points


judges.png


contest%20judging.png


Coding
Is the skill bug- and leak-free? Does it support multiple instances? Is there a good documentation and are there enough configurable variables to fit the needs of different user? Does it cause performance issues upon effect? Is the code fitting for a decent spell submission, or is it too simple?/25

Concept
Is it unique? How creatively was the idea executed and is it fitting the theme?/15

Visuals
How does the skill look? Is it overloaded with special effects? How explanatory is the tooltip/description of its functionality?/10

contest%20dates%20and%20deadline.png

  • The contest shall begin on 6th of September and conclude on 7th of October (day is included).

Assigned moderator: IcemanBo

:fp:The Poll | Results
 

Shar Dundred

Community Moderator
Level 72
Joined
May 6, 2009
Messages
5,869
Shar be like; "WTF, no demon theme? I am out niggas."

Well, deception is used by Demons, after all....Hmm.... Perhaps I should join...

Nah, rather not. I won't allow a certain someone to judge my poor triggers. They might develop feelings some day and, if that actually happened, *I* will be the only one allowed to hurt them. >:)
 

Shar Dundred

Community Moderator
Level 72
Joined
May 6, 2009
Messages
5,869
scared? :D
As mentioned in the rules, using GUI gives you exactly 0 negative points compared to Jass

You are extremely scary, edo. :xxd:
Well, still, JASS gives you better possibilites, does it not? Anyway, doesn't matter.

Awesome that's it's starting up so fast. I'll only have a week or so to work on mine once it starts before I get tied up so expect to see a lot of quick WIPs once it begins

Okay, I'm out, won't challenge the TANK himself. :xxd:

Unless I get a really, really, REALLY good concept done. :p
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Interesting, I may or may not join depending on the free time I have.
So it requires WIPS huh.But for example if person A posted a WIP and person B is already working on a spell very similar to person A's WIP, then what appropriate action shpuld person B do?

EDIT: Is the criteria for contest judging equally distributed? All have 33.333%?
 
Particle Punisher

Alright! Let's get this show on the road

Purpose: Particle punisher is a two-part mind game ability designed to incentivise enemies into playing a high-risk-high-reward game with the player centred around making quick choices.

how it works:
The ability is split into two parts which activate depending on the target (it can either target units or the ground) the first part (when targetting the ground) launches particles which land and can be picked up (automatically picked up when an enemy comes into close range), depending on how close the target point was to an enemy unit when the particle was fired determines whether or not the particle will damage or heal the opponent. The second (when targetting a unit) punishes opponents who have been tricked multiple times in a short period by firing a particle at them dealing damage per successful deception.

Specifics:
Part 1: Each particle lasts 5 seconds, healing particles heal for 4x as much as damaging ones and the longer a particle lies on the floor the weaker its effect becomes (higher reward for picking up a particle quickly) units which pick up a particle will also be given a buff which slows them down exponentially (damaging packets increase the level/slow while healing ones reduce the level/slow) and adds a particle to a ring above them (1 for a heal particle, 2 for a damage particle) the slow buff automatically reduces in level every couple of seconds and is removed once it hits level 0, when this happens the particle ring is also removed (without damaging the afflicted unit) Level 1 slow has a 0% speed reduction (applies if the unit has no buff and picked up a healing particle) Level 2 has a 15% speed reduction (applies if the unit has no buff and picked up a damaging particle) and can go up to 5 levels

Part 2: A large high-velocity tracking particle is fired at a target unit, if the unit moves away enough the particle will disappear (miss the target). On hit the unit is stunned for a brief period and all nearby particles (damage and healing) are pulled into and also hit the target unit and add to the particle ring, the main projectile itself deals no damage. If there are particles in the particle ring when the stun is about to expire then each particle will launch the energy contained into the target unit adding additional time into the stun, if the target unit dies during this period then the remaining energy is released in an explosion centred around the target, if there is a particularly high amount of particles in the ring then it is possible for the casting unit to place damaging particles at the feet of the target which it will automatically pick up and add to the ring, though this is not sustainable.

Healing and damaging particles look the same
Particles look fairly inocuous to begin with
Names and numbers are placeholders for now (but they convey the idea)

Concept Images
1 - Possible look of final explosion
2 - Possible look of final explosion
3 - Stepping on Healing particle
4 - Stepping on Damaging particle
5 - Particle ring (purple) with launched energy (blue)

Edit: End of the day progress report
Work done: 4 hours
Lines: 630
Status: Miles off
 

Attachments

  • Concept 2.png
    Concept 2.png
    157.4 KB · Views: 152
  • Concept 3.png
    Concept 3.png
    183.5 KB · Views: 143
  • Concept 4.png
    Concept 4.png
    178.5 KB · Views: 111
  • Concept 5.png
    Concept 5.png
    262.6 KB · Views: 145
  • Concept 1.png
    Concept 1.png
    192.4 KB · Views: 146
Last edited:
Level 33
Joined
Apr 24, 2012
Messages
5,113
Alright! Let's get this show on the road

Purpose: Particle punisher is a two-part mind game ability designed to incentivise enemies into playing a high-risk-high-reward game with the player centred around making quick choices.

how it works:
The ability is split into two parts which activate depending on the target (it can either target units or the ground) the first part (when targetting the ground) launches particles which land and can be picked up (automatically picked up when an enemy comes into close range), depending on how close the target point was to an enemy unit when the particle was fired determines whether or not the particle will damage or heal the opponent. The second (when targetting a unit) punishes opponents who have been tricked multiple times in a short period by firing a particle at them dealing damage per successful deception.

Specifics:
Part 1: Each particle lasts 5 seconds, healing particles heal for 4x as much as damaging ones and the longer a particle lies on the floor the weaker its effect becomes (higher reward for picking up a particle quickly) units which pick up a particle will also be given a buff which slows them down exponentially (damaging packets increase the level/slow while healing ones reduce the level/slow) and adds a particle to a ring above them (1 for a heal particle, 2 for a damage particle) the slow buff automatically reduces in level every couple of seconds and is removed once it hits level 0, when this happens the particle ring is also removed (without damaging the afflicted unit) Level 1 slow has a 0% speed reduction (applies if the unit has no buff and picked up a healing particle) Level 2 has a 15% speed reduction (applies if the unit has no buff and picked up a damaging particle) and can go up to 5 levels

Part 2: A large high-velocity tracking particle is fired at a target unit, if the unit moves away enough the particle will disappear (miss the target). On hit the unit is stunned for a brief period and all nearby particles (damage and healing) are pulled into and also hit the target unit and add to the particle ring, the main projectile itself deals no damage. If there are particles in the particle ring when the stun is about to expire then each particle will launch the energy contained into the target unit adding additional time into the stun, if the target unit dies during this period then the remaining energy is released in an explosion centred around the target, if there is a particularly high amount of particles in the ring then it is possible for the casting unit to place damaging particles at the feet of the target which it will automatically pick up and add to the ring, though this is not sustainable.

Healing and damaging particles look the same
Particles look fairly inocuous to begin with
Names and numbers are placeholders for now (but they convey the idea)

Concept Images
1 - Possible look of final explosion
2 - Possible look of final explosion
3 - Stepping on Healing particle
4 - Stepping on Damaging particle
5 - Particle ring (purple) with launched energy (blue)

Edit: End of the day progress report
Work done: 4 hours
Lines: 630
Status: Miles off

and, of course, eye candies :D You really have the ability to create eye candies even in the hardest themes. dayum
 

Ardenian

A

Ardenian

Hm, I have an idea, but I am unsure of it, it does not sound good to me, could you comment on it, please ?


Ability: Mirrorique ( cheap English-French mix)
Basically, the hero uses an ability to become invisible, like Windwalk.
If the caster casts any ability now, while having the buff,
then a visible dummy unit will be created and ordered the same ( = dummy order, doing no harm) order, instead of the caster who will be stopped, remaining invisible and lurking.
The second part would be a second spell that allows to create an invisible duplicate of the hero with the same buff, causing additional confusion.

This idea has some severe problems though, starting with the problem that you need low mana cost/ high mana amount and low cooldowns to efficiently use this ability.
Furthermore, the idea isn't very original, in my opinion.

What do you say ?
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
'Kay.. Here is what I will be doing. Concept will likely be heavily tweaked, the only thing I am dead certain about is the goldmine, but that alone is too simple so I have to make it a multiuse ability.

Corruption(name pending)

Sends out disrupting spirits towards a certain object, giving the object a negative effect for a set period of time.

Examples:
Cast Corruption on a gold mine and whoever tries to harvest it will instantly die.
Cast Corruption on an shop and all sold units/items from that shop will be.. void.
Cast Corruption on an enemy and he will be dealing periodic damage to all nearby allies.
Cast Corruption on the ground and some sort of flower will deal damage to an enemy who goes close to it.
 
I've made a fair bit of progress, thought I'd make a quick (and a bit choppy) GIF to show some of the mechanics I'm working on for the spell

Firstly: The AOE target indicator can be used to figure out whether or not a particle you launch will be a healing one or a damaging one
Secondly: The particle pickup overshoots the target indicator slightly so enemies need to be aware of the direction it came from to help figure out what kind it is, the trajectory is also oddly curved to help further disorientate enemies (the closer you aim to yourself the more curved it becomes)
Thirdly: 60% of the damage is dealt by the initial blast, the remaining 40% is dealt by the particles that are created on explosion (which home in on the target but can be escaped)

I haven't yet applied the slow mechanics or the particle ring mechanics so I don't have a GIF of them yet

Obviously it's in need of a bit of refinement but it's getting there

Edit: end of the day progress report
Work done: 9 hours
Lines: 925
Status: 1/3 done
 

Attachments

  • Zephyr Contest #13 WIP.gif
    Zephyr Contest #13 WIP.gif
    5.8 MB · Views: 168
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Just a WIP.

Have been working on object datas and some triggers. One of them:

  • PD Missile
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Custom script: set udg_PD__Missile__Timer = CreateTimer()
      • Custom script: set udg_PD__MaxX = GetRectMaxX(bj_mapInitialPlayableArea)
      • Custom script: set udg_PD__MaxY = GetRectMaxY(bj_mapInitialPlayableArea)
      • Custom script: set udg_PD__MinX = GetRectMinX(bj_mapInitialPlayableArea)
      • Custom script: set udg_PD__MinY = GetRectMinY(bj_mapInitialPlayableArea)
      • Custom script: endfunction
      • Custom script:
      • Custom script:
      • Custom script: function PD__Missile__Callback takes nothing returns nothing
      • Custom script: local real s
        • Do Multiple ActionsFor each (Integer PD__Index) from 1 to PD__Missile__Count, do (Actions)
          • Loop - Actions
            • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • PD__Missile__Distance[PD__Index] Greater than (>) 0.00
              • Then - Actions
                • Set PD__Missile__LocX[PD__Index] = (PD__Missile__LocX[PD__Index] + (PD__Config__Speed[PD__Main__Level[PD__Missile__Source[PD__Index]]] x (Cos(PD__Missile__Angle[PD__Index]))))
                • Set PD__Missile__LocY[PD__Index] = (PD__Missile__LocY[PD__Index] + (PD__Config__Speed[PD__Main__Level[PD__Missile__Source[PD__Index]]] x (Sin(PD__Missile__Angle[PD__Index]))))
                • Set PD__Missile__Distance[PD__Index] = (PD__Missile__Distance[PD__Index] - PD__Config__Speed[PD__Main__Level[PD__Missile__Source[PD__Index]]])
                  • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • PD__Missile__LocX[PD__Index] Less than (<) PD__MaxX
                      • PD__Missile__LocY[PD__Index] Less than (<) PD__MaxY
                      • PD__Missile__LocX[PD__Index] Greater than (>) PD__MinX
                      • PD__Missile__LocY[PD__Index] Greater than (>) PD__MinY
                    • Then - Actions
                      • Custom script: call SetUnitX(udg_PD__Missile__Dagger[udg_PD__Index], udg_PD__Missile__LocX[udg_PD__Index])
                      • Custom script: call SetUnitY(udg_PD__Missile__Dagger[udg_PD__Index], udg_PD__Missile__LocY[udg_PD__Index])
                      • Custom script: if udg_PD__Missile__Real[udg_PD__Index] then
                      • Custom script: call GroupEnumUnitsInRange(udg_PD__TempGroup, udg_PD__Missile__LocX[udg_PD__Index], udg_PD__Missile__LocY[udg_PD__Index], 100, null)
                      • Custom script: else
                      • Custom script: if udg_PD__Missile__Distance[udg_PD__Index] < udg_PD__Config__Distance[udg_PD__Main__Level[udg_PD__Index]] then
                      • Custom script: if udg_PD__Missile__AlphaRate[udg_PD__Index] == 0 then
                      • Set PD__Missile__AlphaRate[PD__Index] = (PD__Missile__Alpha[PD__Index] / (Integer((PD__Config__Distance[PD__Missile__Source[PD__Index]] / PD__Config__Speed[PD__Missile__Source[PD__Index]]))))
                      • Custom script: endif
                      • Set PD__Missile__AlphaNow[PD__Index] = (PD__Missile__AlphaNow[PD__Index] - PD__Missile__AlphaRate[PD__Index])
                      • Custom script: if udg_PD__Missile__AlphaNow[udg_PD__Index] > 0 then
                      • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Index], 255, 255, 255, udg_PD__Missile__AlphaNow[udg_PD__Index])
                      • Custom script: else
                      • -------- dispose --------
                      • Custom script: endif
                      • Custom script: endif
                      • Custom script: endif
                    • Else - Actions
                      • -------- dispose --------
              • Else - Actions
                • -------- dispose --------
      • Custom script: endfunction
      • Custom script:
      • Custom script:
      • Custom script: function PD__LaunchMissile takes nothing returns nothing
      • Custom script: local real d = udg_PD__Config__Distance[udg_PD__Main__Level[udg_PD__LaunchSource]]
      • Custom script: local real a = GetRandomReal(-bj_PI, bj_PI)
      • Custom script: local real x = GetUnitX(udg_PD__Main__Target[udg_PD__LaunchSource]) + d * Cos(a)
      • Custom script: local real y = GetUnitY(udg_PD__Main__Target[udg_PD__LaunchSource]) + d * Sin(a)
      • Set PD__Missile__Count = (PD__Missile__Count + 1)
      • Set PD__Missile__Source[PD__Missile__Count] = PD__LaunchSource
      • Custom script: set udg_PD__Missile__Real[udg_PD__Missile__Count] = udg_PD__LaunchType
      • Custom script: set udg_PD__Missile__LocX[udg_PD__Missile__Count] = x
      • Custom script: set udg_PD__Missile__LocY[udg_PD__Missile__Count] = y
      • Custom script: set udg_PD__Missile__Angle[udg_PD__Missile__Count] = a
      • Custom script: set udg_PD__Missile__Distance[udg_PD__Missile__Count] = d
      • Custom script: set udg_PD__Missile__Dagger[udg_PD__Missile__Count] = CreateUnit(udg_PD__Main__Owner[udg_PD__LaunchSource], udg_PD__Config__DummyID, x, y, a*bj_RADTODEG)
      • Special Effect - Create a special effect attached to the overhead of PD__Missile__Dagger[PD__Missile__Count] using PD__Config__MissileGfx
      • Set PD__Missile__Gfx[PD__Missile__Count] = (Last created special effect)
      • Set PD__Missile__AlphaRate[PD__Missile__Count] = 0
      • Custom script: if udg_PD__LaunchType then
      • Set PD__Missile__Alpha[PD__Missile__Count] = PD__Config__RealAlpha[PD__Main__Level[PD__LaunchSource]]
      • Custom script: else
      • Set PD__Missile__Alpha[PD__Missile__Count] = PD__Config__FakeAlpha[PD__Main__Level[PD__LaunchSource]]
      • Custom script: endif
      • Set PD__Missile__AlphaNow[PD__Missile__Count] = PD__Missile__Alpha[PD__Missile__Count]
      • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Missile__Count], 255, 255, 255, udg_PD__Missile__AlphaNow[udg_PD__Missile__Count])
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • PD__Missile__Count Equal to (==) 1
          • Then - Actions
            • Custom script: call TimerStart(udg_PD__Missile__Timer, 0.031250, true, function PD__Missile__Callback)
          • Else - Actions
 

Kyrbi0

Arena Moderator
Level 45
Joined
Jul 29, 2008
Messages
9,492
Oh, don't get me wrong; I'm sure you're doing a great job. And I love GUI; it's all I use as well. But you're code is a massive, implacable stretch of Custom Script (JASS written into GUI), punctuated rarely by variable calls & whatnot. It's not bad, but I'm not sure it can really be called "GUI" too much anymore. ; )
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Oh, don't get me wrong; I'm sure you're doing a great job. And I love GUI; it's all I use as well. But you're code is a massive, implacable stretch of Custom Script (JASS written into GUI), punctuated rarely by variable calls & whatnot. It's not bad, but I'm not sure it can really be called "GUI" too much anymore. ; )

I use custom scripts for optimizations, but I'm going make it "as GUI as possible". :)

EDIT:

Better? :p

  • PD Missile
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Custom script: set udg_PD__Missile__Timer = CreateTimer()
      • Set PD__MaxX = (Max X of (Playable map area))
      • Set PD__MaxY = (Max Y of (Playable map area))
      • Set PD__MinX = (Min X of (Playable map area))
      • Set PD__MinY = (Min Y of (Playable map area))
      • Custom script: endfunction
      • Custom script:
      • Custom script:
      • Custom script: function PD__Missile__Dispose takes integer i returns integer
      • Custom script: return i
      • Custom script: endfunction
      • Custom script:
      • Custom script:
      • Custom script: function PD__Missile__Callback takes nothing returns nothing
        • Do Multiple ActionsFor each (Integer PD__Index) from 1 to PD__Missile__Count, do (Actions)
          • Loop - Actions
            • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • PD__Missile__Distance[PD__Index] Greater than (>) 0.00
              • Then - Actions
                • Set PD__Missile__LocX[PD__Index] = (PD__Missile__LocX[PD__Index] + (PD__Config__Speed[PD__Main__Level[PD__Missile__Source[PD__Index]]] x (Cos(PD__Missile__Angle[PD__Index]))))
                • Set PD__Missile__LocY[PD__Index] = (PD__Missile__LocY[PD__Index] + (PD__Config__Speed[PD__Main__Level[PD__Missile__Source[PD__Index]]] x (Sin(PD__Missile__Angle[PD__Index]))))
                • Set PD__Missile__Distance[PD__Index] = (PD__Missile__Distance[PD__Index] - PD__Config__Speed[PD__Main__Level[PD__Missile__Source[PD__Index]]])
                  • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • PD__Missile__LocX[PD__Index] Less than (<) PD__MaxX
                      • PD__Missile__LocY[PD__Index] Less than (<) PD__MaxY
                      • PD__Missile__LocX[PD__Index] Greater than (>) PD__MinX
                      • PD__Missile__LocY[PD__Index] Greater than (>) PD__MinY
                    • Then - Actions
                      • Custom script: call SetUnitX(udg_PD__Missile__Dagger[udg_PD__Index], udg_PD__Missile__LocX[udg_PD__Index])
                      • Custom script: call SetUnitY(udg_PD__Missile__Dagger[udg_PD__Index], udg_PD__Missile__LocY[udg_PD__Index])
                        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                          • If - Conditions
                            • PD__Missile__Real[PD__Index] Equal to (==) True
                          • Then - Actions
                            • Custom script: call GroupEnumUnitsInRange(udg_PD__TempGroup, udg_PD__Missile__LocX[udg_PD__Index], udg_PD__Missile__LocY[udg_PD__Index], 100, null)
                            • Custom script: loop
                            • Custom script: set udg_PD__TempUnit = FirstOfGroup(udg_PD__TempGroup)
                            • Custom script: exitwhen udg_PD__TempUnit == null
                            • Unit Group - Remove PD__TempUnit from PD__TempGroup
                              • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • PD__TempUnit Equal to (==) PD__Main__Target[PD__Missile__Source[PD__Index]]
                                • Then - Actions
                                • Else - Actions
                            • Custom script: endloop
                          • Else - Actions
                            • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                              • If - Conditions
                                • PD__Missile__Distance[PD__Index] Less than (<) PD__Config__FadeDistance[PD__Main__Level[PD__Missile__Source[PD__Index]]]
                              • Then - Actions
                                • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                  • If - Conditions
                                    • PD__Missile__AlphaRate[PD__Index] Equal to (==) 0
                                  • Then - Actions
                                    • Set PD__Missile__AlphaRate[PD__Index] = (PD__Missile__Alpha[PD__Index] / (Integer((PD__Config__Distance[PD__Missile__Source[PD__Index]] / PD__Config__Speed[PD__Missile__Source[PD__Index]]))))
                                  • Else - Actions
                                • Set PD__Missile__AlphaNow[PD__Index] = (PD__Missile__AlphaNow[PD__Index] - PD__Missile__AlphaRate[PD__Index])
                                  • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • PD__Missile__AlphaNow[PD__Index] Greater than (>) PD__Missile__AlphaRate[PD__Index]
                                    • Then - Actions
                                      • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Index], 255, 255, 255, udg_PD__Missile__AlphaNow[udg_PD__Index])
                                    • Else - Actions
                                      • -------- dispose --------
                                      • Custom script: set udg_PD__Index = PD__Missile__Dispose(udg_PD__Index)
                              • Else - Actions
                    • Else - Actions
                      • -------- dispose --------
                      • Custom script: set udg_PD__Index = PD__Missile__Dispose(udg_PD__Index)
              • Else - Actions
                • -------- dispose --------
                • Custom script: set udg_PD__Index = PD__Missile__Dispose(udg_PD__Index)
      • Custom script: endfunction
      • Custom script:
      • Custom script:
      • Custom script: function PD__LaunchMissile takes nothing returns nothing
      • Custom script: local real a = GetRandomReal(-bj_PI, bj_PI)
      • Custom script: local real d = udg_PD__Config__Distance[udg_PD__Main__Level[udg_PD__LaunchSource]]
      • Custom script: local real x = GetUnitX(udg_PD__Main__Target[udg_PD__LaunchSource]) + d * Cos(a)
      • Custom script: local real y = GetUnitY(udg_PD__Main__Target[udg_PD__LaunchSource]) + d * Sin(a)
      • Set PD__Missile__Count = (PD__Missile__Count + 1)
      • Set PD__Missile__Real[PD__Missile__Count] = PD__LaunchType
      • Set PD__Missile__Source[PD__Missile__Count] = PD__LaunchSource
      • Custom script: set udg_PD__Missile__LocX[udg_PD__Missile__Count] = x
      • Custom script: set udg_PD__Missile__LocY[udg_PD__Missile__Count] = y
      • Custom script: set udg_PD__Missile__Angle[udg_PD__Missile__Count] = a
      • Custom script: set udg_PD__Missile__Distance[udg_PD__Missile__Count] = d
      • Custom script: set udg_PD__Missile__Dagger[udg_PD__Missile__Count] = CreateUnit(udg_PD__Main__Owner[udg_PD__LaunchSource], udg_PD__Config__DummyID, x, y, a*bj_RADTODEG)
      • Special Effect - Create a special effect attached to the overhead of PD__Missile__Dagger[PD__Missile__Count] using PD__Config__MissileGfx
      • Set PD__Missile__Gfx[PD__Missile__Count] = (Last created special effect)
      • Set PD__Missile__AlphaRate[PD__Missile__Count] = 0
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • PD__LaunchType Equal to (==) True
          • Then - Actions
            • Set PD__Missile__Alpha[PD__Missile__Count] = PD__Config__RealAlpha[PD__Main__Level[PD__LaunchSource]]
          • Else - Actions
            • Set PD__Missile__Alpha[PD__Missile__Count] = PD__Config__FakeAlpha[PD__Main__Level[PD__LaunchSource]]
      • Set PD__Missile__AlphaNow[PD__Missile__Count] = PD__Missile__Alpha[PD__Missile__Count]
      • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Missile__Count], 255, 255, 255, udg_PD__Missile__AlphaNow[udg_PD__Missile__Count])
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • PD__Missile__Count Equal to (==) 1
          • Then - Actions
            • Custom script: call TimerStart(udg_PD__Missile__Timer, 0.031250, true, function PD__Missile__Callback)
          • Else - Actions
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
First trigger is done. :)


  • PD Missile
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- Initializations --------
      • Custom script: set udg_PD__Missile__Timer = CreateTimer()
      • Set PD__MaxX = (Max X of (Playable map area))
      • Set PD__MaxY = (Max Y of (Playable map area))
      • Set PD__MinX = (Min X of (Playable map area))
      • Set PD__MinY = (Min Y of (Playable map area))
      • Custom script: endfunction
      • Custom script:
      • Custom script: function PD__Missile__Dispose takes nothing returns nothing
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • PD__Missile__Real[PD__Index] Equal to (==) True
          • Then - Actions
            • Set PD__Main__HitCount[PD__Missile__Source[PD__Index]] = (PD__Main__HitCount[PD__Missile__Source[PD__Index]] + 1)
          • Else - Actions
      • Set PD__Main__MissileCount[PD__Missile__Source[PD__Index]] = (PD__Main__MissileCount[PD__Missile__Source[PD__Index]] - 1)
      • Custom script: endfunction
      • Custom script:
      • Custom script: function PD__Missile__Callback takes nothing returns nothing
      • Custom script: local player p = GetLocalPlayer()
      • Custom script: local boolean isLocal
        • Do Multiple ActionsFor each (Integer PD__Index) from 1 to PD__Missile__Count, do (Actions)
          • Loop - Actions
            • Custom script: set isLocal = p == udg_PD__Main__Enemy[udg_PD__Missile__Source[udg_PD__Index]] or p == udg_PD__Main__Owner[udg_PD__Missile__Source[udg_PD__Index]]
              • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • PD__Missile__AlphaNow[PD__Index] Less than (<) PD__Missile__Alpha[PD__Index]
                • Then - Actions
                  • Set PD__Missile__AlphaNow[PD__Index] = (PD__Missile__AlphaNow[PD__Index] + PD__Missile__AlphaRate[PD__Index])
                    • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                      • If - Conditions
                        • PD__Missile__AlphaNow[PD__Index] Greater than (>) PD__Missile__Alpha[PD__Index]
                      • Then - Actions
                        • Set PD__Missile__AlphaNow[PD__Index] = PD__Missile__Alpha[PD__Index]
                      • Else - Actions
                    • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                      • If - Conditions
                        • PD__Missile__Real[PD__Index] Equal to (==) False
                        • PD__Main__Cursed[PD__Missile__Source[PD__Index]] Equal to (==) True
                      • Then - Actions
                        • Custom script: if isLocal then
                        • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Index], 255, 255, 255, udg_PD__Missile__AlphaNow[udg_PD__Index])
                        • Custom script: endif
                      • Else - Actions
                        • Custom script: if isLocal then
                        • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Index], 255, 255, 255, 0)
                        • Custom script: endif
                • Else - Actions
            • Set PD__Missile__LocX[PD__Index] = (PD__Missile__LocX[PD__Index] + (PD__Config__Speed[PD__Main__Level[PD__Missile__Source[PD__Index]]] x (Cos(PD__Missile__Angle[PD__Index]))))
            • Set PD__Missile__LocY[PD__Index] = (PD__Missile__LocY[PD__Index] + (PD__Config__Speed[PD__Main__Level[PD__Missile__Source[PD__Index]]] x (Sin(PD__Missile__Angle[PD__Index]))))
            • Set PD__Missile__Distance[PD__Index] = (PD__Missile__Distance[PD__Index] - PD__Config__Speed[PD__Main__Level[PD__Missile__Source[PD__Index]]])
              • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • PD__Missile__LocX[PD__Index] Less than (<) PD__MaxX
                  • PD__Missile__LocY[PD__Index] Less than (<) PD__MaxY
                  • PD__Missile__LocX[PD__Index] Greater than (>) PD__MinX
                  • PD__Missile__LocY[PD__Index] Greater than (>) PD__MinY
                • Then - Actions
                  • Custom script: call SetUnitX(udg_PD__Missile__Dagger[udg_PD__Index], udg_PD__Missile__LocX[udg_PD__Index])
                  • Custom script: call SetUnitY(udg_PD__Missile__Dagger[udg_PD__Index], udg_PD__Missile__LocY[udg_PD__Index])
                    • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                      • If - Conditions
                        • PD__Missile__Real[PD__Index] Equal to (==) True
                      • Then - Actions
                        • Custom script: call GroupEnumUnitsInRange(udg_PD__TempGroup, udg_PD__Missile__LocX[udg_PD__Index], udg_PD__Missile__LocY[udg_PD__Index], udg_PD__Config__HitRadius, null)
                        • Custom script: loop
                        • Custom script: set udg_PD__TempUnit = FirstOfGroup(udg_PD__TempGroup)
                        • Custom script: exitwhen udg_PD__TempUnit == null
                        • Unit Group - Remove PD__TempUnit from PD__TempGroup
                          • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • PD__TempUnit Equal to (==) PD__Main__Target[PD__Missile__Source[PD__Index]]
                            • Then - Actions
                              • Set PD__Main__Cursed[PD__Index] = True
                              • Set PD__Main__HitCount[PD__Index] = (PD__Main__HitCount[PD__Index] + 1)
                              • Unit - Cause PD__Main__Caster[PD__Missile__Source[PD__Index]] to damage PD__Main__Target[PD__Missile__Source[PD__Index]], dealing PD__Config__Damage[PD__Main__Level[PD__Missile__Source[PD__Index]]] damage of attack type PD__Config__AttackType and damage type PD__Config__DamageType
                              • Special Effect - Create a special effect attached to the PD__Config__HitGfxPt of PD__TempUnit using PD__Config__HitGfx
                              • Special Effect - Destroy (Last created special effect)
                              • -------- Dispose --------
                              • Custom script: call PD__Missile__Dispose()
                            • Else - Actions
                        • Custom script: endloop
                      • Else - Actions
                    • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                      • If - Conditions
                        • PD__Missile__Distance[PD__Index] Less than (<) PD__Config__FadeDistance[PD__Main__Level[PD__Missile__Source[PD__Index]]]
                      • Then - Actions
                        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                          • If - Conditions
                            • PD__Missile__AlphaNow[PD__Index] Greater than (>) PD__Missile__AlphaRate[PD__Index]
                          • Then - Actions
                            • Set PD__Missile__AlphaNow[PD__Index] = (PD__Missile__AlphaNow[PD__Index] - PD__Missile__AlphaRate[PD__Index])
                            • Custom script: if isLocal then
                            • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Index], 255, 255, 255, udg_PD__Missile__AlphaNow[udg_PD__Index])
                            • Custom script: endif
                          • Else - Actions
                            • -------- Dispose --------
                            • Custom script: call PD__Missile__Dispose()
                      • Else - Actions
                • Else - Actions
                  • -------- Dispose --------
                  • Custom script: call PD__Missile__Dispose()
      • Custom script: endfunction
      • Custom script:
      • Custom script: function PD__LaunchMissile takes nothing returns nothing
      • Custom script: local real a = GetRandomReal(-bj_PI, bj_PI)
      • Custom script: local real d = udg_PD__Config__Distance[udg_PD__Main__Level[udg_PD__LaunchSource]]
      • Custom script: local real x = GetUnitX(udg_PD__Main__Target[udg_PD__LaunchSource]) + d * Cos(a)
      • Custom script: local real y = GetUnitY(udg_PD__Main__Target[udg_PD__LaunchSource]) + d * Sin(a)
      • Set PD__Missile__Count = (PD__Missile__Count + 1)
      • Set PD__Missile__Real[PD__Missile__Count] = PD__LaunchType
      • Set PD__Missile__Source[PD__Missile__Count] = PD__LaunchSource
      • Custom script: set udg_PD__Missile__LocX[udg_PD__Missile__Count] = x
      • Custom script: set udg_PD__Missile__LocY[udg_PD__Missile__Count] = y
      • Custom script: set udg_PD__Missile__Angle[udg_PD__Missile__Count] = a
      • Custom script: set udg_PD__Missile__Dagger[udg_PD__Missile__Count] = CreateUnit(udg_PD__Main__Owner[udg_PD__LaunchSource], udg_PD__Config__DummyID, x, y, a*bj_RADTODEG)
      • Special Effect - Create a special effect attached to the overhead of PD__Missile__Dagger[PD__Missile__Count] using PD__Config__MissileGfx
      • Set PD__Missile__Gfx[PD__Missile__Count] = (Last created special effect)
      • Set PD__Missile__AlphaRate[PD__Missile__Count] = (PD__Missile__Alpha[PD__Missile__Count] / (Integer((PD__Config__Distance[PD__LaunchSource] / PD__Config__Speed[PD__LaunchSource]))))
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • PD__LaunchType Equal to (==) True
          • Then - Actions
            • Set PD__Missile__Alpha[PD__Missile__Count] = PD__Config__RealNormalAlpha[PD__Main__Level[PD__LaunchSource]]
            • Custom script: set udg_PD__Missile__Distance[udg_PD__Missile__Count] = d*udg_PD__Config__RealDistanceFactor
          • Else - Actions
            • Set PD__Missile__Alpha[PD__Missile__Count] = PD__Config__FakeNormalAlpha[PD__Main__Level[PD__LaunchSource]]
            • Custom script: set udg_PD__Missile__Distance[udg_PD__Missile__Count] = d
      • Set PD__Missile__AlphaNow[PD__Missile__Count] = PD__Missile__Alpha[PD__Missile__Count]
      • -------- Hide dagger from all players --------
      • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Missile__Count], 255, 255, 255, 0)
      • -------- Reveal only to the caster and the target --------
      • Custom script: if GetLocalPlayer() == udg_PD__Main__Enemy[udg_PD__LaunchSource] or GetLocalPlayer() == udg_PD__Main__Owner[udg_PD__LaunchSource] then
      • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Missile__Count], 255, 255, 255, udg_PD__Missile__AlphaNow[udg_PD__Missile__Count])
      • Custom script: endif
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • PD__Missile__Count Equal to (==) 1
          • Then - Actions
            • Custom script: call TimerStart(udg_PD__Missile__Timer, udg_PD__Config__Interval, true, function PD__Missile__Callback)
          • Else - Actions

Spell descriptions:
Tosses a delusioning dagger which attacks the target thrice. Any contact with the dagger will curse the victim to illude of being stormed by streaks of daggers, but only the real one may hit the victim. Every successfully landed attack causes a destructive damage of 150.
Level 1 - Fake daggers are easy to recognize.
Level 2 - Fake daggers are hard to recognize.
Level 3 - Fake daggers are very hard to recognize.


~Concept~
It's quite a tricky spell, if you are a victim of this spell you gotta concentrate and decide which one of those daggers are the real one, and of course you gotta avoid it. Otherwise, you will get a painful penalty of 150 damage every hit. Yet, it's not a perfect spell tho. It has downwards for the caster. In order to illude your target, you gonna have to lay at least one hit to the target. The first shot will always be a "real dagger", missing the first one will be a big disadvantage for the caster. In short, your target can only see "fake daggers" if only it has been illuded. So far, that's the concept. :)


Come on guys, keep the thread alive ;)
 
Last edited:
Bannar is a judge now.

Interesting, I may or may not join depending on the free time I have.
So it requires WIPS huh.But for example if person A posted a WIP and person B is already working on a spell very similar to person A's WIP, then what appropriate action shpuld person B do?

EDIT: Is the criteria for contest judging equally distributed? All have 33.333%?
If there is a problem judges will manage it.

The average of all judge score points will be takes and be used as "JudgeScore" in main formula.
But the poll and votes will also play a role, and also depend on amount of total votes.

Oh, the Quilnez jumps around from vJass, JASS, GUI, the Master of all classes!
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Come on, you shouldn't say that around the Real Master >.>

I'm nowhere close to sir Bribe's mastery :D

EDIT:
Finished with the triggers.

  • PD Config
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- Object Editor data --------
      • Set PD__Config__SpellID = Phantasm Dagger
      • Set PD__Config__DummyID = Panthasm Dagger (Missile)
      • -------- Spell configuration --------
      • -------- 1. Dealt damage on hit --------
      • Set PD__Config__Damage[1] = 200.00
      • Set PD__Config__Damage[2] = 200.00
      • Set PD__Config__Damage[3] = 200.00
      • -------- 2. Number of attacks before the spell is ended --------
      • Set PD__Config__HitCount[1] = 3
      • Set PD__Config__HitCount[2] = 3
      • Set PD__Config__HitCount[3] = 3
      • -------- 3. Delay between launched daggers --------
      • Set PD__Config__DelayMin[1] = 0.30
      • Set PD__Config__DelayMin[2] = 0.20
      • Set PD__Config__DelayMin[3] = 0.10
      • -------- - --------
      • Set PD__Config__DelayMax[1] = 1.00
      • Set PD__Config__DelayMax[2] = 0.80
      • Set PD__Config__DelayMax[3] = 0.60
      • -------- - --------
      • Set PD__Config__Speed[1] = 35.00
      • Set PD__Config__Speed[2] = 35.00
      • Set PD__Config__Speed[3] = 35.00
      • -------- - --------
      • Set PD__Config__FadeDistance[1] = 200.00
      • Set PD__Config__FadeDistance[2] = 200.00
      • Set PD__Config__FadeDistance[3] = 200.00
      • -------- - --------
      • Set PD__Config__FakeStartAlpha[1] = 0
      • Set PD__Config__FakeStartAlpha[2] = 0
      • Set PD__Config__FakeStartAlpha[3] = 0
      • -------- - --------
      • Set PD__Config__FakeNormalAlpha[1] = 70
      • Set PD__Config__FakeNormalAlpha[2] = 110
      • Set PD__Config__FakeNormalAlpha[3] = 150
      • -------- - --------
      • Set PD__Config__RealStartAlpha[1] = 0
      • Set PD__Config__RealStartAlpha[2] = 0
      • Set PD__Config__RealStartAlpha[3] = 0
      • -------- - --------
      • Set PD__Config__RealNormalAlpha[1] = 255
      • Set PD__Config__RealNormalAlpha[2] = 255
      • Set PD__Config__RealNormalAlpha[3] = 255
      • -------- - --------
      • Set PD__Config__Distance[1] = 800.00
      • Set PD__Config__Distance[2] = 800.00
      • Set PD__Config__Distance[3] = 800.00
      • -------- - --------
      • Set PD__Config__RealRate[1] = 25.00
      • Set PD__Config__RealRate[2] = 25.00
      • Set PD__Config__RealRate[3] = 25.00
      • -------- - --------
      • Set PD__Config__HitRadius = 100.00
      • -------- - --------
      • Set PD__Config__DistanceFactor = 2.00
      • -------- - --------
      • Set PD__Config__Height = 60.00
      • -------- - --------
      • Set PD__Config__Interval = 0.03
      • -------- - --------
      • Set PD__Config__AttackType = Hero
      • Set PD__Config__DamageType = Normal
      • -------- 5. On hit effect --------
      • Set PD__Config__HitGfx = Abilities\Spells\Other\Stampede\StampedeMissileDeath.mdl
      • Set PD__Config__HitGfxPt = chest
  • PD Missile
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- Initializations --------
      • Set PD__MaxX = (Max X of (Playable map area))
      • Set PD__MaxY = (Max Y of (Playable map area))
      • Set PD__MinX = (Min X of (Playable map area))
      • Set PD__MinY = (Min Y of (Playable map area))
      • Custom script: set udg_PD__Missile__Timer = CreateTimer()
      • Custom script: endfunction
      • Custom script:
      • Custom script: function PD__Missile__Dispose takes nothing returns nothing
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • PD__Missile__Real[PD__Index] Equal to (==) True
          • Then - Actions
            • Set PD__Main__RealLaunched[PD__Missile__Source[PD__Index]] = False
            • Set PD__Main__HitCount[PD__Missile__Source[PD__Index]] = (PD__Main__HitCount[PD__Missile__Source[PD__Index]] + 1)
          • Else - Actions
      • Set PD__Main__MissileCount[PD__Missile__Source[PD__Index]] = (PD__Main__MissileCount[PD__Missile__Source[PD__Index]] - 1)
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • PD__Main__MissileCount[PD__Missile__Source[PD__Index]] Equal to (==) 0
          • Then - Actions
            • -------- Dispose main spell --------
              • Do Multiple ActionsFor each (Integer PD__TempInt) from 1 to PD__Missile__Count, do (Actions)
                • Loop - Actions
                  • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • PD__Missile__Source[PD__TempInt] Equal to (==) PD__Main__Count
                    • Then - Actions
                      • Set PD__Missile__Source[PD__TempInt] = PD__Missile__Source[PD__Index]
                    • Else - Actions
            • Set PD__Main__Caster[PD__Missile__Source[PD__Index]] = PD__Main__Caster[PD__Main__Count]
            • Set PD__Main__Cursed[PD__Missile__Source[PD__Index]] = PD__Main__Cursed[PD__Main__Count]
            • Set PD__Main__Delay[PD__Missile__Source[PD__Index]] = PD__Main__Delay[PD__Main__Count]
            • Set PD__Main__Enemy[PD__Missile__Source[PD__Index]] = PD__Main__Enemy[PD__Main__Count]
            • Set PD__Main__HitCount[PD__Missile__Source[PD__Index]] = PD__Main__HitCount[PD__Main__Count]
            • Set PD__Main__Level[PD__Missile__Source[PD__Index]] = PD__Main__Level[PD__Main__Count]
            • Set PD__Main__MissileCount[PD__Missile__Source[PD__Index]] = PD__Main__MissileCount[PD__Main__Count]
            • Set PD__Main__Owner[PD__Missile__Source[PD__Index]] = PD__Main__Owner[PD__Main__Count]
            • Set PD__Main__RealCount[PD__Missile__Source[PD__Index]] = PD__Main__RealCount[PD__Main__Count]
            • Set PD__Main__Target[PD__Missile__Source[PD__Index]] = PD__Main__Target[PD__Main__Count]
            • Set PD__Main__Caster[PD__Main__Count] = No unit
            • Set PD__Main__Target[PD__Main__Count] = No unit
            • Set PD__Main__Count = (PD__Main__Count - 1)
              • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • PD__Main__Count Equal to (==) 0
                • Then - Actions
                  • Custom script: call PauseTimer(udg_PD__Main__Timer)
                • Else - Actions
          • Else - Actions
      • Unit - Remove PD__Missile__Dagger[PD__Index] from the game
      • -------- Deindex missile --------
      • Set PD__Missile__Alpha[PD__Index] = PD__Missile__Alpha[PD__Missile__Count]
      • Set PD__Missile__AlphaNow[PD__Index] = PD__Missile__AlphaNow[PD__Missile__Count]
      • Set PD__Missile__AlphaRate[PD__Index] = PD__Missile__AlphaRate[PD__Missile__Count]
      • Set PD__Missile__Angle[PD__Index] = PD__Missile__Angle[PD__Missile__Count]
      • Set PD__Missile__Dagger[PD__Index] = PD__Missile__Dagger[PD__Missile__Count]
      • Set PD__Missile__Distance[PD__Index] = PD__Missile__Distance[PD__Missile__Count]
      • Set PD__Missile__Hit[PD__Index] = PD__Missile__Hit[PD__Missile__Count]
      • Set PD__Missile__LocX[PD__Index] = PD__Missile__LocX[PD__Missile__Count]
      • Set PD__Missile__LocY[PD__Index] = PD__Missile__LocY[PD__Missile__Count]
      • Set PD__Missile__Real[PD__Index] = PD__Missile__Real[PD__Missile__Count]
      • Set PD__Missile__Source[PD__Index] = PD__Missile__Source[PD__Missile__Count]
      • Set PD__Missile__Dagger[PD__Missile__Count] = No unit
      • Set PD__Missile__Count = (PD__Missile__Count - 1)
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • PD__Missile__Count Equal to (==) 0
          • Then - Actions
            • Custom script: call PauseTimer(udg_PD__Missile__Timer)
          • Else - Actions
            • Set PD__Index = (PD__Index - 1)
      • Custom script: endfunction
      • Custom script:
      • Custom script: function PD__Missile__Callback takes nothing returns nothing
      • Custom script: local player p = GetLocalPlayer()
      • Custom script: local boolean isLocal
        • Do Multiple ActionsFor each (Integer PD__Index) from 1 to PD__Missile__Count, do (Actions)
          • Loop - Actions
            • Custom script: set isLocal = p == udg_PD__Main__Enemy[udg_PD__Missile__Source[udg_PD__Index]] or p == udg_PD__Main__Owner[udg_PD__Missile__Source[udg_PD__Index]]
              • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • PD__Missile__AlphaNow[PD__Index] Less than (<) PD__Missile__Alpha[PD__Index]
                  • PD__Missile__Distance[PD__Index] Greater than (>) (PD__Config__Distance[PD__Main__Level[PD__Missile__Source[PD__Index]]] - PD__Config__FadeDistance[PD__Main__Level[PD__Missile__Source[PD__Index]]])
                • Then - Actions
                  • Set PD__Missile__AlphaNow[PD__Index] = (PD__Missile__AlphaNow[PD__Index] + PD__Missile__AlphaRate[PD__Index])
                    • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                      • If - Conditions
                        • PD__Missile__AlphaNow[PD__Index] Greater than (>) PD__Missile__Alpha[PD__Index]
                      • Then - Actions
                        • Set PD__Missile__AlphaNow[PD__Index] = PD__Missile__Alpha[PD__Index]
                      • Else - Actions
                    • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                      • If - Conditions
                        • PD__Missile__Real[PD__Index] Equal to (==) True
                      • Then - Actions
                        • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Index], 255, 255, 255, udg_PD__Missile__AlphaNow[udg_PD__Index])
                      • Else - Actions
                        • Custom script: if isLocal then
                          • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • PD__Main__Cursed[PD__Missile__Source[PD__Index]] Equal to (==) True
                            • Then - Actions
                              • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Index], 255, 255, 255, udg_PD__Missile__AlphaNow[udg_PD__Index])
                            • Else - Actions
                              • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Index], 255, 255, 255, 0)
                        • Custom script: endif
                • Else - Actions
            • Set PD__Missile__LocX[PD__Index] = (PD__Missile__LocX[PD__Index] + (PD__Config__Speed[PD__Main__Level[PD__Missile__Source[PD__Index]]] x (Cos(PD__Missile__Angle[PD__Index]))))
            • Set PD__Missile__LocY[PD__Index] = (PD__Missile__LocY[PD__Index] + (PD__Config__Speed[PD__Main__Level[PD__Missile__Source[PD__Index]]] x (Sin(PD__Missile__Angle[PD__Index]))))
            • Set PD__Missile__Distance[PD__Index] = (PD__Missile__Distance[PD__Index] - PD__Config__Speed[PD__Main__Level[PD__Missile__Source[PD__Index]]])
              • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • PD__Missile__LocX[PD__Index] Less than (<) PD__MaxX
                  • PD__Missile__LocY[PD__Index] Less than (<) PD__MaxY
                  • PD__Missile__LocX[PD__Index] Greater than (>) PD__MinX
                  • PD__Missile__LocY[PD__Index] Greater than (>) PD__MinY
                • Then - Actions
                  • Custom script: call SetUnitX(udg_PD__Missile__Dagger[udg_PD__Index], udg_PD__Missile__LocX[udg_PD__Index])
                  • Custom script: call SetUnitY(udg_PD__Missile__Dagger[udg_PD__Index], udg_PD__Missile__LocY[udg_PD__Index])
                    • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                      • If - Conditions
                        • PD__Missile__Real[PD__Index] Equal to (==) True
                        • PD__Missile__Hit[PD__Index] Equal to (==) False
                      • Then - Actions
                        • Custom script: call GroupEnumUnitsInRange(udg_PD__TempGroup, udg_PD__Missile__LocX[udg_PD__Index], udg_PD__Missile__LocY[udg_PD__Index], udg_PD__Config__HitRadius, null)
                        • Custom script: loop
                        • Custom script: set udg_PD__TempUnit = FirstOfGroup(udg_PD__TempGroup)
                        • Custom script: exitwhen udg_PD__TempUnit == null
                        • Unit Group - Remove PD__TempUnit from PD__TempGroup
                          • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • PD__TempUnit Equal to (==) PD__Main__Target[PD__Missile__Source[PD__Index]]
                              • (PD__TempUnit is alive) Equal to (==) True
                            • Then - Actions
                              • Set PD__Missile__Hit[PD__Index] = True
                              • Set PD__Main__Cursed[PD__Missile__Source[PD__Index]] = True
                              • Unit - Cause PD__Main__Caster[PD__Missile__Source[PD__Index]] to damage PD__Main__Target[PD__Missile__Source[PD__Index]], dealing PD__Config__Damage[PD__Main__Level[PD__Missile__Source[PD__Index]]] damage of attack type PD__Config__AttackType and damage type PD__Config__DamageType
                              • Special Effect - Create a special effect attached to the PD__Config__HitGfxPt of PD__TempUnit using PD__Config__HitGfx
                              • Special Effect - Destroy (Last created special effect)
                            • Else - Actions
                        • Custom script: endloop
                      • Else - Actions
                    • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                      • If - Conditions
                        • PD__Missile__Distance[PD__Index] Less than (<) PD__Config__FadeDistance[PD__Main__Level[PD__Missile__Source[PD__Index]]]
                      • Then - Actions
                        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                          • If - Conditions
                            • PD__Missile__AlphaNow[PD__Index] Greater than (>) PD__Missile__AlphaRate[PD__Index]
                          • Then - Actions
                            • Set PD__Missile__AlphaNow[PD__Index] = (PD__Missile__AlphaNow[PD__Index] - PD__Missile__AlphaRate[PD__Index])
                              • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • PD__Missile__Real[PD__Index] Equal to (==) True
                                • Then - Actions
                                  • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Index], 255, 255, 255, udg_PD__Missile__AlphaNow[udg_PD__Index])
                                • Else - Actions
                                  • Custom script: if isLocal then
                                    • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                      • If - Conditions
                                        • PD__Main__Cursed[PD__Missile__Source[PD__Index]] Equal to (==) True
                                      • Then - Actions
                                        • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Index], 255, 255, 255, udg_PD__Missile__AlphaNow[udg_PD__Index])
                                      • Else - Actions
                                        • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Index], 255, 255, 255, 0)
                                  • Custom script: endif
                          • Else - Actions
                            • -------- Dispose --------
                            • Custom script: call PD__Missile__Dispose()
                      • Else - Actions
                • Else - Actions
                  • -------- Dispose --------
                  • Custom script: call PD__Missile__Dispose()
      • Custom script: endfunction
      • Custom script:
      • Custom script: function PD__Missile__Launch takes nothing returns nothing
      • Custom script: local real a = GetRandomReal(-bj_PI, bj_PI)
      • Custom script: local real d = udg_PD__Config__Distance[udg_PD__Main__Level[udg_PD__LaunchSource]]
      • Custom script: local real x = GetUnitX(udg_PD__Main__Target[udg_PD__LaunchSource]) + d * Cos(a)
      • Custom script: local real y = GetUnitY(udg_PD__Main__Target[udg_PD__LaunchSource]) + d * Sin(a)
      • Set PD__Missile__Count = (PD__Missile__Count + 1)
      • Set PD__Missile__Real[PD__Missile__Count] = PD__LaunchType
      • Set PD__Missile__Source[PD__Missile__Count] = PD__LaunchSource
      • Custom script: set a = a*bj_RADTODEG + 180
      • Custom script: set udg_PD__Missile__LocX[udg_PD__Missile__Count] = x
      • Custom script: set udg_PD__Missile__LocY[udg_PD__Missile__Count] = y
      • Custom script: set udg_PD__Missile__Angle[udg_PD__Missile__Count] = a
      • Custom script: set udg_PD__Missile__Distance[udg_PD__Missile__Count] = d*udg_PD__Config__DistanceFactor
      • Custom script: set udg_PD__Missile__Dagger[udg_PD__Missile__Count] = CreateUnit(udg_PD__Main__Owner[udg_PD__LaunchSource], udg_PD__Config__DummyID, x, y, a)
      • Custom script: if UnitAddAbility(udg_PD__Missile__Dagger[udg_PD__Missile__Count], 'Amrf') and UnitRemoveAbility(udg_PD__Missile__Dagger[udg_PD__Missile__Count], 'Amrf') then
      • Custom script: endif
      • Animation - Change PD__Missile__Dagger[PD__Missile__Count] flying height to (PD__Config__Height + (Current flying height of PD__Main__Target[PD__Main__Count])) at 0.00
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • PD__LaunchType Equal to (==) True
          • Then - Actions
            • Set PD__Missile__Alpha[PD__Missile__Count] = PD__Config__RealNormalAlpha[PD__Main__Level[PD__LaunchSource]]
            • Set PD__Missile__AlphaNow[PD__Missile__Count] = PD__Config__RealStartAlpha[PD__Main__Level[PD__LaunchSource]]
            • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Missile__Count], 255, 255, 255, udg_PD__Missile__AlphaNow[udg_PD__Missile__Count])
          • Else - Actions
            • Set PD__Missile__Alpha[PD__Missile__Count] = PD__Config__FakeNormalAlpha[PD__Main__Level[PD__LaunchSource]]
            • Set PD__Missile__AlphaNow[PD__Missile__Count] = PD__Config__FakeStartAlpha[PD__Main__Level[PD__LaunchSource]]
            • -------- Reveal only to the caster and the target --------
            • Custom script: if GetLocalPlayer() == udg_PD__Main__Enemy[udg_PD__LaunchSource] or GetLocalPlayer() == udg_PD__Main__Owner[udg_PD__LaunchSource] then
            • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Missile__Count], 255, 255, 255, udg_PD__Missile__AlphaNow[udg_PD__Missile__Count])
            • Custom script: else
            • Custom script: call SetUnitVertexColor(udg_PD__Missile__Dagger[udg_PD__Missile__Count], 255, 255, 255, 0)
            • Custom script: endif
      • Set PD__Missile__AlphaRate[PD__Missile__Count] = ((PD__Missile__Alpha[PD__Missile__Count] - PD__Missile__AlphaNow[PD__Missile__Count]) / (Integer((PD__Config__FadeDistance[PD__Main__Level[PD__LaunchSource]] / PD__Config__Speed[PD__Main__Level[PD__LaunchSource]]))))
      • Set PD__Missile__Hit[PD__Missile__Count] = False
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • PD__Missile__Count Equal to (==) 1
          • Then - Actions
            • Custom script: call TimerStart(udg_PD__Missile__Timer, udg_PD__Config__Interval, true, function PD__Missile__Callback)
          • Else - Actions
  • PD Main
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Custom script: call ExecuteFunc("PD__Main__Init")
      • Custom script: endfunction
      • Custom script:
      • Custom script: function PD__Main__Callback takes nothing returns nothing
        • Do Multiple ActionsFor each (Integer PD__Index) from 1 to PD__Main__Count, do (Actions)
          • Loop - Actions
            • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • PD__Main__HitCount[PD__Index] Less than (<) PD__Config__HitCount[PD__Main__Level[PD__Index]]
                • (PD__Main__Target[PD__Index] is alive) Equal to (==) True
              • Then - Actions
                • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  • If - Conditions
                    • PD__Main__Delay[PD__Index] Greater than (>) PD__Config__Interval
                  • Then - Actions
                    • Set PD__Main__Delay[PD__Index] = (PD__Main__Delay[PD__Index] - PD__Config__Interval)
                  • Else - Actions
                    • Set PD__Main__Delay[PD__Index] = (Random real number between PD__Config__DelayMin[PD__Main__Level[PD__Index]] and PD__Config__DelayMax[PD__Main__Level[PD__Index]])
                    • Custom script: set udg_PD__LaunchType = GetRandomReal(0, 100) < udg_PD__Config__RealRate[udg_PD__Main__Level[udg_PD__Index]]
                    • Custom script: set udg_PD__LaunchType = udg_PD__LaunchType and udg_PD__Main__RealCount[udg_PD__Index] < udg_PD__Config__HitCount[udg_PD__Main__Level[udg_PD__Index]]
                    • Custom script: set udg_PD__LaunchType = udg_PD__LaunchType or udg_PD__Main__MissileCount[udg_PD__Index] == 0 and not udg_PD__Main__RealLaunched[udg_PD__Index]
                    • Set PD__LaunchSource = PD__Index
                      • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • PD__LaunchType Equal to (==) True
                        • Then - Actions
                          • Set PD__Main__RealCount[PD__Index] = (PD__Main__RealCount[PD__Index] + 1)
                          • Set PD__Main__RealLaunched[PD__Index] = True
                        • Else - Actions
                    • Set PD__Main__MissileCount[PD__Index] = (PD__Main__MissileCount[PD__Index] + 1)
                    • Custom script: call ExecuteFunc("PD__Missile__Launch")
              • Else - Actions
      • Custom script: endfunction
      • Custom script:
      • Custom script: function PD__Main__OnCast takes nothing returns boolean
      • Custom script: if GetSpellAbilityId() == udg_PD__Config__SpellID then
      • Set PD__Main__Count = (PD__Main__Count + 1)
      • Set PD__Main__Caster[PD__Main__Count] = (Triggering unit)
      • Set PD__Main__Target[PD__Main__Count] = (Target unit of ability being cast)
      • Set PD__Main__Owner[PD__Main__Count] = (Triggering player)
      • Set PD__Main__Cursed[PD__Main__Count] = False
      • Set PD__Main__Enemy[PD__Main__Count] = (Owner of PD__Main__Target[PD__Main__Count])
      • Set PD__Main__Level[PD__Main__Count] = (Level of PD__Config__SpellID for PD__Main__Caster[PD__Main__Count])
      • Set PD__Main__Delay[PD__Main__Count] = (Random real number between PD__Config__DelayMin[PD__Main__Level[PD__Main__Count]] and PD__Config__DelayMax[PD__Main__Level[PD__Main__Count]])
      • Set PD__Main__MissileCount[PD__Main__Count] = 0
      • Set PD__Main__RealCount[PD__Main__Count] = 0
      • Set PD__Main__HitCount[PD__Main__Count] = 0
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • PD__Main__Count Equal to (==) 1
          • Then - Actions
            • Custom script: call TimerStart(udg_PD__Main__Timer, udg_PD__Config__Interval, true, function PD__Main__Callback)
          • Else - Actions
      • Custom script: endif
      • Custom script: return false
      • Custom script: endfunction
      • Custom script:
      • Custom script: function PD__Main__Init takes nothing returns nothing
      • Custom script: local trigger t = CreateTrigger()
      • Custom script: call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
      • Custom script: call TriggerAddCondition(t, Condition(function PD__Main__OnCast))
      • Custom script: set t = null

Erm.. it doesn't turn so well as imagined in the first place. Dunno what to do now :D
 
Last edited:
Got any screenshots? I'm curious to see how that idea pans out visually - it sounds really interesting

Eitherway, I'm getting pretty close to completion, the first (most complex) part of the ability is now finished (Huzzah!) and I've got to start work on the second part, I've modified the launching pattern a bit again (it now consistently hits the middle of the cast indicator by default) because I wasn't happy with how it was feeling, however you can re-implement that behaviour by configuring a bit (and now it starts off by firing up and backwards) Slow is now fully operational and the particle ring creation is in place.

Since all projectiles are handled by my integrated projectile engine making the second part is pretty simple:
Set up launching projectile -> Rest is already done
Set up setting off the particle ring -> Rest is already done
the remaining work is mostly the final explosion and stunning the unit during the second part

so this is what the (nearly finalised) first part looks like (particle was picked up in the bottom right - you can see its remains - which is why the projectiles aren't in a neat circle)

Edit: End of the day progress report
Work Done: 15 hours
Lines: 1354
Status: 3/4 done
 

Attachments

  • Zephyr Contest #13 WIP 2.png
    Zephyr Contest #13 WIP 2.png
    247.5 KB · Views: 79
Last edited:
Level 10
Joined
Apr 4, 2010
Messages
509
I think my spell will be Shapeshift/Doppelgang/Disguise type of ability.
A skill suitable for a master thief. The spell works by allowing you to steal the identity of any unit or destructible, achieving an undercover style of infiltration, allowing you to breach enemy lines. Be-careful though, the player that controls the original, you will have control over you.

This spell can be used to disguise yourself as a creep in a camp, allowing you to ambush a travelling passer-by. You can also disguise yourself as an opponent to steal or purchase precious items never available to you before. Uncover useful information & such as the Krabby Pattie Secret formula or simply disguise yourself as an innocent chicken or tree to lead your pursuers astray.
:ogre_datass:
 
I've finished making all the code work for my entry (it's yet to be optimised or documented though) so I'll soon post my full entry once I've documented and made all the GIFs I want as well as making the configurable names all follow the same convention and organise them (always throw them on as I need them, making convention and arrangement inconsistent)

Code details:
Lines (incomplete Documentation): 1425
Configurables: 143
Dummy Units: 1
Dummy Abilities: 3 (Main Ability, Slow Ability, Stun Ability)


JASS:
constant function PP_TimerSpeed takes nothing returns real
    return 0.031250000
endfunction

constant function PP_DummyID takes nothing returns integer
    return 'u000'
endfunction

constant function PP_AbilityID takes nothing returns integer
    return 'A000'
endfunction

constant function PP_BuffID takes nothing returns integer
    return 'A001'
endfunction

constant function PP_StunID takes nothing returns integer
    return 'A002'
endfunction

constant function PP_StunOrderID takes nothing returns integer
    return 852095
endfunction

constant function PP_ParticleTypeDistBase takes nothing returns real
    return 160.00
endfunction

constant function PP_ParticleTypeDistPerLevel takes nothing returns real
    return .0
endfunction

constant function PP_DThenH takes nothing returns boolean
    return true
endfunction

constant function PP_PDamageHealthBase takes nothing returns real
    return 100.
endfunction

constant function PP_PDamageHealthPerLevel takes nothing returns real
    return 75.
endfunction

constant function PP_PDamageManaBase takes nothing returns real
    return 0.
endfunction

constant function PP_PDamageManaPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PHealHealthBase takes nothing returns real
    return 400.
endfunction

constant function PP_PHealHealthPerLevel takes nothing returns real
    return 100.
endfunction

constant function PP_PHealManaBase takes nothing returns real
    return 0.
endfunction

constant function PP_PHealManaPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PPercentageMainBase takes nothing returns real
    return .6
endfunction

constant function PP_PPercentageMainPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PDStartLevelBase takes nothing returns integer
    return 2
endfunction

constant function PP_PDStartLevelPerLevel takes nothing returns integer
    return 0
endfunction

constant function PP_PHStartLevelBase takes nothing returns integer
    return 1
endfunction

constant function PP_PHStartLevelPerLevel takes nothing returns integer
    return 0
endfunction

constant function PP_PDLevelModifierBase takes nothing returns integer
    return 1
endfunction

constant function PP_PDLevelModifierPerLevel takes nothing returns integer
    return 0
endfunction

constant function PP_PHLevelModifierBase takes nothing returns integer
    return -1
endfunction

constant function PP_PHLevelModifierPerLevel takes nothing returns integer
    return 0
endfunction

constant function PP_PSlowTimeoutBase takes nothing returns real
    return 4.00
endfunction

constant function PP_PSlowTimeoutPerLevel takes nothing returns real
    return 0.00
endfunction

constant function PP_PProjectileCountBase takes nothing returns integer
    return 7
endfunction

constant function PP_PProjectileCountPerLevel takes nothing returns integer
    return 0
endfunction

constant function PP_PickupAOEBase takes nothing returns real
    return 100.
endfunction

constant function PP_PickupAOEPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PickupDurationBase takes nothing returns real
    return 4.
endfunction

constant function PP_PickupDurationPerLevel takes nothing returns real
    return 1.
endfunction

constant function PP_PickupDecayRateBase takes nothing returns real
    return 0.98566
endfunction

constant function PP_PickupDecayRatePerLevel takes nothing returns real
    return 0.0020
endfunction

constant function PP_PPLaunchOffset takes nothing returns real
    return 90.
endfunction

constant function PP_PPLaunchAngleBase takes nothing returns real
    return 135.
endfunction

constant function PP_PPLaunchAnglePerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PPProjectileSpeedBase takes nothing returns real
    return 200.
endfunction

constant function PP_PPProjectileSpeedPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PPProjectileTurnRateBase takes nothing returns real
    return 5.
endfunction

constant function PP_PPProjectileTurnRatePerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PPProjectileTurnEfficiencyBase takes nothing returns real
    return 0.30
endfunction

constant function PP_PPProjectileTurnEfficiencyPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PPProjectileAccelBase takes nothing returns real
    return 1.01
endfunction

constant function PP_PPProjectileAccelPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PProjectileAOEBase takes nothing returns real
    return 90.
endfunction

constant function PP_PProjectileAOEPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PLaunchHeightOffset takes nothing returns real
    return 0.
endfunction

constant function PP_PLaunchDistOffset takes nothing returns real
    return 20.
endfunction

constant function PP_PLaunchAngleBase takes nothing returns real
    return 55.
endfunction

constant function PP_PLaunchAnglePerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PProjectileSpeedBase takes nothing returns real
    return 175.
endfunction

constant function PP_PProjectileSpeedPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PProjectileTurnRateBase takes nothing returns real
    return 1.
endfunction

constant function PP_PProjectileTurnRatePerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PProjectileTurnEfficiencyBase takes nothing returns real
    return .25
endfunction

constant function PP_PProjectileTurnEfficiencyPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PProjectileAccelBase takes nothing returns real
    return 1.01
endfunction

constant function PP_PProjectileAccelPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_ProjectileAOEBase takes nothing returns real
    return 55.
endfunction

constant function PP_ProjectileAOEPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PHParticleCountBase takes nothing returns integer
    return 1
endfunction

constant function PP_PHParticleCountPerLevel takes nothing returns integer
    return 0
endfunction

constant function PP_PDParticleCountBase takes nothing returns integer
    return 2
endfunction

constant function PP_PDParticleCountPerLevel takes nothing returns integer
    return 0
endfunction

constant function PP_ParticleParticleCountBase takes nothing returns integer
    return 0
endfunction

constant function PP_ParticleParticleCountPerLevel takes nothing returns integer
    return 0
endfunction

constant function PP_ParticleRingStoredHealthDamageBase takes nothing returns real
    return 100.
endfunction

constant function PP_ParticleRingStoredHealthDamagePerLevel takes nothing returns real
    return 50.
endfunction

constant function PP_ParticleRingStoredManaDamageBase takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleRingStoredManaDamagePerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleRingStoredSalvosBase takes nothing returns integer
    return 3
endfunction

constant function PP_ParticleRingStoredSalvosPerLevel takes nothing returns integer
    return 0
endfunction

constant function PP_ParticleHealthDamageBase takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleHealthDamagePerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleManaDamageBase takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleManaDamagePerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleLaunchOffset takes nothing returns real
    return 50.
endfunction

constant function PP_ParticleLaunchAngleBase takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleLaunchAnglePerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleSpeedBase takes nothing returns real
    return 75.
endfunction

constant function PP_ParticleSpeedPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleTurnRateBase takes nothing returns real
    return 1.
endfunction

constant function PP_ParticleTurnRatePerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleTurnEfficiencyBase takes nothing returns real
    return .5
endfunction

constant function PP_ParticleTurnEfficiencyPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleAccelBase takes nothing returns real
    return 1.00
endfunction

constant function PP_ParticleAccelPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleAOEBase takes nothing returns real
    return 60.
endfunction

constant function PP_ParticleAOEPerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PRProjectileLaunchAngle takes nothing returns real
    return 30.
endfunction

constant function PP_PRProjectileSpeed takes nothing returns real
    return 70.
endfunction

constant function PP_PRProjectileTurnRate takes nothing returns real
    return 1.
endfunction

constant function PP_PRProjectileTurnEfficiency takes nothing returns real
    return .25
endfunction

constant function PP_PRProjectileAccel takes nothing returns real
    return 1.01
endfunction

constant function PP_PRProjectileAOE takes nothing returns real
    return 60.
endfunction

constant function PP_PFPercentageHealth takes nothing returns real
    return .5
endfunction

constant function PP_PFPercentageMana takes nothing returns real
    return 0.
endfunction

constant function PP_PFAOE takes nothing returns real
    return 150.
endfunction

constant function PP_AttachmentPoint takes nothing returns string
    return "origin"
endfunction

constant function PP_PickupEffect takes nothing returns string
    return "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
endfunction

constant function PP_PickupDetonateEffect takes nothing returns string
    return "Abilities\\Weapons\\SteamTank\\SteamTankImpact.mdl"
endfunction

constant function PP_SlowEffect takes nothing returns string
    return "Abilities\\Spells\\Human\\slow\\slowtarget.mdl"
endfunction

constant function PP_PickupScaleBase takes nothing returns real
    return 2.
endfunction

constant function PP_PickupScalePerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_PHProjectileEffect takes nothing returns string
    return "Abilities\\Weapons\\SeaElementalMissile\\SeaElementalMissile.mdl"
endfunction

constant function PP_PDProjectileEffect takes nothing returns string
    return "Abilities\\Weapons\\SludgeMissile\\SludgeMissile.mdl"
endfunction

constant function PP_PProjectileScaleBase takes nothing returns real
    return 0.25
endfunction

constant function PP_PProjectileScalePerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleEffect takes nothing returns string
    return "war3mapImported\\Spirit Orb.mdl"
endfunction

constant function PP_ParticleScaleBase takes nothing returns real
    return 0.1
endfunction

constant function PP_ParticleScalePerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleRingEffect takes nothing returns string
    return "Objects\\InventoryItems\\CrystalShard\\CrystalShard.mdl"
endfunction

constant function PP_ParticleRingSpawnEffect takes nothing returns string
    return "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl"
endfunction

constant function PP_ParticleRingDestroyEffect takes nothing returns string
    return "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl"
endfunction

constant function PP_ParticleRingScaleBase takes nothing returns real
    return 1.0
endfunction

constant function PP_ParticleRingScalePerLevel takes nothing returns real
    return 0.
endfunction

constant function PP_ParticleReleaseEffect takes nothing returns string
    return "Abilities\\Weapons\\WaterElementalMissile\\WaterElementalMissile.mdl"
endfunction

constant function PP_ParticleReleaseScale takes nothing returns real
    return 0.1
endfunction

constant function PP_PFinalEffect takes nothing returns string
    return "war3mapImported\\AquaSpike.mdx"
endfunction

constant function PP_PFinalScale takes nothing returns real
    return 1.
endfunction

constant function PP_FilterMaxZ takes nothing returns real
    return 50.
endfunction

constant function PP_HeightLet takes nothing returns real
    return 20.
endfunction

constant function PP_ParticleRingHeight takes nothing returns real
    return 150.
endfunction

constant function PP_ParticleRingOffset takes nothing returns real
    return 100.
endfunction

constant function PP_ParticleRingSpinSpeed takes nothing returns real
    return 0.02
endfunction

constant function PP_ParticleRingFireRate takes nothing returns real
    return 0.30
endfunction

constant function PP_WeaponType takes nothing returns weapontype
    return null
endfunction

constant function PP_DamageType takes nothing returns damagetype
    return DAMAGE_TYPE_MAGIC
endfunction

constant function PP_AttackType takes nothing returns attacktype
    return ATTACK_TYPE_MAGIC
endfunction

constant function PP_TargetAimOffset takes nothing returns real
    return 40.
endfunction

constant function PP_FinalHeightOffset takes nothing returns real
    return 0.
endfunction

constant function PP_EffectDelayTimer takes nothing returns real
    return 3.00
endfunction

constant function PP_DummyPlayer takes nothing returns player
    return Player(14)
endfunction

constant function PP_Gravity takes nothing returns real
    return 2.
endfunction

constant function PP_PickupStageID takes nothing returns integer
    return 1
endfunction

constant function PP_ProjectileStageID takes nothing returns integer
    return 2
endfunction

constant function PP_SlowedUnitStageID takes nothing returns integer
    return 3
endfunction

constant function PP_ParticleRingStageID takes nothing returns integer
    return 4
endfunction

constant function PP_RecycleStageID takes nothing returns integer
    return 5
endfunction

/////////////////////////////////////////////////////////////////////
//  Enemy target filter function - Passed units and players, using //
//  them to check if the unit can be treated as an enemy by the    //
//  spellset                                                       //
/////////////////////////////////////////////////////////////////////
function PP_TargetFilter takes unit u, player pl returns boolean

    //Checks if the unit can be used as a target
    return (not IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (GetUnitFlyHeight(u) <= PP_FilterMaxZ()) and (not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)) and (IsUnitEnemy(u, pl)) and (GetUnitTypeId(u) != PP_DummyID()) and not(IsUnitType(u, UNIT_TYPE_DEAD) or GetUnitTypeId(u) == 0)
   
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to get the z height of locations needed by the  //
//  spell, since it can only be done with locations, this one     //
//  is reused throughout, instead of creating/destroying them     //
////////////////////////////////////////////////////////////////////
function PP_GetZ takes real x, real y returns real

    //Gets the location Z of the selected location
    call MoveLocation(udg_PP_Loc, x, y)
    return GetLocationZ(udg_PP_Loc)
   
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to make sure that the location is within the    //
//  map bounds so that units cannot be moved outside of it and    //
//  get permanently stuck                                         //
////////////////////////////////////////////////////////////////////
function PP_ValidateLocation takes real x, real y returns boolean
   
    //Check if the point is within the map bounds
    return (x < udg_PP_MapMaxX) and (x > udg_PP_MapMinX) and (y < udg_PP_MapMaxY) and (y > udg_PP_MapMinY)

endfunction

////////////////////////////////////////////////////////////////////
//  Function used to recycle instances, so that they can used     //
//  again later, keeping the total array sizes smaller            //
////////////////////////////////////////////////////////////////////
function PP_Recycle takes integer Node returns nothing
           
        //Set up the StageID to prevent interaction
        set udg_PP_StageID[Node] = PP_RecycleStageID()
       
        if (udg_PP_LastNode == Node) then
            set udg_PP_LastNode = udg_PP_PrevNode[Node]
        endif
           
        //Recycles the node
        set udg_PP_RecycleNodes[udg_PP_RecyclableNodes] = Node
        set udg_PP_RecyclableNodes = udg_PP_RecyclableNodes + 1
        set udg_PP_NextNode[udg_PP_PrevNode[Node]] = udg_PP_NextNode[Node]
        set udg_PP_PrevNode[udg_PP_NextNode[Node]] = udg_PP_PrevNode[Node]
        set udg_PP_AbilityCounter = udg_PP_AbilityCounter - 1

        //Stops the timer if this is the only remaining Node
        if (udg_PP_AbilityCounter == 0) then
            call PauseTimer(udg_PP_Timer)
        endif

endfunction

////////////////////////////////////////////////////////////////////
//  Function used to create new Nodes for the system whenever a   //
//  unit or effect is added to run in the loop function           //
////////////////////////////////////////////////////////////////////
function PP_CreateNode takes nothing returns integer
    //set up local
    local integer Node = 0
   
    //Checking for recycleable Nodes
    if (udg_PP_RecyclableNodes == 0) then
        set udg_PP_NodeNumber = udg_PP_NodeNumber + 1
        set Node = udg_PP_NodeNumber
    else
        set udg_PP_RecyclableNodes = udg_PP_RecyclableNodes - 1
        set Node = udg_PP_RecycleNodes[udg_PP_RecyclableNodes]
    endif

    //Sets up this Node
    set udg_PP_NextNode[Node] = 0
    set udg_PP_NextNode[udg_PP_LastNode] = Node
    set udg_PP_PrevNode[Node] = udg_PP_LastNode
    set udg_PP_LastNode = Node
   
    set udg_PP_AbilityCounter = udg_PP_AbilityCounter + 1
   
    return Node
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to add new particles to the rings of units      //
//  when they have aquired a pickup or been hit by the main       //
//  particle (if it has been configured to add particles)         //
////////////////////////////////////////////////////////////////////
function PP_AddParticleToRing takes unit u, integer UNode, integer Number, real Level returns nothing
    local integer Node
    local integer TempInt = 0
    local real TempReal
    
    loop
        set TempInt = TempInt + 1
        exitwhen (TempInt > Number)
        
        set Node = PP_CreateNode()
        set udg_PP_Unit[Node] = CreateUnit(PP_DummyPlayer(), PP_DummyID(), GetUnitX(u), GetUnitY(u), 0)
        set udg_PP_CurrentEffect[Node] = AddSpecialEffectTarget(PP_ParticleRingEffect(), udg_PP_Unit[Node], PP_AttachmentPoint())
        call SetUnitScale(udg_PP_Unit[Node], PP_ParticleRingScaleBase() + (PP_ParticleRingScalePerLevel() * Level), 0., 0.)
        if UnitAddAbility(udg_PP_Unit[Node], 'Amrf') and UnitRemoveAbility(udg_PP_Unit[Node], 'Amrf') then
        endif
        call DestroyEffect(AddSpecialEffectTarget(PP_ParticleRingSpawnEffect(), udg_PP_Unit[Node], PP_AttachmentPoint()))
        call SetUnitFlyHeight(udg_PP_Unit[Node], PP_ParticleRingHeight(), 0.)
        set udg_PP_Caster[Node] = u
        set udg_PP_StageID[Node] = PP_ParticleRingStageID()
        set udg_PP_Integer2[UNode] = udg_PP_Integer2[UNode] + 1
        set udg_PP_Real4[UNode] = udg_PP_Real4[UNode] + PP_ParticleRingStoredHealthDamageBase() + (PP_ParticleRingStoredHealthDamagePerLevel() * Level)
        set udg_PP_Real5[UNode] = udg_PP_Real5[UNode] + PP_ParticleRingStoredManaDamageBase() + (PP_ParticleRingStoredManaDamagePerLevel() * Level)
        set udg_PP_Integer3[UNode] = udg_PP_Integer3[UNode] + PP_ParticleRingStoredSalvosBase() + (PP_ParticleRingStoredSalvosPerLevel() * R2I(Level))
        set TempReal = I2R(udg_PP_Integer2[UNode] * udg_PP_Integer3[UNode])
        set udg_PP_Real7[UNode] = udg_PP_Real4[UNode] / TempReal
        set udg_PP_Real8[UNode] = udg_PP_Real5[UNode] / TempReal
    endloop
    
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to move all projectile-type entities in the     //
//  abiity - the physics engine of the spell                      //
////////////////////////////////////////////////////////////////////
function PP_Move takes integer Node returns boolean
    local real x = GetUnitX(udg_PP_Unit[Node])
    local real y = GetUnitY(udg_PP_Unit[Node])
    local real dy = udg_PP_Real9[Node] - y
    local real dx = udg_PP_Real8[Node]- x
    local real x2
    local real y2
    local real Angle = Atan2(dy, dx)
    local real Angle2 = Atan2((PP_GetZ(udg_PP_Real8[Node], udg_PP_Real9[Node]) + udg_PP_Real14[Node]) - (PP_GetZ(x, y) + GetUnitFlyHeight(udg_PP_Unit[Node])), Pow(dx * dx + dy * dy, 0.5))
    local real Angle3 = Atan2(udg_PP_Real4[Node], udg_PP_Real3[Node])
    local real Angle4 = Atan(udg_PP_Real2[Node])
    local real TempReal = Pow(Pow(udg_PP_Real2[Node], 2) + Pow(udg_PP_Real3[Node], 2) + Pow(udg_PP_Real4[Node], 2), 0.5) * udg_PP_Real6[Node]
    local real TempReal2 = 1/(1 + udg_PP_Real6[Node]) 
    
    set udg_PP_Real2[Node] = ((udg_PP_Real2[Node] + (TempReal + udg_PP_Real5[Node]) * Sin(Angle2)) * udg_PP_Real1[Node]) * TempReal2
    set udg_PP_Real3[Node] = ((udg_PP_Real3[Node] + (TempReal + udg_PP_Real5[Node]) * Cos(Angle) * Cos(Angle2)) * udg_PP_Real1[Node]) * TempReal2
    set udg_PP_Real4[Node] = ((udg_PP_Real4[Node] + (TempReal + udg_PP_Real5[Node]) * Sin(Angle) * Cos(Angle2)) * udg_PP_Real1[Node]) * TempReal2
    set udg_PP_Real7[Node] = udg_PP_Real7[Node] + udg_PP_Real2[Node] - PP_Gravity()
    
    set x2 = x + udg_PP_Real3[Node]
    set y2 = y + udg_PP_Real4[Node]
    
    if PP_ValidateLocation(x2, y2) then
        call SetUnitX(udg_PP_Unit[Node], x2)
        call SetUnitY(udg_PP_Unit[Node], y2)
    endif
    
    if not(udg_PP_TargetUnit[Node] == null) then
        set udg_PP_Real8[Node] = GetUnitX(udg_PP_TargetUnit[Node])
        set udg_PP_Real9[Node] = GetUnitY(udg_PP_TargetUnit[Node])
        set udg_PP_Real14[Node] = GetUnitFlyHeight(udg_PP_TargetUnit[Node]) + PP_TargetAimOffset()
    endif
    
    call SetUnitFlyHeight(udg_PP_Unit[Node], udg_PP_Real7[Node] - PP_GetZ(x2, y2), 0.)
    call SetUnitFacing(udg_PP_Unit[Node], bj_RADTODEG * Atan2(udg_PP_Real4[Node], udg_PP_Real3[Node]))
    call SetUnitAnimationByIndex(udg_PP_Unit[Node], R2I(Atan2((udg_PP_Real2[Node]), SquareRoot((udg_PP_Real3[Node] * udg_PP_Real3[Node]) + (udg_PP_Real4[Node] * udg_PP_Real4[Node]))) * bj_RADTODEG + 0.5) + 90)
    
    return (GetUnitFlyHeight(udg_PP_Unit[Node]) <= PP_HeightLet())
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to identify when a projectile has hit it's      //
//  target unit so that damage can be dealt & stun can be         //
//  applied if applicable                                         //
////////////////////////////////////////////////////////////////////
function PP_HitTarget takes integer Node returns boolean
    local real x = GetUnitX(udg_PP_Unit[Node])
    local real y = GetUnitY(udg_PP_Unit[Node])
    local real dx = x - udg_PP_Real8[Node]
    local real dy = y - udg_PP_Real9[Node]
    local real dz = (PP_GetZ(udg_PP_Real8[Node], udg_PP_Real9[Node]) + GetUnitFlyHeight(udg_PP_TargetUnit[Node])) - (PP_GetZ(x, y) + GetUnitFlyHeight(udg_PP_Unit[Node]))
    
    return (dx * dx + dy * dy + dz * dz <= udg_PP_Real10[Node])
endfunction

////////////////////////////////////////////////////////////////////
//  The main function which is used to handle all the key         //
//  components of the spell, including handling all of the spell  //
//  effects of both parts and all units which are being affected  //
//  by anything from the spell                                    //
////////////////////////////////////////////////////////////////////
function PP_Loop takes nothing returns nothing
    //Sets up locals
    local integer Node = 0
    local integer TempNode
    local integer TempNode2
    local integer TempInt = 0
    local integer TempInt2
    local real x
    local real y
    local real x2
    local real y2
    local real dy
    local real dx
    local real TempReal
    local real TempReal2
    local real TempReal3
    local real Angle
    local real Angle2
    local unit u
    local boolean TempBoolean
    local boolean TempBoolean2
    
    loop
        set TempInt = TempInt + 1
        exitwhen TempInt > udg_PP_AbilityCounter
        set Node = udg_PP_NextNode[Node]
        
        //Pickups
        if (udg_PP_StageID[Node] == PP_PickupStageID()) then
        
            if (udg_PP_Boolean1[Node]) then
            
                if (PP_Move(Node)) then
                    set udg_PP_Boolean1[Node] = false
                    set udg_PP_Real1[Node] = PP_PProjectileAccelBase() + (PP_PProjectileAccelPerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real2[Node] = PP_PProjectileSpeedBase() + (PP_PProjectileSpeedPerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real3[Node] = PP_PickupAOEBase() + (PP_PickupAOEPerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real4[Node] = PP_PickupDurationBase() + (PP_PickupDurationPerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real5[Node] = PP_PProjectileTurnRateBase() + (PP_PProjectileTurnRatePerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real6[Node] = PP_PProjectileTurnEfficiencyBase() + (PP_PProjectileTurnEfficiencyPerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real7[Node] = udg_PP_Real7[Node] + PP_PLaunchHeightOffset()
                
                    if (udg_PP_Boolean2[Node]) then
                        set udg_PP_Real8[Node] = PP_PDamageHealthBase() + (PP_PDamageHealthPerLevel() * udg_PP_Real10[Node])
                        set udg_PP_Real9[Node] = PP_PDamageManaBase() + (PP_PDamageManaPerLevel() * udg_PP_Real10[Node])
                    else
                        set udg_PP_Real8[Node] = PP_PHealHealthBase() + (PP_PHealHealthPerLevel() * udg_PP_Real10[Node])
                        set udg_PP_Real9[Node] = PP_PHealManaBase() + (PP_PHealManaPerLevel() * udg_PP_Real10[Node])
                    endif
                    
                    set udg_PP_Real11[Node] = PP_PPercentageMainBase() + (PP_PPercentageMainPerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real12[Node] = PP_PickupDurationBase() + (PP_PickupDurationPerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real13[Node] = PP_PickupDecayRateBase() + (PP_PickupDecayRatePerLevel() * udg_PP_Real10[Node])
                endif
            
            else
                set udg_PP_Real8[Node] = udg_PP_Real8[Node] * udg_PP_Real13[Node]
                set udg_PP_Real9[Node] = udg_PP_Real9[Node] * udg_PP_Real13[Node]
                set udg_PP_Real12[Node] = udg_PP_Real12[Node] - PP_TimerSpeed()
                
                if (udg_PP_Real12[Node] > 0) then
                    set x = GetUnitX(udg_PP_Unit[Node])
                    set y = GetUnitY(udg_PP_Unit[Node])
                    set TempBoolean = true
                    call GroupEnumUnitsInRange(udg_PP_TempGroup, x, y, udg_PP_Real3[Node], null)
                   
                    //Damage Enemy Units
                    loop
                        set u = FirstOfGroup(udg_PP_TempGroup)
                        exitwhen u == null
                       
                        if (PP_TargetFilter(u, udg_PP_Player[Node])) and (TempBoolean) then
                            set TempBoolean = false
                            set udg_PP_Real12[Node] = udg_PP_Real8[Node] * udg_PP_Real11[Node]
                            set udg_PP_Real11[Node] = udg_PP_Real9[Node] * udg_PP_Real11[Node]
                            set udg_PP_Real8[Node] = (udg_PP_Real8[Node] - udg_PP_Real12[Node]) / udg_PP_Integer1[Node]
                            set udg_PP_Real9[Node] = (udg_PP_Real9[Node] - udg_PP_Real11[Node]) / udg_PP_Integer1[Node]
                            
                            call DestroyEffect(AddSpecialEffectTarget(PP_PickupDetonateEffect(), u, PP_AttachmentPoint()))
                            call DestroyEffect(udg_PP_CurrentEffect[Node])
                            
                            set TempInt2 = 0
                            set TempBoolean2 = false
                            set TempNode = 0
                            
                            loop
                                set TempInt2 = TempInt2 + 1
                                exitwhen (TempInt2 > udg_PP_AbilityCounter) or (TempBoolean2 == true)
                                set TempNode = udg_PP_NextNode[TempNode]
                                
                                if (udg_PP_Unit[TempNode] == u) then
                                    set TempBoolean2 = true
                                endif
                                    
                            endloop
                            
                            if (TempBoolean2) then
                                
                                if (UnitAddAbility(udg_PP_Unit[TempNode], PP_BuffID())) then
                                    call SetUnitAbilityLevel(udg_PP_Unit[TempNode], PP_BuffID(), udg_PP_Integer3[Node])
                                    set udg_PP_Real1[TempNode] = PP_PSlowTimeoutBase() + (PP_PSlowTimeoutPerLevel() * udg_PP_Real10[Node])
                                    set udg_PP_Real2[TempNode] = udg_PP_Real1[TempNode]
                                    set udg_PP_Real3[TempNode] = 0
                                    set udg_PP_Integer1[TempNode] = udg_PP_Integer3[Node]
                                    set udg_PP_Boolean1[TempNode] = true
                                    set udg_PP_CurrentEffect[TempNode] = AddSpecialEffectTarget(PP_SlowEffect(), udg_PP_Unit[TempNode], PP_AttachmentPoint())
                                else
                                    set udg_PP_Real1[TempNode] = udg_PP_Real2[TempNode]
                                    
                                    if (udg_PP_Integer1[TempNode] + udg_PP_Integer4[Node] <= 0) then
                                        set udg_PP_Integer1[TempNode] = 1
                                        call SetUnitAbilityLevel(udg_PP_Unit[TempNode], PP_BuffID(), udg_PP_Integer1[TempNode])
                                    else
                                        set udg_PP_Integer1[TempNode] = udg_PP_Integer1[TempNode] + udg_PP_Integer4[Node]
                                        call SetUnitAbilityLevel(udg_PP_Unit[TempNode], PP_BuffID(), udg_PP_Integer1[TempNode])
                                    endif       
                                
                                endif
                                
                            else
                                set TempNode = PP_CreateNode()
                                set udg_PP_Unit[TempNode] = u
                                call UnitAddAbility(udg_PP_Unit[TempNode], PP_BuffID())
                                call SetUnitAbilityLevel(udg_PP_Unit[TempNode], PP_BuffID(), udg_PP_Integer3[Node])
                                set udg_PP_Caster[TempNode] = udg_PP_Caster[Node]
                                set udg_PP_Player[TempNode] = udg_PP_Player[Node]
                                set udg_PP_Real1[TempNode] = PP_PSlowTimeoutBase() + (PP_PSlowTimeoutPerLevel() * udg_PP_Real10[Node])
                                set udg_PP_Real2[TempNode] = udg_PP_Real1[TempNode]
                                set udg_PP_Real3[TempNode] = 0
                                set udg_PP_Real4[TempNode] = 0
                                set udg_PP_Real5[TempNode] = 0
                                set udg_PP_Integer1[TempNode] = udg_PP_Integer3[Node]
                                set udg_PP_Integer2[TempNode] = 0
                                set udg_PP_Integer3[TempNode] = 0
                                set udg_PP_StageID[TempNode] = PP_SlowedUnitStageID()
                                set udg_PP_Boolean1[TempNode] = true
                                set udg_PP_Boolean2[TempNode] = false
                                set udg_PP_CurrentEffect[TempNode] = AddSpecialEffectTarget(PP_SlowEffect(), udg_PP_Unit[TempNode], PP_AttachmentPoint())
                            endif
                            
                            if (udg_PP_Boolean2[Node]) then
                                call UnitDamageTarget(udg_PP_Caster[Node], u, udg_PP_Real12[Node], false, false, PP_AttackType(), PP_DamageType(), PP_WeaponType())
                                call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - udg_PP_Real11[Node])
                            else
                                call SetWidgetLife(u, GetWidgetLife(u) + udg_PP_Real12[Node])
                                call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) + udg_PP_Real11[Node])
                            endif
                            
                            //Give Particle to the target's particle ring
                            call PP_AddParticleToRing(u, TempNode, udg_PP_Integer2[Node], udg_PP_Real10[Node])
                            
                            //Create Projectiles
                            set TempReal = PP_PProjectileSpeedBase() + (PP_PProjectileSpeedPerLevel() * udg_PP_Real10[Node])
                            set TempReal3 = PP_PProjectileAOEBase() + (PP_PProjectileAOEPerLevel() * udg_PP_Real10[Node])
                            set Angle2 = bj_DEGTORAD * (PP_PLaunchAngleBase() + (PP_PLaunchAnglePerLevel() * udg_PP_Real10[Node]))
                            set udg_PP_Real10[Node] = PP_PProjectileScaleBase() + (PP_PProjectileScalePerLevel() * udg_PP_Real10[Node])
                            set TempInt2 = 0
                            set Angle = 0
                            set TempReal2 = (360 / udg_PP_Integer1[Node]) * bj_DEGTORAD
                            
                            loop
                                set TempInt2 = TempInt2 + 1
                                exitwhen (TempInt2 > udg_PP_Integer1[Node])
                                
                                set Angle = Angle + TempReal2
                                set TempNode = PP_CreateNode()
                                set udg_PP_Boolean1[TempNode] = false
                                set udg_PP_Boolean2[TempNode] = udg_PP_Boolean2[Node]
                                set udg_PP_Real1[TempNode] = udg_PP_Real1[Node]
                                set udg_PP_Real2[TempNode] = TempReal * Sin(Angle2)
                                set udg_PP_Real3[TempNode] = TempReal * Cos(Angle) * Cos(Angle2)
                                set udg_PP_Real4[TempNode] = TempReal * Sin(Angle) * Cos(Angle2)
                                set udg_PP_Real5[TempNode] = udg_PP_Real5[Node]
                                set udg_PP_Real6[TempNode] = udg_PP_Real6[Node]
                                set udg_PP_Real7[TempNode] = udg_PP_Real7[Node]
                                set udg_PP_TargetUnit[TempNode] = u
                                set udg_PP_Real8[TempNode] = GetUnitX(u)
                                set udg_PP_Real9[TempNode] = GetUnitY(u)
                                set udg_PP_Real10[TempNode] = TempReal3 * TempReal3
                                set udg_PP_Real11[TempNode] = udg_PP_Real8[Node]
                                set udg_PP_Real12[TempNode] = udg_PP_Real9[Node]
                                set udg_PP_Real14[TempNode] = GetUnitFlyHeight(udg_PP_TargetUnit[TempNode]) + PP_TargetAimOffset()
                                set udg_PP_StageID[TempNode] = PP_ProjectileStageID()
                                set udg_PP_Integer1[TempNode] = 0
                                
                                set udg_PP_Unit[TempNode] = CreateUnit(PP_DummyPlayer(), PP_DummyID(), x + PP_PLaunchDistOffset() * Cos(Angle), y + PP_PLaunchDistOffset() * Sin(Angle), bj_RADTODEG * Atan2(udg_PP_Real4[TempNode], udg_PP_Real3[TempNode]))
                                set udg_PP_Caster[TempNode] = udg_PP_Caster[Node]
                                set udg_PP_Player[TempNode] = udg_PP_Player[Node]
                                if UnitAddAbility(udg_PP_Unit[TempNode], 'Amrf') and UnitRemoveAbility(udg_PP_Unit[TempNode], 'Amrf') then
                                endif
                                call SetUnitScale(udg_PP_Unit[TempNode], udg_PP_Real10[Node], 0., 0.)
                                
                                if (udg_PP_Boolean2[Node]) then
                                    set udg_PP_CurrentEffect[TempNode] = AddSpecialEffectTarget(PP_PDProjectileEffect(), udg_PP_Unit[TempNode], PP_AttachmentPoint())
                                else
                                    set udg_PP_CurrentEffect[TempNode] = AddSpecialEffectTarget(PP_PHProjectileEffect(), udg_PP_Unit[TempNode], PP_AttachmentPoint())
                                endif
                                
                            endloop
                            
                            set udg_PP_StageID[Node] = PP_RecycleStageID()
                            set udg_PP_Real1[Node] = PP_EffectDelayTimer()
                        endif
                       
                        call GroupRemoveUnit(udg_PP_TempGroup, u)
                    endloop
                
                else
                    call DestroyEffect(udg_PP_CurrentEffect[Node])
                    set udg_PP_Real1[Node] = PP_EffectDelayTimer()
                    set udg_PP_StageID[Node] = PP_RecycleStageID()
                endif
                    
            endif
        
        //Projectiles
        elseif (udg_PP_StageID[Node] == PP_ProjectileStageID()) then
            if (PP_Move(Node)) then
                call DestroyEffect(udg_PP_CurrentEffect[Node])
                set udg_PP_StageID[Node] = PP_RecycleStageID()
                set udg_PP_Real1[Node] = PP_EffectDelayTimer()
            elseif (PP_HitTarget(Node)) then
                call DestroyEffect(udg_PP_CurrentEffect[Node])
                
                if (udg_PP_Boolean2[Node]) then
                    call UnitDamageTarget(udg_PP_Caster[Node], udg_PP_TargetUnit[Node], udg_PP_Real11[Node], false, false, PP_AttackType(), PP_DamageType(), PP_WeaponType())
                    call SetUnitState(udg_PP_TargetUnit[Node], UNIT_STATE_MANA, GetUnitState(udg_PP_TargetUnit[Node], UNIT_STATE_MANA) - udg_PP_Real12[Node])
                else
                    call SetWidgetLife(udg_PP_TargetUnit[Node], GetWidgetLife(udg_PP_TargetUnit[Node]) + udg_PP_Real11[Node])
                    call SetUnitState(udg_PP_TargetUnit[Node], UNIT_STATE_MANA, GetUnitState(udg_PP_TargetUnit[Node], UNIT_STATE_MANA) + udg_PP_Real12[Node])
                endif
                
                if (udg_PP_Boolean1[Node]) then
                    set TempBoolean = false
                    set TempInt2 = 0
                    set TempNode = 0
                    
                    loop
                        set TempInt2 = TempInt2 + 1
                        exitwhen (TempInt2 > udg_PP_AbilityCounter) or (TempBoolean)
                        set TempNode = udg_PP_NextNode[TempNode]
                        
                        if (udg_PP_Unit[TempNode] == udg_PP_TargetUnit[Node]) then
                            set TempBoolean = true
                        endif
                        
                    endloop
                
                    if (TempBoolean) then
                    
                        if not(udg_PP_Boolean2[TempNode]) then
                            //Give Particle to the target's particle ring
                            call PP_AddParticleToRing(udg_PP_Unit[TempNode], TempNode, udg_PP_Integer1[Node], udg_PP_Real13[Node])
                        
                            if (udg_PP_Integer2[TempNode] > 0) then
                                set udg_PP_Boolean2[TempNode] = true 
                                set udg_PP_Real6[TempNode] = 0
                                set udg_PP_Real9[TempNode] = 0
                                set udg_PP_Real10[TempNode] = 0
                                set udg_PP_Real11[TempNode] = udg_PP_Real13[Node]
                            else
                                set udg_PP_Boolean2[TempNode] = false
                            endif
                            
                        endif
                        
                    else
                        set TempNode = PP_CreateNode()
                        set udg_PP_Unit[TempNode] = udg_PP_TargetUnit[Node]
                        set udg_PP_Caster[TempNode] = udg_PP_Caster[Node]
                        set udg_PP_Player[TempNode] = udg_PP_Player[Node]
                        set udg_PP_Real3[TempNode] = 0
                        set udg_PP_Real4[TempNode] = 0
                        set udg_PP_Real5[TempNode] = 0
                        set udg_PP_Real6[TempNode] = 0
                        set udg_PP_Real9[TempNode] = 0
                        set udg_PP_Real10[TempNode] = 0
                        set udg_PP_Real11[TempNode] = udg_PP_Real13[Node]
                        set udg_PP_Integer2[TempNode] = 0
                        set udg_PP_Integer3[TempNode] = 0
                        set udg_PP_StageID[TempNode] = PP_SlowedUnitStageID()
                        set udg_PP_Boolean1[TempNode] = false
                        //Give Particle to the target's particle ring
                        call PP_AddParticleToRing(udg_PP_Unit[TempNode], TempNode, udg_PP_Integer1[Node], udg_PP_Real13[Node])
                        
                        if (udg_PP_Integer2[TempNode] > 0) then
                            set udg_PP_Boolean2[TempNode] = true 
                        else
                            set udg_PP_Boolean2[TempNode] = false
                        endif
                        
                    endif
                    
                endif
                
                set udg_PP_StageID[Node] = PP_RecycleStageID()
                set udg_PP_Real1[Node] = PP_EffectDelayTimer()
            endif
        
        //Affected Enemy Units
        elseif (udg_PP_StageID[Node] == PP_SlowedUnitStageID()) then
            
            if not(udg_PP_Boolean1[Node]) and not(udg_PP_Boolean2[Node]) then
            
                set TempInt2 = 0
                set TempNode = 0
                
                loop
                    set TempInt2 = TempInt2 + 1
                    exitwhen (TempInt2 > udg_PP_AbilityCounter)
                    set TempNode = udg_PP_NextNode[TempNode]
                    
                    if (udg_PP_StageID[TempNode] == PP_ParticleRingStageID()) and (udg_PP_Caster[TempNode] == udg_PP_Unit[Node]) then
                        call DestroyEffect(udg_PP_CurrentEffect[TempNode])
                        call DestroyEffect(AddSpecialEffectTarget(PP_ParticleRingDestroyEffect(), udg_PP_Unit[TempNode], PP_AttachmentPoint()))
                        set udg_PP_StageID[TempNode] = PP_RecycleStageID()
                        set udg_PP_Real1[TempNode] = PP_EffectDelayTimer()
                    endif
                    
                endloop
                
                call PP_Recycle(Node)
                set TempInt = TempInt - 1
            else
                set TempBoolean = false
                set x = GetUnitX(udg_PP_Unit[Node])
                set y = GetUnitY(udg_PP_Unit[Node])
                
                //Enemy is slowed
                if (udg_PP_Boolean1[Node]) then
                
                    if (IsUnitType(udg_PP_Unit[Node], UNIT_TYPE_DEAD)) then
                        set udg_PP_Integer1[Node] = 1
                        set udg_PP_Real1[Node] = 0
                    endif
                    
                    if (udg_PP_Real1[Node] <= 0) then
                        
                        if (udg_PP_Integer1[Node] == 1) then
                            call UnitRemoveAbility(udg_PP_Unit[Node], PP_BuffID())
                            call DestroyEffect(udg_PP_CurrentEffect[Node])
                            set udg_PP_Boolean1[Node] = false
                        else
                            set udg_PP_Integer1[Node] = udg_PP_Integer1[Node] - 1
                            call SetUnitAbilityLevel(udg_PP_Unit[Node], PP_BuffID(), udg_PP_Integer1[Node])
                            set udg_PP_Real1[Node] = udg_PP_Real2[Node]
                        endif
                        
                    else
                        set udg_PP_Real1[Node] = udg_PP_Real1[Node] - PP_TimerSpeed()
                    endif
                    
                endif
                
                //Particle Ring Activated
                if (udg_PP_Boolean2[Node]) then
                
                    if (udg_PP_Integer3[Node] > 0) and not(IsUnitType(udg_PP_Unit[Node], UNIT_TYPE_DEAD)) then
                        
                        if (udg_PP_Real6[Node] <= 0) then
                            set udg_PP_Real6[Node] = PP_ParticleRingFireRate()
                            set udg_PP_Integer3[Node] = udg_PP_Integer3[Node] - 1
                            set udg_PP_Real9[Node] = udg_PP_Real9[Node] + udg_PP_Real7[Node] * R2I(udg_PP_Integer2[Node])
                            set udg_PP_Real10[Node] = udg_PP_Real10[Node] + udg_PP_Real8[Node] * R2I(udg_PP_Integer2[Node])
                            set TempBoolean = true
                            set TempNode = PP_CreateNode()
                            set udg_PP_Unit[TempNode] = CreateUnit(PP_DummyPlayer(), PP_DummyID(), x, y, 0.)
                            set udg_PP_StageID[TempNode] = PP_RecycleStageID()
                            set udg_PP_Real1[TempNode] = PP_EffectDelayTimer()
                            call UnitAddAbility(udg_PP_Unit[TempNode], PP_StunID())
                            call IssueTargetOrderById(udg_PP_Unit[TempNode], PP_StunOrderID(), udg_PP_Unit[Node])
                        else
                            set udg_PP_Real6[Node] = udg_PP_Real6[Node] - PP_TimerSpeed()
                        endif
                        
                    else
                        //Final Explosion
                        set udg_PP_Boolean2[Node] = false
                        set udg_PP_Integer1[Node] = 1
                        set udg_PP_Real1[Node] = 0
                        set TempNode = PP_CreateNode()
                        set udg_PP_Unit[TempNode] = CreateUnit(PP_DummyPlayer(), PP_DummyID(), x, y, 0.)
                        call SetUnitScale(udg_PP_Unit[TempNode], PP_PFinalScale(), 0., 0.)
                        if UnitAddAbility(udg_PP_Unit[TempNode], 'Amrf') and UnitRemoveAbility(udg_PP_Unit[TempNode], 'Amrf') then
                        endif
                        call SetUnitFlyHeight(udg_PP_Unit[TempNode], PP_FinalHeightOffset(), 0.)
                        call DestroyEffect(AddSpecialEffectTarget(PP_PFinalEffect(), udg_PP_Unit[TempNode], PP_AttachmentPoint()))
                        set udg_PP_StageID[TempNode] = PP_RecycleStageID()
                        set udg_PP_Real1[TempNode] = PP_EffectDelayTimer()

                        call GroupEnumUnitsInRange(udg_PP_TempGroup, x, y, PP_PFAOE(), null)
                   
                        //Damage Enemy Units
                        loop
                            set u = FirstOfGroup(udg_PP_TempGroup)
                            exitwhen u == null
                           
                            if (PP_TargetFilter(u, udg_PP_Player[Node])) then
                                call UnitDamageTarget(udg_PP_Caster[Node], u, (udg_PP_Real4[Node] * PP_PFPercentageHealth()) + (udg_PP_Real4[Node] - udg_PP_Real9[Node]), false, false, PP_AttackType(), PP_DamageType(), PP_WeaponType())
                                call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - ((udg_PP_Real5[Node] * PP_PFPercentageMana()) + (udg_PP_Real5[Node] - udg_PP_Real10[Node])))
                            endif
                            
                            call GroupRemoveUnit(udg_PP_TempGroup, u)
                        endloop
                        
                    endif
                    
                endif
                
                //Enemy Particle Ring
                set udg_PP_Real3[Node] = udg_PP_Real3[Node] + PP_ParticleRingSpinSpeed()
                set TempInt2 = 0
                set TempNode = 0
                set TempReal = udg_PP_Real3[Node]
                set TempReal2 = (2 * bj_PI) / I2R(udg_PP_Integer2[Node])
                
                loop
                    set TempInt2 = TempInt2 + 1
                    exitwhen (TempInt2 > udg_PP_AbilityCounter)
                    set TempNode = udg_PP_NextNode[TempNode]
                    
                    if (udg_PP_StageID[TempNode] == PP_ParticleRingStageID()) and (udg_PP_Caster[TempNode] == udg_PP_Unit[Node]) then
                        set TempReal = TempReal + TempReal2
                        set x2 = x + PP_ParticleRingOffset() * Cos(TempReal)
                        set y2 = y + PP_ParticleRingOffset() * Sin(TempReal)
                        call SetUnitX(udg_PP_Unit[TempNode], x2)
                        call SetUnitY(udg_PP_Unit[TempNode], y2)
                        call SetUnitFlyHeight(udg_PP_Unit[TempNode], PP_ParticleRingHeight() - (PP_GetZ(x, y) - PP_GetZ(x2, y2)), 0.) 
                        call SetUnitFacing(udg_PP_Unit[TempNode], TempReal * bj_RADTODEG)
                        
                        if (TempBoolean) then
                            set TempNode2 = PP_CreateNode()
                            set dy = (y2 - y)
                            set dx = (x2 - x)
                            set Angle = Atan2(dy, dx)
                            set Angle2 = bj_DEGTORAD * PP_PRProjectileLaunchAngle()
                            set udg_PP_Unit[TempNode2] = CreateUnit(PP_DummyPlayer(), PP_DummyID(), x2, y2, 0.)
                            if UnitAddAbility(udg_PP_Unit[TempNode2], 'Amrf') and UnitRemoveAbility(udg_PP_Unit[TempNode2], 'Amrf') then
                            endif
                            set udg_PP_Caster[TempNode2] = udg_PP_Caster[Node]
                            set udg_PP_Player[TempNode2] = udg_PP_Player[Node]
                            set udg_PP_CurrentEffect[TempNode2] = AddSpecialEffectTarget(PP_ParticleReleaseEffect(), udg_PP_Unit[TempNode2], PP_AttachmentPoint())
                            call SetUnitScale(udg_PP_Unit[TempNode2], PP_ParticleReleaseScale(), 0., 0.)
                            set TempReal3 = PP_PRProjectileSpeed()
                            set udg_PP_Real1[TempNode2] = PP_PRProjectileAccel()
                            set udg_PP_Real2[TempNode2] = TempReal3 * Sin(Angle2)
                            set udg_PP_Real3[TempNode2] = TempReal3 * Cos(Angle) * Cos(Angle2)
                            set udg_PP_Real4[TempNode2] = TempReal3 * Sin(Angle) * Cos(Angle2)
                            set udg_PP_Real5[TempNode2] = PP_PRProjectileTurnRate()
                            set udg_PP_Real6[TempNode2] = PP_PRProjectileTurnEfficiency()
                            set udg_PP_Real7[TempNode2] = PP_GetZ(x2, y2) + PP_ParticleRingHeight() + PP_ParticleLaunchOffset()
                            set udg_PP_Real8[TempNode2] = x2
                            set udg_PP_Real9[TempNode2] = y2
                            set TempReal3 = PP_PRProjectileAOE()
                            set udg_PP_Real10[TempNode2] = TempReal3 * TempReal3
                            set udg_PP_Real11[TempNode2] = udg_PP_Real7[Node]
                            set udg_PP_Real12[TempNode2] = udg_PP_Real8[Node]
                            set udg_PP_TargetUnit[TempNode2] = udg_PP_Unit[Node]
                            set udg_PP_Real14[TempNode2] = GetUnitFlyHeight(udg_PP_TargetUnit[TempNode2]) + PP_TargetAimOffset()
                            set udg_PP_Boolean1[TempNode2] = false
                            set udg_PP_Boolean2[TempNode2] = true
                            set udg_PP_StageID[TempNode2] = PP_ProjectileStageID()
                            call SetUnitFlyHeight(udg_PP_Unit[TempNode2], udg_PP_Real7[TempNode2] - PP_GetZ(x2, y2), 0.)                            
                        endif
                        
                    endif
                    
                endloop
                
            endif
            
        elseif (udg_PP_StageID[Node] == PP_RecycleStageID()) then
        
            if (udg_PP_Real1[Node] <= 0) then
                call RemoveUnit(udg_PP_Unit[Node])
                call PP_Recycle(Node)
                set TempInt = TempInt - 1
            else
                set udg_PP_Real1[Node] = udg_PP_Real1[Node] - PP_TimerSpeed()
            endif
        
        endif
        
    endloop
    
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to check that the ability being cast by a hero  //
//  is the right ability and check what the target is in order    //
//  to play the correct part of the ability                       //
////////////////////////////////////////////////////////////////////
function PP_OnCast takes nothing returns boolean
    local integer SpellID = GetSpellAbilityId()
    local integer Node
    local integer iLevel
    local unit Target = GetSpellTargetUnit()
    local unit u
    local unit u2
    local real x
    local real y
    local real x2
    local real y2
    local real dy
    local real dx
    local real rLevel
    local real Angle
    local real Angle2
    local real TempReal
    local boolean TempBoolean
    
    if (SpellID == PP_AbilityID()) then
        set u = GetTriggerUnit()
        set x = GetUnitX(u)
        set y = GetUnitY(u)
        set iLevel = GetUnitAbilityLevel(u, PP_AbilityID())
        set rLevel = I2R(iLevel)
        set Node = PP_CreateNode()
        set udg_PP_Unit[Node] = CreateUnit(PP_DummyPlayer(), PP_DummyID(), x, y, 0.)
        set udg_PP_Caster[Node] = u
        set udg_PP_Player[Node] = GetOwningPlayer(u)
        if UnitAddAbility(udg_PP_Unit[Node], 'Amrf') and UnitRemoveAbility(udg_PP_Unit[Node], 'Amrf') then
        endif
            
        if (Target == null) then
            set x2 = GetSpellTargetX()
            set y2 = GetSpellTargetY()
            set dy = (y2 - y)
            set dx = (x2 - x)
            set Angle = Atan2(dy, dx)
            set Angle2 = bj_DEGTORAD * (PP_PPLaunchAngleBase() + (PP_PPLaunchAnglePerLevel() * rLevel))
            set udg_PP_CurrentEffect[Node] = AddSpecialEffectTarget(PP_PickupEffect(), udg_PP_Unit[Node], PP_AttachmentPoint())
            call SetUnitScale(udg_PP_Unit[Node], PP_PickupScaleBase() + (PP_PickupScalePerLevel() * rLevel), 0., 0.)
            set TempReal = PP_PPProjectileSpeedBase() + (PP_PPProjectileSpeedPerLevel() * rLevel)
            set udg_PP_StageID[Node] = PP_PickupStageID()
            set udg_PP_Boolean1[Node] = true
            set udg_PP_Real1[Node] = PP_PPProjectileAccelBase() + (PP_PPProjectileAccelPerLevel() * rLevel)
            set udg_PP_Real2[Node] = TempReal * Sin(Angle2)
            set udg_PP_Real3[Node] = TempReal * Cos(Angle) * Cos(Angle2)
            set udg_PP_Real4[Node] = TempReal * Sin(Angle) * Cos(Angle2)
            set udg_PP_Real5[Node] = PP_PPProjectileTurnRateBase() + (PP_PPProjectileTurnRatePerLevel() * rLevel)
            set udg_PP_Real6[Node] = PP_PPProjectileTurnEfficiencyBase() + (PP_PPProjectileTurnEfficiencyPerLevel() * rLevel)
            set udg_PP_Real7[Node] = PP_GetZ(x, y) + GetUnitFlyHeight(u) + PP_PPLaunchOffset()
            set udg_PP_Real8[Node] = x2
            set udg_PP_Real9[Node] = y2
            set udg_PP_Real10[Node] = rLevel
            set udg_PP_Real14[Node] = 0.
            set udg_PP_Integer1[Node] = PP_PProjectileCountBase() + (PP_PProjectileCountPerLevel() * iLevel)
            
            call GroupEnumUnitsInRange(udg_PP_TempGroup, x2, y2, PP_ParticleTypeDistBase() + (PP_ParticleTypeDistPerLevel() * rLevel), null)
            set TempBoolean = false
            
            loop
                set u2 = FirstOfGroup(udg_PP_TempGroup)
                exitwhen (u2 == null)
                
                if (PP_TargetFilter(u2, udg_PP_Player[Node])) then
                    set TempBoolean = true
                endif
                
                call GroupRemoveUnit(udg_PP_TempGroup, u2)
            endloop
            
            if (TempBoolean) then
                set udg_PP_Boolean2[Node] = PP_DThenH()
            else
                set udg_PP_Boolean2[Node] = not(PP_DThenH())
            endif
            
            if (udg_PP_Boolean2[Node]) then
                set udg_PP_Integer2[Node] = PP_PDParticleCountBase() + (PP_PDParticleCountPerLevel() * iLevel)
                set udg_PP_Integer3[Node] = PP_PDStartLevelBase() + (PP_PDStartLevelPerLevel() * iLevel)
                set udg_PP_Integer4[Node] = PP_PDLevelModifierBase() + (PP_PDLevelModifierPerLevel() * iLevel)
            else
                set udg_PP_Integer2[Node] = PP_PHParticleCountBase() + (PP_PHParticleCountPerLevel() * iLevel)
                set udg_PP_Integer3[Node] = PP_PHStartLevelBase() + (PP_PHStartLevelPerLevel() * iLevel)
                set udg_PP_Integer4[Node] = PP_PHLevelModifierBase() + (PP_PHLevelModifierPerLevel() * iLevel)
            endif
            
            set udg_PP_TargetUnit[Node] = Target
            call SetUnitFlyHeight(udg_PP_Unit[Node], udg_PP_Real7[Node] - PP_GetZ(x, y), 0.)
            
        else
            set x2 = GetUnitX(Target)
            set y2 = GetUnitY(Target)
            set dy = (y2 - y)
            set dx = (x2 - x)
            set Angle = Atan2(dy, dx)
            set Angle2 = bj_DEGTORAD * (PP_ParticleLaunchAngleBase() + (PP_ParticleLaunchAnglePerLevel() * rLevel))
            set udg_PP_CurrentEffect[Node] = AddSpecialEffectTarget(PP_ParticleEffect(), udg_PP_Unit[Node], PP_AttachmentPoint())
            call SetUnitScale(udg_PP_Unit[Node], PP_ParticleScaleBase() + (PP_ParticleScalePerLevel() * rLevel), 0., 0.)
            set TempReal = PP_ParticleSpeedBase() + (PP_ParticleSpeedPerLevel() * rLevel)
            set udg_PP_Real1[Node] = PP_ParticleAccelBase() + (PP_ParticleAccelPerLevel() * rLevel)
            set udg_PP_Real2[Node] = TempReal * Sin(Angle2)
            set udg_PP_Real3[Node] = TempReal * Cos(Angle) * Cos(Angle2)
            set udg_PP_Real4[Node] = TempReal * Sin(Angle) * Cos(Angle2)
            set udg_PP_Real5[Node] = PP_ParticleTurnRateBase() + (PP_ParticleTurnRatePerLevel() * rLevel)
            set udg_PP_Real6[Node] = PP_ParticleTurnEfficiencyBase() + (PP_ParticleTurnEfficiencyPerLevel() * rLevel)
            set udg_PP_Real7[Node] = PP_GetZ(x, y) + GetUnitFlyHeight(u) + PP_ParticleLaunchOffset()
            set udg_PP_Real8[Node] = x2
            set udg_PP_Real9[Node] = y2
            set TempReal = PP_ParticleAOEBase() + (PP_ParticleAOEPerLevel() * rLevel)
            set udg_PP_Real10[Node] = TempReal * TempReal
            set udg_PP_Real11[Node] = PP_ParticleHealthDamageBase() + (PP_ParticleHealthDamagePerLevel() * rLevel)
            set udg_PP_Real12[Node] = PP_ParticleManaDamageBase() + (PP_ParticleManaDamagePerLevel() * rLevel)
            set udg_PP_Integer1[Node] = PP_ParticleParticleCountBase() + (PP_ParticleParticleCountPerLevel() * iLevel)
            set udg_PP_Real13[Node] = rLevel
            set udg_PP_TargetUnit[Node] = Target
            set udg_PP_Real14[Node] = GetUnitFlyHeight(udg_PP_TargetUnit[Node]) + PP_TargetAimOffset()
            set udg_PP_Boolean1[Node] = true
            set udg_PP_Boolean2[Node] = true
            set udg_PP_StageID[Node] = PP_ProjectileStageID()
            call SetUnitFlyHeight(udg_PP_Unit[Node], udg_PP_Real7[Node] - PP_GetZ(x, y), 0.)
        endif
        
        call  SetUnitFacing(udg_PP_Unit[Node], bj_RADTODEG * Atan2(udg_PP_Real4[Node], udg_PP_Real3[Node]))

        if (udg_PP_AbilityCounter == 1) then
            call TimerStart(udg_PP_Timer, PP_TimerSpeed(), true, function PP_Loop)
        endif
        
    endif
    
    return false
endfunction

////////////////////////////////////////////////////////////////////
//  Initialisation trigger, applies the conditions to triggers    //
//  and sets up the global location used to get location Z's      //
//  as well as the map bounds                                     //
////////////////////////////////////////////////////////////////////
function InitTrig_Particle_Punisher takes nothing returns nothing
    //Set up locals
    local trigger PP = CreateTrigger()
    local integer index = 0

    //Set up hero casting triggers
    loop
        //Applies the even to each player in turn
        call TriggerRegisterPlayerUnitEvent(PP, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop

    //Applies the function to check for each spell to the trigger
    call TriggerAddCondition(PP, Condition(function PP_OnCast))

    //Set up the location used to find Z heights
    set udg_PP_Loc = Location(0,0)
    //Set up the Timer used to run the loop
    set udg_PP_Timer = CreateTimer()

    //Sets up the variables used to make sure a point is within the map area
    set udg_PP_MapMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
    set udg_PP_MapMinX = GetRectMinX(bj_mapInitialPlayableArea)
    set udg_PP_MapMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
    set udg_PP_MapMinY = GetRectMinY(bj_mapInitialPlayableArea)
endfunction
////////////////////////////////////////////////////////////////////
// End of the spell                                               //
////////////////////////////////////////////////////////////////////


And here's on last WIP image for you guys (when the particle ring is activated but before the final explosion)
 

Attachments

  • Zephyr Contest #13 WIP 3.png
    Zephyr Contest #13 WIP 3.png
    182.1 KB · Views: 141
Entry Post - Punishing Particles

[TD]Punishing Particles[/TD]
Tooltip


Icon
icons_18026_btn.jpg
[td]
Alternate
icons_18027_btn.jpg
Q - Punishing Particles
Launches experimental energies when aimed to land near enemy units which rapidly decay, damaging or healing them when stepped on depending on how close to an enemy the projectile target was. They also apply energy stacks onto enemy units, launching energy directly at an enemy releases the stored energy

Level 1 - Energy heals enemies by 500 and deal 175 damage, energy stacks deal 75 damage
Level 2 - Energy heals enemies by 600 and deal 250 damage, energy stacks deal 100 damage
Level 3 - Energy heals enemies by 700 and deal 325 damage, energy stacks deal 125 damage

Code

JASS:
////////////////////////////////////////////////////////////////////
//                   PUNISHING PARTICLES V1.00                    //
//  Author: Tank-Commander                                        //
//  Requires: Dummy.mdl                                           //
//  Purpose: Deceptive/Skill-Based/Disable                        //
//                                                                //
//  Notes:                                                        //
//    -  Read the readme before you try modifying the config      //
//    -  Use the "Helpful files" to help you import the spell     //
//                                                                //
//  Credits:                                                      //
//    -  (Dummy.mdl) Vexorian                                     //
//    -  (AquaSpike.mdl) JetFangInferno                           //
//    -  (SpiritOrb.mdl) 00110000                                 //
//    -  (WispMissile.blp) ~Nightmare                             //
//                                                                //
//  If you have used this spell in your map, you are required     //
//  to give credits to Tank-Commander for the creation of it      //
//  If you would like to use snippets of code from this for       //
//  whatever, getting permission and crediting the source/linking //
//  would be much appreciated.                                    //
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  README:                                                       //
//    Before modifying this spell a few things need to be         //
//    understood and read, this is one of those things, while     //
//    most modification can be considered intuitive, it still     //
//    helps to read through these instructions, as they will      //
//    inform you about how to configure this spell to your        //
//    desire.                                                     //
//----------------------------------------------------------------//
//  Initial importing: The variable creator trigger can be        //
//  imported first and if you have the correct settings (file,    //
//  preferences, General, automatically create unknown variables  //
//  checked, then when you paste in the variable creator it       //
//  will automatically give you all the variables you need for    //
//  this spell                                                    //
//                                                                //
//  While the remaining object editor based data is not required  //
//  to function (provided they're replaced with equivelents)      //
//  it's recommended that they are also imported, if their data   //
//  values are not the same as listed in the configuration, those //
//  configurables will need to be changed to work correctly       //
//----------------------------------------------------------------//
//  This configuration is divided up in order to make it easier   //
//  to modify specific aspects of the spell via locating the      //
//  appropriate section, they are divided up into these sections: //
//      - General                                                 //
//      - Setup                                                   //
//      - Damage                                                  //
//      - Aesthetics                                              //
//      - Physics                                                 //
//      - Loop control (Can be configured but mostly read-only)   //
//----------------------------------------------------------------//
//  WHAT PART IS WHAT?!                                           //
//  This section tells you about what prefix denotes what part    //
//  of the spell                                                  //
//      - Pickup: This is the healing or damaging part left on    //
//                the floor by the first part (target ground)     //
//                of the abilities for enemies to step on         //
//      - PickupProjectile: This is the Pickup while it is still  //
//                in transit (flying through the air)             //
//      - ParticleProjectile: This is the particles that are      //
//                created when the pickup is stepped on           //
//      - DamagingPickup: This is specific to Pickups that deal   //
//                damage                                          //
//      - HealingPickup: This is specific to Pickups that heal    //
//                enemies                                         //
//      - Particle: This is the second part (target enemy) of     //
//                the ability while it is in transit before it    //
//                has activated energy stacks                     //
//      - ParticleRing: These are the energy stacks which float   //
//                above and around an affected enemy              //
//      - ReleasedParticle: These are the particles created by    //
//                an active ParticleRing or energy stack          //
//      - ParticleFinale: This is the explosion when all          //
//                ParticleRings or energy stacks have released    //
//                their energy                                    //
//                                                                //
//  Following this section should make most of the configuration  //
//  self-explanatory, so comments are kept to the less clear      //
//  configurables                                                 //
//----------------------------------------------------------------//
//  CONFIGURABLE INFORMATION/HELP:                                //
//                                                                //
//  - Viewing data values: To see data values in the editor you   //
//  need to press Ctrl + D, to shift back to normal viewing       //
//  press it again                                                //
//                                                                //
//  - Effects: Pathnames for effects used in the spells should    //
//  have two "\"s throughout or the effect will not work (the     //
//  WE progress bar will not go away when saving, however if      //
//  fixed afterwards the save will still work, but the progress   //
//  bar will still remain until the WE is closed)                 //
//  e.g. "units\\human\\Footman\\Footman"                         //
//                                                                //
//  - Effect Scaling: Some effects have scale values below them   //
//  the scale determines the size of the effect and is expressed  //
//  as a real percentage (1.00 = 100%)                            //
//                                                                //
//  - Removing Effects: to remove an effect you don't want from   //
//  the ability, set the model path to that of Dummy.mdl          //
//                                                                //
//  - Base and Per Values: Most configurables have a base and per //
//  value, Base values are what a value is set to regardless of   //
//  other factors. Per values are what a value is set to based on //
//  what the per value is the formula for calculating the result  //
//  is as follows:                                                //
//    - BaseValue + (Factor * PerValue)                           //
//                                                                //
//  - Factors: Per values all have factors, what the factor is,   //
//  is described in the configuration. All factors in this spell  //
//  are per level (level of the ability)                          //
//                                                                //
//  - AttackTypes: This should match the Damage Type of the       //
//  ability, though it can be something else if you wish          //
//                                                                //
//  - DamageTypes: This changes the damage multiplyer vs. enemy   //
//  armour types, note that by default the damage filters         //
//  exclude magic immune units so changing this from MAGIC        //
//  damage will not make them take damage                         //
//                                                                //
//  - WeaponTypes: Generally don't need to be used, should only   //
//  not be null if you particularly wish or need to use them      //
//                                                                //
//  - Physics: This has it's own section at its relevent point    //
//  in the configuration given the complexity of how it works     //
//  and the amount of configurables, please consult with that     //
//  when setting it up                                            //
//                                                                //
//  - StageIDs: Modifying StageIDs in the loop control can cause  //
//   the spellto stop functioning corretly, understanding of the  //
//  code is strongly recommended should you attempt to change     //
//  these                                                         //
//                                                                //
//----------------------------------------------------------------//
//                           GENERAL                              //
//----------------------------------------------------------------//
//  TimerSpeed: This is the rate in which the loop function runs  //
//  default value is 0.031250000, this value cannot be 0, for any //
//  other value the system automatically adjusts so that things   //
//  remain as normal, the exception to this is the decay rate and //
//  energy stack spin speeds which will need to be adjusted to    //
//  match the new TimerSpeed                                      //
//  vals between 0.03 <-> 0.04 are recommended                    //
constant function PP_TimerSpeed takes nothing returns real
    return 0.031250000
endfunction
//----------------------------------------------------------------//
//  DummyID: This is the data value of the unit that serves as    //
//  the dummy, it should have Dummy.mdl set to its model have     //
//  locust as its ability, movement type float (or fly) and 0     //
//  pitch and roll angle for optimal use                          //
constant function PP_DummyID takes nothing returns integer
    return 'u000'
endfunction
//----------------------------------------------------------------//
//  AbilityID: This is the data value of the ability that serves  //
//  as the base ability for this spell, it should be based on     //
//  channel and have the target type set to "Unit or Point        //
//  Target" so that both parts may be used, if you'd like to use  //
//  two different abilities for each part then you will also      //
//  have to modify the appropriate code near the bottom of this   //
//  trigger                                                       //
constant function PP_AbilityID takes nothing returns integer
    return 'A000'
endfunction
//----------------------------------------------------------------//
//  BuffID: This is the data value of the ability used to slow    //
//  units that have stepped on a particle, it should have at      //
//  least two levels, how much each level slows is optional       //
constant function PP_BuffID takes nothing returns integer
    return 'A001'
endfunction
//----------------------------------------------------------------//
//  StunID: This is the data value of the ability used to stun    //
//  enemies during the second part of the ability, it should stun //
//  for at least 0.5 seconds in order to make it constant. If     //
//  you want to remove the stun, you can set this to any other    //
//  ability and it will not run                                   //
constant function PP_StunID takes nothing returns integer
    return 'A002'
endfunction
//----------------------------------------------------------------//
//  StunOrderID: This is the OrderID for the stun ability, this   //
//  should match your StunID ability type, if you do not know the //
//  order ID it can be located via search engine by typing in     //
//  "WC3 Order IDs" though there are other methods such as using  //
//  a trigger to tell you what the order ID for a given ability   //
//  is                                                            //
constant function PP_StunOrderID takes nothing returns integer
    return 852095
endfunction
//----------------------------------------------------------------//
//  EffectDelayTimer: This is the time in seconds after a unit is //
//  set to be recycled that it will be removed from the game,     //
//  it should be high enough so that effects can finish being     //
//  played before the unit is removed                             //
constant function PP_EffectDelayTimer takes nothing returns real
    return 3.00
endfunction
//----------------------------------------------------------------//
//  DummyPlayer: This is the player who will own all dummy units  //
//  created by this ability, by default this is Player(14)        //
constant function PP_DummyPlayer takes nothing returns player
    return Player(14)
endfunction
//----------------------------------------------------------------//
//                            SETUP                               //
//----------------------------------------------------------------//
//  AttackType: This is the attack type used by the spell, for    //
//  information pertaining to this and DamageType and WeaponType  //
//  consult the CONFIGURABLE INFORMATION/HELP section             //
constant function PP_AttackType takes nothing returns attacktype
    return ATTACK_TYPE_MAGIC
endfunction
//----------------------------------------------------------------//
//  Damageype: This is the damage type used by the spell, for    //
//  information pertaining to this and AttackType and WeaponType  //
//  consult the CONFIGURABLE INFORMATION/HELP section             //
constant function PP_DamageType takes nothing returns damagetype
    return DAMAGE_TYPE_MAGIC
endfunction
//----------------------------------------------------------------//
//  WeaponType: This is the weapon type used by the spell, for    //
//  information pertaining to this and DamageType and AttackType  //
//  consult the CONFIGURABLE INFORMATION/HELP section             //
constant function PP_WeaponType takes nothing returns weapontype
    return null
endfunction
//----------------------------------------------------------------//
//  DThenH: This determines which way around Pickups are ordered  //
//  if true then pickups closer to enemies will deal damage if    //
//  false then pickups closer to enemies will heal them instead   //
constant function PP_DThenH takes nothing returns boolean
    return true
endfunction
//----------------------------------------------------------------//
//  PickupTypeDist: This determines how close a pickup must be    //
//  to an enemy for the "closer version" to be applied            //
//  this should closely match the AOE of the dummy ability        //
//  with a bit of an oversight (about 10.00) to make it easier    //
//  to use the ability effectively                                //
constant function PP_PickupTypeDistBase takes nothing returns real
    return 160.00
endfunction
//                                                                //
constant function PP_PickupTypeDistPerLevel takes nothing returns real
    return .0
endfunction
//----------------------------------------------------------------//
//  FilterMaxZ: This is the maximum fly height of a unit that     //
//  can be targetted by this ability if the default target filter //
//  is being used                                                 //
constant function PP_FilterMaxZ takes nothing returns real
    return 50.
endfunction
//----------------------------------------------------------------//
//  PickupAOE: This is the area around the pickup that if any     //
//  valid enemy unit comes within range of, will automatically    //
//  pick up and set off the particle                              //
constant function PP_PickupAOEBase takes nothing returns real
    return 100.
endfunction
//                                                                //
constant function PP_PickupAOEPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  PickupDuration: This is the timer in seconds for which any    //
//  given pickup remains on the map before it is automatically    //
//  removed (they can have negligible damage but still apply the  //
//  normal amount of energy stacks)                               //
constant function PP_PickupDurationBase takes nothing returns real
    return 4.
endfunction
//                                                                //
constant function PP_PickupDurationPerLevel takes nothing returns real
    return 1.
endfunction
//----------------------------------------------------------------//
//  SlowTimeout: This is how long it takes for each level of the  //
//  slow to be reduced to 1 level lower, consider how many levels //
//  units will have before choosing what to set this as           //
constant function PP_SlowTimeoutBase takes nothing returns real
    return 4.00
endfunction
//                                                                //
constant function PP_SlowTimeoutPerLevel takes nothing returns real
    return 0.00
endfunction
//----------------------------------------------------------------//
//  PickupStartLevel: This is the level of the slow that will     //
//  be applied to a unit that stepped on a pickup if they do not  //
//  already have an applied slow                                  //
constant function PP_DamagingPickupStartLevelBase takes nothing returns integer
    return 2
endfunction
//                                                                //
constant function PP_DamagingPickupStartLevelPerLevel takes nothing returns integer
    return 0
endfunction
//                                                                //
constant function PP_HealingPickupStartLevelBase takes nothing returns integer
    return 1
endfunction
//                                                                //
constant function PP_HealingPickupStartLevelPerLevel takes nothing returns integer
    return 0
endfunction
//----------------------------------------------------------------//
//  PickupLevelModifier: This is the way in which stepping on a   //
//  pickup affects the slow level of a unit which already has an  //
//  applied slow                                                  //
constant function PP_DamagingPickupLevelModifierBase takes nothing returns integer
    return 1
endfunction
//                                                                //
constant function PP_DamagingPickupLevelModifierPerLevel takes nothing returns integer
    return 0
endfunction
//                                                                //
constant function PP_HealingPickupLevelModifierBase takes nothing returns integer
    return -1
endfunction
//                                                                //
constant function PP_HealingPickupLevelModifierPerLevel takes nothing returns integer
    return 0
endfunction
//----------------------------------------------------------------//
//                           DAMAGE                               //
//----------------------------------------------------------------//
constant function PP_DamagingPickupDamageHealthBase takes nothing returns real
    return 100.
endfunction
//                                                                //
constant function PP_DamagingPickupDamageHealthPerLevel takes nothing returns real
    return 75.
endfunction
//----------------------------------------------------------------//
constant function PP_DamagingPickupDamageManaBase takes nothing returns real
    return 0.
endfunction
//                                                                //
constant function PP_DamagingPickupDamageManaPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_HealingPickupHealHealthBase takes nothing returns real
    return 400.
endfunction
//                                                                //
constant function PP_HealingPickupHealHealthPerLevel takes nothing returns real
    return 100.
endfunction
//----------------------------------------------------------------//
constant function PP_HealingPickupHealManaBase takes nothing returns real
    return 0.
endfunction
//                                                                //
constant function PP_HealingPickupHealManaPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_PickupPercentageMainBase takes nothing returns real
    return .6
endfunction
//                                                                //
constant function PP_PickupPercentageMainPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  PickupDecayRate: This is the speed at which any given pickup  //
//  loses its potency per timer iteration, to find the number you //
//  want for a given interval/amount lost use the formula:        //
//  Pow(Amount to decay by, 1 / Interval to decay over)           //
//  Keep in mind that the interval must be a factor of the        //
//  TimerSpeed value                                              //
//  e.g. to decay 0.5 of your potency over 1.5 seconds            //
//  Pow(0.5, 1 / (1.5 / 0.03125)) given default TimerSpeed        //
//  Pow(0.5, 1/48)                                                //
//  0.98566319(...)                                               //
//  Which is the default value for this configurable              //
constant function PP_PickupDecayRateBase takes nothing returns real
    return 0.98566
endfunction
//                                                                //
constant function PP_PickupDecayRatePerLevel takes nothing returns real
    return 0.00200
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleHealthDamageBase takes nothing returns real
    return 0.
endfunction
//                                                                //
constant function PP_ParticleHealthDamagePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleManaDamageBase takes nothing returns real
    return 0.
endfunction
//                                                                //
constant function PP_ParticleManaDamagePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  ParticleRingCount: This is the amount of energy stacks that   //
//  are applied to a unit by the prefixed source                  //
constant function PP_HealingPickupParticleRingCountBase takes nothing returns integer
    return 1
endfunction
//                                                                //
constant function PP_HealingPickupParticleRingCountPerLevel takes nothing returns integer
    return 0
endfunction
//                                                                //
constant function PP_DamagingPickupParticleRingCountBase takes nothing returns integer
    return 2
endfunction
//                                                                //
constant function PP_DamagingPickupParticleRingCountPerLevel takes nothing returns integer
    return 0
endfunction
//                                                                //
constant function PP_ParticleParticleRingCountBase takes nothing returns integer
    return 0
endfunction
//                                                                //
constant function PP_ParticleParticleRingCountPerLevel takes nothing returns integer
    return 0
endfunction
//----------------------------------------------------------------//
//  ParticleRingStored: This is the amount of the suffixed        //
//  thing that is kept within each energy stack before it is      //
//  activated                                                     //
constant function PP_ParticleRingStoredHealthDamageBase takes nothing returns real
    return 50.
endfunction
//                                                                //
constant function PP_ParticleRingStoredHealthDamagePerLevel takes nothing returns real
    return 25.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleRingStoredManaDamageBase takes nothing returns real
    return 0.
endfunction
//                                                                //
constant function PP_ParticleRingStoredManaDamagePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
//  FireRate: This is how fast energy stacks release their energy //
//  and thus directly relates to how long a unit will be stunned  //
//  for (lower number -> faster fire rate)                        //
//  (faster fire rate -> Stunned for a shorter period of time)    //
constant function PP_ParticleRingFireRate takes nothing returns real
    return 0.30
endfunction
//----------------------------------------------------------------//
//  StoredSalvos: This is how many more sets of particles that    //
//  will be launched at an affected unit by a active energy       //
//  energy stacks, per energy stack                               //
constant function PP_ParticleRingStoredSalvosBase takes nothing returns integer
    return 3
endfunction
//                                                                //
constant function PP_ParticleRingStoredSalvosPerLevel takes nothing returns integer
    return 0
endfunction
//----------------------------------------------------------------//
//  FinalePercentage: This is the ratio to the amount of total    //
//  stored energy that is dealt as bonus damage once all energy   //
//  stacks have released their energy (0.5 is 50%)                //
constant function PP_ParticleFinalePercentageHealth takes nothing returns real
    return .5
endfunction
//                                                                //
constant function PP_ParticleFinalePercentageMana takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleFinaleAOE takes nothing returns real
    return 150.
endfunction
//----------------------------------------------------------------//
//                         AESTHETICS                             //
//----------------------------------------------------------------//
//  AttachmentPoint: This is the point on the dummy model that    //
//  all effects are attached to - by default it's set to origin   //
//  and performs most optimally when left that way                //
constant function PP_AttachmentPoint takes nothing returns string
    return "origin"
endfunction
//----------------------------------------------------------------//
constant function PP_PickupEffect takes nothing returns string
    return "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
endfunction
//----------------------------------------------------------------//
constant function PP_PickupDetonateEffect takes nothing returns string
    return "Abilities\\Weapons\\SteamTank\\SteamTankImpact.mdl"
endfunction
//----------------------------------------------------------------//
constant function PP_SlowEffect takes nothing returns string
    return "Abilities\\Spells\\Human\\slow\\slowtarget.mdl"
endfunction
//----------------------------------------------------------------//
constant function PP_PickupScaleBase takes nothing returns real
    return 2.
endfunction
//                                                                //
constant function PP_PickupScalePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_HealingPickupProjectileEffect takes nothing returns string
    return "Abilities\\Weapons\\SeaElementalMissile\\SeaElementalMissile.mdl"
endfunction
//----------------------------------------------------------------//
constant function PP_DamagingPickupProjectileEffect takes nothing returns string
    return "Abilities\\Weapons\\SludgeMissile\\SludgeMissile.mdl"
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleProjectileScaleBase takes nothing returns real
    return 0.25
endfunction
//                                                                //
constant function PP_ParticleProjectileScalePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleEffect takes nothing returns string
    return "war3mapImported\\Spirit Orb.mdl"
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleScaleBase takes nothing returns real
    return 3.
endfunction
//                                                                //
constant function PP_ParticleScalePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleRingEffect takes nothing returns string
    return "Objects\\InventoryItems\\CrystalShard\\CrystalShard.mdl"
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleRingSpawnEffect takes nothing returns string
    return "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl"
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleRingDestroyEffect takes nothing returns string
    return "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl"
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleRingScaleBase takes nothing returns real
    return 1.0
endfunction
//                                                                //
constant function PP_ParticleRingScalePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleReleaseEffect takes nothing returns string
    return "Abilities\\Weapons\\WaterElementalMissile\\WaterElementalMissile.mdl"
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleReleaseScale takes nothing returns real
    return 0.1
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleFinaleinalEffect takes nothing returns string
    return "war3mapImported\\AquaSpike.mdx"
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleFinaleinalScale takes nothing returns real
    return 1.
endfunction
//----------------------------------------------------------------//
//  HeightOffset: This is how high off the ground (0) the effect  //
//  is placed at                                                  //
constant function PP_ParticleFinaleHeightOffset takes nothing returns real
    return 0.
endfunction
//                                                                //
constant function PP_ParticleRingHeightOffset takes nothing returns real
    return 150.
endfunction
//----------------------------------------------------------------//
//  Offset: This is how far away from the middle of the host unit //
//  the effect is placed at                                       //
constant function PP_ParticleRingOffset takes nothing returns real
    return 100.
endfunction
//----------------------------------------------------------------//
//  SpinSpeed: This is how fast the energy stacks spin in radians //
//  per TimerSpeed cycle
constant function PP_ParticleRingSpinSpeed takes nothing returns real
    return 0.02
endfunction
//----------------------------------------------------------------//
//  ProjectileCount: This is the amount of particle projectiles   //
//  that are created by a pickup when they are stepped on         //
//  how many there are (so long as it's 1 or above) does not      //
//  impact damage dealt)                                          //
constant function PP_ParticleProjectileCountBase takes nothing returns integer
    return 7
endfunction
//                                                                //
constant function PP_ParticleProjectileCountPerLevel takes nothing returns integer
    return 0
endfunction
//----------------------------------------------------------------//
//                           PHYSICS                              //
//----------------------------------------------------------------//
//  Physics in this ability are rather complex, so the guide to   //
//  configure them is located here rather than at the top to make //
//  consultation easier                                           //
//                                                                //
//  Each prefixed section is arranged into the same order to      //
//  further ease the difficulty of the section                    //
//      - AOE: This is how close to a target the projectile must  //
//          be to be considered in contact with that target       //
//          not all projectiles have this field                   //
//      - LaunchOffset: Has a height offset variant as well,      //
//          this is how far away from the source that the unit    //
//          will be created, height is how far above              //
//      - LaunchAngle: This is the angle (in degrees) that the    //
//          projectiles will be launched (90 being upwards, 0     //
//          being straight across and -90 being downwards)        //
//      - Speed: This is how fast the projectile initially        //
//          travels, the strength of the launch                   //
//      - TurnRate: This is the strength at which the projectile  //
//          is pulled towards its target - this does affect the   //
//          speed of the projectile and should almost never be    //
//          a negative value as that may cause crashes            //
//      - TurnEfficiency: This is the rate at which existing      //
///         momentum is converted to be toward the target unit    //
//          (this will cause the projectile to slow when turning) //
//          1 converts 50% each cycle, 0.5 converts 25% and so on //
//      - Acell: This is the percentage increase in speed the     //
//          projectile gains or loses each cycle (1.01 being an   //
//          increase of 1% speed)                                 //
//                                                                //
//  Experimenting with this section can create interesting        //
//  results - feel free to play around with the settings but make //
//  sure to change it from any game-crashing setups               //
//----------------------------------------------------------------//
//  HeightLet: This is the maximum fly height any given           //
//  projectile can have and be treated as being on the ground     //
constant function PP_HeightLet takes nothing returns real
    return 20.
endfunction
//----------------------------------------------------------------//
constant function PP_PickupProjectileLaunchOffset takes nothing returns real
    return 90.
endfunction
//----------------------------------------------------------------//
constant function PP_PickupProjectileLaunchAngleBase takes nothing returns real
    return 135.
endfunction
//                                                                //
constant function PP_PickupProjectileLaunchAnglePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_PickupProjectileSpeedBase takes nothing returns real
    return 200.
endfunction
//                                                                //
constant function PP_PickupProjectileSpeedPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_PickupProjectileTurnRateBase takes nothing returns real
    return 5.
endfunction
//                                                                //
constant function PP_PickupProjectileTurnRatePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_PickupProjectileTurnEfficiencyBase takes nothing returns real
    return 0.30
endfunction
//                                                                //
constant function PP_PickupProjectileTurnEfficiencyPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_PickupProjectileAccelBase takes nothing returns real
    return 1.01
endfunction
//                                                                //
constant function PP_PickupProjectileAccelPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleProjectileAOEBase takes nothing returns real
    return 90.
endfunction
//                                                                //
constant function PP_ParticleProjectileAOEPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleProjectileLaunchHeightOffset takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleProjectileLaunchDistOffset takes nothing returns real
    return 20.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleProjectileLaunchAngleBase takes nothing returns real
    return 55.
endfunction
//                                                                //
constant function PP_ParticleProjectileLaunchAnglePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleProjectileSpeedBase takes nothing returns real
    return 175.
endfunction
//                                                                //
constant function PP_ParticleProjectileSpeedPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleProjectileTurnRateBase takes nothing returns real
    return 1.
endfunction
//                                                                //
constant function PP_ParticleProjectileTurnRatePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleProjectileTurnEfficiencyBase takes nothing returns real
    return .25
endfunction
//                                                                //
constant function PP_ParticleProjectileTurnEfficiencyPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleProjectileAccelBase takes nothing returns real
    return 1.01
endfunction
//                                                                //
constant function PP_ParticleProjectileAccelPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleAOEBase takes nothing returns real
    return 55.
endfunction
//                                                                //
constant function PP_ParticleAOEPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleLaunchOffset takes nothing returns real
    return 50.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleLaunchAngleBase takes nothing returns real
    return 0.
endfunction
//                                                                //
constant function PP_ParticleLaunchAnglePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleSpeedBase takes nothing returns real
    return 75.
endfunction
//                                                                //
constant function PP_ParticleSpeedPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleTurnRateBase takes nothing returns real
    return 1.
endfunction
//                                                                //
constant function PP_ParticleTurnRatePerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleTurnEfficiencyBase takes nothing returns real
    return .5
endfunction
//                                                                //
constant function PP_ParticleTurnEfficiencyPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleAccelBase takes nothing returns real
    return 1.00
endfunction
//                                                                //
constant function PP_ParticleAccelPerLevel takes nothing returns real
    return 0.
endfunction
//----------------------------------------------------------------//
constant function PP_ReleasedParticleProjectileAOE takes nothing returns real
    return 60.
endfunction
//----------------------------------------------------------------//
constant function PP_ReleasedParticleLaunchOffset takes nothing returns real
    return 50.
endfunction
//----------------------------------------------------------------//
constant function PP_ReleasedParticleProjectileLaunchAngle takes nothing returns real
    return 30.
endfunction
//----------------------------------------------------------------//
constant function PP_ReleasedParticleProjectileSpeed takes nothing returns real
    return 70.
endfunction
//----------------------------------------------------------------//
constant function PP_ReleasedParticleProjectileTurnRate takes nothing returns real
    return 1.
endfunction
//----------------------------------------------------------------//
constant function PP_ReleasedParticleProjectileTurnEfficiency takes nothing returns real
    return .25
endfunction
//----------------------------------------------------------------//
constant function PP_ReleasedParticleProjectileAccel takes nothing returns real
    return 1.01
endfunction
//----------------------------------------------------------------//
//  Aimoffset: This is how far above the fly height of the unit   //
//  that all projectiles will attempt to aim at                   //
constant function PP_TargetAimOffset takes nothing returns real
    return 40.
endfunction
//----------------------------------------------------------------//
//  Gravity: This is how fast all projectiles are pulled toward   //
//  the ground
constant function PP_Gravity takes nothing returns real
    return 2.
endfunction
//----------------------------------------------------------------//
//                        LOOP CONTROL                            //
//----------------------------------------------------------------//
constant function PP_PickupStageID takes nothing returns integer
    return 1
endfunction
//----------------------------------------------------------------//
constant function PP_ReleasedParticleojectileStageID takes nothing returns integer
    return 2
endfunction
//----------------------------------------------------------------//
constant function PP_SlowedUnitStageID takes nothing returns integer
    return 3
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleRingStageID takes nothing returns integer
    return 4
endfunction
//----------------------------------------------------------------//
constant function PP_RecycleStageID takes nothing returns integer
    return 5
endfunction
//----------------------------------------------------------------//
//                      END OF CONFIGURATION                      //
//----------------------------------------------------------------//
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//  Target filter Code (can be configured but requires some       //
//  understanding of programming to do so)                        //
////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////
//  Enemy target filter function - Passed units and players, using //
//  them to check if the unit can be treated as an enemy by the    //
//  spellset                                                       //
/////////////////////////////////////////////////////////////////////
function PP_TargetFilter takes unit u, player pl returns boolean

    //Checks if the unit can be used as a target
    return (not IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (GetUnitFlyHeight(u) <= PP_FilterMaxZ()) and (not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)) and (IsUnitEnemy(u, pl)) and (GetUnitTypeId(u) != PP_DummyID()) and not(IsUnitType(u, UNIT_TYPE_DEAD) or GetUnitTypeId(u) == 0)
   
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to get the z height of locations needed by the  //
//  spell, since it can only be done with locations, this one     //
//  is reused throughout, instead of creating/destroying them     //
////////////////////////////////////////////////////////////////////
function PP_GetZ takes real x, real y returns real

    //Gets the location Z of the selected location
    call MoveLocation(udg_PP_Loc, x, y)
    return GetLocationZ(udg_PP_Loc)
   
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to make sure that the location is within the    //
//  map bounds so that units cannot be moved outside of it and    //
//  get permanently stuck                                         //
////////////////////////////////////////////////////////////////////
function PP_ValidateLocation takes real x, real y returns boolean
   
    //Check if the point is within the map bounds
    return (x < udg_PP_MapMaxX) and (x > udg_PP_MapMinX) and (y < udg_PP_MapMaxY) and (y > udg_PP_MapMinY)

endfunction

////////////////////////////////////////////////////////////////////
//  Function used to recycle instances, so that they can used     //
//  again later, keeping the total array sizes smaller            //
////////////////////////////////////////////////////////////////////
function PP_Recycle takes integer Node returns nothing
       
        if (udg_PP_LastNode == Node) then
            set udg_PP_LastNode = udg_PP_PrevNode[Node]
        endif
           
        //Recycles the node
        set udg_PP_RecycleNodes[udg_PP_RecyclableNodes] = Node
        set udg_PP_RecyclableNodes = udg_PP_RecyclableNodes + 1
        set udg_PP_NextNode[udg_PP_PrevNode[Node]] = udg_PP_NextNode[Node]
        set udg_PP_PrevNode[udg_PP_NextNode[Node]] = udg_PP_PrevNode[Node]
        set udg_PP_AbilityCounter = udg_PP_AbilityCounter - 1

        //Stops the timer if this is the only remaining Node
        if (udg_PP_AbilityCounter == 0) then
            call PauseTimer(udg_PP_Timer)
        endif

endfunction

////////////////////////////////////////////////////////////////////
//  Function used to create new Nodes for the system whenever a   //
//  unit or effect is added to run in the loop function           //
////////////////////////////////////////////////////////////////////
function PP_CreateNode takes nothing returns integer
    //set up local
    local integer Node = 0
   
    //Checking for recycleable Nodes
    if (udg_PP_RecyclableNodes == 0) then
        set udg_PP_NodeNumber = udg_PP_NodeNumber + 1
        set Node = udg_PP_NodeNumber
    else
        set udg_PP_RecyclableNodes = udg_PP_RecyclableNodes - 1
        set Node = udg_PP_RecycleNodes[udg_PP_RecyclableNodes]
    endif

    //Sets up this Node
    set udg_PP_NextNode[Node] = 0
    set udg_PP_NextNode[udg_PP_LastNode] = Node
    set udg_PP_PrevNode[Node] = udg_PP_LastNode
    set udg_PP_LastNode = Node
   
    set udg_PP_AbilityCounter = udg_PP_AbilityCounter + 1
   
    return Node
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to add new particles to the rings of units      //
//  when they have aquired a pickup or been hit by the main       //
//  particle (if it has been configured to add particles)         //
////////////////////////////////////////////////////////////////////
function PP_AddParticleToRing takes unit u, integer UNode, integer Number, real Level returns nothing
    //Set up locals
    local integer Node
    local integer TempInt = 0
    local real TempReal
    
    //Creates the particles
    loop
        set TempInt = TempInt + 1
        exitwhen (TempInt > Number)
        
        //Create Unit
        set Node = PP_CreateNode()
        set udg_PP_Unit[Node] = CreateUnit(PP_DummyPlayer(), PP_DummyID(), GetUnitX(u), GetUnitY(u), 0)
        set udg_PP_CurrentEffect[Node] = AddSpecialEffectTarget(PP_ParticleRingEffect(), udg_PP_Unit[Node], PP_AttachmentPoint())
        call SetUnitScale(udg_PP_Unit[Node], PP_ParticleRingScaleBase() + (PP_ParticleRingScalePerLevel() * Level), 0., 0.)
        if UnitAddAbility(udg_PP_Unit[Node], 'Amrf') and UnitRemoveAbility(udg_PP_Unit[Node], 'Amrf') then
        endif
        call DestroyEffect(AddSpecialEffectTarget(PP_ParticleRingSpawnEffect(), udg_PP_Unit[Node], PP_AttachmentPoint()))
        call SetUnitFlyHeight(udg_PP_Unit[Node], PP_ParticleRingHeightOffset(), 0.)
        //Set up Data of the Particle
        set udg_PP_Caster[Node] = u
        set udg_PP_StageID[Node] = PP_ParticleRingStageID()
        //Update host unit information
        set udg_PP_Integer2[UNode] = udg_PP_Integer2[UNode] + 1
        set udg_PP_Real4[UNode] = udg_PP_Real4[UNode] + PP_ParticleRingStoredHealthDamageBase() + (PP_ParticleRingStoredHealthDamagePerLevel() * Level)
        set udg_PP_Real5[UNode] = udg_PP_Real5[UNode] + PP_ParticleRingStoredManaDamageBase() + (PP_ParticleRingStoredManaDamagePerLevel() * Level)
        set udg_PP_Integer3[UNode] = udg_PP_Integer3[UNode] + PP_ParticleRingStoredSalvosBase() + (PP_ParticleRingStoredSalvosPerLevel() * R2I(Level))
        set TempReal = I2R(udg_PP_Integer2[UNode] * udg_PP_Integer3[UNode])
        set udg_PP_Real7[UNode] = (udg_PP_Real4[UNode] - udg_PP_Real9[UNode]) / TempReal
        set udg_PP_Real8[UNode] = (udg_PP_Real5[UNode] - udg_PP_Real10[UNode]) / TempReal
    endloop
    
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to move all projectile-type entities in the     //
//  abiity - the physics engine of the spell                      //
////////////////////////////////////////////////////////////////////
function PP_Move takes integer Node returns boolean
    //set up locals
    local real x = GetUnitX(udg_PP_Unit[Node])
    local real y = GetUnitY(udg_PP_Unit[Node])
    local real dy = udg_PP_Real9[Node] - y
    local real dx = udg_PP_Real8[Node]- x
    local real x2
    local real y2
    local real Angle = Atan2(dy, dx)
    local real Angle2 = Atan2((PP_GetZ(udg_PP_Real8[Node], udg_PP_Real9[Node]) + udg_PP_Real14[Node]) - (PP_GetZ(x, y) + GetUnitFlyHeight(udg_PP_Unit[Node])), Pow(dx * dx + dy * dy, 0.5))
    local real Angle3 = Atan2(udg_PP_Real4[Node], udg_PP_Real3[Node])
    local real Angle4 = Atan(udg_PP_Real2[Node])
    local real TempReal = Pow(Pow(udg_PP_Real2[Node], 2) + Pow(udg_PP_Real3[Node], 2) + Pow(udg_PP_Real4[Node], 2), 0.5) * udg_PP_Real6[Node]
    local real TempReal2 = 1/(1 + udg_PP_Real6[Node]) 
    
    //Calculate new velocities
    set udg_PP_Real2[Node] = ((udg_PP_Real2[Node] + (TempReal + udg_PP_Real5[Node]) * Sin(Angle2)) * udg_PP_Real1[Node]) * TempReal2
    set udg_PP_Real3[Node] = ((udg_PP_Real3[Node] + (TempReal + udg_PP_Real5[Node]) * Cos(Angle) * Cos(Angle2)) * udg_PP_Real1[Node]) * TempReal2
    set udg_PP_Real4[Node] = ((udg_PP_Real4[Node] + (TempReal + udg_PP_Real5[Node]) * Sin(Angle) * Cos(Angle2)) * udg_PP_Real1[Node]) * TempReal2
    set udg_PP_Real7[Node] = udg_PP_Real7[Node] + udg_PP_Real2[Node] - PP_Gravity()
    
    set x2 = x + udg_PP_Real3[Node]
    set y2 = y + udg_PP_Real4[Node]
    
    //Make sure the location is within the map bounds
    if PP_ValidateLocation(x2, y2) then
        call SetUnitX(udg_PP_Unit[Node], x2)
        call SetUnitY(udg_PP_Unit[Node], y2)
    endif
    
    //Update target unit information if applicable
    if not(udg_PP_TargetUnit[Node] == null) then
        set udg_PP_Real8[Node] = GetUnitX(udg_PP_TargetUnit[Node])
        set udg_PP_Real9[Node] = GetUnitY(udg_PP_TargetUnit[Node])
        set udg_PP_Real14[Node] = GetUnitFlyHeight(udg_PP_TargetUnit[Node]) + PP_TargetAimOffset()
    endif
    
    //Apply visuals
    call SetUnitFlyHeight(udg_PP_Unit[Node], udg_PP_Real7[Node] - PP_GetZ(x2, y2), 0.)
    call SetUnitFacing(udg_PP_Unit[Node], bj_RADTODEG * Atan2(udg_PP_Real4[Node], udg_PP_Real3[Node]))
    call SetUnitAnimationByIndex(udg_PP_Unit[Node], R2I(Atan2((udg_PP_Real2[Node]), Pow((udg_PP_Real3[Node] * udg_PP_Real3[Node]) + (udg_PP_Real4[Node] * udg_PP_Real4[Node]), 0.5)) * bj_RADTODEG + 0.5) + 90)
    
    //Check if the unit has crashed into the ground
    return (GetUnitFlyHeight(udg_PP_Unit[Node]) <= PP_HeightLet())
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to identify when a projectile has hit it's      //
//  target unit so that damage can be dealt & stun can be         //
//  applied if applicable                                         //
////////////////////////////////////////////////////////////////////
function PP_HitTarget takes integer Node returns boolean
    //Set up locals
    local real x = GetUnitX(udg_PP_Unit[Node])
    local real y = GetUnitY(udg_PP_Unit[Node])
    local real dx = x - udg_PP_Real8[Node]
    local real dy = y - udg_PP_Real9[Node]
    local real dz = (PP_GetZ(udg_PP_Real8[Node], udg_PP_Real9[Node]) + GetUnitFlyHeight(udg_PP_TargetUnit[Node])) - (PP_GetZ(x, y) + GetUnitFlyHeight(udg_PP_Unit[Node]))
    
    //Measure distance between the Unit and its Target and return if it's close enough
    return (dx * dx + dy * dy + dz * dz <= udg_PP_Real10[Node])
endfunction

////////////////////////////////////////////////////////////////////
//  The main function which is used to handle all the key         //
//  components of the spell, including handling all of the spell  //
//  effects of both parts and all units which are being affected  //
//  by anything from the spell                                    //
////////////////////////////////////////////////////////////////////
function PP_Loop takes nothing returns nothing
    //Sets up locals
    local integer Node = 0
    local integer TempNode
    local integer TempNode2
    local integer TempInt = 0
    local integer TempInt2
    local real x
    local real y
    local real x2
    local real y2
    local real dy
    local real dx
    local real TempReal
    local real TempReal2
    local real TempReal3
    local real Angle
    local real Angle2
    local unit u
    local boolean TempBoolean
    local boolean TempBoolean2
    
    loop
        set TempInt = TempInt + 1
        exitwhen TempInt > udg_PP_AbilityCounter
        set Node = udg_PP_NextNode[Node]
        
        //This loop is structured in order to be as efficient as possible
        //As such, functions ran more often are closer to the top
        //So fewer comparisons are run
        
        //Projectiles
        if (udg_PP_StageID[Node] == PP_ReleasedParticleojectileStageID()) then
            //Move the projectile
            if (PP_Move(Node)) then
                //Destroy on crash
                call DestroyEffect(udg_PP_CurrentEffect[Node])
                set udg_PP_StageID[Node] = PP_RecycleStageID()
                set udg_PP_Real1[Node] = PP_EffectDelayTimer()
            //Check if it hit the target
            elseif (PP_HitTarget(Node)) then
                call DestroyEffect(udg_PP_CurrentEffect[Node])
                
                //Damage the target appropriately (healing or damaging)
                if (udg_PP_Boolean2[Node]) then
                    call UnitDamageTarget(udg_PP_Caster[Node], udg_PP_TargetUnit[Node], udg_PP_Real11[Node], false, false, PP_AttackType(), PP_DamageType(), PP_WeaponType())
                    call SetUnitState(udg_PP_TargetUnit[Node], UNIT_STATE_MANA, GetUnitState(udg_PP_TargetUnit[Node], UNIT_STATE_MANA) - udg_PP_Real12[Node])
                else
                    call SetWidgetLife(udg_PP_TargetUnit[Node], GetWidgetLife(udg_PP_TargetUnit[Node]) + udg_PP_Real11[Node])
                    call SetUnitState(udg_PP_TargetUnit[Node], UNIT_STATE_MANA, GetUnitState(udg_PP_TargetUnit[Node], UNIT_STATE_MANA) + udg_PP_Real12[Node])
                endif
                
                //Check if the projectile activates particle stacks
                if (udg_PP_Boolean1[Node]) then
                    set TempBoolean = false
                    set TempInt2 = 0
                    set TempNode = 0
                    
                    //Check if the target unit is already part of the linked list
                    loop
                        set TempInt2 = TempInt2 + 1
                        exitwhen (TempInt2 > udg_PP_AbilityCounter) or (TempBoolean)
                        set TempNode = udg_PP_NextNode[TempNode]
                        
                        if (udg_PP_Unit[TempNode] == udg_PP_TargetUnit[Node]) then
                            //Mark the unit as found
                            set TempBoolean = true
                        endif
                        
                    endloop
                
                    //Check if the unit was found
                    if (TempBoolean) then
                    
                        //Check if this unit's particle stacks are active
                        if not(udg_PP_Boolean2[TempNode]) then
                            //Give Particle to the target's particle ring
                            call PP_AddParticleToRing(udg_PP_Unit[TempNode], TempNode, udg_PP_Integer1[Node], udg_PP_Real13[Node])
                        
                            //Check if the unit has any particle stacks
                            if (udg_PP_Integer2[TempNode] > 0) then
                                //Activate stacks
                                set udg_PP_Boolean2[TempNode] = true 
                                set udg_PP_Real6[TempNode] = 0
                                set udg_PP_Real9[TempNode] = 0
                                set udg_PP_Real10[TempNode] = 0
                                set udg_PP_Real11[TempNode] = udg_PP_Real13[Node]
                            endif
                            
                        endif
                        
                    else
                        //Set up new node data
                        set TempNode = PP_CreateNode()
                        set udg_PP_Unit[TempNode] = udg_PP_TargetUnit[Node]
                        set udg_PP_Caster[TempNode] = udg_PP_Caster[Node]
                        set udg_PP_Player[TempNode] = udg_PP_Player[Node]
                        set udg_PP_Real3[TempNode] = 0
                        set udg_PP_Real4[TempNode] = 0
                        set udg_PP_Real5[TempNode] = 0
                        set udg_PP_Real6[TempNode] = 0
                        set udg_PP_Real9[TempNode] = 0
                        set udg_PP_Real10[TempNode] = 0
                        set udg_PP_Real11[TempNode] = udg_PP_Real13[Node]
                        set udg_PP_Integer2[TempNode] = 0
                        set udg_PP_Integer3[TempNode] = 0
                        set udg_PP_StageID[TempNode] = PP_SlowedUnitStageID()
                        set udg_PP_Boolean1[TempNode] = false
                        //Give Particle to the target's particle ring
                        call PP_AddParticleToRing(udg_PP_Unit[TempNode], TempNode, udg_PP_Integer1[Node], udg_PP_Real13[Node])
                        
                        //Check if the unit has any particle stacks
                        if (udg_PP_Integer2[TempNode] > 0) then
                            set udg_PP_Boolean2[TempNode] = true 
                        else
                            set udg_PP_Boolean2[TempNode] = false
                        endif
                        
                    endif
                    
                endif
                
                //Recycle Projectile
                set udg_PP_StageID[Node] = PP_RecycleStageID()
                set udg_PP_Real1[Node] = PP_EffectDelayTimer()
            endif
        
        //Affected Enemy Units
        elseif (udg_PP_StageID[Node] == PP_SlowedUnitStageID()) then
            
            //Check if the unit is ready to be removed
            //(Slow and Stacks Inactive)
            if not(udg_PP_Boolean1[Node]) and not(udg_PP_Boolean2[Node]) then
            
                set TempInt2 = 0
                set TempNode = 0
                
                //Find and remove particle stacks
                loop
                    set TempInt2 = TempInt2 + 1
                    exitwhen (TempInt2 > udg_PP_AbilityCounter)
                    set TempNode = udg_PP_NextNode[TempNode]
                    
                    if (udg_PP_StageID[TempNode] == PP_ParticleRingStageID()) and (udg_PP_Caster[TempNode] == udg_PP_Unit[Node]) then
                        call DestroyEffect(udg_PP_CurrentEffect[TempNode])
                        call DestroyEffect(AddSpecialEffectTarget(PP_ParticleRingDestroyEffect(), udg_PP_Unit[TempNode], PP_AttachmentPoint()))
                        set udg_PP_StageID[TempNode] = PP_RecycleStageID()
                        set udg_PP_Real1[TempNode] = PP_EffectDelayTimer()
                    endif
                    
                endloop
                
                //Recycle Unit
                call PP_Recycle(Node)
                set TempInt = TempInt - 1
            else
                set TempBoolean = false
                set x = GetUnitX(udg_PP_Unit[Node])
                set y = GetUnitY(udg_PP_Unit[Node])
                
                //Enemy is slowed
                if (udg_PP_Boolean1[Node]) then
                
                    //Check if the unit is alive
                    if (IsUnitType(udg_PP_Unit[Node], UNIT_TYPE_DEAD)) then
                        //Sets up slow to be removed
                        set udg_PP_Integer1[Node] = 1
                        set udg_PP_Real1[Node] = 0
                    endif
                    
                    //Check slow timeout
                    if (udg_PP_Real1[Node] <= 0) then
                        
                        //Check if the slow is ready to be removed
                        if (udg_PP_Integer1[Node] == 1) then
                            //Remove the slow from the unit
                            call UnitRemoveAbility(udg_PP_Unit[Node], PP_BuffID())
                            call DestroyEffect(udg_PP_CurrentEffect[Node])
                            //Mark the slow as inactive for this unit
                            set udg_PP_Boolean1[Node] = false
                        else
                            //Decrease slow level by 1
                            set udg_PP_Integer1[Node] = udg_PP_Integer1[Node] - 1
                            call SetUnitAbilityLevel(udg_PP_Unit[Node], PP_BuffID(), udg_PP_Integer1[Node])
                            set udg_PP_Real1[Node] = udg_PP_Real2[Node]
                        endif
                        
                    else
                        set udg_PP_Real1[Node] = udg_PP_Real1[Node] - PP_TimerSpeed()
                    endif
                    
                endif
                
                //Particle Ring Activated
                if (udg_PP_Boolean2[Node]) then
                
                    //Check if there are any salvos left and that the unit is still alive
                    if (udg_PP_Integer3[Node] > 0) and not(IsUnitType(udg_PP_Unit[Node], UNIT_TYPE_DEAD)) then
                        
                        //Check if the salvo is ready to be fired
                        if (udg_PP_Real6[Node] <= 0) then
                            //Update tracking variables
                            set udg_PP_Real6[Node] = PP_ParticleRingFireRate()
                            set udg_PP_Integer3[Node] = udg_PP_Integer3[Node] - 1
                            set udg_PP_Real9[Node] = udg_PP_Real9[Node] + (udg_PP_Real7[Node] * R2I(udg_PP_Integer2[Node]))
                            set udg_PP_Real10[Node] = udg_PP_Real10[Node] + (udg_PP_Real8[Node] * R2I(udg_PP_Integer2[Node]))
                            //Mark the salvo as ready to fire
                            set TempBoolean = true
                            //Stun the unit again
                            set TempNode = PP_CreateNode()
                            set udg_PP_Unit[TempNode] = CreateUnit(PP_DummyPlayer(), PP_DummyID(), x, y, 0.)
                            set udg_PP_StageID[TempNode] = PP_RecycleStageID()
                            set udg_PP_Real1[TempNode] = PP_EffectDelayTimer()
                            call UnitAddAbility(udg_PP_Unit[TempNode], PP_StunID())
                            call IssueTargetOrderById(udg_PP_Unit[TempNode], PP_StunOrderID(), udg_PP_Unit[Node])
                        else
                            set udg_PP_Real6[Node] = udg_PP_Real6[Node] - PP_TimerSpeed()
                        endif
                        
                    else
                        //Final Explosion
                        set udg_PP_Boolean2[Node] = false
                        set udg_PP_Integer1[Node] = 1
                        set udg_PP_Real1[Node] = 0
                        //Set up aesthetics
                        set TempNode = PP_CreateNode()
                        set udg_PP_Unit[TempNode] = CreateUnit(PP_DummyPlayer(), PP_DummyID(), x, y, 0.)
                        call SetUnitScale(udg_PP_Unit[TempNode], PP_ParticleFinaleinalScale(), 0., 0.)
                        if UnitAddAbility(udg_PP_Unit[TempNode], 'Amrf') and UnitRemoveAbility(udg_PP_Unit[TempNode], 'Amrf') then
                        endif
                        call SetUnitFlyHeight(udg_PP_Unit[TempNode], PP_ParticleFinaleHeightOffset(), 0.)
                        call DestroyEffect(AddSpecialEffectTarget(PP_ParticleFinaleinalEffect(), udg_PP_Unit[TempNode], PP_AttachmentPoint()))
                        set udg_PP_StageID[TempNode] = PP_RecycleStageID()
                        set udg_PP_Real1[TempNode] = PP_EffectDelayTimer()

                        call GroupEnumUnitsInRange(udg_PP_TempGroup, x, y, PP_ParticleFinaleAOE(), null)
                        
                        //Damage Enemy Units
                        loop
                            set u = FirstOfGroup(udg_PP_TempGroup)
                            exitwhen u == null
                           
                            if (PP_TargetFilter(u, udg_PP_Player[Node])) then
                                call UnitDamageTarget(udg_PP_Caster[Node], u, (udg_PP_Real4[Node] * PP_ParticleFinalePercentageHealth()) + (udg_PP_Real4[Node] - udg_PP_Real9[Node]), false, false, PP_AttackType(), PP_DamageType(), PP_WeaponType())
                                call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - ((udg_PP_Real5[Node] * PP_ParticleFinalePercentageMana()) + (udg_PP_Real5[Node] - udg_PP_Real10[Node])))
                            endif
                            
                            call GroupRemoveUnit(udg_PP_TempGroup, u)
                        endloop
                        
                    endif
                    
                endif
                
                //Enemy Particle Ring
                set udg_PP_Real3[Node] = udg_PP_Real3[Node] + PP_ParticleRingSpinSpeed()
                set TempInt2 = 0
                set TempNode = 0
                set TempReal = udg_PP_Real3[Node]
                set TempReal2 = (2 * bj_PI) / I2R(udg_PP_Integer2[Node])
                
                //Find all particle stacks
                loop
                    set TempInt2 = TempInt2 + 1
                    exitwhen (TempInt2 > udg_PP_AbilityCounter)
                    set TempNode = udg_PP_NextNode[TempNode]
                    
                    if (udg_PP_StageID[TempNode] == PP_ParticleRingStageID()) and (udg_PP_Caster[TempNode] == udg_PP_Unit[Node]) then
                        //Update position
                        set TempReal = TempReal + TempReal2
                        set x2 = x + PP_ParticleRingOffset() * Cos(TempReal)
                        set y2 = y + PP_ParticleRingOffset() * Sin(TempReal)
                        call SetUnitX(udg_PP_Unit[TempNode], x2)
                        call SetUnitY(udg_PP_Unit[TempNode], y2)
                        call SetUnitFlyHeight(udg_PP_Unit[TempNode], PP_ParticleRingHeightOffset() - (PP_GetZ(x, y) - PP_GetZ(x2, y2)), 0.) 
                        call SetUnitFacing(udg_PP_Unit[TempNode], TempReal * bj_RADTODEG)
                        
                        //Check if a salvo is marked as ready
                        if (TempBoolean) then
                            //Fire projectile
                            set TempNode2 = PP_CreateNode()
                            //Set up salvo data
                            set TempReal3 = PP_GetZ(x2, y2)
                            set dy = (y2 - y)
                            set dx = (x2 - x)
                            set Angle = Atan2(dy, dx)
                            set Angle2 = bj_DEGTORAD * PP_ReleasedParticleProjectileLaunchAngle()
                            //Create Unit
                            set udg_PP_Unit[TempNode2] = CreateUnit(PP_DummyPlayer(), PP_DummyID(), x2, y2, 0.)
                            if UnitAddAbility(udg_PP_Unit[TempNode2], 'Amrf') and UnitRemoveAbility(udg_PP_Unit[TempNode2], 'Amrf') then
                            endif
                            //Set up projectile data
                            set udg_PP_Caster[TempNode2] = udg_PP_Caster[Node]
                            set udg_PP_Player[TempNode2] = udg_PP_Player[Node]
                            set udg_PP_CurrentEffect[TempNode2] = AddSpecialEffectTarget(PP_ParticleReleaseEffect(), udg_PP_Unit[TempNode2], PP_AttachmentPoint())
                            call SetUnitScale(udg_PP_Unit[TempNode2], PP_ParticleReleaseScale(), 0., 0.)
                            set udg_PP_Real1[TempNode2] = PP_ReleasedParticleProjectileAccel()
                            set udg_PP_Real2[TempNode2] = PP_ReleasedParticleProjectileSpeed() * Sin(Angle2)
                            set udg_PP_Real3[TempNode2] = PP_ReleasedParticleProjectileSpeed() * Cos(Angle) * Cos(Angle2)
                            set udg_PP_Real4[TempNode2] = PP_ReleasedParticleProjectileSpeed() * Sin(Angle) * Cos(Angle2)
                            set udg_PP_Real5[TempNode2] = PP_ReleasedParticleProjectileTurnRate()
                            set udg_PP_Real6[TempNode2] = PP_ReleasedParticleProjectileTurnEfficiency()
                            set udg_PP_Real7[TempNode2] = TempReal3 + PP_ParticleRingHeightOffset() + PP_ReleasedParticleLaunchOffset()
                            set udg_PP_Real8[TempNode2] = x2
                            set udg_PP_Real9[TempNode2] = y2
                            set udg_PP_Real10[TempNode2] = PP_ReleasedParticleProjectileAOE() * PP_ReleasedParticleProjectileAOE()
                            set udg_PP_Real11[TempNode2] = udg_PP_Real7[Node]
                            set udg_PP_Real12[TempNode2] = udg_PP_Real8[Node]
                            set udg_PP_TargetUnit[TempNode2] = udg_PP_Unit[Node]
                            set udg_PP_Real14[TempNode2] = GetUnitFlyHeight(udg_PP_Caster[TempNode]) + PP_TargetAimOffset()
                            set udg_PP_Boolean1[TempNode2] = false
                            set udg_PP_Boolean2[TempNode2] = true
                            set udg_PP_StageID[TempNode2] = PP_ReleasedParticleojectileStageID()
                            call SetUnitFlyHeight(udg_PP_Unit[TempNode2], udg_PP_Real7[TempNode2] - TempReal3, 0.)                            
                        endif
                        
                    endif
                    
                endloop
                
            endif
            
        //Recycling
        elseif (udg_PP_StageID[Node] == PP_RecycleStageID()) then
        
            //Check if the unit is ready to be recycled
            if (udg_PP_Real1[Node] <= 0) then
                //Remove and Recycle Unit
                call RemoveUnit(udg_PP_Unit[Node])
                call PP_Recycle(Node)
                set TempInt = TempInt - 1
            else
                set udg_PP_Real1[Node] = udg_PP_Real1[Node] - PP_TimerSpeed()
            endif
        
        //Pickups
        elseif (udg_PP_StageID[Node] == PP_PickupStageID()) then
        
            //Check if the pickup is on the ground
            if (udg_PP_Boolean1[Node]) then
            
                //Move pickup
                if (PP_Move(Node)) then
                    //Mark it as on the ground
                    set udg_PP_Boolean1[Node] = false
                    //Set up data for the grounded pickup
                    set udg_PP_Real1[Node] = PP_ParticleProjectileAccelBase() + (PP_ParticleProjectileAccelPerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real2[Node] = PP_ParticleProjectileSpeedBase() + (PP_ParticleProjectileSpeedPerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real3[Node] = PP_PickupAOEBase() + (PP_PickupAOEPerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real4[Node] = PP_PickupDurationBase() + (PP_PickupDurationPerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real5[Node] = PP_ParticleProjectileTurnRateBase() + (PP_ParticleProjectileTurnRatePerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real6[Node] = PP_ParticleProjectileTurnEfficiencyBase() + (PP_ParticleProjectileTurnEfficiencyPerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real7[Node] = udg_PP_Real7[Node] + PP_ParticleProjectileLaunchHeightOffset()
                
                    if (udg_PP_Boolean2[Node]) then
                        set udg_PP_Real8[Node] = PP_DamagingPickupDamageHealthBase() + (PP_DamagingPickupDamageHealthPerLevel() * udg_PP_Real10[Node])
                        set udg_PP_Real9[Node] = PP_DamagingPickupDamageManaBase() + (PP_DamagingPickupDamageManaPerLevel() * udg_PP_Real10[Node])
                    else
                        set udg_PP_Real8[Node] = PP_HealingPickupHealHealthBase() + (PP_HealingPickupHealHealthPerLevel() * udg_PP_Real10[Node])
                        set udg_PP_Real9[Node] = PP_HealingPickupHealManaBase() + (PP_HealingPickupHealManaPerLevel() * udg_PP_Real10[Node])
                    endif
                    
                    set udg_PP_Real11[Node] = PP_PickupPercentageMainBase() + (PP_PickupPercentageMainPerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real12[Node] = PP_PickupDurationBase() + (PP_PickupDurationPerLevel() * udg_PP_Real10[Node])
                    set udg_PP_Real13[Node] = PP_PickupDecayRateBase() + (PP_PickupDecayRatePerLevel() * udg_PP_Real10[Node])
                endif
            
            else
                //Lower potency of pickup
                set udg_PP_Real8[Node] = udg_PP_Real8[Node] * udg_PP_Real13[Node]
                set udg_PP_Real9[Node] = udg_PP_Real9[Node] * udg_PP_Real13[Node]
                set udg_PP_Real12[Node] = udg_PP_Real12[Node] - PP_TimerSpeed()
                
                //Check if the projectile is still alive
                if (udg_PP_Real12[Node] > 0) then
                    //Look for enemy units
                    set x = GetUnitX(udg_PP_Unit[Node])
                    set y = GetUnitY(udg_PP_Unit[Node])
                    set TempBoolean = true
                    call GroupEnumUnitsInRange(udg_PP_TempGroup, x, y, udg_PP_Real3[Node], null)
                   
                    //Damage Enemy Units
                    loop
                        set u = FirstOfGroup(udg_PP_TempGroup)
                        exitwhen u == null
                       
                        if (PP_TargetFilter(u, udg_PP_Player[Node])) and (TempBoolean) then
                            //Limit the amount of units damaged to 1
                            set TempBoolean = false
                            //Get the damage which belongs to the explosion and projectiles
                            set udg_PP_Real12[Node] = udg_PP_Real8[Node] * udg_PP_Real11[Node]
                            set udg_PP_Real11[Node] = udg_PP_Real9[Node] * udg_PP_Real11[Node]
                            set udg_PP_Real8[Node] = (udg_PP_Real8[Node] - udg_PP_Real12[Node]) / udg_PP_Integer1[Node]
                            set udg_PP_Real9[Node] = (udg_PP_Real9[Node] - udg_PP_Real11[Node]) / udg_PP_Integer1[Node]
                            
                            //Blow up the pickup
                            call DestroyEffect(AddSpecialEffectTarget(PP_PickupDetonateEffect(), u, PP_AttachmentPoint()))
                            call DestroyEffect(udg_PP_CurrentEffect[Node])
                            
                            set TempInt2 = 0
                            set TempBoolean2 = false
                            set TempNode = 0
                            
                            //Check if the target already belongs to the linked list
                            loop
                                set TempInt2 = TempInt2 + 1
                                exitwhen (TempInt2 > udg_PP_AbilityCounter) or (TempBoolean2 == true)
                                set TempNode = udg_PP_NextNode[TempNode]
                                
                                if (udg_PP_Unit[TempNode] == u) then
                                    //Mark the unit as found
                                    set TempBoolean2 = true
                                endif
                                    
                            endloop
                            
                            //Check if the unit was found
                            if (TempBoolean2) then
                                
                                //Check if the slow is active on this unit
                                if (UnitAddAbility(udg_PP_Unit[TempNode], PP_BuffID())) then
                                    //Set up slow
                                    call SetUnitAbilityLevel(udg_PP_Unit[TempNode], PP_BuffID(), udg_PP_Integer3[Node])
                                    set udg_PP_Real1[TempNode] = PP_SlowTimeoutBase() + (PP_SlowTimeoutPerLevel() * udg_PP_Real10[Node])
                                    set udg_PP_Real2[TempNode] = udg_PP_Real1[TempNode]
                                    set udg_PP_Real3[TempNode] = 0
                                    set udg_PP_Integer1[TempNode] = udg_PP_Integer3[Node]
                                    //Mark the slow as active
                                    set udg_PP_Boolean1[TempNode] = true
                                    set udg_PP_CurrentEffect[TempNode] = AddSpecialEffectTarget(PP_SlowEffect(), udg_PP_Unit[TempNode], PP_AttachmentPoint())
                                else
                                    //Modify the slow as appropriate (increase or decrease level)
                                    set udg_PP_Real1[TempNode] = udg_PP_Real2[TempNode]
                                    
                                    if (udg_PP_Integer1[TempNode] + udg_PP_Integer4[Node] <= 0) then
                                        set udg_PP_Integer1[TempNode] = 1
                                        call SetUnitAbilityLevel(udg_PP_Unit[TempNode], PP_BuffID(), udg_PP_Integer1[TempNode])
                                    else
                                        set udg_PP_Integer1[TempNode] = udg_PP_Integer1[TempNode] + udg_PP_Integer4[Node]
                                        call SetUnitAbilityLevel(udg_PP_Unit[TempNode], PP_BuffID(), udg_PP_Integer1[TempNode])
                                    endif       
                                
                                endif
                                
                            else
                                //Set up new node and the slow
                                set TempNode = PP_CreateNode()
                                set udg_PP_Unit[TempNode] = u
                                call UnitAddAbility(udg_PP_Unit[TempNode], PP_BuffID())
                                call SetUnitAbilityLevel(udg_PP_Unit[TempNode], PP_BuffID(), udg_PP_Integer3[Node])
                                set udg_PP_Caster[TempNode] = udg_PP_Caster[Node]
                                set udg_PP_Player[TempNode] = udg_PP_Player[Node]
                                set udg_PP_Real1[TempNode] = PP_SlowTimeoutBase() + (PP_SlowTimeoutPerLevel() * udg_PP_Real10[Node])
                                set udg_PP_Real2[TempNode] = udg_PP_Real1[TempNode]
                                set udg_PP_Real3[TempNode] = 0
                                set udg_PP_Real4[TempNode] = 0
                                set udg_PP_Real5[TempNode] = 0
                                set udg_PP_Real9[TempNode] = 0
                                set udg_PP_Real10[TempNode] = 0
                                set udg_PP_Integer1[TempNode] = udg_PP_Integer3[Node]
                                set udg_PP_Integer2[TempNode] = 0
                                set udg_PP_Integer3[TempNode] = 0
                                set udg_PP_StageID[TempNode] = PP_SlowedUnitStageID()
                                //Mark the slow as active
                                set udg_PP_Boolean1[TempNode] = true
                                set udg_PP_Boolean2[TempNode] = false
                                set udg_PP_CurrentEffect[TempNode] = AddSpecialEffectTarget(PP_SlowEffect(), udg_PP_Unit[TempNode], PP_AttachmentPoint())
                            endif
                            
                            //Damage the target unit
                            if (udg_PP_Boolean2[Node]) then
                                call UnitDamageTarget(udg_PP_Caster[Node], u, udg_PP_Real12[Node], false, false, PP_AttackType(), PP_DamageType(), PP_WeaponType())
                                call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - udg_PP_Real11[Node])
                            else
                                call SetWidgetLife(u, GetWidgetLife(u) + udg_PP_Real12[Node])
                                call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) + udg_PP_Real11[Node])
                            endif
                            
                            //Give Particle to the target's particle ring
                            call PP_AddParticleToRing(u, TempNode, udg_PP_Integer2[Node], udg_PP_Real10[Node])
                            
                            //Set up projectile data
                            set TempReal = PP_ParticleProjectileSpeedBase() + (PP_ParticleProjectileSpeedPerLevel() * udg_PP_Real10[Node])
                            set TempReal3 = PP_ParticleProjectileAOEBase() + (PP_ParticleProjectileAOEPerLevel() * udg_PP_Real10[Node])
                            set Angle2 = bj_DEGTORAD * (PP_ParticleProjectileLaunchAngleBase() + (PP_ParticleProjectileLaunchAnglePerLevel() * udg_PP_Real10[Node]))
                            set udg_PP_Real10[Node] = PP_ParticleProjectileScaleBase() + (PP_ParticleProjectileScalePerLevel() * udg_PP_Real10[Node])
                            set TempInt2 = 0
                            set Angle = 0
                            set TempReal2 = (360 / udg_PP_Integer1[Node]) * bj_DEGTORAD
                            
                            //Create projectiles
                            loop
                                set TempInt2 = TempInt2 + 1
                                exitwhen (TempInt2 > udg_PP_Integer1[Node])
                                
                                set Angle = Angle + TempReal2
                                set TempNode = PP_CreateNode()
                                //Apply projectile data
                                set udg_PP_Boolean1[TempNode] = false
                                set udg_PP_Boolean2[TempNode] = udg_PP_Boolean2[Node]
                                set udg_PP_Real1[TempNode] = udg_PP_Real1[Node]
                                set udg_PP_Real2[TempNode] = TempReal * Sin(Angle2)
                                set udg_PP_Real3[TempNode] = TempReal * Cos(Angle) * Cos(Angle2)
                                set udg_PP_Real4[TempNode] = TempReal * Sin(Angle) * Cos(Angle2)
                                set udg_PP_Real5[TempNode] = udg_PP_Real5[Node]
                                set udg_PP_Real6[TempNode] = udg_PP_Real6[Node]
                                set udg_PP_Real7[TempNode] = udg_PP_Real7[Node]
                                set udg_PP_TargetUnit[TempNode] = u
                                set udg_PP_Real8[TempNode] = GetUnitX(u)
                                set udg_PP_Real9[TempNode] = GetUnitY(u)
                                set udg_PP_Real10[TempNode] = TempReal3 * TempReal3
                                set udg_PP_Real11[TempNode] = udg_PP_Real8[Node]
                                set udg_PP_Real12[TempNode] = udg_PP_Real9[Node]
                                set udg_PP_Real14[TempNode] = GetUnitFlyHeight(udg_PP_TargetUnit[TempNode]) + PP_TargetAimOffset()
                                set udg_PP_StageID[TempNode] = PP_ReleasedParticleojectileStageID()
                                set udg_PP_Integer1[TempNode] = 0
                                
                                //Create unit
                                set udg_PP_Unit[TempNode] = CreateUnit(PP_DummyPlayer(), PP_DummyID(), x + PP_ParticleProjectileLaunchDistOffset() * Cos(Angle), y + PP_ParticleProjectileLaunchDistOffset() * Sin(Angle), bj_RADTODEG * Atan2(udg_PP_Real4[TempNode], udg_PP_Real3[TempNode]))
                                set udg_PP_Caster[TempNode] = udg_PP_Caster[Node]
                                set udg_PP_Player[TempNode] = udg_PP_Player[Node]
                                if UnitAddAbility(udg_PP_Unit[TempNode], 'Amrf') and UnitRemoveAbility(udg_PP_Unit[TempNode], 'Amrf') then
                                endif
                                call SetUnitScale(udg_PP_Unit[TempNode], udg_PP_Real10[Node], 0., 0.)
                                
                                //Put on the right effect for its type
                                if (udg_PP_Boolean2[Node]) then
                                    set udg_PP_CurrentEffect[TempNode] = AddSpecialEffectTarget(PP_DamagingPickupProjectileEffect(), udg_PP_Unit[TempNode], PP_AttachmentPoint())
                                else
                                    set udg_PP_CurrentEffect[TempNode] = AddSpecialEffectTarget(PP_HealingPickupProjectileEffect(), udg_PP_Unit[TempNode], PP_AttachmentPoint())
                                endif
                                
                            endloop
                            
                            //Recycle Pickup
                            set udg_PP_StageID[Node] = PP_RecycleStageID()
                            set udg_PP_Real1[Node] = PP_EffectDelayTimer()
                        endif
                       
                        call GroupRemoveUnit(udg_PP_TempGroup, u)
                    endloop
                
                else
                    //Recycle Pickup
                    call DestroyEffect(udg_PP_CurrentEffect[Node])
                    set udg_PP_Real1[Node] = PP_EffectDelayTimer()
                    set udg_PP_StageID[Node] = PP_RecycleStageID()
                endif
                    
            endif
            
        endif
        
    endloop
    
endfunction

////////////////////////////////////////////////////////////////////
//  Function used to check that the ability being cast by a hero  //
//  is the right ability and check what the target is in order    //
//  to play the correct part of the ability                       //
////////////////////////////////////////////////////////////////////
function PP_OnCast takes nothing returns boolean
    //Set up locals
    local integer SpellID = GetSpellAbilityId()
    local integer Node
    local integer iLevel
    local unit Target = GetSpellTargetUnit()
    local unit u
    local unit u2
    local real x
    local real y
    local real x2
    local real y2
    local real dy
    local real dx
    local real rLevel
    local real Angle
    local real Angle2
    local real TempReal
    local boolean TempBoolean
    
    //Check that the right spell was cast
    if (SpellID == PP_AbilityID()) then
        //Set up spell data
        set u = GetTriggerUnit()
        set x = GetUnitX(u)
        set y = GetUnitY(u)
        set iLevel = GetUnitAbilityLevel(u, PP_AbilityID())
        set rLevel = I2R(iLevel)
        set Node = PP_CreateNode()
        //Create Unit
        set udg_PP_Unit[Node] = CreateUnit(PP_DummyPlayer(), PP_DummyID(), x, y, 0.)
        set udg_PP_Caster[Node] = u
        set udg_PP_Player[Node] = GetOwningPlayer(u)
        if UnitAddAbility(udg_PP_Unit[Node], 'Amrf') and UnitRemoveAbility(udg_PP_Unit[Node], 'Amrf') then
        endif
            
        //Check what part of the spell to use
        if (Target == null) then
            //Energy Pickup Type
            set x2 = GetSpellTargetX()
            set y2 = GetSpellTargetY()
            set dy = (y2 - y)
            set dx = (x2 - x)
            set Angle = Atan2(dy, dx)
            set Angle2 = bj_DEGTORAD * (PP_PickupProjectileLaunchAngleBase() + (PP_PickupProjectileLaunchAnglePerLevel() * rLevel))
            //Apply effects
            set udg_PP_CurrentEffect[Node] = AddSpecialEffectTarget(PP_PickupEffect(), udg_PP_Unit[Node], PP_AttachmentPoint())
            call SetUnitScale(udg_PP_Unit[Node], PP_PickupScaleBase() + (PP_PickupScalePerLevel() * rLevel), 0., 0.)
            set TempReal = PP_PickupProjectileSpeedBase() + (PP_PickupProjectileSpeedPerLevel() * rLevel)
            //Set up pickup projectile data
            set udg_PP_StageID[Node] = PP_PickupStageID()
            set udg_PP_Boolean1[Node] = true
            set udg_PP_Real1[Node] = PP_PickupProjectileAccelBase() + (PP_PickupProjectileAccelPerLevel() * rLevel)
            set udg_PP_Real2[Node] = TempReal * Sin(Angle2)
            set udg_PP_Real3[Node] = TempReal * Cos(Angle) * Cos(Angle2)
            set udg_PP_Real4[Node] = TempReal * Sin(Angle) * Cos(Angle2)
            set udg_PP_Real5[Node] = PP_PickupProjectileTurnRateBase() + (PP_PickupProjectileTurnRatePerLevel() * rLevel)
            set udg_PP_Real6[Node] = PP_PickupProjectileTurnEfficiencyBase() + (PP_PickupProjectileTurnEfficiencyPerLevel() * rLevel)
            set udg_PP_Real7[Node] = PP_GetZ(x, y) + GetUnitFlyHeight(u) + PP_PickupProjectileLaunchOffset()
            set udg_PP_Real8[Node] = x2
            set udg_PP_Real9[Node] = y2
            set udg_PP_Real10[Node] = rLevel
            set udg_PP_Real14[Node] = 0.
            set udg_PP_Integer1[Node] = PP_ParticleProjectileCountBase() + (PP_ParticleProjectileCountPerLevel() * iLevel)
            
            //Find units near the target zone
            call GroupEnumUnitsInRange(udg_PP_TempGroup, x2, y2, PP_PickupTypeDistBase() + (PP_PickupTypeDistPerLevel() * rLevel), null)
            set TempBoolean = false
            
            //Check if there are any units
            loop
                set u2 = FirstOfGroup(udg_PP_TempGroup)
                exitwhen (u2 == null)
                
                if (PP_TargetFilter(u2, udg_PP_Player[Node])) then
                    //Mark that a unit was found
                    set TempBoolean = true
                endif
                
                call GroupRemoveUnit(udg_PP_TempGroup, u2)
            endloop
            
            //Check if a unit was found as well as
            //Check which way around the player wants
            //(Damaging and then Heal or Heal and then Damaging)
            if (TempBoolean) then
                set udg_PP_Boolean2[Node] = PP_DThenH()
            else
                set udg_PP_Boolean2[Node] = not(PP_DThenH())
            endif
            
            //Apply appropriate data for damaging or healing pickups
            if (udg_PP_Boolean2[Node]) then
                set udg_PP_Integer2[Node] = PP_DamagingPickupParticleRingCountBase() + (PP_DamagingPickupParticleRingCountPerLevel() * iLevel)
                set udg_PP_Integer3[Node] = PP_DamagingPickupStartLevelBase() + (PP_DamagingPickupStartLevelPerLevel() * iLevel)
                set udg_PP_Integer4[Node] = PP_DamagingPickupLevelModifierBase() + (PP_DamagingPickupLevelModifierPerLevel() * iLevel)
            else
                set udg_PP_Integer2[Node] = PP_HealingPickupParticleRingCountBase() + (PP_HealingPickupParticleRingCountPerLevel() * iLevel)
                set udg_PP_Integer3[Node] = PP_HealingPickupStartLevelBase() + (PP_HealingPickupStartLevelPerLevel() * iLevel)
                set udg_PP_Integer4[Node] = PP_HealingPickupLevelModifierBase() + (PP_HealingPickupLevelModifierPerLevel() * iLevel)
            endif
            
            set udg_PP_TargetUnit[Node] = Target
            call SetUnitFlyHeight(udg_PP_Unit[Node], udg_PP_Real7[Node] - PP_GetZ(x, y), 0.)
            
        else
            //Particle Ring Activator Type
            set x2 = GetUnitX(Target)
            set y2 = GetUnitY(Target)
            set dy = (y2 - y)
            set dx = (x2 - x)
            set Angle = Atan2(dy, dx)
            set Angle2 = bj_DEGTORAD * (PP_ParticleLaunchAngleBase() + (PP_ParticleLaunchAnglePerLevel() * rLevel))
            //Apply effects
            set udg_PP_CurrentEffect[Node] = AddSpecialEffectTarget(PP_ParticleEffect(), udg_PP_Unit[Node], PP_AttachmentPoint())
            call SetUnitScale(udg_PP_Unit[Node], PP_ParticleScaleBase() + (PP_ParticleScalePerLevel() * rLevel), 0., 0.)
            set TempReal = PP_ParticleSpeedBase() + (PP_ParticleSpeedPerLevel() * rLevel)
            //Set up particle data
            set udg_PP_Real1[Node] = PP_ParticleAccelBase() + (PP_ParticleAccelPerLevel() * rLevel)
            set udg_PP_Real2[Node] = TempReal * Sin(Angle2)
            set udg_PP_Real3[Node] = TempReal * Cos(Angle) * Cos(Angle2)
            set udg_PP_Real4[Node] = TempReal * Sin(Angle) * Cos(Angle2)
            set udg_PP_Real5[Node] = PP_ParticleTurnRateBase() + (PP_ParticleTurnRatePerLevel() * rLevel)
            set udg_PP_Real6[Node] = PP_ParticleTurnEfficiencyBase() + (PP_ParticleTurnEfficiencyPerLevel() * rLevel)
            set udg_PP_Real7[Node] = PP_GetZ(x, y) + GetUnitFlyHeight(u) + PP_ParticleLaunchOffset()
            set udg_PP_Real8[Node] = x2
            set udg_PP_Real9[Node] = y2
            set TempReal = PP_ParticleAOEBase() + (PP_ParticleAOEPerLevel() * rLevel)
            set udg_PP_Real10[Node] = TempReal * TempReal
            set udg_PP_Real11[Node] = PP_ParticleHealthDamageBase() + (PP_ParticleHealthDamagePerLevel() * rLevel)
            set udg_PP_Real12[Node] = PP_ParticleManaDamageBase() + (PP_ParticleManaDamagePerLevel() * rLevel)
            set udg_PP_Integer1[Node] = PP_ParticleParticleRingCountBase() + (PP_ParticleParticleRingCountPerLevel() * iLevel)
            set udg_PP_Real13[Node] = rLevel
            set udg_PP_TargetUnit[Node] = Target
            set udg_PP_Real14[Node] = GetUnitFlyHeight(udg_PP_TargetUnit[Node]) + PP_TargetAimOffset()
            //Mark as an activator particle and as a damaging particle
            set udg_PP_Boolean1[Node] = true
            set udg_PP_Boolean2[Node] = true
            set udg_PP_StageID[Node] = PP_ReleasedParticleojectileStageID()
            call SetUnitFlyHeight(udg_PP_Unit[Node], udg_PP_Real7[Node] - PP_GetZ(x, y), 0.)
        endif
        
        //Make them face the right way
        call  SetUnitFacing(udg_PP_Unit[Node], bj_RADTODEG * Atan2(udg_PP_Real4[Node], udg_PP_Real3[Node]))

        //Check if this is the first instance and start the timer
        if (udg_PP_AbilityCounter == 1) then
            call TimerStart(udg_PP_Timer, PP_TimerSpeed(), true, function PP_Loop)
        endif
        
    endif
    
    return false
endfunction

////////////////////////////////////////////////////////////////////
//  Initialisation trigger, applies the conditions to triggers    //
//  and sets up the global location used to get location Z's      //
//  as well as the map bounds                                     //
////////////////////////////////////////////////////////////////////
function InitTrig_Punishing_Particles takes nothing returns nothing
    //Set up locals
    local trigger PP = CreateTrigger()
    local integer index = 0

    //Set up hero casting triggers
    loop
        //Applies the even to each player in turn
        call TriggerRegisterPlayerUnitEvent(PP, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop

    //Applies the function to check for each spell to the trigger
    call TriggerAddCondition(PP, Condition(function PP_OnCast))

    //Set up the location used to find Z heights
    set udg_PP_Loc = Location(0,0)
    //Set up the Timer used to run the loop
    set udg_PP_Timer = CreateTimer()

    //Sets up the variables used to make sure a point is within the map area
    set udg_PP_MapMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
    set udg_PP_MapMinX = GetRectMinX(bj_mapInitialPlayableArea)
    set udg_PP_MapMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
    set udg_PP_MapMinY = GetRectMinY(bj_mapInitialPlayableArea)
endfunction
////////////////////////////////////////////////////////////////////
// End of the spell                                               //
////////////////////////////////////////////////////////////////////

Spellset Information

- 1836 lines of pure JASS
- 143 Configurables reaching all aspects of the ability
- 1 ability 2 parts, compact and powerful
- Extensive Readme to help you configure the ability
- Doesn't interfere with game scorescreen
- Compatiable with Vanilla WE
- Functions for ground and flying heros
- Arcs are stable on uneven terrain
- Features can be adapted to your liking due to the configuration including complete removal
- Attractive yet functional
- All levels are set to look identical with default configuration for extra deception
- Particle Types are decided upon launch rather than upon landing, allowing you to continue to deceive enemies who understand the ability
- Combines Deception with Skill and Tactics
- Useful outside of Deception as a skilshot
- Easy to reach target filtering
- Two parts can be easily seperated into two different abilities
- Ignores magic immune enemies correctly
- You can potentially infinitely stack Energy Stacks (though there'd never be a reason to do this and most would die before you can get to a number particularly high)
- Designed to efficiently use each variable, reusing them as much as possible
- Variable reuse reduces the amount of variables to import to 40
- Buffs for all status conditions
- Try switching the particle model to something more inviting like a treasure chest if players refuse to pick up particles to make it more deceptive (the arc may need to be modified to make this work effectively)
- Comes with omnipresent Mr. Fluffy and his entourage of Tanks
Tips and Tricks


- You can use the ability as a skillshot or to play a mindgame with your opponent dependent on your playstyle
- Make sure your opponent is aware that the ability can heal them - throw out a lot of healing particles while they have recieved negligible damage before mixing in damaging ones
- If your opponent is too hard for you to skillshot, start out by using a healing particle to slow them down before switching to damaging ones - be sure to hit them plenty of times though otherwise the investment will be in vain and be weary of the mana you are consuming, use this method sparingly
- Block off retreat paths with damaging particles, the slow and extra damage will allow you to punish them particularly hard if you catch them out
- A portion of the total damage of the projectile is dealt immediately on pickup the remaining damage stored in the smaller particles can be dodged: low health enemies may be forced to wastefully use their escape to dodge this damage
- Use the targeting marker to identify what kind of particle you are firing - if the circle overlaps with the centre of the unit then the particle will be damaging (A unit going green does not necessarily mean the projectile will be damaging)
- With a modified target filter the ability can also be used as a strong heal for allies while retaining offensive uses (but be careful if you do this since you may damage them and they will be slowed)


- Utilise this part to create fatal punishes on your opponents while they remain stunned
- Enemies are stunned longer and take more damage the more energy stacks you have built up on them, use this in sync with part 1 to quickly turn around a fight
- at level 3, 1 healing particle 1 damaging particle and part 2 will deal more damage than a fully charged healing particle (cancelling out the first part) use this to lure out low health enemies or fix mistakes you have made if you have the mana to spare
- This does nothing at all if the enemy has not yet got any energy stacks on them so be careful not to misclick when sending out particles - it will still cost you mana
- If you kill an enemy during the second part, all remaining damage that would've been released onto them is added on to the area damage, use it to finish off low health enemies for maximum benefit
- The projectile can miss: wait for a direct line of sight before using it and if possible do so when the enemy cannot use an escape to dodge
- Heavily stacked enemies can be easily scared away from a fight if they know you can stun lock them the moment they overextend allowing you to put heavy pressure on the player


- If you have an escape it may be worth picking up a healing particle and quickly following it up with the escape in order to avoid taking skillshot hits from the ability
- While the part 2 projectile is very fast it can be dodged via making it hit into walls or the ground (if there is uneven terrain) when holding a lot of stacks try to avoid giving them a direct line of sight or if your reactions are very fast and you have a blink-type ability, blink over the projectile - if it's near a wall the particle turning may result in it missing
- If your opponent is bad with landing skillshots and you are in good shape there's little need to pickup the particles, be careful about getting too greedy
- Positioning is everything, getting into a bad spot where your retreat path can be blocked off/made awkward by a particle can result in an easily given death

Helpful Files

- Variable Creator: Copy and paste into your map, you now have all the variables needed for the spell to run
  • Variable Creator
    • Events
    • Conditions
    • Actions
      • Set PP_AbilityCounter = 0
      • Set PP_Boolean1[0] = False
      • Set PP_Boolean2[0] = False
      • Set PP_Caster[0] = PP_Caster[0]
      • Set PP_CurrentEffect[0] = PP_CurrentEffect[0]
      • Set PP_Integer1[0] = 0
      • Set PP_Integer2[0] = 0
      • Set PP_Integer3[0] = 0
      • Set PP_Integer4[0] = 0
      • Set PP_LastNode = 0
      • Set PP_Loc = PP_Loc
      • Set PP_MapMaxX = 0.00
      • Set PP_MapMaxY = 0.00
      • Set PP_MapMinX = 0.00
      • Set PP_MapMinY = 0.00
      • Set PP_NextNode[0] = 0
      • Set PP_NodeNumber = 0
      • Set PP_Player[0] = PP_Player[0]
      • Set PP_PrevNode[0] = 0
      • Set PP_Real1[0] = 0.00
      • Set PP_Real2[0] = 0.00
      • Set PP_Real3[0] = 0.00
      • Set PP_Real4[0] = 0.00
      • Set PP_Real5[0] = 0.00
      • Set PP_Real6[0] = 0.00
      • Set PP_Real7[0] = 0.00
      • Set PP_Real8[0] = 0.00
      • Set PP_Real9[0] = 0.00
      • Set PP_Real10[0] = 0.00
      • Set PP_Real11[0] = 0.00
      • Set PP_Real12[0] = 0.00
      • Set PP_Real13[0] = 0.00
      • Set PP_Real14[0] = 0.00
      • Set PP_RecyclableNodes = 0
      • Set PP_RecycleNodes[0] = 0
      • Set PP_StageID[0] = 0
      • Set PP_TargetUnit[0] = PP_TargetUnit[0]
      • Set PP_TempGroup = PP_TempGroup
      • Set PP_Timer = PP_Timer
      • Set PP_Unit[0] = PP_Unit[0]

Images

Tooltip

Part 1

Part 2

GIFs

attachment.php

Healing Particle

Damaging Particle

Thin Line

attachment.php

attachment.php
attachment.php

attachment.php
attachment.php

Energy Release

Finale

Adding Extra

Overload

Adding Extra (cleaner)

attachment.php
attachment.php
attachment.php
attachment.php
attachment.php

Normal

Dying Early

Piling On

Damaging Particle

Healing Particle

attachment.php
attachment.php
attachment.php
attachment.php
attachment.php


[tr]
 

Attachments

  • Zephyr Contest #13 Screenshot 1.1.png
    Zephyr Contest #13 Screenshot 1.1.png
    79.1 KB · Views: 2,251
  • Zephyr Contest #13 Screenshot 1.2.png
    Zephyr Contest #13 Screenshot 1.2.png
    193.2 KB · Views: 2,317
  • Zephyr Contest #13 Screenshot 2.1.png
    Zephyr Contest #13 Screenshot 2.1.png
    77 KB · Views: 2,270
  • Zephyr Contest #13 Screenshot 2.2.png
    Zephyr Contest #13 Screenshot 2.2.png
    224.5 KB · Views: 2,254
  • Zephyr Contest #13 Screenshot 3.png
    Zephyr Contest #13 Screenshot 3.png
    211.9 KB · Views: 2,261
  • Zephyr Contest #13 Screenshot 6.png
    Zephyr Contest #13 Screenshot 6.png
    216 KB · Views: 2,180
  • Zephyr Contest #13 Screenshot 5.png
    Zephyr Contest #13 Screenshot 5.png
    213.7 KB · Views: 2,213
  • Zephyr Contest #13 Screenshot 4.png
    Zephyr Contest #13 Screenshot 4.png
    203.4 KB · Views: 2,206
  • Zephyr Contest #13 Screenshot 7.png
    Zephyr Contest #13 Screenshot 7.png
    209.3 KB · Views: 2,139
  • Zephyr Contest #13 Screenshot 8.png
    Zephyr Contest #13 Screenshot 8.png
    173.3 KB · Views: 2,159
  • Zephyr Contest #13 GIF 1.gif
    Zephyr Contest #13 GIF 1.gif
    5.5 MB · Views: 695
  • Zephyr Contest #13 GIF 2.gif
    Zephyr Contest #13 GIF 2.gif
    4.5 MB · Views: 2,258
  • Zephyr Contest #13 GIF 3.gif
    Zephyr Contest #13 GIF 3.gif
    5.9 MB · Views: 2,335
  • Zephyr Contest #13 GIF 4.gif
    Zephyr Contest #13 GIF 4.gif
    5.8 MB · Views: 2,246
  • Zephyr Contest #13 GIF 5.gif
    Zephyr Contest #13 GIF 5.gif
    4.2 MB · Views: 578
  • Zephyr Contest #13 Tooltip.png
    Zephyr Contest #13 Tooltip.png
    80.8 KB · Views: 2,157
  • Tank-Commander - PP.w3x
    120.8 KB · Views: 61
Last edited:
Status
Not open for further replies.
Top