- Reaction score
- 456
Lunar Pulse
Obsidan Statue begins to drain energy inside
itself. After finished draining, strange waves
begin to pulse out of Obsidian Statue, freezing
and damaging enemy units in their way.
How far the far the waves will go,
depends on the time spent on channeling.
Level 1: Each wave deals 100 damage and
freezes for 1 second. Can be channeled up to 6
seconds, and has maximum wave distance of 600.
Pulsing lasts for 6 seconds.
Level 2: Each wave deals 150 damage and
freezes for 1.5 seconds. Can be channeled up to 8
seconds, and has maximum wave distance of 800.
Pulsing lasts for 8 seconds.
Level 3: Each wave deals 200 damage and
freezes for 2 seconds. Can be channeled up to 10
seconds, and has maximum wave distance of 1000.
Pulsing lasts for 10 seconds.
http://xs221.xs.to/xs221/07440/spellscreen.png
How to use, over 9 lines of code:
Spell, over 300 lines of code:
MUI: Yes.. In my tests at least..
Lag: It sure does if it is casted many times. Also, it depends on what you put onto configuration menu.
Known bugs: You really shouldn't cast the spell again (with same unit), if the caster is channeling already..
What else: Figure out yourself.
EDIT://Updated map 3rd time.
Obsidan Statue begins to drain energy inside
itself. After finished draining, strange waves
begin to pulse out of Obsidian Statue, freezing
and damaging enemy units in their way.
How far the far the waves will go,
depends on the time spent on channeling.
Level 1: Each wave deals 100 damage and
freezes for 1 second. Can be channeled up to 6
seconds, and has maximum wave distance of 600.
Pulsing lasts for 6 seconds.
Level 2: Each wave deals 150 damage and
freezes for 1.5 seconds. Can be channeled up to 8
seconds, and has maximum wave distance of 800.
Pulsing lasts for 8 seconds.
Level 3: Each wave deals 200 damage and
freezes for 2 seconds. Can be channeled up to 10
seconds, and has maximum wave distance of 1000.
Pulsing lasts for 10 seconds.
http://xs221.xs.to/xs221/07440/spellscreen.png
How to use, over 9 lines of code:
JASS:
How To Use:
¯¯¯¯¯¯¯¯¯¯¯
1. Export the "LunarStrain.mdx" from the import manager.
2. Import the exported model into your map.
3. Copy and paste the spell "Lunar Pulse" from object editor to your map.
4. Copy and paste the unit "[DummyU] Lunar Pulse]" from object editor to your map.
5. Copy the "Lunar Pulse" trigger from trigger editor to your map.
6. Change the rawcodes inside the "Lunar Pulse" trigger to match to the copied
unit039;s and spell039;s rawcodes.
7. Modify the spell to your liking.
JASS:
scope LunarPulse
private constant function SpellId takes nothing returns integer
return 039;A000039; //Rawcode of your spell
endfunction
private constant function MaximumChannel takes integer level returns real
return 4.00 + (level * 2.00) //Maximum channeling time of the spell
endfunction
private constant function ChannelInterval takes integer level returns real
return 0.035 //Interval of the channel timer
endfunction
private constant function MaximumDistance takes integer level returns real
return 400.00 + (level * 200.00) //Maximum distance of the pulses
endfunction
private constant function DummyId takes nothing returns integer
return 039;h001039; //Rawcode of your dummy wave unit
endfunction
private constant function DummyCount takes integer level returns integer
return 36 //Quantity of the dummies per wave. MAX = 40.
endfunction
private constant function PulsingDuration takes integer level returns real
return 4.00 + (level * 2.00) //How long does the pulsing last.
endfunction
private constant function PulseTimerInterval takes integer level returns real
return 0.035 //Interval of the pulse timer
endfunction
private constant function PulseInterval takes integer level returns real
return 2.00 //Time between each pulse. This is also the duration of each pulse
endfunction
private constant function FollowCaster takes nothing returns boolean
return true //Set to true, if you wanted the pulse wave to follow the caster
endfunction
private constant function CasterEffectPath takes integer level returns string
return "LunarStrain.mdx" //Path for the effect, which is attached to the caster
endfunction
private constant function CasterEffectPoint takes integer level returns string
return "origin" //Attach point name of the effect, which is attached to the caster
endfunction
private constant function Damage takes integer level returns real
return 50.00 + (level * 50.00) //How much each wave deals damage
endfunction
private constant function Freeze takes integer level returns real
return 0.50 + (level * 0.50) //How long are the enemies freezed
endfunction
private constant function FreezeDamageArea takes integer level returns real
return 48.00 //How big is the area where the units are frozen and damaged
endfunction
private constant function FreezeEffectPath takes integer level returns string
return "Abilities\\Weapons\\DragonHawkMissile\\DragonHawkMissile.mdl" //Path for the effect, which appears on freezed units
endfunction
private constant function FreezeEffectPoint takes integer level returns string
return "origin" //Attach point name of the effect, which appears when unit gets freezed
endfunction
globals
private integer lastStruct
endglobals
private struct LPdata
//Pulsing Data
trigger controlTrigger = CreateTrigger()
triggeraction controlAction
trigger pulseTrigger = CreateTrigger()
triggeraction pulseAction
boolean firstTime = true
unit array waveDummy[40]
real casterX
real casterY
real currentDistance
integer pulseCount = 0
group damagerGroup = CreateGroup()
method freezeUnit takes unit whichUnit returns nothing
local LPdata dat
local integer index = 0
loop
exitwhen (index == lastStruct + 1)
set dat = index
if (IsUnitInGroup(whichUnit, dat.damagerGroup)) then
exitwhen true
endif
set index = index + 1
endloop
call DestroyEffect(AddSpecialEffectTarget(dat.freezeEffectPath, whichUnit, dat.freezeEffectPoint))
call PauseUnit(whichUnit, true)
call SetUnitTimeScale(whichUnit, 0.00 * 0.01)
call PolledWait(dat.freeze)
call PauseUnit(whichUnit, false)
call SetUnitTimeScale(whichUnit, 100.00 * 0.01)
if (IsUnitInGroup(whichUnit, dat.damagerGroup)) then
call GroupRemoveUnit(dat.damagerGroup, whichUnit)
endif
endmethod
static method pulsePeriod takes nothing returns nothing
local LPdata dat
local real x
local real y
local integer index = 0
local group g
local unit f
loop
exitwhen (index == lastStruct + 1)
set dat = index
if (GetTriggeringTrigger() == dat.pulseTrigger) then
exitwhen true
endif
set index = index + 1
endloop
set dat.currentDistance = dat.currentDistance + ((dat.finalDistance / dat.pulseInterval) * dat.pulseTimerInterval)
if (FollowCaster() == true) then
set dat.casterX = GetUnitX(dat.casterUnit)
set dat.casterY = GetUnitY(dat.casterUnit)
endif
set index = 0
loop
exitwhen (index == dat.dummyCount)
set x = dat.casterX + dat.currentDistance * Cos((index * (360.00 / dat.dummyCount)) * bj_DEGTORAD)
set y = dat.casterY + dat.currentDistance * Sin((index * (360.00 / dat.dummyCount)) * bj_DEGTORAD)
call SetUnitX(dat.waveDummy[index], x)
call SetUnitY(dat.waveDummy[index], y)
set g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, dat.freezeDamageArea, null)
loop
set f = FirstOfGroup(g)
exitwhen (f == null)
call GroupRemoveUnit(g, f)
if ((IsUnitEnemy(f, GetOwningPlayer(dat.casterUnit)) == true) and (IsUnitInGroup(f, dat.damagerGroup) == false) and (GetUnitState(f, UNIT_STATE_LIFE) >= 1)) then
call UnitDamageTarget(dat.casterUnit, f, dat.damage, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS)
call GroupAddUnit(dat.damagerGroup, f)
call dat.freezeUnit.execute(f)
endif
set f = null
endloop
call GroupClear(g)
call DestroyGroup(g)
set g = null
set index = index + 1
endloop
endmethod
static method controlPulse takes nothing returns nothing
local LPdata dat
local real x
local real y
local integer index = 0
loop
exitwhen (index == lastStruct + 1)
set dat = index
if (GetTriggeringTrigger() == dat.controlTrigger) then
exitwhen true
endif
set index = index + 1
endloop
set dat.currentDistance = 0.00
set dat.casterX = GetUnitX(dat.casterUnit)
set dat.casterY = GetUnitY(dat.casterUnit)
set index = 0
if ((dat.pulseCount >= R2I(dat.pulsingDuration / dat.pulseInterval)) or (GetUnitState(dat.casterUnit, UNIT_STATE_LIFE) <= 0)) then
call TriggerRemoveAction(dat.controlTrigger, dat.controlAction)
set dat.controlAction = null
call DisableTrigger(dat.controlTrigger)
call DestroyTrigger(dat.controlTrigger)
set dat.controlTrigger = null
call TriggerRemoveAction(dat.pulseTrigger, dat.pulseAction)
set dat.pulseAction = null
call DisableTrigger(dat.pulseTrigger)
call DestroyTrigger(dat.pulseTrigger)
set dat.pulseTrigger = null
call DestroyEffect(dat.casterEffect)
set dat.casterEffect = null
loop
exitwhen (index == dat.dummyCount)
call KillUnit(dat.waveDummy[index])
set dat.waveDummy[index] = null
set index = index + 1
endloop
call dat.destroy()
return
endif
call GroupClear(dat.damagerGroup)
call DestroyGroup(dat.damagerGroup)
set dat.damagerGroup = null
set dat.damagerGroup = CreateGroup()
set dat.pulseCount = dat.pulseCount + 1
loop
exitwhen (index == dat.dummyCount)
call KillUnit(dat.waveDummy[index])
set dat.waveDummy[index] = null
set x = dat.casterX + dat.currentDistance * Cos((index * (360.00 / dat.dummyCount)) * bj_DEGTORAD)
set y = dat.casterY + dat.currentDistance * Sin((index * (360.00 / dat.dummyCount)) * bj_DEGTORAD)
set dat.waveDummy[index] = CreateUnit(GetOwningPlayer(dat.casterUnit), DummyId(), x, y, (index * (360.00 / dat.dummyCount)))
set index = index + 1
endloop
if (dat.firstTime == true) then
set dat.firstTime = false
call TriggerRegisterTimerEvent(dat.pulseTrigger, dat.pulseTimerInterval, true)
set dat.pulseAction = TriggerAddAction(dat.pulseTrigger, function LPdata.pulsePeriod)
endif
endmethod
//Channel Data
trigger channelTrigger = CreateTrigger()
triggeraction channelAction
real currentChannel = 0.00
real finalDistance
real channelCasterX
real channelCasterY
effect casterEffect
static method channelPeriod takes nothing returns nothing
local LPdata dat
local integer index = 0
loop
exitwhen (index == lastStruct + 1)
set dat = index
if (GetTriggeringTrigger() == dat.channelTrigger) then
exitwhen true
endif
set index = index + 1
endloop
set dat.currentChannel = dat.currentChannel + dat.channelInterval
if ((GetUnitX(dat.casterUnit) != dat.channelCasterX) and (GetUnitY(dat.casterUnit) != dat.channelCasterY)) or (GetUnitState(dat.casterUnit, UNIT_STATE_LIFE) <= 0) or (dat.currentChannel >= dat.maximumChannel) then
call PauseUnit(dat.casterUnit, true)
call PauseUnit(dat.casterUnit, false)
call TriggerRemoveAction(dat.channelTrigger, dat.channelAction)
call DisableTrigger(dat.channelTrigger)
call DestroyTrigger(dat.channelTrigger)
set dat.channelTrigger = null
if ((dat.maximumDistance / dat.maximumChannel) * dat.currentChannel > dat.maximumDistance) then
set dat.finalDistance = dat.maximumDistance
else
set dat.finalDistance = (dat.maximumDistance / dat.maximumChannel) * dat.currentChannel
endif
set dat.casterEffect = AddSpecialEffectTarget(dat.casterEffectPath, dat.casterUnit, dat.casterEffectPoint)
call TriggerRegisterTimerEvent(dat.controlTrigger, dat.pulseInterval, true)
set dat.controlAction = TriggerAddAction(dat.controlTrigger, function LPdata.controlPulse)
endif
endmethod
//General Data
unit casterUnit
real maximumChannel
real channelInterval
real maximumDistance
integer dummyCount
real pulsingDuration
real pulseTimerInterval
real pulseInterval
string casterEffectPath
string casterEffectPoint
real damage
real freeze
real freezeDamageArea
string freezeEffectPath
string freezeEffectPoint
static method create takes unit casterUnit, real maximumChannel, real channelInterval, real maximumDistance, integer dummyCount, real pulsingDuration, real pulseTimerInterval , real pulseInterval, string casterEffectPath, string casterEffectPoint, real damage, real freeze, real freezeDamageArea, string freezeEffectPath, string freezeEffectPoint returns LPdata
local LPdata dat = LPdata.allocate()
set dat.casterUnit = casterUnit
set dat.maximumChannel = maximumChannel
set dat.channelInterval = channelInterval
set dat.maximumDistance = maximumDistance
set dat.dummyCount = dummyCount
set dat.pulsingDuration = pulsingDuration
set dat.pulseTimerInterval = pulseTimerInterval
set dat.pulseInterval = pulseInterval
set dat.casterEffectPath = casterEffectPath
set dat.casterEffectPoint = casterEffectPoint
set dat.damage = damage
set dat.freeze = freeze
set dat.freezeDamageArea = freezeDamageArea
set dat.freezeEffectPath = freezeEffectPath
set dat.freezeEffectPoint = freezeEffectPoint
set dat.channelCasterX = GetUnitX(dat.casterUnit)
set dat.channelCasterY = GetUnitY(dat.casterUnit)
call TriggerRegisterTimerEvent(dat.channelTrigger, dat.channelInterval, true)
set dat.channelAction = TriggerAddAction(dat.channelTrigger, function LPdata.channelPeriod)
return dat
endmethod
endstruct
private function ControlConditions takes nothing returns boolean
return GetSpellAbilityId() == SpellId()
endfunction
private function ControlActions takes nothing returns nothing
local unit casterUnit = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(casterUnit, SpellId())
local LPdata dat = LPdata.create(casterUnit, MaximumChannel(level), ChannelInterval(level), MaximumDistance(level), DummyCount(level), PulsingDuration(level), PulseTimerInterval(level), PulseInterval(level), CasterEffectPath(level), CasterEffectPoint(level), Damage(level), Freeze(level), FreezeDamageArea(level), FreezeEffectPath(level), FreezeEffectPoint(level))
set lastStruct = dat
set casterUnit = null
endfunction
//===========================================================================
function InitTrig_Lunar_Pulse takes nothing returns nothing
local trigger trig = CreateTrigger()
local integer index = 0
loop
exitwhen (index == 12)
call TriggerRegisterPlayerUnitEvent(trig, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
endloop
call TriggerAddAction(trig, function ControlActions)
call TriggerAddCondition(trig, Filter(function ControlConditions))
set trig = null
endfunction
endscope
MUI: Yes.. In my tests at least..
Lag: It sure does if it is casted many times. Also, it depends on what you put onto configuration menu.
Known bugs: You really shouldn't cast the spell again (with same unit), if the caster is channeling already..
What else: Figure out yourself.
EDIT://Updated map 3rd time.