Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,10 @@ All of the following commands can only be used on _your_ grenades. They will app
- ``.movebot``: moves the last bot you placed to your current position
- ``.nobot``: removes the bot you're aiming at (can also use ``.kickbot`` or ``.removebot``)
- ``.nobots``: clears all bots (``.clearbots``, ``.removebots``, ``.kickbots`` also work)
- ``.savebots``: saves all current bots to a file
- ``.loadbots``: loads bots from the file (written by the last ``.savebots``)
- ``.savebots <setup>``: saves all current bots to a file
- ``.loadbots <setup>``: loads bots from the file
- ``.botsetups``: list the setups available to load
- ``.removebotsetup <setup>``: delete a saved setup

### Miscellaneous commands
- ``.timer``: starts a timer when you start moving in any direction, and stops it when you stop moving, telling you the duration of time between starting/stopping
Expand Down
6 changes: 6 additions & 0 deletions scripting/practicemode.sp
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,12 @@ public void OnPluginStart() {
RegConsoleCmd("sm_loadbots", Command_LoadBots);
PM_AddChatAlias(".loadbots", "sm_loadbots");

RegConsoleCmd("sm_botsetups", Command_ListSetups);
PM_AddChatAlias(".botsetups", "sm_botsetups");

RegConsoleCmd("sm_removebotsetup", Command_RemoveBotSetup);
PM_AddChatAlias(".removebotsetup", "sm_removebotsetup");

RegConsoleCmd("sm_botsmenu", Command_BotsMenu);
PM_AddChatAlias(".bots", "sm_botsmenu");
}
Expand Down
120 changes: 116 additions & 4 deletions scripting/practicemode/bots.sp
Original file line number Diff line number Diff line change
Expand Up @@ -481,8 +481,25 @@ public Action Command_SaveBots(int client, int args) {

char mapName[PLATFORM_MAX_PATH];
GetCleanMapName(mapName, sizeof(mapName));

char path[PLATFORM_MAX_PATH];
BuildPath(Path_SM, path, sizeof(path), "data/practicemode/bots/%s.cfg", mapName);

char fileName[PLATFORM_MAX_PATH];

if(args > 0 && GetCmdArg(1, fileName, sizeof(fileName)) != 0) {
if(!IsValidFileName(fileName)) {
ReplyToCommand(client, "Invalid: Permitted characters (A-Za-z._-)");
return Plugin_Handled;
}
if(strlen(fileName) > 32) {
ReplyToCommand(client, "Invalid: Max name length 32");
return Plugin_Handled;
}
BuildPath(Path_SM, path, sizeof(path), "data/practicemode/bots/%s_%s.cfg", mapName, fileName);
} else {
BuildPath(Path_SM, path, sizeof(path), "data/practicemode/bots/%s.cfg", mapName);
}

KeyValues botsKv = new KeyValues("Bots");

int output_index = 0;
Expand Down Expand Up @@ -521,14 +538,35 @@ public Action Command_LoadBots(int client, int args) {
if (!g_InPracticeMode) {
return Plugin_Handled;
}

char mapName[PLATFORM_MAX_PATH];
GetCleanMapName(mapName, sizeof(mapName));

char path[PLATFORM_MAX_PATH];
BuildPath(Path_SM, path, sizeof(path), "data/practicemode/bots/%s.cfg", mapName);

char fileName[PLATFORM_MAX_PATH];

if(args > 0 && GetCmdArg(1, fileName, sizeof(fileName)) != 0) {
if(!IsValidFileName(fileName)) {
ReplyToCommand(client, "Invalid: Permitted characters (A-Za-z._-)");
return Plugin_Handled;
}
if(strlen(fileName) > 32) {
ReplyToCommand(client, "Invalid: Max name length 32");
return Plugin_Handled;
}
BuildPath(Path_SM, path, sizeof(path), "data/practicemode/bots/%s_%s.cfg", mapName, fileName);
} else {
BuildPath(Path_SM, path, sizeof(path), "data/practicemode/bots/%s.cfg", mapName);
}

KeyValues botsKv = new KeyValues("Bots");
botsKv.ImportFromFile(path);

if(!botsKv.ImportFromFile(path)) {
delete botsKv;
ReplyToCommand(client, "Invalid: Unable to load setup %s", fileName);
return Plugin_Handled;
}

botsKv.GotoFirstSubKey();

do {
Expand All @@ -552,6 +590,80 @@ public Action Command_LoadBots(int client, int args) {
return Plugin_Handled;
}

public Action Command_ListSetups(int client, int args) {
if (!g_InPracticeMode) {
return Plugin_Handled;
}

char mapName[PLATFORM_MAX_PATH];
GetCleanMapName(mapName, sizeof(mapName));

char path[PLATFORM_MAX_PATH];

BuildPath(Path_SM, path, sizeof(path), "data/practicemode/bots/");

DirectoryListing dirList = OpenDirectory(path);

char fileName[PLATFORM_MAX_PATH];

int mapNameLength = strlen(mapName);

ReplyToCommand(client, "List of Bot Setups");
ReplyToCommand(client, "------------------");

while(dirList.GetNext(fileName, sizeof(fileName))) {
int fileNameLength = strlen(fileName);
if(String_StartsWith(fileName, mapName)) {
char responseName[PLATFORM_MAX_PATH];
int j = 0;
for(int i = (mapNameLength+1);i < (fileNameLength - 4);i++) {
responseName[j++] = fileName[i];
}
if(strlen(responseName) != 0) {
ReplyToCommand(client, "%s", responseName);
}
}
}

ReplyToCommand(client, "------------------");

return Plugin_Handled;
}

public Action Command_RemoveBotSetup(int client, int args) {
if (!g_InPracticeMode) {
return Plugin_Handled;
}

char mapName[PLATFORM_MAX_PATH];
GetCleanMapName(mapName, sizeof(mapName));

char path[PLATFORM_MAX_PATH];

char fileName[PLATFORM_MAX_PATH];

if(args > 0 && GetCmdArg(1, fileName, sizeof(fileName)) != 0) {
if(!IsValidFileName(fileName)) {
ReplyToCommand(client, "Invalid: Permitted characters (A-Za-z._-)");
return Plugin_Handled;
}
if(strlen(fileName) > 32) {
ReplyToCommand(client, "Invalid: Max name length 32");
return Plugin_Handled;
}
BuildPath(Path_SM, path, sizeof(path), "data/practicemode/bots/%s_%s.cfg", mapName, fileName);
if(FileExists(path)) {
DeleteFile(path);
ReplyToCommand(client, "Setup deleted successfully");
} else {
ReplyToCommand(client, "Invalid: Setup not found");
}
} else {
ReplyToCommand(client, "Invalid: Must provide a setup name");
}
return Plugin_Handled;
}

public Action Command_SwapBot(int client, int args) {
int target = GetClientAimTarget(client, true);
if (!IsPMBot(target)) {
Expand Down
13 changes: 13 additions & 0 deletions scripting/practicemode/util.sp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ static char _colorNames[][] = {"{NORMAL}", "{DARK_RED}", "{PINK}", "{GRE
static char _colorCodes[][] = {"\x01", "\x02", "\x03", "\x04", "\x05", "\x06",
"\x07", "\x08", "\x09", "\x0B", "\x0C", "\x0E"};

static char _validFileNameCharacters[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";

stock void SwitchPlayerTeam(int client, int team) {
if (GetClientTeam(client) == team)
return;
Expand Down Expand Up @@ -414,3 +416,14 @@ stock int RemoveDuplicates(ArrayList list, int stringLength) {
}
return count;
}

stock bool IsValidFileName(char[] fileName) {
int i = 0;
while(fileName[i] != '\0') {
char c = fileName[i++]
if(FindCharInString(_validFileNameCharacters, c) == -1) {
return false;
}
}
return true;
}