• 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.

Is there any easier way of picking units?

Status
Not open for further replies.
Level 4
Joined
Feb 2, 2009
Messages
71
First of all, I'm new to JASS, but not new to creating triggers.
I know enough JASS to create simple spells,
but now that I'm trying to create more complex spells I get stuck.

I tried creating the pickfunction in the GUI and then convert it.
What I got was a haystack of GetBooleanAnd functions.
And also I got this boolexpr wich I didn't understand much about, but I've understood it's some kind of filter that is getting a boolean value from a bunch of functions. (correct me if I'm wrong)

Is there any easier/smarter way of picking units matching conditions?
 
Level 4
Joined
Feb 2, 2009
Messages
71
Hmm, I've tried to replicate it, but I don't get the filter to work. The trigger stops when I run the line

Tell me what I do wrong please.

Here's the filter:
Code:
function FilterTargets takes nothing returns boolean
    if not IsUnitType(GetFilterUnit(), UNIT_TYPE_HERO) then
    return FALSE
    elseif not IsUnitAlly(GetFilterUnit(), GetTriggerPlayer()) then
    return FALSE
    elseif not UnitHasBuffBJ(GetFilterUnit(), 'B000') then
    return FALSE
    elseif not (GetUnitLifePercent(GetFilterUnit()) > GetUnitLifePercent(GetTriggerUnit())) then
    return FALSE
    else
    return TRUE
    endif
endfunction

If you wonder about my if then else stack.
I thought it'd be an easy-to-read way of stacking up lots of conditions that all must be TRUE. Maybe that's where the error is?
I've tried with AND instead, but I get the same result.

And here's the other things:
Code:
local filterfunc filter = Filter(function FilterTargets)

call GroupEnumUnitsInRangeOfLoc(targetGroup, GetUnitLoc(caster), radius, filter)

The trigger stops when I call this function:
Code:
GroupEnumUnitsInRangeOfLoc(targetGroup, GetUnitLoc(caster), radius, filter)
 
Level 7
Joined
Jul 20, 2008
Messages
377
What do you mean by the trigger stops? Does it save without any compile error? If so:

I think the problem may be that you're using elseif where you shouldn't be. The way elses work is, if the first "if" statement is false, the next "else" statement will be considered, and if that is false too, the next "else" statement... and so on forth. But if one statement is true, then the rest of your statements are automatically ignored (which is why for maximum efficiency, you should always place the condition that is most likely to be true at the top).

My advice is to use OR, not AND, for any of the conditions that need to be true. AND means that ALL of the conditions must be true before that statement is executed. OR means at least one is true.

My suggestion: do something like this:

JASS:
if (Condition 1 that should be true) or (Condition 2 that should be true) or ... (Condition N that should be true) then
     return true
else
     return false
endif

Of course, it's much more efficient to do this:

JASS:
return (Condition 1) or (Condition 2) or ... (Condition N)
 
Level 4
Joined
Feb 2, 2009
Messages
71
What I mean with stop? It actually just stops. See below.

Code:
call DisplayTextToForce(GetPlayersAll(), "bump1")
call GroupEnumUnitsInRangeOfLoc(targetGroup, GetUnitLoc(caster), radius, filter)
call DisplayTextToForce(GetPlayersAll(), "bump2")
...Only "bump1" is displayed.

I need to use AND, becase all the booleans must be true.
I said that I had already tried with AND instead, but I get the same result.
 
Level 7
Joined
Jul 20, 2008
Messages
377
Put this in your filter function:

JASS:
call DisplayTextToForce(GetPlayersAll(), "bump2")

(btw, use
JASS:
 tags for your code here)

Just put that at different points in that function and see where it quits.
 
Level 4
Joined
Feb 2, 2009
Messages
71
JASS:
function FilterTargets takes nothing returns boolean
call DisplayTextToForce(GetPlayersAll(), "bump3")
return true
endfunction

"bump3" does not display. I think I just got my first grey hair!

EDIT:
I've tried removing everything but the pickfunction, still the same problem. Here's the whole trigger.
JASS:
function FilterTargets takes nothing returns boolean
    call DisplayTextToForce(GetPlayersAll(), "bump3")
    return true
endfunction

function Trig_BloodTransfusion_Conditions takes nothing returns boolean
    return  GetUnitAbilityLevel(GetTriggerUnit(), 'A000') == 1
endfunction

function Trig_BloodTransfusion_Actions takes nothing returns nothing
    local filterfunc filter = Filter(function FilterTargets)
    local group targetGroup
    loop
        call DisplayTextToForce(GetPlayersAll(), "bump1")
        call GroupEnumUnitsInRect(targetGroup, GetPlayableMapRect(), filter)
        call DisplayTextToForce(GetPlayersAll(), "bump2")
        call DestroyFilter(filter)
        call TriggerSleepAction(2.0)
    endloop
endfunction

//===========================================================================
function InitTrig_Blood_Transfusion_Copy takes nothing returns nothing
    set gg_trg_Blood_Transfusion_Copy = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Blood_Transfusion_Copy, EVENT_PLAYER_HERO_SKILL )
    call TriggerAddCondition( gg_trg_Blood_Transfusion_Copy, Condition( function Trig_BloodTransfusion_Conditions ))
    call TriggerAddAction( gg_trg_Blood_Transfusion_Copy, function Trig_BloodTransfusion_Actions )
endfunction
 
Last edited:
Level 11
Joined
Apr 6, 2008
Messages
760
endless loop...

JASS:
globals //if u have JNGP
    filterfunc filter
endglobals

function FilterTargets takes nothing returns boolean
    call DisplayTextToForce(GetPlayersAll(), "bump3")
    return true
endfunction

function Trig_BloodTransfusion_Conditions takes nothing returns boolean
    return  GetUnitAbilityLevel(GetTriggerUnit(), 'A000') == 1
endfunction

function Trig_BloodTransfusion_Actions takes nothing returns nothing
    local group targetGroup = CreateGroup() //didnt create the group
    local unit temp

    call GroupEnumUnitsInRect(targetGroup, GetPlayableMapRect(), filter)
    
    loop
        set temp = FirstOfGroup(targetGroup)
        exitwhen temp == null
        call GroupRemoveUnit(targetGroup,temp)
        call DisplayTextToForce(GetPlayersAll(), "bump1")
    endloop

    call DisplayTextToForce(GetPlayersAll(), "bump2")
    call DestroyGroup(targetGroup)
    call DestroyFilter(filter)
    set filter = null
    set targetGroup = null
endfunction

//===========================================================================
function InitTrig_Blood_Transfusion_Copy takes nothing returns nothing
    set gg_trg_Blood_Transfusion_Copy = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Blood_Transfusion_Copy, EVENT_PLAYER_HERO_SKILL )
    call TriggerAddCondition( gg_trg_Blood_Transfusion_Copy, Condition( function Trig_BloodTransfusion_Conditions ))
    call TriggerAddAction( gg_trg_Blood_Transfusion_Copy, function Trig_BloodTransfusion_Actions )
    set filter = Filter(function FilterTargets) //if u have JNGP
endfunction
 
Level 4
Joined
Feb 2, 2009
Messages
71
God bless you Ciebron!

Basically all my problems were solved as soon as I created the group.
Didn't know I had to. Works great now!

And ye, my loop was endless, that's because it's an aura that takes hitpoints from the caster, and gives to friendly units every 2 seconds. (blood transfusion).

I see you chose to set the filter as a global... why's that? It works with local too.

And oh, I don't know what JNGP is, but it seem like I have it. Maybe it's included in the Jass NewGen Pack v5b?
EDIT: HAHAHA I realized it was the pack... sorry for stupidity. I don't change it so everyone can laugh at me.

Anyway, here's the whole spell if you are interested. Let me see if you can find out what it does.
JASS:
function FilterTargets takes nothing returns boolean
    if not IsUnitType(GetFilterUnit(), UNIT_TYPE_HERO) then   //is hero?
    return FALSE
    elseif not IsUnitAlly(GetFilterUnit(), GetTriggerPlayer()) then //is an ally?
    return FALSE
    elseif not UnitHasBuffBJ(GetFilterUnit(), 'B000') then  //has buff?
    return FALSE
    elseif not (GetUnitLifePercent(GetFilterUnit()) < GetUnitLifePercent(GetTriggerUnit())) then  //has less hp then caster?
    return FALSE
    else
    return TRUE
    endif
endfunction

function Trig_BloodTransfusion_Conditions takes nothing returns boolean
    return  ((GetUnitAbilityLevel(GetTriggerUnit(), 'A000') == 1) and (GetUnitTypeId(GetTriggerUnit()) == 'O000' ))
    
endfunction

function Trig_BloodTransfusion_Actions takes nothing returns nothing
    local unit caster = GetTriggerUnit()
    local unit target
    local integer abilityLevel = GetUnitAbilityLevel(caster, 'A000')
    local group targetGroup = CreateGroup()
    local real points
    local real casterHP
    local real casterMP
    local filterfunc filter
    set filter = Filter(function FilterTargets)
    
    loop
    set casterHP = GetUnitState(caster, UNIT_STATE_LIFE)
    set casterMP = GetUnitState(caster, UNIT_STATE_MANA)
    set points = 0.01 * abilityLevel * GetUnitState(caster, UNIT_STATE_MAX_LIFE)
    call GroupEnumUnitsInRect(targetGroup, GetPlayableMapRect(), filter)
    if CountUnitsInGroup(targetGroup) > 0 then
        loop
        set target = GroupPickRandomUnit(targetGroup)
        call SetUnitLifeBJ(caster, casterHP - points)
        call SetUnitLifeBJ(target, GetUnitState(target, UNIT_STATE_LIFE) + points)
        call AddSpecialEffectTarget("Abilities\\Spells\\Human\\Feedback\\SpellBreakerAttack.mdl", target, "overhead")
        call AddSpecialEffectTarget("Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodPriest.mdl", caster, "chest")
        call GroupRemoveUnit(targetGroup, target)
        exitwhen CountUnitsInGroup(targetGroup) == 0
        endloop
    elseif GetUnitLifePercent(caster) > GetUnitManaPercent(caster)+1+abilityLevel then
    call SetUnitLifeBJ(caster, casterHP - points)
    call SetUnitManaBJ(caster, casterMP + points)
    call AddSpecialEffectTarget("Abilities\\Weapons\\HydraliskImpact\\HydraliskImpact.mdl", caster, "chest")
    endif
    exitwhen GetUnitState(caster, UNIT_STATE_LIFE) <= 0
    call DestroyFilter(filter)
    call TriggerSleepAction(2.0)
    endloop
endfunction

//===========================================================================
function InitTrig_Blood_Transfusion takes nothing returns nothing
    set gg_trg_Blood_Transfusion = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Blood_Transfusion, EVENT_PLAYER_HERO_SKILL )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Blood_Transfusion, EVENT_PLAYER_HERO_REVIVE_FINISH )
    call TriggerAddCondition( gg_trg_Blood_Transfusion, Condition( function Trig_BloodTransfusion_Conditions ))
    call TriggerAddAction( gg_trg_Blood_Transfusion, function Trig_BloodTransfusion_Actions )
endfunction

Feel free to give me tips about how to improve it, if it aint too complicated. I'm new to JASS. This is my second spell.
 
Level 11
Joined
Apr 6, 2008
Messages
760
if you are planning to make a multiplayer map i wouldnt recomment a sleep since its very in accurate use a timer instead.
JASS:
    call TriggerSleepAction(2.0)

JASS:
function FilterTargets takes nothing returns boolean
    if not IsUnitType(GetFilterUnit(), UNIT_TYPE_HERO) then   //is hero?
    return FALSE
    elseif not IsUnitAlly(GetFilterUnit(), GetTriggerPlayer()) then //is an ally?
    return FALSE
    elseif not UnitHasBuffBJ(GetFilterUnit(), 'B000') then  //has buff?
    return FALSE
    elseif not (GetUnitLifePercent(GetFilterUnit()) < GetUnitLifePercent(GetTriggerUnit())) then  //has less hp then caster?
    return FALSE
    else
    return TRUE
    endif
endfunction

u call GetFilterUnit() 4 times and u have if then else

do

JASS:
function FilterTargets takes nothing returns boolean
    local unit u = GetFilterUnit()
    local unit t = GetTriggerUnit()
    local boolean ok = not IsUnitType(u, UNIT_TYPE_HERO) and not IsUnitAlly(u, GetOwningPlayer(t)) and GetUnitAbilityLevel(u, 'B000') > 0 and not (GetUnitLifePercent(u) < GetUnitLifePercent(t))
    set u = null
    set t = null
    return ok
endfunction

can do alot more with this code.. but have too sleep now :)
 
Level 4
Joined
Feb 2, 2009
Messages
71
Changed the filter now.

About the timer.
Can I use timer instead without rebuilding the whole trigger?
Timer doesn't pause the trigger like TriggerSleepAction does, right?
 
Level 7
Joined
Jul 20, 2008
Messages
377
Correct, starting a timer won't pause your trigger. However, here's where JASS is so nice - with a timer, you can specify a function for it to automatically call when the timer expires. You don't need a Timer Expires trigger. :)
 
Status
Not open for further replies.
Top