////////////////////////////////////////////////////////////////////
// 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_ANCIENT)) and (IsUnitEnemy(u, pl)) and (GetUnitTypeId(u) != MC_DummyID()) and not(IsUnitType(u, UNIT_TYPE_DEAD) or GetUnitTypeId(u) == 0)
endfunction
////////////////////////////////////////////////////////////////////
// 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]
loop
exitwhen (Node == 0) or (udg_MC_Unit[Node] == u)
set Node = udg_MC_NextNode[Node]
endloop
set udg_MC_Delay[Node] = 0.
set udg_MC_Angle[Node] = udg_MC_AngleLimit[Node]
endfunction
////////////////////////////////////////////////////////////////////
// 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()
else
return angle
endif
endfunction
////////////////////////////////////////////////////////////////////
// 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()
endif
return (boundary - angle >= -MC_CleaveAngleLet() and boundary2 - angle <= MC_CleaveAngleLet())
else
if boundary2 >= MC_AngleCorrection() and angle < boundary then
set angle = angle + MC_AngleCorrection()
endif
return (boundary2 - angle >= -MC_CleaveAngleLet() and boundary - angle <= MC_CleaveAngleLet())
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// 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
loop
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)
endif
else
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)
loop
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()
endif
//Within the correct arc
if (MC_ValidateAngle(udg_MC_Angle[Node], angle, angle2)) then
set bool = true
//Damage unit and setup knockback data
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()
else
set angle2 = angle2 + MC_KnockbackCleaveAngle()
endif
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())
//*********************************************
endif
endif
call GroupRemoveUnit(udg_MC_TempGroup, u)
endloop
//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
endif
//Move Position
set udg_MC_Angle[Node] = angle
endif
else
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]
endif
endif
set Node = udg_MC_NextNode[Node]
endloop
endfunction
////////////////////////////////////////////////////////////////////
// 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 (WARK: Here I changed the condition check)
if ( not (( GetRandomInt(1, 5) <= 2 )) and (( GetUnitTypeId(GetAttacker()) == 'noga' ) or ( GetUnitTypeId(GetAttacker()) == 'okod' ) or ( GetUnitTypeId(GetAttacker()) == 'nba2' )) ) then
//Get unit and check for multiple channels
set u = GetAttacker()
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
else
set udg_MC_RecyclableNodes = udg_MC_RecyclableNodes - 1
set Node = udg_MC_RecycleNodes[udg_MC_RecyclableNodes]
endif
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)
endif
//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
else
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
endif
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_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)
endif
return false
endfunction
////////////////////////////////////////////////////////////////////
// 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_ATTACKED)
call TriggerAddCondition(t, Condition(function MC_StartCleave))
endfunction
////////////////////////////////////////////////////////////////////
//END OF THE SPELL //
////////////////////////////////////////////////////////////////////