• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[JASS] Damaging Units in Range of Another Unit/Killing "Projectile" Dummy On Collision

Status
Not open for further replies.
Level 4
Joined
Sep 25, 2005
Messages
71
Alright, with the exception of a few bugs (in particular, multiple instances firing simultaneously rarely create a dummy unit that sticks around and doesn't even up moving,) I've hammered out most of this spell I've been working on.

The idea is to create a fireball which travels in a line. The trick and the part I'm having issues implementing is, well, actually doing something with the fireball. Ideally, the fireball travels, and if a unit comes within range, it deals damage to that unit, kills the fireball/smoke trail.

What functions should I be looking at to find whether there's a single unit nearby/what kind of system for managing this should I use, and what kind of function am I using for actually dealing the damage? Should I have an "if" clause to make sure the execution loop stops when this situation happens?

Anyways, thanks in advance, sorry about the jumble of questions above.

JASS:
globals
    timer fireballTimer = CreateTimer()
    real fireballInterval = .015
    integer activeFireballs = 0
    fireballData array fireballArray
endglobals

struct fireballData
    unit caster
    unit dummy
    real angle
    real x
    real y
    real speed
    real maxDist
    real distance
endstruct

function fireballExecution takes nothing returns nothing
    local integer i = 0
    local real x = 0.
    local real y = 0.
    local effect smoke
    
    local fireballData localFireball = fireballData.create()
    

    loop
        exitwhen i >= activeFireballs
        
        
        set localFireball = fireballArray[i]
        set x = GetUnitX(localFireball.dummy) + localFireball.speed * Cos(localFireball.angle * bj_DEGTORAD)
        set y = GetUnitY(localFireball.dummy) + localFireball.speed * Sin(localFireball.angle * bj_DEGTORAD)
        
        call SetUnitBoundedX(localFireball.dummy, x)
        call SetUnitBoundedY(localFireball.dummy, y)
        
        set localFireball.distance = localFireball.distance + localFireball.speed
        
        set smoke = AddSpecialEffect("Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl", x, y)
               
        if localFireball.distance >= localFireball.maxDist then

            call KillUnit(localFireball.dummy)
            set activeFireballs = activeFireballs - 1
            set fireballArray[i] = fireballArray[activeFireballs]
            
            call localFireball.destroy()
            
        endif
        
        call DestroyEffect(smoke)
        set smoke = null
        set i = i + 1
    endloop
    
    if activeFireballs == 0 then
        call PauseTimer(fireballTimer)
    endif
    
endfunction

function activatedFireball takes nothing returns nothing
    local unit caster = GetTriggerUnit()
    local unit fireball
    local player casterOwner = GetOwningPlayer(GetTriggerUnit())
    local fireballData localFireball = fireballData.create()
    
    set fireball = CreateUnit(casterOwner, 'o003', GetUnitX(caster), GetUnitY(caster), GetUnitFacing(caster))
    call UnitApplyTimedLife(fireball, 'B001', .21)
    call SetUnitPathing(fireball, false)
    set localFireball.caster = caster
    set localFireball.dummy = fireball
    set localFireball.angle = GetUnitFacing(caster)
    set localFireball.x = GetUnitX(caster)
    set localFireball.y = GetUnitY(caster)
    set localFireball.speed = 33.
    set localFireball.maxDist = 700.
    set localFireball.distance = 0.
    set fireballArray[activeFireballs] = localFireball
    
    if activeFireballs <= 0 then
        call TimerStart(fireballTimer, fireballInterval, true, function fireballExecution)
    endif
    
    set activeFireballs = activeFireballs + 1
    
    set caster = null
    set fireball = null
    set casterOwner = null
    call localFireball.destroy()
    
endfunction

function checkFireball takes nothing returns boolean
    if GetSpellAbilityId() == 'A005' then
        call activatedFireball()
    endif
    return false
endfunction

function InitTrig_Fireball takes nothing returns nothing
    local trigger localTrigVar = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( localTrigVar, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( localTrigVar, Condition( function checkFireball ) )
    set localTrigVar = null
endfunction
 

Attachments

  • MvMAbilityDump.w3x
    28.3 KB · Views: 27
The most commonly used method to damage a nearby unit is a group enumeration (you'll want a low radius, like 64 or something). Here is an example:
JASS:
globals
    private group g = CreateGroup()
endglobals

function Example takes nothing returns nothing 
    local real x = GetUnitX(GetTriggerUnit())
    local real y = GetUnitY(GetTriggerUnit())
    local unit fog 

    call GroupEnumUnitsInRange(g, x, y, 100, null)
    loop
        set fog = FirstOfGroup(g)
        exitwhen fog == null
        if IsUnitEnemy(fog, GetTriggerPlayer()) then
            call UnitDamageTarget(GetTriggerUnit(), fog, 5000, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
        endif
        call GroupRemoveUnit(g, fog)
    endloop
endfunction

That will enumerate the units within a 100 radius around the trigger unit. If they are an enemy, it will damage them. In your case, upon damaging you would destroy the instance (because the fireball should stop moving): call localFireball.destroy()

That is how you would go about it. As for damaging, a simple UnitDamageTarget() will work (as shown above).
 
Last edited:
Level 4
Joined
Sep 25, 2005
Messages
71
I tried as much, but for some reason it's locking up the game:

JASS:
unction fireballExecution takes nothing returns nothing
    local integer i = 0
    local real x = 0.
    local real y = 0.
    local effect smoke
    local unit enemy
    local group affectedUnits = CreateGroup()
    
    local fireballData localFireball = fireballData.create()
    

    loop
        exitwhen i >= activeFireballs
        
        
        set localFireball = fireballArray[i]
        set x = GetUnitX(localFireball.dummy) + localFireball.speed * Cos(localFireball.angle * bj_DEGTORAD)
        set y = GetUnitY(localFireball.dummy) + localFireball.speed * Sin(localFireball.angle * bj_DEGTORAD)
        
        call SetUnitBoundedX(localFireball.dummy, x)
        call SetUnitBoundedY(localFireball.dummy, y)
        
        set localFireball.distance = localFireball.distance + localFireball.speed
        
        set smoke = AddSpecialEffect("Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl", x, y)
        
        call GroupEnumUnitsInRange(fireballTargets, x, y, 64, null)
        loop
            set enemy = FirstOfGroup(fireballTargets)
            exitwhen enemy == null
            if IsUnitEnemy(enemy, GetTriggerPlayer()) == true then
                call UnitDamageTarget(GetTriggerUnit(), enemy, 100, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
            endif
        endloop
        
        if localFireball.distance >= localFireball.maxDist then

            call KillUnit(localFireball.dummy)
            set activeFireballs = activeFireballs - 1
            set fireballArray[i] = fireballArray[activeFireballs]
            
            call localFireball.destroy()
            
        endif
        
        call DestroyEffect(smoke)
        set affectedUnits = null
        set smoke = null
        set i = i + 1
    endloop

Since it requires the fireball to reach the distance to deal with the instances, if I did "call localFireball.destroy" it messes up the iteration too, right? Could it be the fast I'm having it iterate at a really fast interval?

EDIT: That can't be it. It's now not killing the unit, deals no damage with each movement, even with a "slowed" interval (.5 instead of .012):

JASS:
function fireballExecution takes nothing returns nothing
    local integer i = 0
    local real x = 0.
    local real y = 0.
    local effect smoke
    local unit enemy
    
    local fireballData localFireball = fireballData.create()
    

    loop
        exitwhen i >= activeFireballs
        
        
        set localFireball = fireballArray[i]
        set x = GetUnitX(localFireball.dummy) + localFireball.speed * Cos(localFireball.angle * bj_DEGTORAD)
        set y = GetUnitY(localFireball.dummy) + localFireball.speed * Sin(localFireball.angle * bj_DEGTORAD)
        
        call SetUnitBoundedX(localFireball.dummy, x)
        call SetUnitBoundedY(localFireball.dummy, y)
        
        set localFireball.distance = localFireball.distance + localFireball.speed
        
        set smoke = AddSpecialEffect("Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl", x, y)
        
        call GroupEnumUnitsInRange(fireballTargets, x, y, 64, null)
        loop
            set enemy = FirstOfGroup(fireballTargets)
            exitwhen enemy == null
            if IsUnitEnemy(enemy, GetTriggerPlayer()) == true then
                call UnitDamageTarget(GetTriggerUnit(), enemy, 100, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
            endif
        endloop
        
        if localFireball.distance >= localFireball.maxDist then

            call KillUnit(localFireball.dummy)
            set activeFireballs = activeFireballs - 1
            set fireballArray[i] = fireballArray[activeFireballs]
            
            call localFireball.destroy()
            
        endif
        
        call DestroyEffect(smoke)
        set smoke = null
        set i = i + 1
    endloop
    
    if activeFireballs == 0 then
        call PauseTimer(fireballTimer)
    endif
    
endfunction
 
Level 4
Joined
Sep 25, 2005
Messages
71
No more lockup, however, there's some sort of issue. I'm trying to get it to affect neutral hostiles, which I'm pretty sure changes the behavior of stuff.

Anyways, I added in a "KillUnit" effect purely to debug, and what I'm finding is immediately upon activating the ability, it happens. There's some issue with how it's figuring here.

JASS:
        call GroupEnumUnitsInRange(fireballEnumGroup,x,y, 128., null)
        loop
            set enemy = FirstOfGroup(fireballEnumGroup)
            exitwhen enemy == null
            if IsUnitEnemy(enemy, GetTriggerPlayer()) then
                call UnitDamageTarget(GetTriggerUnit(), enemy, 50., true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, null)
                call KillUnit(localFireball.dummy)
            endif
            call GroupRemoveUnit(fireballEnumGroup, enemy)
        endloop
 
I just posted mine as an example. In your case, you may need to modify some things, namely GetTriggerPlayer() and GetTriggerUnit().

GetTriggerPlayer() should be GetOwningPlayer(localFireball.dummy)
GetTriggerUnit() should be localFireball.caster

At the moment, GetTriggerPlayer() and GetTriggerUnit() are probably returning null in the timer periodic function.
 
Level 4
Joined
Sep 25, 2005
Messages
71
I went back and found that was exactly the case. Thanks for your help, by the way! Here's the full functional code, if you notice something alarming/an unfixed leak etc.:

JASS:
globals
    timer fireballTimer = CreateTimer()
    real fireballInterval = .015
    integer activeFireballs = 0
    group fireballEnumGroup = CreateGroup()
    fireballData array fireballArray
endglobals

struct fireballData
    unit caster
    unit dummy
    real angle
    real x
    real y
    real speed
    real maxDist
    real distance
endstruct

function fireballExecution takes nothing returns nothing
    local integer i = 0
    local real x = 0.
    local real y = 0.
    local effect smoke
    local effect explosion
    local unit enemy
    
    local fireballData localFireball = fireballData.create()
    

    loop
        exitwhen i >= activeFireballs
        
        
        set localFireball = fireballArray[i]
        set x = GetUnitX(localFireball.dummy) + localFireball.speed * Cos(localFireball.angle * bj_DEGTORAD)
        set y = GetUnitY(localFireball.dummy) + localFireball.speed * Sin(localFireball.angle * bj_DEGTORAD)
        
        call SetUnitBoundedX(localFireball.dummy, x)
        call SetUnitBoundedY(localFireball.dummy, y)
        
        set localFireball.distance = localFireball.distance + localFireball.speed
        
        set smoke = AddSpecialEffect("Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl", x, y)
        
        call GroupEnumUnitsInRange(fireballEnumGroup, x, y, 128., null)
        loop
            set enemy = FirstOfGroup(fireballEnumGroup)
            exitwhen enemy == null
            if IsUnitEnemy(enemy, GetOwningPlayer(localFireball.caster)) == true and IsUnitAliveBJ(enemy) == true then
                call UnitDamageTarget(localFireball.caster, enemy, 250., true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, null)
                set explosion = AddSpecialEffect("Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl", x, y)
                call DestroyEffect(explosion)
                call KillUnit(localFireball.dummy)
                set localFireball.distance = localFireball.maxDist
            endif
            call GroupRemoveUnit(fireballEnumGroup, enemy)
        endloop
        
        if localFireball.distance >= localFireball.maxDist then

            call KillUnit(localFireball.dummy)
            set activeFireballs = activeFireballs - 1
            set fireballArray[i] = fireballArray[activeFireballs]
            
            call localFireball.destroy()
            
        endif
        
        call DestroyEffect(smoke)
        set explosion = null
        set smoke = null
        set enemy = null
        set i = i + 1
    endloop
    
    if activeFireballs == 0 then
        call PauseTimer(fireballTimer)
    endif
    
endfunction

function activatedFireball takes nothing returns nothing
    local unit caster = GetTriggerUnit()
    local unit fireball
    local player casterOwner = GetOwningPlayer(GetTriggerUnit())
    local fireballData localFireball = fireballData.create()
    
    set fireball = CreateUnit(casterOwner, 'o003', GetUnitX(caster), GetUnitY(caster), GetUnitFacing(caster))
    call UnitApplyTimedLife(fireball, 'B001', .33)
    call SetUnitPathing(fireball, false)
    set localFireball.caster = caster
    set localFireball.dummy = fireball
    set localFireball.angle = GetUnitFacing(caster)
    set localFireball.x = GetUnitX(caster)
    set localFireball.y = GetUnitY(caster)
    set localFireball.speed = 33.
    set localFireball.maxDist = 700.
    set localFireball.distance = 0.
    set fireballArray[activeFireballs] = localFireball
    
    if activeFireballs <= 0 then
        call TimerStart(fireballTimer, fireballInterval, true, function fireballExecution)
    endif
    
    set activeFireballs = activeFireballs + 1
    
    set caster = null
    set fireball = null
    set casterOwner = null
    call localFireball.destroy()
    
endfunction

function checkFireball takes nothing returns boolean
    if GetSpellAbilityId() == 'A005' then
        call activatedFireball()
    endif
    return false
endfunction

function InitTrig_Fireball takes nothing returns nothing
    local trigger localTrigVar = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( localTrigVar, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( localTrigVar, Condition( function checkFireball ) )
    set localTrigVar = null
endfunction
 
Level 4
Joined
Sep 25, 2005
Messages
71
Also, won't -asbolute- simultaneous castings mess this up?

When I tried a nearly identical instancing structure with another ability (a plain move-forward ability,) one unit would get the effect, the others would get stuck without any effect from the timer.

This is similar to when the fireballs are spammed in this ability.

Is there any way to make sure that -never- happens?
 
Last edited:
The first and most notable issue that may be related to it is this line:
JASS:
    set caster = null
    set fireball = null
    set casterOwner = null
    call localFireball.destroy() // this line
You are destroying the instance prematurely. Remember that you don't just destroy things at the end of the function--you destroy them when you are completely finished with using them (in this case, when the spell is over). You only need to destroy it when (A) the fireball hits a unit, or (B) the fireball finishes goes its max distance.

When you destroy it prematurely, that instance is sent to the recycler to be used by the next instance. Thus, the next casts may take that instance and overwrite the instance's data while the first spell is still in progress. That's why you should only destroy it when you're finished with the spell--you don't want any of the data to be overwritten.

The second issue is this line in "fireballExecution":
JASS:
    local fireballData localFireball = fireballData.create()
It should just be:
JASS:
    local fireballData localFireball
Otherwise you are creating an instance for no reason. :) [which may make you hit the 8192 simultaneous instance limit] You already get the instance in the loop through set localFireball = fireballArray[i], so you don't need to create one. You just need to write the local (without a declaration) so you can use it to point to the spell's instances.

Make those changes and it should work. ;D
 
Level 4
Joined
Sep 25, 2005
Messages
71
The second issue is this line in "fireballExecution":
JASS:
    local fireballData localFireball = fireballData.create()
It should just be:
JASS:
    local fireballData localFireball
Otherwise you are creating an instance for no reason. :) [which may make you hit the 8192 simultaneous instance limit] You already get the instance in the loop through set localFireball = fireballArray[i], so you don't need to create one. You just need to write the local (without a declaration) so you can use it to point to the spell's instances.

Make those changes and it should work. ;D

The first suggestion indeed fixed the problem for this and the other spell I was working on, but I have to ask: aren't I now creating a struct that is never destroyed each time this is called?

As for the other, by not intializing it, it doesn't seem to be passing data correctly. For instance by simply having a non-initialized localFireball it creates the dummy unit correctly but the execution of the actual spell doesn't happen anymore.

Wait: I'm a dumbass. I went for the other function, not the execute! Yeah, that works now.

Still, yeah, aren't I just leaving a struct there without calling .destroy()?
 
Still, yeah, aren't I just leaving a struct there without calling .destroy()?

That's a good question. The answer is no. Here is a quick explanation:

You create an instance "activatedFireball". Then the timer starts. When the fireball reaches its max distance or hits a unit, you call the .destroy() method on that instance. Thus, it is properly removed.

When you make a spell with a periodic system, you are just passing the same data throughout the spell. You aren't creating new ones, otherwise we would have to destroy it each time we accessed the data. We are just reading the same instance over and over, and once the spell is done, you can safely destroy it.

If you destroy it before that, then there will be issues. You might be under the impression that it is okay because your spell still worked (there is a logical reason behind that, but it relates to how structs work internally), but it is still problematic. :)
 
Level 4
Joined
Sep 25, 2005
Messages
71
That makes sense. I figured. Thanks for the explanation. So basically, I create the instance, assign it to the array, and we're good there. We use the execution function local for another to pass the data to, and we destroy that and set the prior values in the array to "recycle" them.

This is why, for instance, the whole incrementation of the localFireball.distance vs. localFireball.maxDist works, right? because it's still there. We get rid of it at execution and everything is fine in terms of leaks, then, correct?

One last question. Say if I wanted to make it not die on contact, but instead affect any units it passes through - but not periodically, only one time for each unit. What would be a good way to do this? I imagine finding an enum func to basically add them to a unit group for it to check if "this unit has been affected," right? Or is there some other flag functionality I could use?
 
That makes sense. I figured. Thanks for the explanation. So basically, I create the instance, assign it to the array, and we're good there. We use the execution function local for another to pass the data to, and we destroy that and set the prior values in the array to "recycle" them.

This is why, for instance, the whole incrementation of the localFireball.distance vs. localFireball.maxDist works, right? because it's still there. We get rid of it at execution and everything is fine in terms of leaks, then, correct?

Yes. Perfect. ;)

One last question. Say if I wanted to make it not die on contact, but instead affect any units it passes through - but not periodically, only one time for each unit. What would be a good way to do this? I imagine finding an enum func to basically add them to a unit group for it to check if "this unit has been affected," right? Or is there some other flag functionality I could use?

A group per spell cast is the best option, IMO. You can do flagging, but you have to keep track of the units to set their flags back to false after the spell is done. With groups, you can easily keep track of them.
 
Level 4
Joined
Sep 25, 2005
Messages
71
Alright. So changing the current enum funcs, I should probably create a... Global group array? A local group? Add unit to it during the enum loop, then at end of the fireballExecute deal damage to it?

Also, is there some form of indicator for whether a unit is flying/ground? I mean, cool as it sounds, a ground-bound fireball doesn't seem to make sense hitting something up in the sky.

Instead of doing as ideal, my current code doesn't seem to properly check whether the unit is part of the group or not or perhaps just add it. Here's my current fireballExecute function trying to implement such a damaging system:
JASS:
function fireballExecution takes nothing returns nothing
    local integer i = 0
    local real x = 0.
    local real y = 0.
    local effect smoke
    local effect explosion
    local unit enemy
    local group fireballTargets = CreateGroup()
    
    local fireballData localFireball
    

    loop
        exitwhen i >= activeFireballs
        
        
        set localFireball = fireballArray[i]
        set x = GetUnitX(localFireball.dummy) + localFireball.speed * Cos(localFireball.angle * bj_DEGTORAD)
        set y = GetUnitY(localFireball.dummy) + localFireball.speed * Sin(localFireball.angle * bj_DEGTORAD)
        
        call SetUnitBoundedX(localFireball.dummy, x)
        call SetUnitBoundedY(localFireball.dummy, y)
        
        set localFireball.distance = localFireball.distance + localFireball.speed
        
        set smoke = AddSpecialEffect("Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl", x, y)
        
        call GroupEnumUnitsInRange(fireballEnumGroup, x, y, 128., null)
        loop
            set enemy = FirstOfGroup(fireballEnumGroup)
            exitwhen enemy == null
            if IsUnitEnemy(enemy, GetOwningPlayer(localFireball.caster)) == true and GetWidgetLife(enemy) > 0.405 == true and IsUnitInGroup(enemy, fireballTargets) == false then
                call GroupAddUnit(fireballTargets, enemy)
                call UnitDamageTarget(localFireball.caster, enemy, 50., true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, null)
                set explosion = AddSpecialEffect("Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl", x, y)
                call DestroyEffect(explosion)
            endif
            call GroupRemoveUnit(fireballEnumGroup, enemy)
        endloop
        
        if localFireball.distance >= localFireball.maxDist then

            call GroupClear(fireballTargets)
            call KillUnit(localFireball.dummy)
            set activeFireballs = activeFireballs - 1
            set fireballArray[i] = fireballArray[activeFireballs]
            
            call localFireball.destroy()
            
        endif
        
        call DestroyEffect(smoke)
        set explosion = null
        set smoke = null
        set enemy = null
        set i = i + 1
    endloop
    
    if activeFireballs == 0 then
        call PauseTimer(fireballTimer)
    endif
    
endfunction

Is it because the group gets cleared before the next check? Wouldn't it be so long as the unit was there for more than two checks, it should be avoid dealing damage as is?
 
Last edited:
When you create it as a local, there is no reference to it the next time the timer ticks. Thus, it doesn't know if the unit is ever in the group.

Actually, it creates a new group every time the timer ticks. Instead, you should make a group struct member.
JASS:
struct fireballData
    unit caster
    unit dummy
    real angle
    real x
    real y
    real speed
    real maxDist
    real distance
    group hit
endstruct

In the create method where you set all the members, add:
set localFireball.hit = CreateGroup()

In the area where you add the unit, modify it to:
JASS:
call GroupAddUnit(localFireball.hit, enemy)
And change the IsUnitInGroup() check to check if the unit is in the "hit" group instead.

Then, when you destroy the instance, just call DestroyGroup(localFireball.hit).
 
You should be able to use:
JASS:
IsUnitType(<unit>, UNIT_TYPE_FLYING)
IsUnitType(<unit>, UNIT_TYPE_GROUND)

Alternatively:
JASS:
GetUnitFlyHeight(<unit>) > 0 // means flying
But flying units can have a fly height of 0 so it isn't super accurate.

EDIT: And thanks for the compliment. :D You're taking all this in quite fast, too, so you deserve also kudos.
 
Yeah, you can. There are a few ways. First way:
JASS:
function DamageFilter takes unit u, player p, group g returns boolean
    return IsUnitEnemy(u, p) and GetWidgetLife(u) > 0.405 and not IsUnitType(u, UNIT_TYPE_FLYING) and not IsUnitInGroup(u, g)
endfunction
Or if you don't want it to stretch your trigger to the ends of the earth, you can abuse comment delimiters:
JASS:
function DamageFilter takes unit u, player p, group g returns boolean
    return IsUnitEnemy(u, p) /*
    */ and GetWidgetLife(u) > 0.405 /*
    */ and not IsUnitType(u, UNIT_TYPE_FLYING) /*
    */ and not IsUnitInGroup(u, g)
endfunction
 
Level 16
Joined
Dec 15, 2011
Messages
1,423
Yeah, you can. There are a few ways. First way:
JASS:
function DamageFilter takes unit u, player p, group g returns boolean
    return IsUnitEnemy(u, p) and GetWidgetLife(u) > 0.405 and not IsUnitType(u, UNIT_TYPE_FLYING) and not IsUnitInGroup(u, g)
endfunction
Or if you don't want it to stretch your trigger to the ends of the earth, you can abuse comment delimiters:
JASS:
function DamageFilter takes unit u, player p, group g returns boolean
    return IsUnitEnemy(u, p) /*
    */ and GetWidgetLife(u) > 0.405 /*
    */ and not IsUnitType(u, UNIT_TYPE_FLYING) /*
    */ and not IsUnitInGroup(u, g)
endfunction

In my humble opinion, the GetWidgetLife(u) > 0.405 method is kinda not a foolproof method to detect whether the unit is alive or not. Magtheridon96 outlined it nicely here. That being said, I think we should be using the UnitAlive native instead.

Of course it is still a viable approach to solving the problem and it is up to the OP to choose what to follow.

P.S: Please don't hate me for this Sensei x)
 
Level 4
Joined
Sep 25, 2005
Messages
71
Yeah, you can. There are a few ways. First way:
JASS:
function DamageFilter takes unit u, player p, group g returns boolean
    return IsUnitEnemy(u, p) and GetWidgetLife(u) > 0.405 and not IsUnitType(u, UNIT_TYPE_FLYING) and not IsUnitInGroup(u, g)
endfunction
Or if you don't want it to stretch your trigger to the ends of the earth, you can abuse comment delimiters:
JASS:
function DamageFilter takes unit u, player p, group g returns boolean
    return IsUnitEnemy(u, p) /*
    */ and GetWidgetLife(u) > 0.405 /*
    */ and not IsUnitType(u, UNIT_TYPE_FLYING) /*
    */ and not IsUnitInGroup(u, g)
endfunction


I had figured there was a similar syntax as in java for comment "blocks." Thanks a ton, that looks a lot better. Although I did have some issues implementing it inside a struct as a method (for my Lightning Cone ability,) this is the kind of function I would probably want to just put with other global map script anyways (Is unit not-dead, enemy, correct air/ground, and not spell immune/resistant, or mechanical = valid target for most spells)
 
In my humble opinion, the GetWidgetLife(u) > 0.405 method is kinda not a foolproof method to detect whether the unit is alive or not. Magtheridon96 outlined it nicely here. That being said, I think we should be using the UnitAlive native instead.

Yep, I know. I just rewrote his conditions in the function. Thanks for the link though.
 
Status
Not open for further replies.
Top