xxanimusxx 2 Posted October 25, 2013 Chat-Events Library Summary Calling this a library may sound a bit excessive but it's as close as a definition I could think of. Using the Chat-Events Library you can define Events which are triggered everytime the player writes something specific into the game-chat. The usage resembles that of addEventHandler to ease and shorten the time to familiarize with the commands used in these scripts. This release was tested on my own copy of ArmA2OA (vanilla) and could harbor many bugs to correct - if you encounter any, feel free to rant about them! Downloads [latest] v0.81 Installation Extract the archive into your missions-folder and call the initialization in your init.sqf accordingly: // somewhere in your init.sqf if (!isDedicated) then { execVM "chatEvents\init.sqf"; waitUntil {!isNil "aniChatEvents_initated"}; }; Preface: These scripts are (hopefully sufficiently) commented and mostly provided with examples to offer a deeper insight of expected parameters and other stuff to consider. It is highly recommended to look into those files before posting any bug report to ensure a well defined usage of the provided scripts. Please also consider starting your missions with the -showScriptErrors startup parameter to get error messages ingame. This will save you some valuable time figuring out what your problem is in case of occuring errors. Functionality: This "library" consists of 3 main-functions and another 3 helper-functions. aniChatEvents_addEventHandler: adds an event-handler aniChatEvents_removeEventHandler: removes an event-handler aniChatEvents_removeAllEventHandlers: removes all event-handlers aniChatEvents_strstr: searches for a string in another string aniChatEvents_strlen: returns the string-length aniChatEvents_substr: returns a sub-string The four steps to success Define a global function which is bound to be spawned everytime a chat-event is triggered.Name it however you want, you could also use a public variable as the handler, but we'll indulge in that later. Add a new chat-eventhandler by supplying above meantioned function (by its name as a string) and the trigger-string.Everytime the player sends a message through the ingame-chat, the ChatEvents-Library will loop through all registered event-handlersand check their respective trigger-string (or also called "needle"). If the trigger-string is contained in the sent message, your registered functionwill be spawned and delivered an array with information about the message itself. ... Profit. Code examples For all these following codes, we will assume a scenario where we want to spawn a vehicle using the direct-channel of our chat (please disregard the logic behind this use case...). Furthermore we will use the whole message to extract which type of vehicle to spawn. The message we will use as reference is: /spawn MV22 So we're gonna define a function handling this for us and want to test out several configurations of adding the event-handler. And before these questions pop up: Where you put this following code is irrelavant - as long as you do it before you add the event-handler into the queue. Event-Handler spawnVehicleHandler = { _unit = _this select 0; _msg = _this select 1; _channel= _this select 2; _index = _this select 3; // disregard messages not sent in direct channel if (_channel == "direct") then { // Get the classname out of the message _className = ""; if ((_msg call aniChatEvents_strlen) > 7 /* 7 = Length of needle '/spawn' + Whitespace */) then { _className = [_msg, 7] call aniChatEvents_substr; // Is this a valid classname? if (configName(configFile >> "cfgVehicles" >> _className) != "") then { _spawnPos = _unit modelToWorld [0, 10, 0]; _spawnPos set [2, 0]; createVehicle [_className, _spawnPos, [], 0, "NONE"]; hintsilent format["%1 spawned", getText(configFile>>"cfgVehicles">>_className>>"displayname")]; } else { hintsilent "Invalid classname"; }; }; }; }; This code practically extracts the substring after "/spawn " and uses it to spawn the given vehicle. Adding the Event-Handler spawnHandlerID = [["/spawn", true, true, true], "spawnVehicleHandler"] call aniChatEvents_addEventHandler; The less code lines we have the more questions are arising. In this line we're telling that we want to register a global function named "spawnVehicleHandler" which is then spawned everytime the string "/spawn" is found in the sent chat-message. The three true's are "modifiers" and tell the search-engine to only match "/spawn" if it's the first word, not in another word and case-sensitive (but more on the syntax later). Removing the Event-Handler If you don't need the event-handler anymore (e.g. after activating a trigger once) you can also remove the event-handler out of the queue using the ID which was returned using the above command. spawnHandlerID call aniChatEvents_removeEventHandler; Syntax, parameters and return values Understanding the syntax of the three main functions is mandatory to get a well functioning and moreover efficient string-matching, as this can cansume a lot of script-execution-time if not used correctly. I will therefore insert the comment-section which I already wrote in the header of every individual file contained in this release to save me some time over typing it all again. aniChatEvents_addEventHandler * aniChatEvents_addEventHandler * ------------------------------ * Adds another event into the event queue and returns * the identifier of the newly added event. * * Syntax: * ------------------------------ * handleID = [Needle, callback] call aniChatEvents_addEventHandler; * * Return Value: * handleID: Number (the ID used to reference the handler) * * Parameters: * Needle: String (the string to search for, provide an empty string to trigger callback on every sent message) * callback: String (the name of the function to call whenever the needle-string matches) * * Alternative Syntax: * ------------------------------ * handleID = [ [Needle, searchStart] , callback ] call aniChatEvents_addEventHandler; * handleID = [ [Needle, searchStart, wholeWords] , callback ] call aniChatEvents_addEventHandler; * handleID = [ [Needle, searchStart, wholeWords, caseSensitive] , callback ] call aniChatEvents_addEventHandler; * * Parameters: * Needle: String (the string to search for) * searchStart: Bool (only matches if needle is at the start of the chat-message, default: false) * wholeWords: Bool (only matches if needle is a whole word, default: false) * caseSensitive: Bool (pretty much self-explanatory, default: false) * * In any case, the spawned callback upon a successful match is given an array of parameters: * [unit, message, channel, needlePos] * * unit: Player (the player who wrote the message) * message: String (the written message) * channel: String (the channel in which the message was written) * needlePos: Number (the null-based index of the first occurence of Needle in message) * * provided channel names: * "direct", "global", "group", "side", "vehicle", "command" aniChatEvents_removeEventHandler * aniChatEvents_removeEventHandler * ------------------------------ * Removes the event handler with the given handleID from * the event queue. * * Syntax: * ------------------------------ * handleID call aniChatEvents_removeEventHandler; * * Parameters: * handleID: Number (handleID received upon calling aniChatEvents_addEventHandler) * * Alternative Syntax: * ------------------------------ * removeAll call aniChatEvents_removeEventHandler; * * Parameters: * removeAll: Bool (removes every single event handler in the event queue) aniChatEvents_removeAllEventHandlers Alias for true call aniChatEvents_removeEventHandler; aniChatEvents_substr * aniChatEvents_substr * ------------------------------ * Searches a string in another string with the * provided modifiers (flags). * * Syntax: * ------------------------------ * newString = [refString, start] call aniChatEvents_substr; * * Return Value: * newString: String (newly created substring) * * Parameters: * refString: String (the referenced string which is used to form the substring) * start: Number (the null-based index from which the substring should be formed) * * Alternative Syntax: * ------------------------------ * newString = [refString, start, length] call aniChatEvents_substr; * * Return Value: * newString: String (newly created substring) * * Parameters: * refString: String (the referenced string which is used to form the substring) * start: Number (the null-based index from which the substring should be formed (inclusive)) * length: Number (the number of (max.) characters copied into the new string from parameter start) * * * In both cases start and length can be supplied with negative numbers, effectively offsetting from the end of * refString and not the start. * Having start = -2 will translate to: start = refStringlength - 2 * Having length = -1 will translate to: length = refStringlength - 1 * Look at http://us1.php.net/manual/en/function.substr.php for more detailed examples. aniChatEvents_strlen * aniChatEvents_strlen * ------------------------------ * Returns the length of the provided string. * * Syntax: * ------------------------------ * size = string call aniChatEvents_strlen; * * Return Value: * size: Number (string-length, returns -1 if supplied with no string) * * Parameters: * string: String (well, duh.....) aniChatEvents_strstr * aniChatEvents_strstr * ------------------------------ * Searches a string in another string with the * provided modifiers (flags). * * Syntax: * ------------------------------ * [match,index] = [needle, haystack, flags] call aniChatEvents_strstr; * * Return Value: * match: Boolean (pretty much self-explanatory) * index: Number (null-based index of the first occurence of needle in haystack) * * Parameters: * needle: String (the string to search for) * haystack: String (the string in which to search needle) * flags: Array<Boolean> [searchStart, wholeWords, caseSensitive] Useful informations These details are for the advanced scripters under us - if you're still dizzy from the above code examples, you can safely disregard this section :) The first revision of this library had you supply the reference to the global function in aniChatEvent_addEventHandler rather the name of the function as a string. I made this step in thought of more dynamic functions - you can at any time in your mission just redefine the global function you registered and your function will be spawned as if nothing happened - in fact there is no need to keep track of it as long as the variable which you registered using its name points to a function. Another probable use of this is using public variables - you could use publicVariable to broadcast a new function to every client as long as you use the same variable name which you registered before. The Chat-Events Library won't and can't replace complex routines and guis to execute in-place code - don't try to use the chat-box as a debugging-console or something of that sort as we did with our example above. This use case involves a custom made GUI and some scripting to back it up. Share this post Link to post Share on other sites
.kju 3245 Posted October 26, 2013 Pretty cool system and nifty :bounce3: For those also wondering how you managed to grab the chat input the code snipped from the init: ... while {true} do { aniChatEvents_chatMessage = ""; waitUntil {_idd = findDisplay 24; !isNull _idd}; _ctrl = _idd displayCtrl 101; _ctrl ctrlAddEventHandler ["keyUp", "aniChatEvents_chatMessage = ctrlText (_this select 0); aniChatEvents_chatChannel = ctrlText ((findDisplay 63) displayCtrl 101);"]; waitUntil {isNull _ctrl}; if (aniChatEvents_chatMessage != "") then { call _this; }; }; ... Thanks a lot for sharing! Share this post Link to post Share on other sites
xxanimusxx 2 Posted October 26, 2013 It was pretty easy actually :D My first approach was waiting for an "-" and logging every consecutive key pressed after that until the enter-key was pressed to send the message away. But before scripting that I unpacked some pbo's from the dta/common folder of vanilla ArmA2OA in hope of finding some config entries with known names and behold, I did find some entries. All I had to do was finding out the IDD and IDC of the controls and voila, an infinite loop later we have all we need to grab the chat message :D The "hard" part was to write code handling the string comparison; not being able to use efficient c-code almost killed me... xD For all those to whom this information matters, here are the IDD's and IDC's of the controls: Chat-InputField: ParentClass-IDD: 24; InputField-IDC: 101; Channel-Label_ ParentClass-IDD: 63; TextField-IDC: 101; Share this post Link to post Share on other sites
TomOZ 3 Posted August 18, 2020 Hey guys, I just came across this page, and i must say that i'm really interested in the script you put up xxanimusxx, but sadly the link to download it no longer works (as expected being around 7 years old) - I am wondering if there is any way I could download the script, or get access to it potentially for a mission and to study the script? Thanks if possible, and if you even respond on a 7 year old thread lmao. Cheers, Tom. Share this post Link to post Share on other sites