wraithseeker
Tired.
- Reaction score
- 122
The document is here, let it speak for itself.
JASS:
Knockback System By wraithseeker
v 1.05
Special Thanks to Pyrogasm and Kenny! for guiding me and helping me with this system
Credits to Vile for the knockback effects
Credits to Moyack for the ParabolaZ function
Credits to Rising_Dusk for GroupUtils
Credits to PitzerMike for IsDestructableLibrary
Credits to Cohadar for PUI
Credits to Anitarf for IsTerrainWalkable
And credits to the others who have helped me in a way or another.
Changelog v1.01
- Removed d.destroy() and changed to d.release() for PUI issues.
- Took away some silly parameters which was totally useless.
- Optimized the code.
Changelog v1.02
- Optimized code.
- Indented some code.
- Added some extra parametres.
- unit height no longer gets bugged when at the borders of the map.
Changelog v1.03
- Removed some useless struct members.
- Made method Terraincheck not public and not to take knock d for efficient purposes.
- Updated documention.
- Code now has comments and names are more friendly.
Changelog v1.04
- Used PUI text macro to shorten things.
- Removed some useless call.
Changelog v1.05
- Fixed a serious bug
A system I made that can be used for knockback spells in a variety of
applications in a map. User defined variables make it easy to give the desired
effect for any spell.
requires
- A vJASS preprocessor (JNGP).
- The special effects found in the import/export section of this map.
They are the "Dust.mdx" for land, "SlideWater.mdx" for water, "TornadoMissle.mdx" for air and "DustAndRocks.mdx" for collision on cliffs.
- GroupUtils, PUI, IsDestructableLib, IsTerrainWalkable
Pros
- Can support many kind of stuffs you want in a knockback
- Leak free and efficient
- Made in vJASS
- Uses only a single timer and not many
- Knockback is realistic
- Allows you to knock a unit at a constant speed
- Knock a unit while flying with a ParabolaZ
- Allows Chain knockbacks which is not found here
- You can use a constant knockback speed if you do not want any increment or decrement
- You can increase your knockback speed instead of decreasing for dashing spells mainly.
Cons
- requires 4 library
Other Information
- Angle is taken in Radians. But can easily be changed if you know how.
- Units will stop when they reach the map borders.
- Remember to import the special effect into your map if you need them else it would look really plain.
- There are five functions that can be used in this system and more will be added soon if I have the time.
Finding the Distances
- This is some general knowledge on how to calculate the distance with a formula.
The Formula to calculate the distance.
= -1 * V * V / (2 * A / Interval)
Variable V = The initial speed of the knocked unit which must be positive.
Variable A = The decrement of the speed per Interval which must be negative.
Variable Interval = The timer period that function Update runs, known as TIME in the globals block.
For example, we have initial speed value as 1000 and decrement as 15 and we subsitute them into the formula
-1 * 1000 * 1000 / (2 * -15 / 0.03) = 1000 distance
Note that the default timer interval is 0.03 and it is reccomended that you do not change it at all.
Implementation:
- First off you need JNGP known as JassNewGenPack which is a modified world editor.
- Create a new trigger and then convert it to custom text and then you copy paste
the code into the trigger.
- Now you will either need to export the special effects from this map to
special effects found in this map.
- Once you have the effects in your map. Find the configuration block
that is underneath all this green text. Change the paths of the effect
to the path in the system.
It is not recommended if you do not know much about importing or exporting to change the paths
else just use the paths in the system.
- Save a map and then see if you get any errors, if you do not have it, then congratulations,
you have successfully brought the system over to your map.
NOTE: Please report any bugs to me at thehelper.net via PM. (Username: wraithseeker)
Usage
call KnockbackTargetEx(source,t,angle,speed,decrement,increment,KillTree,AllowMove,ConstantSpeed,chain,Fly,Increase)
Source = The unit who started the knockback.
Target = The unit that will be used in the knockback.
Angle = The angle that the unit will be knocked back.
For example Atan2(cy-y,cx-x)
X is the coordinate of unit Target
Y is the coordinate of unit Target
CX is the coordinate of unit source
CY is the coordinate of unit source
Decrement = The speed decrement every interval.
Increment = The Increment speed of the unit target per interval, usually you should set it to 0 or null
unless you have boolean increment set to true.
ChainHeight = The amount of height the unit target can have before it stops chaining units and killing trees
Meaning if a unit reaches a certain height lets say 200, chaining and killing trees will be disabled but
before it reaches 200, chaining and killing trees are enabled.
MaxHeight = The maximum height you want a unit to have while in the air, leave this to 0 if you want
the system to count it for you. Best left alone.
Tree = This boolean will decide whether you want the unit target to knock down trees or not
Move = This boolean will decide whether you want the unit target to move while getting knocked back.
ConstantSpeed = This boolean will decide whether you want the unit target to move at a constant speed or not.
Chain = This boolean will decide whether you want the unit target to chain knock units or not.
Fly = This boolean will decide whether you want the unit target to fly while getting knocked back
and pathing will be disabled.
Increase = This boolean will decide whether you want to increase the unit target speed per interval.
Example of Usage
call KnockbackTargetEx(t,u,a,1000.00,15.00,0,true,false,false,true,true,false)
call KnockbackTargetEx(source,t,angle,800,20,0,true,false,false,true,true,false)
The first one will cause the target unit of a spell to be knocked back 1000 distance away using the formula
and it will have decrement speed of 15 per interval. There is no Increment as boolean Increment is set to
false. boolean KillTree is set to true so trees will be killed and the unit will not be allowed to move due
to the boolean AllowMove being set to false. Units will be chained and they will also fly but not increase
their speed.
The second one will cause the target unit of a spell to be knocked back 480 distance away using the formula
and it will have decrement speed of 20 per interval. There is no Increment as boolean Increment is set to
false. boolean KillTree is set to true so trees will be killed and the unit will not be allowed to move due
to the boolean AllowMove being set to false. Units will be chained and they will also fly but not increase
their speed.
Other functions
call IsKnockedBack(Target)
This function checks if the unit is currently sliding using this
system. It will return true if it is.
call IsUnitSliding(Target)
This function will stop the unit from sliding (using this system).
It also returns true if the unit is stopped.
These functions can be used in conjunction with each other, by checking if a
unit is sliding then stopping it if it is.
The System
JASS:
library Knockback initializer Init requires DestructableLib, IsTerrainWalkable, GroupUtils, PUI
globals
private constant real TIME = 0.03 // The timer interval.
private constant real CHAINRADIUS = 100.00 // The radius a unit can get chained when near the unit target.
private constant real SPEEDFACTOR = 0.75 // How much speed will be reduced when a unit chains another unit.
private constant real RADIUS = 128.00 // The radius to check tree.
private constant real HEIGHTLEVEL = 200.00 // The default height level that stops chaining or killing trees when in the air.
private constant real FACTOR = 0.3333 // Or 0.25 for smoothness.
private constant string GROUND = "MDX\\Dust.mdx" // The effect for ground.
private constant string WATER = "MDX\\SlideWater.mdx" // The effect for water.
private constant string COLLISION = "MDX\\DustAndRocks.mdx" // The effect when at cliff
private constant string FLYING = "MDX\\TornadoMissile.mdx"// The effect when flying
private constant string ATTACHPOINT = "origin" // The attachment point for effects
endglobals
globals
private integer array Knocker
private integer Count = 0
private constant integer INVULNERABLE = 039;Avul039;
private constant integer FLYID = 039;Amrf039;
private timer Timer = null
private rect TreeRect = null
private boolexpr TreeCheck = null
private boolexpr ChainFilter = null
private unit Target = null
private unit Source = null
private real MapMaxX = 0
private real MapMaxY = 0
private real MapMinX = 0
private real MapMinY = 0
endglobals
private function CheckTrees takes nothing returns boolean
return IsDestructableTree(GetFilterDestructable())
endfunction
private function Trees takes nothing returns nothing
call KillDestructable(GetEnumDestructable())
endfunction
private function ChainCheck takes nothing returns boolean
return Target != GetFilterUnit() and IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(Source)) and IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND) == true and IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) == false and GetWidgetLife(GetFilterUnit()) > 0.405 and GetUnitAbilityLevel(GetFilterUnit(),INVULNERABLE) <= 0
endfunction
function ParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)
endfunction
private function IsPointOutside takes real x, real y returns boolean
return (x > MapMaxX or y > MapMaxY or x < MapMinX or y < MapMinY)
endfunction
public struct Knock
//! runtextmacro PUI()
unit source = null
unit target = null
integer mode = 0
group hit = null
real cos = 0
real sin = 0
real speed = 0
real decrement = 0
real distance = 0
real movedistance = 0
real cspeed = 0
real icspeed = 0
real maxheight = 0
real chainheight = 0
effect effects = null
boolean terrain = false
boolean trees = false
boolean allowmove = false
boolean constantspeed = false
boolean chain = false
boolean fly = false
boolean increase = false
method TerrainCheck takes nothing returns integer
local real x = GetUnitX(this.target)
local real y = GetUnitY(this.target)
if IsTerrainWalkable(x + 50.00 * this.cos,y + 50.00 * this.sin) == false then
return 3
else
if IsTerrainPathable(x,y,PATHING_TYPE_FLOATABILITY) then
return 1
elseif not IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) then
return 2
endif
endif
return 0
endmethod
static method create takes unit source, unit target, real angle, real speed, real decrement, real increment, real maxheight, real chainheight, boolean tree, boolean move, boolean constantspeed, boolean chain, boolean fly, boolean increase returns Knock
local Knock d = Knock.allocate()
set d.source = source
set d.target = target
set d.trees = tree
set d.fly = fly
set d.icspeed = increment
set d.maxheight = maxheight
set d.chainheight = chainheight
set d.constantspeed = constantspeed
set d.cspeed = speed
set d.allowmove = move
set d.chain = chain
set d.movedistance = 0
set d.hit = NewGroup()
set d.speed = speed * TIME
set d.decrement = decrement * TIME
set d.sin = Sin(angle)
set d.cos = Cos(angle)
set d.distance = -1 * speed * speed / (2 * -decrement / TIME)
if d.fly == true then
call SetUnitPathing(d.target,false)
call UnitAddAbility(d.target,FLYID)
call UnitRemoveAbility(d.target,FLYID)
set d.effects = AddSpecialEffectTarget(FLYING,d.target,ATTACHPOINT)
else
set d.mode = d.TerrainCheck()
if d.mode == 1 then
set d.effects = AddSpecialEffectTarget(GROUND,d.target,ATTACHPOINT)
elseif d.mode == 2 then
set d.effects = AddSpecialEffectTarget(WATER,d.target,ATTACHPOINT)
elseif d.mode == 3 then
set d.effects = AddSpecialEffectTarget(COLLISION,d.target,ATTACHPOINT)
endif
endif
return d
endmethod
method onDestroy takes nothing returns nothing
call DestroyEffect(this.effects)
call ReleaseGroup(this.hit)
call SetUnitPathing(this.target,true)
endmethod
endstruct
private function Update takes nothing returns nothing
local Knock d = 0
local Knock c = 0
local unit t = null
local real x = 0.00
local real y = 0.00
local real cx = 0.00
local real cy = 0.00
local integer mode = 0
local integer i = Count - 1
local real height = 0
loop
exitwhen i < 0
set d = Knocker<i>
set mode = d.mode
set d.movedistance = d.movedistance + d.speed
set x = GetUnitX(d.target)
set y = GetUnitY(d.target)
set height = GetUnitFlyHeight(d.target)
if d.chainheight == 0 then
if height >= HEIGHTLEVEL then
set d.chain = false
set d.trees = false
endif
else
if height >= d.chainheight then
set d.chain = false
set d.trees = false
endif
endif
if d.speed <= 0 or IsPointOutside(x,y) then
call d.release()
set Knocker<i> = Knocker[Count]
call SetUnitFlyHeight(d.target,0,0)
if i < 0 then
call PauseTimer(Timer)
set Count = 0
else
set Knocker<i> = Knocker[Count]
endif
else
if d.constantspeed == true then
set x = x + d.cspeed * d.cos
set y = y + d.cspeed * d.sin
else
if d.increase == true then
set x = x + d.cspeed * d.cos
set y = y + d.cspeed * d.sin
else
set x = x + d.speed * d.cos
set y = y + d.speed * d.sin
endif
endif
if d.allowmove == true then
call SetUnitX(d.target,x)
call SetUnitY(d.target,y)
else
call SetUnitPosition(d.target,x,y)
endif
if d.trees == true then
call SetRect(TreeRect,x-RADIUS,y-RADIUS,x+RADIUS,y+RADIUS)
call EnumDestructablesInRect(TreeRect,TreeCheck,function Trees)
endif
if d.fly == true then
if d.maxheight == 0 then
call SetUnitFlyHeight(d.target,ParabolaZ(FACTOR*d.distance,d.distance,d.movedistance),0)
else
call SetUnitFlyHeight(d.target,ParabolaZ(d.maxheight,d.distance,d.movedistance),0)
endif
else
set d.mode = d.TerrainCheck()
if d.mode == 1 and (mode == 2 or mode == 3) then
call DestroyEffect(d.effects)
set d.effects = AddSpecialEffectTarget(GROUND,d.target,ATTACHPOINT)
elseif d.mode == 2 and (mode == 1 or mode == 3) then
call DestroyEffect(d.effects)
set d.effects = AddSpecialEffectTarget(WATER,d.target,ATTACHPOINT)
elseif d.mode == 3 and (mode == 1 or mode == 2) then
call DestroyEffect(d.effects)
set d.effects = AddSpecialEffectTarget(COLLISION,d.target,ATTACHPOINT)
endif
endif
if d.chain == true then
set Target = d.target
set Source = d.source
call GroupEnumUnitsInRange(ENUM_GROUP,x,y,CHAINRADIUS,ChainFilter)
loop
set t = FirstOfGroup(ENUM_GROUP)
exitwhen t == null
if not IsUnitInGroup(t,d.hit) then
set cx = GetUnitX(t)
set cy = GetUnitY(t)
call GroupAddUnit(d.hit,t)
set c = Knock.create(d.source,t,Atan2(cy-y,cx-x),(d.speed/TIME)*SPEEDFACTOR,(d.decrement/TIME),d.icspeed,d.maxheight,d.chainheight,d.trees,d.allowmove,d.constantspeed,d.chain,d.fly,d.increase)
call GroupAddUnit(c.hit,d.target)
set Knocker[Count] = c
set Count = Count + 1
endif
call GroupRemoveUnit(ENUM_GROUP,t)
endloop
endif
if d.increase == true then
set d.cspeed = d.cspeed + d.icspeed
endif
set d.speed = d.speed - d.decrement
endif
set i = i - 1
endloop
set t = null
endfunction
function KnockbackStop takes unit target returns boolean
local Knock d = Knock[target]
local integer i = Count - 1
if d != 0 then
call d.release()
set Knocker<i> = Knocker[Count]
if i <= 0 then
call PauseTimer(Timer)
endif
return true
endif
return false
endfunction
function IsKnockedBack takes unit target returns boolean
return Knock[target] != 0
endfunction
function KnockbackTargetEx takes unit source, unit target, real angle, real speed, real decrement, real increment,real maxheight,real chainheight, boolean tree, boolean move, boolean constantspeed,boolean chain,boolean fly,boolean increase returns boolean
local Knock d = 0
if target == null or source == null or speed == null or decrement == null then
debug call BJDebugMsg("Invalid Values!")
return false
endif
set d = Knock.create(source,target,angle,speed,decrement,increment,maxheight,chainheight,tree,move,constantspeed,chain,fly,increase)
set Knock[target] = d
if Count == 0 then
call TimerStart(Timer,TIME,true,function Update)
endif
set Knocker[Count] = d
set Count = Count + 1
return true
endfunction
function KnockbackTarget takes unit source, unit target, real angle, real speed, real decrement, boolean tree returns nothing
call KnockbackTargetEx(source,target,angle,speed,decrement,0,0,0,tree,false,false,false,false,false)
endfunction
function KnockbackTargetFly takes unit source, unit target, real angle, real speed, real decrement, boolean tree, boolean fly returns nothing
call KnockbackTargetEx(source,target,angle,speed,decrement,0,0,0,tree,false,false,false,fly,false)
endfunction
function KnockbackTargetFlyEx takes unit source, unit target, real angle, real speed, real decrement, real increment, real maxheight,real chainheight,boolean tree, boolean move, boolean constantspeed, boolean chain, boolean increase returns nothing
call KnockbackTargetEx(source,target,angle,speed,decrement,increment,maxheight,chainheight,tree,move,constantspeed,chain,true,increase)
endfunction
function KnockbackChain takes unit source, unit target, real angle, real speed, real decrement, boolean tree returns nothing
call KnockbackTargetEx(source,target,angle,speed,decrement,0,0,0,tree,false,false,true,false,false)
endfunction
function KnockbackConstant takes unit source, unit target, real angle, real speed, real decrement, boolean tree returns nothing
call KnockbackTargetEx(source,target,angle,speed,decrement,0,0,0,tree,false,true,false,false,false) // note, use the formula to calculate the distance that it is going to reach
endfunction
function KnockBackIncrease takes unit source, unit target, real angle, real speed, real increment, real decrement, boolean tree returns nothing
call KnockbackTargetEx(source,target,angle,speed,decrement,increment,0,0,tree,false,false,false,false,true)
endfunction
private function Init takes nothing returns nothing
set Timer = CreateTimer()
set TreeRect = Rect(0.00,0.00,1.00,1.00)
set TreeCheck = Filter(function CheckTrees)
set ChainFilter = Filter(function ChainCheck)
set MapMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set MapMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set MapMinX = GetRectMinX(bj_mapInitialPlayableArea)
set MapMinY = GetRectMinY(bj_mapInitialPlayableArea)
endfunction
endlibrary </i></i></i></i>