Snippet Event

Troll-Brain

You can change this now in User CP.
Reaction score
85
You don't get it, it's perfect for those who want release custom events.

Simply added "readonly static thistype getTriggering" in the struct Event and the method fire.

JASS:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  ~~    Event     ~~    By Jesus4Lyf    ~~    Version 1.04    ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  What is Event?
//         - Event simulates Warcraft III events. They can be created,
//           registered for, fired and also destroyed.
//         - Event, therefore, can also be used like a trigger "group".
//         - This was created when there was an influx of event style systems 
//           emerging that could really benefit from a standardised custom
//           events snippet. Many users were trying to achieve the same thing
//           and making the same kind of errors. This snippet aims to solve that.
//
//  Functions:
//         - Event.create()       --> Creates a new Event.
//         - .destroy()           --> Destroys an Event.
//         - .fire()              --> Fires all triggers which have been
//                                    registered on this Event.
//         - .register(trigger)   --> Registers another trigger on this Event.
//         - .unregister(trigger) --> Unregisters a trigger from this Event.
//
//  Details:
//         - Event is extremely efficient and lightweight.
//         - It is safe to use with dynamic triggers.
//         - Internally, it is just a linked list. Very simple.
//
//  How to import:
//         - Create a trigger named Event.
//         - Convert it to custom text and replace the whole trigger text with this.
//
//  Thanks:
//         - Builder Bob for the trigger destroy detection method.
//         - Azlier for inspiring this by ripping off my dodgier code.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library Event


    ///////////////
    // EventRegs //
    ////////////////////////////////////////////////////////////////////////////
    // For reading this far, you can learn one thing more.
    // Unlike normal Warcraft III events, you can attach to Event registries.
    // 
    // Event Registries are registrations of one trigger on one event.
    // These cannot be created or destroyed, just attached to.
    //
    // It is VERY efficient for loading and saving data.
    // 
    //  Functions:
    //         - set eventReg.data = someStruct --> Store data.
    //         - eventReg.data                  --> Retreive data.
    //         - Event.getTriggeringEventReg()  --> Get the triggering EventReg.
    //         - eventReg.destroy()             --> Undo this registration.
    // 
    private keyword destroyNode
    struct EventReg extends array
        integer data
        method clear takes nothing returns nothing
            set this.data=0
        endmethod
        method destroy takes nothing returns nothing
            call Event(this).destroyNode()
        endmethod
    endstruct
    
    private module Stack
        static thistype top=0
        static method increment takes nothing returns nothing
            set thistype.top=thistype(thistype.top+1)
        endmethod
        static method decrement takes nothing returns nothing
            set thistype.top=thistype(thistype.top-1)
        endmethod
    endmodule
    
    private struct EventStack extends array
        implement Stack
        Event current
    endstruct
    
    struct Event
        private trigger trig
        private thistype next
        private thistype prev
        readonly static thistype getTriggering = 0
        
        static method getTriggeringEventReg takes nothing returns EventReg
            return EventStack.top.current
        endmethod
        
        static method create takes nothing returns Event
            local Event this=Event.allocate()
            set this.next=this
            set this.prev=this
            return this
        endmethod
        
        private static trigger currentTrigger
        method fire takes nothing returns nothing
            local thistype curr=this.next
            call EventStack.increment()
            loop
                exitwhen curr==this
                set thistype.currentTrigger=curr.trig
                if IsTriggerEnabled(thistype.currentTrigger) then
                    set EventStack.top.current=curr
                    set this.getTriggering = this
                    if TriggerEvaluate(thistype.currentTrigger) then
                        call TriggerExecute(thistype.currentTrigger)
                    endif
                    set this.getTriggering = 0
                else
                    call EnableTrigger(thistype.currentTrigger) // Was trigger destroyed?
                    if IsTriggerEnabled(thistype.currentTrigger) then
                        call DisableTrigger(thistype.currentTrigger)
                    else // If trigger destroyed...
                        set curr.next.prev=curr.prev
                        set curr.prev.next=curr.next
                        call curr.deallocate()
                    endif
                endif
                set curr=curr.next
            endloop
            call EventStack.decrement()
        endmethod
        method register takes trigger t returns EventReg
            local Event new=Event.allocate()
            set new.prev=this.prev
            set this.prev.next=new
            set this.prev=new
            set new.next=this
            
            set new.trig=t
            
            call EventReg(new).clear()
            return new
        endmethod
        method destroyNode takes nothing returns nothing // called on EventReg
            set this.prev.next=this.next
            set this.next.prev=this.prev
            call this.deallocate()
        endmethod
        method unregister takes trigger t returns nothing
            local thistype curr=this.next
            loop
                exitwhen curr==this
                if curr.trig==t then
                    set curr.next.prev=curr.prev
                    set curr.prev.next=curr.next
                    call curr.deallocate()
                    return
                endif
                set curr=curr.next
            endloop
        endmethod
        
        method destroy takes nothing returns nothing
            local thistype curr=this.next
            loop
                call curr.deallocate()
                exitwhen curr==this
                set curr=curr.next
            endloop
        endmethod
        method chainDestroy takes nothing returns nothing
            call this.destroy() // backwards compatability.
        endmethod
    endstruct
    
    /////////////////////////////////////////////////////
    // Demonstration Functions & Alternative Interface //
    ////////////////////////////////////////////////////////////////////////////
    // What this would look like in normal WC3 style JASS (should all inline).
    // 
    function CreateEvent takes nothing returns Event
        return Event.create()
    endfunction
    function DestroyEvent takes Event whichEvent returns nothing
        call whichEvent.chainDestroy()
    endfunction
    function FireEvent takes Event whichEvent returns nothing
        call whichEvent.fire()
    endfunction
    function TriggerRegisterEvent takes trigger whichTrigger, Event whichEvent returns EventReg
        return whichEvent.register(whichTrigger)
    endfunction
    
    // And for EventRegs...
    function SetEventRegData takes EventReg whichEventReg, integer data returns nothing
        set whichEventReg.data=data
    endfunction
    function GetEventRegData takes EventReg whichEventReg returns integer
        return whichEventReg.data
    endfunction
    function GetTriggeringEventReg takes nothing returns integer
        return Event.getTriggeringEventReg()
    endfunction
endlibrary


JASS:
library CustomEventMaker initializer onInit uses Event

globals
    Event EVENT1
    Event EVENT2
endglobals

private function Event1 takes nothing returns boolean
    call EVENT1.fire()
    return false
endfunction
private function Event2 takes nothing returns boolean
    call EVENT2.fire()
    return false
endfunction

private function onInit takes nothing returns nothing // or you can use a module initializer, you know why, it's just a sample ...
    local trigger trig = CreateTrigger()
    set EVENT1 = Event.create()
    set EVENT2 = Event.create()
    
    // yes this examples are just silly, they are just the same as native events
    // but i won't post a whole real code ...

    call TriggerRegisterPlayerChatEvent(trig,Player(0),"test1",true)
    call TriggerAddCondition(trig,function Event1)
    set trig = CreateTrigger()
    call TriggerRegisterPlayerChatEvent(trig,Player(0),"test2",true)
    call TriggerAddCondition(trig,function Event2)
endfunction

endlibrary


JASS:
library Sample initializer onInit uses CustomEventMaker

private function Actions takes nothing returns nothing
    local Event evt = Event.getTriggering
    
    if evt == EVENT1 then
        call BJDebugMsg("EVENT 1 fire")
    endif
    if evt == EVENT2 then
        call BJDebugMsg("EVENT 2 fire")
    endif
endfunction

private function onInit takes nothing returns nothing
    local trigger trig = CreateTrigger()
    call TriggerAddAction(trig,function Actions)
    call TriggerRegisterEvent(trig,EVENT1)
    call TriggerRegisterEvent(trig,EVENT2)
endfunction

endlibrary
 

Jesus4Lyf

Good Idea™
Reaction score
397
Simply added "readonly static thistype getTriggering" in the struct Event and the method fire.
No, it fails recursion. I'd need to use a stack...
That's why I'm not big on implementing it.

I can, it's not a huge issue, but I'm curious as to why you want it...
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
EDIT : I didn't see Jesus4Lyf's Post.

Jesus4Lyf said:
No, it fails recursion. I'd need to use a stack...
That's why I'm not big on implementing it.

I can, it's not a huge issue, but I'm curious as to why you want it...
Why it would fail recursion ? I'm lost here.
Could you give an example plz ?

I use several native events on a same trigger sometimes, i don't see why i wouldn't do the same for custom ones, i hate splitting, duplicating the code when it's unnecessary.
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
Hmm.
It's probably because all off my custom events can't be recursive naturally, like trade between players, constructing event, and so one.
I mean there is no way that you can fire the same trigger when the event fire.
(Except if you evaluate/execute the triggering trigger inside one of his condition/action, but you should be shot for that anyway)

Like this example EVENT1 and EVENT2 can't be recursive in any way, it's just impossible that happens.

Anyway i don't see the usefulness for recursive for any event, especially healing event, that's silly.
The user must disable /enable the trigger to avoid such recursive events, like natives one.

Who doesn't know that he must disable the trigger when he gives an order to an unit on an order event ...
 

Jesus4Lyf

Good Idea™
Reaction score
397
Easy example: Two units have 10% chance to return 100% damage upon taking damage. One attacks the other, and returns returned damage (recursive Event).

Point is, lets say Event 1 has 3 triggers registered, and the first causes Event 2 to be fired. The next 3 triggers now will believe the current Event is Event 2, unless I implement it recursively. Which is not hard, I repeat. Just avoidable.

I might do it soon.
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
Easy example: Two units have 10% chance to return 100% damage upon taking damage. One attacks the other, and returns returned damage (recursive Event).

Point is, lets say Event 1 has 3 triggers registered, and the first causes Event 2 to be fired. The next 3 triggers now will believe the current Event is Event 2, unless I implement it recursively. Which is not hard, I repeat. Just avoidable.

I might do it soon.
Oh ok now i understand, kingkingyyk3 confused me with his off-topic.
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
I've added [forcemethodevaluate] inside jasshleper.conf to get rid of these auto evaluates.
I think for a public resource you should always evaluate yourself when it's needed.

JASS:
    struct EventReg extends array
        integer data
        method clear takes nothing returns nothing
            set this.data=0
        endmethod
        method destroy takes nothing returns nothing
            call Event(this).destroyNode.evaluate()
        endmethod
    endstruct
 

Azlier

Old World Ghost
Reaction score
461
Does anybody actually use EventReg?
 

Jesus4Lyf

Good Idea™
Reaction score
397
Do you think a such thing (it can't be an human user, really) should be shot ?
There is, in my head, two logical causes for it. One is removing events with O(1) complexity, the other is attaching to dynamic events (when a specific unit hits the ground, for example). Perhaps with the advancements with had with function interfaces and all, they should be shot... *shrugs*.
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
Pretty much, yes.
If i need a dynamic event i will just use a dynamic trigger.

The most point of this is to be a standard for custom events which follow Blizzard one, not really have some odd interface and O(1) removing event.
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
Plz reconsider this EventReg thing, i can't believe someone actually use it.
And if you don't use it, there is at very least one set of variable, it slow all the thing !!! xD

At least plz fix the call of destroyNode inside EventReg.
Making EventReg optional could be great also.

I was considering about a convention for custom events.
Instead of having X functions TriggerRegisterMyZomgCustomEvent1337, we could use global Event and TriggerRegister, follow jass2 convention like i've posted few posts before this one.

CUSTOM_EVENT_MYEVENT
Well ofc the user could break it by using CUSTOM_EVENT_MYEVENT.destroy(), but we can't always protect users from themselves ...
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
EventReg is useful for attaching data to dynamic triggers. For better sake, I think you can make a ENABLE_EVENT_REG = true/false.
 

dudeim

New Member
Reaction score
22
When saving my map with this snippet in it i get an error:
Member redeclared: destroy

i went searching for it and saw you have two times a method called destroy is it because of that i get the error or what?
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top