wraithseeker
Tired.
- Reaction score
- 122
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 ATTACHPOINT = "origin" // The attachment point for effects
endglobals
globals
private constant integer INVULNERABLE = 039;Avul039;
private constant integer FLYID = 039;Amrf039;
private rect TreeRect = null
private boolexpr TreeCheck = null
private boolexpr ChainFilter = null
private boolexpr LineFilter = null
private real MapMaxX = 0
private real MapMaxY = 0
private real MapMinX = 0
private real MapMinY = 0
endglobals
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
private interface face
method OnStart takes nothing returns nothing defaults nothing
method OnStop takes nothing returns nothing defaults nothing
method OnStopCondition takes nothing returns boolean defaults false
method OnChain takes nothing returns nothing defaults nothing
endinterface
struct Knock extends face
private static timer Timer = CreateTimer()
private static integer Count = 0
private static Knock array D
private static Knock data
//! runtextmacro PUI()
private integer mode = 0
private group hit = null
private group linehit = null
private real VariableSpeed = 0
private effect effects = null
unit source = null
unit target = null
unit dashtarget = null
integer Mode = 0
real cos = 0
real sin = 0
real speed = 0
real decrement = 0
real distance = 0
real Increment = 0
real positionZ = 0
real LineDamage = 0
string SFX = ""
string attachpoint = "origin"
location TargetPoint = null
boolean trees = false
boolean chain = false
boolean fly = false
boolean ToTarget = false
boolean Move = false
private static method CheckTrees takes nothing returns boolean
return IsDestructableTree(GetFilterDestructable())
endmethod
private static method Trees takes nothing returns nothing
call KillDestructable(GetEnumDestructable())
endmethod
private static method ChainCheck takes nothing returns boolean
local Knock d = .data
return d.target != GetFilterUnit() and IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(d.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
endmethod
private static method LineCheck takes nothing returns boolean
local Knock d = .data
return GetWidgetLife(GetFilterUnit()) > 0.405 and IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(d.source)) and GetFilterUnit() != d.source
endmethod
method TerrainCheck takes nothing returns integer
local real x = GetUnitX(.target)
local real y = GetUnitY(.target)
local real height = GetUnitFlyHeight(.target)
if IsTerrainWalkable(x + 50.00 * .cos,y + 50.00 * .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
method KnockbackStop takes unit target returns boolean
local Knock d = Knock[target]
local integer i = .Count - 1
if d != 0 then
if .Count > 0 then
set .D<i>= .D[.Count]
set i = i - 1
else
call PauseTimer(.Timer)
endif
call d.release()
return true
endif
return false
endmethod
method IsKnockedBack takes unit target returns boolean
return Knock[target] != 0
endmethod
static method create takes unit source, unit target, real angle, real speed, real decrement returns Knock
local Knock d = Knock.allocate()
if target == null or source == null or speed == 0.00 or decrement == 0.00 then
call BJDebugMsg("Invalid Values!")
call d.destroy()
endif
set d.source = source
set d.target = target
set d.trees = false
set d.fly = false
set d.chain = false
set d.ToTarget = false
set d.Move = false
set d.hit = NewGroup()
set d.linehit = 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)
set d.positionZ = 0.
set d.LineDamage = 0
set d.Mode = 0
set d.VariableSpeed = 0
set d.Increment = 0
set d.dashtarget = null
set d.TargetPoint = null
set d.VariableSpeed = speed
set d.SFX = ""
set d.attachpoint = "origin"
set d.mode = d.TerrainCheck()
if d.mode == 1 then
set d.effects = AddSpecialEffectTarget(GROUND,d.target,d.attachpoint)
elseif d.mode == 2 then
set d.effects = AddSpecialEffectTarget(WATER,d.target,d.attachpoint)
elseif d.mode == 3 then
set d.effects = AddSpecialEffectTarget(COLLISION,d.target,d.attachpoint)
endif
set Knock[target] = d
set .D[.Count] = d
if .Count == 0 then
call TimerStart(.Timer,TIME,true,function Knock.action)
endif
set .Count = .Count + 1
if d.OnStart.exists then
call d.OnStart()
endif
return d
endmethod
static method get takes unit u returns integer
return Knock<u>
endmethod
private method onDestroy takes nothing returns nothing
call DestroyEffect(.effects)
call ReleaseGroup(.hit)
call ReleaseGroup(.linehit)
call SetUnitFlyHeight(.target,GetUnitDefaultFlyHeight(.target),0)
call SetUnitPathing(.target,true)
endmethod
private static method action takes nothing returns nothing
local Knock d
local Knock this = 0
local real x = 0.00
local real y = 0.00
local real cx = 0.00
local real cy = 0.00
local real tx = 0.00
local real ty = 0.00
local integer mode = 0
local real height = 0.00
local group g = NewGroup()
local real angle = 0.00
local integer i = 0
local unit t = null
loop
exitwhen i >= .Count
set this = .D<i>
set x = GetUnitX(.target)
set y = GetUnitY(.target)
set height = GetUnitFlyHeight(.target)
set mode = .mode
set .positionZ = .positionZ + .speed
if height >= HEIGHTLEVEL then
set .chain = false
set .trees = false
endif
if .ToTarget and .TargetPoint == null then
set cx = GetUnitX(.dashtarget)
set cy = GetUnitY(.dashtarget)
set x = GetUnitX(.target)
set y = GetUnitY(.target)
set angle = Atan2(cy-y,cx-x)
set .sin = Sin(angle)
set .cos = Cos(angle)
if SquareRoot((cx - x) * (cx - x) + (cy - y) * (cy - y)) <= 125 then
if .OnStop.exists then
call .OnStop()
endif
call .release()
set .Count = .Count - 1
if .Count > 0 then
set .D<i>= .D[.Count]
set i = i - 1
else
call PauseTimer(.Timer)
endif
endif
endif
if .OnStopCondition.exists then
call .OnStopCondition()
if .OnStop.exists then
call .OnStop()
endif
call .release()
set .Count = .Count - 1
if .Count > 0 then
set .D<i>= .D[.Count]
set i = i - 1
else
call PauseTimer(.Timer)
endif
endif
if .TargetPoint == null and not .ToTarget and not .OnStopCondition.exists then
if .speed <= 0 or IsPointOutside(x,y) then
if .OnStop.exists then
call .OnStop()
endif
call .release()
set .Count = .Count - 1
if .Count > 0 then
set .D<i>= .D[.Count]
set i = i - 1
else
call PauseTimer(.Timer)
endif
endif
endif
if .Mode == 0 then
set x = x + .speed * .cos
set y = y + .speed * .sin
elseif .Mode == 1 then
set x = x + .speed * .cos
set y = y + .speed * .sin
elseif .Mode == 2 then
set x = x + .VariableSpeed *.cos
set y = y + .VariableSpeed *.sin
endif
if .Move then
call SetUnitX(.target,x)
call SetUnitY(.target,y)
else
call SetUnitPosition(.target,x,y)
endif
if .LineDamage > 0 then
set .data = this
call GroupEnumUnitsInRange(g,x,y,100,LineFilter)
loop
set t = FirstOfGroup(g)
exitwhen t == null
if not IsUnitInGroup(t,.linehit) then
call UnitDamageTarget(.source,t,.LineDamage,false,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
call GroupAddUnit(.linehit,t)
endif
call GroupRemoveUnit(g,t)
endloop
endif
if .trees then
call SetRect(TreeRect,x-RADIUS,y-RADIUS,x+RADIUS,y+RADIUS)
call EnumDestructablesInRect(TreeRect,TreeCheck,function Knock.Trees)
endif
if .fly then
call UnitAddAbility(.target,FLYID)
call UnitRemoveAbility(.target,FLYID)
call SetUnitPathing(.target,false)
call SetUnitFlyHeight(.target,ParabolaZ(FACTOR*.distance,.distance,.positionZ),0)
endif
set .mode = .TerrainCheck()
set height = GetUnitFlyHeight(.target)
if .SFX == "" then
if height <= 0 then
if .mode == 1 and (mode == 2 or mode == 3) then
call DestroyEffect(.effects)
set .effects = AddSpecialEffectTarget(GROUND,.target,.attachpoint)
elseif .mode == 2 and (mode == 1 or mode == 3) then
call DestroyEffect(.effects)
set .effects = AddSpecialEffectTarget(WATER,.target,.attachpoint)
elseif .mode == 3 and (mode == 1 or mode == 2) then
call DestroyEffect(.effects)
set .effects = AddSpecialEffectTarget(COLLISION,.target,.attachpoint)
endif
endif
else
call DestroyEffect(.effects)
set .effects = AddSpecialEffectTarget(.SFX,.target,.attachpoint)
endif
if .chain == true then
set .data = this
call GroupEnumUnitsInRange(ENUM_GROUP,x,y,CHAINRADIUS,ChainFilter)
loop
set t = FirstOfGroup(ENUM_GROUP)
exitwhen t == null
if not IsUnitInGroup(t,.hit) then
set cx = GetUnitX(t)
set cy = GetUnitY(t)
call GroupAddUnit(.hit,t)
set d = Knock.create(.source,t,Atan2(cy-y,cx-x),(.speed/TIME)*SPEEDFACTOR,(.decrement/TIME))
call GroupAddUnit(d.hit,.target)
if .OnChain.exists then
call .OnChain()
endif
if .Count == 0 then
call TimerStart(.Timer,TIME,true,function Knock.action)
endif
set .Count = .Count + 1
set .D[.Count] = d
endif
call GroupRemoveUnit(ENUM_GROUP,t)
endloop
endif
set .speed = .speed - .decrement
if .Mode == 2 then
set .VariableSpeed = .VariableSpeed + .Increment
endif
set i = i + 1
endloop
endmethod
static method onInit takes nothing returns nothing
set TreeRect = Rect(0.00,0.00,1.00,1.00)
set TreeCheck = Filter(function Knock.CheckTrees)
set ChainFilter = Filter(function Knock.ChainCheck)
set LineFilter = Filter(function Knock.LineCheck)
endmethod
endstruct
private function Init takes nothing returns nothing
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></u></i>
SetUnitPathing didn't work well after the knockback. If you are saying why don't I initialize it in the create method, it is so that users can make a unit suddenly fly from a current knockback for some reasons.
Like a unit has to reach distance of 300 before flying to a distance of 600.
Here's the code cut off which has to do with it
JASS:
if .fly then
call UnitAddAbility(.target,FLYID)
call UnitRemoveAbility(.target,FLYID)
call SetUnitPathing(.target,false)
call SetUnitFlyHeight(.target,ParabolaZ(FACTOR*.distance,.distance,.positionZ),0)
endif
JASS:
private method onDestroy takes nothing returns nothing
call DestroyEffect(.effects)
call ReleaseGroup(.hit)
call ReleaseGroup(.linehit)
call SetUnitFlyHeight(.target,GetUnitDefaultFlyHeight(.target),0)
call SetUnitPathing(.target,true)
endmethod