• 🏆 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!
  • ✅ The POLL for Hive's Texturing Contest #33 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!

Making a JASS AoE Damage function

Status
Not open for further replies.
JASS:
function DamageValidEnemy takes nothing returns boolean
    if IsUnitEnemy( GetFilterUnit(), GetOwningPlayer(udg_u) ) then
        call UnitDamageTargetBJ( udg_u , GetFilterUnit(), udg_dmg, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
    endif
    return false
endfunction

function DamageAoE takes unit u, real dmg, real aoe, real buildingfactor returns nothing
    set udg_u = u
    set udg_dmg = dmg
    call GroupEnumUnitsInRange(udg_g,GetUnitX(u),GetUnitY(u),aoe,Condition(function DamageValidEnemy))
    set u = null
endfunction
I am new to JASS so I'd like to ask if anything of this code is not ok or if there are better ways to damage enemys

first I wanted to ask soemthing else but then I found the mistake but the thread was already created....

note: I have JNGP but I prefer the normal WE cause our pcs at school detect it as a hack and make it impossible to work with it :p
 
Level 8
Joined
Feb 15, 2009
Messages
463
you leak for example a boolexpr without globals from jngp i dont know if you can make them global but in locals (takes more time but doesnt leak ) it is like
JASS:
local boolexpr b = Condition(function DamageValidEnemy)
call DestroyBollexpr(b)
set b = null

also why u let the damage function return something?

faster is btw just this

unit udg_u (whatever name) the caster is needed
in vJass this can be done much better,faster,cleaner and easier

JASS:
function Match takes nothing returns boolean
    return IsUnitType(GetFilterUnit, UNIT_TYPE_STRUCTURE) == false
endfunction

function Callback takes nothing returns nothing
   call UnitDamageTarget(udg_u , GetEnumUnit() , 50.00 , ATTACK...........etc.)
endfunction

function Actions takes nothing returns nothing
local group g = CreateGroup()
local boolexpr b = Condition(function Match)
   call GroupEnumUnitsInRange(g , x, y , aoe , b)
   call ForGroup(g,function Callback)
call DestroyGroup(g)
call DestroyBoolexpr(b)
set g = null
set b = null
endfunction
 
Level 12
Joined
Jul 27, 2008
Messages
1,181
Here's a more advanced AoE damage API i just made:
JASS:
function IsEnemy takes nothing returns boolean
    return IsUnitAlly(GetFilterUnit(),udg_DMG_Player)
endfunction

function AoE_DMG takes unit source, unit target, real damage, real radius, damagetype DMG_TYPE, attacktype ATK_TYPE, boolean friendlyFire returns nothing
    local group dmgTempGroup = CreateGroup()
    local filterfunc dmgFilterFunc = null
    local unit tmpDMG = null
    set udg_DMG_Player = GetOwningPlayer(source)
    
    if friendlyFire == false then
        set dmgFilterFunc = Filter(function IsEnemy)
    endif
    
    call GroupEnumUnitsInRange(dmgTempGroup,GetUnitX(target),GetUnitY(target),radius,dmgFilterFunc)
    
    loop
        set tmpDMG = FirstOfGroup(dmgTempGroup)
        call UnitDamageTarget(source,target,damage,false,true,ATK_TYPE,DMG_TYPE,WEAPON_TYPE_WHOKNOWS)
        call GroupRemoveUnit(dmgTempGroup,tmpDMG)
        exitwhen tmpDMG == null
    endloop
    
    call DestroyGroup(dmgTempGroup)
    
    set udg_DMG_Player = null
    set tmpDMG = null
    set dmgTempGroup = null
endfunction
Call it like:
JASS:
call AoE_DMG(source, target, damage, radius, damage_type, attack_type, friendly_fire)
Note : Friendly Fire is a boolean.
Note2 : It uses a global player variable (DMG_Player)
 
Level 11
Joined
Apr 29, 2007
Messages
826
faster is btw just this

unit udg_u (whatever name) the caster is needed
in vJass this can be done much better,faster,cleaner and easier

JASS:
function Match takes nothing returns boolean
    return IsUnitType(GetFilterUnit, UNIT_TYPE_STRUCTURE) == false
endfunction

function Callback takes nothing returns nothing
   call UnitDamageTarget(udg_u , GetEnumUnit() , 50.00 , ATTACK...........etc.)
endfunction

function Actions takes nothing returns nothing
local group g = CreateGroup()
local boolexpr b = Condition(function Match)
   call GroupEnumUnitsInRange(g , x, y , aoe , b)
   call ForGroup(g,function Callback)
call DestroyGroup(g)
call DestroyBoolexpr(b)
set g = null
set b = null
endfunction

no. Doing the actions directly in the condition of the GroupeEnumUnitsInRange is faster.
 
you leak for example a boolexpr without globals from jngp i dont know if you can make them global but in locals (takes more time but doesnt leak ) it is like
JASS:
local boolexpr b = Condition(function DamageValidEnemy)
call DestroyBollexpr(b)
set b = null
also why u let the damage function return something?

faster is btw just this

unit udg_u (whatever name) the caster is needed
in vJass this can be done much better,faster,cleaner and easier

JASS:
function Match takes nothing returns boolean
    return IsUnitType(GetFilterUnit, UNIT_TYPE_STRUCTURE) == false
endfunction

function Callback takes nothing returns nothing
   call UnitDamageTarget(udg_u , GetEnumUnit() , 50.00 , ATTACK...........etc.)
endfunction

function Actions takes nothing returns nothing
local group g = CreateGroup()
local boolexpr b = Condition(function Match)
   call GroupEnumUnitsInRange(g , x, y , aoe , b)
   call ForGroup(g,function Callback)
call DestroyGroup(g)
call DestroyBoolexpr(b)
set g = null
set b = null
endfunction

http://wiki.thehelper.net/wc3/Boolexpr says something different about leaks (but I may test it myself if you won't belive it)

and this says that my way is faster
http://wiki.thehelper.net/wc3/Group_API
(scroll down to the bottom)

however I forgot that players leak in GUI so thanks to reaper
 
Level 7
Joined
Mar 8, 2009
Messages
360
I think this is fastest and most leakless but it can be better with vJASS.

JASS:
function DamageValidEnemy takes nothing returns boolean
    if IsUnitEnemy( GetFilterUnit(), GetOwningPlayer(udg_u) ) then
        call UnitDamageTarget( udg_u, GetFilterUnit(), udg_dmg, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
    endif
    return false
endfunction

function DamageAoE takes unit aUnit, real damage, real aoe, real buildingfactor returns nothing
    local group g
    local boolexpr b = Condition(function DamageValidEnemy)
    set udg_u = aUnit
    set udg_dmg = damage
    
    call GroupEnumUnitsInRange(g,GetUnitX(udg_u),GetUnitY(udg_u),aoe, b)
    
    call DestroyGroup(g)
    call DestroyBollexpr(b)
    set b = null
    set g = null
endfunction
 
Most efficient preprocessor-less version;

JASS:
function DamageValidEnemy takes nothing returns boolean
    return IsUnitEnemy( GetFilterUnit(), GetOwningPlayer(udg_u) )
endfunction

function DamageAoE takes unit aUnit, real damage, real aoe, real buildingfactor returns nothing
    local unit u
    // Create a variable named udg_g of type group.
    if udg_g == null then
        set udg_g = CreateGroup()
    endif
    call GroupEnumUnitsInRange(udg_g ,GetUnitX(udg_u),GetUnitY(udg_u), aoe, b)
    loop
        set u = FirstOfGroup(udg_g)
        exitwhen u == null
        call UnitDamageTarget(aUnit, u, damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
    endloop
endfunction

Only requires one global.
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
To start with, ForGroup is the fastest way to loop... FirstOfGroup loops are inefficient...

Vulcano's way seems to be the best. But here's a bit of improvement:
JASS:
//Vulcano's way:

// you'll need a global group g
// variable editor automatically creates the group

function DamageValidEnemy takes nothing returns boolean
    if IsUnitEnemy(GetFilterUnit(), udg_player) then
        call UnitDamageTarget(udg_u, GetFilterUnit(), udg_dmg, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
    endif
    return false
endfunction

function DamageAoE takes unit aUnit, real damage, real aoe returns nothing
    set udg_u = aUnit
    set udg_dmg = damage
    set udg_player = GetOwningPlayer(udg_u)

    call GroupEnumUnitsInRange(udg_g,GetUnitX(udg_u),GetUnitY(udg_u),aoe, Condition(function DamageValidEnemy))
    call DestroyCondition(Condition(function DamageValidEnemy))
endfunction

Yet I still prefer the ForGroup method, but I'm not sure if it's better than Vulcano's or not..
Just checked, this method is faster then ForGroup :)
 
Level 20
Joined
Apr 22, 2007
Messages
1,960
Deuterium said:
And well, I destroy the condition to avoid boolexpr leaking...
Boolexpr don't leak like some handle types. They're apparently stored in a table similar to that of the strings in Wc3, such that referring to Condition(function someFunction) only creates a new boolexpr when it's the first time that this function is called. For example:
JASS:
local boolexpr b1 = Condition(function SomeFunction)
local boolexpr b2 = Condition(function SomeFunction)
GetHandleId(b1) will be equal to GetHandleId(b2)

Destroying them is known to cause fuck ups because it really isn't necessary and isn't a leak per se: the memory is still usable and hasn't been lost.
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
Yes I understand what you're saying hindy... never knew that. I always wondered why we could destroy conditions without setting them into variables :p

And it never fucked up for me, and I doubt it will if condition is destroyed directly after being used. But as you said, it's not a leak per se; I just like cleaning shit until next cast :p
 
Most efficient preprocessor-less version;

JASS:
function DamageValidEnemy takes nothing returns boolean
    return IsUnitEnemy( GetFilterUnit(), GetOwningPlayer(udg_u) )
endfunction

function DamageAoE takes unit aUnit, real damage, real aoe, real buildingfactor returns nothing
    local unit u
    // Create a variable named udg_g of type group.
    if udg_g == null then
        set udg_g = CreateGroup()
    endif
    call GroupEnumUnitsInRange(udg_g ,GetUnitX(udg_u),GetUnitY(udg_u), aoe, b)
    loop
        set u = FirstOfGroup(udg_g)
        exitwhen u == null
        call UnitDamageTarget(aUnit, u, damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
    endloop
endfunction

Only requires one global.


Isn't the udg_u should be aUnit???? and also where do you use this I cant see a call for this function
JASS:
function DamageValidEnemy takes nothing returns boolean
    return IsUnitEnemy( GetFilterUnit(), GetOwningPlayer(udg_u) )
endfunction
 
To start with, ForGroup is the fastest way to loop... FirstOfGroup loops are inefficient...

Vulcano's way seems to be the best. But here's a bit of improvement:
JASS:
//Vulcano's way:

// you'll need a global group g
// variable editor automatically creates the group

function DamageValidEnemy takes nothing returns boolean
    if IsUnitEnemy(GetFilterUnit(), udg_player) then
        call UnitDamageTarget(udg_u, GetFilterUnit(), udg_dmg, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
    endif
    return false
endfunction

function DamageAoE takes unit aUnit, real damage, real aoe returns nothing
    set udg_u = aUnit
    set udg_dmg = damage
    set udg_player = GetOwningPlayer(udg_u)

    call GroupEnumUnitsInRange(udg_g,GetUnitX(udg_u),GetUnitY(udg_u),aoe, Condition(function DamageValidEnemy))
    call DestroyCondition(Condition(function DamageValidEnemy))
endfunction

Yet I still prefer the ForGroup method, but I'm not sure if it's better than Vulcano's or not..
Just checked, this method is faster then ForGroup :)


Is it necessary to
JASS:
set udg_u = aUnit
set udg_dmg = damage
? can't we just use aUnit and damage directly?
 
Turns out I'm right. I placed a bunch of knights/footman on the map and all the knights were removed using this code.

And yes I know I leak two boolexpr, 'tis just an example.

JASS:
scope groups initializer onInit
    
    globals
        private group g = CreateGroup()
    endglobals
    
    private function test takes nothing returns nothing
        call RemoveUnit(GetEnumUnit())
    endfunction
    
    private function onInit takes nothing returns nothing
        call GroupEnumUnitsOfType(g, "Footman", null)
        call GroupEnumUnitsOfType(g, "Knight", null)
        call ForGroup(g, function test)
    endfunction
    
endscope
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
The enumeration thing, better testing should be done, or we should checking with someone who is definite of the answer. But I always knew that it doesn't clear the group :s

And Reaper, no need to clear, cause Vulcano's way don't enumerate any unit, it keeps the group empty =)

EDIT:
TriggerHappy, you're right =) enumaration automatically clears group :p
 
Level 20
Joined
Apr 22, 2007
Messages
1,960
When you use 'null' as a boolexpr, it often leaks.

I think there's some voodoo stuff going on with the GroupEnum thing though. I never really looked into group leaks since they were figured out after I stopped Jassing, but I remember Griffen having a detailed explanation on wc3c. Indeed, it's right here. So yeah, figure it out from there.
 
Status
Not open for further replies.
Top