library EnergyFissure /*
****************************************************************************************************
*
* E N E R G Y F I S S U R E
*
* ~ version 2.0.2
* ~ coded by Mr_Bean
* ~ idea by noobieatmaps
*
****************************************************************************************************
*
* */ requires /*
* ¯¯¯¯¯¯¯¯
* */ SpellEffectEvent /* http://www.hiveworkshop.com/forums/jass-resources-412/snippet-spelleffectevent-187193
* */ T32 /* http://www.thehelper.net/threads/timer32.118245/
* */ TimerUtils /* http://www.wc3c.net/showthread.php?t=101322
* */ xefx /* http://www.wc3c.net/showthread.php?t=101150
*
****************************************************************************************************
*
* Installation
* ¯¯¯¯¯¯¯¯¯¯¯¯
* - Make sure you've got (and installed properly) the above systems.
* - Copy the "Energy Fissure" hero ability. Update SPELL_ID to its raw ID.
* - Go through the configurables section below and change what you want to.
*
****************************************************************************************************
*
* Configuration
* ¯¯¯¯¯¯¯¯¯¯¯¯¯
*/
globals
//==================================================
//=== RAW IDS
private constant integer SPELL_ID = 'A000' // Raw ID of the ability.
//==================================================
//=== VOID CONFIGURATION
private constant real VOID_HEIGHT = 100.0 // Height of void.
private constant real VOID_VISION = 300.0 // Vision area you get of the void. Set to 0.0 to disable.
private constant real DESTROY_DELAY = 2.0 // Delay between units being zapped and the void being removed.
// Model of void:
private constant string VOID_EFFECT = "DarkVoid.mdx"
//==================================================
//=== WAVE CONFIGURATION
private constant integer NUM_WAVES = 8 // Number of waves created.
private constant real WAVE_DELAY = 1.0 // Delay between void created and waves created.
private constant real WAVE_SPEED = 300.0 // Speed of waves.
// Model of waves:
private constant string WAVE_EFFECT = "DeathWave.mdx"
//==================================================
//=== LIGHTNING CONFIGURATION
private constant real BOLT_DURATION = 0.5 // Duration of lightning.
private constant real BOLT_HEIGHT = 50.0 // Height of lightning.
private constant string BOLT_CODE = "MBUR" // Lightning code.
// Effect created on zapped units:
private constant string BOLT_EFFECT = "Abilities\\Spells\\NightElf\\ManaBurn\\ManaBurnTarget.mdl"
// Attachment point for above effect:
private constant string BOLT_FX_ATTACH = "origin"
//==================================================
//=== FLOATING TEXT CONFIGURATION
private constant boolean DISPLAY_TEXT = true // Display floating text showing damage dealt?
private constant real TEXT_ANGLE = 90.0 // Movement angle.
private constant real TEXT_SPEED = 64.0 // Movement speed.
private constant real TEXT_OFFSET = 50.0 // Height above target.
private constant real TEXT_DURATION = 2.0 // Duration.
private constant real TEXT_FADEPOINT = 1.0 // Fade time.
private constant real TEXT_HEIGHT = 0.023 // Size.
// Colour:
private constant string TEXT_COLOUR = "|cff8000FF"
endglobals
//==================================================
//=== DISTANCE OF WAVES PER LEVEL
private function GetWaveDistance takes integer level returns real
return (100.0 * level) + 200.0
endfunction
//==================================================
//=== MANA BURNED PER LEVEL
private function GetManaBurned takes integer level returns real
return 100.0 * level
endfunction
//==================================================
//=== DAMAGE FUNCTION SETUP
// This is if you want to change attack/damage types or if you use a custom
// function for damage detection or something similar.
private function DealDamage takes unit source, unit target, real amount returns nothing
call UnitDamageTarget(source, target, amount, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
endfunction
/***************************************************************************************************
*
* END OF CONFIGURATION AND DOCUMENTATION
*
***************************************************************************************************/
private struct ManaBolt
static constant real TEXT_X_VELOCITY = (Cos(TEXT_ANGLE * bj_DEGTORAD) * TEXT_SPEED) * 0.071 / 128.0
static constant real TEXT_Y_VELOCITY = (Sin(TEXT_ANGLE * bj_DEGTORAD) * TEXT_SPEED) * 0.071 / 128.0
//-----
static location loc = Location(0.0, 0.0)
//-----
unit source
unit target
lightning bolt
real sx
real sy
real sz
real time = BOLT_DURATION
real manaBurn
//-----
/**
* Destroys the lightning and cleans up.
*/
private method destroy takes nothing returns nothing
call DestroyLightning(bolt)
set source = null
set target = null
set bolt = null
call deallocate()
endmethod
static if (DISPLAY_TEXT) then
/**
* Creates text above the target showing the damage dealt.
* Only created if DISPLAY_TEXT is true.
*/
private method displayDamage takes real amount returns nothing
local texttag tt
if (IsVisibleToPlayer(GetUnitX(target), GetUnitY(target), GetLocalPlayer())) then
set tt = CreateTextTag()
call SetTextTagText(tt, TEXT_COLOUR + "-" + I2S(R2I(amount)) + "|r", TEXT_HEIGHT)
call SetTextTagPosUnit(tt, target, TEXT_OFFSET)
call SetTextTagVelocity(tt, TEXT_X_VELOCITY, TEXT_Y_VELOCITY)
call SetTextTagPermanent(tt, false)
call SetTextTagLifespan(tt, TEXT_DURATION)
call SetTextTagFadepoint(tt, TEXT_FADEPOINT)
call SetTextTagVisibility(tt, true)
set tt = null
endif
endmethod
endif
/**
* Drains the target's mana (if it has) and deals damage accordingly.
* Displays text if it's enabled.
*/
private method zap takes nothing returns nothing
local real curr
local real damage = 0.0
if (GetWidgetLife(target) > 0.405) then
set curr = GetUnitState(target, UNIT_STATE_MANA)
if (curr >= manaBurn) then
call SetUnitState(target, UNIT_STATE_MANA, curr - manaBurn)
set damage = manaBurn
elseif (curr > 0.0) then
call SetUnitState(target, UNIT_STATE_MANA, 0.0)
set damage = curr
endif
if (damage != 0.0) then
call DealDamage(source, target, damage)
endif
static if (DISPLAY_TEXT) then
call displayDamage(damage)
endif
endif
endmethod
/**
* Moves the lightning. If the duration expires, zaps the target and
* destroys the bolt.
*/
private method periodic takes nothing returns nothing
call MoveLocation(loc, GetUnitX(target), GetUnitY(target))
call MoveLightningEx(bolt, true, sx, sy, BOLT_HEIGHT + GetLocationZ(loc), /*
*/ GetUnitX(target), GetUnitY(target), BOLT_HEIGHT)
set time = time - T32_PERIOD
if (time <= 0.0) then
call stopPeriodic()
call zap()
call destroy()
endif
endmethod
implement T32x
/**
* Creates a new instance. Creates BOLT_EFFECT on the target and starts
* counting down until the damage is dealt.
*/
static method create takes unit s, real x, real y, unit t, real amt returns thistype
local thistype this = allocate()
set source = s
set target = t
set sx = x
set sy = y
call MoveLocation(loc, sx, sy)
set sz = BOLT_HEIGHT + GetLocationZ(loc)
set manaBurn = amt
set bolt = AddLightningEx(BOLT_CODE, true, sx, sy, sz, GetUnitX(target), GetUnitY(target), BOLT_HEIGHT)
call DestroyEffect(AddSpecialEffectTarget(BOLT_EFFECT, target, BOLT_FX_ATTACH))
call startPeriodic()
return this
endmethod
endstruct
private struct EnergyFissure
static constant real ANGLE_DIV = (2.0 * bj_PI) / NUM_WAVES
static constant real INCREMENT = WAVE_SPEED * T32_PERIOD
//-----
static real array X_VELOCITY[NUM_WAVES]
static real array Y_VELOCITY[NUM_WAVES]
static group enumG = CreateGroup()
static unit temp
//-----
unit caster
player owner
timer tim
real tx
real ty
real time
real aoe
real manaBurn
xefx pointFx
fogmodifier fog
//-----
xefx array waves[NUM_WAVES]
//-----
/**
* Destroys the void and each wave. Cleans up then deallocates.
*/
private method destroy takes nothing returns nothing
if (VOID_VISION > 0.0) then
call DestroyFogModifier(fog)
set fog = null
endif
call pointFx.destroy()
set caster = null
set owner = null
set tim = null
call deallocate()
endmethod
private static method cleanUp takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call ReleaseTimer(GetExpiredTimer())
call destroy()
endmethod
/**
* The filter applied while enumerating units in range.
*/
private method filterUnit takes unit u returns boolean
return IsUnitEnemy(u, owner) /* Enemy of caster.
*/ and not IsUnitType(u, UNIT_TYPE_DEAD) /* Alive.
*/ and GetUnitTypeId(u) != 0 /* Still alive.
*/ and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) /* Not magic immune.
*/ and not IsUnitType(u, UNIT_TYPE_STRUCTURE) /* Not a structure. */
endmethod
/**
* Zaps all units in range of the void, burning their mana and
* dealing damage equal to the amount burned.
*/
private method zapUnits takes nothing returns nothing
// First, destroy wave effects:
local integer i = 0
loop
exitwhen i == NUM_WAVES
call waves[i].destroy()
set i = i + 1
endloop
// Then zap units:
call GroupEnumUnitsInRange(enumG, tx, ty, aoe, null)
loop
set temp = FirstOfGroup(enumG)
exitwhen temp == null
call GroupRemoveUnit(enumG, temp)
if (filterUnit(temp)) then
call ManaBolt.create(caster, pointFx.x, pointFx.y, temp, manaBurn)
endif
endloop
endmethod
/**
* Moves each wave. If they reach their max distance, units within
* range get zapped, and the spell ends.
*/
private method periodic takes nothing returns nothing
local integer i = 0
loop
exitwhen i == NUM_WAVES
set waves[i].x = waves[i].x + X_VELOCITY[i]
set waves[i].y = waves[i].y + Y_VELOCITY[i]
set i = i + 1
endloop
set time = time - T32_PERIOD
if (time <= 0.0) then
call stopPeriodic()
call zapUnits()
call TimerStart(tim, DESTROY_DELAY, false, function thistype.cleanUp)
endif
endmethod
implement T32x
/**
* Creates each wave effect. Also starts moving them.
*/
private static method createPulses takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
local integer i = 0
loop
exitwhen i == NUM_WAVES
set waves[i] = xefx.create(tx, ty, i * ANGLE_DIV)
set waves[i].fxpath = WAVE_EFFECT
set i = i + 1
endloop
call startPeriodic()
endmethod
/**
* Creates a new instance. Creates the void effect at the target point
* and waits before creating the waves.
*/
private static method create takes nothing returns thistype
local thistype this = allocate()
local integer level
set caster = GetTriggerUnit()
set owner = GetTriggerPlayer()
set tx = GetSpellTargetX()
set ty = GetSpellTargetY()
set level = GetUnitAbilityLevel(caster, SPELL_ID)
set manaBurn = GetManaBurned(level)
set aoe = GetWaveDistance(level)
set time = aoe / WAVE_SPEED
set pointFx = xefx.create(tx, ty, 0.0)
set pointFx.z = VOID_HEIGHT
set pointFx.fxpath = VOID_EFFECT
if (VOID_VISION > 0.0) then
set fog = CreateFogModifierRadius(owner, FOG_OF_WAR_VISIBLE, tx, ty, VOID_VISION, true, false)
call FogModifierStart(fog)
endif
set tim = NewTimerEx(this)
call TimerStart(tim, WAVE_DELAY, false, function thistype.createPulses)
return this
endmethod
/**
* Stores the x and y velocities for each wave. Registers the spell
* and preloads the effects.
*/
private static method onInit takes nothing returns nothing
local integer i = 0
loop
exitwhen i == NUM_WAVES
set X_VELOCITY[i] = INCREMENT * Cos(i * ANGLE_DIV)
set Y_VELOCITY[i] = INCREMENT * Sin(i * ANGLE_DIV)
set i = i + 1
endloop
call RegisterSpellEffectEvent(SPELL_ID, function thistype.create)
call Preload(VOID_EFFECT)
call Preload(WAVE_EFFECT)
call Preload(BOLT_EFFECT)
endmethod
endstruct
endlibrary