• 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] Specific unit leaving region

Status
Not open for further replies.
Level 14
Joined
Jul 1, 2008
Messages
1,314
Hey everybody,

I got a question about this native:

JASS:
native TriggerRegisterLeaveRegion takes trigger whichTrigger, region whichRegion, boolexpr filter returns event

Is it possible to use its boolexpr in a way to make the event only trigger, once a specific unit leaves a specific region (which would make it a specific unit event)?

by using the boolexpr like "IsLeavingUnit == some specific unit, which is saved in a variable at the time of creating this boolexpr"

I have a system that recognizes units of certain type and then creates other triggers for these specific units.

One of them should be a "specific unit leaves region X" trigger
(for performance reasons, I did not want every unit be able to trigger this)

So I tried to create a trigger like this (which fires upon a specific unit entering region X):

JASS:
set tempTrigger = CreateTrigger()
            set CattleRegisterLeavingUnit = cattle
            call TriggerRegisterLeaveRegion( tempTrigger, region X, Condition( function CattleCheckLeavingTypeId))

and

JASS:
function CattleCheckLeavingTypeId takes nothing returns boolean
        // only allow region triggering to be activated by the right unit (cattle)
        return GetLeavingUnit() == CattleRegisterLeavingUnit
    endfunction

function Actionfunction
// -> send back leaving cattle to left region X

So, I thought, this creates a Conditional Event, where this specific unit is stored. This would be a specific unit event.

What I expected to go wrong:

Every unit leaving the region X would trigger this and sends back the assigned unit.

What actually goes wrong:

Every unit leaving triggers this and the very same unit is send back into the region X


Thanks for reading this and for any help :)
 
Level 14
Joined
Jul 1, 2008
Messages
1,314
The only way to make it specific is to use the "gane time" event which will run every 0.10 seconds or so. In the actions, check if your unit is still in the region.

It's probably more efficient to leave it as-is.

Hey Bribe, thanks for your answer.

I know I could check periodically or just use a general LeavesRegion Events and check for unit types, but I was curious about this boolexpr, that this native takes.

So using this boolexpr does not work?
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
That should work, excepted i think you should use GetFilterUnit instead of GetTrigger/Leaving/Unit.
Now all units will still fire the event, and then the boolexpr will be evaluated.
I don't know if there is a difference (in term of performance) with an event with a null boolexpr and a trigger condition.
 
Level 14
Joined
Jul 1, 2008
Messages
1,314
That should work, excepted i think you should use GetFilterUnit instead of GetTrigger/Leaving/Unit.
Now all units will still fire the event, and then the boolexpr will be evaluated.
I don't know if there is a difference (in term of performance) with an event with a null boolexpr and a trigger condition.

unfortunately changing it to GetFilterUnit() disabled the event :/ but thanks for your comment ..
 
Level 14
Joined
Jul 1, 2008
Messages
1,314
There is it :)

JASS:
library CATTLE                                                               
    
    globals
        private          trigger tempTrigger
        private          unit    CattleRegisterLeavingUnit   = null            // internal helper to register cattle region events
    endglobals
    
    
    function CattleCheckLeavingTypeId takes nothing returns boolean
        // only allow region triggering to be activated by the right unit (cattle)
        return GetLeavingUnit() == CattleRegisterLeavingUnit
        // return GetFilterUnit() == CattleRegisterLeavingUnit
    endfunction
    
    private function CattleSendBackToRegisteredRegion takes nothing returns nothing
        // this function is used to send cattle back to its assigned region, if it leaves and is not allowed
        local unit cattle               = GetLeavingUnit()
        local boolean IsAllowedToLeave  = LoadBoolean( udg_GAMEPLAY_DATA[15], GetHandleId( cattle), 5)
        local integer WHICH_REGION      = 0
        local real x                    = 0.
        local real y                    = 0.
        // if cattle is not allowed to leave its assigned region, then send it back
        if not IsAllowedToLeave then
            set WHICH_REGION = LoadInteger( udg_GAMEPLAY_DATA[15], GetHandleId( cattle), 6) // load assigned region index
            set x = GetRandomReal( GetRectMinX( udg_GAMEPLAY_Rects[WHICH_REGION]), GetRectMaxX( udg_GAMEPLAY_Rects[WHICH_REGION]))
            set y = GetRandomReal( GetRectMinY( udg_GAMEPLAY_Rects[WHICH_REGION]), GetRectMaxY( udg_GAMEPLAY_Rects[WHICH_REGION]))
            call IssuePointOrder( cattle, "move", x, y)
        endif
        // Remove Leaks
        set cattle = null
    endfunction
    
    // *************************************************************************************************************
    // Cattle Fate Decision Block
    // *************************************************************************************************************
    private function RegisterCattleLifeEvents takes nothing returns nothing
        local unit cattle                = GetEnteringUnit()
        local boolean WasRegistered      = LoadBoolean( udg_GAMEPLAY_DATA[15], GetHandleId( cattle), 0) // check, if cattle was already registered
        local timer CATTLE_GROWTH_TIMER  
        local integer cattleType         = GetUnitTypeId( cattle)
        local integer cattleTiming       = 0
        local integer playerId           = GetPlayerId( GetOwningPlayer( cattle))
        local integer WHICH_REGION       = 0
        
        // only register cattle, if it enters the first time 
        if WasRegistered == FALSE then
            // Mark cattle as registered
            call SaveBoolean( udg_GAMEPLAY_DATA[15], GetHandleId( cattle), 0, TRUE)
            // Store cattle assigned region.
            call SaveBoolean( udg_GAMEPLAY_DATA[15], GetHandleId( cattle), 5, FALSE)
            if cattleType == 'n005' or cattleType == 'n00I' then // chicken    
                // lock chicken into barn
                set WHICH_REGION = (playerId*13)+1
            else
                // lock cows and pigs into stable Region
                set WHICH_REGION = (playerId*13)+7
            endif
            call SaveInteger( udg_GAMEPLAY_DATA[15], GetHandleId( cattle), 6, WHICH_REGION)
            set CattleRegisterLeavingUnit = cattle
            set tempTrigger = CreateTrigger()
            call TriggerRegisterLeaveRegion( tempTrigger, udg_GAMEPLAY_Regions[WHICH_REGION], Condition( function CattleCheckLeavingTypeId))
            call TriggerAddAction( tempTrigger, function CattleSendBackToRegisteredRegion)
        endif
        /* [...] */
        // Remove Leaks
        set cattle                    = null
        set CattleRegisterLeavingUnit = null
        set CATTLE_GROWTH_TIMER       = null
    endfunction
    
    // *************************************************************************************************************
    // Init Block (Has to be called from outside! GameSetUp\Game_Initialization)
    // *************************************************************************************************************
    public function RegisterCattle takes nothing returns nothing
        local integer index = 0
        // create a trigger, that will react to a player animal entering players' scheune
        set tempTrigger = CreateTrigger()
        loop
            exitwhen index > 3
            call TriggerRegisterEnterRegion( tempTrigger, udg_GAMEPLAY_Regions[(index*13)+1], null) // barn
            set index = index + 1
        endloop
        // The condition checks, whether the entering unit is of type cattle.
        call TriggerAddCondition( tempTrigger, Condition( function IsTriggerUnitCattleType))
        call TriggerAddAction( tempTrigger, function RegisterCattleLifeEvents)
        // Remove Leaks
        set tempTrigger = null
    endfunction
    
endlibrary
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Just tested, and i confirm that the native to use in a such filter is GetFilterUnit.
GetTriggerUnit and GetLeavingUnit returns null.

Now that said, i'm quite sure that doesn't worth to use a such boolexpr, the difference performance VS a null boolexpr event and a trigger condition, if any, would be unnoticeable in almost every scenario, if not all of them.

In fact, i've answered just for the sake of accuracy.
 
Level 14
Joined
Jul 1, 2008
Messages
1,314
hm strange, then the mistake has to be somewhere else. At least I know now, that you can use this. I stay with a normal condition function though.

Thanks to both of you for helping!

I guess, this is solved then.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,287
The event with filter is likely not be as efficient as one might think because it will still need to filter every unit leaving the region which translates to evaluating that JASS function for every unit leaving the region. That said the frequency of units leaving a region is generally such that one does not really need to consider such overhead.

If there are multiple specific units you want to test for leaving a region then the most efficient would be to either test if the leaving unit is in a group or has a certain hashtable entry. The unit group test is a simple native which does all the testing so should be very fast however it might suffer from O(n) degradation with larger groups. The hashtable test will be O(1) for most reasonable situations however the native itself might be slower to call due to more arguments. Both likely perform better than multiple triggers, multiple events with specific filters or multiple equality tests. However the performance improvement is likely so insignificant that optimizations elsewhere will make a much larger difference.
 
Status
Not open for further replies.
Top