Massive Cleave V1.01

This bundle is marked as approved. It works and satisfies the submission rules.
[TD]Massive Cleave[/TD]

Q - Massive Cleave
Cleaves enemies in an arc in front of the caster sending them flying in terror

Level 1 - 100 damage, small area
Level 2 - 120 damage, medium area
Level 3 - 140 damage, large area

//                     MASSIVE CLEAVE V1.01                       //
//  Author: Tank-Commander                                        //
//  Purpose: A powerful keepaway ability for scaring opposition   //
//                                                                //
//  Requires:                                                     //
//    - (optional) BUS_Knockback by Tank-Commander                //
//      remove lines outlined by "******" in code if not used     //
//                                                                //
//  Notes:                                                        //
//    -  Read the readme before you try modifying the config      //
//    -  Use the "Helpful files" to help you import the system    //
//                                                                //
//  Credits:                                                      //
//    -  (Dummy.mdl) Vexorian                                     //
//                                                                //
//  If you have used this spell in your map, you are required     //
//  to give credits to Tank-Commander for the creation of it      //
//  If you would like to use snippets of code from this for       //
//  whatever, getting permission and crediting the source/linking //
//  would be much appreciated.                                    //

//  README:                                                       //
//    Before modifying this spell a few things need to be         //
//    understood and read, this is one of those things, while     //
//    most modification can be considered intuitive, it still     //
//    helps to read through these intstructions, as they will     //
//    inform you about how to configure this spell to your        //
//    desire.                                                     //
//  Initial importing: The variable creator trigger can be        //
//  imported first and if you have the correct settings (file,    //
//  preferences, General, automatically create unknown variables  //
//  checked, then when you paste in the variable creator it       //
//  will automatically give you all the variables you need for    //
//  this spell                                                    //
//                                                                //
//  While the remaining object editor based data is not required  //
//  to function (provided they're replaced with equivelents)      //
//  it's recommended that they are also imported, if their data   //
//  value are not the same as listed in the configuration, those  //
//  configurables will need to be changed to work correctly       //
//                           MISC                                 //
//  TimerSpeed: the time in seconds between each iteration of     //
//  the main loop function (default is 0.031250000) it's          //
//  recommended you leave it like that                            //
constant function MC_TimerSpeed takes nothing returns real
    return 0.031250000
//  Ability: This is the data value of the ability used as the    //
//  base, make sure it is based off channel (to view raw data     //
//  press ctrl + d, pressing again switches back)                 //
constant function MC_Ability takes nothing returns integer
    return 'A000'
//  DummyID: This is the data value of the unit to be used as the //
//  dummy for blood effects generated by the cleave               //
constant function MC_DummyID takes nothing returns integer
    return 'u000'
//  OrderID: This is the order ID used by the ability to tell if  //
//  the unit is still channelling the ability and cancelling it   //
//  if it stops (852474 is default for 1.28)                      //
constant function MC_OrderID takes nothing returns integer
    return 852473
//  Attachmentpoint: This is the location on the Dummy unit that  //
//  blood effects will be placed on                               //
constant function MC_AttachmentPoint takes nothing returns string
    return "origin"
//  Clockwise: Determines what direction the cleave will take     //
//  (set it to match the handedness of the unit(s) using the      //
//  ability, righthanded: anticlockwise, lefthanded: clockwise    //
constant function MC_Clockwise takes nothing returns boolean
    return false
//  Timer: How long in seconds dummy units are alive for          //
constant function MC_Timer takes nothing returns real
    return 3.
//  DummyPlayer: The owning player of the dummy units             //
constant function MC_DummyPlayer takes nothing returns player
    return Player(14)
//  AttackType: The attack type used when dealing damage         //
constant function MC_AttackType takes nothing returns attacktype
//  DamageType: The damage type used when dealing damage          //
constant function MC_DamageType takes nothing returns damagetype
//                        MAIN ABILITY                            //
//  AOE: The Area around the caster that the cleave reaches       //
function MC_AOE takes real level returns real
    return 250 + (25 * level)
//  EffectDistance: How far away from the caster blood effects    //
//  are created
function MC_EffectDistance takes real level returns real
    return 150 + (25 * level)
//  Angle: The angle covered by the cleave (radians) bj_PI = 90   //
//  degrees, it will eb centered around the unit facing angle     //
function MC_Angle takes real level returns real
    return 1.7 + (0.26 * level)
//  Divisions: This is the amount of segments in your cleave      //
//  it's recommended to have at least 3 for all levels            //
function MC_Divisions takes real level returns real
    return 2 + (1 * level)
//  HealthDamage: The amount of damage your cleave deals to       //
//  the health of units hit                                       //
function MC_HealthDamage takes real level returns real
    return 80 + (20 * level)
//  ManaDamage: The amount of damage your cleave deals to the     //
//  mana of units hit                                             //
function MC_ManaDamage takes real level returns real
    return 0.
//  InitialDelay: The time after starting the ability that the    //
//  first cleave segment is used and units are hit in seconds     //
function MC_InitialDelay takes real level returns real
    return .20 + (-0.01 * level)
//  DivisionDelay: The time between each cleave segment being     //
//  used and units getting hit in seconds                         //
function MC_DivisionDelay takes real level returns real
    return 0.04 + (-0.01 * level)
//  KnockbackForce: The force at which units are hit by the       //
//  cleave (only relevent to knockback and not damage)            //
function MC_KnockbackForce takes real level returns real
    return 50 + (10 * level)
//  KnockbackCleaveAngle: This is the angle taken from straight   //
//  forward that units are knocked back in (positive values       //
//  lead to the unit getting pushed in the direction of the       //
//  cleaver)                                                      //
constant function MC_KnockbackCleaveAngle takes nothing returns real
    return  bj_PI / 3
//  PitchCalcVal: The hit height of the cleaver on target units   //
//  (used to work out their angle when launched, higher values    //
//  result in more steep arcs but may need more KnockbackForce    //
//  to be effective)                                              //
constant function MC_PitchCalcVal takes nothing returns real
    return 200.
//  CleaveHitEffect: The effect created when the cleaver hits     //
//  a unit successfully                                           //
constant function MC_CleaveHitEffect takes nothing returns string
    return "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
//  CleaveHitScale: The size of the effect created when the       //
//  cleave hits a unit successfully (1 = 100% model size)         //
constant function MC_CleaveHitScale takes real level returns real
    return 1 + (0.2 * level)
//  FilterMaxZ: The Highest fly height a unit can have while      //
//  still being considered a valid target                         //
constant function MC_FilterMaxZ takes nothing returns real
    return 0.01
//  CleaveAngleLet: Added to angles to compensate for floating    //
//  point arithmetic errors (read-only)                           //
constant function MC_CleaveAngleLet takes nothing returns real
    return 0.01
//  AngleCorrection: Used to convert negative angles into         //
//  positive ones (read-only)                                     //
constant function MC_AngleCorrection takes nothing returns real
    return bj_PI * 2
//                      END OF CONFIGURATION                      //

//  Target filter function used to differentiate between units    //
//  that can be hit by the spell and those that cannot            //
function MC_TargetFilter takes unit u, player pl returns boolean
    return (not IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (GetUnitFlyHeight(u) <= MC_FilterMaxZ()) and (not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)) and (IsUnitEnemy(u, pl)) and (GetUnitTypeId(u) != MC_DummyID()) and not(IsUnitType(u, UNIT_TYPE_DEAD) or GetUnitTypeId(u) == 0)

//  Check cleave function used ot prevent two channels being done //
//  by the same unit at the same time                             //
function MC_CheckCleave takes unit u returns nothing
    local integer Node = udg_MC_NextNode[0]
        exitwhen (Node == 0) or (udg_MC_Unit[Node] == u)
        set Node = udg_MC_NextNode[Node]
    set udg_MC_Delay[Node] = 0.
    set udg_MC_Angle[Node] = udg_MC_AngleLimit[Node]

//  AbsAngle function used to convert negative angles (rads) into //
//  positive angles (rads), standardises angles so formulas can   //
//  be used effectively                                           //
function MC_AbsAngle takes real angle returns real
    if angle < 0. then
        return angle + MC_AngleCorrection()
        return angle
//  Validate Angle function used to check if a given unit is      //
//  within the boundaries of the current cleave segment           //
function MC_ValidateAngle takes real boundary, real boundary2, real angle returns boolean

    //Check what direction the cleave is going in
    //And then check if the angle is within the two boundaries
    if MC_Clockwise() then
        if boundary <= 0 and angle < boundary2 then
            set angle = angle - MC_AngleCorrection()
        return (boundary - angle >= -MC_CleaveAngleLet() and boundary2 - angle <= MC_CleaveAngleLet())
        if boundary2 >=  MC_AngleCorrection() and angle < boundary then
            set angle = angle + MC_AngleCorrection()
        return (boundary2 - angle >= -MC_CleaveAngleLet() and boundary - angle <= MC_CleaveAngleLet())
    return false

//  Loop function used to control the cleave, damaging units      //
//  knocking them in the air and creating effects                 //
function MC_MassiveCleaveLoop takes nothing returns nothing
    //Set up Locals
    local integer Node = udg_MC_NextNode[0]
    local real angle
    local real angle2
    local real tempReal
    local real x
    local real y
    local real x2
    local real y2
    local real dy
    local real dx
    local boolean bool
    local unit u
    //Cycle through each node
        exitwhen Node == 0
        //Check if it's time to create another cleave point
        if udg_MC_Delay[Node] < MC_TimerSpeed() then
            //Check if the cleave is finished
            if (udg_MC_Angle[Node] >= (udg_MC_AngleLimit[Node] - MC_CleaveAngleLet()) and not(MC_Clockwise())) or ((udg_MC_Angle[Node] <= (udg_MC_AngleLimit[Node] + MC_CleaveAngleLet())) and MC_Clockwise()) then
                set udg_MC_RecycleNodes[udg_MC_RecyclableNodes] = Node
                set udg_MC_RecyclableNodes = udg_MC_RecyclableNodes + 1
                set udg_MC_NextNode[udg_MC_PrevNode[Node]] = udg_MC_NextNode[Node]
                set udg_MC_PrevNode[udg_MC_NextNode[Node]] = udg_MC_PrevNode[Node]
                //Pause timer if this was the last instance
                if (udg_MC_PrevNode[0] == 0) then
                    call PauseTimer(udg_MC_Timer)
                set x = GetUnitX(udg_MC_Unit[Node])
                set y = GetUnitY(udg_MC_Unit[Node])
                set bool = false
                set udg_MC_Delay[Node] = udg_MC_DelayReset[Node]
                set angle = udg_MC_Angle[Node] + udg_MC_Division[Node]

                //Find units to cleave
                call GroupEnumUnitsInRange(udg_MC_TempGroup, x, y, udg_MC_AOE[Node], null)
                    set u = FirstOfGroup(udg_MC_TempGroup)
                    exitwhen u == null
                    //Valid target type
                    if  MC_TargetFilter(u, udg_MC_Player[Node]) then
                        set x2 = GetUnitX(u)
                        set y2 = GetUnitY(u)
                        set dy = y2 - y
                        set dx = x2 - x
                        set angle2 = Atan2(dy, dx)

                        if angle2 < 0. then
                            set angle2 = angle2 + MC_AngleCorrection()
                        //Within the correct arc
                        if (MC_ValidateAngle(udg_MC_Angle[Node], angle, angle2)) then
                            set bool = true
                            //Damage unit and setup knockback data
                            call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - udg_MC_ManaDamage[Node])
                            call UnitDamageTarget(udg_MC_Unit[Node], u, udg_MC_HealthDamage[Node], true, false,  MC_AttackType(), MC_DamageType(), null)

                            //Knockback (delete if not using BUS_Knockback)
                            if MC_Clockwise() then
                                set angle2 = angle2 - MC_KnockbackCleaveAngle()
                                set angle2 = angle2 + MC_KnockbackCleaveAngle()

                            set tempReal = SquareRoot(dx * dx + dy * dy)

                            call BUS_StartKnockback(u, udg_MC_KnockbackForce[Node], x2 + tempReal * Cos(angle2), x2, y2 + tempReal * Sin(angle2), y2, 0., MC_PitchCalcVal())
                    call GroupRemoveUnit(udg_MC_TempGroup, u)
                //Create blood effect if a unit was hit
                if bool then
                    //Find position
                    set angle2 = udg_MC_Angle[Node] + udg_MC_AngleAdjust[Node]
                    //Create effect
                    set u = CreateUnit(MC_DummyPlayer(), MC_DummyID(), x + udg_MC_EffectDistance[Node] * Cos(angle2), y + udg_MC_EffectDistance[Node] * Sin(angle2), angle2 * bj_RADTODEG)
                    call SetUnitScale(u, udg_MC_CleaveScale[Node], 0., 0.)
                    call DestroyEffect(AddSpecialEffectTarget(MC_CleaveHitEffect(), u, MC_AttachmentPoint()))
                    call UnitApplyTimedLife(u, 'BHwe', MC_Timer())
                    set u = null
                //Move Position
                set udg_MC_Angle[Node] = angle

            set udg_MC_Delay[Node] = udg_MC_Delay[Node] - MC_TimerSpeed()
            if not(GetUnitCurrentOrder(udg_MC_Unit[Node]) == MC_OrderID()) then
                set udg_MC_Delay[Node] = 0.
                set udg_MC_Angle[Node] = udg_MC_AngleLimit[Node]
        set Node = udg_MC_NextNode[Node]

//  Function used to start the channel process when the abiliyt   //
//  has been cast                                                 //
function MC_StartCleave takes nothing returns boolean
    //Set up locals
    local integer Node
    local real level
    local real offset
    local real facing
    local unit u
    //Start the channel
    if (GetSpellAbilityId() == MC_Ability()) then
        //Get unit and check for multiple channels
        set u = GetTriggerUnit()
        call MC_CheckCleave(u)
        //Set up Node
        if (udg_MC_RecyclableNodes == 0) then
            set udg_MC_NodeNumber = udg_MC_NodeNumber + 1
            set Node = udg_MC_NodeNumber
            set udg_MC_RecyclableNodes = udg_MC_RecyclableNodes - 1
            set Node = udg_MC_RecycleNodes[udg_MC_RecyclableNodes]

        set udg_MC_NextNode[Node] = 0
        set udg_MC_NextNode[udg_MC_PrevNode[0]] = Node
        set udg_MC_PrevNode[Node] = udg_MC_PrevNode[0]
        set udg_MC_PrevNode[0] = Node
        //Start timer if this is the only instance
        if (udg_MC_PrevNode[Node] == 0) then
            call TimerStart(udg_MC_Timer, MC_TimerSpeed(), true, function MC_MassiveCleaveLoop)
        //Set up cleave data
        set udg_MC_Unit[Node] = u
        set udg_MC_Player[Node] = GetTriggerPlayer()
        set level = GetUnitAbilityLevel(udg_MC_Unit[Node], MC_Ability())
        set facing = GetUnitFacing(udg_MC_Unit[Node]) * bj_DEGTORAD
        set offset = MC_Angle(level)

        if MC_Clockwise() then
            set udg_MC_Division[Node] = offset / -MC_Divisions(level)
            set offset = offset / 2
            set udg_MC_AngleLimit[Node] = MC_AbsAngle(facing + offset)
            set udg_MC_Angle[Node] = udg_MC_AngleLimit[Node] - offset * 2
            set udg_MC_Division[Node] = offset / MC_Divisions(level)
            set offset = offset / -2
            set udg_MC_Angle[Node] = MC_AbsAngle(facing + offset)
            set udg_MC_AngleLimit[Node] = udg_MC_Angle[Node] - offset * 2
        set udg_MC_AOE[Node] = MC_AOE(level)
        set udg_MC_EffectDistance[Node] = MC_EffectDistance(level)
        set udg_MC_AngleAdjust[Node] = (udg_MC_Division[Node] / 2)
        set udg_MC_HealthDamage[Node] = MC_HealthDamage(level)
        set udg_MC_ManaDamage[Node] = MC_ManaDamage(level)
        set udg_MC_Delay[Node] = MC_InitialDelay(level)
        set udg_MC_DelayReset[Node] = MC_DivisionDelay(level)
        set udg_MC_KnockbackForce[Node] = MC_KnockbackForce(level)
        set udg_MC_CleaveScale[Node] = MC_CleaveHitScale(level)

    return false

//  Function used to register the trigger of the ability          //
function InitTrig_Massive_Cleave takes nothing returns nothing
    //Set up local variables
    local trigger t = CreateTrigger()

    //Set up trigger
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function MC_StartCleave))
//END OF THE SPELL                                                //

Spell Information

- 478 lines of pure JASS
- 25 Configurables reaching all aspects of the ability
- Throw enemies miles
- Feel the power
- Cleft thy foes in twain
- Uses BUS Knockback systems to make the code significantly shorter
- Extensive Readme to help you configure the ability
- Doesn't interfere with game scorescreen
- Compatible with Vanilla WE
- Functions for ground and flying heroes (though I wouldn't suggest it for fliers generally)
- Arcs are stable on uneven terrain
- Features can be adapted to your liking due to the configuration including complete removal
- Attractive yet functional
- Makes your big monsters actually a bit more intimidating instead of oversized footmen
- Comes with omnipresent Mr. Fluffy and his entourage of Tanks
Tips and Tricks

- You don't really need this, a massive cleaver is pretty straight forward
- Aim to hit as many as possible
- Run if enemy has it
Helpful Files

- Variable Creator: Copy and paste into your map, you now have all the variables needed for the spell to run
- Comes with the variable creators for the relevant parts of the used systems
  • Variable Creator
    • Events
    • Conditions
    • Actions
      • Set MC_AOE[0] = 0.00
      • Set MC_Angle[0] = 0.00
      • Set MC_AngleAdjust[0] = 0.00
      • Set MC_AngleLimit[0] = 0.00
      • Set MC_CleaveScale[0] = 0.00
      • Set MC_Delay[0] = 0.00
      • Set MC_DelayReset[0] = 0.00
      • Set MC_Division[0] = 0.00
      • Set MC_EffectDistance[0] = 0.00
      • Set MC_HealthDamage[0] = 0.00
      • Set MC_KnockbackForce[0] = 0.00
      • Set MC_ManaDamage[0] = 0.00
      • Set MC_NextNode[0] = 0
      • Set MC_NodeNumber = 0
      • Set MC_Player[0] = Player 1 (Red)
      • Set MC_RecyclableNodes = 0
      • Set MC_RecycleNodes[0] = 0
      • Set MC_TempGroup = MC_TempGroup
      • Set MC_Timer = MC_Timer
      • Set MC_Unit[0] = No unit







- Added note for updated OrderID if used in 1.28
- Added a variable missing from the variable creator onto it
- Added channel checking to prevent both multiple casts and allow interrupts to work properly
- Corrected "*****" border
- Loop slightly restructured to match channel checking
- Slight efficiency improvements
- Initial Upload


Cleave, Mash, AOE, Knockback, Cleft, Brain not necessary, Powertrip, intimidation, thy foe, who being naughty in My sight, shall snuff it.[/tr]

Massive Cleave V1.01 (Map)

4th Apr 2016 Your resource has been reviewed by BPower. In case of any questions or for reconfirming the moderator's rating, please make use of the Quick Reply function of this thread. Review: The cleaving effect works out perfectly with...




4th Apr 2016

General Info

Your resource has been reviewed by BPower.
In case of any questions or for reconfirming the moderator's rating,
please make use of the Quick Reply function of this thread.

The cleaving effect works out perfectly with the unit animation.
I can imagine it beeing used for example as a boss / semi-boss ability.
The knockback brings in an unpredictable apsect to any fight. Doubtless an amazing spell!

Decent configuration options, great coding and documentation. I couldn't ask for more.
Approved with a rating of 5/5, Highly Recommended.


  • Nothing

Review changelog:
  1. -





Interesting and quite useful, great job, as always!
You mean forcing them to play the animation? I had considered it but there's select few models it works well with (footman, archer, units that fall backwards for example) but terribly on others (huntress, knight, units that fall forward & units that explode/other animation that makes no sense when knocked back) - it also wouldn't change anything if the stun option for BUS Knockback was set to false; hence why I chose not to in the end
Level 22
Feb 6, 2014
This got approved so fast but I already checked it out so here are my thoughts
  • I fail to see the purpose of MC_DivisionDelay, isn't configuring this the same as configuring the timeout?
  • This part
        if MC_Clockwise() then
            set angle2 = angle2 - MC_KnockbackCleaveAngle()
            set angle2 = angle2 + MC_KnockbackCleaveAngle()
        set tempReal = Pow(dx * dx + dy * dy, 0.5)
        set x = x2 + tempReal * Cos(angle2)
        set y = y2 + tempReal * Sin(angle2)
    should be included in the things to be deleted when not using the Knockback.
  • SquareRoot is faster than Pow(base, 0.5) according to the Math Library by lfh.
  • R2I in real level is unnecessary.
  • local integer Node = 0 should not be initialized, the next code execution after the locals declaration will literally overwrite integer Node anyway. Or you could make it local integer Node = udg_MC_NextNode[Node] and then move set Node = udg_MC_NextNode[Node] before endloop
  • You could use GetUnitX, GetUnitY (periodically) on the caster instead of storing the casting location because currently, it will cleave units in the casting position so if the caster is instantly moved by some other spell which involve moving while in the middle of the cleave, the cleaving will continue from the casting position instead from the caster's current location.
  • Also, you could make the Node instance immediately end when the caster stops channeling the cleave. Because if the caster is stunned while in the middle of the cleave, the cleaving still continues.
Level 19
Mar 18, 2012
Hats off! These are aspects I didn't consider.
I definitly agree on storing the casters location and the current order comparison.

As these are non critical issues I suggest we leave the resource status approved.
I guess you'll update as soon as you find the time for it.
I fail to see the purpose of MC_DivisionDelay, isn't configuring this the same as configuring the timeout?
It's a bit different - it's easier to notice if the division delay is high but essentially it times the difference between each hit in the cleave - obviously if the value is lower than the timerspeed then it results in a delay the same as the timeout but if greater results in a Ceiling(Delay / TimerSpeed) gap between each part of the cleave (works well with units with slow animations)

- I'll update the markers to include the other parts, won't take long

- I'll change Pow() to SquareRoot then
- I don't recall any part of the code using R2I?
- I'm not sure if that's the case, I have experience of the linked list failing if Node is not initialised to 0 (though initialising it NextNode[0] and moving the iteration line would work perfectly well)

- I can see the use of it, would be a matter of weighing realistic speed of the cleave vs the likelyhood of moving and the efficiency of getting those values periodically (it may also require the introduction of more local variables given that it's a value used pretty often) I'll look into it
- I'll add the option to end the instance when the channel ends, it'll be pretty fast to implement
Level 2
Aug 18, 2016
Hi first of all thanks for this awesome spell which was needed more than anything for WC3,
im trying to transfer this spell to my map for usage and i do transfer all spells effects and dummy unit plus triggers, but it wont work! when i do disable "Massive Cleave" trigger and try to enable it again i get this error:

call BUS_StartKnockback(u, udg_MC_KnockbackForce[Node], x2 + tempReal * Cos(angle2), x2, y2 + tempReal * Sin(angle2), y2, 0., MC_PitchCalcVal())

please help
Level 2
Aug 18, 2016
here bro, thanks for trying to help

found anything?


  • test.w3x
    52.3 KB · Views: 39
Last edited by a moderator:
Level 2
Aug 18, 2016
oh! so u did check the trigger and it was working perfectly? :eek:
i did used JNGP once but right now for testing i have used normal editor!
Level 1
Oct 24, 2019
A very rad spell, i have a problem tho, cant seem to get it work, i decided to delete it because the heroes in my map dont deal damage anymore after the spell, i deleted everything from the dummy to the triggers and the effects, still my heroes deal no damage, i put in so much work into that map and it saved like that , i have no backup SOS