#strict 2 static Event_Stack; static Event_StackPos; static Event_Listeners; static const Event_Sender = 0; static const Event_Name = 1; static const Event_ReturnValue = 2; static const Event_Accepted = 3; static const Event_Prevented = 4; global func AddEventListener(eventName, array listener, int priority, customArgs) { if(GetType(eventName) == C4V_Array) { for(var i = 0; i < GetLength(eventName); ++i) { if(GetType(customArgs) == C4V_Array) { AddEventListener(eventName[i], listener, priority, customArgs[i]); } else { AddEventListener(eventName[i], listener, priority, customArgs); } } return; } if(GetType(customArgs) != C4V_Array) { customArgs = [customArgs]; } var sender = this; if(GetType(sender) == C4V_C4Object) { sender = ObjectNumber(sender); } if(GetLength(listener) == 3) { customArgs = listener[2]; listener = [listener[0], listener[1]]; } var newListener = [listener, customArgs]; var listeners = GetEventListeners(sender, eventName); var i; for(i = 0; i < GetLength(listeners); ++i) { if(GetType(listeners[i]) != C4V_Array) { listeners[i] = [priority, [newListener]]; i = -1; break; } else if(listeners[i][0] == priority) { listeners[i][1][] = newListener; i = -1; break; } else if(listeners[i][0] > priority) { break; } } if(i != -1) { var swap = listeners[i], swap2; listeners[i] = [priority, [newListener]]; var length = GetLength(listeners); for(; i < length; ++i) { swap2 = listeners[i + 1]; listeners[i + 1] = swap; swap = swap2; } } SetEventListeners(sender, eventName, listeners); } global func RemoveEventListener(sender, eventName, listener, customArgs) { if(GetType(sender) == C4V_C4Object) { sender = ObjectNumber(sender); } if(sender == -1) { var i = 0; for(var i = 0; i < GetLength(Event_Listeners); ++i) { if(GetType(Event_Listeners[i]) == C4V_Array) { RemoveEventListener(i, eventName, listener, customArgs); } } } else { if(eventName == -1) { for(var event in Event_Listeners[sender]) { RemoveEventListener(sender, event[0], listener, customArgs); } } else { var emptyPrios = 0; var eventListeners = GetEventListeners(sender, eventName); for(var i = 0; i < GetLength(eventListeners); ++i) { if(GetType(eventListeners[i]) != C4V_Array) { ++emptyPrios; continue; } var listeners = eventListeners[i][1]; eventListeners[i][1] = []; for(var eventListener in listeners) { if(!((listener == -1 || eventListener[0] == listener) && (customArgs == -1 || eventListener[1] == customArgs))) { eventListeners[i][1][] = eventListener; } } if(GetLength(eventListeners[i][1]) == 0) { ++emptyPrios; } } if(emptyPrios == GetLength(eventListeners)) { ClearEventListener(sender, eventName); } else { ClearEmptyPrios(eventListeners); SetEventListeners(sender, eventName, eventListeners); } } } } global func ClearEventListener(sender, eventName) { var eventListeners = Event_Listeners[sender]; Event_Listeners[sender] = []; for(var i = 0; i < GetLength(eventListeners); ++i) { if(eventListeners[i][0] != eventName) { Event_Listeners[sender][] = eventListeners[i]; } } if(GetLength(Event_Listeners[sender]) == 0) { Event_Listeners[sender] = 0; } } global func ClearEmptyPrios(&prios) { var oldPrios = prios; prios = []; for(var prio in oldPrios) { if(GetType(prio) == C4V_Array) { if(GetLength(prio[1]) != 0) { prios[] = prio; } } } } global func GetEventListeners(sender, eventName) { if(GetType(Event_Listeners) == C4V_Array && GetType(Event_Listeners[sender])) { for(var event in Event_Listeners[sender]) { if(event[0] == eventName) { return event[1]; } } } return []; } global func SetEventListeners(sender, eventName, listeners) { if(GetType(Event_Listeners) != C4V_Array) { Event_Listeners = CreateArray(sender); Event_Listeners[sender] = [[eventName, listeners]]; } else { if(GetType(Event_Listeners[sender]) == C4V_Array) { for(var i = 0; i < GetLength(Event_Listeners[sender]); ++i) { if(Event_Listeners[sender][i][0] == eventName) { Event_Listeners[sender][i][1] = listeners; return; } } } else { Event_Listeners[sender] = []; } Event_Listeners[sender][] = [eventName, listeners]; } } global func PushEvent(array event) { if(GetType(Event_Stack) != C4V_Array) { /*Event_Stack = [0, 0]; // otherwise there is a really stupid operator "=" left side: got "any" but expected "&" error at this line in Event(): * // Event_Stack[Event_StackPos][Event_ReturnValue] = CallListener(listener[0], listener[1], args, event); * Event_StackPos = 0; * PopEvent();*/ Event_Stack = []; Event_StackPos = -1; } Event_Stack[++Event_StackPos] = event; } global func PopEvent() { if(Event_StackPos >= 0) { var event = Event_Stack[Event_StackPos]; SetLength(Event_Stack, Event_StackPos--); return event; } } global func Accept() { Event_Stack[Event_StackPos][Event_Accepted] = true; } global func Prevent() { Event_Stack[Event_StackPos][Event_Prevented] = true; } global func Accepted(array event) { if(event) { return event[Event_Accepted]; } else { return Event_Stack[Event_StackPos][Event_Accepted]; } } global func Prevented(array event) { if(event) { return event[Event_Prevented]; } else { return Event_Stack[Event_StackPos][Event_Prevented]; } } global func ReturnValue(array event) { if(event) { return event[Event_ReturnValue]; } else { return Event_Stack[Event_StackPos][Event_ReturnValue]; } } global func Event(string eventName, array args) { var sender = this; var event = [sender, eventName, 0, false, false]; PushEvent(event); if(GetType(sender) == C4V_C4Object) { sender = ObjectNumber(sender); } var allListeners = [GetEventListeners(sender, eventName)]; if(sender != 0) { allListeners[1] = GetEventListeners(0, eventName); } for(var listeners in allListeners) { for(var listenerPrio in listeners) { if(GetType(listenerPrio) == C4V_Array) { for(var listener in listenerPrio[1]) { var ret = CallListener(listener[0], listener[1], args, event); var e = Event_Stack[Event_StackPos]; e[Event_ReturnValue] = ret; Event_Stack[Event_StackPos] = e; if(Accepted()) { break; } } } } } event = PopEvent(); return event; } global func CallListener(array listener, array customArgs, array args, array event) { if(GetType(listener[0]) == C4V_Any) { return eval(Format("%s(%s, %s, %s)", listener[1], Serialize(event), Serialize(customArgs), Serialize(args))); } else if(GetType(listener[0]) == C4V_C4Object) { if(GetType(listener[1]) == C4V_String) { return eval(Format("%s->%s(%s, %s, %s)", Serialize(listener[0]), listener[1], Serialize(event), Serialize(customArgs), Serialize(args))); } else if(GetType(listener[1]) == C4V_Array) { return listener[0]->f(listener[1], [event, customArgs, args]); } } else if(listener[0] == -1 && event[0] != 0) { if(GetType(listener[1]) == C4V_String) { return eval(Format("%s->%s(%s, %s, %s)", Serialize(event[0]), listener[1], Serialize(event), Serialize(customArgs), Serialize(args))); } else if(GetType(listener[1]) == C4V_Array) { return event[0]->f(listener[1], [event, customArgs, args]); } } else if(GetType(listener[0]) == C4V_Array) { return f(listener, [event, customArgs, args]); } } global func Event_Adapter(target, string function, passArgs) { return [target, "Event_AdapterListener", [target, function, passArgs]]; } global func Event_AdapterListener(array event, array customArgs, array args) { if(customArgs[2] == -1) { args = []; } else if(GetType(customArgs[2]) == C4V_Array) { args = customArgs[2]; } var argString = ""; for(var i = 0; i < GetLength(args) && i < 10; ++i) { if(i != 0) { argString ..= ", "; } argString ..= Serialize(args[i]); } if(GetType(customArgs[0]) == C4V_Any || customArgs[0] == -1) { return eval(Format("%s(%s)", customArgs[1], argString)); } else if(GetType(customArgs[0]) == C4V_C4Object) { return eval(Format("%s->%s(%s)", Serialize(customArgs[0]), customArgs[1], argString)); } } global func GameCallEx(string function) { var event = Event(Format("GameCallEx%s", function), CreateFilledArray(...)); if(Prevented(event)) { return ReturnValue(event); } else { return _inherited(function, ...); } }