• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] Event (library)

Status
Not open for further replies.
Level 16
Joined
Mar 3, 2006
Messages
1,564
JASS:
library Event /* v2.0.0.1
************************************************************************************
*
*   Functions
*
*       function CreateEvent takes nothing returns integer
*       function TriggerRegisterEvent takes trigger t, integer ev returns nothing
*
************************************************************************************
*
*       struct Event extends array
*
*           static method create takes nothing returns thistype
*           method registerTrigger takes trigger t returns nothing
*           method register takes boolexpr c returns nothing
*           method fire takes nothing returns nothing
*
************************************************************************************/
    globals
        private real q=0
    endglobals
    struct Event extends array
        private static integer w=0
        private static trigger array e
        static method create takes nothing returns thistype
            set w=w+1
            set e[w]=CreateTrigger()
            return w
        endmethod
        method registerTrigger takes trigger t returns nothing
            call TriggerRegisterVariableEvent(t,SCOPE_PRIVATE+"q",EQUAL,this)
        endmethod
        method register takes boolexpr c returns nothing
            call TriggerAddCondition(e[this],c)
        endmethod
        method fire takes nothing returns nothing
            set q=0
            set q=this
            call TriggerEvaluate(e[this])
        endmethod
    endstruct
    function CreateEvent takes nothing returns Event
        return Event.create()
    endfunction
    function TriggerRegisterEvent takes trigger t,Event ev returns nothing
        call ev.registerTrigger(t)
    endfunction
    function RegisterEvent takes boolexpr c,Event ev returns nothing
        call ev.register(c)
    endfunction
    function FireEvent takes Event ev returns nothing
        call ev.fire()
    endfunction
endlibrary

What does this library do ? Does it add new events of some sort ?

I understand how the first 2 methods work but what I can't understand what good this can offer ?
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
It allows you to declare your own events and to register them on triggers. The triggers get assigned to the event in a list and are executed when the event fires.

Events are basically mediators between different parts of code. You do not call the target from the source spot directly but this hub instead. All listeners that have signed up before are served.
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
so you can make your own events like

TrigerRegisterUnitEvent
TriggerRegisterPlayerUnitEvent
TriggerRegisterRegionEvent

like if u wanted to make an event to function when a unit was moving, you could make the system than define an event for your system than make the function

TriggerRegisterUnitMoving

and Event would take care of that.
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
This system uses the TRVE to run your triggers by placing a dummy variable on them and changing its value to fire. Could have also been done with TriggerExecute and the like.

It does not provide any new event responses this way but you can determine the point of time when your triggers shall perform. By "own" events we don't mean that you can catch more stuff of wc3's basic engine but make use of the technical/structual concept in coding.

For general information about custom events, take a look into my tutorial.
 
Level 16
Joined
Mar 3, 2006
Messages
1,564

I was talking about this line:

call TriggerRegisterVariableEvent(t,SCOPE_PRIVATE+"q",EQUAL,this)

Isn't t is the trigger that I want to execute that will fire with the above event, lets assume that "this" is to be an event called FOLLOW which is actually a number, how does that make my own event, I mean there is no event in WC3 called FOLLOW.

I hope this clarify what I am getting at.
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
You can create a native unit-targeting order event and put several required conditions like if the order is smart/move/patrol, if the trigger unit has the ability to move, if the target is not an enemy etc. When all those conditions are met, the unit is expected to follow the target and this is the state you declare your own "follow" event in.

Your custom events are shaped by a gate of other events and/or conditions, so you do not have to put them everywhere and have a central collecting point.
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
I was talking about this line:

call TriggerRegisterVariableEvent(t,SCOPE_PRIVATE+"q",EQUAL,this)

Isn't t is the trigger that I want to execute that will fire with the above event, lets assume that "this" is to be an event called FOLLOW which is actually a number, how does that make my own event, I mean there is no event in WC3 called FOLLOW.

I hope this clarify what I am getting at.

new Event -> Register a trigger to Event -> When you want to run the event, just do event.fire()
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Another advantage of using Event rather than your own stuff is a common API (event.register), less work (don't have to make lots of extra variables and functions), and less variables in your map.

Consider this...

You have 3 triggers for 3 events, 3 functions to register to those events, and 3 variables to hold the 3 triggers (6 total).

Now consider this instead

You have 3 variables for the 3 events (registration is already supported in those variables) (3 total)

less work see? : )

Overall, if we do a line comparison

3 lines for each function, giving 9 lines + another 3 lines for vars + 3 lines for creation + 1 line for real event + 3 lines for event constants integers for real event var = 9 + 3 + 3 + 1 + 3 = 19 lines
3 lines for event vars + 3 lines for creation = 6 lines

19 lines w/o vs 6 lines w/ =)

edit
the less work thing is the main reason I use it. Doing those event registrations every time gets old fast ;o.
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
@ Nestharus
There is a great pace between you and me on how we both think, I am just a beginner (very beginner) trying to understand how it work, I am not questioning how fast or less work the library will provide.

But thanks anyway for the reply, friend.

Anyways,

I made something like that and I don't know if I am using it right or not:

JASS:
globals
    Event EVENT_UNIT_SPELL_DEATH
endglobals
JASS:
function IsDeathBySpell takes nothing returns boolean
    local boolean deathSpell

    // some stuff that I-don't-know-what for detecting is the death by spell or not

    return deathSpell
endfunction

function Trig_ev1_Actions takes nothing returns nothing
    call BJDebugMsg("A unit died by a spell")
endfunction

function InitTrig_ev1 takes nothing returns nothing
    set gg_trg_ev1 = CreateTrigger(  )
    set EVENT_UNIT_SPELL_DEATH = CreateEvent()
    call TriggerRegisterEvent( gg_trg_ev1 , EVENT_UNIT_SPELL_DEATH )
    call RegisterEvent( Condition(function IsDeathBySpell) , EVENT_UNIT_SPELL_DEATH )
    call TriggerAddAction( gg_trg_ev1, function Trig_ev1_Actions )
endfunction
JASS:
function Trig_death_Actions takes nothing returns nothing
    call FireEvent(EVENT_UNIT_SPELL_DEATH)
endfunction

function InitTrig_death takes nothing returns nothing
    set gg_trg_death = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_death, EVENT_PLAYER_UNIT_DEATH )
    call TriggerAddAction( gg_trg_death, function Trig_death_Actions )
endfunction
 
Level 4
Joined
Jan 27, 2010
Messages
133
So, event works like an interface between different systems.

For instance if you make a missile-system. Now, you want to be able to execute code when a missile hits its target. Let's say you have 10 different spells using the system. Instead of hardcoding all spells directly into your system; you fire an event when the missile hits. Then the spell-code can pick up that event.

Interfaces are basically a way to allow your code to be more modular and portable.

On a side note: Nestharus, what is the difference between Event-lib and vJass function interfaces?
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
running a function interface = a trigger eval

so if you have a list of 10 function interfaces, that's 10 trigger evals

event is always set a variable (triggers pick up on that set, which is faster than 10 separate evals), and then eval 1 trigger (10 conditions on 1 trigger is faster than 10 triggers with 10 conditions)

it's also WAY simpler : D

would u rather loop over a list of registered functions or just do event.fire() in 1 line?
 
Level 4
Joined
Jan 27, 2010
Messages
133
event is always set a variable (triggers pick up on that set, which is faster than 10 separate evals), and then eval 1 trigger (10 conditions on 1 trigger is faster than 10 triggers with 10 conditions)

Ah, I see now! Clever use of the variable change-event!

Though I honestly think speed does not matter in event-callbacks. I mean, if you're doing 1000 of them per second, then maybe the abstraction between systems is wrong :)

it's also WAY simpler : D

would u rather loop over a list of registered functions or just do event.fire() in 1 line?

Well, I'm lazy, so... :p
If I made a system for myself, I'd rather do event.fire()

If I made a public system I would probably use interfaces, just because of the convenience for the coder (no triggers involved (that the coder can see, at least)):

JASS:
function onInit()
{
    RegisterSomeEvent( FuncPtr );
}
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
damn it, this is getting to nowhere. I guess I am talking a really advanced things at a wrong time.


ok, I am trying to make a combat state system which detects if there is a combat or not in the entire map.

I am making it like that, I detect when any unit engages in combat by the wc3 events then increase a value of a counter then detects when any unit's combat end either if its target is dead or left the combat then decrease the counter, if the counter value gets to zero that would fire a trigger that set the combat state to false.

Now the question is, I am learning how to use the event-lib so that I could apply it here but from what is said (what Nestharus said) is this system needs this library ? And if so how would I use it ?

Help, pleeeeeease
 
Level 4
Joined
Jan 27, 2010
Messages
133
Do you want something to happen exactly when the combat stops/starts? In that case, yes, use event.

I believe something like this, yes?

JASS:
globals
    public Event EVENT_COMBAT_START = CreateEvent()
endglobals

//... inside your system ...

// ... lots of code...
// .....
// Determine if combat is going on
if count == 0 AND newCount > 0 then
    call FireEvent( EVENT_COMBAT_START )
endif

//... inside separate trigger ...

function Actions takes nothing returns nothing
    call BJDebugMsg("Combat started!")
endfunction

function InitTrig takes nothing returns nothing
    local trigger trg=CreateTrigger()
    TriggerRegisterEvent(trg, EVENT_COMBAT_START )
    TriggerAddAction(trg,function Actions)
endfunction

However, if you just want to be able to check if combat is going on or not, then you can just use a public function:
JASS:
library MyCombatLibrary
    function IsCombatGoingOn takes nothing returns boolean
        return combatCount!=0 // or whatever you use :)
    endfunction

   // .... lots of code....
   // ....
endlibrary

// ... inside trigger ....
function WhenYouUsedAnAbilityOrSth takes nothing returns nothing
    if IsCombatGoingOn() then
        call KillUnit( udg_pacifist )
    endif
endfunction
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
@themerion

Its the 2nd case I am just detecting if there is a combat or not in progress in the entire map and then set a boolean.

INFO:
I am detecting the event of entering the combat by:
OR
1. A unit is issued an attack order but target is not a tree
2. A unit smart (R-click) an enemy
3. A unit acquires a target
4. A unit casts a hostile spell

and detecting that a unit left combat by:

OR
1. A unit is issued a move order
2. A unit smarts but the target unit is null which means he smart a location
3. The target is dead (if there are more enemy around him he will acquire a target which will make him enter a combat)

What I was trying to accomplish with the library (or at least thought the library could do) is that I group the event that registers the unit that enters a combat together since they use the same actions.
 
Level 4
Joined
Jan 27, 2010
Messages
133
But you don't need event for grouping the stuff INSIDE your system. Just declare a function...!?

JASS:
// Ta-Da!
function EntersCombat takes unit u returns nothing
    // Stuff in common here
endfunction

// ========================================

function ActionsSmart takes nothing returns nothing
    if GetOrderTargetUnit()!=null then
        call EntersCombat( GetOrderedUnit() )
    endif
endfunction

function ActionsAttack takes nothing returns nothing
     if *IsNotTree* then
          call EntersCombat( GetAttacker() )
     endif
endfunction

// ...
// etc

function InitTrg takes nothing returns nothing
    local trigger trgAttack = CreateTrigger()
    local trigger trgSmart = CreateTrigger()
// etc...

    call TriggerRegisterAnyUnitEventBJ( trgAttack, EVENT_PLAYER_UNIT_ATTACKED )
    call TriggerAddAction( trgAttack, function ActionsAttack)

    call TriggerRegisterAnyUnitEventBJ( trgSmart, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
    call TriggerAddAction( trgSmart, function ActionsSmart)
//etc....

endfunction

Now, if you wanted some code OUTSIDE the system to know if a unit entered/exited combat, you would use Event, and fire it in EntersCombat.
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
Though I honestly think speed does not matter in event-callbacks. I mean, if you're doing 1000 of them per second, then maybe the abstraction between systems is wrong :)

Even if you were ready to give up the independence of your system and congest it with static lines, that might still be slower because the list of target systems you want to run may alter during runtime. It's usual that events are not as generic as "Any unit enters combat" but instead "<specific unit> enters combat", so the event is bound to a subject. There are enough other reasons to split systems.
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
... It's usual that events are not as generic as "Any unit enters combat" but instead "<specific unit> enters combat", so the event is bound to a subject. There are enough other reasons to split systems.

The system can do both, because I am flagging the unit that enters/leaves the combat by adding/removing it into/from a group. It is part of the system to work but it was not my intend to make it so.
 
Status
Not open for further replies.
Top