////////////////////////////////////////////////////////////////////
// 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 //
// - (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
//----------------------------------------------------------------//
// 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 "Abilities\\Weapons\\FaerieDragonMissile\\FaerieDragonMissile.mdl"
endfunction
//----------------------------------------------------------------//
constant function PP_ParticleScaleBase takes nothing returns real
return 1.5
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 75.
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
//----------------------------------------------------------------//
// 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])
call KillUnit(udg_PP_Unit[Node])
call PP_Recycle(Node)
//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
call KillUnit(udg_PP_Unit[Node])
call PP_Recycle(Node)
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()))
call KillUnit(udg_PP_Unit[TempNode])
call PP_Recycle(TempNode)
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.)
call UnitAddAbility(udg_PP_Unit[TempNode], PP_StunID())
call IssueTargetOrderById(udg_PP_Unit[TempNode], PP_StunOrderID(), udg_PP_Unit[Node])
call KillUnit(udg_PP_Unit[TempNode])
call PP_Recycle(TempNode)
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()))
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
call KillUnit(udg_PP_Unit[TempNode])
call PP_Recycle(TempNode)
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
//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
call KillUnit(udg_PP_Unit[Node])
call PP_Recycle(Node)
endif
call GroupRemoveUnit(udg_PP_TempGroup, u)
endloop
else
//Recycle Pickup
call DestroyEffect(udg_PP_CurrentEffect[Node])
call KillUnit(udg_PP_Unit[Node])
call PP_Recycle(Node)
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.)
set Target = null
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()
//Set up hero casting triggers
call TriggerRegisterAnyUnitEventBJ(PP, EVENT_PLAYER_UNIT_SPELL_EFFECT)
//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 //
////////////////////////////////////////////////////////////////////