Moderator
M
Moderator
05:59, 13th Aug 2013
Magtheridon96: Approved. 5/5
Good work
Magtheridon96: Approved. 5/5
Good work
library VorpalExtermination /* v1.0.0.8 by Doomlord
*************************************************************************************
*
* The Hero throws a magical shuriken that deals damage to all enemies it comes in contact with.
* If the shuriken comes in contact with an enemy hero or reaches its maximum range,
* a spinning glaive will be released for 5 seconds to deal damage in an AoE and slow enemies.
* Once the duration is up, the glaive will split into slicing blades that explode
* in a caustic finale after a short period.
*
*************************************************************************************
*
* Credits
*
* Dirac
* -----------------------
*
* Missile library
*
* Maker
* -----------------------
*
* TimedLightnings, FloatingTextArc library
*
* Garfield1337
* -----------------------
*
* UnitZ library
*
* Nestharus
* -----------------------
*
* Alloc, DummyCaster library
*
* PurgeandFire
* -----------------------
*
* SpecialEffectZ library
*
* Bribe
* -----------------------
*
* SpellEffectEvent library
*
* Infrisios
* -----------------------
*
* ArcaneGlaive_2.mdx
*
* WILL THE ALMIGHTY
* -----------------------
*
* EMPBomb.mdx
*
* Suselishe
* -----------------------
*
* Cyclon Explosion.mdx
*
*************************************************************************************
*
* */ uses /*
*
* */ Missile /* hiveworkshop.com/forums/jass-resources-412/system-missile-207854/
* */ SpecialEffectZ /* wc3jass.com/5007/snippet-addspecialeffectz/
* */ UnitZ /* hiveworkshop.com/forums/jass-resources-412/snippet-getterrainz-unitz-236942/
* */ Alloc /* hiveworkshop.com/forums/jass-resources-412/snippet-alloc-alternative-221493/
* */ TimedLightnings /* hiveworkshop.com/forums/spells-569/system-timed-lightnings-v1-0-1-1-a-205105/
* */ DummyCaster /* hiveworkshop.com/forums/jass-resources-412/snippet-dummy-caster-197087/
* */ DelayedDummyRecycler /* hiveworkshop.com/forums/submissions-414/snippet-delayeddummyrecycler-239327/
* */ optional FloatingTextArc /* hiveworkshop.com/forums/spells-569/arcing-floating-text-1-0-0-3-a-228710/
* */ optional SpellEffectEvent /* hiveworkshop.com/forums/jass-resources-412/snippet-spelleffectevent-187193/
*
************************************************************************************
*
* SETTINGS
*
*/
globals
// Ability raw code
private constant integer ABI_ID = 'A001'
// Slow ability raw code
private constant integer SLOW_ID = 'A002'
// Slow order id
private constant integer SLOW_ORDER_ID = 852075
// Height difference for missiles
private constant real HEIGHT_DIFFERENCE = 100.
// FIRST PHASE
// Primary missile model (throw phase)
private constant string PRIMARY_MISSILEFX = "Abilities\\Weapons\\GlaiveMissile\\GlaiveMissile.mdl"
// On collide model for main missile
private constant string PRIMARY_COLLIDEFX = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
// Primary attachment point
private constant string PRIMARY_ATTACHPOINT = "chest"
// Primary missile scaling
private constant real PRIMARY_MISSILE_SCALE = 1.5
// Area of Effect for throw phase
private constant real PRIMARY_AOE = 200.
// SECOND PHASE
// Secondary missile model (spin phase)
private constant string SECONDARY_MISSILEFX = "war3mapImported\\ArcaneGlaive_2.mdx"
// On collide model for spin phase
private constant string SECONDARY_COLLIDEFX = "Objects\\Spawnmodels\\Human\\HumanBlood\\HeroBloodElfBlood.mdl"
// Secondary attachment point
private constant string SECONDARY_ATTACHPOINT = "chest"
// Glaive expiration effect
private constant string SECONDARY_EXPFX = "war3mapImported\\Cyclon Explosion.mdx"
// Secondary missile scaling
private constant real SECONDARY_MISSILE_SCALE = 3.
// Glaive expiration time
private constant real EXPIRATION_TIME = 5.
/* Damage fraction for spin phase. The unit will be
damaged by main spell damage multiplied by SECONDARY_FRACTION */
private constant real SECONDARY_FRACTION = 0.25
// Damage fidelity for spin phase. Units will be damaged every DAMAGE_FIDELITY(s)
private constant real DAMAGE_FIDELITY = 0.5
// Area of Effect for spin phase
private constant real SECONDARY_AOE = 300.
// THIRD PHASE
// Tertiary missile model (spread phase)
private constant string TERTIARY_MISSILEFX = "Abilities\\Weapons\\SentinelMissile\\SentinelMissile.mdl"
// On collide model for spread phase
private constant string TERTIARY_COLLIDEFX = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
// Tertiary attachment point
private constant string TERTIARY_ATTACHPOINT = "chest"
// Final explosion model
private constant string EXPLOSIONFX = "war3mapImported\\EMPBomb.mdx"
// Explosion hit model
private constant string EXPLOSION_HITFX = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
// Explosion hit attachment point
private constant string EXPLOSION_ATTACHPOINT = "origin"
// Bonus effect
private constant string BONUSFX = "Abilities\\Spells\\Other\\Monsoon\\MonsoonBoltTarget.mdl"
// Tertiary missile scaling
private constant real TERTIARY_MISSILE_SCALE = 1.5
// Glaive spread count
private constant integer SPREAD_COUNT = 12
/* Damage fraction for spread phase. The unit will be
damaged by main spell damage multiplied by TERTIARY_FRACTION */
private constant real TERTIARY_FRACTION = 0.2
// Glaive spread max range
private constant real SPREAD_MAX_RANGE = 400.
// Inactive time for spread glaives
private constant real INACTIVE_PERIOD = 1.5
// Area of Effect for spread phase slicing
private constant real TERTIARY_AOE = 200.
// Explosion AoE for spread phase
private constant real EXPLOSION_AOE = 300.
/* Some explosion effect needs scaling and
thus we need a special technique for it */
private constant boolean SPECIAL_EXPLOSION_FX_USAGE = true
// Explosion effect scaling. Only use this if the above boolean is true.
private constant real EXPLOSION_SCALE = 5.
// ENERGY GATHER EFFECT
// Effect model
private constant string ENERGY_GATHER_FX = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
// Effect model variant
private constant string ENERGY_GATHER_FX_VAR = "Abilities\\Weapons\\VengeanceMissile\\VengeanceMissile.mdl"
// Effect when lightning orbs reach the glaive
private constant string ENERGY_GATHER_FX_FINISH = "Abilities\\Spells\\Orc\\Purge\\PurgeBuffTarget.mdl"
/* Effect orbs spawn rate per second. There must be a remainder
of 0 from the division 60/ENERGY_GATHER_SPAWN_OFFSET */
private constant integer ENERGY_GATHER_SPAWN_RATE = 12
// Effect spawn offset
private constant real ENERGY_GATHER_SPAWN_OFFSET = 400.
// Effect orbs move speed
private constant real ENERGY_GATHER_SPEED = 900.
// DAMAGE CONFIGURATION
// SLICE DAMAGE
// Attack type
private constant attacktype SLICE_ATT = ATTACK_TYPE_HERO
// Damage type
private constant damagetype SLICE_DAM = DAMAGE_TYPE_NORMAL
// Weapon type
private constant weapontype SLICE_WEA = WEAPON_TYPE_METAL_HEAVY_SLICE
// EXPLOSION DAMAGE
// Attack type
private constant attacktype EXP_ATT = ATTACK_TYPE_NORMAL
// Damage type
private constant damagetype EXP_DAM = DAMAGE_TYPE_MAGIC
// Weapon type
private constant weapontype EXP_WEA = null
endglobals
/************************************************************************************
*
* END SETTINGS
*
*/
globals
private group g = CreateGroup()
private string array s
endglobals
// Primary missile speed
private constant function GetPrimarySpeed takes integer lvl returns real
return 1440.
endfunction
// Tertiary missile speed
private constant function GetTertiarySpeed takes integer lvl returns real
return 1120.
endfunction
// Main spell damage
private constant function GetDamage takes integer level returns real
return 50. + level*100.
endfunction
// Explosion damage
private constant function GetExplosionDamage takes integer level returns real
return 100. + level*50
endfunction
// Filter out some targets
private function FilterUnit takes unit u, player casterOwner returns boolean
return /*
*/ IsUnitEnemy(u, casterOwner) and /* Target is an enemy of caster
*/ not IsUnitType(u, UNIT_TYPE_DEAD) and /* Target is not dead
*/ not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and /* Target is not immune to magic
*/ not IsUnitType(u, UNIT_TYPE_STRUCTURE) /* Target is not a structure
*/
endfunction
// Filter target for glaive release
private function FilterActivationUnit takes unit u returns boolean
return /*
*/ IsUnitType(u, UNIT_TYPE_HERO) /* Target is a Hero
*/
endfunction
// Lightning settings - set lightning types for randomizer
private function LightningSettings takes nothing returns nothing
set s[0] = "AFOD"
set s[1] = "FORK"
set s[2] = "MBUR"
set s[3] = "SPLK"
set s[4] = "DRAL"
set s[5] = "DRAM"
endfunction
// Lightning type randomizer
private function LightningRandomizer takes nothing returns string
return s[GetRandomInt(0, 5)]
endfunction
// As usual, skip this part
private struct GlaiveSpread extends array
implement Alloc
private boolean b
private real timeCounter
private real x
private real y
private real z
private Missile m
static method onPeriod takes Missile m returns boolean
local thistype this = thistype(m.data)
local unit u
local unit v
if this.b then
// Is inactive period over?
if this.timeCounter >= INACTIVE_PERIOD then
call DestroyEffect(AddSpecialEffectZ(TERTIARY_MISSILEFX, m.impact.x, m.impact.y, m.impact.z))
static if SPECIAL_EXPLOSION_FX_USAGE then
set v = Dummy.create(m.impact.x, m.impact.y, 270).unit
call SetUnitScale(v, EXPLOSION_SCALE, 0, 0)
call SetUnitZ(v, m.impact.z)
call RecycleDummyDelayedEx(v, 3, AddSpecialEffectTarget(EXPLOSIONFX, v, "origin"), false)
set v = null
call DestroyEffect(AddSpecialEffectZ(ENERGY_GATHER_FX, m.impact.x, m.impact.y, m.impact.z))
else
call DestroyEffect(AddSpecialEffectZ(EXPLOSIONFX, m.impact.x, m.impact.y, m.impact.z))
endif
call GroupEnumUnitsInRange(g, m.x, m.y, EXPLOSION_AOE, null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
if FilterUnit(u, GetOwningPlayer(m.source)) then
call DestroyEffect(AddSpecialEffectTarget(EXPLOSION_HITFX, u, EXPLOSION_ATTACHPOINT))
call UnitDamageTarget(m.source, u, GetDamage(GetUnitAbilityLevel(m.source, ABI_ID)), false, false, EXP_ATT, EXP_DAM, EXP_WEA)
endif
call GroupRemoveUnit(g, u)
endloop
call this.deallocate()
return true
else
// Create lightning links to center
if this.timeCounter == 0 then
set bj_lastCreatedLightning = AddLightningEx(LightningRandomizer(), true, this.x, this.y, this.z, m.impact.x, m.impact.y, m.impact.z)
call TimedL.P2P(bj_lastCreatedLightning, INACTIVE_PERIOD, 1, 0)
call DestroyEffect(AddSpecialEffectZ(BONUSFX, m.impact.x, m.impact.y, m.impact.z))
endif
set this.timeCounter = this.timeCounter + .031250000
endif
endif
return false
endmethod
static method onFinish takes Missile m returns boolean
set thistype(m.data).b = true
// Stop the slicing blades
set m.speed = 0
return false
endmethod
static method onCollide takes Missile m, unit justHit returns boolean
if FilterUnit(justHit, GetOwningPlayer(m.source)) then
// Damage enemies and play some extra blood effects
call UnitDamageTarget(m.source, justHit, GetDamage(GetUnitAbilityLevel(m.source, ABI_ID))*TERTIARY_FRACTION, false, false, SLICE_ATT, SLICE_DAM, SLICE_WEA)
call DestroyEffect(AddSpecialEffectTarget(TERTIARY_COLLIDEFX, justHit, TERTIARY_ATTACHPOINT))
endif
return false
endmethod
implement MissileStruct
static method onActivate takes unit caster, real x, real y, real x1, real y1 returns thistype
local thistype this = thistype.allocate()
local real r = GetTerrainZ(x, y)
local integer i = GetUnitAbilityLevel(caster, ABI_ID)
set this.timeCounter = 0
set this.b = false
set this.x = x
set this.y = y
set this.z = GetTerrainZ(x, y) + HEIGHT_DIFFERENCE
set this.m = Missile.create(x, y, this.z, Atan2(y1 - y, x1 - x), SPREAD_MAX_RANGE, GetTerrainZ(x1, y1) + HEIGHT_DIFFERENCE)
set m.source = caster
set m.model = TERTIARY_MISSILEFX
set m.scale = TERTIARY_MISSILE_SCALE
set m.collision = TERTIARY_AOE
set m.speed = GetTertiarySpeed(i)/32
set m.data = this
call launch(m)
return this
endmethod
endstruct
private struct EnergyGatherFxInstance extends array
implement Alloc
private Missile m
private integer i
private real alphaStep
static method onFinish takes Missile m returns boolean
local unit v
if thistype(m.data).i == 0 then
call DestroyEffect(AddSpecialEffectZ(ENERGY_GATHER_FX, m.impact.x, m.impact.y, m.impact.z))
else
call DestroyEffect(AddSpecialEffectZ(ENERGY_GATHER_FX_VAR, m.impact.x, m.impact.y, m.impact.z))
endif
set v = Dummy.create(m.impact.x, m.impact.y, 270).unit
call SetUnitZ(v, m.impact.z)
call SetUnitScale(v, 1.25, 0, 0)
call RecycleDummyDelayedEx(v, 2, AddSpecialEffectTarget(ENERGY_GATHER_FX_FINISH, v, "origin"), false)
set v = null
call SetUnitVertexColor(m.dummy, 255, 255, 255, 255)
call thistype(m.data).deallocate()
return true
endmethod
static method onPeriod takes Missile m returns boolean
set thistype(m.data).alphaStep = thistype(m.data).alphaStep + 255/(ENERGY_GATHER_SPAWN_OFFSET/(ENERGY_GATHER_SPEED/32))
call SetUnitVertexColor(m.dummy, 255, 255, 255, R2I(thistype(m.data).alphaStep))
return false
endmethod
implement MissileStruct
static method onActivate takes real x, real y returns thistype
local thistype this = thistype.allocate()
local real r = GetTerrainZ(x, y) + HEIGHT_DIFFERENCE
local real s = GetRandomReal(0, 2*bj_PI)
local real x1 = x + ENERGY_GATHER_SPAWN_OFFSET*Cos(s)
local real y1 = y + ENERGY_GATHER_SPAWN_OFFSET*Sin(s)
set this.m = Missile.create(x1, y1, r, Atan2(y - y1, x - x1), ENERGY_GATHER_SPAWN_OFFSET, r)
set this.i = GetRandomInt(0, 1)
set this.alphaStep = 0
if this.i == 0 then
set m.model = ENERGY_GATHER_FX
set m.scale = 1
else
set m.model = ENERGY_GATHER_FX_VAR
set m.scale = 1.5
endif
set m.speed = ENERGY_GATHER_SPEED/32
set m.data = this
call launch(m)
return this
endmethod
endstruct
private struct EnergyGatherFx extends array
private integer counter
private real dur
private real x
private real y
implement CTL
implement CTLExpire
if this.dur <= 0 then
call this.destroy()
else
if this.counter == 0 or ModuloInteger(this.counter, 60/ENERGY_GATHER_SPAWN_RATE) == 0 and this.dur >= 0.5 then
call EnergyGatherFxInstance.onActivate(this.x, this.y)
endif
set this.counter = this.counter + 1
set this.dur = this.dur - .031250000
endif
implement CTLNull
implement CTLEnd
static method onStart takes real x, real y, real duration returns thistype
local thistype this = create()
set this.counter = 0
set this.dur = duration
set this.x = x
set this.y = y
return this
endmethod
endstruct
private struct GlaiveSpin extends array
implement Alloc
private real baseDamage
private real smallDamage
private real timeCounter
private Missile m
static method onPeriod takes Missile m returns boolean
local unit u
local thistype this = thistype(m.data)
local real i = 0
// Is the duration up yet?
if this.timeCounter >= EXPIRATION_TIME then
call DestroyEffect(AddSpecialEffectZ(SECONDARY_MISSILEFX, m.impact.x, m.impact.y, m.impact.z))
call DestroyEffect(AddSpecialEffectZ(SECONDARY_EXPFX, m.impact.x, m.impact.y, m.impact.z))
// Splits the glaive into slicing blades
loop
exitwhen i >= 2*bj_PI
call GlaiveSpread.onActivate(m.source, m.impact.x, m.impact.y, m.impact.x + SPREAD_MAX_RANGE*Cos(i), m.impact.y + SPREAD_MAX_RANGE*Sin(i))
set i = i + 2*bj_PI/SPREAD_COUNT
endloop
call this.deallocate()
return true
else
// Accumulate damage for the next damage instance
set this.smallDamage = this.smallDamage + this.baseDamage*.031250000
// Do we acquire enough damage yet?
if this.smallDamage >= this.baseDamage*DAMAGE_FIDELITY then
call GroupEnumUnitsInRange(g, m.x, m.y, SECONDARY_AOE, null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
if FilterUnit(u, GetOwningPlayer(m.source)) then
call DestroyEffect(AddSpecialEffectTarget(SECONDARY_COLLIDEFX, u, SECONDARY_ATTACHPOINT))
call UnitDamageTarget(m.source, u, this.smallDamage, false, false, SLICE_ATT, SLICE_DAM, SLICE_WEA)
call DummyCaster[SLOW_ID].castTarget(GetOwningPlayer(m.source), 10 - R2I((GetWidgetLife(u)/GetUnitState(u, UNIT_STATE_MAX_LIFE))*10), SLOW_ORDER_ID, u)
endif
call GroupRemoveUnit(g, u)
endloop
set this.smallDamage = 0
endif
set this.timeCounter = this.timeCounter + .031250000
endif
return false
endmethod
implement MissileStruct
static method onActivate takes unit caster, real x, real y returns thistype
local thistype this = thistype.allocate()
local real r = GetTerrainZ(x, y)
local integer i = GetUnitAbilityLevel(caster, ABI_ID)
set this.baseDamage = GetDamage(i)*SECONDARY_FRACTION
set this.timeCounter = 0
set this.smallDamage = 0
set this.m = Missile.create(x, y, r + HEIGHT_DIFFERENCE, 0, 1, r + HEIGHT_DIFFERENCE)
set m.source = caster
set m.model = SECONDARY_MISSILEFX
set m.scale = SECONDARY_MISSILE_SCALE
set m.speed = 0
set m.data = this
call EnergyGatherFx.onStart(x, y, EXPIRATION_TIME)
call launch(m)
return this
endmethod
endstruct
private struct GlaiveThrow extends array
implement Alloc
private unit caster
private Missile m
// Shuriken at max range, activate buzzsaw
static method onFinish takes Missile m returns boolean
call DestroyEffect(AddSpecialEffectZ(PRIMARY_MISSILEFX, m.impact.x, m.impact.y, m.impact.z))
call GlaiveSpin.onActivate(m.source, m.impact.x, m.impact.y)
call thistype(m.data).deallocate()
set thistype(m.data).caster = null
return true
endmethod
static method onCollide takes Missile m, unit justHit returns boolean
if FilterUnit(justHit, GetOwningPlayer(m.source)) then
call UnitDamageTarget(m.source, justHit, GetDamage(GetUnitAbilityLevel(m.source, ABI_ID)), false, false, SLICE_ATT, SLICE_DAM, SLICE_WEA)
call DestroyEffect(AddSpecialEffectTarget(PRIMARY_COLLIDEFX, justHit, PRIMARY_ATTACHPOINT))
// Hero collision. Release buzzsaw
if FilterActivationUnit(justHit) then
call DestroyEffect(AddSpecialEffectZ(PRIMARY_MISSILEFX, m.x, m.y, m.z))
call GlaiveSpin.onActivate(m.source, m.x, m.y)
call thistype(m.data).deallocate()
set thistype(m.data).caster = null
return true
endif
endif
return false
endmethod
implement MissileStruct
private static method create takes nothing returns thistype
local thistype this = thistype.allocate()
local integer i
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local real x1
local real y1
local real a
set this.caster = GetTriggerUnit()
set i = GetUnitAbilityLevel(this.caster, ABI_ID)
set x1 = GetUnitX(this.caster)
set y1 = GetUnitY(this.caster)
set a = Atan2(y - y1, x - x1)
set this.m = Missile.create(x1 + 100*Cos(a), y1 + 100*Sin(a), GetUnitZ(this.caster) + HEIGHT_DIFFERENCE, a, SquareRoot((x - x1)*(x - x1) + (y - y1)*(y - y1)) - 100, GetTerrainZ(x, y) + HEIGHT_DIFFERENCE)
set m.source = this.caster
set m.speed = GetPrimarySpeed(i)/32
set m.model = PRIMARY_MISSILEFX
set m.collision = PRIMARY_AOE
set m.scale = PRIMARY_MISSILE_SCALE
set m.data = this
static if LIBRARY_FloatingTextArc then
call ArcingTextTag.create("|c00ECEC00 VORPAL EXTERMINATION!|r", this.caster)
endif
call launch(m)
return this
endmethod
static if not LIBRARY_SpellEffectEvent then
private static method onCast takes nothing returns boolean
if GetSpellAbilityId() == ABI_ID then
call thistype.create()
endif
return false
endmethod
endif
private static method onInit takes nothing returns nothing
local trigger t
static if LIBRARY_SpellEffectEvent then
call RegisterSpellEffectEvent(ABI_ID, function thistype.create)
else
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.onCast))
set t = null
endif
call LightningSettings()
endmethod
endstruct
endlibrary