/*******************************************************************************************************
Command Generator by ~Cueball~
A Guide For The Community
Change The Following Five Defines
To Configure The Script To Your Needs
Read readme.html For Information
******************************************************************************************************/
#define PrintInConsole 1 // 1 = Send a '[generator]' message to the console when a command is successfully generated.
#define SaveCommands 1 // 1 = Allow generated commands to be used immediately in the same session.
#define SendAdminMessage 1 // 1 = Send a message to all logged-in RCON admins when a command is successfully generated.
#define SendAnnounceMessage 1 // 1 = Send a message to every connected player with information about how to use the command.
#define SendTeleMessage 1 // 1 = Send a message stating the name of the command and its creator to the player when the command is used.
#define VehicleTele 1 // 1 = Allow vehicle teleports to be saved to a file, as well as used in saved commands.
#define COLOUR_COMMAND 0x33CCFFAA // The colour to send announcement messages in if 'SendAnnounceMessage' is defined as 1.
//******************************************************************************************************
#include <a_samp> // Necessary include which holds all of SA-MP's native functions.
#define FILTERSCRIPT // This is a filterscript, so we define it as one.
#if defined FILTERSCRIPT // If we have defined 'FILTERSCRIPT', do all the code until the first '#endif'.
//******************************************************************************************************
new File:GenCmds, // Create a global file handle variable, so that we don't create alot of local variables which do the same thing.
CurrentCommand, // Create a global variable (integer), which holds the current command count.
string[500]; // Create a global variable (string), with a maximum length of 500 characters. Saves memory instead of creating strings after every '/cgen'.
//******************************************************************************************************
// ARRAY CREATION - MAIN
//******************************************************************************************************
#define MAX_COMMANDS 150 // The maximum amount of commands that can be used at one time. KEEP AROUND THIS VALUE TO SAVE MEMORY.
#define MAX_COMMAND_NAME 15 // The maximum command name length you want your commands to be. '/cgen hello' = Command length of 5 characters.
enum COMMAND_MAIN { // Enumerating 'COMMAND_MAIN'.
NAME[MAX_COMMAND_NAME], // A string with a maximum length of MAX_COMMAND_NAME characters.
CREATOR[MAX_PLAYER_NAME], // A string with a maximum length of MAX_PLAYER_NAME (24) characters.
Float:POS[4], // 4 floats with a single name: 'POS'.
INTERIOR // An integer.
}
new gCommands[MAX_COMMANDS][COMMAND_MAIN]; // Creating a global variable with MAX_COMMANDS ammount of cells, and each set of cells holding our 'COMMAND_MAIN' enumeration.
//******************************************************************************************************
// ARRAY CREATION - INVALID NAMES
//******************************************************************************************************
#define MAX_INVALID_COMMANDS 21 // The amount of invalid command names you have. Must be an exact value, or else you will recieve errors.
#define MAX_INVALID_NAME 9 // The maximum invalid command name length you have. Remember to add an extra value for the trailing 0. 'cmd' = 3 + 1.
new gInvalidCommands[MAX_INVALID_COMMANDS][MAX_INVALID_NAME] = { // Add all your invalid command names here (but remember to change the value of 'MAX_INVALID_COMMANDS' when you are finished.
"rules", "commands", "cmds", "cmd", "register", "login", "logout", "signup",
"signin", "signout", "admins", "kick", "ban", "wire", "unwire", "mute", "unmute",
"explode", "goto", "gethere", "tele"
};
//******************************************************************************************************
// CALLBACKS
//******************************************************************************************************
public OnFilterScriptInit()
{
print("\n****************************************"); // Give credit to the creator of the script.
print("* Command_Generator by ~Cueball~ *");
print("****************************************\n");
if(!fexist("Generated_Commands.txt")) // Check if 'Generated_Commands.txt' exists in the 'scriptfiles' folder. If it doesn't, do the following:
{
GenCmds = fopen("Generated_Commands.txt", io_append); // Create the file 'Generated_Commands.txt' with the filemode being 'io_append'. We store the variable returned by the function into our 'GenCmds' global variable, as we will use this as a file handle.
fclose(GenCmds); // Close the file handle 'GenCmds'. This will successfully close 'Generated_Commands.txt', which will stop our server from crashing.
}
return 1; // Return 1 to the server, which will allow information to be processed after this script has been looped through.
}
#endif
//******************************************************************************************************
public OnPlayerConnect(playerid)
return SendClientMessage(playerid, 0x33CCFFAA, "Running Command_Generator Script by ~Cueball~ || To get started type \'/cgen\' at your wanted location."); // Let the player know that the script is running, and tell them how to save a command.
//******************************************************************************************************
public OnPlayerCommandText(playerid, cmdtext[])
{
if(strcmp (cmdtext, "/cgen", true, 5) == 0) // '/cgen'.
{
if (strlen(cmdtext) < 7 || cmdtext[6] == '/') // If the player's command name wasn't given, or if they tried to do (FOR EXAMPLE): '/cgen /chiliad', tell them how to use the command correctly.
return SendClientMessage(playerid, 0xFF9900AA, "USAGE: /cgen [teleport/command name] (DO NOT INCLUDE THE '/'!)");
if(strlen(cmdtext) > (MAX_COMMAND_NAME + 6)) // If their command name is too long, tell them that they have made a mistake.
return SendClientMessage(playerid, 0xFF9900AA, "ERROR: You're command name is too long!");
format(string, MAX_COMMAND_NAME, "%s", cmdtext[6]); // Formatting 'string' to hold their command name, so that we can successfully compare strings later.
if(strcmp(string, "help", true, 4) == 0) // '/cgen help'.
{
SendClientMessage(playerid, 0x33CCFFAA, "Command Generator Help by ~Cueball~"); // Show helpful information about Command Generator
SendClientMessage(playerid, 0xFF9900AA, "Go to a location and type \'/cgen [command name]\'. The command will be sent to the server owner.");
SendClientMessage(playerid, 0xFF9900AA, "If enabled by the server, you can then type \'/[command name]\',");
SendClientMessage(playerid, 0xFF9900AA, "where \'[command name]\' is the name of a previously generated command.");
SendClientMessage(playerid, 0x33CCFFAA, "PLEASE NOTE: Do not try to generate any frequently used command names such as \'/help\'.");
return SendClientMessage(playerid, 0x33CCFFAA, "Administrators keep constant watch over generated commands, so it is unwise to flood the system.");
}
for(new i = 0; i < MAX_COMMANDS; i++) // A for loop which runs a maximum of MAX_COMMANDS - 1 times.
if(gCommands[i][NAME][0] != '\0' && strcmp(string, gCommands[i][NAME], true, strlen(gCommands[i][NAME])) == 0) // If the current cell of 'gCommands[*][NAME][0]' is not empty AND it is the same as the command name the player supplied (if that command name is already in use), tell them that they must use a different command name.
return SendClientMessage(playerid, 0xFF9900AA, "ERROR: Somebody has already generated a command with that name! Please use a different one.");
for(new i = 0; i < MAX_INVALID_COMMANDS; i++) // A for loop which runs a maximum of MAX_INVALID_COMMANDS - 1 times.
if(strcmp(string, gInvalidCommands[i], true, strlen(gInvalidCommands[i])) == 0) // If the command name that the player supplied is the same as one in our 'gInvalidCommands' array, tell them that that command name is disabled.
return SendClientMessage(playerid, 0xFF9900AA, "ERROR: The server owner has disabled generating a command with that name!");
new Float:x, Float:y, Float:z, Float:Ang, Interior, // Create 4 floats which will hold the players position and facing angle, as well as an integer.
PlayerIp[16], PlayerName[MAX_PLAYER_NAME], // Create 2 strings, with a maximum length of 16 and 24 characters (the value of 'MAX_PLAYER_NAME') respectively.
hour, minute, second, year, month, day; // Create 6 integers which will hold the servers current time and date.
GetPlayerPos(playerid, x, y, z); // Store the players current X, Y and Z co-ordinates into our 'x', 'y' and 'z' variables respectively.
GetPlayerFacingAngle(playerid, Ang); // Store the players current angle that they are facing into our 'Ang' variable.
Interior = GetPlayerInterior(playerid); // Store the players current interior into our 'Interior' variable.
GetPlayerName(playerid, PlayerName, sizeof(PlayerName)); // Store the players name into our 'PlayerName' variable, with a maximum length of the size of 'PlayerName' (24, or 'MAX_PLAYER_NAME').
GetPlayerIp(playerid, PlayerIp, sizeof(PlayerIp)); // Store the players IP address into our 'PlayerIp' variable, with a maximum length of the size of 'PlayerIp' (24).
gettime(hour, minute, second); // Store the servers current time in our 'hour', 'minute' and 'second' variables.
getdate(year, month, day); // Store the servers current date in our 'year', 'month' and 'day' variables.
GenCmds = fopen("Generated_Commands.txt", io_append); // Open the file 'Generated_Commands.txt' with the filemode being 'io_append'. We store the variable returned by the function into our 'GenCmds' global variable, as we will use this as a file handle.
format(string, sizeof(string), "if(strcmp(\"/%s\", cmdtext, true, %d) == 0) // Requested by player '%s' (IP: %s) on the %d/%d/%d. Time: %d:%d:%d\r\n{\r\n", cmdtext[6], strlen(cmdtext) - 5, PlayerName, PlayerIp, day, month, year, hour, minute, second); // Formatting 'string' to hold a valid command check.
fwrite(GenCmds, string); // Writing the formatted 'string' to our 'GenCmds' file.
#if VehicleTele == 1 // If 'VehicleTele' is defined as 1, do the following:
#if SendAnnounceMessage == 1 // If 'SendAnnounceMessage' is defined as 1, do the following:
format(string, sizeof(string), " if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER)\r\n {\r\n SetPlayerInterior(playerid, %d);\r\n LinkVehicleToInterior(GetPlayerVehicleID(playerid), %d);\r\n SetVehiclePos(GetPlayerVehicleID(playerid), %f, %f, %f);\r\n SetVehicleZAngle(GetPlayerVehicleID(playerid), %f);\r\n ", Interior, Interior, x, y, z, Ang); // Formatting 'string' to hold a valid set of functions.
fwrite(GenCmds, string); // Writing the formatted 'string' to our 'GenCmds' file.
format(string, sizeof(string), " return SendClientMessageToAll(0x%x, \"Player '%s' has teleported to %s. Type '/%s' to teleport there.\");\r\n }\r\n", COLOUR_COMMAND, PlayerName, cmdtext[6], cmdtext[6]); // Formatting 'string' to hold a valid set of functions.
fwrite(GenCmds, string); // Writing the formatted 'string' to our 'GenCmds' file.
format(string, sizeof(string), " else\r\n {\r\n SetPlayerInterior(playerid, %d);\r\n SetPlayerPos(playerid, %f, %f, %f);\r\n SetPlayerFacingAngle(playerid, %f);\r\n return SendClientMessageToAll(0x%x, \"Player '%s' has teleported to %s. Type '/%s' to teleport there.\");\r\n }\r\n}\r\n", Interior, x, y, z, Ang, COLOUR_COMMAND, PlayerName, cmdtext[6], cmdtext[6]); // Formatting 'string' to hold a valid set of functions.
fwrite(GenCmds, string); // Writing the formatted 'string' to our 'GenCmds' file.
#else // If 'SendAnnounceMessage' was NOT 1, do the following:
format(string, sizeof(string), " if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER)\r\n {\r\n SetPlayerInterior(playerid, %d);\r\n LinkVehicleToInterior(GetPlayerVehicleID(playerid), %d);\r\n SetVehiclePos(GetPlayerVehicleID(playerid), %f, %f, %f);\r\n SetVehicleZAngle(GetPlayerVehicleID(playerid), %f);\r\n return 1;\r\n }\r\n", Interior, Interior, x, y, z, Ang); // Formatting 'string' to hold a valid set of functions.
fwrite(GenCmds, string); // Writing the formatted 'string' to our 'GenCmds' file.
format(string, sizeof(string), " else\r\n {\r\n SetPlayerInterior(playerid, %d);\r\n SetPlayerPos(playerid, %f, %f, %f);\r\n SetPlayerFacingAngle(playerid, %f);\r\n return 1;\r\n }\r\n}\r\n", Interior, x, y, z, Ang); // Formatting 'string' to hold a valid set of functions.
fwrite(GenCmds, string); // Writing the formatted 'string' to our 'GenCmds' file.
#endif // End the check for 'SendAnnounceMessage == 1'. This will prevent errors.
#else // If 'VehicleTele' was NOT 1, do the following:
#if SendAnnounceMessage == 1 // If 'SendAnnounceMessage' is defined as 1, do the following:
format(string, sizeof(string), " SetPlayerInterior(playerid, %d);\r\n SetPlayerPos(playerid, %f, %f, %f);\r\n SetPlayerFacingAngle(playerid, %f);\r\n return SendClientMessageToAll(0x%x, \"Player '%s' has teleported to %s. Type '%s' to teleport there.\");\r\n}\r\n", Interior, x, y, z, Ang, COLOUR_COMMAND, PlayerName, cmdtext[6], cmdtext[6]); // Formatting 'string' to hold a valid set of functions.
fwrite(GenCmds, string); // Writing the formatted 'string' to our 'GenCmds' file.
#else // If 'SendAnnounceMessage' was NOT 1, do the following:
format(string, sizeof(string), " SetPlayerInterior(playerid, %d);\r\n SetPlayerPos(playerid, %f, %f, %f);\r\n SetPlayerFacingAngle(playerid, %f);\r\n return 1;\r\n}\r\n", Interior, x, y, z, Ang); // Formatting 'string' to hold a valid set of functions.
fwrite(GenCmds, string); // Writing the formatted 'string' to our 'GenCmds' file.
#endif // End the check for 'SendAnnounceMessage == 1'. This will prevent errors.
#endif // End the check for 'VehicleTele == 1'. This will prevent errors.
fwrite(GenCmds, "\r\n// ******************* Command Generator By ~Cueball~ ******************* \\\\\r\n\r\n"); // Write a little command separator comment to the file.
fclose(GenCmds); // Close the file handle 'GenCmds'. This will successfully close 'Generated_Commands.txt', which will stop our server from crashing.
#if PrintInConsole == 1 // If 'PrintInConsole' is defined as 1, do the following:
printf("[generator] Player '%s' (IP: %s) requested '/%s'.", PlayerName, PlayerIp, cmdtext[6]); // Format a string with the necessary info, and then print it to the server console.
#endif // End the check for 'PrintInConsole == 1'. This will prevent errors.
#if SendAdminMessage == 1 // If 'SendAdminMessage' is defined as 1, do the following:
format(string, sizeof(string), "Command Generator: Player '%s' (ID: %d) requested '/%s'.", PlayerName, playerid, cmdtext[6]); // Formatting 'string' to hold a set of information about the player who generated the command.
for(new i = 0; i <= MAX_PLAYERS; i++) // A for loop which runs a maximum of MAX_PLAYERS (200) times.
if(IsPlayerConnected(i)) // If the current iteration is connected:
if(IsPlayerAdmin(i)) // If the current iteration is logged in as an RCON admin:
SendClientMessage(i, 0x33CCFFAA, string); // Sending the formatted 'string' to the player.
#endif // End the check for 'SendAdminMessage == 1'. This will prevent errors.
format(string, sizeof(string), "Command Generator: Your command '/%s' has been generated and sent to the server owner.", cmdtext[6]); // Formatting 'string' to hold a message containing the command name.
SendClientMessage(playerid, 0x33CCFFAA, string); // Sending the formatted 'string' to the player.
SendClientMessage(playerid, 0x33CCFFAA, "Your command statistics are:"); // Sending a message to the player.
format(string, sizeof(string), "Command Name: /%s | Interior: %d | Angle Value: %.2f", cmdtext[6], Interior, Ang); // Formatting 'string' to hold a message containing relevant command information.
SendClientMessage(playerid, 0x33CCFFAA, string); // Sending the formatted 'string' to the player.
format(string, sizeof(string), "X Value: %.2f | Y Value: %.2f | Z Value: %.2f", x, y, z, Ang, Interior); // Formatting 'string' to hold a message containing relevant command information.
SendClientMessage(playerid, 0x33CCFFAA, string); // Sending the formatted 'string' to the player.
#if SaveCommands == 1 // If 'SaveCommands' is defined as 1, do the following:
if(CurrentCommand == MAX_COMMANDS) // If 'CurrentCommand' is equal to 'MAX_COMMANDS' (ie: The amount of commands has reached its maximum):
CurrentCommand = 0; // Set 'CurrentCommand' to equal 0.
format(gCommands[CurrentCommand][NAME], MAX_COMMAND_NAME, "%s", cmdtext[6]); // Change the current command's 'NAME' cell of our 'gCommands' array to the name of the command.
format(gCommands[CurrentCommand][CREATOR], MAX_PLAYER_NAME, "%s", PlayerName); // Change the current command's 'CREATOR' cell of our 'gCommands' array to the name of the command creator.
gCommands[CurrentCommand][POS][0] = x; // Store the 'x' co-ordinate of our command in the first cell of our current command's 'POS' cell of our 'gCommands' array.
gCommands[CurrentCommand][POS][1] = y; // Store the 'y' co-ordinate of our command in the second cell of our current command's 'POS' cell of our 'gCommands' array.
gCommands[CurrentCommand][POS][2] = z; // Store the 'z' co-ordinate of our command in the third cell of our current command's 'POS' cell of our 'gCommands' array.
gCommands[CurrentCommand][POS][3] = Ang; // Store the 'angle' co-ordinate of our command in the fourth cell of our current command's 'POS' cell of our 'gCommands' array.
gCommands[CurrentCommand][INTERIOR] = GetPlayerInterior(playerid); // Store the interior of our command in our current command's 'INTERIOR' cell of our 'gCommands' array.
format(string, sizeof(string), "The server has allowed your command to be used immediately. Type '/%s' to teleport to this current location.", cmdtext[6]); // Formatting 'string' to hold a message containing the command name.
SendClientMessage(playerid, 0xFF9900AA, string); // Sending the formatted 'string' to the player.
CurrentCommand++;
#endif // End the check for 'SaveCommands == 1'. This will prevent errors.
return 1; // Return 1 to the server, and stop the 'SERVER: Unknown command.' message being sent to the player.
}
#if SaveCommands == 1 // If 'SaveCommands' is defined as 1, do the following:
format(string, MAX_COMMAND_NAME, "%s", cmdtext[1]); // Formatting 'string' to hold their command name, so that we can successfully compare strings later.
for(new i = 0; i <= MAX_COMMANDS; i++) // A for loop which runs a maximum of MAX_COMMANDS times.
{
if(gCommands[i][NAME][0] != '\0' && strcmp(string, gCommands[i][NAME], true, strlen(gCommands[i][NAME])) == 0) // If the current cell of 'gCommands[*][NAME][0]' is not empty AND it is the same as the command name the player supplied, do the following:
{
#if VehicleTele == 1 // If 'VehicleTele' is defined as 1, do the following:
if(IsPlayerInAnyVehicle(playerid)) // If the player is in ANY vehicle, do the following:
{
SetPlayerInterior(playerid, gCommands[i][INTERIOR]); // Set the player's interior to the correct value for our command.
LinkVehicleToInterior(GetPlayerVehicleID(playerid), gCommands[i][INTERIOR]); // Get the player's vehicle id, and set its interior to the correct value for our command.
SetVehiclePos(GetPlayerVehicleID(playerid), gCommands[i][POS][0], gCommands[i][POS][1], gCommands[i][POS][2]); // Get the player's vehicle id, and set its position to the correct co-ordinate for our command.
SetVehicleZAngle(GetPlayerVehicleID(playerid), gCommands[i][POS][3]); // Get the player's vehicle id, and set it to face the correct angle for our command.
}
else // If the player is NOT in a vehicle, do the following:
{
SetPlayerInterior(playerid, gCommands[i][INTERIOR]); // Set the player's interior to the correct value for our command.
SetPlayerPos(playerid, gCommands[i][POS][0], gCommands[i][POS][1], gCommands[i][POS][2]); // Set the player's position to the correct co-ordinate for our command.
SetPlayerFacingAngle(playerid, gCommands[i][POS][3]); // Set the player to face the correct angle for our command.
}
#else // If 'VehicleTele' was NOT 1, do the following:
SetPlayerInterior(playerid, gCommands[i][INTERIOR]); // Set the player's interior to the correct value for our command.
SetPlayerPos(playerid, gCommands[i][POS][0], gCommands[i][POS][1], gCommands[i][POS][2]); // Set the player's position to the correct co-ordinate for our command.
SetPlayerFacingAngle(playerid, gCommands[i][POS][3]); // Set the player to face the correct angle for our command.
#endif // End the check for 'VehicleTele == 1'. This will prevent errors.
#if SendTeleMessage == 1 // If 'SendTeleMessage' is defined as 1, do the following:
format(string, sizeof(string), "Command '/%s' was created by '%s'. You can create your own commands by typing '/cgen' at your wanted location.", gCommands[i][NAME], gCommands[i][CREATOR]); // Formatting 'string' to hold a message containing the command name and the creator of the command's name.
SendClientMessage(playerid, 0x33CCFFAA, string); // Sending the formatted 'string' to the player.
#endif // End the check for 'SendTeleMessage == 1'. This will prevent errors.
#if SendAnnounceMessage == 1 // If 'SendAnnounceMessage' is defined as 1, do the following:
GetPlayerName(playerid, string, MAX_PLAYER_NAME); // Store the players name into our 'string' variable, with a maximum length of 24 ('MAX_PLAYER_NAME').
format(string, sizeof(string), "Player '%s' has teleported to %s. Type '%s' to teleport there.", string, gCommands[i][NAME], cmdtext); // Formatting 'string' to hold a message containing the players name and the command name.
SendClientMessageToAll(COLOUR_COMMAND, string); // Sending the formatted 'string' to the player in the defined colour.
#endif // End the check for 'SendAnnounceMessage == 1'. This will prevent errors.
return 1; // Return 1 to the server, and stop the 'SERVER: Unknown command.' message being sent to the player.
}
}
#endif // End the check for 'SaveCommands == 1'. This will prevent errors.
return 0; // Send the 'SERVER: Unknown command.' message for any other commands.
}
//******************************************************************************************************
public OnVehicleSpawn(vehicleid)
return LinkVehicleToInterior(vehicleid, 0); // Set the vehicle's interior to 0, which will prevent cars from being invisible if they were used in a generated command with an interior other than 0 (inside a building).