Downloads containing chatbinds.mut

Downloads
Name Author Game Mode Rating
JJ2+ Only: ChatBindsFeatured Download juanpablo123 Mutator 9.5 Download file

File preview

#pragma name "ChatBinds"

/*
	ChatBinds mutator by Headshot / juanpablo123
	A simple, yet powerful mutator that allows players to essentially "bind"
	chat commands to their keys for fast access.

	Features three different binding modes: !bind, !bindtoggle, and !bindtoggle2.

	!bind: This binds a command to a specified key. Simplest option.
	ex. !bind k !k

	!bindtoggle: Allows binding a chat command that requires an on/off 
	parameter.
	ex. !bindtoggle p /spectate

	!bindtoggle2: Allows binding two off/on chat commands (in that order) that
	toggle one option.
	ex. !bindtoggle2 o /stop /start
	
	You are also able to bind, but not limited to, keys from F1 to F24
	(does anyone even have such function keys that high?) or even the numpad keys.
	
	Your binds are saved, so they will work on any server that uses this mutator.
*/






/*
	source for key names from below:
	https://docs.microsoft.com/es-es/windows/win32/inputdev/virtual-key-codes
*/

dictionary keyNames = {
	{"backspace", 0x08},
	{"tab", 0x09},
	{"clear", 0x0c},
	{"enter", 0x0d},
	{"return", 0x0d},
	{"shift", 0x10},
	{"ctrl", 0x11},
	{"control", 0x11},
	{"alt", 0x12},
	{"menu", 0x12},
	{"pause", 0x13},
	{"capslock", 0x14},
	{"esc", 0x1b},
	{"escape", 0x1b},
	{"space", 0x20},
	{"pgup", 0x21},
	{"pageup", 0x21},
	{"pgdn", 0x22},
	{"pgdown", 0x22},
	{"pagedown", 0x22},
	{"end", 0x23},
	{"home", 0x24},
	{"left", 0x25},
	{"up", 0x26},
	{"right", 0x27},
	{"down", 0x28},
	{"select", 0x29},
	{"printscreen", 0x2c},
	{"prntscrn", 0x2c},
	{"printscrn", 0x2c},
	{"snapshot", 0x2c},
	{"ins", 0x2d},
	{"insert", 0x2d},
	{"del", 0x2e},
	{"delete", 0x2e},
	{"1", 0x31},
	{"2", 0x32},
	{"3", 0x33},
	{"4", 0x34},
	{"5", 0x35},
	{"6", 0x36},
	{"7", 0x37},
	{"8", 0x38},
	{"9", 0x39},
	{"0", 0x30},
	{"a", 0x41},
	{"b", 0x42},
	{"c", 0x43},
	{"d", 0x44},
	{"e", 0x45},
	{"f", 0x46},
	{"g", 0x47},
	{"h", 0x48},
	{"i", 0x49},
	{"j", 0x4a},
	{"k", 0x4b},
	{"l", 0x4c},
	{"m", 0x4d},
	{"n", 0x4e},
	{"o", 0x4f},
	{"p", 0x50},
	{"q", 0x51},
	{"r", 0x52},
	{"s", 0x53},
	{"t", 0x54},
	{"u", 0x55},
	{"v", 0x56},
	{"w", 0x57},
	{"x", 0x58},
	{"y", 0x59},
	{"z", 0x5a},
	{"lmeta", 0x5b},
	{"lwin", 0x5b},
	{"rmeta", 0x5c},
	{"rwin", 0x5c},
	{"apps", 0x5d},
	{"numpad0", 0x60},
	{"numpad_0", 0x60},
	{"numpad_ins", 0x60},
	{"numpad_insert", 0x60},
	{"numpad1", 0x61},
	{"numpad_1", 0x61},
	{"numpad_end", 0x61},
	{"numpad2", 0x62},
	{"numpad_2", 0x62},
	{"numpad_dn", 0x62},
	{"numpad_down", 0x62},
	{"numpad3", 0x63},
	{"numpad_3", 0x63},
	{"numpad_pgdn", 0x63},
	{"numpad_pagedn", 0x63},
	{"numpad_pagedown", 0x63},
	{"numpad4", 0x64},
	{"numpad_4", 0x64},
	{"numpad_left", 0x64},
	{"numpad5", 0x65},
	{"numpad_5", 0x65},
	{"numpad6", 0x66},
	{"numpad_6", 0x66},
	{"numpad_right", 0x66},
	{"numpad7", 0x67},
	{"numpad_7", 0x67},
	{"numpad_home", 0x67},
	{"numpad8", 0x68},
	{"numpad_8", 0x68},
	{"numpad_up", 0x68},
	{"numpad9", 0x69},
	{"numpad_9", 0x69},
	{"numpad_pgup", 0x69},
	{"numpad_pageup", 0x69},
	{"numpad_multiply", 0x6a},
	{"numpad_asterisk", 0x6a},
	{"numpad_add", 0x6b},
	{"numpad_plus", 0x6b},
	{"numpad_sub", 0x6d},
	{"numpad_substract", 0x6d},
	{"numpad_minus", 0x6d},
	{"numpad_dot", 0x6e},
	{"numpad_period", 0x6e},
	{"numpad_decimal", 0x6e},
	{"numpad_del", 0x6e},
	{"numpad_delete", 0x6e},
	{"numpad_divide", 0x6f},
	{"numpad_div", 0x6f},
	{"numpad_slash", 0x6f},
	{"f1", 0x70},
	{"f2", 0x71},
	{"f3", 0x72},
	{"f4", 0x73},
	{"f5", 0x74},
	{"f6", 0x75},
	{"f7", 0x76},
	{"f8", 0x77},
	{"f9", 0x78},
	{"f10", 0x79},
	{"f11", 0x7a},
	{"f12", 0x7b},
	{"f13", 0x7c},
	{"f14", 0x7d},
	{"f15", 0x7e},
	{"f16", 0x7f},
	{"f17", 0x80},
	{"f18", 0x81},
	{"f19", 0x82},
	{"f20", 0x83},
	{"f21", 0x84},
	{"f22", 0x85},
	{"f23", 0x86},
	{"f24", 0x87},
	{"numlock", 0x90},
	{"scroll", 0x91},
	{"scrollock", 0x91},
	{"scrolllock", 0x91},
	{"scroll_lock", 0x91},
	{"scrll", 0x91},
	{"lshift", 0xa0},
	{"rshift", 0xa1},
	{"lctrl", 0xa2},
	{"lcontrol", 0xa2},
	{"rctrl", 0xa3},
	{"rcontrol", 0xa3},
	{"lmenu", 0xa4},
	{"lalt", 0xa4},
	{"rmenu", 0xa5},
	{"ralt", 0xa5},
	{"back", 0xa6},
	{"browser_back", 0xa6},
	{"forward", 0xa7},
	{"browser_forward", 0xa7},
	{"next", 0xa7},
	{"browser_next", 0xa7},
	{"refresh", 0xa8},
	{"browser_refresh", 0xa8},
	{"browser_stop", 0xa9},
	{"search", 0xaa},
	{"browser_search", 0xaa},
	{"favorites", 0xab},
	{"browser_favorites", 0xab},
	{"browser_home", 0xac},
	{"vol_mute", 0xad},
	{"volume_mute", 0xad},
	{"mute", 0xad},
	{"vol_dn", 0xae},
	{"volume_dn", 0xae},
	{"vol_down", 0xae},
	{"volume_down", 0xae},
	{"vol_up", 0xaf},
	{"volume_up", 0xaf},
	{"media_next", 0xb0},
	{"media_prev", 0xb1},
	{"media_back", 0xb1},
	{"media_stop", 0xb2},
	{"media_playpause", 0xb3},
	{"media_play_pause", 0xb3},
	{"media_play", 0xb3},
	{"media_pause", 0xb3},
	{"launch_mail", 0xb4},
	{"launch_media_select", 0xb5},
	{"launch_app1", 0xb6},
	{"launch_app2", 0xb7},
	{"semicolon", 0xba},
	{";", 0xba},
	{":", 0xba},
	{"plus", 0xbb},
	{"+", 0xbb},
	{"comma", 0xbc},
	{",", 0xbc},
	{"minus", 0xbd},
	{"-", 0xbd},
	{"period", 0xbe},
	{"dot", 0xbe},
	{".", 0xbe},
	{"question", 0xbf},
	{"?", 0xbf},
	{"slash", 0xbf},
	{"/", 0xbf},
	{"tilde", 0xc0},
	{"~", 0xc0},
	{"grave_accent", 0xc0},
	{"graveaccent", 0xc0},
	{"grave", 0xc0},
	{"`", 0xc0},
	{"[", 0xdb},
	{"{", 0xdb},
	{"\\", 0xdc},
	{"|", 0xdc},
	{"}", 0xdd},
	{"]", 0xdd},
	{"\"", 0xde},
	{"'", 0xde},
	{"quote", 0xde}
};

enum TOGGLETYPES
{
	TOGGLE_NONE,
	TOGGLE_ON_OFF,
	TOGGLE_TWO_CMDS,
	
	BIND_LENGTH=0xde+1
};

array<string> binds(BIND_LENGTH, "");
array<bool> pressed(BIND_LENGTH, false);
array<array<int>> isToggle(BIND_LENGTH, array<int> = {TOGGLE_NONE, 0}); // {toggle type, on/off toggle itself}
array<array<string>> toggleCmds(BIND_LENGTH, array<string> = {"", ""}); // for TOGGLE_TWO_CMDS, the two commands used for toggling something (ex. {"/stop", "/start"})

void onLevelBegin()
{
	jjSTREAM tutorial("chatbinds_tut.asdat");
	jjSTREAM binds_file("my_chatbinds.asdat");

	if (tutorial.isEmpty())
	{
		jjAlert("Welcome to ChatBinds!");
		jjAlert("To get started, use the !bind, !bindtoggle, !bindtoggle2 and !unbind commands.");
		tutorial.push(0);
		tutorial.save("chatbinds_tut.asdat");
	}
	if (binds_file.isEmpty()) return; // file doesn't exist or has nothing

	for (uint i=0x00; i<BIND_LENGTH; i++)
	{
		string bind, togglecmd_1, togglecmd_2;
		bool has_togglecmds;
		int toggle;
		binds_file.pop(bind);
		binds_file.pop(toggle);
		binds_file.pop(has_togglecmds);
		if (has_togglecmds)
		{
			binds_file.pop(togglecmd_1);
			binds_file.pop(togglecmd_2);
		}
		binds[i] = bind;
		isToggle[i][0] = toggle;
		toggleCmds[i] = array<string> = {togglecmd_1, togglecmd_2};
	}
}

void saveBinds()
{
	jjSTREAM binds_file;

	for (uint i=0x00; i<BIND_LENGTH; i++)
	{
		binds_file.push(binds[i]);
		binds_file.push(isToggle[i][0]);
		if (not toggleCmds[i][0].isEmpty())
		{
			binds_file.push(true);
			binds_file.push(toggleCmds[i][0]);
			binds_file.push(toggleCmds[i][1]);
		}
		else
			binds_file.push(false);
	}
	
	binds_file.save("my_chatbinds.asdat");
}

bool onLocalChat(string &in chatmsg, CHAT::Type chatType)
{
	array<string> cmdargs = chatmsg.split(" ");
	string cmd = cmdargs[0];
	cmdargs.removeAt(0);
	
	if (cmd == "!bind")
	{
		if (cmdargs.isEmpty())
		{
			jjAlert("Usage: !bind <key> [chat message or command]");
			jjAlert("Leave out the second argument to display what command the key is bound to.");
			jjAlert("Example: ||!bind k !k ||||||or ||!bind k");
		}
		else
		{
			string key = cmdargs[0];
			if (keyNames.exists(key))
			{
				uint keyInd = uint(keyNames[key]);
				if (cmdargs.length() >= 2)
				{
					cmdargs.removeAt(0);
					string cmd_bind = join(cmdargs, " ");

					binds[keyInd] = cmd_bind;
					isToggle[keyInd] = array<int> = {TOGGLE_NONE, 0};
					toggleCmds[keyInd] = array<string> = {"", ""};

					jjAlert("Bound key ||"+key+" ||||||to ||"+cmd_bind);
					saveBinds();
				}
				else
				{
					if (not binds[keyInd].isEmpty() and isToggle[keyInd][0] == TOGGLE_ON_OFF)
						jjAlert("||"+key+" ||||||is bound to a toggle: ||"+binds[keyInd]+" on/off");
					else if (not binds[keyInd].isEmpty())
						jjAlert("||"+key+" ||||||is bound to ||"+binds[keyInd]);
					else if (not toggleCmds[keyInd][0].isEmpty())
						jjAlert("||"+key+" ||||||is bound to a toggle: ||"+toggleCmds[keyInd][0]+" ||||||and ||"+toggleCmds[keyInd][1]);
					else
						jjAlert("||"+key+" ||||||is not bound");
				}
			}
			else
				jjAlert("|Invalid key '"+key+" '");
		}
		return true;
	}
	
	else if (cmd == "!bindtoggle")
	{
		if (cmdargs.isEmpty())
		{
			jjAlert("Usage: !bindtoggle <key> [chat message or command]");
			jjAlert("A special command to bind on/off commands to keys.");
			jjAlert("Example: !bind p /spectate");
		}
		else
		{
			string key = cmdargs[0];
			if (keyNames.exists(key))
			{
				uint keyInd = uint(keyNames[key]);
				if (cmdargs.length() >= 2)
				{
					cmdargs.removeAt(0);
					string cmd_bind = join(cmdargs, " ");

					binds[keyInd] = cmd_bind;
					isToggle[keyInd] = array<int> = {TOGGLE_ON_OFF, 0};
					toggleCmds[keyInd] = array<string> = {"", ""};

					jjAlert("(Toggle) bound key ||"+key+" ||||||to ||"+cmd_bind+" on/off");
					saveBinds();
				}
				else
				{
					if (not binds[keyInd].isEmpty() and isToggle[keyInd][0] == TOGGLE_ON_OFF)
						jjAlert("||"+key+" ||||||is bound to a toggle: ||"+binds[keyInd]+" on/off");
					else if (not binds[keyInd].isEmpty())
						jjAlert("||"+key+" ||||||is bound to ||"+binds[keyInd]);
					else if (not toggleCmds[keyInd][0].isEmpty())
						jjAlert("||"+key+" ||||||is bound to a toggle: ||"+toggleCmds[keyInd][0]+" ||||||and ||"+toggleCmds[keyInd][1]);
					else
						jjAlert("||"+key+" ||||||is not bound");
				}
			}
			else
				jjAlert("|Invalid key '"+key+" '");
		}
		return true;
	}
	
	else if (cmd == "!bindtoggle2")
	{
		if (cmdargs.isEmpty())
		{
			jjAlert("Usage: !bindtoggle2 <key> <OFF command> <ON command>");
			jjAlert("Like !bindtoggle, but uses two commands to toggle something.");
			jjAlert("Example: !bind p /stop /start");
		}
		else
		{
			string key = cmdargs[0];
			if (keyNames.exists(key))
			{
				uint keyInd = uint(keyNames[key]);
				if (cmdargs.length() >= 3)
				{
					string on_cmd = cmdargs[1];
					string off_cmd = cmdargs[2];

					isToggle[keyInd] = array<int> = {TOGGLE_TWO_CMDS, 0};
					toggleCmds[keyInd] = array<string> = {on_cmd, off_cmd};

					jjAlert("(Toggle) bound key ||"+key+" ||||||to ||"+on_cmd+" - "+off_cmd);
					saveBinds();
				}
				else if (cmdargs.length() == 2)
					jjAlert("|Missing ON command argument");
				else
				{
					if (not binds[keyInd].isEmpty() and isToggle[keyInd][0] == TOGGLE_ON_OFF)
						jjAlert("||"+key+" ||||||is bound to a toggle: ||"+binds[keyInd]+" on/off");
					else if (not binds[keyInd].isEmpty())
						jjAlert("||"+key+" ||||||is bound to ||"+binds[keyInd]);
					else if (not toggleCmds[keyInd][0].isEmpty())
						jjAlert("||"+key+" ||||||is bound to a toggle: ||"+toggleCmds[keyInd][0]+" ||||||and ||"+toggleCmds[keyInd][1]);
					else
						jjAlert("||"+key+" ||||||is not bound");
				}
			}
			else
				jjAlert("|Invalid key '"+key+" '");
		}
		return true;
	}
	
	else if (cmd == "!unbind")
	{
		if (cmdargs.isEmpty())
		{
			jjAlert("Usage: !unbind <key>");
			jjAlert("Removes a chat bind from a key.");
			jjAlert("Example: !unbind p");
		}
		else
		{
			string key = cmdargs[0];
			if (keyNames.exists(key))
			{
				uint keyInd = uint(keyNames[key]);
				
				if (binds[keyInd].isEmpty() and toggleCmds[keyInd][0].isEmpty())
					jjAlert("||"+key+" ||||||is not bound");
				else
				{
					jjAlert("Unbound ||"+key);

					binds[keyInd] = "";
					isToggle[keyInd] = array<int> = {0, 0};
					toggleCmds[keyInd] = array<string> = {"", ""};

					saveBinds();
				}
			}
			else
				jjAlert("|Invalid key '"+key+" '");
		}
		return true;
	}
	
	return false;
}

void onPlayerInput(jjPLAYER@ player)
{
	for (uint i=0x00; i<BIND_LENGTH; i++)
	{
		if (jjKey[i] and (not binds[i].isEmpty() or not toggleCmds[i][0].isEmpty()) and not pressed[i])
		{
			switch(isToggle[i][0])
			{
				case TOGGLE_NONE:
					jjChat(binds[i]);
					break;
				
				case TOGGLE_ON_OFF:
					jjChat(binds[i]+" "+ ((isToggle[i][1] > 0) ? "off" : "on"));
					break;
				
				case TOGGLE_TWO_CMDS:
					jjChat(toggleCmds[i][isToggle[i][1]]);
					break;
			}

			isToggle[i][1] = -isToggle[i][1]+1;
			pressed[i] = true;
		}
		else if (not jjKey[i] and pressed[i])
			pressed[i] = false;
	}
}