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

Static counterpart to Enter region event?

Status
Not open for further replies.
Level 15
Joined
Aug 7, 2013
Messages
1,337
Hi,

Is there a static counterpart to an Enter region event, i.e.

if a unit is in a region?

EnterRegion event is, well, an event. The state of the unit goes from

Not in region --> in region

So if a unit is already in a region, EnterRegion won't fire off.

On the other hand, the static form would only detect if the unit is in the region (i.e. a state rather than a change/event).

How would I make a trigger that does this (fires off whenever a unit is inside a region?)?
 
Try this. As far as a trigger that fires, why not add the unit to the enters region event and then immediately check if it is in the region?
JASS:
function IsUnitNotInRect takes unit Unit,rect R returns boolean
    local real X=GetUnitX(Unit)
    local real Y=GetUnitY(Unit)
    return X<GetRectMinX(R)or X>GetRectMaxX(R)or Y<GetRectMinY(R)or Y>GetRectMaxY(R)
endfunction
 
An event usually implies a change in some state. To statically determine if a unit is in a region, you would simply use IsUnitInRegion, or for a rect:
JASS:
function IsUnitInRect takes unit u, rect r returns boolean
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    return (x >= GetRectMinX(r)) and (x <= GetRectMaxX(r)) and (y >= GetRectMinY(r)) and (y <= GetRectMaxY(r))
endfunction

But it wouldn't make sense for a trigger to fire when a unit exists inside a region, because that would fire an infinite amount of times. Instead, go with a periodic timer and just check if the unit is still inside the region, or have a separate event that fires when a unit leaves and determine who is still inside based on that (add units to a group when they enter, remove them when they leave. do what you want with the group).

edit: Beat to the post.
 
Level 15
Joined
Aug 7, 2013
Messages
1,337
I'm not asking for a function that tells me if a unit is in a rect.

I'm asking for how to fire a trigger as a reaction to a unit being in a rect/region.

It wouldn't fire an infinite number of times--it'd just fire every trigger cycle. Which could potentially go on forever, until the trigger is disabled.

The unit has been in the region/rect for quite some time before I turn on the trigger.

Problem with timer is, is that I can't bind it to a player without doing it myself. Was hoping to use the standard jass trigger event API.
 
Level 15
Joined
Aug 7, 2013
Messages
1,337
You want all existing units in the rect to trigger the enter event when you create the trigger?

Exactly. Thanks for fleshing it out.

Hmm...that could work I suppose. I just have to fiddle around with the event orderings/timings.

I was thinking of using this event instead:

JASS:
call TriggerRegisterPlayerUnitEvent(t, players[pid], EVENT_PLAYER_UNIT_SELECTED, null)

Any way I can force a player to select a unit, which would then fire off that event?
 
TriggerEvaluate? You're going to have to manage that event yourself, since there isn't an event that reacts to a unit being inside a rect/region. Or you can always move the unit out and back in, but it would be better to just manage an event yourself.

Essentially, you would manage the data and firing yourself. Custom events are pretty useful since they allow you to emulate JASS trigger behavior.

First, you'll have some global trigger that manages the event. Whenever someone wants to register something to it, just add that code to the trigger, e.g.:
JASS:
globals
    trigger customEvent = CreateTrigger()
endglobals

function RegisterSomeEvent takes code c returns nothing
    call TriggerAddCondition(customEvent, Condition(c)) 
    // with jasshelper enabled, this implies that c returns boolean
    // you can also use TriggerAddAction + TriggerExecute instead
endfunction

Registering an event is as simple as adding some functions to the trigger. When you want the event to fire, simply use TriggerEvaluate(). If you want to pass data, just use globals and some wrappers. e.g.:
JASS:
globals
    trigger customEvent = CreateTrigger()
    unit triggerData = null
endglobals

function RegisterSomeEvent takes code c returns nothing
    call TriggerAddCondition(customEvent, Condition(c)) 
endfunction

function FireSomeEvent takes nothing returns nothing
    local unit temp = triggerData
    set triggerData = GetTriggerUnit() // assign data
    call TriggerEvaluate(customEvent)
    set triggerData = temp // this is related to recursion, ask if you need an explanation
    set temp = null
endfunction

function GetSomeEventTriggerUnit takes nothing returns unit
    return triggerData
endfunction

In that sense, someone can easily have an interface to respond to that event:
JASS:
scope Example initializer Init
    private function Act takes nothing returns boolean
        local unit triggeringUnit = GetSomeEventTriggerUnit() // event data
        // do some things
        return false
    endfunction

    private function Init takes nothing returns nothing
        call RegisterSomeEvent(function Act)
    endfunction
endscope

Obviously, that is a very vague example which does nothing in particular. But it is useful when you want to create a system that exposes the user to an event-based interface, rather than relying on stub methods or extending structs, etc. (which uses triggers in the underlying code anyway).

Take for example, my Track system. I have custom events to register when a trackable is clicked or hovered. Of course, the user can register those events himself, but with custom events, I can expose the user to additional trigger data, such as the trackable's struct instance, the player who clicked it, etc.

Anyway, that should be what you're looking for. It is much better than evaluating an arbitrary trigger directly (what if you want more triggers to respond to the unit being in the region?), and it is better than forcing it through some weird method e.g. moving the unit out and away. You can also use something like TriggerRegisterVariableEvent. That is what is used to make custom GUI events in systems such as Bribe's DDS. You may want to check it out.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Yes there is a native that does exactly what you want.

JASS:
native IsUnitInRegion takes region whichRegion,unit whichUnit returns Boolean

Obviously this is not an event since there are already events to detect the change in this value. You may need to check periodically, or on map initialization for pre-placed units.
 
Level 15
Joined
Aug 7, 2013
Messages
1,337
Thank you for your very comprehensive example Purgeandfire.

I am little confused as how to this would solve my problem, since my understanding it's just a circular solution, because

JASS:
function FireSomeEvent takes nothing returns nothing
    local unit temp = triggerData
    set triggerData = GetTriggerUnit() // assign data
    call TriggerEvaluate(customEvent)
    set triggerData = temp // this is related to recursion, ask if you need an explanation
    set temp = null
endfunction

this function needs to be called. But how? When does it get called?

I've got all my functions/structures lined up, it's just getting the trigger to fire in the case I mentioned above--a reaction to a unit being in a region (that it has already entered).
 
Last edited:

EdgeOfChaos

E

EdgeOfChaos

Just use a periodic with 0.01 (or 0.03, whatever you want) and do your actions for all units in the region, imo.
 
Status
Not open for further replies.
Top