Rotating Blades V 1.3.3

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
  • Like
Reactions: Cihparg
Hello guys...this is my 1st spell
it is mui and doesnt leak...

Rotating Blades:

A blade is trown at enemy that hovers over target, swooping in every sec and damaging target.
Duration:3 + AbilityLevel sec
Damage Per Swoop: 40 * AbilityLevel

Table from Bribe,
RegisterPlayerUnitEvent from Magtheridon96,
SpellEffectEvent from Bribe

scope RotatingBlades
        //edit the values to customize
        private integer ABILITY_CODE = 'A000'
        private integer DUMMY_UNIT_CODE = 'h000'
        private attacktype ATTACK_TYPE = ATTACK_TYPE_HERO
        private damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL
        private real LOOP_INTERVAL = 0.0315
        private real HOVER_DIST = 150
        private real HOVER_DIST_DUR_DAM = 50
        private real MOVE_SPEED = 20
        private real ROTATE_SPEED = 1.5 //in degrees
        private integer DAM_DUR = 16
        private integer HOVER_DUR = 33
        private string ATTACH_MODEL = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl" //effect when dealing damage
        private string ATTACH_POINT = "chest"
        //do not edit below
        private timer LoopTimer = CreateTimer()
    //edit the return value to change the no of times blade swoops per level
    private function NoOfSwoopsPerLevel takes integer lvl returns integer
        return 2+lvl
    //edit the return value to change the damage dealt by blade per loop
    private function DamagePerLevel takes integer lvl returns real
        return 3.0+lvl //this * DAM_DUR gives total damage per swoop
    private struct Blade
        unit blade
        unit caster
        unit target
        integer lvl
        integer dur
        integer swoops
        integer status
        real angle
        effect model
        static Blade array Data
        static integer top = 0
        static method BladeLoop takes nothing returns nothing
            local integer i = 1
            local Blade bld
            local real dist
            local real x
            local real y
            local real tx
            local real ty
            local boolean kill
                exitwhen i > top
                set kill = false
                set bld = Data[i]
                if bld.status == 2 then
                    set bld.angle = bld.angle + ROTATE_SPEED
                    set dist = HOVER_DIST
                    if bld.dur < 5 then
                        set dist = HOVER_DIST*(bld.dur)/5
                    elseif HOVER_DUR - bld.dur < 5 then
                        set dist = HOVER_DIST*(HOVER_DUR - bld.dur)/5
                    set x = GetUnitX(
                    set y = GetUnitY(
                    set bld.dur = bld.dur - 1
                    if bld.dur == 0 then
                        set bld.status = 3
                        set bld.dur = DAM_DUR
                        set bld.model = AddSpecialEffectTarget(ATTACH_MODEL,, ATTACH_POINT)
                elseif bld.status == 1 then
                    set tx = GetUnitX(
                    set ty = GetUnitY(
                    set x = GetUnitX(bld.blade)
                    set y = GetUnitY(bld.blade)
                    set bld.angle = Atan2(ty - y, tx - x)
                    set dist = MOVE_SPEED
                    if RAbsBJ(x - tx) < HOVER_DIST and RAbsBJ(y - ty) < HOVER_DIST then
                        set bld.status = 2
                        set bld.dur = HOVER_DUR
                        set bld.swoops = NoOfSwoopsPerLevel(bld.lvl)
                    set bld.dur = bld.dur - 1
                    set dist = HOVER_DIST_DUR_DAM
                    set x = GetUnitX(
                    set y = GetUnitY(
                    call UnitDamageTarget(bld.caster,, DamagePerLevel(bld.lvl), true, false, ATTACK_TYPE, DAMAGE_TYPE, null) 
                    if bld.dur == 0 then
                        set bld.swoops = bld.swoops - 1
                        set bld.status = 2
                        set bld.dur = HOVER_DUR
                        call DestroyEffect(bld.model)
                        set bld.model = null
                call SetUnitPosition(bld.blade, x + dist*Cos(bld.angle), y + dist*Sin(bld.angle))
                //call SetUnitX(bld.blade, x + dist*Cos(bld.angle))
                //call SetUnitY(bld.blade, y + dist*Sin(bld.angle))
                if IsUnitType(, UNIT_TYPE_DEAD) or bld.swoops == 0 then
                    call RemoveUnit(bld.blade)
                    call bld.destroy()
                    set Data[i] = Data[top]
                    set top = top - 1
                    if top == 0 then
                        call PauseTimer(LoopTimer)
                    set i = i + 1
        static method Create takes nothing returns boolean
            local Blade bld = .allocate()
            local unit trig = GetTriggerUnit()
            local unit tar = GetSpellTargetUnit()
            local real x = GetUnitX(trig)
            local real y = GetUnitY(trig)
            local real tx = GetUnitX(tar)
            local real ty = GetUnitY(tar)
            set bld = .allocate()
            set bld.caster = trig
            set = tar
            set bld.angle = Atan2(ty - y, tx - x)
            set bld.blade = CreateUnit(GetTriggerPlayer(), DUMMY_UNIT_CODE, x, y, bld.angle)
            set bld.lvl = GetUnitAbilityLevel(bld.caster, ABILITY_CODE)
            set bld.status = 1
            set bld.dur = 1
            set bld.swoops = 1
            set top = top + 1
            set Data[top] = bld
            if top == 1 then
                call TimerStart(LoopTimer, LOOP_INTERVAL, true, function Blade.BladeLoop)
            return false
        static method onInit takes nothing returns nothing
            call RegisterSpellEffectEvent(ABILITY_CODE, function Blade.Create)

version 1.3.1:
Now uses SpellEffectEvent

version 1.3:
Changed the things suggested by bribe

version 1.2:
Converted to vJass

version 1.1:
1.Fixed leaks
2.Improved code
3.Blade damage is now gradual


Rotating Blades 1.3.1 (Map)

12th Dec 2015 IcemanBo: Too long as NeedsFix. Rejected. Update 26 April 2012 Bribe: Your map still is showing "SpellEffectEvent" instead of the spell. 5 Feb 2012 Bribe: I think your map is somehow corrupted (it shows SpellEffectEvent in place...




12th Dec 2015
IcemanBo: Too long as NeedsFix. Rejected.

Update 26 April 2012
Bribe: Your map still is showing "SpellEffectEvent" instead of the spell.

5 Feb 2012
Bribe: I think your map is somehow corrupted (it shows SpellEffectEvent in place of where your spell is supposed to be). I can't find the spell itself anywhere in your map...

Are you using any additional third party extensions like UMSWE, EGUI or WEU? You should disable them, cause your map doesn't display properly for me.
Level 37
Mar 6, 2006
The hashtable creation should be at the BladeInit trigger.

function Trig_BladesCast_Conditions takes nothing returns boolean
    if ( GetSpellAbilityId() != udg_BladeAbilityId ) then
        return false
    return true
function Trig_BladesCast_Conditions takes nothing returns boolean
        return GetSpellAbilityId() != udg_BladeAbilityId

local integer i
    call CreateNUnitsAtLoc( 1, udg_BladeUnitId, GetTriggerPlayer(), GetUnitLoc(GetTriggerUnit()), bj_UNIT_FACING )
    set i = GetHandleId( GetLastCreatedUnit() )
GetUnitLoc leaks and you could use custom function for the unit creation.


In BladeMove you could use coordinates instead of locations. If you want to use SetUnitPositionLoc, then convert the final coordinates into a location.

IsUnitDeadBJ -> GetUnitState(whichUnit, UNIT_STATE_LIFE) <= 0
ForGroupBJ -> ForGroup
Instead of CountUnitsInGroup, you could use an integer to keep track of the group's size.

0.01 is too low of a period, use 0.02 or 0.03.

And so on.

Get rid of the rest of BJ's also.

Level 29
Mar 10, 2009
I call this GUI-JASS (improved version?)...

- In JASS, we dont create too much events/actions, we merge it in 1 or two...
- Practice not using gg_trg_ instead use locals like "local trigger t = CreateTrigger()", then null it...
- Practice renaming your functions so that you can easily identify it and look beautiful and remove those horrible Trig_???
- Usually we dont use EnableTrigger nor DisableTrigger
- You should null your local variable location after you remove them, also your unit and timers(if have)...
- In GUI, StringHash is OK coz normal integer is confusing, but in JASS we usually use normal integer...
- Use coordinates instead of locations
- You should make configurables
- Usually we use Timers as handle(ofc depends on the situation)...