• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

KnockBackUtils and KnockBackUtilsEx

Level 7
Joined
Apr 27, 2011
Messages
272
Im currently updating the system again...

Just a simple knockback system that has a special extension that adds an "OnKnockBack" pseudo-event which is a great help for making spells.

KnockBackUtils:
JASS:
library KnockBackUtils //optional KnockBackUtilsEx
//===========================================================================
// KnockBackUtils Module by Alain.Mark
//
//	-Info-
//	 -Just another simple knockback code.
//
//	-API-
//	 -function KnockBackUnit takes unit whichUnit, real distance, real speed, real angle returns integer
//
//===========================================================================

	//=======================================================================
	// configurables
	//=======================================================================
		globals
			private constant timer KNOCKBACK_UTILS_TIMER=CreateTimer()
			private constant real KNOCKBACK_UTILS_TIMER_TICK=0.025
		endglobals
	
//===========================================================================
// 
//===========================================================================
	globals
		private integer o
		private real 	ux
		private real 	uy
		private real	uz
	endglobals
	
//===========================================================================
	globals
		private integer n=-1
	endglobals
	
//===========================================================================
	globals
		private unit array uQ
		private real array dQ
		private real array vQ
		private real array aQ
		private real array vxQ
		private real array vyQ
		//! runtextmacro optional KnockBackUtilsEx_Globals()
	endglobals
	
//===========================================================================
	globals
		private real MIN_X
		private real MIN_Y
		private real MAX_X
		private real MAX_Y
	endglobals
	
//===========================================================================
	private function Pathable takes real x, real y returns boolean
		return IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) and x>MIN_X and y>MIN_Y and x<MAX_X and x<MAX_Y
	endfunction
	
//===========================================================================
	private function OnLoop takes nothing returns nothing
		set o=n
		loop
			exitwhen o<0
			if(dQ[o]>0.00)then
				set ux=GetUnitX(uQ[o])+vxQ[o]
				set uy=GetUnitY(uQ[o])+vyQ[o]
				if(Pathable(ux,uy))then
					call SetUnitX(uQ[o],ux)
					call SetUnitY(uQ[o],uy)
					set dQ[o]=dQ[o]-vQ[o]
				else
					set dQ[o]=0.00
				endif
				//! runtextmacro optional KnockBackUtilsEx_FireCode()				
			else
                call SetUnitPathing(uQ[o],false)
				set uQ[o]=uQ[n]
				set dQ[o]=dQ[n]
				set vQ[o]=vQ[n]
				set aQ[o]=aQ[n]
				set vxQ[o]=vxQ[n]
				set vyQ[o]=vyQ[n]
				//! runtextmacro optional KnockBackUtilsEx_QueueSwap()
				set n=n-1
				if(n<0)then
					call TimerStart(KNOCKBACK_UTILS_TIMER,0.00,true,null)
				endif
			endif
			set o=o-1
		endloop
	endfunction
	
//===========================================================================
	function KnockBackUnit takes unit u, real d, real v, real a returns integer
		set n=n+1
		set uQ[n]=u
		set dQ[n]=d
		set vQ[n]=v*KNOCKBACK_UTILS_TIMER_TICK
		set aQ[n]=a
		set vxQ[n]=(v*KNOCKBACK_UTILS_TIMER_TICK)*Cos(a*0.01745)
		set vyQ[n]=(v*KNOCKBACK_UTILS_TIMER_TICK)*Sin(a*0.01745)
		//! runtextmacro optional KnockBackUtilsEx_execQToFalse()
        call SetUnitPathing(u,false)
		if(n==0)then
			call TimerStart(KNOCKBACK_UTILS_TIMER,KNOCKBACK_UTILS_TIMER_TICK,true,function OnLoop)
		endif
		return n
	endfunction
	
//===========================================================================
	//! runtextmacro optional KnockBackUtilsEx_Plugins()
	
//===========================================================================
	private module m
		private static method onInit takes nothing returns nothing
			set MIN_X=GetCameraBoundMinX()
			set MIN_Y=GetCameraBoundMinY()
			set MAX_X=GetCameraBoundMaxX()
			set MAX_Y=GetCameraBoundMaxY()
		endmethod
	endmodule
	private struct s
		implement m
	endstruct
	
//===========================================================================
endlibrary

KnockBackUtilsEx:
JASS:
library KnockBackUtilsEx
//===========================================================================
// KnockBackUtilsEx by Alain.Mark
//
// -Info-
//	-This extension module will add more functionalities to KnockBackUtils.
//
// -API- (added to KnockBackUtils)
//	-function OnKnockBackAction takes integer whichInstance, code c returns nothing
//	-function GetKnockBackInstance takes nothing returns integer
//	-function GetKnockBackUnit takes nothing returns nothing
//
//===========================================================================
	//! textmacro KnockBackUtilsEx_Globals
		private trigger array trgQ
		private boolean array execQ
	//! endtextmacro
	
//===========================================================================
	//! textmacro KnockBackUtilsEx_FireCode
		if(execQ[o])then
			call TriggerExecute(trgQ[o])
		endif
	//! endtextmacro
	
//===========================================================================
	//! textmacro KnockBackUtilsEx_QueueSwap
		set trgQ[o]=trgQ[n]
		set execQ[o]=execQ[n]
	//! endtextmacro
	
//===========================================================================
	//! textmacro KnockBackUtilsEx_execQToFalse
		set execQ[n]=false
	//! endtextmacro
	
//===========================================================================
	//! textmacro KnockBackUtilsEx_Plugins
		function OnKnockBack takes integer i, code c returns nothing
			if(trgQ[i]==null)then
				set trgQ[i]=CreateTrigger()
			else
				call TriggerClearActions(trgQ[i])
			endif
			set execQ[i]=true
			call TriggerAddAction(trgQ[i],c)
		endfunction
		
		function GetKnockBackInstance takes nothing returns integer
			return o
		endfunction
		
		function GetKnockBackUnit takes nothing returns unit
			return uQ[o]
		endfunction
		
	//! endtextmacro
	
//===========================================================================
endlibrary

Sample usage of the extension:
JASS:
 private function SomeCode takes nothing returns nothing
	local integer i=GetKnockBackInstance()
	call BJDebugMsg(someString[i]) // removes the requirement of unit indexing. (in this situation only)
 endfunction
 
 private function SomeFunctionName returns nothing
	...
	local integer knockback_instance=KnockBackUnit(someUnit,dist,speed,angle)
	
	// this is the purpose why the "KnockBackUnit" function returns an integer because
	// you can utilize it for making spells and stuff once coupled with "OnKnockBackAction":
	set someString[knockback_instance]="Hello World!!! :D"
	
	call OnKnockBack(knockback_instance,function SomeCode) 
	// "SomeCode" will be executed while "someUnit" is being knockbacked
 endfunction
 
Last edited:
Level 7
Joined
Apr 27, 2011
Messages
272
Your pathing check does not consider collision sizes.

You could use the custom Inferno ability that I used in the GUI Knockback 2D if you want the ultimate vJass knockback system.

what would happen if i didn't consider collision sizes? :O

btw is there any way to check terrain pathability without using items and GetLocationZ???? I just scanned my code and i realized that my pathing check was actually useless.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Look at http://www.hiveworkshop.com/forums/spells-569/knockback-2d-203180/ like I suggested. You simply set the ability level of the custom Inferno to the approximate collision size of the unit (I use 16, 32, 48 and 64 by default) and if the IssuePointOrderById function returns true the terrain is pathable for that collision size.

However, Wards may work the same way (I haven't checked) but while considering trees in their pathing.
 
Level 7
Joined
Apr 27, 2011
Messages
272
Oh yes wards i thought of them once but i don't want to constantly summon or move a another unit... I'll just use a constant collision size of 16 and 64. And oh, It doesn't make sense to me that you use 32 and 48 when you can just consider 16 as the MIN collision and 64 as the MAX collision.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
No, having four ability levels gives the greatest fluidity of collision (the right size collision for the right size unit) and protection against being squeezed into normally too-narrow passages thus blocking any potential for exit. And you can't just always assume the worst (64) because then you run into events where normal units like size 24 and 32 can't fit into regular places.

You don't need to summon the units, you simply set the casting-time of the ability to something obscene. The order-issuing native will fire regardless of whether the ability is actually going to end up being cast.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Well you could do something like an PollPointByCollision function that takes x, y, collision and either embed it or put it in another resource, though you should probably do an //! external command to create the object editor data because it needs 4 ability levels pointing to 4 units (you can use the same units I did if you want which were peasant, paladin, infernal and centaur giant)
 
private constant real KNOCKBACK_UTILS_TIMER_TICK=0.025

Using 0.031250000 is more optimal :/
40 FPS gives +25% better visuals (theoretically speaking), but 32 FPS is already great enough.

As for the extension, I recommend using TriggerAddCondition and TriggerEvaluate instead.
Actions are about 3x slower than conditions.
You'd just have to call Filter(c) to convert the code to a boolexpr
 
Last edited:
Level 7
Joined
Apr 27, 2011
Messages
272
maybe add support for attaching models while getting knockbacked?

Hehehehe. :p that's the use of the "KnockBackUtilsEx" module.

JASS:
	function AddEffectsWhileBeingKnockBacked takes nothing returns nothing
		call DestroyEffect(AddSpecialEffectTarget(GetKnockBackUnit(),SOME_EFFECT,SOME_ATTACHMENT_POINT))
	endfunction
	
	function SomeFunctionName takes nothing returns nothing
		local integer i=KnockBackUnit(SomeUnit,SomeDistance,SomeSpeed,SomeAngle)
		call OnKnockBack(i,function AddEffectsWhileBeingKnockBacked) // <- see ;P
	endfunction

@Bribe, can you please make a LUA script version of the Dummy Caster unit and Pathing Checker unit you used in the Knockback 2D? if you don't mind. :)
 
Last edited:
Top