Hello. I've gotten into JASS quite recently, and currently, am working on push/knockback abilities. I think, at least, that I've gotten the hang of the ones for single units, but now, I've been trying to create a boss ability, that knocks all the units away from the caster - a mass push/knockback ability.
Eventually, I settled with this functionality:
> Units around the caster, that are alive and enemy of the caster, are placed into a group (b1KnockUnits)
> The units from the group are placed into Unit Array (using FirstOfGroup), and that array is looped through in Timer function.
I wanted to ask if using multiple loops inside a Timer Function, that is used every 0.04 secs, might cause problems, in terms of lag, for example?
Also, is there a more efficient way to do this? The ability seemingly does it's job, but it looks clumsy and awkward, especially talking about the vertical movement.
Eventually, I settled with this functionality:
> Units around the caster, that are alive and enemy of the caster, are placed into a group (b1KnockUnits)
> The units from the group are placed into Unit Array (using FirstOfGroup), and that array is looped through in Timer function.
I wanted to ask if using multiple loops inside a Timer Function, that is used every 0.04 secs, might cause problems, in terms of lag, for example?
Also, is there a more efficient way to do this? The ability seemingly does it's job, but it looks clumsy and awkward, especially talking about the vertical movement.
JASS:
function Trig_Begone_Conditions takes nothing returns boolean
if ( GetSpellAbilityId() == 'A001' ) then
return true
endif
return false
endfunction
// Condition used to find matching units for the b1KnockUnits group:
function KnockGroupConditions takes nothing returns boolean
return GetBooleanAnd((GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) <= 0) == false, IsUnitAlly(GetFilterUnit(), GetOwningPlayer(udg_FW)) == false)
endfunction
// This is the Timer function, that is used every 0.04 secs. The Ifs and Loops are all inside.
function Timer_Function takes nothing returns nothing
// Setup the local variables:
local timer Clock = GetExpiredTimer()
local real array knockAngle
local location array movePoint
local location array targetPoint
local unit u
// The integers below are used for Loops.
local integer i = 0
local integer j = 0
local integer k = 0
local integer l = 0
local integer g = 0
//> The "IF" statement below makes sure, that the commands(functions) inside that "IF" statement
//> are used only once.
if (udg_b1knockCheck < 1) then
loop
exitwhen k >= udg_b1GroupCount
call UnitAddAbility(udg_KickUnit[k], 'Amrf')
call UnitRemoveAbility(udg_KickUnit[k], 'Amrf')
call PauseUnit(udg_KickUnit[k], true)
call SetUnitPathing(udg_KickUnit[k], false)
set k = k + 1
endloop
set udg_b1knockCheck = udg_b1knockCheck + 1
endif
//> This the main part of the function - the IF statement below.
//> It checks whether b1knockN (distance travelled) is higher than Maximum distance (b1knockDistance)
//> The first part is if the condition returns true (stops the timer).
//> The second part ("else" part) is if the condition is false (resumes the action).
if (udg_b1knockN > udg_b1knockDistance) then
//> The variable below is used to check how many units fell down the cliff.
//> (Every unit, that falls down the cliff, is added to "b1ThrownU" Group)
set udg_b1Check2 = CountUnitsInGroup(udg_b1ThrownU)
// Timer is stopped and the trigger is being cleaned up:
call PauseTimer(Clock)
loop
exitwhen j >= udg_b1GroupCount
call PauseUnit(udg_KickUnit[j], false)
call SetUnitPathing(udg_KickUnit[j], true)
call SetUnitFlyHeight(udg_KickUnit[j], 0, 200.00 )
call RemoveLocation(movePoint[j])
call RemoveLocation(targetPoint[j])
set udg_KickUnit[j] = null
set j = j + 1
endloop
//> Checks if there ARE any units, that fell down the cliff (if b1Check2 > 0), and,
//> if so, tells how many.
if (udg_b1Check2 > 0) then
call DisplayTimedTextToPlayer(Player(2), 0, 0, 3, I2S(udg_b1Check2) + "|c00FF7F00 units were thrown off the Cliff!|r")
endif
// Final cleaning up:
call RemoveLocation(udg_b1knockCastPoint)
set udg_b1knockN = 0
set udg_b1knockHN = 0
set udg_b1Check2 = 0
call DestroyTimer(Clock)
call DestroyGroup(udg_b1KnockUnits)
else // The second part of the if statement
loop
//> Loop end when all the units in the unit array (KickUnit) are looped through.
//> The size (b1GroupCount) of the Group (b1KnockUnits), that the unit array was made from,
//> is used to determine how many units to loop through in total.
exitwhen i >= udg_b1GroupCount
set targetPoint[i] = GetUnitLoc(udg_KickUnit[i])
set knockAngle[i] = AngleBetweenPoints(udg_b1knockCastPoint, targetPoint[i])
set movePoint[i] = PolarProjectionBJ(targetPoint[i], 20, knockAngle[i])
call SetUnitPositionLoc(udg_KickUnit[i], movePoint[i])
//> If statement below is used to check if a unit was thrown off the cliff.
//> If yes, then that unit is killed and added to Thrown units Group (ThrownU).
//> This is done to count how many were thrown off, as stated before.
if (GetTerrainCliffLevel(GetLocationX(GetUnitLoc(udg_KickUnit[i])), GetLocationY(GetUnitLoc(udg_KickUnit[i]))) < 3) then
call KillUnit(udg_KickUnit[i])
if (IsUnitInGroup(udg_KickUnit[i], udg_b1ThrownU) == false) then
call GroupAddUnit(udg_b1ThrownU, udg_KickUnit[i])
endif
endif
call RemoveLocation(movePoint[i])
call RemoveLocation(targetPoint[i])
set i = i + 1
endloop
// The If statement (and the loops inside it) below is used to move units vertically.
if (udg_b1knockHN < 250) then
loop
exitwhen l >= udg_b1GroupCount
call SetUnitFlyHeight(udg_KickUnit[l], 40.00, 1000.00 )
set l = l + 1
endloop
set udg_b1knockHN = udg_b1knockHN + 40
else
loop
exitwhen g >= udg_b1GroupCount
call SetUnitFlyHeight( udg_KickUnit[g], ( GetUnitFlyHeight(udg_KickUnit[g]) - 40.00 ), 1000.00 )
set g = g + 1
endloop
set udg_b1knockHN = udg_b1knockHN - 40
endif
set udg_b1knockN = udg_b1knockN + 20
endif
endfunction
// The MainFunction.
function Trig_Begone_Actions takes nothing returns nothing
local timer Clock = CreateTimer()
local location B1PlayGround = GetRectCenter(gg_rct_FWBossArea)
local integer i
local integer j = 0
local integer k = 0
local unit u
set udg_b1ThrownU = CreateGroup()
set udg_b1knockCaster = GetSpellAbilityUnit()
set udg_b1knockCastPoint = GetUnitLoc(udg_b1knockCaster)
set udg_b1KnockUnits = GetUnitsInRangeOfLocMatching(500.00, udg_b1knockCastPoint, Condition(function KnockGroupConditions))
set udg_b1GroupCount = CountUnitsInGroup(udg_b1KnockUnits)
set udg_b1knockDistance = 500
set udg_b1knockCheck = 0
set udg_b1AreaHeightLevel = GetTerrainCliffLevel(GetLocationX(B1PlayGround), GetLocationY(B1PlayGround))
//> This is where units from the Group(b1KnockUnits) are placed into Unit Array (KickUnit):
set u = FirstOfGroup(udg_b1KnockUnits)
loop
exitwhen u == null
call DisplayTimedTextToPlayer(Player(2), 0, 0, 3, "a " + I2S(j))
set udg_KickUnit[j] = u
call GroupRemoveUnit(udg_b1KnockUnits, u)
set u = FirstOfGroup(udg_b1KnockUnits)
set j = j + 1
endloop
call TimerStart(Clock, 0.04, true, function Timer_Function)
endfunction
//===========================================================================
function InitTrig_Begone takes nothing returns nothing
set gg_trg_Begone = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Begone, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Begone, Condition( function Trig_Begone_Conditions ) )
call TriggerAddAction( gg_trg_Begone, function Trig_Begone_Actions )
endfunction