Jump to content
xxanimusxx

[Release] Chat-Events Library

Recommended Posts

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

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

  1. 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.
  2. 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-handlers
    and check their respective trigger-string (or also called "needle"). If the trigger-string is contained in the sent message, your registered function
    will be spawned and delivered an array with information about the message itself.
  3. ...
  4. 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

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

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

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

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×