-
Are you planning to upload your awesome spell or system to Hive? Please review the rules here.Dismiss Notice
-
Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.Dismiss Notice
-
DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.Dismiss Notice
-
The Lich King demands your service! We've reached the 19th edition of the Icon Contest. Come along and make some chilling servants for the one true king.Dismiss Notice
-
The 4th SFX Contest has started. Be sure to participate and have a fun factor in it.Dismiss Notice
-
The poll for the 21st Terraining Contest is LIVE. Be sure to check out the entries and vote for one.Dismiss Notice
-
The results are out! Check them out.Dismiss Notice
-
Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!Dismiss Notice
-
The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!Dismiss Notice
-
Check out the Staff job openings thread.Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.
Trigger Viewer



































Enter map-specific custom script code below. This text will be included in the map script after variables are declared and before any trigger code.
//TESH.scrollpos=0 //TESH.alwaysfold=0
Name | Type | Is Array | Initial Value |
//TESH.scrollpos=0
//TESH.alwaysfold=0
library_once TimerUtils initializer init
//*********************************************************************
//* TimerUtils (Blue flavor for 1.23b or later)
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3campaigns.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Blue Flavor: Slower than the red flavor, it got a 408000 handle id
//* limit, which means that if more than 408000 handle ids
//* are used in your map, TimerUtils might fail, this
//* value is quite big and it is much bigger than the
//* timer limit in Red flavor.
//*
//********************************************************************
//==================================================================================================
globals
private hashtable hasht //I <3 blizz
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
call SaveInteger(hasht,0, GetHandleId(t), value)
endfunction
function GetTimerData takes timer t returns integer
return LoadInteger(hasht, 0, GetHandleId(t))
endfunction
//==========================================================================================
globals
private timer array tT
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
if (tN==0) then
set tT[0]=CreateTimer()
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==8191) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
set hasht = InitHashtable()
endfunction
endlibrary
//TESH.alwaysfold=0
library_once TimerUtils initializer init
//*********************************************************************
//* TimerUtils (Blue flavor for 1.23b or later)
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3campaigns.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Blue Flavor: Slower than the red flavor, it got a 408000 handle id
//* limit, which means that if more than 408000 handle ids
//* are used in your map, TimerUtils might fail, this
//* value is quite big and it is much bigger than the
//* timer limit in Red flavor.
//*
//********************************************************************
//==================================================================================================
globals
private hashtable hasht //I <3 blizz
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
call SaveInteger(hasht,0, GetHandleId(t), value)
endfunction
function GetTimerData takes timer t returns integer
return LoadInteger(hasht, 0, GetHandleId(t))
endfunction
//==========================================================================================
globals
private timer array tT
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
if (tN==0) then
set tT[0]=CreateTimer()
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==8191) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
set hasht = InitHashtable()
endfunction
endlibrary
History
Version 1.0
- Fixed a Math problem
- Spell was ready, initial release to the forums, for improvements
Version 1.1
- Now you can have waves of lights! If you don't like, just set the interval to zero!
Version 1.2
- Optimization in the code's speed, now it is even faster, and the code is more simple than ever !
Version 1.3
- Added a JESP manifest document
- Added a nice effect on the hero
Version 1.4
- Removed some members from the structure that weren't needed, now x, y and angle are just local variables
- Added Anitarf to the credits section
Version 1.4a
- Removed member "i" it was not needed. Now it is also a local variable
- Made some improvements to the comments
Version 1.5
- Added a boolean variable. Now the rays can depend on the casters angle if the user wants to
Version 1.5.1
- Updated for version 1.24
Version 1.0
- Fixed a Math problem
- Spell was ready, initial release to the forums, for improvements
Version 1.1
- Now you can have waves of lights! If you don't like, just set the interval to zero!
Version 1.2
- Optimization in the code's speed, now it is even faster, and the code is more simple than ever !
Version 1.3
- Added a JESP manifest document
- Added a nice effect on the hero
Version 1.4
- Removed some members from the structure that weren't needed, now x, y and angle are just local variables
- Added Anitarf to the credits section
Version 1.4a
- Removed member "i" it was not needed. Now it is also a local variable
- Made some improvements to the comments
Version 1.5
- Added a boolean variable. Now the rays can depend on the casters angle if the user wants to
Version 1.5.1
- Updated for version 1.24
//TESH.scrollpos=0
//TESH.alwaysfold=0
This is the JESP standard document, if a map contains this document it means that there are
spells that follow this standard.
Spells of this map that follow the standard:
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
- "Sun Ray"
Advantages of the Standard
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
- Implementing spells that follow the standard is relatively easier than implementing JASS
spells that don't follow the standard.
- Configuring/Balancing spells that follow the standard is relatively easier than
implementing JASS spells that don't follow the standard.
- Users may do the following procedure to make a new ability that uses the spell's script :
* Create a new Trigger with a name (case sensitive)
* Convert that trigger to custom text.
* Copy the spell's script to a text editor like Notepad or your OS equivalent.
* Replace the spell's Code name with the name you used on the trigger.
* Copy the new text to the new trigger
* Duplicate the Spell's original objects to have new ones for the new spell script.
You are now able to use that new version of the spell.
- In case two guys give the same name to 2 different spells, there are no conflict problems
because you can easily change the name of one of them
What is the JESP Standard?
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
The JESP standard was designed to make spell sharing much better. And to make sure JASS
enhanced spells follow a rule, to prevent chaos.
What does JESP Standard stands for?
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
JASS
Enhanced
Spell
Pseudotemplate
Requirements for a spell to follow the JESP Standard
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
- The spell is written in JASS
- The spell is 100% multi instanceable.
- The spell script is ready to support spells of any number of levels.
(default config header is not required to support all of them)
- The Spell has an specific code name.
- The Spell's trigger must have the spell's codename as name
- The Spell's InitTrig function must be named: InitTrig_<CodeName>
- The spell has a configuration header.
- It is mandatory that rawcodes of objects are configurable in the header.
- All the spell's specific code is inside the spell's "Trigger" (Trigger== that custom text
slot that world editor calls Trigger, the spell may use as many 'trigger' OBJECTS as needed)
- Every spell-specific single identifier or key works in such a way that reproducing the
spell's trigger but after performing a text-replace of codename with another name (and thus
renaming the cloned trigger to the new code name) it won't cause compile errors / conflicts
when playing the map.
- There is no code inside the spell's "Trigger" that is not specific to the spell.
- There are no requirements for GUI variables that are specific to the spell. If a system
used by the spell requires GUI variables the code for the system must be outside the "Trigger"
- Eyecandy and spell's balance have to be easy to configure
- The name of the author should be included in the spell's script.
- The reason to exist of this standard is spell sharing. This document should be included
within the map. And it should specify which spell follows the standard, in the top list.
//TESH.alwaysfold=0
This is the JESP standard document, if a map contains this document it means that there are
spells that follow this standard.
Spells of this map that follow the standard:
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
- "Sun Ray"
Advantages of the Standard
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
- Implementing spells that follow the standard is relatively easier than implementing JASS
spells that don't follow the standard.
- Configuring/Balancing spells that follow the standard is relatively easier than
implementing JASS spells that don't follow the standard.
- Users may do the following procedure to make a new ability that uses the spell's script :
* Create a new Trigger with a name (case sensitive)
* Convert that trigger to custom text.
* Copy the spell's script to a text editor like Notepad or your OS equivalent.
* Replace the spell's Code name with the name you used on the trigger.
* Copy the new text to the new trigger
* Duplicate the Spell's original objects to have new ones for the new spell script.
You are now able to use that new version of the spell.
- In case two guys give the same name to 2 different spells, there are no conflict problems
because you can easily change the name of one of them
What is the JESP Standard?
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
The JESP standard was designed to make spell sharing much better. And to make sure JASS
enhanced spells follow a rule, to prevent chaos.
What does JESP Standard stands for?
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
JASS
Enhanced
Spell
Pseudotemplate
Requirements for a spell to follow the JESP Standard
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
- The spell is written in JASS
- The spell is 100% multi instanceable.
- The spell script is ready to support spells of any number of levels.
(default config header is not required to support all of them)
- The Spell has an specific code name.
- The Spell's trigger must have the spell's codename as name
- The Spell's InitTrig function must be named: InitTrig_<CodeName>
- The spell has a configuration header.
- It is mandatory that rawcodes of objects are configurable in the header.
- All the spell's specific code is inside the spell's "Trigger" (Trigger== that custom text
slot that world editor calls Trigger, the spell may use as many 'trigger' OBJECTS as needed)
- Every spell-specific single identifier or key works in such a way that reproducing the
spell's trigger but after performing a text-replace of codename with another name (and thus
renaming the cloned trigger to the new code name) it won't cause compile errors / conflicts
when playing the map.
- There is no code inside the spell's "Trigger" that is not specific to the spell.
- There are no requirements for GUI variables that are specific to the spell. If a system
used by the spell requires GUI variables the code for the system must be outside the "Trigger"
- Eyecandy and spell's balance have to be easy to configure
- The name of the author should be included in the spell's script.
- The reason to exist of this standard is spell sharing. This document should be included
within the map. And it should specify which spell follows the standard, in the top list.
//TESH.scrollpos=0
//TESH.alwaysfold=0
//===========================================================================
//The caster uses his light powers to summon waves of Light Rays around him,
//damaging enemy Undead units nearby, and healing allied units
//
//Requires TimerUtils
//
//@author Flame_Phoenix
//
//@credits
//- Blackroot (aka Modeler), the first creator, gave me the basic idea and concept
//- the-thingy, by telling me where to use bj_DEGTORAD and why
//- Alexander244, for helping me fixing a bug with parenthesis ... lol
//- Anitarf, for suggesting a slight improvement for the code
//- My first teacher of vJASS: Blue_Jeans
//- All other people I forgot or ignored
//
//@version 1.5
//===========================================================================
scope SunRay initializer Init
//needed for spell's core, don't change
private keyword tmpPlayer
//===========================================================================
//=============================SETUP START===================================
//===========================================================================
globals
private constant integer AID = 'A000' //raecode of ability
private constant real LIGHT_RADIUS = 100 //radius of each single light
private constant string LIGHT_EFFECT = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl" //the effect of the light
private constant real LIGHT_INTERVAL = 0.2 //the interval that separates each light
private constant boolean CASTER_ANG = true //if true we consider the caster's facing angle, else we don't
endglobals
private constant function Damage takes integer level returns real
return level * 5. //the damage the enemy undead units will take
endfunction
private constant function Heal takes integer level returns real
return level * 10. //the heal your allied units will receive
endfunction
private constant function LightNumber takes integer level returns integer
//each Sun Ray of (4 + level) lights
return 4 + level
endfunction
private constant function RayNumber takes integer level returns integer
//the number of Sun Rays of the spell
return 5 + level
endfunction
private function AllyTargets takes nothing returns boolean
//what allied units will be affected by the spell
return IsUnitAlly(GetFilterUnit(), tmpPlayer) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) == false) and (GetWidgetLife(GetFilterUnit()) > 0.405)
endfunction
private function EnemyTargets takes nothing returns boolean
//what enemy units will be affected by the spell
return IsUnitEnemy(GetFilterUnit(), tmpPlayer) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) == false) and (GetUnitRace(GetFilterUnit()) == RACE_UNDEAD) and (GetWidgetLife(GetFilterUnit()) > 0.405)
endfunction
//===========================================================================
//=============================SETUP END=====================================
//===========================================================================
globals
private player tmpPlayer
private group g
private boolexpr enemies
private boolexpr allies
endglobals
private struct MyStruct
unit caster
real casterX
real casterY
integer level
timer t
real distInc
integer lightsCreated
static method create takes unit caster returns MyStruct
local MyStruct data = MyStruct.allocate()
//setting variables
set data.caster = caster
set data.casterX = GetUnitX(caster)
set data.casterY = GetUnitY(caster)
set data.level = GetUnitAbilityLevel(caster, AID)
set data.t = NewTimer() //this will create the lights =)
set data.distInc = LIGHT_RADIUS
set data.lightsCreated = 0
return data
endmethod
method onDestroy takes nothing returns nothing
call ReleaseTimer(.t)
endmethod
endstruct
//===========================================================================
private function CreateLights takes nothing returns nothing
local MyStruct data = MyStruct(GetTimerData(GetExpiredTimer()))
local unit f
local real x //the X position of the effect
local real y //the Y position of the effect
local real angle
local integer i //a counter for the loop
//we set this variable depending if we want to consider the
//caster's angle or not
if CASTER_ANG then
set angle = GetUnitFacing(data.caster)
else
set angle = 0
endif
//if we didn't pass the number of lights, than we create lights
//again, however, if we did, we end everything
if data.lightsCreated < LightNumber(data.level) then
//in this outer loop we create the Sun Rays
set i = 0
loop
exitwhen(i == RayNumber(data.level))
set x = data.casterX + data.distInc * Cos(angle)
set y = data.casterY + data.distInc * Sin(angle)
call DestroyEffect(AddSpecialEffect(LIGHT_EFFECT, x, y))
//in this first double inner loop we select the enemy units and damage them
set tmpPlayer = GetOwningPlayer(data.caster)
call GroupEnumUnitsInRange(g, x, y, LIGHT_RADIUS, enemies)
loop
set f = FirstOfGroup(g)
exitwhen(f == null)
call GroupRemoveUnit(g, f)
call UnitDamageTarget(data.caster, f, Damage(data.level), true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, null)
endloop
//in this second double inner loop we select the allied units and heal them
set tmpPlayer = GetOwningPlayer(data.caster)
call GroupEnumUnitsInRange(g, x, y, LIGHT_RADIUS, allies)
loop
set f = FirstOfGroup(g)
exitwhen(f == null)
call GroupRemoveUnit(g, f)
call SetWidgetLife(f, GetWidgetLife(f) + Heal(data.level))
endloop
set angle = angle + (360 / RayNumber(data.level)) * bj_DEGTORAD
set i = i + 1
endloop
set data.distInc = data.distInc + LIGHT_RADIUS
set data.lightsCreated = data.lightsCreated + 1
else
call data.destroy()
endif
endfunction
//===========================================================================
private function Conditions takes nothing returns boolean
local MyStruct data
if GetSpellAbilityId() == AID then
set data = MyStruct.create(GetTriggerUnit())
//now we start the timer !
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, LIGHT_INTERVAL, true, function CreateLights)
endif
return false
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger SunRayTrg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( SunRayTrg, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( SunRayTrg, Condition( function Conditions ) )
set SunRayTrg = null
//setting globals
set g = CreateGroup()
set enemies = Condition(function EnemyTargets)
set allies = Condition(function AllyTargets)
//preloading effect
call Preload(LIGHT_EFFECT)
endfunction
endscope
//TESH.alwaysfold=0
//===========================================================================
//The caster uses his light powers to summon waves of Light Rays around him,
//damaging enemy Undead units nearby, and healing allied units
//
//Requires TimerUtils
//
//@author Flame_Phoenix
//
//@credits
//- Blackroot (aka Modeler), the first creator, gave me the basic idea and concept
//- the-thingy, by telling me where to use bj_DEGTORAD and why
//- Alexander244, for helping me fixing a bug with parenthesis ... lol
//- Anitarf, for suggesting a slight improvement for the code
//- My first teacher of vJASS: Blue_Jeans
//- All other people I forgot or ignored
//
//@version 1.5
//===========================================================================
scope SunRay initializer Init
//needed for spell's core, don't change
private keyword tmpPlayer
//===========================================================================
//=============================SETUP START===================================
//===========================================================================
globals
private constant integer AID = 'A000' //raecode of ability
private constant real LIGHT_RADIUS = 100 //radius of each single light
private constant string LIGHT_EFFECT = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl" //the effect of the light
private constant real LIGHT_INTERVAL = 0.2 //the interval that separates each light
private constant boolean CASTER_ANG = true //if true we consider the caster's facing angle, else we don't
endglobals
private constant function Damage takes integer level returns real
return level * 5. //the damage the enemy undead units will take
endfunction
private constant function Heal takes integer level returns real
return level * 10. //the heal your allied units will receive
endfunction
private constant function LightNumber takes integer level returns integer
//each Sun Ray of (4 + level) lights
return 4 + level
endfunction
private constant function RayNumber takes integer level returns integer
//the number of Sun Rays of the spell
return 5 + level
endfunction
private function AllyTargets takes nothing returns boolean
//what allied units will be affected by the spell
return IsUnitAlly(GetFilterUnit(), tmpPlayer) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) == false) and (GetWidgetLife(GetFilterUnit()) > 0.405)
endfunction
private function EnemyTargets takes nothing returns boolean
//what enemy units will be affected by the spell
return IsUnitEnemy(GetFilterUnit(), tmpPlayer) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) == false) and (GetUnitRace(GetFilterUnit()) == RACE_UNDEAD) and (GetWidgetLife(GetFilterUnit()) > 0.405)
endfunction
//===========================================================================
//=============================SETUP END=====================================
//===========================================================================
globals
private player tmpPlayer
private group g
private boolexpr enemies
private boolexpr allies
endglobals
private struct MyStruct
unit caster
real casterX
real casterY
integer level
timer t
real distInc
integer lightsCreated
static method create takes unit caster returns MyStruct
local MyStruct data = MyStruct.allocate()
//setting variables
set data.caster = caster
set data.casterX = GetUnitX(caster)
set data.casterY = GetUnitY(caster)
set data.level = GetUnitAbilityLevel(caster, AID)
set data.t = NewTimer() //this will create the lights =)
set data.distInc = LIGHT_RADIUS
set data.lightsCreated = 0
return data
endmethod
method onDestroy takes nothing returns nothing
call ReleaseTimer(.t)
endmethod
endstruct
//===========================================================================
private function CreateLights takes nothing returns nothing
local MyStruct data = MyStruct(GetTimerData(GetExpiredTimer()))
local unit f
local real x //the X position of the effect
local real y //the Y position of the effect
local real angle
local integer i //a counter for the loop
//we set this variable depending if we want to consider the
//caster's angle or not
if CASTER_ANG then
set angle = GetUnitFacing(data.caster)
else
set angle = 0
endif
//if we didn't pass the number of lights, than we create lights
//again, however, if we did, we end everything
if data.lightsCreated < LightNumber(data.level) then
//in this outer loop we create the Sun Rays
set i = 0
loop
exitwhen(i == RayNumber(data.level))
set x = data.casterX + data.distInc * Cos(angle)
set y = data.casterY + data.distInc * Sin(angle)
call DestroyEffect(AddSpecialEffect(LIGHT_EFFECT, x, y))
//in this first double inner loop we select the enemy units and damage them
set tmpPlayer = GetOwningPlayer(data.caster)
call GroupEnumUnitsInRange(g, x, y, LIGHT_RADIUS, enemies)
loop
set f = FirstOfGroup(g)
exitwhen(f == null)
call GroupRemoveUnit(g, f)
call UnitDamageTarget(data.caster, f, Damage(data.level), true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, null)
endloop
//in this second double inner loop we select the allied units and heal them
set tmpPlayer = GetOwningPlayer(data.caster)
call GroupEnumUnitsInRange(g, x, y, LIGHT_RADIUS, allies)
loop
set f = FirstOfGroup(g)
exitwhen(f == null)
call GroupRemoveUnit(g, f)
call SetWidgetLife(f, GetWidgetLife(f) + Heal(data.level))
endloop
set angle = angle + (360 / RayNumber(data.level)) * bj_DEGTORAD
set i = i + 1
endloop
set data.distInc = data.distInc + LIGHT_RADIUS
set data.lightsCreated = data.lightsCreated + 1
else
call data.destroy()
endif
endfunction
//===========================================================================
private function Conditions takes nothing returns boolean
local MyStruct data
if GetSpellAbilityId() == AID then
set data = MyStruct.create(GetTriggerUnit())
//now we start the timer !
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, LIGHT_INTERVAL, true, function CreateLights)
endif
return false
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger SunRayTrg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( SunRayTrg, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( SunRayTrg, Condition( function Conditions ) )
set SunRayTrg = null
//setting globals
set g = CreateGroup()
set enemies = Condition(function EnemyTargets)
set allies = Condition(function AllyTargets)
//preloading effect
call Preload(LIGHT_EFFECT)
endfunction
endscope































































