Name | Type | is_array | initial_value |
//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:
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
- "Spike Impact"
- "Cutwave"
- "Thunder Wave"
- "Geyser"
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
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.scrollpos=0
//TESH.alwaysfold=0
//******************************************************************************
//*
//* Damage Detection script
//* By moyack. 2009
//*
//* ============================================================================
//* Credits to Litany, DioD, Captain Griffen, Troll Brain and other nice guys *
//* for their suggestions, comments and ideas. *
//* ============================================================================
//*
//* For Damage detection, you just need to use these functions:
//*
//* => AddDamageCondition(<Boolexpr variable>) returns nothing
//* -------------------------------------------------------
//* Just add a condition function which manage the damaged unit and the script
//* will use it with all the the units in the DD.D group.
//*
//* => CreateDummy( player, 'Unitid', x, y, facing_Angle ) returns unit
//* ----------------------------------------------------------------
//* Like the CreateUnit function, but all the units created with this function
//* won't trigger the this Damage Detection script.
//*
//* => DoNonDetectableDamage(unit, widget, damage, boolean_attack, boolean_ranged, attacktype, damagetype, weapontype) returns boolean
//* -------------------------------------------------------------------------------------------------------------------------------
//* Like the UnitDamageTarget function, but it can be used inside condition functions.
//* How to know if you need to use it? if you use UnitDamageTarget() inside a DD function and
//* it freezes the game until it kills the attacked unit(s), then you have to replace that
//* function by this custom one.
//********************************************************************************
library UnitDamage
private struct DD // damage detection struct
static group D // group of units that will have damage detection
static group Dummies // group of units which will not be detected by the system
static trigger T
static timer Tm = CreateTimer() // used to control the infinite looping when is used UnitDamageTarget over the same triggering unit
// Add the attacked unit to the damage detection if the unit is not in the pack
private static method AddUnit takes unit d returns nothing
if not IsUnitInGroup(d, DD.D) and not IsUnitInGroup(d, DD.Dummies) then
debug call DisplayTimedTextFromPlayer(GetLocalPlayer(), 0,0,2,"Added " + GetUnitName(d) + " to the DD")
call TriggerRegisterUnitEvent(DD.T, d, EVENT_UNIT_DAMAGED)
call GroupAddUnit(DD.D, d)
endif
set d = null
endmethod
private static method Attacked takes nothing returns nothing
call DD.AddUnit(GetTriggerUnit())
endmethod
private static method Spelled takes nothing returns nothing
if GetSpellTargetUnit() != null then
call DD.AddUnit(GetSpellTargetUnit())
endif
endmethod
static method AntiLoop takes nothing returns nothing
call EnableTrigger(DD.T)
endmethod
private static method onInit takes nothing returns nothing
set DD.T = CreateTrigger()
set DD.D = CreateGroup()
set DD.Dummies = CreateGroup()
call TriggerRegisterAnyUnitEventBJ(DD.T, EVENT_PLAYER_UNIT_ATTACKED)
call TriggerAddAction(DD.T, function DD.Attacked)
set DD.T = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(DD.T, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction(DD.T, function DD.Spelled)
set DD.T = CreateTrigger()
endmethod
endstruct
// Damage detection system functions...
function AddDamageCondition takes boolexpr func returns nothing
call TriggerAddCondition(DD.T, func)
endfunction
function CreateDummy takes player p, integer id, real x, real y, real f returns unit
local unit u = CreateUnit(p, id, x, y, f)
call GroupAddUnit(DD.Dummies, u)
return u
endfunction
function DoNonDetectableDamage takes unit u, widget t, real damage, boolean attack, boolean ranged, attacktype AT, damagetype DT, weapontype WT returns boolean
call DisableTrigger(DD.T)
call TimerStart(DD.Tm, 0., false, function DD.AntiLoop)
return UnitDamageTarget(u, t, damage, attack, ranged, AT, DT, WT)
endfunction
endlibrary
//TESH.scrollpos=196
//TESH.alwaysfold=0
// ° Mapmaking since 2006...
// °
// °
// °
// °°°ÛÜ
// °°X°ÛÛÛ ÛÛÛÛÛÛÛÛ ÿÜÛÛÛÛÛÛÛÛÜ
// °°XX° ÛÛÛ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXX°° ÛÛÛÛÛÛÜ ÛÛÛÜ ÛÛÛÛÛ ßÛÛÛÛÛ ßÛÛÛÛ ÛÛÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÜ
// ÛÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÜÛÛÛÛÛÛ
// °°XXXXX° ÛÛÛÛ ÛÛÛÜ ÛÛÛÛÛ ÛÛÛÛÛÛÜ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXXXX °° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛ °°°ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ°°° ÛÛÛÛÛÛÛÛÛÛÛÛÛß
// ° XXXXX °°ÛÛÛÛÛ°°°°ÛÛÛÛÛÛÛÛ°°XX ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ XXX°°ÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛ
// °° XXXXX ÜÛÛÛÛÛÛ X ÛÛÛÛÛÛÛÛÛ XXX ÛÛÛÛÛÛÛÛÛÛÛ XXXXXX ÛÛÛÛÛÛÛ° ÛÛÛ
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°° °°°°
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°X°°
// °°° XXXXXXXXXX °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° XXXXXXXXXXXXXXXXX°°
// °°°°°°°°°°°°°°°° °°°°°°°° XXXXXXX °°°
// °°°°°° XX °°
// ...2009 and still moving on. °°°°°°°
// °°
// Screen Solution: 1280x1024 Visit www.ngo.clan.su!
//========================================================================================
scope SpikedImpact initializer Init
//========================================================================================
//====================================SETUP START=========================================
//========================================================================================
globals
//Default: 'SpIm'
private constant integer AID = 'SpIm' //the rawcode of the ability "Spike Impact"
//Default: 'eSp1'
private constant integer SPIKED_ONE = 'eSp1' //the rawcode of the unit spike 1
//Default: 'eSp2'
private constant integer SPIKED_TWO = 'eSp2' //the rawcode of the unit spike 2
//Default: 'eSp3'
private constant integer SPIKED_THREE = 'eSp3' //the rawcode of the unit spike 3
//Default: 'eSp4'
private constant integer SPIKED_FOUR = 'eSp4' //the rawcode of the unit spike 4
//Default: 8
private constant integer MAX = 8 //the maximal amount of spikes for each heigh
//Default: "Morph"
private constant string START_ANIMATION = "Morph" //the animation the caster will play when he casts the spell
//Default: "Morph Defend"
private constant string END_ANIMATION = "Morph Defend" //the animation the caster will play when the spell ends
//Default: 255
private constant integer RED = 255 //The red RGB color of the affected units from 0 to 255
//Default: 45
private constant integer GREEN = 45 //The green RGB color of the affected units from 0 to 255
//Default: 45
private constant integer BLUE = 45 //The blue RGB color of the affected units from 0 to 255
//Default: "Objects\\Spawnmodels\\Orc\\Orcblood\\BattrollBlood.mdl"
private constant string ENEMY_EFFECT = "Objects\\Spawnmodels\\Orc\\Orcblood\\BattrollBlood.mdl" //the that will be created at the enemy when it is affected, in this case is blood.
//Default: 0.3
private constant real SPIKE_GROW = 0.3 //the time the spikes will have to grow before they are paused
//Default: 1.5
private constant real SPIKE_PAUSE = 1.5 //the duration of pausing the spikes
//Default: 1.2
private constant real SPIKE_DEATH = 1.2 //this is how long the death animation of the spikes lasts
endglobals
private constant function Radius takes integer level returns real
//Default: 650. + level * 50.
return 650. + level * 50.
endfunction
private constant function Damage takes integer level returns real
//Default: level * 80. + 25.
return level * 80. + 25.
endfunction
//========================================================================================
//====================================SETUP END===========================================
//========================================================================================
globals
private unit TempCaster = null
endglobals
private function Pick takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(TempCaster)) and (GetWidgetLife(GetFilterUnit()) > 0.405) and not IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)
endfunction
private function KillEnemies takes unit caster, unit target, integer level returns nothing
local real DamageToDeal = Damage(level)
call PauseUnit(target, false)
call SetUnitTimeScale(target, 0.00)
call SetUnitVertexColor(target, 255, 255, 255, 255)
if(GetWidgetLife(target) <= DamageToDeal) then
call SetUnitExploded(target, true)
else
call DestroyEffect(AddSpecialEffectTarget(ENEMY_EFFECT, target, "chest"))
endif
call UnitDamageTarget(caster, target, DamageToDeal, true, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
endfunction
private function RecolorEnemies takes nothing returns nothing
local unit Enemy = GetEnumUnit()
call PauseUnit(Enemy, true)
call SetUnitTimeScale(Enemy, 0.00)
call SetUnitVertexColor(Enemy, RED, GREEN, BLUE, 255)
call DestroyEffect(AddSpecialEffectTarget(ENEMY_EFFECT, Enemy, "chest"))
set Enemy = null
endfunction
private struct SIData
unit caster
integer level
unit array spikes [36]
timer t
group g
static method Reset takes nothing returns nothing
local SIData data = SIData(GetTimerData(GetExpiredTimer()))
call data.destroy()
endmethod
static method End takes nothing returns nothing
local SIData data = SIData(GetTimerData(GetExpiredTimer()))
local unit f
local integer i = 0
loop
set f = FirstOfGroup(data.g)
exitwhen f == null
call KillEnemies(data.caster, f, data.level)
call GroupRemoveUnit(data.g, f)
endloop
set i = 0
loop
exitwhen (i == MAX * 4)
call PauseUnit(data.spikes[i], false)
call UnitApplyTimedLife(data.spikes[i], 'BTLF', 1.00)
call SetUnitTimeScale(data.spikes[i], 1)
set i = i + 1
endloop
call SetTimerData(data.t, integer(data))
call SetUnitAnimation(data.caster, END_ANIMATION)
call TimerStart(data.t, 0.5, false, function SIData.Reset)
endmethod
static method Growth takes nothing returns nothing
local SIData data = SIData(GetTimerData(GetExpiredTimer()))
local integer i = 0
loop
exitwhen (i == MAX * 4)
call PauseUnit(data.spikes[i], true)
call SetUnitTimeScale(data.spikes[i], 0.)
set i = i + 1
endloop
set TempCaster = data.caster
call GroupEnumUnitsInRange(data.g, GetUnitX(data.caster), GetUnitY(data.caster), Radius(data.level), Condition(function Pick))
call ForGroup(data.g, function RecolorEnemies)
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, SPIKE_DEATH, false, function SIData.End)
endmethod
static method create takes unit aCaster returns SIData
local SIData data = SIData.allocate()
local real x
local real y
local real Degrees
local integer SpikeNumber = 0
local integer i = 0
local player owner = GetOwningPlayer(aCaster)
set data.caster = aCaster
set data.level = GetUnitAbilityLevel(aCaster, AID)
set data.g = CreateGroup()
loop
exitwhen (i == MAX)
set Degrees = (360./MAX * I2R(i))
set x = GetUnitX(data.caster) + 10.0 * Cos(Degrees * bj_DEGTORAD)
set y = GetUnitY(data.caster) + 10.0 * Sin(Degrees * bj_DEGTORAD)
set data.spikes [SpikeNumber] = CreateUnit(owner, SPIKED_ONE, x, y, Degrees)
set data.spikes [SpikeNumber + 1] = CreateUnit(owner, SPIKED_TWO, x, y, Degrees)
set data.spikes [SpikeNumber + 2] = CreateUnit(owner, SPIKED_THREE, x, y, Degrees)
set data.spikes [SpikeNumber + 3] = CreateUnit(owner, SPIKED_FOUR, x, y, Degrees)
set SpikeNumber = SpikeNumber + 4
set i = i + 1
endloop
call PauseUnit(data.caster, true)
call SetUnitAnimation(data.caster, START_ANIMATION)
set data.t = NewTimer()
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, SPIKE_GROW, false, function SIData.Growth)
return data
endmethod
method onDestroy takes nothing returns nothing
local integer Index = 1
loop
exitwhen Index > 36
set this.spikes [Index] = null
set Index = Index + 1
endloop
call ReleaseTimer(this.t)
call IssueImmediateOrder(this.caster, "stop")
call SetUnitAnimation(this.caster, "stand")
call PauseUnit(this.caster, false)
call GroupClear(this.g)
set this.caster = null
set this.g = null
endmethod
endstruct
//====================================================================================
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == AID
endfunction
//====================================================================================
private function Actions takes nothing returns nothing
call SIData.create(GetSpellAbilityUnit())
endfunction
//===========================Creating the trigger=====================================
private function Init takes nothing returns nothing
local trigger Tri = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(Tri, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction(Tri, function Actions)
call TriggerAddCondition(Tri, Condition(function Conditions))
// this will remove the first cast lag
call RemoveUnit(CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), SPIKED_ONE, 0.00, 0.00, 0.00))
call RemoveUnit(CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), SPIKED_TWO, 0.00, 0.00, 0.00))
call RemoveUnit(CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), SPIKED_THREE, 0.00, 0.00, 0.00))
call RemoveUnit(CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), SPIKED_FOUR, 0.00, 0.00, 0.00))
call Preload(ENEMY_EFFECT)
endfunction
endscope
//TESH.scrollpos=254
//TESH.alwaysfold=0
// ° Mapmaking since 2006...
// °
// °
// °
// °°°ÛÜ
// °°X°ÛÛÛ ÛÛÛÛÛÛÛÛ ÿÜÛÛÛÛÛÛÛÛÜ
// °°XX° ÛÛÛ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXX°° ÛÛÛÛÛÛÜ ÛÛÛÜ ÛÛÛÛÛ ßÛÛÛÛÛ ßÛÛÛÛ ÛÛÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÜ
// ÛÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÜÛÛÛÛÛÛ
// °°XXXXX° ÛÛÛÛ ÛÛÛÜ ÛÛÛÛÛ ÛÛÛÛÛÛÜ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXXXX °° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛ °°°ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ°°° ÛÛÛÛÛÛÛÛÛÛÛÛÛß
// ° XXXXX °°ÛÛÛÛÛ°°°°ÛÛÛÛÛÛÛÛ°°XX ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ XXX°°ÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛ
// °° XXXXX ÜÛÛÛÛÛÛ X ÛÛÛÛÛÛÛÛÛ XXX ÛÛÛÛÛÛÛÛÛÛÛ XXXXXX ÛÛÛÛÛÛÛ° ÛÛÛ
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°° °°°°
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°X°°
// °°° XXXXXXXXXX °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° XXXXXXXXXXXXXXXXX°°
// °°°°°°°°°°°°°°°° °°°°°°°° XXXXXXX °°°
// °°°°°° XX °°
// ...2009 and still moving on. °°°°°°°
// °°
// Screen Solution: 1280x1024 Visit www.ngo.clan.su!
//================================================================================
scope ThunderWave initializer Init
//=======================================================================
//========================= SETUP START =================================
//=======================================================================
globals
//Default: 'ThWa'
private constant integer AID = 'ThWa' //The rawcode from the ability "Thunder Wave"
//Default: 'eDUM'
private constant integer DUMMY = 'eDUM' //The rawcode from the unit "Dummy Missile"
//Default: 'TWst'
private constant integer STUN = 'TWst' //The rawcode from the ability "Thunder Wave (Stun)"
//Default: "FORK"
private constant string LGTYPE = "FORK" //The lightning type of the lightning being created
//Default: "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
private constant string IMPACTSPX = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl" //The path of the impact effect
//Default: "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
private constant string MAINSPX = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl" //The path for the orb model
//Default: "Abilities\\Spells\\Orc\\Purge\\PurgeBuffTarget.mdl"
private constant string SECSPX = "Abilities\\Spells\\Orc\\Purge\\PurgeBuffTarget.mdl" //The path for the charging effect for the orb model
//Default: "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
private constant string HITSPX = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl" //The effect spawned on enemies when successfully hitting them
//Default: "spell slam"
private constant string ANIM = "spell slam" //While casting, the caster is paused and plays this animation
//Default: 1.5
private constant real SPELLDURA = 1.5 //The duration for the whole spell
///Default: 1.5
private constant real SIZE = 1.5 //The size for the orb models
//Defaul: 200.
private constant real DISTLEVEL = 200. //This variable defines the distance level for the position of the orbs (Has only graphical meaning)
//Default: 200.
private constant real HEIGHTLEVEL = 200. //This variable defines the height level for the flying height of the orbs (Has only graphical meaning)
//Default: 150.
private constant real DEBUGADD = 150. //If the lightning is created just like that, it will look odd since the lightning doesn't really "touch" the orbs. This value will increase the height of the lightning so it looks realistic.
endglobals
private constant function GetDamage takes integer level returns real
//Default: level * 15. + 15.
return level * 15. + 15.
endfunction
private constant function GetMaxDistance takes integer level returns real
//Default: level * 75. + 400.
return level * 75. + 400.
endfunction
private constant function GetStunChance takes integer level returns real
//Default: level * 1.5 + 2.5
return level * 1.5 + 2.5
endfunction
private constant function GetImpactRadius takes integer level returns real
//Default: level * 50. + 50.
return level * 50. + 50.
endfunction
//=======================================================================
//========================= SETUP END =================================
//=======================================================================
globals
private unit TempCaster = null
endglobals
private function A2PXY takes real x,real y,real xt,real yt returns real
return ModuloReal(bj_RADTODEG*Atan2(yt-y,xt-x),360.)
endfunction
private function UnitAllowFly takes unit u returns nothing
call UnitAddAbility(u, 'Arav')
call UnitRemoveAbility(u, 'Arav')
endfunction
private function Pick takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(TempCaster)) and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND)
endfunction
//================================================================================
private function DealDamage takes unit Caster, integer level, real x, real y returns nothing
local group Enemies = CreateGroup()
local unit f
local unit d
set TempCaster = Caster
call GroupEnumUnitsInRange(Enemies, x, y, GetImpactRadius(level), Condition(function Pick))
loop
set f = FirstOfGroup(Enemies)
exitwhen f == null
call UnitDamageTarget(Caster, f, GetDamage(level), true, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
call AddSpecialEffect(HITSPX, GetUnitX(f), GetUnitY(f))
if GetRandomReal(1, 100) < GetStunChance(level) then
set d = CreateUnit(GetOwningPlayer(Caster), DUMMY, GetUnitX(f), GetUnitY(f), 0.)
call UnitAddAbility(d, STUN)
call SetUnitAbilityLevel(d, STUN, level)
call UnitApplyTimedLife(d, 'BTLK', 0.5)
call IssueTargetOrder(d, "thunderbolt", f)
endif
call GroupRemoveUnit(Enemies, f)
endloop
call DestroyGroup(Enemies)
set Enemies = null
endfunction
//================================================================================
private struct TWData
unit array Missiles [6]
unit caster
real CenterX
real CenterY
real Angle
timer t
integer level
lightning LocLg
real DistAdd = 0.
integer Counter
effect array spx [6]
effect array spx2 [6]
static method Execute takes nothing returns nothing
local TWData data = TWData(GetTimerData(GetExpiredTimer()))
local real x
local real y
local integer i = 1
if data.Counter <= 5 then
set data.Counter = data.Counter + 1
else
if data.spx2 [1] != null then
loop
exitwhen i == 6
call DestroyEffect(data.spx2 [i])
set i = i + 1
endloop
endif
if data.Counter < 11 then
if data.LocLg != null then
call DestroyLightning(data.LocLg)
endif
set data.DistAdd = data.DistAdd + (GetMaxDistance(data.level) / 5)
set x = data.CenterX + data.DistAdd * Cos(data.Angle * bj_DEGTORAD)
set y = data.CenterY + data.DistAdd * Sin(data.Angle * bj_DEGTORAD)
set data.LocLg = AddLightningEx(LGTYPE, false, GetUnitX(data.Missiles [data.Counter - 5]), GetUnitY(data.Missiles [data.Counter - 5]), GetUnitFlyHeight(data.Missiles [data.Counter - 5]) + DEBUGADD, x, y, 0.)
call DestroyEffect(AddSpecialEffect(IMPACTSPX, x, y))
call DealDamage(data.caster, data.level, x, y)
set data.Counter = data.Counter + 1
else
call PauseTimer(data.t)
call data.destroy()
endif
endif
endmethod
static method create takes unit Caster, real CenterX, real CenterY, real Angle returns TWData
local TWData data = TWData.allocate()
local real Ang = Angle - 90
local real x = CenterX + DISTLEVEL * Cos(Ang * bj_DEGTORAD)
local real y = CenterY + DISTLEVEL * Sin(Ang * bj_DEGTORAD)
set data.Angle = Angle
set data.caster = Caster
call SetUnitFacing(data.caster, data.Angle)
set data.CenterX = CenterX
set data.CenterY = CenterY
set data.Counter = 1
set data.level = GetUnitAbilityLevel(data.caster, AID)
set data.Missiles [1] = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY, x, y, 0.)
call UnitAllowFly(data.Missiles [1])
call SetUnitFlyHeight(data.Missiles [1], GetUnitFlyHeight(Caster) + 50, 0.)
call SetUnitScale(data.Missiles [1], SIZE, SIZE, SIZE)
set data.spx [1] = AddSpecialEffectTarget(MAINSPX, data.Missiles [1], "chest")
set data.spx2 [1] = AddSpecialEffectTarget(SECSPX, data.Missiles [1], "origin")
set Ang = Angle + 90
set x = CenterX + DISTLEVEL * Cos(Ang * bj_DEGTORAD)
set y = CenterY + DISTLEVEL * Sin(Ang * bj_DEGTORAD)
set data.Missiles [2] = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY, x, y, 0.)
call UnitAllowFly(data.Missiles [2])
call SetUnitFlyHeight(data.Missiles [2], GetUnitFlyHeight(Caster) + 50, 0.)
call SetUnitScale(data.Missiles [2], SIZE, SIZE, SIZE)
set data.spx [2] = AddSpecialEffectTarget(MAINSPX, data.Missiles [2], "chest")
set data.spx2 [2] = AddSpecialEffectTarget(SECSPX, data.Missiles [2], "origin")
set Ang = Angle - 90
set x = CenterX + (DISTLEVEL / 2) * Cos(Ang * bj_DEGTORAD)
set y = CenterY + (DISTLEVEL / 2) * Sin(Ang * bj_DEGTORAD)
set data.Missiles [3] = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY, x, y, 0.)
call UnitAllowFly(data.Missiles [3])
call SetUnitFlyHeight(data.Missiles [3], GetUnitFlyHeight(Caster) + 50 + (HEIGHTLEVEL / 2), 0.)
call SetUnitScale(data.Missiles [3], SIZE, SIZE, SIZE)
set data.spx [3] = AddSpecialEffectTarget(MAINSPX, data.Missiles [3], "chest")
set data.spx2 [3] = AddSpecialEffectTarget(SECSPX, data.Missiles [3], "origin")
set Ang = Angle + 90
set x = CenterX + (DISTLEVEL / 2) * Cos(Ang * bj_DEGTORAD)
set y = CenterY + (DISTLEVEL / 2) * Sin(Ang * bj_DEGTORAD)
set data.Missiles [4] = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY, x, y, 0.)
call UnitAllowFly(data.Missiles [4])
call SetUnitFlyHeight(data.Missiles [4], GetUnitFlyHeight(Caster) + 50 +(HEIGHTLEVEL / 2), 0.)
call SetUnitScale(data.Missiles [4], SIZE, SIZE, SIZE)
set data.spx [4] = AddSpecialEffectTarget(MAINSPX, data.Missiles [4], "chest")
set data.spx2 [4] = AddSpecialEffectTarget(SECSPX, data.Missiles [4], "origin")
set data.Missiles [5] = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY, CenterX, CenterY, 0.)
call UnitAllowFly(data.Missiles [5])
call SetUnitFlyHeight(data.Missiles [5], GetUnitFlyHeight(Caster) + 50 + HEIGHTLEVEL, 0.)
call SetUnitScale(data.Missiles [5], SIZE, SIZE, SIZE)
set data.spx [5] = AddSpecialEffectTarget(MAINSPX, data.Missiles [5], "chest")
set data.spx2 [5] = AddSpecialEffectTarget(SECSPX, data.Missiles [5], "origin")
call PauseUnit(data.caster, true)
call SetUnitAnimation(data.caster, ANIM)
set data.t = NewTimer()
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, SPELLDURA / 10, true, function TWData.Execute)
return data
endmethod
method onDestroy takes nothing returns nothing
local integer Index = 1
call ReleaseTimer(this.t)
call SetUnitAnimation(this.caster, "stand")
call PauseUnit(this.caster, false)
loop
exitwhen Index == 6
call DestroyEffect(this.spx [Index])
call UnitApplyTimedLife(this.Missiles [Index], 'BTLK', 0.5)
set this.Missiles [Index] = null
set this.spx [Index] = null
set this.spx2 [Index] = null
set Index = Index + 1
endloop
if this.LocLg != null then
call DestroyLightning(this.LocLg)
set this.LocLg = null
endif
endmethod
endstruct
//================================================================================
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == AID
endfunction
//================================================================================
private function Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local location temploc = GetSpellTargetLoc()
local real TarX = GetLocationX(temploc)
local real TarY = GetLocationY(temploc)
call TWData.create(caster, GetUnitX(caster), GetUnitY(caster), A2PXY(GetUnitX(caster), GetUnitY(caster), TarX, TarY))
call RemoveLocation(temploc)
set temploc = null
set caster = null
endfunction
//================================================================================
private function Init takes nothing returns nothing
local trigger tri = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(tri, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(tri, Condition(function Conditions))
call TriggerAddAction(tri, function Actions)
// this will remove the first cast lag
call RemoveUnit(CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY, 0.00, 0.00, 0.00))
//Preloading strings to avoid leaks
call Preload(LGTYPE)
call Preload(IMPACTSPX)
call Preload(MAINSPX)
call Preload(SECSPX)
call Preload(ANIM)
endfunction
endscope
//TESH.scrollpos=59
//TESH.alwaysfold=0
// ° Mapmaking since 2006...
// °
// °
// °
// °°°ÛÜ
// °°X°ÛÛÛ ÛÛÛÛÛÛÛÛ ÿÜÛÛÛÛÛÛÛÛÜ
// °°XX° ÛÛÛ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXX°° ÛÛÛÛÛÛÜ ÛÛÛÜ ÛÛÛÛÛ ßÛÛÛÛÛ ßÛÛÛÛ ÛÛÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÜ
// ÛÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÜÛÛÛÛÛÛ
// °°XXXXX° ÛÛÛÛ ÛÛÛÜ ÛÛÛÛÛ ÛÛÛÛÛÛÜ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXXXX °° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛ °°°ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ°°° ÛÛÛÛÛÛÛÛÛÛÛÛÛß
// ° XXXXX °°ÛÛÛÛÛ°°°°ÛÛÛÛÛÛÛÛ°°XX ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ XXX°°ÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛ
// °° XXXXX ÜÛÛÛÛÛÛ X ÛÛÛÛÛÛÛÛÛ XXX ÛÛÛÛÛÛÛÛÛÛÛ XXXXXX ÛÛÛÛÛÛÛ° ÛÛÛ
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°° °°°°
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°X°°
// °°° XXXXXXXXXX °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° XXXXXXXXXXXXXXXXX°°
// °°°°°°°°°°°°°°°° °°°°°°°° XXXXXXX °°°
// °°°°°° XX °°
// ...2009 and still moving on. °°°°°°°
// °°
// Screen Solution: 1280x1024 Visit www.ngo.clan.su!
//================================================================================
scope Cutwave initializer Init
//===========================================================================
//=============================== SETUP START ===============================
//===========================================================================
globals
//Default: 'CuWa'
private constant integer AID = 'CuWa' //The rawcode of the ability "Cutwave"
//Default: 'CWbl'
private constant integer BLEED = 'CWbl' //The rawcode of the ability "Bleed"
//Default: 'eROT'
private constant integer DUMMY = 'eROT' //The rawcode of the unit "Dummy Missile (Rotated)"
//Default: "Abilities\\Weapons\\WingedSerpentMissile\\WingedSerpentMissile.mdl"
private constant string DUMMYMODEL = "Abilities\\Weapons\\WingedSerpentMissile\\WingedSerpentMissile.mdl" //The model of the dummy unit
//Default: "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
private constant string ENEMYMODEL = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl" //The effect being spawned on the enemy when successfully hitting it
//Default: "Abilities\\Spells\\Items\\AIil\\AIilTarget.mdl"
private constant string SPX = "Abilities\\Spells\\Items\\AIil\\AIilTarget.mdl" //The effect which appears when the cutwave disappears
//Default: "attack"
private constant string ANIM = "attack" //The animation the caster does when casting the ability
//Default: 2.5
private constant real SCALE = 2.5 //The scaling value of the dummy unit
//Default: 76.
private constant real RADIUS = 76. //The detection range
endglobals
private constant function GetDamage takes integer level returns real
//Default: level * 35
return level * 35.
endfunction
private constant function GetMaxDistance takes integer level returns real
//Default: level * 75. + 475.
return level * 75. + 475
endfunction
private constant function GetMissileSpeed takes integer level returns real
//Default: level * 20. + 2.
return level * 20. + 2.
endfunction
//===========================================================================
//=============================== SETUP END ===============================
//===========================================================================
globals
private unit TempCaster = null
private item GetWalkable = null
private constant integer ItemCheckID = 'sehr'
private location TempLoc = Location(0,0)
endglobals
private function IsPointWalkable takes real x,real y returns boolean
call SetItemPosition(GetWalkable,x,y)
call SetItemVisible(GetWalkable,false)
return GetItemX(GetWalkable)== x and GetItemY(GetWalkable)== y
endfunction
private function UnitAllowFly takes unit u returns nothing
call UnitAddAbility(u, 'Arav')
call UnitRemoveAbility(u, 'Arav')
endfunction
private function A2PXY takes real x,real y,real xt,real yt returns real
return ModuloReal(bj_RADTODEG*Atan2(yt-y,xt-x),360.)
endfunction
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == AID
endfunction
private function Pick takes nothing returns boolean
return GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE) > 0 and not IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(TempCaster))
endfunction
private function Kill takes unit caster, integer level, unit target returns nothing
local real DamageToDeal = GetDamage(level)
local real x = GetUnitX(target)
local real y = GetUnitY(target)
local unit u
if(GetWidgetLife(target) <= DamageToDeal) then
call KillUnit(target)
call DestroyEffect(AddSpecialEffectTarget(ENEMYMODEL, target, "chest"))
else
call UnitDamageTarget(caster, target, DamageToDeal, true, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
call DestroyEffect(AddSpecialEffectTarget(ENEMYMODEL, target, "chest"))
set u = CreateUnit(GetOwningPlayer(caster), DUMMY, x, y, 0.)
call UnitAddAbility(u, BLEED)
call SetUnitAbilityLevel(u, BLEED, level)
call IssueTargetOrder(u, "rejuvination", target)
call UnitApplyTimedLife(u, 'BTLK', 0.5)
endif
set u = null
endfunction
private struct CWData
unit Caster
unit Missile
real Speed
real Angle
real Dist
real MaxDist
real StartX
real StartY
real StartZ
real CosA
real SinA
integer Level
integer SaveCliffLvL
effect spx
timer t
group g
static method Execute takes nothing returns nothing
local CWData data = CWData(GetTimerData(GetExpiredTimer()))
local unit f
local real x
local real y
local real z
local real MaxZ
local real MinZ
set data.Dist = data.Dist + data.Speed
set x = data.StartX + data.Dist * data.CosA
set y = data.StartY + data.Dist * data.SinA
if data.SaveCliffLvL < GetTerrainCliffLevel(x, y) then
call DestroyEffect(AddSpecialEffect(SPX, GetUnitX(data.Missile), GetUnitY(data.Missile)))
call PauseTimer(data.t)
call data.destroy()
endif
call SetUnitPosition(data.Missile, x, y)
call MoveLocation(TempLoc, x, y)
set z = GetLocationZ(TempLoc)
call SetUnitFlyHeight(data.Missile, data.StartZ - z, 0.)
set TempCaster = data.Caster
call GroupEnumUnitsInRange(data.g, GetUnitX(data.Missile), GetUnitY(data.Missile), RADIUS, Condition(function Pick))
if data.Dist >= data.MaxDist then
call DestroyEffect(AddSpecialEffect(SPX, GetUnitX(data.Missile), GetUnitY(data.Missile)))
call PauseTimer(data.t)
call data.destroy()
elseif FirstOfGroup(data.g) != null then
loop
set f = FirstOfGroup(data.g)
exitwhen f == null
set MinZ = GetUnitFlyHeight(f) - RADIUS + 100.
set MaxZ = GetUnitFlyHeight(f) + RADIUS + 100.
if GetUnitFlyHeight(data.Missile) >= MinZ and GetUnitFlyHeight(data.Missile) <= MaxZ then
call Kill(data.Caster, data.Level, f)
call data.destroy()
call PauseTimer(data.t)
call GroupClear(data.g)
else
call GroupRemoveUnit(data.g, f)
endif
endloop
endif
endmethod
static method create takes unit caster, integer level, real TarX, real TarY returns CWData
local CWData data = CWData.allocate()
set data.Caster = caster
set data.StartX = GetUnitX(caster)
set data.StartY = GetUnitY(caster)
set data.Angle = A2PXY(data.StartX, data.StartY, TarX, TarY)
set data.CosA = Cos(data.Angle * bj_DEGTORAD)
set data.SinA = Sin(data.Angle * bj_DEGTORAD)
set data.Missile = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY, GetUnitX(caster), GetUnitY(caster), data.Angle)
set data.spx = AddSpecialEffectTarget(DUMMYMODEL, data.Missile, "origin")
call UnitAllowFly(data.Missile)
call SetUnitScale(data.Missile, SCALE, SCALE, SCALE)
call MoveLocation(TempLoc, data.StartX, data.StartY)
set data.StartZ = 170. + GetLocationZ(TempLoc)
set data.Dist = 0.
set data.Level = level
set data.MaxDist = GetMaxDistance(level)
set data.Speed = GetMissileSpeed(level)
set data.SaveCliffLvL = GetTerrainCliffLevel(data.StartX, data.StartY)
set data.g = CreateGroup()
set data.t = NewTimer()
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, 0.03, true, function CWData.Execute)
return data
endmethod
method onDestroy takes nothing returns nothing
call ReleaseTimer(this.t)
call DestroyEffect(this.spx)
call DestroyGroup(this.g)
call SetUnitAnimation(this.Missile, "stand")
call UnitApplyTimedLife(this.Missile, 'BTLK', 0.5)
set this.spx = null
set this.Missile = null
set this.Caster = null
set this.g = null
endmethod
endstruct
//===========================================================================
private function Actions takes nothing returns nothing
local location loc = GetSpellTargetLoc()
call CWData.create(GetSpellAbilityUnit(), GetUnitAbilityLevel(GetSpellAbilityUnit(), AID), GetLocationX(loc), GetLocationY(loc))
call RemoveLocation(loc)
set loc = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger tri = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(tri, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction(tri, function Actions)
call TriggerAddCondition(tri, Condition(function Conditions))
// this will remove the first cast lag
call RemoveUnit(CreateUnit(Player(15), DUMMY, 0.00, 0.00, 0.00))
//Preloading to avoid leaks
call Preload(DUMMYMODEL)
call Preload(ENEMYMODEL)
call Preload(SPX)
set GetWalkable = CreateItem(ItemCheckID, 0., 0.)
call SetItemVisible(GetWalkable,false)
endfunction
endscope
//TESH.scrollpos=252
//TESH.alwaysfold=0
// ° Mapmaking since 2006...
// °
// °
// °
// °°°ÛÜ
// °°X°ÛÛÛ ÛÛÛÛÛÛÛÛ ÿÜÛÛÛÛÛÛÛÛÜ
// °°XX° ÛÛÛ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXX°° ÛÛÛÛÛÛÜ ÛÛÛÜ ÛÛÛÛÛ ßÛÛÛÛÛ ßÛÛÛÛ ÛÛÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÜ
// ÛÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÜÛÛÛÛÛÛ
// °°XXXXX° ÛÛÛÛ ÛÛÛÜ ÛÛÛÛÛ ÛÛÛÛÛÛÜ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXXXX °° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛ °°°ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ°°° ÛÛÛÛÛÛÛÛÛÛÛÛÛß
// ° XXXXX °°ÛÛÛÛÛ°°°°ÛÛÛÛÛÛÛÛ°°XX ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ XXX°°ÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛ
// °° XXXXX ÜÛÛÛÛÛÛ X ÛÛÛÛÛÛÛÛÛ XXX ÛÛÛÛÛÛÛÛÛÛÛ XXXXXX ÛÛÛÛÛÛÛ° ÛÛÛ
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°° °°°°
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°X°°
// °°° XXXXXXXXXX °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° XXXXXXXXXXXXXXXXX°°
// °°°°°°°°°°°°°°°° °°°°°°°° XXXXXXX °°°
// °°°°°° XX °°
// ...2009 and still moving on. °°°°°°°
// °°
// Screen Solution: 1280x1024 Visit www.ngo.clan.su!
//===========================================================================
scope Geyser initializer Init
//===========================================================================
//=========================== SETUP START ===================================
//===========================================================================
private keyword GData
globals
//Default: 'Geys'
private constant integer AID = 'Geys' //The rawcode of the ability "Geyser"
//Default: 'eDUM'
private constant integer DUMMY = 'eDUM' //rawcode of the unit "Dummy Missile"
//Default: 5
private constant integer INTERVALS = 5 //this defines how often the geyser stacks on another water strike
//Default: "Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl"
private constant string MODEL = "Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl" //the model for the dummy units
//Default: "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
private constant string IMPACT = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl" //the impact model
//Default: 500.
private constant real MAXHEIGHT = 500. //the maximal height for the geyser
//Default: 1000.
private constant real FLYHEIGHT = 1000. //the maximal height for the affected targets
//Default: 200.
private constant real RADIUS = 150. //the radius in which the units are affected and the geyser takes place
//Default: 0.5
private constant real MAXDURA = 0.5 //the maximal duration for the water geyser
//Default: 1.08
private constant real JUMPMAXDURA = 1.08
//Default: 0.2
private constant real SMOOTHFACTOR = 0.2
endglobals
private constant function Damage takes integer level returns real
//Default: 35. + level * 50
return 35. + level * 50.
endfunction
private constant function StructuresDamage takes integer level returns real
//Default: level * 90 + 55
return level * 90. + 55.
endfunction
//===========================================================================
//=============================== SETUP END ================================
//===========================================================================
globals
private unit TempCaster
private constant real JUMPMAXINT = ((JUMPMAXDURA / 1.6615) / 0.03) // 1.6615 = Deviation
private constant real UPLIMIT = JUMPMAXINT - JUMPMAXINT * SMOOTHFACTOR
private constant integer MAXARRAY = INTERVALS * 7
endglobals
private function UnitAllowFly takes unit u returns nothing
call UnitAddAbility(u, 'Arav')
call UnitRemoveAbility(u, 'Arav')
endfunction
private function AffectedTargets takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND) and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0.405 and not IsUnit(GetFilterUnit(), TempCaster)
endfunction
private function Structures takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)
endfunction
private struct JumpData
unit Target
unit caster
integer level
real CurHeight
real CurSpeed
real SpeedReduce
timer t
static method Execute takes nothing returns nothing
local JumpData data = JumpData(GetTimerData(GetExpiredTimer()))
if data.CurHeight >= UPLIMIT then
set data.CurSpeed = data.CurSpeed - data.SpeedReduce
endif
set data.CurHeight = data.CurHeight + data.CurSpeed
call SetUnitFlyHeight(data.Target, data.CurHeight, 0.)
if data.CurHeight <= 0. then
call PauseUnit(data.Target, false)
call UnitDamageTarget(data.caster, data.Target, Damage(data.level), true, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
call DestroyEffect(AddSpecialEffect(IMPACT, GetUnitX(data.Target), GetUnitY(data.Target)))
set data.CurHeight = 0.
call SetUnitFlyHeight(data.Target, data.CurHeight, 0.)
call PauseTimer(data.t)
call data.destroy()
endif
endmethod
static method create takes unit Target, unit caster returns JumpData
local JumpData data = JumpData.allocate()
call PauseUnit(Target, true)
call UnitAllowFly(Target)
set data.Target = Target
set data.caster = caster
set data.level = GetUnitAbilityLevel(caster, AID)
set data.CurHeight = 0.
set data.CurSpeed = FLYHEIGHT / (MAXDURA / 0.03)
set data.SpeedReduce = data.CurSpeed / UPLIMIT
call GroupAddUnit(GData.g, data.Target)
set data.t = NewTimer()
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, 0.03, true, function JumpData.Execute)
return data
endmethod
method onDestroy takes nothing returns nothing
call GroupRemoveUnit(GData.g, this.Target)
call ReleaseTimer(this.t)
set this.Target = null
set this.caster = null
endmethod
endstruct
//===========================================================================
private struct GData
unit Caster
unit array Dummies [MAXARRAY]
real TarX
real TarY
real CurZ
real IncrZ
integer Interval
integer Ar
integer level
effect array Spx [MAXARRAY]
timer t
group GetUnits
public static group g = CreateGroup()
JumpData JDat
static method Execute takes nothing returns nothing
local GData data = GData(GetTimerData(GetExpiredTimer()))
local real x
local real y
local integer i = data.Ar
set data.CurZ = data.CurZ + data.IncrZ
set data.Interval = data.Interval + 1
if data.Interval == INTERVALS then
call PauseTimer(data.t)
call data.destroy()
else
loop
exitwhen i > data.Ar + 7
set x = data.TarX + RADIUS * Cos(i * 60 * bj_DEGTORAD)
set y = data.TarY + RADIUS * Sin(i * 60 * bj_DEGTORAD)
set data.Dummies [i] = CreateUnit(GetOwningPlayer(data.Caster), DUMMY, x, y, 0.)
set data.Spx [i] = AddSpecialEffectTarget(MODEL, data.Dummies [i], "chest")
call SetUnitFlyHeight(data.Dummies [i], data.CurZ, 0.)
set i = i + 1
endloop
set data.Dummies [data.Interval * 7] = CreateUnit(GetOwningPlayer(data.Caster), DUMMY, data.TarX, data.TarY, 0.)
set data.Spx [data.Interval * 7] = AddSpecialEffectTarget(MODEL, data.Dummies [data.Interval * 7], "chest")
call SetUnitFlyHeight(data.Dummies [data.Interval * 7], data.CurZ, 0.)
endif
endmethod
static method create takes unit caster, real TarX, real TarY returns GData
local GData data = GData.allocate()
local real x
local real y
local integer i = 1
local unit f
set data.Caster = caster
set data.TarX = TarX
set data.TarY = TarY
set data.Interval = 1
set data.level = GetUnitAbilityLevel(data.Caster, AID)
set data.IncrZ = MAXHEIGHT / 7.
if data.GetUnits == null then
set data.GetUnits = CreateGroup()
endif
if data.g == null then
set data.g = CreateGroup()
endif
loop
exitwhen i > 6
set data.Ar = i
set x = data.TarX + RADIUS * Cos(data.Ar * 60 * bj_DEGTORAD)
set y = data.TarY + RADIUS * Sin(data.Ar * 60 * bj_DEGTORAD)
set data.Dummies [data.Ar] = CreateUnit(GetOwningPlayer(caster), DUMMY, x, y, 0.)
set data.Spx [data.Ar] = AddSpecialEffectTarget(MODEL, data.Dummies [i], "chest")
set i = i + 1
endloop
set data.Dummies [data.Interval * 7] = CreateUnit(GetOwningPlayer(caster), DUMMY, data.TarX, data.TarY, 0.)
set data.Spx [data.Interval * 7] = AddSpecialEffectTarget(MODEL, data.Dummies [data.Interval * 7], "chest")
call GroupEnumUnitsInRange(data.GetUnits, data.TarX, data.TarY, RADIUS, Condition(function Structures))
loop
set f = FirstOfGroup(data.GetUnits)
exitwhen f == null
call UnitDamageTarget(data.Caster, f, StructuresDamage(data.level), true, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
call GroupRemoveUnit(data.GetUnits, f)
endloop
set TempCaster = data.Caster
call GroupEnumUnitsInRange(data.GetUnits, data.TarX, data.TarY, RADIUS, Condition(function AffectedTargets))
loop
set f = FirstOfGroup(data.GetUnits)
exitwhen f == null
if not IsUnitInGroup(f, data.g) then
set data.JDat = JumpData.create(f, data.Caster)
call GroupAddUnit(data.g, f)
endif
call GroupRemoveUnit(data.GetUnits, f)
endloop
set data.t = NewTimer()
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, MAXDURA / 7., true, function GData.Execute)
return data
endmethod
method onDestroy takes nothing returns nothing
local integer i = 1
loop
exitwhen i > MAXARRAY
call UnitApplyTimedLife(this.Dummies [i], 'BTLK', 0.5)
call DestroyEffect(this.Spx [i])
set this.Spx [i] = null
set this.Dummies [i] = null
set i = i + 1
endloop
call ReleaseTimer(this.t)
call GroupClear(this.GetUnits)
call DestroyGroup(this.GetUnits)
set this.CurZ = 0.
set this.GetUnits = null
endmethod
endstruct
//===========================================================================
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == AID
endfunction
//===========================================================================
private function Actions takes nothing returns nothing
local location Loc = GetSpellTargetLoc()
call GData.create(GetSpellAbilityUnit(), GetLocationX(Loc), GetLocationY(Loc))
call RemoveLocation(Loc)
set Loc = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger tri = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(tri, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(tri, Condition(function Conditions))
call TriggerAddAction(tri, function Actions)
// this will remove the first cast lag
call RemoveUnit(CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY, 0.00, 0.00, 0.00))
// prealoading strings to avoid leaks
call Preload(MODEL)
call Preload(IMPACT)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
// ° Mapmaking since 2006...
// °
// °
// °
// °°°ÛÜ
// °°X°ÛÛÛ ÛÛÛÛÛÛÛÛ ÿÜÛÛÛÛÛÛÛÛÜ
// °°XX° ÛÛÛ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXX°° ÛÛÛÛÛÛÜ ÛÛÛÜ ÛÛÛÛÛ ßÛÛÛÛÛ ßÛÛÛÛ ÛÛÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÜ
// ÛÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÜÛÛÛÛÛÛ
// °°XXXXX° ÛÛÛÛ ÛÛÛÜ ÛÛÛÛÛ ÛÛÛÛÛÛÜ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXXXX °° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛ °°°ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ°°° ÛÛÛÛÛÛÛÛÛÛÛÛÛß
// ° XXXXX °°ÛÛÛÛÛ°°°°ÛÛÛÛÛÛÛÛ°°XX ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ XXX°°ÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛ
// °° XXXXX ÜÛÛÛÛÛÛ X ÛÛÛÛÛÛÛÛÛ XXX ÛÛÛÛÛÛÛÛÛÛÛ XXXXXX ÛÛÛÛÛÛÛ° ÛÛÛ
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°° °°°°
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°X°°
// °°° XXXXXXXXXX °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° XXXXXXXXXXXXXXXXX°°
// °°°°°°°°°°°°°°°° °°°°°°°° XXXXXXX °°°
// °°°°°° XX °°
// ...2009 and still moving on. °°°°°°°
// °°
// Screen Solution: 1280x1024 Visit www.ngo.clan.su!
//================================================================================
scope Impulse initializer Init
private keyword KBData
//===========================================================================
//=========================== SETUP START ===================================
//===========================================================================
globals
//Default: 'ImpA'
private constant integer AID = 'ImpA' //The rawcode for the ability "Impulse (Passive)"
//Default: 12
private constant integer POLY = 12 //The polycount for the lightning ring. This is the amount of "attach points" the ring has.(The more polys, the rounder the circle will look. Better stay between 10 and 15 due to bugging danger.)
//Default: "CLSB"
private constant string LGTYPE = "CLSB" //The lightning type for the ring.
//Default: 4.
private constant real SPINSPEED = 4. //The impulse consists out of 2 single rings which spin around, each in another direction. This value defines how fast they spin.
//Default: 75.
private constant real DETECT = 75. //The detection range for the ring picking the enemied units. Detection takes place at the "attach points" from the impulse.
//Default: "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
private constant string HITSPX = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl" //The lightning effect bein spawned when knockbacking enemied units.
//Default:"Abilities\\Weapons\\ChimaeraLightningMissile\\ChimaeraLightningMissile.mdl"
private constant string DISAPPEAR = "Abilities\\Weapons\\ChimaeraLightningMissile\\ChimaeraLightningMissile.mdl" //If the rings disappear, this effect will spawn.
//Default: 0.5
private constant real FADEDURA = 0.5 //The fading-out duration. This won't support picking enemies and damaging them, it is for eyecandy.
endglobals
private constant function GetMaxRange takes integer level returns real
//Default: 125. + level * 75.
return 125. + level * 75.
endfunction
private constant function GetSpeed takes integer level returns real
//Default: level * 2. + 15.
return level * 2. + 15.
endfunction
private constant function GetKBDamage takes integer level returns real
//Default: level * 2.
return level * 2.
endfunction
//===========================================================================
//=========================== SETUP END ===================================
//===========================================================================
globals
private unit TempCaster = null
private item GetWalkable = null
private constant integer ItemCheckID = 'sehr'
private constant real MAXINT = (FADEDURA / 0.03)
endglobals
private function IsPointWalkable takes real x,real y returns boolean
call SetItemPosition(GetWalkable,x,y)
call SetItemVisible(GetWalkable,false)
return GetItemX(GetWalkable) == x and GetItemY(GetWalkable) == y
endfunction
private function Pick takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(TempCaster)) and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0.045 and IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND)
endfunction
private function A2PXY takes real x,real y,real xt,real yt returns real
return ModuloReal(bj_RADTODEG*Atan2(yt-y,xt-x),360.)
endfunction
private struct KBData
unit Caster
unit Target
real LockX
real LockY
real Speed
real Dist
real MaxDist
real Damage
real CosA
real SinA
static group g = CreateGroup()
timer t
static method Execute takes nothing returns nothing
local KBData data = KBData(GetTimerData(GetExpiredTimer()))
local real x
local real y
set data.Dist = data.Dist + data.Speed
set x = data.LockX + data.Dist * data.CosA
set y = data.LockY + data.Dist * data.SinA
if data.Dist < data.MaxDist and IsPointWalkable(x, y) then
call SetUnitPosition(data.Target, x, y)
call UnitDamageTarget(data.Caster, data.Target, data.Damage, true, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
if GetRandomInt(1, 3) == 1 then
call DestroyEffect(AddSpecialEffect(HITSPX , x, y))
endif
else
call PauseTimer(data.t)
call data.destroy()
endif
endmethod
static method create takes unit Caster, unit Target, real LockX, real LockY, integer level, real RemainDist, real Angle, real Speed returns KBData
local KBData data = KBData.allocate()
set data.Caster = Caster
set data.Target = Target
set data.Speed = Speed
set data.LockX = LockX
set data.LockY = LockY
set data.Damage = GetKBDamage(level)
set data.Dist = 0.
set data.MaxDist = RemainDist
set data.CosA = Cos(Angle * bj_DEGTORAD)
set data.SinA = Sin(Angle * bj_DEGTORAD)
set data.t = NewTimer()
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, 0.03, true, function KBData.Execute)
return data
endmethod
method onDestroy takes nothing returns nothing
call ReleaseTimer(this.t)
call GroupRemoveUnit(KBData.g, this.Target)
set this.Target = null
endmethod
endstruct
private struct ImpulseData
unit Caster
real LockX
real LockY
real Dist
real MaxDist
real Speed
real SpeedReduce
real array SaveAngOne [POLY]
real array SaveAngTwo [POLY]
lightning array RingOne [POLY]
lightning array RingTwo [POLY]
group g
timer t
static method Execute takes nothing returns nothing
local ImpulseData data = ImpulseData(GetTimerData(GetExpiredTimer()))
local real x1
local real y1
local real x2
local real y2
local real AngHelp = 360./POLY
local integer i = 0
local unit f = null
if (data.Dist < data.MaxDist) then
set data.Dist = data.Dist + data.Speed
set TempCaster = data.Caster
loop //Ring One
exitwhen i > POLY
set data.SaveAngOne [i] = data.SaveAngOne [i] + SPINSPEED
set x1 = data.LockX + data.Dist * Cos(data.SaveAngOne [i] * bj_DEGTORAD)
set y1 = data.LockY + data.Dist * Sin(data.SaveAngOne [i] * bj_DEGTORAD)
set x2 = data.LockX + data.Dist * Cos((data.SaveAngOne [i] + AngHelp) * bj_DEGTORAD)
set y2 = data.LockY + data.Dist * Sin((data.SaveAngOne [i] + AngHelp) * bj_DEGTORAD)
call MoveLightning(data.RingOne [i], false, x1, y1, x2, y2)
set i = i + 1
endloop
set i = 1
loop //Ring Two
exitwhen i > POLY
set data.SaveAngTwo [i] = data.SaveAngTwo [i] - SPINSPEED
set x1 = data.LockX + data.Dist * Cos(data.SaveAngTwo [i] * bj_DEGTORAD)
set y1 = data.LockY + data.Dist * Sin(data.SaveAngTwo [i] * bj_DEGTORAD)
set x2 = data.LockX + data.Dist * Cos((data.SaveAngTwo [i] + AngHelp) * bj_DEGTORAD)
set y2 = data.LockY + data.Dist * Sin((data.SaveAngTwo [i] + AngHelp) * bj_DEGTORAD)
call MoveLightning(data.RingTwo [i], false, x1, y1, x2, y2)
//Since the lightnings are so close together, picking units in one ring is enough
call GroupEnumUnitsInRange(data.g, x1, y1, (data.Dist * 3) / (POLY / 2), Condition(function Pick))
loop
set f = FirstOfGroup(data.g)
exitwhen f == null
if not IsUnitInGroup(f, KBData.g) then
if not (data.MaxDist - data.Dist <= 0.) then
call GroupAddUnit(KBData.g, f)
call KBData.create(data.Caster, f, x1, y1, GetUnitAbilityLevel(data.Caster, AID), (data.MaxDist - data.Dist), A2PXY(x1, y1, GetUnitX(f), GetUnitY(f)), data.Speed)
endif
endif
call GroupRemoveUnit(data.g, f)
endloop
set i = i + 1
endloop
else
if data.Speed <= 0. then
call PauseTimer(data.t)
call data.destroy()
loop
exitwhen i > 32
set x1 = data.LockX + data.Dist * Cos((11.25 * i) * bj_DEGTORAD)
set y1 = data.LockY + data.Dist * Sin((11.25 * i) * bj_DEGTORAD)
call DestroyEffect(AddSpecialEffect(DISAPPEAR, x1, y1))
set i = i + 1
endloop
else
set data.Speed = data.Speed - data.SpeedReduce
set data.Dist = data.Dist + data.Speed
loop //Ring One
exitwhen i > POLY
set data.SaveAngOne [i] = data.SaveAngOne [i] + SPINSPEED
set x1 = data.LockX + data.Dist * Cos(data.SaveAngOne [i] * bj_DEGTORAD)
set y1 = data.LockY + data.Dist * Sin(data.SaveAngOne [i] * bj_DEGTORAD)
set x2 = data.LockX + data.Dist * Cos((data.SaveAngOne [i] + AngHelp) * bj_DEGTORAD)
set y2 = data.LockY + data.Dist * Sin((data.SaveAngOne [i] + AngHelp) * bj_DEGTORAD)
call MoveLightning(data.RingOne [i], false, x1, y1, x2, y2)
set i = i + 1
endloop
set i = 1
loop //Ring Two
exitwhen i > POLY
set data.SaveAngTwo [i] = data.SaveAngTwo [i] - SPINSPEED
set x1 = data.LockX + data.Dist * Cos(data.SaveAngTwo [i] * bj_DEGTORAD)
set y1 = data.LockY + data.Dist * Sin(data.SaveAngTwo [i] * bj_DEGTORAD)
set x2 = data.LockX + data.Dist * Cos((data.SaveAngTwo [i] + AngHelp) * bj_DEGTORAD)
set y2 = data.LockY + data.Dist * Sin((data.SaveAngTwo [i] + AngHelp) * bj_DEGTORAD)
call MoveLightning(data.RingTwo [i], false, x1, y1, x2, y2)
set i = i + 1
endloop
endif
endif
endmethod
static method create takes unit Caster returns ImpulseData
local ImpulseData data = ImpulseData.allocate()
local integer i = 1
local real x1
local real y1
local real x2
local real y2
local real AngHelp = 360./POLY
set data.Caster = Caster
set data.LockX = GetUnitX(Caster)
set data.LockY = GetUnitY(Caster)
set data.Dist = 10.
set data.g = CreateGroup()
set data.MaxDist = GetMaxRange(GetUnitAbilityLevel(Caster, AID))
set data.Speed = GetSpeed(GetUnitAbilityLevel(Caster, AID))
set data.SpeedReduce = data.Speed / MAXINT
loop
exitwhen i > POLY
set data.SaveAngOne [i] = AngHelp * i
set data.SaveAngTwo [i] = data.SaveAngOne [i]
set x1 = GetUnitX(Caster) + 10. * Cos(data.SaveAngOne [i] * bj_DEGTORAD)
set y1 = GetUnitY(Caster) + 10. * Sin(data.SaveAngOne [i] * bj_DEGTORAD)
set x2 = GetUnitX(Caster) + 10. * Cos((data.SaveAngTwo [i] + AngHelp) * bj_DEGTORAD)
set y2 = GetUnitY(Caster) + 10. * Sin((data.SaveAngTwo [i] + AngHelp) * bj_DEGTORAD)
set data.RingOne [i] = AddLightning(LGTYPE, false, x1, y1, x2, y2)
set data.RingTwo [i] = AddLightning(LGTYPE, false, x1, y1, x2, y2)
set i = i + 1
endloop
set data.t = NewTimer()
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, 0.03, true, function ImpulseData.Execute)
return data
endmethod
method onDestroy takes nothing returns nothing
local integer i = 1
call ReleaseTimer(this.t)
call DestroyGroup(this.g)
loop
exitwhen i > POLY
call DestroyLightning(this.RingOne [i])
call DestroyLightning(this.RingTwo [i])
set this.RingOne [i] = null
set this.RingTwo [i] = null
set i = i + 1
endloop
set this.g = null
endmethod
endstruct
//===========================================================================
private function Actions takes nothing returns nothing
call ImpulseData.create(GetSpellAbilityUnit())
endfunction
//===========================================================================
private function Conditions takes nothing returns boolean
return AID == GetSpellAbilityId()
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger tri = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(tri, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction(tri, function Actions)
call TriggerAddCondition(tri, Condition(function Conditions))
//Preloading to avoid leaks
call Preload(LGTYPE)
call Preload(HITSPX)
set GetWalkable = CreateItem(ItemCheckID, 0., 0.)
call SetItemVisible(GetWalkable,false)
endfunction
endscope
//TESH.scrollpos=304
//TESH.alwaysfold=0
// ° Mapmaking since 2006...
// °
// °
// °
// °°°ÛÜ
// °°X°ÛÛÛ ÛÛÛÛÛÛÛÛ ÿÜÛÛÛÛÛÛÛÛÜ
// °°XX° ÛÛÛ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXX°° ÛÛÛÛÛÛÜ ÛÛÛÜ ÛÛÛÛÛ ßÛÛÛÛÛ ßÛÛÛÛ ÛÛÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÜ
// ÛÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÜÛÛÛÛÛÛ
// °°XXXXX° ÛÛÛÛ ÛÛÛÜ ÛÛÛÛÛ ÛÛÛÛÛÛÜ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXXXX °° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛ °°°ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ°°° ÛÛÛÛÛÛÛÛÛÛÛÛÛß
// ° XXXXX °°ÛÛÛÛÛ°°°°ÛÛÛÛÛÛÛÛ°°XX ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ XXX°°ÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛ
// °° XXXXX ÜÛÛÛÛÛÛ X ÛÛÛÛÛÛÛÛÛ XXX ÛÛÛÛÛÛÛÛÛÛÛ XXXXXX ÛÛÛÛÛÛÛ° ÛÛÛ
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°° °°°°
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°X°°
// °°° XXXXXXXXXX °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° XXXXXXXXXXXXXXXXX°°
// °°°°°°°°°°°°°°°° °°°°°°°° XXXXXXX °°°
// °°°°°° XX °°
// ...2009 and still moving on. °°°°°°°
// °°
// Screen Solution: 1280x1024 Visit www.ngo.clan.su!
//================================================================================
scope ImpulsePassive initializer Init
//===========================================================================
//=========================== SETUP START ===================================
//===========================================================================
globals
//Default: 'ImpP'
private constant integer AID = 'ImpP' //The rawcode for the ability "Impulse (Passive)"
//Default: 12
private constant integer POLY = 12 //The polycount for the lightning ring. This is the amount of "attach points" the ring has.(The more polys, the rounder the circle will look. Better stay between 10 and 15 due to bugging danger.)
//Default: "CLSB"
private constant string LGTYPE = "CLSB" //The lightning type for the ring.
//Default: 4.
private constant real SPINSPEED = 4. //The impulse consists out of 2 single rings which spin around, each in another direction. This value defines how fast they spin.
//Default: 75.
private constant real DETECT = 75. //The detection range for the ring picking the enemied units. Detection takes place at the "attach points" from the impulse.
//Default: "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
private constant string HITSPX = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl" //The lightning effect bein spawned when knockbacking enemied units.
//Default:"Abilities\\Weapons\\ChimaeraLightningMissile\\ChimaeraLightningMissile.mdl"
private constant string DISAPPEAR = "Abilities\\Weapons\\ChimaeraLightningMissile\\ChimaeraLightningMissile.mdl" //If the rings disappear, this effect will spawn.
//Default: 0.5
private constant real FADEDURA = 0.5 //The fading-out duration. This won't support picking enemies and damaging them, it is for eyecandy.
endglobals
private constant function GetChance takes integer level returns integer
//Default: level * 3
return level * 3
endfunction
private constant function GetMinDamage takes integer level returns real
//Default: 8. + level * 8.
return 8. + level * 8.
endfunction
private constant function GetMaxRange takes integer level returns real
//Default: 125. + level * 75.
return 125. + level * 75.
endfunction
private constant function GetSpeed takes integer level returns real
//Default: level * 2. + 15.
return level * 2. + 15.
endfunction
private constant function GetKBDamage takes integer level returns real
//Default: level * 2.
return level * 2.
endfunction
//===========================================================================
//=========================== SETUP END ===================================
//===========================================================================
globals
private unit TempCaster = null
private item GetWalkable = null
private constant integer ItemCheckID = 'sehr'
private constant real MAXINT = (FADEDURA / 0.03)
endglobals
private function IsPointWalkable takes real x,real y returns boolean
call SetItemPosition(GetWalkable,x,y)
call SetItemVisible(GetWalkable,false)
return GetItemX(GetWalkable) == x and GetItemY(GetWalkable) == y
endfunction
private function Pick takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(TempCaster)) and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0.045 and IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND)
endfunction
private function A2PXY takes real x,real y,real xt,real yt returns real
return ModuloReal(bj_RADTODEG*Atan2(yt-y,xt-x),360.)
endfunction
private struct KBData
unit Caster
unit Target
real LockX
real LockY
real Speed
real Dist
real MaxDist
real Damage
real CosA
real SinA
static group g = CreateGroup()
timer t
static method Execute takes nothing returns nothing
local KBData data = KBData(GetTimerData(GetExpiredTimer()))
local real x
local real y
set data.Dist = data.Dist + data.Speed
set x = data.LockX + data.Dist * data.CosA
set y = data.LockY + data.Dist * data.SinA
if data.Dist < data.MaxDist and IsPointWalkable(x, y) then
call SetUnitPosition(data.Target, x, y)
call UnitDamageTarget(data.Caster, data.Target, data.Damage, true, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
if GetRandomInt(1, 3) == 1 then
call DestroyEffect(AddSpecialEffect(HITSPX , x, y))
endif
else
call PauseTimer(data.t)
call data.destroy()
endif
endmethod
static method create takes unit Caster, unit Target, real LockX, real LockY, integer level, real RemainDist, real Angle, real Speed returns KBData
local KBData data = KBData.allocate()
set data.Caster = Caster
set data.Target = Target
set data.Speed = Speed
set data.LockX = LockX
set data.LockY = LockY
set data.Damage = GetKBDamage(level)
set data.Dist = 0.
set data.MaxDist = RemainDist
set data.CosA = Cos(Angle * bj_DEGTORAD)
set data.SinA = Sin(Angle * bj_DEGTORAD)
set data.t = NewTimer()
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, 0.03, true, function KBData.Execute)
return data
endmethod
method onDestroy takes nothing returns nothing
call ReleaseTimer(this.t)
call GroupRemoveUnit(KBData.g, this.Target)
set this.Target = null
endmethod
endstruct
private struct ImpulseData
unit Caster
real LockX
real LockY
real Dist
real MaxDist
real Speed
real SpeedReduce
real array SaveAngOne [POLY]
real array SaveAngTwo [POLY]
lightning array RingOne [POLY]
lightning array RingTwo [POLY]
group g
timer t
static method Execute takes nothing returns nothing
local ImpulseData data = ImpulseData(GetTimerData(GetExpiredTimer()))
local real x1
local real y1
local real x2
local real y2
local real AngHelp = 360./POLY
local integer i = 0
local unit f = null
if (data.Dist < data.MaxDist) then
set data.Dist = data.Dist + data.Speed
set TempCaster = data.Caster
loop //Ring One
exitwhen i > POLY
set data.SaveAngOne [i] = data.SaveAngOne [i] + SPINSPEED
set x1 = data.LockX + data.Dist * Cos(data.SaveAngOne [i] * bj_DEGTORAD)
set y1 = data.LockY + data.Dist * Sin(data.SaveAngOne [i] * bj_DEGTORAD)
set x2 = data.LockX + data.Dist * Cos((data.SaveAngOne [i] + AngHelp) * bj_DEGTORAD)
set y2 = data.LockY + data.Dist * Sin((data.SaveAngOne [i] + AngHelp) * bj_DEGTORAD)
call MoveLightning(data.RingOne [i], false, x1, y1, x2, y2)
set i = i + 1
endloop
set i = 1
loop //Ring Two
exitwhen i > POLY
set data.SaveAngTwo [i] = data.SaveAngTwo [i] - SPINSPEED
set x1 = data.LockX + data.Dist * Cos(data.SaveAngTwo [i] * bj_DEGTORAD)
set y1 = data.LockY + data.Dist * Sin(data.SaveAngTwo [i] * bj_DEGTORAD)
set x2 = data.LockX + data.Dist * Cos((data.SaveAngTwo [i] + AngHelp) * bj_DEGTORAD)
set y2 = data.LockY + data.Dist * Sin((data.SaveAngTwo [i] + AngHelp) * bj_DEGTORAD)
call MoveLightning(data.RingTwo [i], false, x1, y1, x2, y2)
//Since the lightnings are so close together, picking units in one ring is enough
call GroupEnumUnitsInRange(data.g, x1, y1, (data.Dist * 3) / (POLY / 2), Condition(function Pick))
loop
set f = FirstOfGroup(data.g)
exitwhen f == null
if not IsUnitInGroup(f, KBData.g) then
if not (data.MaxDist - data.Dist <= 0.) then
call GroupAddUnit(KBData.g, f)
call KBData.create(data.Caster, f, x1, y1, GetUnitAbilityLevel(data.Caster, AID), (data.MaxDist - data.Dist), A2PXY(x1, y1, GetUnitX(f), GetUnitY(f)), data.Speed)
endif
endif
call GroupRemoveUnit(data.g, f)
endloop
set i = i + 1
endloop
else
if data.Speed <= 0. then
call PauseTimer(data.t)
call data.destroy()
loop
exitwhen i > 32
set x1 = data.LockX + data.Dist * Cos((11.25 * i) * bj_DEGTORAD)
set y1 = data.LockY + data.Dist * Sin((11.25 * i) * bj_DEGTORAD)
call DestroyEffect(AddSpecialEffect(DISAPPEAR, x1, y1))
set i = i + 1
endloop
else
set data.Speed = data.Speed - data.SpeedReduce
set data.Dist = data.Dist + data.Speed
loop //Ring One
exitwhen i > POLY
set data.SaveAngOne [i] = data.SaveAngOne [i] + SPINSPEED
set x1 = data.LockX + data.Dist * Cos(data.SaveAngOne [i] * bj_DEGTORAD)
set y1 = data.LockY + data.Dist * Sin(data.SaveAngOne [i] * bj_DEGTORAD)
set x2 = data.LockX + data.Dist * Cos((data.SaveAngOne [i] + AngHelp) * bj_DEGTORAD)
set y2 = data.LockY + data.Dist * Sin((data.SaveAngOne [i] + AngHelp) * bj_DEGTORAD)
call MoveLightning(data.RingOne [i], false, x1, y1, x2, y2)
set i = i + 1
endloop
set i = 1
loop //Ring Two
exitwhen i > POLY
set data.SaveAngTwo [i] = data.SaveAngTwo [i] - SPINSPEED
set x1 = data.LockX + data.Dist * Cos(data.SaveAngTwo [i] * bj_DEGTORAD)
set y1 = data.LockY + data.Dist * Sin(data.SaveAngTwo [i] * bj_DEGTORAD)
set x2 = data.LockX + data.Dist * Cos((data.SaveAngTwo [i] + AngHelp) * bj_DEGTORAD)
set y2 = data.LockY + data.Dist * Sin((data.SaveAngTwo [i] + AngHelp) * bj_DEGTORAD)
call MoveLightning(data.RingTwo [i], false, x1, y1, x2, y2)
set i = i + 1
endloop
endif
endif
endmethod
static method create takes unit Caster returns ImpulseData
local ImpulseData data = ImpulseData.allocate()
local integer i = 1
local real x1
local real y1
local real x2
local real y2
local real AngHelp = 360./POLY
set data.Caster = Caster
set data.LockX = GetUnitX(Caster)
set data.LockY = GetUnitY(Caster)
set data.Dist = 10.
set data.g = CreateGroup()
set data.MaxDist = GetMaxRange(GetUnitAbilityLevel(Caster, AID))
set data.Speed = GetSpeed(GetUnitAbilityLevel(Caster, AID))
set data.SpeedReduce = data.Speed / MAXINT
loop
exitwhen i > POLY
set data.SaveAngOne [i] = AngHelp * i
set data.SaveAngTwo [i] = data.SaveAngOne [i]
set x1 = GetUnitX(Caster) + 10. * Cos(data.SaveAngOne [i] * bj_DEGTORAD)
set y1 = GetUnitY(Caster) + 10. * Sin(data.SaveAngOne [i] * bj_DEGTORAD)
set x2 = GetUnitX(Caster) + 10. * Cos((data.SaveAngTwo [i] + AngHelp) * bj_DEGTORAD)
set y2 = GetUnitY(Caster) + 10. * Sin((data.SaveAngTwo [i] + AngHelp) * bj_DEGTORAD)
set data.RingOne [i] = AddLightning(LGTYPE, false, x1, y1, x2, y2)
set data.RingTwo [i] = AddLightning(LGTYPE, false, x1, y1, x2, y2)
set i = i + 1
endloop
set data.t = NewTimer()
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, 0.03, true, function ImpulseData.Execute)
return data
endmethod
static method DoEffect takes nothing returns boolean
local unit Target = GetTriggerUnit()
local real Damage = GetEventDamage()
local real Life = GetWidgetLife(Target)
local integer Level = GetUnitAbilityLevel(Target, AID)
local integer Random = GetRandomInt(1, 100)
if Level > 0 then
if not (Damage < GetMinDamage(Level)) and not (Life < 0.045) and Random <= GetChance(Level) then
call ImpulseData.create(Target)
endif
endif
set Target = null
return false
endmethod
method onDestroy takes nothing returns nothing
local integer i = 1
call ReleaseTimer(this.t)
call DestroyGroup(this.g)
loop
exitwhen i > POLY
call DestroyLightning(this.RingOne [i])
call DestroyLightning(this.RingTwo [i])
set this.RingOne [i] = null
set this.RingTwo [i] = null
set i = i + 1
endloop
set this.g = null
endmethod
endstruct
//===========================================================================
private function Conditions takes nothing returns boolean
return AID == GetSpellAbilityId()
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set GetWalkable = CreateItem(ItemCheckID, 0., 0.)
call SetItemVisible(GetWalkable,false)
call AddDamageCondition(Condition(function ImpulseData.DoEffect))
//Preloading to avoid leaks
call Preload(LGTYPE)
call Preload(HITSPX)
endfunction
endscope
//TESH.scrollpos=296
//TESH.alwaysfold=0
// ° Mapmaking since 2006...
// °
// °
// °
// °°°ÛÜ
// °°X°ÛÛÛ ÛÛÛÛÛÛÛÛ ÿÜÛÛÛÛÛÛÛÛÜ
// °°XX° ÛÛÛ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXX°° ÛÛÛÛÛÛÜ ÛÛÛÜ ÛÛÛÛÛ ßÛÛÛÛÛ ßÛÛÛÛ ÛÛÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÜ
// ÛÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÜÛÛÛÛÛÛ
// °°XXXXX° ÛÛÛÛ ÛÛÛÜ ÛÛÛÛÛ ÛÛÛÛÛÛÜ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXXXX °° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛ °°°ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ°°° ÛÛÛÛÛÛÛÛÛÛÛÛÛß
// ° XXXXX °°ÛÛÛÛÛ°°°°ÛÛÛÛÛÛÛÛ°°XX ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ XXX°°ÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛ
// °° XXXXX ÜÛÛÛÛÛÛ X ÛÛÛÛÛÛÛÛÛ XXX ÛÛÛÛÛÛÛÛÛÛÛ XXXXXX ÛÛÛÛÛÛÛ° ÛÛÛ
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°° °°°°
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°X°°
// °°° XXXXXXXXXX °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° XXXXXXXXXXXXXXXXX°°
// °°°°°°°°°°°°°°°° °°°°°°°° XXXXXXX °°°
// °°°°°° XX °°
// ...2010 and still moving on. °°°°°°°
// °°
// Screen Solution: 1280x1024 Visit www.ngo.clan.su!
//================================================================================
scope Zeroblaster initializer Init
//===========================================================================
//===========================================================================
//===========================================================================
globals
//Default: 3
private constant integer LEVELS = 3 //The amount of levels the spell can get
//Default: 'ZeBl'
private constant integer AID = 'ZeBl' //The rawcode for the ability "Zeroblaster"
//Default: 'eDUM'
private constant integer DUMMY = 'eDUM' //The rawcode for the unit "Dummy Missile"
//Default: 'ZBsl'
private constant integer SLOW = 'ZBsl' //The rawcode for the ability "Zeroblaster (Slow)"
//Default: 'ZBst'
private constant integer FREEZE = 'ZBst' //The rawcode for the ability "Zeroblaster (Freeze)"
//Default: "war3mapImported\\FrozenOrb.MDX"
private constant string MISSILE = "war3mapImported\\FrozenOrb.MDX" //The model path for the missiles being fired
//Default: "war3mapImported\\cone of cold.mdx"
private constant string BREATH = "war3mapImported\\cone of cold.mdx" //the model path for the "ice breath" effect
//Default: 0.8
private constant real DURATION = 0.8 //The duration of the spell
//Default: 1.5
private constant real BREATH_SIZE = 1.5 //The breath effect's size
//Default: 0.8
private constant real MISSILE_SIZE = 0.8 //The missile's size
//Default: 200.
private constant real MAX_MISSILE_HEIGHT = 100. //the maximum height the missiles can take
//Default: (1./40.)
private constant real TICK = (1./40.) //The timer interval
//Default: 75.
private constant real MISSILE_DETECT_RANGE = 125. //the detection range to damage/freeze enemies when the missiles reach the ground
//Default: 225.
private constant real BREATH_DETECT_RANGE = 225. //the detection range for the breath's slowing effect
//Default: 25.
private constant real SPREAD_INC = 35. //this spreads the angle the missiles fly towards to the left and to the right so that the missiles don't just fly upon the same line
//Default: ATTACK_TYPE_MAGIC
private constant attacktype ATK_TYPE = ATTACK_TYPE_MAGIC //the attacktype for the damage enemies receive
//Default: DAMAGE_TYPE_COLD
private constant damagetype DMG_TYPE = DAMAGE_TYPE_COLD //the damagetype for the damage enemies receive
//Default: WEAPON_TYPE_WHOKNOWS
private constant weapontype WEP_TYPE = WEAPON_TYPE_WHOKNOWS //the weapontype for the damage enemies receive
//=========================================
private real array Damage [LEVELS]
private real array MaxDist [LEVELS]
private integer array Missiles [LEVELS]
private integer array Chance [LEVELS]
endglobals
private function Settings takes nothing returns nothing
//Damage Settings
set Damage [1] = 10
set Damage [2] = 15
set Damage [3] = 20
//Maximal Distance Settings
set MaxDist [1] = 400
set MaxDist [2] = 500
set MaxDist [3] = 600
//Amount of Missiles Settings
set Missiles [1] = 10
set Missiles [2] = 12
set Missiles [3] = 15
//Chance Settings
set Chance [1] = 5
set Chance [2] = 7
set Chance [3] = 9
endfunction
//===========================================================================
globals
private constant real MAX_INTERVAL = (DURATION / TICK)
private unit TempCaster = null
private group TempGroup = CreateGroup()
endglobals
private function ParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)
endfunction
private function Enum takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND) == true and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(TempCaster))
endfunction
private function A2PXY takes real x,real y,real xt,real yt returns real
return ModuloReal(bj_RADTODEG*Atan2(yt-y,xt-x),360.)
endfunction
private function Rnd takes real value returns integer
if R2I(value) == R2I(value + 0.5) then
return R2I(value)
else
return R2I(value + 0.5)
endif
endfunction
private function GetMaxDist takes integer lvl returns real
return MaxDist [lvl]
endfunction
private function GetMissiles takes integer lvl returns integer
return Missiles [lvl]
endfunction
private function UnitAllowFly takes unit u returns nothing
call UnitAddAbility(u, 'Arav')
call UnitRemoveAbility(u, 'Arav')
endfunction
private struct MissileData
unit Caster
unit Dummy
effect Spx
real MaxHeight
real CurHeight
real CurDist
real MaxDist
real Speed
real LockX
real LockY
real CosA
real SinA
group g
timer t
static method Execute takes nothing returns nothing
local thistype data = thistype(GetTimerData(GetExpiredTimer()))
local real x
local real y
local real z
local unit f = null
local unit d = null
if not (data.CurDist >= data.MaxDist) then
set data.CurDist = data.CurDist + data.Speed
set x = data.LockX + data.CurDist * data.CosA
set y = data.LockY + data.CurDist * data.SinA
set z = ParabolaZ(MAX_MISSILE_HEIGHT, data.MaxDist, data.CurDist)
call SetUnitFlyHeight(data.Dummy, z, 0.)
call SetUnitPosition(data.Dummy, x, y)
else
set TempCaster = data.Caster
call GroupEnumUnitsInRange(data.g, GetUnitX(data.Dummy), GetUnitY(data.Dummy), MISSILE_DETECT_RANGE, Condition(function Enum))
loop
set f = FirstOfGroup(data.g)
exitwhen f == null
call UnitDamageTarget(data.Caster, f, Damage[GetUnitAbilityLevel(data.Caster, AID)], true, true, ATK_TYPE, DMG_TYPE, WEP_TYPE)
if GetRandomInt(1, 100) < Chance [GetUnitAbilityLevel(data.Caster, AID)] then
set d = CreateUnit(GetOwningPlayer(data.Caster), DUMMY, GetUnitX(f), GetUnitY(f), 0.)
call UnitAddAbility(d, FREEZE)
call IssueTargetOrder(d, "thunderbolt", f)
call UnitApplyTimedLife(d, 'BTLK', 0.6)
endif
call GroupRemoveUnit(data.g, f)
endloop
call PauseTimer(data.t)
call data.destroy()
endif
endmethod
static method create takes unit Caster, real Angle, real Height, real Dist returns thistype
local thistype data = thistype.allocate()
set data.Caster = Caster
set data.LockX = GetUnitX(Caster)
set data.LockY = GetUnitY(Caster)
set data.CosA = Cos(Angle * bj_DEGTORAD)
set data.SinA = Sin(Angle * bj_DEGTORAD)
set data.Dummy = CreateUnit(GetOwningPlayer(data.Caster), DUMMY, data.LockX, data.LockY, Angle)
call UnitAllowFly(data.Dummy)
call SetUnitScale(data.Dummy, MISSILE_SIZE, MISSILE_SIZE, MISSILE_SIZE)
set data.Spx = AddSpecialEffectTarget(MISSILE, data.Dummy, "chest")
set data.MaxHeight = MAX_MISSILE_HEIGHT
set data.CurHeight = 0.
set data.MaxDist = Dist
set data.Speed = Dist / MAX_INTERVAL
set data.g = CreateGroup()
set data.t = NewTimer()
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, TICK, true, function thistype.Execute)
return data
endmethod
method onDestroy takes nothing returns nothing
call ReleaseTimer(this.t)
call UnitApplyTimedLife(this.Dummy, 'BTLK', 1.)
call DestroyEffect(this.Spx)
call DestroyGroup(this.g)
set this.Spx = null
set this.Dummy = null
set this.CurDist = 0.
set this.Speed = 0.
set this.CurHeight = 0.
endmethod
endstruct
private struct ZBData
unit Caster
unit Dummy
real Angle
real LockX
real LockY
integer Counter
integer MaxCount
effect Spx
timer t
static method Execute takes nothing returns nothing
local thistype data = thistype(GetTimerData(GetExpiredTimer()))
local real Angle
local real x
local real y
local integer i = 0
local unit f = null
local unit d = null
set data.Counter = data.Counter + 1
if data.Counter == 2 then
loop
exitwhen i >= Rnd(GetMaxDist(GetUnitAbilityLevel(data.Caster, AID)) / BREATH_DETECT_RANGE)
set x = data.LockX + (BREATH_DETECT_RANGE * i) * Cos(data.Angle * bj_DEGTORAD)
set y = data.LockY + (BREATH_DETECT_RANGE * i) * Sin(data.Angle * bj_DEGTORAD)
call GroupEnumUnitsInRange(TempGroup, x, y, BREATH_DETECT_RANGE, Condition(function Enum))
set i = i + 1
endloop
loop
set f = FirstOfGroup(TempGroup)
exitwhen f == null
set d = CreateUnit(GetOwningPlayer(data.Caster), DUMMY, GetUnitX(f), GetUnitY(f), 0.)
call UnitAddAbility(d, SLOW)
call IssueTargetOrder(d, "frostnova", f)
call UnitApplyTimedLife(d, 'BTLK', 0.6)
call GroupRemoveUnit(TempGroup, f)
endloop
endif
if GetRandomInt(1, 2) == 1 then
set Angle = data.Angle - (GetRandomReal(0, SPREAD_INC))
else
set Angle = data.Angle + (GetRandomReal(0, SPREAD_INC))
endif
call MissileData.create(data.Caster, Angle, MAX_MISSILE_HEIGHT, GetRandomReal(0, GetMaxDist(GetUnitAbilityLevel(data.Caster, AID))))
if data.Counter >= data.MaxCount then
call PauseTimer(data.t)
call data.destroy()
endif
endmethod
static method create takes unit Caster, real Angle returns thistype
local thistype data = thistype.allocate()
set data.Caster = Caster
set data.LockX = GetUnitX(Caster)
set data.LockY = GetUnitY(Caster)
set data.Dummy = CreateUnit(GetOwningPlayer(data.Caster), DUMMY, GetUnitX(Caster), GetUnitY(Caster), Angle)
call SetUnitScale(data.Dummy, BREATH_SIZE, BREATH_SIZE, BREATH_SIZE)
set data.Spx = AddSpecialEffectTarget(BREATH, data.Dummy, "origin")
set data.Counter = 0
set data.MaxCount = GetMissiles(GetUnitAbilityLevel(Caster, AID))
set data.Angle = Angle
set data.t = NewTimer()
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, (DURATION/data.MaxCount), true, function thistype.Execute)
return data
endmethod
method onDestroy takes nothing returns nothing
call ReleaseTimer(this.t)
call UnitApplyTimedLife(this.Dummy, 'BTLK', 0.5)
call DestroyEffect(this.Spx)
set this.Spx = null
set this.Dummy = null
set this.Caster = null
set this.Counter = 0
endmethod
endstruct
//===========================================================================
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == AID
endfunction
//===========================================================================
private function Actions takes nothing returns nothing
local real x = GetUnitX(GetSpellAbilityUnit())
local real y = GetUnitY(GetSpellAbilityUnit())
call ZBData.create(GetSpellAbilityUnit(), A2PXY(x,y,GetSpellTargetX(), GetSpellTargetY()))
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger tri = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(tri, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(tri, Condition(function Conditions))
call TriggerAddAction(tri, function Actions)
call Settings()
call Preload(MISSILE)
call Preload(BREATH)
endfunction
endscope
//TESH.scrollpos=244
//TESH.alwaysfold=0
// ° Mapmaking since 2006...
// °
// °
// °
// °°°ÛÜ
// °°X°ÛÛÛ ÛÛÛÛÛÛÛÛ ÿÜÛÛÛÛÛÛÛÛÜ
// °°XX° ÛÛÛ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °XX ° ÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXX°° ÛÛÛÛÛÛÜ ÛÛÛÜ ÛÛÛÛÛ ßÛÛÛÛÛ ßÛÛÛÛ ÛÛÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÜ
// ÛÛÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÛÛÛÛ
// °°°°°°°° ÛÛÛÛÛÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛ ÛÛÛÛÛÜ ÜÛÛÛÛÛÛ
// °°XXXXX° ÛÛÛÛ ÛÛÛÜ ÛÛÛÛÛ ÛÛÛÛÛÛÜ ßÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
// °°XXXXX °° ÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛ °°°ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ°°° ÛÛÛÛÛÛÛÛÛÛÛÛÛß
// ° XXXXX °°ÛÛÛÛÛ°°°°ÛÛÛÛÛÛÛÛ°°XX ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ XXX°°ÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛ
// °° XXXXX ÜÛÛÛÛÛÛ X ÛÛÛÛÛÛÛÛÛ XXX ÛÛÛÛÛÛÛÛÛÛÛ XXXXXX ÛÛÛÛÛÛÛ° ÛÛÛ
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°° °°°°
// °° XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX °°°°°X°°
// °°° XXXXXXXXXX °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° XXXXXXXXXXXXXXXXX°°
// °°°°°°°°°°°°°°°° °°°°°°°° XXXXXXX °°°
// °°°°°° XX °°
// ...2010 and still moving on. °°°°°°°
// °°
// Screen Solution: 1280x1024 Visit www.ngo.clan.su!
//================================================================================
scope Stormslash initializer Init
//===========================================================================
//===========================================================================
//===========================================================================
globals
//Default: 3
private constant integer LEVELS = 3 //The amount of levels the spell can get
//Default: 'StSl'
private constant integer AID = 'StSl' //The rawcode for the ability "Stormslash"
//Default: 'eDUM'
private constant integer DUMMY = 'eDUM' //The rawcode for the unit "Dummy Missile"
//Default: "war3mapImported\\SandBreathDamage.mdx"
private constant string SAND_MODEL = "war3mapImported\\SandBreathDamage.mdx" //The model path for the sand effect
//Default: "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl"
private constant string SWIFT_MODEL = "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl" //The model path for the mirror image effect
//Default: "Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl"
private constant string BLOOD_MODEL = "Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl" //The model path for the blood effect being created on enemies
//Default: "Stand Ready"
private constant string CASTER_ANI = "Stand Ready" //The caster's animation during the cast of the spell
//Default: 3.
private constant real SAND_SIZE = 3. //the scaling value for the sand effects
//Default: 30.
private constant real SLASH_SPEED = 33. //the speed for the single slashs
//Default: (1./40.)
private constant real TICK = (1./40.) //the timer interval
//Default: 0.2
private constant real TIME_BETWEEN = 0.15 //the duration between each slash (please keep in mind that the duration of the spell changes with this. Ergo: You have to change the duration for the spell in the object editor as well)
//Default: 100.
private constant real SLASH_DETECT = 100. //the detection range for the slash to damage enemies
//Default: ATTACK_TYPE_HERO
private constant attacktype ATK_TYPE = ATTACK_TYPE_HERO //the attacktype for the damage enemies receive
//Default: DAMAGE_TYPE_SHADOW_STRIKE
private constant damagetype DMG_TYPE = DAMAGE_TYPE_SHADOW_STRIKE//the damagetype for the damage enemies receive
//Default: WEAPON_TYPE_WHOKNOWS
private constant weapontype WEP_TYPE = WEAPON_TYPE_WHOKNOWS//the weapontype for the damage enemies receive
//=========================================
private real array Radius [LEVELS]
private real array DamagePerStrike [LEVELS]
private integer array SlashAmount [LEVELS]
private real array Distance [LEVELS]
endglobals
private function Settings takes nothing returns nothing
//Radius Settings
set Radius [1] = 400
set Radius [2] = 500
set Radius [3] = 600
//Slash Amount Settings
set SlashAmount [1] = 20
set SlashAmount [2] = 27
set SlashAmount [3] = 34
//Slash Distance Settings
set Distance [1] = 300
set Distance [2] = 350
set Distance [3] = 400
//Damage Settings
set DamagePerStrike [1] = 2
set DamagePerStrike [2] = 4
set DamagePerStrike [3] = 6
endfunction
//===========================================================================
globals
private unit TempCaster = null
private item GetWalkable = null
private constant integer ItemCheckID = 'sehr'
private hashtable ht
private group TempGroup
endglobals
private function A2PXY takes real x,real y,real xt,real yt returns real
return ModuloReal(bj_RADTODEG*Atan2(yt-y,xt-x),360.)
endfunction
private function Enum takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND) == true and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(TempCaster))
endfunction
private function IsPointWalkable takes real x,real y returns boolean
call SetItemPosition(GetWalkable,x,y)
call SetItemVisible(GetWalkable,false)
return GetItemX(GetWalkable)== x and GetItemY(GetWalkable)== y
endfunction
private struct Slash
unit Caster
unit Dummy
real LockX
real LockY
real CurDist
real MaxDist
real CosA
real SinA
timer t
group g
effect Spx
static method Execute takes nothing returns nothing
local thistype data = thistype(GetTimerData(GetExpiredTimer()))
local real x
local real y
local unit f
set data.CurDist = data.CurDist + SLASH_SPEED
set x = data.LockX + data.CurDist * data.CosA
set y = data.LockY + data.CurDist * data.SinA
set TempCaster = data.Caster
call GroupEnumUnitsInRange(TempGroup, x, y, SLASH_DETECT, Condition(function Enum))
loop
set f = FirstOfGroup(TempGroup)
exitwhen f == null
call UnitDamageTarget(data.Caster, f, DamagePerStrike [GetUnitAbilityLevel(data.Caster, AID)], true, true, ATK_TYPE, DMG_TYPE, WEP_TYPE)
if GetRandomInt(1,2) == 1 then
call DestroyEffect(AddSpecialEffect(SWIFT_MODEL, x, y))
endif
call DestroyEffect(AddSpecialEffect(BLOOD_MODEL, GetUnitX(f), GetUnitY(f)))
call GroupRemoveUnit(TempGroup, f)
endloop
call SetUnitPosition(data.Dummy, x, y)
if data.CurDist >= data.MaxDist then
call ReleaseTimer(data.t)
call data.destroy()
endif
endmethod
static method create takes unit Caster, real x, real y, real Angle, real Dist returns thistype
local thistype data = thistype.allocate()
set data.Caster = Caster
set data.LockX = x
set data.LockY = y
set data.Dummy = CreateUnit(GetOwningPlayer(data.Caster), DUMMY, x, y, Angle)
set data.Spx = AddSpecialEffectTarget(SAND_MODEL, data.Dummy, "origin")
set data.CosA = Cos(Angle * bj_DEGTORAD)
set data.SinA = Sin(Angle * bj_DEGTORAD)
set data.g = CreateGroup()
call SetUnitScale(data.Dummy, SAND_SIZE, SAND_SIZE, SAND_SIZE)
set data.CurDist = 0.
set data.MaxDist = Dist
set data.t = NewTimer()
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, TICK, true, function thistype.Execute)
return data
endmethod
method onDestroy takes nothing returns nothing
call ReleaseTimer(this.t)
call UnitApplyTimedLife(this.Dummy, 'BTLK', 0.8)
call DestroyEffect(this.Spx)
call DestroyGroup(this.g)
set this.g = null
set this.Dummy = null
set this.Spx = null
endmethod
endstruct
private struct SSData
unit Caster
real LockX
real LockY
real Angle
real MaxRadius
integer Count
integer lvl
integer MaxCount
timer t
static method Execute takes nothing returns nothing
local thistype data = thistype(GetTimerData(GetExpiredTimer()))
local real x
local real y
local real RndmDist = GetRandomReal(1., data.MaxRadius)
local real RndmAng = GetRandomReal(1., 360.)
set data.Count = data.Count + 1
set x = data.LockX + RndmDist * Cos(RndmAng * bj_DEGTORAD)
set y = data.LockY + RndmDist * Sin(RndmAng * bj_DEGTORAD)
call DestroyEffect(AddSpecialEffect(SWIFT_MODEL, GetUnitX(data.Caster) + GetRandomReal(-50, 50), GetUnitY(data.Caster) + GetRandomReal(-50, 50)))
call Slash.create(data.Caster, x, y, data.Angle, Distance [data.lvl])
if data.Count >= data.MaxCount then
call PauseTimer(data.t)
call data.destroy()
endif
endmethod
static method create takes unit Caster, real TarX, real TarY returns thistype
local thistype data = thistype.allocate()
set data.Caster = Caster
call SetUnitAnimation(data.Caster, CASTER_ANI)
set data.lvl = GetUnitAbilityLevel(data.Caster, AID)
set data.LockX = TarX
set data.LockY = TarY
set data.Angle = A2PXY(GetUnitX(Caster), GetUnitY(Caster), TarX, TarY)
set data.MaxRadius = Radius [data.lvl]
set data.Count = 0
set data.MaxCount = SlashAmount [data.lvl]
set data.t = NewTimer()
call SetTimerData(data.t, integer(data))
call TimerStart(data.t, TIME_BETWEEN, true, function thistype.Execute)
return data
endmethod
method onDestroy takes nothing returns nothing
call ReleaseTimer(this.t)
call SetUnitAnimation(this.Caster, "stand")
endmethod
endstruct
//===========================================================================
private function onCast takes nothing returns boolean
local SSData data
if GetSpellAbilityId() == AID then
set data = SSData.create(GetSpellAbilityUnit(), GetSpellTargetX(), GetSpellTargetY())
call SaveInteger(ht, 0, GetHandleId(GetSpellAbilityUnit()), data)
endif
return false
endfunction
private function onStop takes nothing returns boolean
local SSData data
if GetSpellAbilityId() == AID then
set data = LoadInteger(ht, 0, GetHandleId(GetSpellAbilityUnit()))
call PauseTimer(data.t)
call data.destroy()
endif
return false
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger tri = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(tri, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(tri, Condition(function onCast))
set tri = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(tri, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
call TriggerAddCondition(tri, Condition(function onStop))
set ht = InitHashtable()
set TempGroup = CreateGroup()
call Settings()
call Preload(SAND_MODEL)
call Preload(CASTER_ANI)
call Preload(BLOOD_MODEL)
call Preload(SWIFT_MODEL)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
How to import these spells? Just follow the steps matching the spell.
No worries, it is really easy! However, before you start with anything,
you have to make sure you use JNGP. If you don't, go to www.wc3campaigns.net
and download it or just go on the thread from my spellpack on www.hiveworkshop.com
and click on the given link to JNGP.
Also, you have to go to the Import-Manager (F12) and export the resource "dummy.mdx". After exporting,
import it into your map under the same name.
//============
//============ SPIKE IMPACT
//============
'Step 1:
Copy the spell "Spike Impact" and paste it into your map. RAWCODE ALARM!
If you paste it, you will be asked for a 4 character long code. That is the rawcode of this instance.
Take "SpIm" as code (without the "").
'Step 2:
Go into the Import-Manager (F12) and export the model "ImpaleTargetNoBlood.mdx". After exporting, import it into your map under the same name.
'Step 3:
Copy the units "Spike 1", "Spike 2", "Spike 3" and "Spike 4" into your map. RAWCODE ALARM!
Give the units following rawcodes.
Spike 1: "eSp1"
Spike 2: "eSp2"
Spike 3: "eSp3"
Spike 4: "eSp4"
(Again, without the "")
'Step 4:
If you already have the system "TimerUtils" in your map, you can ignore this step. If not ...
Copy the trigger "TimerUtils" into your map.
'Step 5:
Copy the trigger "SpikeImpact" into your map.
'Step 6:
Give proper credits and have fun with the spell!
//============
//============ CUTWAVE
//============
'Step 1:
Copy the buff "Bleed" into your map. The rawcode doesn't matter.
'Step 2:
Copy the spell "Cutwave (Bleed)" into your map. RAWCODE ALARM!
If you paste it, you will be asked for a 4 character long code. That is the rawcode of this instance.
Take "CWbl" as code (without the "").
'Step 3:
Copy the spell "Cutwave" into your map. RAWCODE ALARM!
Take "CuWa" as code.
'Step 4:
Copy the unit "Dummy Missile (Rotated)" into your map. RAWCODE ALARM!
Take "eROT" as code.
'Step 5:
If you already have the system "TimerUtils" in your map, you can ignore this step. If not ...
Copy the trigger "TimerUtils" into your map.
'Step 6:
Copy the trigger "Cutwave" into your map.
'Step 7:
Give proper credits and have fun with the spell!
//============
//============ Thunder Wave
//============
'Step 1:
Copy the buff "Thunder Wave" into your map. The rawcode doesn't matter.
'Step 2:
Copy the spell "Thunder Wave (Stun)" into your map. RAWCODE ALARM!
If you paste it, you will be asked for a 4 character long code. That is the rawcode of this instance.
Take "TWst" as code (without the "").
'Step 3:
Copy the spell "Thunder Wave" into your map. RAWCODE ALARM!
Take "ThWa" as code.
'Step 4:
Copy the unit "Dummy Missile" into your map. RAWCODE ALARM!
Take "eDUM" as code.
'Step 5:
If you already have the system "TimerUtils" in your map, you can ignore this step. If not ...
Copy the trigger "TimerUtils" into your map.
'Step 6:
Copy the trigger "ThunderWave" into your map.
'Step 7:
Give proper credits and have fun with the spell!
//============
//============ Geyser
//============
'Step 1:
Copy the buff "Nothing" into your map. The rawcode doesn't matter.
'Step 2:
Copy the spell "Geyser" into your map. RAWCODE ALARM!
Take "Geys" as code.
'Step 3:
Copy the unit "Dummy Missile" into your map. RAWCODE ALARM!
Take "eDUM" as code.
'Step 4:
If you already have the system "TimerUtils" in your map, you can ignore this step. If not ...
Copy the trigger "TimerUtils" into your map.
'Step 5:
Copy the trigger "Geyser" into your map.
'Step 6:
Give proper credits and have fun with the spell!
//============
//============ Impulse
//============
'Step 1:
Copy the spell "Impulse" into your map. RAWCODE ALARM!
If you paste it, you will be asked for a 4 character long code. That is the rawcode of this instance.
Take "ImpA" as code (without the "").
'Step 2:
If you already have the system "TimerUtils" in your map, you can ignore this step. If not ...
Copy the trigger "TimerUtils" into your map.
'Step 3:
Copy the trigger "Impulse" into your map.
'Step 4:
Give proper credits and have fun with the spell!
//============
//============ Impulse (Passive)
//============
'Step 1:
Copy the spell "Impulse (Passive)" into your map. RAWCODE ALARM!
If you paste it, you will be asked for a 4 character long code. That is the rawcode of this instance.
Take "ImpP" as code (without the "").
'Step 2:
If you already have the system "TimerUtils" in your map, you can ignore this step. If not ...
Copy the trigger "TimerUtils" into your map.
'Step 3:
Copy the trigger "DamageDetection" into your map.
'Step 4:
Copy the trigger "ImpulsePassive" into your map.
'Step 5:
Give proper credits and have fun with the spell!
//============
//============ Zeroblaster
//============
'Step 1:
Copy the buff "Frozen" into your map.
'Step 2:
Copy the spell "Zeroblaster (Freeze)" into your map. RAWCODE ALARM!
If you paste it, you will be asked for a 4 character long code. That is the rawcode of this instance.
Take "ZBst" as code (without the "").
'Step 3:
Copy the spell "Zeroblaster Slow" into your map. RAWCODE ALARM!
Take "ZBsl" as code (without the "").
'Step 4:
Copy the spell "Zeroblaster" into your map. RAWCODE ALARM!
Take "ZeBl" as code (without the "").
'Step 5:
Copy the unit "Dummy Missile" into your map. RAWCODE ALARM!
Take "eDUM" as code (without the "").
'Step 6:
If you already have the system "TimerUtils" in your map, you can ignore this step. If not ...
Copy the trigger "TimerUtils" into your map.
'Step 7:
Copy the trigger "Zeroblaster" into your map.
'Step 8:
If you want the same models/icon as the spell has currently, export it to your desktop (or somewhere you can find it back)
and import the resources into your map. Otherwise you would have to configure the given variables by yourself.
'Step 9:
Give proper credits and have fun with the spell!
//============
//============ Stormslash
//============
'Step 1:
Copy the spell "Stormslash" into your map. RAWCODE ALARM!
If you paste it, you will be asked for a 4 character long code. That is the rawcode of this instance.
Take "StSl" as code (without the "").
'Step 2:
Copy the unit "Dummy Missile" into your map. RAWCODE ALARM!
Take "eDUM" as code (without the "").
'Step 3:
If you already have the system "TimerUtils" in your map, you can ignore this step. If not ...
Copy the trigger "TimerUtils" into your map.
'Step 4:
Copy the trigger "Stormslash" into your map.
'Step 5:
If you want the same models/icon as the spell has currently, export it to your desktop (or somewhere you can find it back)
and import the resources into your map. Otherwise you would have to configure the given variables by yourself.
'Step 6:
Give proper credits and have fun with the spell!