Jesus4Lyf
Good Idea™
- Reaction score
- 397
Since you must fire Events manually, a global variable should more or less handle that for you...
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~ 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
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
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
No, it fails recursion. I'd need to use a stack...Simply added "readonly static thistype getTriggering" in the struct Event and the method fire.
Why it would fail recursion ? I'm lost here.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...
Oh ok now i understand, kingkingyyk3 confused me with his off-topic.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.
That's indeed the question in my head since i've seen this script.Does anybody actually use EventReg?
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*.Do you think a such thing (it can't be an human user, really) should be shot ?
And why i would need a such thing ?EventReg is useful for attaching data to dynamic triggers.
Why not.For better sake, I think you can make a ENABLE_EVENT_REG = true/false.