• 🏆 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!

[JASS] AoE Knockback Issue

Status
Not open for further replies.
Level 13
Joined
Jul 26, 2008
Messages
1,009
Alright, I'm using the knockback system provided by Silvenon.

http://www.hiveworkshop.com/forums/f413/knockback-unit-35545/

I can get the knockback to work with single target abilities, like stormbolt. However, the knockback doesn't work at all with an AoE skill like Howl of Terror, for obvious reasons.

I've tried ForGroupBJ(etc.etc.) with no luck. I've got CSCache in my map, but most the AOE related is for dummy casters.

I just need a steer in the right direction of what to use to make the knockback effect AOE.

Also, I'm aware that the knockback angle will need to be adjusted for AoE, so that the units move in a direction away from the caster. Any ideas on what set up I would use for that?

Much thanks.
 
Level 13
Joined
Jul 26, 2008
Messages
1,009
That's a good start, though it's a very very vague and incomplete guideline. So, I'm still stuck.

I obviously need to set up the group first, don't I? Should I do this:

JASS:
call GroupEnumUnitsInRange(g,GetUnitX(c),GetUnitY(c),500,null)

Also, I need to make sure only the units that are allies are struck with knockback.

JASS:
if IsPlayerAlly(GetOwningPlayer(t),GetOwningPlayer(c)) then
endif

Even with these modifications, the spell won't knockback.

JASS:
function Trig_VR_Actions takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local unit t
    local real x1 = GetUnitX(c)  
    local real y1 = GetUnitY(c) 
    local real x2 = GetUnitX(t) 
    local real y2 = GetUnitY(t) 
    local real dist = 200   
    local real angle = Atan2(y2 - y1, x2 - x1)   
    local real dur = 1
        local group g
    call GroupEnumUnitsInRange(g,GetUnitX(c),GetUnitY(c),500,null)
    loop
     exitwhen t == null
     set t = FirstOfGroup(g)
     if IsPlayerAlly(GetOwningPlayer(t),GetOwningPlayer(c)) then
        call Knockback(t, dist, angle, dur)
        call UnitDamageTargetBJ(GetTriggerUnit(),GetSpellTargetUnit(),50.00*(I2R(GetUnitAbilityLevel(GetTriggerUnit(),'AHtb'))) + 25.00*I2R(GetUnitAbilityLevel(GetTriggerUnit(),'BMas')), ATTACK_TYPE_CHAOS, DAMAGE_TYPE_FIRE)
     endif
    call GroupRemoveUnit(g,t)
    endloop
    set c = null  
    set t = null
endfunction

Not to mention, they'll be pushed at the direction the caster is facing still, when I need them to shoot away from the caster.

Additional help would be nice.
 
Level 3
Joined
Jun 14, 2007
Messages
56
dont forget local group g = CreateGroup()

and put the set t = FirstOfGroup(g) above the exitwhen code

and as for the angle, in the loop before the knockback try set a = AngleBetweenPoints(GetUnitLoc(c), GetUnitLoc(t))



atm i've programmed a missile that you fire, and explodes upon hitting something, and using silvenon's system it knocks back units in a (larger) radius away from the explosion. if this doesnt fix it tell me and i'll compare our codes more carefully
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
JASS:
local unit u = GetTriggerUnit()
local unit iterator
local group g = CreateGroup()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real x2
local real y2
local real angle

call GroupEnumUnitsInRange(g,x,y,500,null)

loop
    set iterator = FirstOfGroup(g)
    exitwhen iterator == null
    call GroupRemoveUnit(g,iterator)
    
    // I assume you want them to be enemies, not allies
    if IsPlayerEnemy(GetOwningPlayer(u),GetOwningPlayer(iterator)) then
        set x2 = GetUnitX(iterator)
        set y2 = GetUnitY(iterator)
        set angle = bj_RADTODEG * Atan2(y2 - y, x2 - x)
        
        call Knockback(iterator,whatever,angle,whatever)
        call UnitDamageTarget(u,iterator,blablabla)
    endif
endloop

set u = null
call DestroyGroup(g)
set g = null
 
Level 11
Joined
Apr 6, 2008
Messages
760
JASS:
function Trig_VR_Actions takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local unit t
    local real x1 = GetUnitX(c)
    local real y1 = GetUnitY(c)
    local real x2 = GetUnitX(t) //need to be set inside the loop
    local real y2 = GetUnitY(t) //need to be set inside the loop
    local real dist = 200
    local real angle = Atan2(y2 - y1, x2 - x1) //need to be set inside the loop
    local real dur = 1
    local group g // CreateGroup
    call GroupEnumUnitsInRange(g,GetUnitX(c),GetUnitY(c),500,null)
    loop
     exitwhen t == null
     set t = FirstOfGroup(g)
     if IsPlayerAlly(GetOwningPlayer(t),GetOwningPlayer(c)) then // make a filter function instead
        call Knockback(t, dist, angle, dur)
        call UnitDamageTargetBJ(GetTriggerUnit(),GetSpellTargetUnit(),50.00*(I2R(GetUnitAbilityLevel(GetTriggerUnit(),'AHtb'))) + 25.00*I2R(GetUnitAbilityLevel(GetTriggerUnit(),'BMas')), ATTACK_TYPE_CHAOS, DAMAGE_TYPE_FIRE)
     // use c instead of GetTriggerUnit() and dont use BJ
     endif
    call GroupRemoveUnit(g,t)
    endloop
    set c = null
    set t = null
    //destroy grp and null
endfunction

and this one works

JASS:
private function FilterFunc takes nothing returns boolean
    local unit C = GetTriggerUnit()
    local unit F = GetFilterUnit()
    local boolean Ok = IsUnitEnemy(F,GetOwningPlayer(C)) and GetWidgetLife(F) > .305
    set C = null
    set F = null
    return Ok
endfunction
 
private function Actions takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local unit t
    local real x1 = GetUnitX(c)
    local real y1 = GetUnitY(c)
    local real x2
    local real y2
    local real dist = 200
    local real angle
    local real dur = 1
    local group g = CreateGroup()
    
    call GroupEnumUnitsInRange(g,x1,y1,500,Filter(function FilterFunc))
    
    loop
        set t = FirstOfGroup(g)
        exitwhen t == null
        call GroupRemoveUnit(g,t)
        set x2 = GetUnitX(t)
        set y2 = GetUnitY(t)
        set angle = Atan2(y2 - y1, x2 - x1)
        call Knockback(t, dist, angle, dur)
        call UnitDamageTarget(c,t,50.00*(I2R(GetUnitAbilityLevel(c,'AHtb'))) + 25.00*I2R(GetUnitAbilityLevel(c,'BMas')),false,false,ATTACK_TYPE_CHAOS, DAMAGE_TYPE_FIRE,null)
    endloop
    
    call DestroyGroup(g)
    
    set g = null
    set c = null
    set t = null
endfunction
 
Level 13
Joined
Jul 26, 2008
Messages
1,009
Thanks Ghostwolf. I see what I was doing wrong now. Was setting up the units position before the loop, when I needed to set it within the loop so it marks the location of every unit as they're picked. And I didn't set the group as pointed out.

Anyways, the UnitDamageTarget takes two extra booleans (Ranged and Attack) and Weapon Type. All of these are for attacking a unit via the attack function. Plus I don't know the syntax for Weapon Type.

Right now, both the original angle formula and AngleBetweenPoints(GetUnitLoc(c), GetUnitLoc(t)) cause the targeted unit to move in left to right angles instead of shoot out away from the caster. Now, all I need is the proper formula for this. Honestly I would have thought CheatENabled's formula would have worked.

function Trig_VR_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit t
local group g = CreateGroup()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real x2
local real y2
local real angle
local real dist = 225
local real dur = 0.7
call GroupEnumUnitsInRange(g,x,y,500,null)
loop
set t = FirstOfGroup(g)
exitwhen t == null
call GroupRemoveUnit(g,t)
if IsPlayerEnemy(GetOwningPlayer(u),GetOwningPlayer(t)) then
set x2 = GetUnitX(t)
set y2 = GetUnitY(t)
set angle = AngleBetweenPoints(GetUnitLoc(u), GetUnitLoc(t))
call Knockback(t, dist, angle, dur)
call UnitDamageTargetBJ(t,u,50.00*(I2R(GetUnitAbilityLevel(u,'AHtb'))) + 25.00*I2R(GetUnitAbilityLevel(u,'BMas')),ATTACK_TYPE_CHAOS, DAMAGE_TYPE_FIRE)
endif
endloop
set u = null
call DestroyGroup(g)
set g = null
endfunction
JASS:
 
Last edited:
Level 11
Joined
Apr 6, 2008
Messages
760
Anyways, the UnitDamageTarget takes two extra booleans (Ranged and Attack) and Weapon Type. All of these are for attacking a unit via the attack function. Plus I don't know the syntax for Weapon Type.

JASS:
function UnitDamageTargetBJ takes unit whichUnit, unit target, real amount, attacktype whichAttack, damagetype whichDamage returns boolean
    return UnitDamageTarget(whichUnit, target, amount, true, false, whichAttack, whichDamage, WEAPON_TYPE_WHOKNOWS)
endfunction

see its a petty useless BJ (slower)

u can do like this (which i usally do)

JASS:
UnitDamageTarget(Unit, target, amount, false, false, null, null, null)
 
Level 29
Joined
Jul 29, 2007
Messages
5,174

I gave you the exact code that you need just without mentioning a few variables and arguments that you need to specify...
Since you still seem to have problems, here just copy paste this.

JASS:
local unit u = GetTriggerUnit()
local unit iterator
local group g = CreateGroup()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real x2
local real y2
local real angle
local real d = 200 // distance
local real t = 1   // time
local integer damage = 50*GetUnitAbilityLevel(u,'AHtb') 
// what's the point of type-casting the damage to real if it's an integer?

call GroupEnumUnitsInRange(g,x,y,500,null)

loop
    set iterator = FirstOfGroup(g)
    exitwhen iterator == null
    call GroupRemoveUnit(g,iterator)
    
    // I assume you want them to be enemies, not allies
    if IsPlayerEnemy(GetOwningPlayer(u),GetOwningPlayer(iterator)) then
        set x2 = GetUnitX(iterator)
        set y2 = GetUnitY(iterator)
        set angle = bj_RADTODEG * Atan2(y2 - y, x2 - x)
        
        call Knockback(iterator,d,angle,t)
        call UnitDamageTarget(u,iterator,damage,true,false,ATTACK_TYPE_MELEE,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
    endif
endloop

set u = null
call DestroyGroup(g)
set g = null
 
Level 3
Joined
Jun 14, 2007
Messages
56
Honestly I would have thought CheatENabled's formula would have worked

Oh yeah i forgot one essential thing, that angle that you would receive with what i said (AngleBetweenPoints) is in DEGREES

Silvenon's Knockback angle needs something in RADIANS


to convert degress to radians just times it by bJ_DEGTORAD, so you can enter the parameter as (angle * bJ_DEGTORAD) otherwise it will just shoot off to the right etc. Otherwise you can just do the Atan2 thing that you did initially as it should work fine and it returns a radian value, as long as its inside the loop




The reason why Ghostwolf's code may not work is that I think he turned it into degrees for you, when this wasn't needed due to the specifics of Silvenon's Knockback. So if you input that angle into the parameter for Knockback it wouldnt work, you just have to remove the "bj_RADTODEG * " where he sets the angle, and that means its not turning the radians into degrees when you dont want it to

Ghostwolf can you confirm or correct me here?
 
Level 3
Joined
Jun 14, 2007
Messages
56
ahh true indeed. yeah im not too sure either what if its an radian or degree value it returns!

Hahah good on ya, i only have some basic maths skills as of yet too, heading into university (college) next year tho hopefully i'll come out a bit more clued on with maths
 
Status
Not open for further replies.
Top