TriggerHappy
...
- Reaction score
- 341
Rune Ritual
TriggerHappy
(Video) (Screenshot)
TriggerHappy
(Video) (Screenshot)
Spell Description
The caster channels his inner darkness, causing runes to circle around him.
It drags the nearest four units towards the runes and they are struck with lightning periodicly.
It drags the nearest four units towards the runes and they are struck with lightning periodicly.
Requirements
- UnitStatus by RisingDusk
- TimerUtils by Vexorian
- SimError (optional) by Vexorian
Code
JASS:
//===============================================================================\\
// \\
// Rune Ritual \\
// by \\
// TriggerHappy \\
// \\
// \\
//===============================================================================\\
// \\
// The caster channels his inner darkness, causing runes to circle around him. \\
// It drags the nearest four units towards the runes and they are struck with \\
// lightning periodicly. \\
// \\
//===============================================================================\\
// \\
// Requires: \\
// +TimerUtils \\
// +UnitStatus \\
// +SimError (optional) \\
// \\
//===============================================================================\\
scope RuneRitual initializer onInit //requires TimerUtils, UnitStatus optional SimError
globals
private constant integer SPELL_RAW_CODE = 039;A000039; // The spells raw code
private constant integer RUNE_DUMMY = 039;h000039; // The rune dummies raw code
private constant integer DMG_TICKS = 100 // How many timer intervals before the units get damaged
private constant real RUNE_DISTANCE = 300 // How far the units are made from the caster
private constant real TIMER_PERIOD = 0.03 // How far the units are made from the caster
private constant real SPIN_SPEED = 0.03 // how fast the runes spin
private constant boolean REQUIRE_UNITS = false // Displays an error if there are no enemy units around
private constant string DAMAGE_EFFECT = "Abilities\\Spells\\Other\\Monsoon\\MonsoonBoltTarget.mdl" // the effect when a unit is damaged
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL
endglobals
private constant function AOE takes integer level returns real
return (level*400.0)-((level-1)*100.0)
endfunction
private constant function DURATION takes integer level returns real
return level*5.00-(level)
endfunction
private constant function DAMAGE takes integer level returns real
return level*50.00
endfunction
//===============================================================================\\
// DO NOT EDIT BELOW THIS LINE \\
//===============================================================================\\
private keyword data
globals
private group GLOBAL_GROUP = CreateGroup()
private player TEMP_PLAYER
private data TEMP_DATA
private hashtable HASH = InitHashtable()
endglobals
native UnitAlive takes unit id returns boolean
private struct data
unit array rune[4]
unit array picked[4]
unit caster
real x
real y
real spin = 0.00
integer level
integer in = 0
integer ticks = DMG_TICKS
real array runeX[4]
real array runeY[4]
timer t
static method callback takes nothing returns nothing
local data this = GetTimerData(GetExpiredTimer())
local integer i = 0
set this.ticks = this.ticks + 1
loop
exitwhen i > 4
set this.runeX<i> = this.x+RUNE_DISTANCE*Cos((i*90) * bj_DEGTORAD+this.spin)
set this.runeY<i> = this.y+RUNE_DISTANCE*Sin((i*90) * bj_DEGTORAD+this.spin)
call SetUnitX(this.rune<i>, this.runeX<i>)
call SetUnitY(this.rune<i>, this.runeY<i>)
if this.picked<i> != null then
call SetUnitX(this.picked<i>, this.runeX<i>)
call SetUnitY(this.picked<i>, this.runeY<i>)
endif
if this.ticks >= DMG_TICKS and UnitAlive(this.picked<i>) then
call DestroyEffect(AddSpecialEffectTarget(DAMAGE_EFFECT, this.picked<i>, "origin"))
call UnitDamageTarget(this.caster, this.picked<i>, DAMAGE(this.level), true, false, ATTACK_TYPE, DAMAGE_TYPE, null)
endif
set i = i + 1
endloop
if this.ticks >= DMG_TICKS then
set this.ticks = 0
endif
set this.spin = this.spin+SPIN_SPEED
endmethod
static method Enemies takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = IsUnitEnemy(u, TEMP_PLAYER) and UnitAlive(u) and not LoadBoolean(HASH, GetHandleId(u), 0)
if TEMP_DATA.in < 4 and b then
set TEMP_DATA.picked[TEMP_DATA.in] = u
call StunUnit(u, true)
call SetUnitX(u, TEMP_DATA.runeX[TEMP_DATA.in])
call SetUnitY(u, TEMP_DATA.runeY[TEMP_DATA.in])
set TEMP_DATA.in = TEMP_DATA.in + 1
call SaveBoolean(HASH, GetHandleId(u), 0, true)
endif
set u = null
return b
endmethod
static method end takes nothing returns nothing
local timer t = GetExpiredTimer()
local data this = GetTimerData(t)
call ReleaseTimer(this.t)
set this.t = t
call this.destroy()
endmethod
static method create takes unit u returns data
local data this = data.allocate()
local integer i = 0
local real x
local real y
local real d
local timer t = NewTimer()
set this.caster = u
set this.y = GetUnitY(this.caster)
set this.x = GetUnitX(this.caster)
set this.level = GetUnitAbilityLevel(this.caster, SPELL_RAW_CODE)
set this.t = t
set d = DURATION(this.level)
call SaveBoolean(HASH, GetHandleId(u), 0, true)
set TEMP_DATA = this
set TEMP_PLAYER = GetOwningPlayer(this.caster)
call GroupEnumUnitsInRange(GLOBAL_GROUP, this.x, this.y, AOE(this.level), Filter(function data.Enemies))
static if REQUIRE_UNITS then
set bj_groupCountUnits = 0
call ForGroup(GLOBAL_GROUP, function CountUnitsInGroupEnum)
if bj_groupCountUnits == 0 then
static if LIBRARY_SimError then
call SimError(TEMP_PLAYER, "There are no enemy units around.")
else
call DisplayTimedTextToPlayer(TEMP_PLAYER, 0.52, 0.96, 2.00, "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cffffcc00There are no enemy units around.|r")
endif
call this.destroy()
return 0
endif
endif
loop
exitwhen i > 3
set x = this.x + RUNE_DISTANCE * Cos((i*90) * bj_DEGTORAD)
set y = this.y + RUNE_DISTANCE * Sin((i*90)* bj_DEGTORAD)
set this.rune<i> = CreateUnit(TEMP_PLAYER, RUNE_DUMMY, x, y, 0)
set i = i + 1
endloop
call SetTimerData(t, this)
call TimerStart(t, TIMER_PERIOD, true, function data.callback)
set t = NewTimer()
call SetTimerData(t, this)
call TimerStart(t, DURATION(this.level), false, function data.end)
return this
endmethod
method onDestroy takes nothing returns nothing
local integer i = 0
call ReleaseTimer(this.t)
call SaveBoolean(HASH, GetHandleId(this.caster), 0, false)
loop
exitwhen i > 4
call RemoveUnit(this.rune<i>)
if this.picked<i> != null then
call SaveBoolean(HASH, GetHandleId(this.picked<i>), 0, false)
call StunUnit(this.picked<i>, false)
set this.picked<i> = null
endif
set i = i + 1
endloop
endmethod
endstruct
private function Actions takes nothing returns boolean
local unit u = GetTriggerUnit()
if GetSpellAbilityId() == SPELL_RAW_CODE then
if LoadBoolean(HASH, GetHandleId(u), 0) then
static if LIBRARY_SimError then
call SimError(GetOwningPlayer(u), "You already have a rune ritual running.")
else
call DisplayTimedTextToPlayer(GetOwningPlayer(u), 0.52, 0.96, 2.00, "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cffffcc00You already have a rune ritual running.|r"
endif
set u = null
return false
else
call data.create(u)
endif
endif
set u = null
return false
endfunction
private function onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function Actions))
endfunction
endscope</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>