# [vJASS][Snippet] KnockbackTools

#### Trigger.edge

Level 9
Well another knockback system, I hope can be useful for someone

JASS:
``````library KnockbackTools uses Optimizer32, Event, DestructableLib, AutoFly
/*****************************************************************************
*
*   KnockbackTools
*   _______________
*   v1.1.1.1
*   by Thelordmarshall
*
*   Well another fucking Knockback system...
*
*   Pros:
*   _____
*   You can:
*       - Use slide speed or not.
*       - Use fly on launch targets.
*       - Create functions for loop/stop events.
*       - And more....
*
*   API:
*   ____
*   struct Knockback extends array:
*       - method launch takes real angle, real distance returns nothing
*           - Launch the target.
*   method operator:
*       - useSlideSpeed (boolean)
*       - speed (real)
*       - timerSpeed (real)
*       - arc (real)
*       - fx (string)
*       - pathing (boolean)
*       - pause (boolean)
*       - fly (boolean)
*       - hitTrees (boolean)
*
*   Functions:
*   __________
*       - function Parabola takes real arc, real d, real x returns real
*       - function ParabolicMovement takes real h, real d, real x returns real
*
*   Credits:
*   ________
*       - Nestharus: Event.
*       - PitzerMike: DestructableLib.
*       - moyackx: Parabolic formulas.
*
*****************************************************************************/

//CONFIGURATION
globals
private constant real ARC_LIMIT = 1.
private constant real RATIO     = 200.
endglobals
//ENDCONFIGURATION

function Parabola takes real arc, real d, real x returns real
return (4*arc)*(d-x)*(x/d)
endfunction

function ParabolicMovement takes real h, real d, real x returns real
local real a=-4*h/(d*d)
local real b=4*h/d
return a*x*x+b*x
endfunction

struct Knockback extends array
private static integer more=0
private static integer array list
static integer instanceData=0
static unit lastStopedUnit=null
static unit loopUnit=null
private static rect treesRect=null
private unit u
private real d1
private real d2
private real sin
private real cos
private real x
private real y
private unit kb_targetUnit
private real kb_distance
private real kb_speed
private real kb_timerSpeed
private real kb_arc
private integer kb_data
private string kb_fx
private boolean kb_collision
private boolean kb_pause
private boolean kb_slideSpeed
private boolean kb_hitTrees
private Timer32 t32

private static method destroyDelay takes nothing returns nothing
local thistype this=Timer32.getData()
set list[this]=list[0]
set list[0]=this
if .u!=null then
set lastStopedUnit=.u
set instanceData=.kb_data
call FireEvent(Knockback.EVENT_STOP)
set lastStopedUnit=null
if .kb_pause then
call PauseUnit(.u,false)
endif
if not .kb_collision then
call SetUnitPathing(.u,true)
endif
if .kb_arc>0. then
call SetUnitFlyHeight(.u,GetUnitDefaultFlyHeight(.u),0.)
endif
set .u=null
endif
set .kb_targetUnit=null
endmethod

method manualDestroy takes nothing returns nothing
call Timer32.start(this,.02,function thistype.destroyDelay)
endmethod

private static method killTrees takes nothing returns nothing
local destructable d=GetEnumDestructable()
if not IsDestructableDead(d) and IsDestructableTree(d) then
call KillDestructable(d)
endif
set d=null
endmethod

private static method onLoop takes nothing returns nothing
local thistype this=Timer32.getData()
local real x=GetUnitX(.u)
local real y=GetUnitY(.u)
local real x2
local real y2
local real a
local real d
if GetUnitTypeId(.u)!=0 then
set loopUnit=.u
call FireEvent(Knockback.EVENT_LOOP)
set loopUnit=null
if .kb_pause and not IsUnitPaused(.u) then
call PauseUnit(.u,true)
endif
if .kb_targetUnit!=null then
set x2=GetUnitX(.kb_targetUnit)
set y2=GetUnitY(.kb_targetUnit)
set a=Atan2(y2-y,x2-x)
set .cos=Cos(a)
set .sin=Sin(a)
set .kb_distance=SquareRoot(Pow(x2-.x,2)+Pow(y2-.y,2))
endif
if .kb_slideSpeed then
set x=x+.d1*.cos
set y=y+.d1*.sin
set .d1=.d1-.d2
else
set x=x+.kb_speed*.cos
set y=y+.kb_speed*.sin
endif
set d=SquareRoot(Pow(x-.x,2)+Pow(y-.y,2))
if d<=.kb_distance then
call SetUnitPosition(.u,x,y)
if (.kb_fx!=null or .kb_fx!="") then
endif
if .kb_arc>0. then
if .kb_arc>-ARC_LIMIT and .kb_arc<ARC_LIMIT then
call SetUnitFlyHeight(.u,Parabola(.kb_arc,.kb_distance,d),0.)
else
call SetUnitFlyHeight(.u,ParabolicMovement(.kb_arc,.kb_distance,d),0.)
endif
endif
if .kb_hitTrees then
call MoveRectTo(treesRect,x,y)
call EnumDestructablesInRect(treesRect,null,function thistype.killTrees)
endif
endif
if(.kb_slideSpeed and .d1<=0.)then
call .manualDestroy()
call .t32.stop()
elseif(not .kb_slideSpeed and d>=.kb_distance)then
call .manualDestroy()
call .t32.stop()
endif
else
call .manualDestroy()
call .t32.stop()
endif
endmethod

method launch takes real a, real d, real speed returns nothing
local integer q=R2I(.kb_timerSpeed/Timer32.PERIOD)
set .kb_distance=d
set .kb_speed=speed
set .x=GetUnitX(.u)
set .y=GetUnitY(.u)
set .cos=Cos(a)
set .sin=Sin(a)
if .kb_slideSpeed then
set .d1=2*d/(q+1)
set .d2=.d1/q
endif
call SetUnitPathing(.u,.kb_collision)
set .t32=Timer32.start(this,0,function thistype.onLoop)
endmethod

static method create takes unit forWhichUnit returns Knockback
local thistype this=list[0]
if this==0 then
set this=more+1
set more=this
else
set list[0]=list[this]
endif
set .u=forWhichUnit
return this
endmethod

//! textmacro kb_operator takes OPERATOR_NAME,VAR_TYPE,VAR_NAME
method operator \$OPERATOR_NAME\$= takes \$VAR_TYPE\$ \$VAR_NAME\$ returns nothing
set .kb_\$OPERATOR_NAME\$=\$VAR_NAME\$
endmethod
//! endtextmacro

//! runtextmacro kb_operator("targetUnit","unit","u")
//! runtextmacro kb_operator("data","integer","d")
//! runtextmacro kb_operator("slideSpeed","boolean","b")
////! runtextmacro kb_operator("speed","real","s")
//! runtextmacro kb_operator("timerSpeed","real","s")
//! runtextmacro kb_operator("arc","real","a")
//! runtextmacro kb_operator("fx","string","f")
///! runtextmacro kb_operator("stop","boolean","b")
//! runtextmacro kb_operator("collision","boolean","b")
//! runtextmacro kb_operator("pause","boolean","b")
//! runtextmacro kb_operator("hitTrees","boolean","b")

static method registerEvent takes boolexpr c, Event ev returns nothing
call ev.register(c)
endmethod

private static method onInit takes nothing returns nothing
set treesRect=Rect(-RATIO,-RATIO,RATIO,RATIO)
set EVENT_LOOP=CreateEvent()
set EVENT_STOP=CreateEvent()
endmethod
endstruct
endlibrary``````

#### Nestharus

Level 31
Event is deprecated in favor of Trigger

It's no longer supported in Unit Indexer and so on.

It gives you a lot of extra features and it's slightly faster than native triggers

#### Kazeon

Hosted Project: EC
Level 33
JASS:
``//Well another fucking Knockback system...``
You wrote the reason why this is not acceptable by yourself. Good.

These kind of things can be approved at spell section, but not here. So please don't waste your time, for your own good. I'm glad someone trying to improve but you are doing it at (maybe) the wrong place. Jass section is not where you gamble your luck.

#### Trigger.edge

Level 9
JASS:
``//Well another fucking Knockback system...``
You wrote the reason why this is not acceptable by yourself. Good.

These kind of things can be approved at spell section, but not here. So please don't waste your time, for your own good. I'm glad someone trying to improve but you are doing it at (maybe) the wrong place. Jass section is not where you gamble your luck.

Sure mate . I'm working on the next version ...'ll fix it, don't worry.

#### BPower

Level 19
Event is deprecated and DestructableLib is graveyarded ( both are requirements )

Pro contra of your knockback system towards Knockback3D written by Cokemonkey?
--> Tell me why we need a second knockback resource
• Better API?
• Other, more features?
• Cleaner code?
• Easy implementation and usage?
• lightweight?
• etc ....

Unnecessary operator overloading, as they do not include extra safety. You just generate not useful code here.
Why not manipulate the variables directly?

Lacking description in the configuration block. RATIO, ACR_LINIT???

The whole code could require some description aswell.

Destructable enumeration should always be optional and in best case covered in static ifs.

Also:

Knockback does not stop when hitting unpathable terrain.
SetUnitPosition saves you from out of map bounds issues, but
may look fishy ingame. Also it has a much greater computation time then SetUnitX/Y

Stick to the JPAG, when submitting code.

The way it is now, it's going directly to the graveyard.

#### Xonok

Level 21
Don't include mapbound safety in a knockback system. BoundSentinel does it better than any knockback system could.(and cheaper)

#### BPower

Level 19
BoundSentinel can fail in rare cases. WorldBounds never fails.

From all I wrote you picked out the in bounds crit?!

#### edo494

Level 23
why sending everything to graveyard("The way it is now, it's going directly to the graveyard."), thats like anything that is Need's fix should be rejected straight up.

Of course if it doesnt receive update/fix, then yea, but leave some time to people to update thier resource(Yes it has been submitted 3 months ago, but your review appeared today, not 3 months ago)

#### BPower

Level 19
I'm not moving the thread to the garveyard now. The phrase just points out that
it's not in a state for approval. I will see how the thread develops and then make a descion.

Worst user case is that imported code from a second person is not working or not easy to implement.
So what we need is
• A minimum of debug safety, with proper output format. ( Library, function , object, instance, description, [game time?])
• A minimum of basic features, so we really get what we import and not more. ( no pack )
• A maximum of optional extension for a full range API ( optional, but really nice to have )
• Understandable and well documented API
• Finally, clean and acceptable optimized code ( not talking about micro optimizing )

#### Xonok

Level 21
BoundSentinel can fail in rare cases. WorldBounds never fails.

WorldBounds is irrelevant to this. It doesn't detect when a unit leaves the map.

#### BPower

Level 19
If you compare coordinates you want to move to, it does.

I had cases where BoundSentinel failed to move in a unit, which resulted in a game crash.
If you don't believe me, just download the test map from my Missile submission and enter
PI/2 as argument for curve=.

#### Xonok

Level 21
If BoundSentinel fails to move in a unit, it's probably because the Extra value is invalid. When I set it to 0(instead of 500) it doesn't crash.

#### BPower

Level 19
Gy. We can pull this out from the Graveyard, if you decide to work on the code again.

* Well another fucking Knockback system...

Replies
3
Views
1K
Replies
24
Views
4K
Replies
3
Views
2K
Replies
39
Views
6K
Replies
50
Views
10K