Omnislash v1.03
A DotA-like Omnislash, made in vJASS. Given the recent increased activity in Tinkis dated Omnislash thread, I figured I would dust off this old favorite, give it an overhall, and release it to the public.
Contains two versions. The Classic Omnislash, and an OnDamage Omnislash, which uses the heroes actual attack to deal the damage, as opposed to triggering it.
Import Difficulty: Low
Units Affected: Enemy, ground, non-structure, non-magic immune, visible
Target Type: Single unit - Enemy, ground, organic
Spell Info:
Quickly move around the battlefield, slashing many enemies. You are invulnerable for the duration. Deals between 150 and 250 damage per slash.
Level 1 - Attacks 3 times.
Level 2 - Attacks 5 times.
Level 3 - Attacks 8 times.
The Classic Omnislash requires only Timer Utils to function. The OnDamage Omnislash requires Timer Utils and IDDS (which requires Table 3.0). It also makes use of an attack speed modifying item ability, which can make the hero attack much faster when attacking during the Omnislash.
Classic:
OnDamage:
Updates:
A DotA-like Omnislash, made in vJASS. Given the recent increased activity in Tinkis dated Omnislash thread, I figured I would dust off this old favorite, give it an overhall, and release it to the public.
Contains two versions. The Classic Omnislash, and an OnDamage Omnislash, which uses the heroes actual attack to deal the damage, as opposed to triggering it.
Import Difficulty: Low
Units Affected: Enemy, ground, non-structure, non-magic immune, visible
Target Type: Single unit - Enemy, ground, organic
Spell Info:
Quickly move around the battlefield, slashing many enemies. You are invulnerable for the duration. Deals between 150 and 250 damage per slash.
Level 1 - Attacks 3 times.
Level 2 - Attacks 5 times.
Level 3 - Attacks 8 times.
The Classic Omnislash requires only Timer Utils to function. The OnDamage Omnislash requires Timer Utils and IDDS (which requires Table 3.0). It also makes use of an attack speed modifying item ability, which can make the hero attack much faster when attacking during the Omnislash.
Classic:
JASS:
scope Omnislash initializer Init
globals
private constant integer AbilId = 039;A000039;
private constant real TimerInterval = .4
private constant string BlinkFX = "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl"
private constant string CasterAttachPoint = "weapon"
private constant string CasterFX = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl"
private constant string SlashAnimation = "attack"
endglobals
private constant function MaxSlashes takes integer lvl returns integer
if lvl<3 then
return 1+2*lvl
else
return 8
endif
endfunction
private function SlashDamage takes integer lvl returns real
return GetRandomReal(150.,250.) // This can be changed to a constant function if you update it to use an equation
endfunction
private constant function TargetAoE takes integer lvl returns real
return 475.
endfunction
private constant function TargetBoolean takes unit caster, unit target returns boolean
return true
endfunction
//== No touching past this point ==\\
globals
private group G = CreateGroup()
private group OmniGroup = CreateGroup()
private unit Targ
private boolexpr B
private integer I
endglobals
private struct data
unit u
unit targ
player p
effect fx
timer t
integer lvl
integer count = 1
integer max
real aoe
method onDestroy takes nothing returns nothing
call DestroyEffect(.fx)
call ReleaseTimer(.t)
call SetUnitInvulnerable(.u,false)
call SetUnitVertexColor(.u,255,255,255,255)
call GroupRemoveUnit(OmniGroup,.u)
call SelectUnit(.u, GetLocalPlayer()==.p)
endmethod
endstruct
private function Filt takes nothing returns boolean
local data d = I
set Targ = GetFilterUnit()
if TargetBoolean(d.u,Targ) and IsUnitEnemy(Targ,d.p) and GetWidgetLife(Targ)>.405 and IsUnitType(Targ,UNIT_TYPE_STRUCTURE)==false and IsUnitType(Targ,UNIT_TYPE_MAGIC_IMMUNE)==false and not IsUnitHidden(Targ) then
return true
endif
return false
endfunction
private function DoSlash takes data d, real ang, real off returns nothing
call SetUnitPosition(d.u,GetUnitX(d.targ)+off*Cos(ang),GetUnitY(d.targ)+off*Sin(ang))
call DestroyEffect(AddSpecialEffectTarget(BlinkFX, d.u, "chest"))
call UnitDamageTarget(d.u,d.targ,SlashDamage(d.lvl), false, false, ATTACK_TYPE_HERO, DAMAGE_TYPE_NORMAL, null)
call SetUnitAnimation(d.u,SlashAnimation)
endfunction
private function Effects takes nothing returns nothing
local data d = GetTimerData(GetExpiredTimer())
set d.count = d.count + 1
call GroupClear(G)
set I = d
call GroupEnumUnitsInRange(G,GetUnitX(d.u),GetUnitY(d.u),d.aoe,B)
set d.targ = FirstOfGroup(G)
if d.targ!=null then
call DoSlash(d,GetRandomReal(1., 360.)*bj_DEGTORAD,GetRandomReal(0., 85.)+100.)
endif
if d.count>=d.max or d.targ==null then
call d.destroy()
endif
endfunction
private function Actions takes nothing returns nothing
local data d = data.create()
local real ang = GetRandomReal(1., 360.)*bj_DEGTORAD
local real off = GetRandomReal(0., 85.)+100.
set d.u = GetTriggerUnit()
set d.targ = GetSpellTargetUnit()
set d.p = GetOwningPlayer(d.u)
set d.fx = AddSpecialEffectTarget(CasterFX, d.u, CasterAttachPoint)
set d.lvl = GetUnitAbilityLevel(d.u,AbilId)
set d.max = MaxSlashes(d.lvl)
set d.aoe = TargetAoE(d.lvl)
set d.t = NewTimer()
call SetUnitInvulnerable(d.u, true)
call SetUnitVertexColor(d.u, 255, 255, 255, 100)
if GetLocalPlayer()==d.p then
call SelectUnit(d.u, false)
endif
call GroupAddUnit(OmniGroup,d.u)
call DoSlash(d,ang,off)
call SetTimerData(d.t,d)
call TimerStart(d.t, TimerInterval, true, function Effects)
endfunction
private function SpellConditions takes nothing returns boolean
if GetSpellAbilityId() == AbilId then
call Actions()
endif
return false
endfunction
private function SelectConditions takes nothing returns boolean
if IsUnitInGroup(GetTriggerUnit(),OmniGroup) and GetLocalPlayer()==GetOwningPlayer(GetTriggerUnit()) then
call SelectUnit(GetTriggerUnit(),false)
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t1 = CreateTrigger()
local trigger t2 = CreateTrigger()
local integer i = 0
loop
exitwhen i>bj_MAX_PLAYERS
call TriggerRegisterPlayerUnitEvent(t1,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
call TriggerRegisterPlayerUnitEvent(t2,Player(i),EVENT_PLAYER_UNIT_SELECTED,null)
set i = i + 1
endloop
call TriggerAddCondition(t1, Condition( function SpellConditions ))
call TriggerAddCondition(t2, Condition( function SelectConditions ))
set B = Condition(function Filt)
call Preload(BlinkFX)
call Preload(CasterFX)
endfunction
endscope
OnDamage:
JASS:
scope OnDamageOmnislash initializer Init
globals
private constant integer AbilId = 039;A000039;
private constant integer AttackSpeedId = 039;A001039;
private constant real TimerInterval = 1.5
private constant string BlinkFX = "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl"
private constant string CasterAttachPoint = "weapon"
private constant string CasterFX = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl"
endglobals
private constant function MaxSlashes takes integer lvl returns integer
if lvl<3 then
return 1+2*lvl
else
return 8
endif
endfunction
private constant function TargetAoE takes integer lvl returns real
return 475.
endfunction
private constant function TargetBoolean takes unit caster, unit target returns boolean
return true
endfunction
//== No touching past this point ==\\
private keyword data
globals
private group G = CreateGroup()
private group OmniGroup = CreateGroup()
private unit Targ
private boolexpr B
private integer I
private data array D
endglobals
private struct data
unit u
unit targ
player p
effect fx
timer t
integer lvl
integer count = 1
integer max
real aoe
method onDestroy takes nothing returns nothing
call UnitRemoveAbility(.u,AttackSpeedId)
call DestroyEffect(.fx)
call ReleaseTimer(.t)
call SetUnitInvulnerable(.u,false)
call SetUnitVertexColor(.u,255,255,255,255)
call GroupRemoveUnit(OmniGroup,.u)
call SelectUnit(.u, GetLocalPlayer()==.p)
endmethod
endstruct
private function Filt takes nothing returns boolean
local data d = I
set Targ = GetFilterUnit()
if TargetBoolean(d.u,Targ) and IsUnitEnemy(Targ,d.p) and GetWidgetLife(Targ)>.405 and IsUnitType(Targ,UNIT_TYPE_STRUCTURE)==false and IsUnitType(Targ,UNIT_TYPE_MAGIC_IMMUNE)==false and not IsUnitHidden(Targ) then
return true
endif
return false
endfunction
private function DoSlash takes data d, real ang, real off returns nothing
call SetUnitPosition(d.u,GetUnitX(d.targ)+off*Cos(ang),GetUnitY(d.targ)+off*Sin(ang))
call DestroyEffect(AddSpecialEffectTarget(BlinkFX, d.u, "chest"))
call IssueTargetOrder(d.u,"attack",d.targ)
endfunction
private function Effects takes nothing returns nothing
local data d = GetTimerData(GetExpiredTimer())
set d.count = d.count + 1
call GroupClear(G)
set I = d
call GroupEnumUnitsInRange(G,GetUnitX(d.u),GetUnitY(d.u),d.aoe,B)
set d.targ = FirstOfGroup(G)
if d.targ!=null then
call DoSlash(d,GetRandomReal(1., 360.)*bj_DEGTORAD,GetRandomReal(0., 85.)+100.)
endif
if d.count>=d.max or d.targ==null then
call d.destroy()
endif
endfunction
private function Actions takes nothing returns nothing
local data d = data.create()
local real ang = GetRandomReal(1., 360.)*bj_DEGTORAD
local real off = GetRandomReal(0., 85.)+100.
set d.u = GetTriggerUnit()
set d.targ = GetSpellTargetUnit()
set d.p = GetOwningPlayer(d.u)
set d.fx = AddSpecialEffectTarget(CasterFX, d.u, CasterAttachPoint)
set d.lvl = GetUnitAbilityLevel(d.u,AbilId)
set d.max = MaxSlashes(d.lvl)
set d.aoe = TargetAoE(d.lvl)
set d.t = NewTimer()
set D[GetHandleId(d.u)-0x100000] = d
call UnitAddAbility(d.u,AttackSpeedId)
call SetUnitInvulnerable(d.u, true)
call SetUnitVertexColor(d.u, 255, 255, 255, 100)
if GetLocalPlayer()==d.p then
call SelectUnit(d.u, false)
endif
call GroupAddUnit(OmniGroup,d.u)
call DoSlash(d,ang,off)
call SetTimerData(d.t,d)
call TimerStart(d.t, TimerInterval, false, function Effects)
endfunction
private function DamageDone takes nothing returns nothing
local data d = D[GetHandleId(GetTriggerDamageSource())-0x100000]
call PauseTimer(d.t)
call TimerStart(d.t,0.,false,function Effects)
endfunction
private function SpellConditions takes nothing returns boolean
if GetSpellAbilityId() == AbilId then
call Actions()
endif
return false
endfunction
private function SelectConditions takes nothing returns boolean
if IsUnitInGroup(GetTriggerUnit(),OmniGroup) and GetLocalPlayer()==GetOwningPlayer(GetTriggerUnit()) then
call SelectUnit(GetTriggerUnit(),false)
endif
return false
endfunction
private function DamageConditions takes nothing returns boolean
if IsUnitInGroup(GetTriggerDamageSource(),OmniGroup) then
call DamageDone()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t1 = CreateTrigger()
local trigger t2 = CreateTrigger()
local trigger t3 = CreateTrigger()
local integer i = 0
loop
exitwhen i>bj_MAX_PLAYERS
call TriggerRegisterPlayerUnitEvent(t1,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
call TriggerRegisterPlayerUnitEvent(t2,Player(i),EVENT_PLAYER_UNIT_SELECTED,null)
set i = i + 1
endloop
call TriggerRegisterDamageEvent(t3,1)
call TriggerAddCondition(t1, Condition( function SpellConditions ))
call TriggerAddCondition(t2, Condition( function SelectConditions ))
call TriggerAddCondition(t3, Condition( function DamageConditions ))
set B = Condition(function Filt)
call Preload(BlinkFX)
call Preload(CasterFX)
endfunction
endscope
Updates:
1.03
- Ported to patch 1.24+
1.02
- Minor code updates
1.01
- Changed configurable functions to constants where applicable