HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Knockback System

03-15-2009, 05:44 AM#1
wraithseeker
Bump. Angle still doesn't work .. sigh..

Code update!

Collapse JASS:
scope KnockTest initializer Init

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'TEST'
endfunction

private function Actions takes nothing returns nothing
    local unit u = GetSpellTargetUnit()
    local unit t = GetTriggerUnit()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real tx = GetUnitY(t)
    local real ty = GetUnitX(t)
    local real a = Atan2(y-ty,x-tx)*57.29582
    call KnockbackTarget(t,u,a,1000,30)
    set u = null
    set t = null
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( t, function Actions )
    call TriggerAddCondition(t,Condition(function Conditions))
endfunction

endscope

Collapse JASS:
library Knockback initializer Init requires BoundSentinel, TimerUtils, DestructableLib

globals
    private real TIME = 0.04
endglobals

private struct Knock
    unit source
    unit target
    real x
    real y
    real cos
    real sin
    real speed
    real decrement
    timer Timer
    effect mode

static method create takes unit source, unit target, real angle, real initialspeed, real decrement returns Knock
    local Knock d = Knock.allocate()
    set d.source = source
    set d.target = target
    set d.speed = initialspeed * TIME
    set d.decrement = decrement * TIME
    set d.sin = Sin(angle)
    set d.cos = Cos(angle)
    set d.Timer = NewTimer()
    return d
    endmethod
    
method onDestroy takes nothing returns nothing
call ReleaseTimer(.Timer)
    endmethod
        endstruct

private function Update takes nothing returns nothing
    local Knock d = Knock(GetTimerData(GetExpiredTimer()))
    local unit u = d.target
    local real sx = GetUnitX(u)
    local real sy = GetUnitY(u)
    local real x = sx + d.speed * d.cos
    local real y = sy + d.speed * d.sin
    local real tx
    local real ty
    if d.speed <= 0 then
        call d.destroy()
    endif
        set x = sx + d.speed * d.cos
        set y = sy + d.speed * d.sin
        call SetUnitPosition(u,x,y)
        set d.speed = d.speed - d.decrement
    set u = null
endfunction

function KnockbackTarget takes unit source, unit target , real angle, real initialspeed, real decrement returns boolean
    local Knock d = 0
    if target == null or source == null or initialspeed == null or decrement == null then
        call BJDebugMsg("Invalid Values!")
        return false
    endif
    set d = Knock.create(source,target,(angle*0.01745328),initialspeed,decrement)
    call SetTimerData(d.Timer,integer (d))
    call TimerStart(d.Timer,TIME,true,function Update)
    return true
endfunction


private function Init takes nothing returns nothing
endfunction
endlibrary
03-15-2009, 05:52 AM#2
Blackroot
You have no reason to be using degrees. Don't convert either way; just use plain radians.

And this is the reason it doesn't work:
Expand JASS:
03-15-2009, 06:01 AM#3
wraithseeker
Quote:
Originally Posted by Blackroot
You have no reason to be using degrees. Don't convert either way; just use plain radians.

So how do I use plain radians?
Quote:
Originally Posted by BLackroot
And this is the reason it doesn't work:
Expand JASS:

Wow! Silly me man , I must be a blind old man who can't see. I didn't even manage to see that after millions of checking.
03-15-2009, 06:05 AM#4
Blackroot
Expand JASS:
You're converting radians to degrees here. (Atan2 returns radians)

Expand JASS:
And degrees to radians here.

You can remove both and gain more speed an accuracy at no cost to the system.
03-15-2009, 06:31 AM#5
0zyx0
This script could possibly crash a map, if the unit was knocbacked to a point outside the map bounds.
03-15-2009, 06:34 AM#6
TriggerHappy
Quote:
Originally Posted by 0zyx0
This script could possibly crash a map, if the unit was knocbacked to a point outside the map bounds.

This will check if the given coordinates are inside the map bounds.

Collapse JASS:
function mapbounds takes real x, real y returns boolean
        return x < GetRectMaxX(bj_mapInitialPlayableArea)-64.00 and x > GetRectMinX(bj_mapInitialPlayableArea)+64.00 and y < GetRectMaxY(bj_mapInitialPlayableArea)-64.00 and y > GetRectMinY(bj_mapInitialPlayableArea)+64.00
endfunction
03-15-2009, 06:46 AM#7
wraithseeker
My code shows that it requires BoundSentinel :P.
03-15-2009, 07:17 AM#8
Bobo_The_Kodo
I really don't think SetUnitPosition works outside of map bounds ;; It doesn't matter anyway, unless your speed is fast enough to bypass the entire boundary, which is the users fault anyway...

I would just check the pathing before setting the position to it, to avoid wierd errors

(there are 2 scripts for this in database)
03-15-2009, 01:42 PM#9
wraithseeker
Right now everything works but some effects are not getting destroyed.

Collapse JASS:
library Knockback initializer Init requires BoundSentinel, TimerUtils, DestructableLib

globals
    private constant real TIME = 0.04
    private constant string GROUND = "MDX\\KnockbackDust.mdx"
    private constant string WATER = "MDX\\KnockbackWater.mdx"
    private constant string ATTACHPOINT = "origin"
    private constant real RADIUS = 180
    private rect TreeRect
    private boolexpr TreeCheck
endglobals

private function CheckTrees takes nothing returns boolean
if IsDestructableTree(GetFilterDestructable()) then
return true
endif
return false
endfunction
private function Trees takes nothing returns nothing
call KillDestructable(GetEnumDestructable())
endfunction

private struct Knock
    unit source
    unit target
    real x
    real y
    real cos
    real sin
    real speed
    real decrement
    timer Timer
    effect effects
    boolean Terrain
    integer EffectMode
    boolean Trees
    
 public method TerrainCheck takes Knock d returns integer
        local real x = GetUnitX(d.target)
        local real y = GetUnitY(d.target)
        if IsTerrainPathingType(x, y, TERRAIN_PATHING_LAND) then
            return 1
        elseif IsTerrainPathingType(x, y, TERRAIN_PATHING_SHALLOW) then
            return 2
        endif
        return 0
    endmethod

static method create takes unit source, unit target, real angle, real initialspeed, real decrement, boolean KillTree returns Knock
    local Knock d = Knock.allocate()
    local real x
    local real y
    set d.source = source
    set d.target = target
    set d.Trees = KillTree
    set d.EffectMode = d.TerrainCheck(d)
    set x = GetUnitX(d.target)
    set y = GetUnitY(d.target)
    set d.speed = initialspeed * TIME
    set d.decrement = decrement * TIME
    set d.sin = Sin(angle)
    set d.cos = Cos(angle)
    set d.Timer = NewTimer()
    if d.EffectMode == 1 then
    set d.effects = AddSpecialEffectTarget(GROUND,d.target,ATTACHPOINT)
    endif
    if d.EffectMode == 2 then
    set d.effects = AddSpecialEffectTarget(WATER,d.target,ATTACHPOINT)
    endif
    return d
    endmethod
    
method onDestroy takes nothing returns nothing
call DestroyEffect(this.effects)
call ReleaseTimer(this.Timer)
    endmethod
        endstruct

private function Update takes nothing returns nothing
    local Knock d = Knock(GetTimerData(GetExpiredTimer()))
    local unit u = d.target
    local real sx = GetUnitX(u)
    local real sy = GetUnitY(u)
    local real x = sx + d.speed * d.cos
    local real y = sy + d.speed * d.sin
    if d.speed <= 0 then
        call d.destroy()
    endif
    if d.Trees == true then
        set sx = GetUnitX(u)
        set sy = GetUnitY(u)
        call SetRect(TreeRect,sx-RADIUS,sy-RADIUS,sx+RADIUS,sy+RADIUS)
        call EnumDestructablesInRect(TreeRect,TreeCheck,function Trees)
        endif
    call SetUnitPosition(u,x,y)
    set d.EffectMode = d.TerrainCheck(d)
    if d.EffectMode == 1 then
        call DestroyEffect(d.effects)
        set d.effects = AddSpecialEffectTarget(GROUND,d.target,ATTACHPOINT)
   endif
   if d.EffectMode == 2 then
        call DestroyEffect(d.effects)
        set d.effects = AddSpecialEffectTarget(WATER,d.target,ATTACHPOINT)
    endif
    
        set d.speed = d.speed - d.decrement
    set u = null
endfunction

function KnockbackTarget takes unit source, unit target , real angle, real initialspeed, real decrement,boolean KillTree returns boolean
    local Knock d = 0
    if target == null or source == null or initialspeed == null or decrement == null then
        call BJDebugMsg("Invalid Values!")
        return false
    endif
    set d = Knock.create(source,target,angle,initialspeed,decrement,KillTree)
    call SetTimerData(d.Timer,integer (d))
    call TimerStart(d.Timer,TIME,true,function Update)
    return true
endfunction


private function Init takes nothing returns nothing
set TreeRect = Rect(0,0,1,1)
set TreeCheck = Filter(function CheckTrees)
endfunction
endlibrary

Collapse JASS:
scope KnockTest initializer Init

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'TEST'
endfunction

private function Actions takes nothing returns nothing
    local unit u = GetSpellTargetUnit()
    local unit t = GetTriggerUnit()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real tx = GetUnitX(t)
    local real ty = GetUnitY(t)
    local real a = Atan2(y-ty,x-tx)
    call KnockbackTarget(t,u,a,1000,30,true)
    set u = null
    set t = null
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( t, function Actions )
    call TriggerAddCondition(t,Condition(function Conditions))
endfunction

endscope
03-16-2009, 02:45 AM#10
wraithseeker
Collapse JASS:
//Formula to calculate Distance = -1 * V * V / (2 * A / Interval)  Where variable V is speed and A is decrement.//
//                            Note! V must be positive and A must be negative!!!!                             //
library Knockback initializer Init requires BoundSentinel, TimerUtils, DestructableLib, TerrainPathability

globals
    private constant real TIME = 0.03
    private constant string GROUND = "MDX\\Dust.mdx"
    private constant string WATER = "MDX\\SlideWater.mdx"
    private constant string COLLISION = "MDX\\DustAndRocks.mdx"
    private constant string ATTACHPOINT = "origin"
    private constant real RADIUS = 180
    private rect TreeRect
    private boolexpr TreeCheck
endglobals

private function CheckTrees takes nothing returns boolean
    if IsDestructableTree(GetFilterDestructable()) then
        return true
    endif
    return false
endfunction

private function Trees takes nothing returns nothing
    call KillDestructable(GetEnumDestructable())
endfunction

private struct Knock
    unit source
    unit target
    real x
    real y
    real cos
    real sin
    real speed
    real decrement
    timer Timer
    effect effects
    boolean Terrain
    integer EffectMode
    boolean Trees
    
 public method TerrainCheck takes Knock d returns integer
        local real x = GetUnitX(d.target)
        local real y = GetUnitY(d.target)
        if IsTerrainPathingType(x, y, TERRAIN_PATHING_LAND) then
            return 1
        elseif IsTerrainPathingType(x, y, TERRAIN_PATHING_SHALLOW) then
            return 2
        endif
        return 0
    endmethod

static method create takes unit source, unit target, real angle, real speed, real decrement, boolean KillTree returns Knock
    local Knock d = Knock.allocate()
    local real x
    local real y
    set d.source = source
    set d.target = target
    set d.Trees = KillTree
    set d.EffectMode = d.TerrainCheck(d)
    set x = GetUnitX(d.target)
    set y = GetUnitY(d.target)
    set d.speed = speed * TIME
    set d.decrement = decrement * TIME
    set d.sin = Sin(angle)
    set d.cos = Cos(angle)
    set d.Timer = NewTimer()
    if d.EffectMode == 1 then
    if IsTerrainWalkable(x,y) then
        set d.effects = AddSpecialEffectTarget(COLLISION,d.target,ATTACHPOINT)
    else
        set d.effects = AddSpecialEffectTarget(GROUND,d.target,ATTACHPOINT)
    endif
    endif
    if d.EffectMode == 2 then
        set d.effects = AddSpecialEffectTarget(WATER,d.target,ATTACHPOINT)
    endif
    if IsTerrainWalkable(x,y) == false then
        set d.effects = AddSpecialEffectTarget(COLLISION,d.target,ATTACHPOINT)
    endif
    return d
    endmethod
    
method onDestroy takes nothing returns nothing
    call DestroyEffect(this.effects)
    call ReleaseTimer(this.Timer)
    endmethod
        endstruct

private function Update takes nothing returns nothing
    local Knock d = Knock(GetTimerData(GetExpiredTimer()))
    local unit u = d.target
    local real sx = GetUnitX(u)
    local real sy = GetUnitY(u)
    local real x = sx + d.speed * d.cos
    local real y = sy + d.speed * d.sin
    local integer mode = d.EffectMode
    if d.speed <= 0 then
        call d.destroy()
    endif
    if d.Trees == true then
        call SetRect(TreeRect,sx-RADIUS,sy-RADIUS,sx+RADIUS,sy+RADIUS)
        call EnumDestructablesInRect(TreeRect,TreeCheck,function Trees)
        endif
    call SetUnitPosition(u,x,y)
    set d.EffectMode = d.TerrainCheck(d)
    if d.EffectMode == 1 and mode == 2 then
    if IsTerrainWalkable(x,y) then
    call DestroyEffect(d.effects)
    set d.effects = AddSpecialEffectTarget(COLLISION,d.target,ATTACHPOINT)
    else
        call DestroyEffect(d.effects)
        set d.effects = AddSpecialEffectTarget(GROUND,d.target,ATTACHPOINT)
   endif
   endif
   if d.EffectMode == 2 and mode == 1 then
        call DestroyEffect(d.effects)
        set d.effects = AddSpecialEffectTarget(WATER,d.target,ATTACHPOINT)
    endif
        set d.speed = d.speed - d.decrement
    set u = null
endfunction

function KnockbackTarget takes unit source, unit target , real angle, real speed, real decrement,boolean KillTree returns boolean
    local Knock d = 0
    if target == null or source == null or speed == null or decrement == null then
        call BJDebugMsg("Invalid Values!")
        return false
    endif
    set d = Knock.create(source,target,angle,speed,decrement,KillTree)
    call SetTimerData(d.Timer,integer (d))
    call TimerStart(d.Timer,TIME,true,function Update)
    return true
endfunction


private function Init takes nothing returns nothing
    set TreeRect = Rect(0,0,1,1)
    set TreeCheck = Filter(function CheckTrees)
endfunction
endlibrary