- Joined
- Nov 22, 2006
- Messages
- 1,260
Knockback(Ex)
By: Silvenon
Credits to:
- Diablo-dk - minor performance improvements
- PurplePoot - various improvements
Fixes:
- renamed UnitKnockback/UnitKnockback_Execute into Knockback/Knockback_Execute (actually made Execute public)
- removed UnitKnockbackWithLightning, found out it's useless
- optimized the performance, it only uses Jass NewGen Pack now
- added KnockbackEx function
- changed the parameters a bit, added new feature(s)
- uses initializer Init_Knockback, so no map initialization trigger is required anymore
- this version actually works
- doesn't use the stupid CheckPathability function anymore
- has a different system instead
- added instructions for GUI users
- removed the CSSafety requirement
- renamed Knockback_Init function
- added a new radius feature (look in the parameter explanation)
- removed the Data returnage, PP was right, it can only screw things up
- modified the code, so now it uses create and onDestroy methods, I hope it's more readable now
JASS:
library Knockback initializer Init
// **************************************************************************
// ** **
// ** Knockback(Ex) **
// ** ————————————— **
// ** **
// ** A function made for efficient knockbacking **
// ** **
// ** By: Silvenon **
// ** **
// **************************************************************************
//=======================================//
//Credits to PitzerMike for this function//
//=======================================//
globals
private constant integer DUMMY_ID = 'h000'
endglobals
private function TreeFilter takes nothing returns boolean
local destructable d = GetFilterDestructable()
local boolean i = IsDestructableInvulnerable(d)
local unit u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY_ID, GetWidgetX(d), GetWidgetY(d), 0)
local boolean result = false
call UnitAddAbility(u, 'Ahrl')
if i then
call SetDestructableInvulnerable(d, false)
endif
set result = IssueTargetOrder(u, "harvest", d)
call RemoveUnit(u)
if i then
call SetDestructableInvulnerable(d, true)
endif
set u = null
set d = null
return result
endfunction
//===========================================================================
globals
private timer Tim = CreateTimer()
private integer Total = 0
private boolexpr Cond = null
private integer array Ar
private boolean array BoolAr
private real MAX_X
private real MAX_Y
private real MIN_X
private real MIN_Y
endglobals
private constant function Interval takes nothing returns real
return 0.04
endfunction
private function KillTree takes nothing returns nothing
if BoolAr[0] then
call KillDestructable(GetEnumDestructable())
else
set BoolAr[1] = true
endif
endfunction
public struct Data
unit u
real d1
real d2
real sin
real cos
real r
string s = ""
effect e = null
static method create takes unit u, integer q, real d, real a, real r, integer t, string s, string p returns Data
local Data dat = Data.allocate()
set dat.u = u
set dat.d1 = 2 * d / (q + 1)
set dat.d2 = dat.d1 / q
set dat.sin = Sin(a)
set dat.cos = Cos(a)
set dat.r = r
if s != "" and s != null then
if t == 2 then
if p != "" and p != null then
set dat.e = AddSpecialEffectTarget(s, u, p)
else
set dat.e = AddSpecialEffectTarget(s, u, "chest")
endif
elseif t == 1 then
set dat.s = s
endif
endif
call SetUnitPosition(u, GetUnitX(u), GetUnitY(u))
call PauseUnit(u, true)
if Total == 0 then
call TimerStart(Tim, Interval(), true, function Data.Execute)
endif
set Total = Total + 1
set Ar[Total - 1] = dat
return dat
endmethod
static method Execute takes nothing returns nothing
local Data dat
local integer i = 0
local real x
local real y
local rect r
local real rad
loop
exitwhen i >= Total
set dat = Ar[i]
if dat.s != "" and dat.s != null then
set x = GetUnitX(dat.u)
set y = GetUnitY(dat.u)
call DestroyEffect(AddSpecialEffect(dat.s, x, y))
set x = x + dat.d1 * dat.cos
set y = y + dat.d1 * dat.sin
else
set x = GetUnitX(dat.u) + dat.d1 * dat.cos
set y = GetUnitY(dat.u) + dat.d1 * dat.sin
endif
if dat.r != 0 then
set BoolAr[0] = dat.r > 0
set rad = dat.r
if not BoolAr[0] then
set rad = rad * (-1)
endif
set r = Rect(x - rad, y - rad, x + rad, y + rad)
call EnumDestructablesInRect(r, Cond, function KillTree)
call RemoveRect(r)
set r = null
endif
if (x < MAX_X and y < MAX_Y and x > MIN_X and y > MIN_Y) and not BoolAr[1] then
call SetUnitX(dat.u, x)
call SetUnitY(dat.u, y)
endif
set dat.d1 = dat.d1 - dat.d2
if dat.d1 <= 0 or (x > MAX_X or y > MAX_Y or x < MIN_X or y < MIN_Y) or BoolAr[1] then
set Ar[i] = Ar[Total - 1]
set Total = Total - 1
call dat.destroy()
endif
set i = i + 1
endloop
if Total == 0 then
call PauseTimer(Tim)
endif
endmethod
method onDestroy takes nothing returns nothing
if .e != null then
call DestroyEffect(.e)
endif
call PauseUnit(.u, false)
set BoolAr[0] = false
set BoolAr[1] = false
endmethod
endstruct
function KnockbackEx takes unit u, real d, real a, real w, real r, integer t, string s, string p returns nothing
call Data.create(u, R2I(w / Interval()), d, a, r, t, s, p)
endfunction
function Knockback takes unit u, real d, real a, real w returns nothing
call Data.create(u, R2I(w / Interval()), d, a, 0, 0, "", "")
endfunction
private function Init takes nothing returns nothing
set Cond = Filter(function TreeFilter)
set BoolAr[0] = false
set BoolAr[1] = false
set MAX_X = GetRectMaxX(bj_mapInitialPlayableArea) - 64
set MAX_Y = GetRectMaxY(bj_mapInitialPlayableArea) - 64
set MIN_X = GetRectMinX(bj_mapInitialPlayableArea) + 64
set MIN_Y = GetRectMinY(bj_mapInitialPlayableArea) + 64
endfunction
endlibrary
Are you getting tired of writing a knockback code every single time when you want to knockback something? If the answer is yes, then this is what you need. This function knockbacks a unit according to the parameters below:
- unit u = the unit being knockbacked
- real d = the distance the unit is knockbacked to
- real a = the angle (direction of the knockback) in RADIANS
- real w = the duration of the knockback
- real r = the radius of tree destroying, but there's a new trick: if you put a negative number as the radius, the unit will stop knockbacking when it gets in that range of a tree and if you put a positive value, the unit will destroy trees when it gets in that range of a tree (if you don't want any of those, just put 0)
- integer t = type 0 means no effect (both s and p should be ""), type 1 means periodic effect (meaning you should put "" as the attachment point, parameter p), type 2 means a special effect attached on the unit and destroyed when the knockback is finished (this is where you use parameter p)
- string s = the path to the special effect you want to use (periodic), that effect will be destroyed immediatelly (you can put "" if you don't want a special effect)
- string p = used for type 2, it's the attachment point of the effect, "chest" is default (so if you put "", it will be "chest")
Instructions:
Create a dummy unit according to one of these two tutorials: 1, 2 (I suggest the second one). You MUST change the DUMMY_ID constant integer to that unit's id.
You can deprivate any function from the library you want to use, I just made it like that so it doesn't interfere with other stuff. If you don't want any special effects and tree destroying, you can use Knockback function that takes only the first 4 parameters.
If you by any chance have angle in degrees and want to use it for this function, when calling the function just multiply that angle with bj_DEGTORAD, example:
call Knockback(u, d, a * bj_DEGTORAD, w)
You can change the interval of execution in the Knockback_Interval constant (default is 0.035).
Example of usage:
[jass=JASS]function Test takes nothing returns nothing
local unit c = GetTriggerUnit()
local unit t = GetSpellTargetUnit()
local real x1 = GetUnitX(c)
local real y1 = GetUnitY(c)
local real x2 = GetUnitX(t)
local real y2 = GetUnitY(t)
local real dist = 500
local real angle = Atan2(y2 - y1, x2 - x1)
local real dur = 2
call Knockback(t, dist, angle, dur)
set c = null
set t = null
endfunction[/code]
[trigger=GUI]Test
Events
Unit - A unit starts the effect of an ability
Conditions
(Ability being cast) Equal to <Some Spell>
Actions
Set Caster = (Triggering unit)
Set Target = (Target unit of ability being cast)
Set Distance = (400 + (100 x (Ability level of <Some Spell> for Caster)))
Set Angle = (Facing angle of Caster)
Set Duration = 2
Custom script: call Knockback(udg_Target, udg_Distance, udg_Angle * bj_DEGTORAD, udg_Duration)[/trigger]
On the same principle you use the KnockbackEx function
Requires: Jass NewGen Pack
Find more about the function in my Knockback tutorial
Please report any errors.
Last edited: