Darthfett
Aerospace/Cybersecurity Software Engineer
- Reaction score
- 615
Death Spell
AoE
Screenshot:
Description:
While channeled, the caster will draw the souls of all nearby corpses to him. Then, once their energy has been channeled to him, he releases them upon his enemies in explosive fury.
Deals 10*(Number of Corpses) to all enemy units in the targeted area. Steals the souls of all units in a 300, 400, 500 etc range, and damages all units in a 300, 400, 500, etc range of the target point.
Deals 10*(Number of Corpses) to all enemy units in the targeted area. Steals the souls of all units in a 300, 400, 500 etc range, and damages all units in a 300, 400, 500, etc range of the target point.
-MPI
-MUI
-Leak-less
-Lag-less
-Created in vJASS
Requires:
PUI
KT2
Dummy unit - with model "Abilities\Weapons\ZigguratMissile\ZigguratMissile.mdl" (Included in Demo Map)
AoE or Point Targeting ability (Included in Demo Map)
JASS:
scope PowerBlitz initializer Init
//==================================================||
// ||
// Spell Created by Darthfett ||
// Concept by ReVolver ||
// ||
// Uses PUI and KT2 ||
// ||
// Easy to end spell, use: ||
// ||
// call PowerBlitz_Data[UNIT].release() ||
// - to finish a spell abruptly ||
// ||
//==================================================||
//You can take out the above if you like. <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile :)" loading="lazy" data-shortname=":)" />
globals
private constant integer AID_PowerBlitz = 039;A001039;
//The ability which starts the spell
private constant string CHANNEL = "shockwave"
//The order string, so that it can stop the corpses if the hero stops channeling.
private constant integer MAX_CORPSES = 10
//The maximum number of corpses that can have their souls stolen.
private constant real TIMEOUT = 0.03125
//The timer timeout. (FPS is ~32)
private constant integer UID_DUMMY = 039;visi039;
//The "souls/ghosts" that are being slid as dummy units
private constant real OFFSET = 10
//How far to slide each tick
private constant integer GHOST_TICK_COUNT_DELAY = 10
//Number of timer ticks in between each corpse spirit spaw
private constant sound SND_Start = CreateSound("Abilities\\Spells\\Demon\\SoulPreservation\\SoulPreservation.wav",false,true,false,10,10,"")
//Sound that plays during at start. Change the string to whatever you need it to be.
private constant sound SND_Damage = CreateSound("Abilities\\Spells\\Other\\Drain\\LifeDrain.wav",false,true,false,10,10,"")
//Sound that plays when damage starts. Change the string to whatever you need it to be.
private constant attacktype ATK_TYPE = ATTACK_TYPE_CHAOS
//The attack type the unit uses to damage enemies
private constant weapontype WPN_TYPE = WEAPON_TYPE_WHOKNOWS
//The weapon type the unit uses to damage enemies
private constant damagetype DMG_TYPE = DAMAGE_TYPE_UNIVERSAL
//The damage type the unit uses to damage enemies
endglobals
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == AID_PowerBlitz
endfunction
private constant function DamageAmount takes real lvl, real count returns real
return 10 * count //Count is the number of corpses.
//This is the damage to all units in the area over all the damage time.
endfunction
private constant function CorpseRange takes integer lvl returns integer
return 200 + (100 * lvl) //Range from which corpses can be picked.
endfunction
private constant function DamageRange takes integer lvl returns integer
return 200 + (100 * lvl) //Range from which / damage is dealt / units slide to from target point
endfunction
//===================DO NOT EDIT BELOW THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING====================\\
globals
private player tempown
private integer gbl_groupCount
private group tempgrp = CreateGroup()
endglobals
//What happens:
//The Caster picks a corpse every GHOST_TICK_COUNT_DELAY * TIMEOUT seconds and starts sliding it toward the caster.
//One there are either:
// 1. MAX_CORPSES corpses slid to the caster
// OR
// 2. No Corpses left in range
//It will wait 2 seconds and then the dummies will start sliding outward from the targetted point.
//The DAMAGE_PER_CORPSES is dealt over the time that the units slide.
//Features:
// Corpses will stop being picked when unit ends spell or dies, but spell will continue.
// Spirits from corpses are created at intervals, and slid to the caster
// Leakless, Lagless, MUI, MPI, etc
// Sound! <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite7" alt=":p" title="Stick Out Tongue :p" loading="lazy" data-shortname=":p" />
private function Remove takes nothing returns nothing
call KillUnit(GetEnumUnit())
endfunction
private function FiltFunc takes nothing returns boolean
if GetWidgetLife(GetFilterUnit()) < .405 and IsUnitType(GetFilterUnit(),UNIT_TYPE_MECHANICAL) == false then
set bj_groupCountUnits = bj_groupCountUnits + 1
return true
endif
return false
endfunction
private function FiltFuncDamage takes nothing returns boolean
return GetWidgetLife(GetFilterUnit()) >= .405 and IsUnitType(GetFilterUnit(),UNIT_TYPE_MECHANICAL) == false and IsUnitEnemy(GetFilterUnit(),tempown)
endfunction
private function GroupCountEnum takes nothing returns nothing
set gbl_groupCount = gbl_groupCount + 1
endfunction
private function GroupCount takes group g returns integer //Non-BJ version of CountUnitsInGroup.
set gbl_groupCount = 0
call ForGroup(g,function GroupCountEnum)
return gbl_groupCount
endfunction
public struct Data
//! runtextmacro PUI()
unit c
player p
group sliders
group slid2
integer i
real cx
real cy
real tx
real ty
real angle
integer lvl
integer ticks
integer units
static method create takes nothing returns Data
local Data d = Data.allocate()
set d.ticks = 0
set d.i = 0
set d.units = 0
set d.sliders = CreateGroup()
set d.slid2 = CreateGroup()
return d
endmethod
method onDestroy takes nothing returns nothing
//All the actual cleanup is done in .release/.destroy methods,
//so that it is possible to stop a spell whenever.
//This makes the spell very flexible
call ForGroup(this.slid2,function Remove)
call DestroyGroup(this.sliders)
call DestroyGroup(this.slid2)
set this.sliders = null
set this.slid2 = null
set this.c = null
endmethod
endstruct
private function Callback_Damage takes nothing returns boolean
local Data d = KT_GetData()
local unit fog
local real x
local real y
local real a
local real newx
local real newy
local integer i = 0
set tempown = d.p
call GroupEnumUnitsInRange(tempgrp,d.tx,d.ty,DamageRange(d.lvl),Filter(function FiltFuncDamage))
set bj_groupCountUnits = 0
call ForGroup(d.slid2,function CountUnitsInGroupEnum)
loop //Damage targets
set fog = FirstOfGroup(tempgrp)
exitwhen fog == null
call GroupRemoveUnit(tempgrp,fog)
call UnitDamageTarget(d.c,fog,(DamageAmount(d.lvl,bj_groupCountUnits) / (DamageRange(d.lvl) / OFFSET)) ,false,false,ATK_TYPE,DMG_TYPE,WPN_TYPE)
endloop
if d.ticks * OFFSET < DamageRange(d.lvl) then
set bj_groupAddGroupDest = tempgrp
call ForGroup(d.slid2,function GroupAddGroupEnum)
loop
set fog = FirstOfGroup(tempgrp)
exitwhen fog == null
call GroupRemoveUnit(tempgrp,fog)
set a = bj_DEGTORAD * ((360 / bj_groupCountUnits) * i)
set newx = d.tx + (OFFSET * d.ticks ) * Cos(a)
set newy = d.ty + (OFFSET * d.ticks ) * Sin(a)
call SetUnitX(fog,newx)
call SetUnitY(fog,newy)
set i = i + 1
endloop
else
call d.release()
return true
endif
set d.ticks = d.ticks + 1
return false
endfunction
private function DamageWait takes nothing returns boolean
local Data d = KT_GetData()
call AttachSoundToUnit(SND_Damage,d.c)
call SetSoundVolume(SND_Damage,127)
call StartSound(SND_Damage)
call KT_Add(function Callback_Damage,d,TIMEOUT)
return true
endfunction
private function Slide2Caster_Callback takes nothing returns boolean
local Data d = KT_GetData()
local unit fog
local unit newdummy
local real x
local real y
local real a
local real newx
local real newy
set bj_groupCountUnits = 0
call GroupEnumUnitsInRange(tempgrp,d.cx,d.cy,CorpseRange(d.lvl),Filter(function FiltFunc))
if GetWidgetLife(d.c) < .405 or GetUnitCurrentOrder(d.c) != OrderId(CHANNEL) then
set bj_groupCountUnits = 0
endif
set d.ticks = d.ticks + 1
if d.units * GHOST_TICK_COUNT_DELAY <= d.ticks and bj_groupCountUnits > 0 and d.units < MAX_CORPSES then //Every GHOST_TICK_COUNT_DELAY ticks it will start a new slider
set fog = FirstOfGroup(tempgrp)
set x = GetUnitX(fog)
set y = GetUnitY(fog)
set a = bj_RADTODEG * Atan2((d.cy - y), (d.cx - x)) //Angle between dummy and caster
set newdummy = CreateUnit(d.p,UID_DUMMY,x,y,a)
call GroupAddUnit(d.sliders,newdummy)
call SetUnitPathing(newdummy,false)
call RemoveUnit(fog)
set d.units = d.units + 1
endif
set bj_groupAddGroupDest = tempgrp
call ForGroup(d.sliders,function GroupAddGroupEnum)
loop
set fog = FirstOfGroup(tempgrp)
exitwhen fog == null
call GroupRemoveUnit(tempgrp,fog)
set x = GetUnitX(fog)
set y = GetUnitY(fog)
set a = Atan2((d.cy - y), (d.cx - x))
set newx = x + OFFSET * Cos(a)
set newy = y + OFFSET * Sin(a)
call SetUnitX(fog,newx)
call SetUnitY(fog,newy)
if SquareRoot((newx - d.cx)*(newx - d.cx) + (newy - d.cy)*(newy - d.cy)) <= 15 then //Distance Formula
call GroupRemoveUnit(d.sliders,fog)
call GroupAddUnit(d.slid2,fog)
endif
endloop
if (d.units >= MAX_CORPSES or bj_groupCountUnits == 0) and GroupCount(d.sliders) == 0 then
call KT_Add(function DamageWait,d,2)
set d.ticks = 0
return true
endif
set newdummy = null
return false
endfunction
private function Actions takes nothing returns nothing
local Data d = Data[GetTriggerUnit()]
local location temp = GetSpellTargetLoc()
if d == 0 then
set d = Data.create()
set Data[GetTriggerUnit()] = d
endif
//Set data
set d.c = GetTriggerUnit()
set d.p = GetOwningPlayer(d.c)
set d.cx = GetUnitX(d.c)
set d.cy = GetUnitY(d.c)
set d.tx = GetLocationX(temp)
set d.ty = GetLocationY(temp)
call RemoveLocation(temp)
set temp = null
set d.lvl = GetUnitAbilityLevel(d.c,AID_PowerBlitz)
call AttachSoundToUnit(SND_Start,d.c)
call SetSoundVolume(SND_Start,127)
call StartSound(SND_Start)
call KT_Add(function Slide2Caster_Callback,d,TIMEOUT)
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function Conditions))
call TriggerAddAction(t,function Actions)
endfunction
endscope
Attached map has the spell, dummy unit, and ability.
===========
The screenshot is not really all that great. You have to see it in action to actually see the spell.