Fix OpenFile

Fix OpenFile

#pragma semicolon 1
#pragma newdecls required

#include <mapchooser_redux>

int g_iMapCount = 0;

ConVar mcr_delete_offical_map;
ConVar mcr_generate_mapcycle;
ConVar mcr_generate_mapgroup;

public Plugin myinfo =
{
    name        = "Map Lister Redux",
    author      = "Kyle",
    description = "Automated Map Voting with Extensions",
    version     = MCR_VERSION,
    url         = "https://kxnrl.com"
};

public void OnPluginStart()
{
    mcr_delete_offical_map = CreateConVar("mcr_delete_offical_map", "1", "auto-delete offical maps", _, true, 0.0, true, 1.0);
    mcr_generate_mapcycle  = CreateConVar("mcr_generate_mapcycle",  "1", "auto-generate map list in mapcycle.txt", _, true, 0.0, true, 1.0);
    mcr_generate_mapgroup  = CreateConVar("mcr_generate_mapgroup",  "1", "auto-generate map group in gamemodes_server.txt", _, true, 0.0, true, 1.0);

    if(!DirExists("cfg/sourcemod/mapchooser"))
        if(!CreateDirectory("cfg/sourcemod/mapchooser", 511))
            SetFailState("Failed to create folder \"cfg/sourcemod/mapchooser\"");

    AutoExecConfig(true, "maplister", "sourcemod/mapchooser");

    g_iMapCount = GetMapCount();

    IloveSaSuSi_but_Idontlikeheranymore_DeleteMap();
    IloveSaSuSi_but_Idontlikeheranymore_MapCycle();
    IloveSaSuSi_but_Idontlikeheranymore_MapGroup();

    CreateTimer(600.0, Timer_Detected, _, TIMER_REPEAT);
}

public Action Timer_Detected(Handle timer)
{
    int count = GetMapCount();
    if(count != g_iMapCount)
    {
        LogMessage("Detected: Map count was changed! last check: %d  current: %d", g_iMapCount, count);
        IloveSaSuSi_but_Idontlikeheranymore_DeleteMap();
        IloveSaSuSi_but_Idontlikeheranymore_MapCycle();
        IloveSaSuSi_but_Idontlikeheranymore_MapGroup();
    }
    return Plugin_Continue;
}

static int GetMapCount()
{
    DirectoryListing dir = OpenDirectory("maps");
    if(dir == null)
        ThrowError("Failed to open maps.");

    int count = 0;

    FileType type = FileType_Unknown;
    char map[128];
    while(dir.GetNext(map, 128, type))
    {
        if(type != FileType_File || StrContains(map, ".bsp", false) == -1)
            continue;

        count++;
    }
    delete dir;

    return count;
}

static void IloveSaSuSi_but_Idontlikeheranymore_DeleteMap()
{
    if(!mcr_delete_offical_map.BoolValue)
        return;

    LogMessage("Process delete offical maps ...");

    DirectoryListing dir = OpenDirectory("maps");
    if(dir == null)
    {
        LogError("IloveSaSuSi_but_Idontlikeheranymore_DeleteMap -> Failed to open maps");
        return;
    }

    g_iMapCount = 0;

    FileType type = FileType_Unknown;
    char map[128];
    while(dir.GetNext(map, 128, type))
    {
        if(type != FileType_File || StrContains(map, ".bsp", false) == -1)
            continue;

        int c = FindCharInString(map, '.', true);
        map[c] = '\0';

        if(!IsOfficalMap(map))
        {
            g_iMapCount++;
            continue;
        }

        Format(map, 128, "maps/%s.bsp", map);

        LogMessage("%s delete offical map [%s]", DeleteFile(map) ? "Successful" : "Failed", map);
    }
    delete dir;
}

static void IloveSaSuSi_but_Idontlikeheranymore_MapCycle()
{
    if(!mcr_generate_mapcycle.BoolValue)
        return;

    LogMessage("Process generate mapcycle ...");

    File file = OpenFile("mapcycle.txt", "w+");
    if(file == null)
    {
        LogError("IloveSaSuSi_but_Idontlikeheranymore_MapCycle -> Failed to open mapcycle.txt");
        return;
    }

    DirectoryListing dir = OpenDirectory("maps");
    if(dir == null)
    {
        LogError("IloveSaSuSi_but_Idontlikeheranymore_MapCycle -> Failed to open maps");
        return;
    }

    FileType type = FileType_Unknown;
    char map[128];
    while(dir.GetNext(map, 128, type))
    {
        if(type != FileType_File || StrContains(map, ".bsp", false) == -1)
            continue;

        int c = FindCharInString(map, '.', true);
        map[c] = '\0';

        file.WriteLine(map);
    }
    delete dir;
    delete file;
}

static void IloveSaSuSi_but_Idontlikeheranymore_MapGroup()
{
    if(!mcr_generate_mapgroup.BoolValue)
        return;

    LogMessage("Process generate mapgroup ...");

    KeyValues kv = new KeyValues("GameModes_Server.txt");

    if(FileExists("gamemodes_server.txt"))
        kv.ImportFromFile("gamemodes_server.txt");

    kv.JumpToKey("mapgroups", true);

    if(kv.JumpToKey("custom_maps", false))
    {
        kv.GoBack();
        kv.DeleteKey("custom_maps");
    }

    kv.JumpToKey("custom_maps", true);

    kv.SetString("name", "custom_maps");

    kv.JumpToKey("maps", true);

    // foreach
    DirectoryListing dir = OpenDirectory("maps");
    if(dir == null)
    {
        LogError("IloveSaSuSi_but_Idontlikeheranymore_MapGroup -> Failed to open maps");
        delete kv;
        return;
    }
    FileType type = FileType_Unknown;
    char map[128];
    while(dir.GetNext(map, 128, type))
    {
        if(type != FileType_File || StrContains(map, ".bsp", false) == -1)
            continue;

        int c = FindCharInString(map, '.', true);
        map[c] = '\0';

        kv.SetString(map, " ");
    }
    delete dir;

    kv.Rewind();
    kv.ExportToFile("gamemodes_server.txt");

    delete kv;
}

static bool IsOfficalMap(const char[] map)
{
    static ArrayList officalmaps = null;
    if(officalmaps == null)
    {
        // create
        officalmaps = new ArrayList(ByteCountToCells(32));

        // input
        officalmaps.PushString("ar_baggage");
        officalmaps.PushString("ar_dizzy");
        officalmaps.PushString("ar_monastery");
        officalmaps.PushString("ar_shoots");
        officalmaps.PushString("cs_agency");
        officalmaps.PushString("cs_assault");
        officalmaps.PushString("cs_insertion");
        officalmaps.PushString("cs_italy");
        officalmaps.PushString("cs_office");
        officalmaps.PushString("de_austria");
        officalmaps.PushString("de_bank");
        officalmaps.PushString("de_cache");
        officalmaps.PushString("de_canals");
        officalmaps.PushString("de_cbble");
        officalmaps.PushString("de_dust2");
        officalmaps.PushString("de_inferno");
        officalmaps.PushString("de_lake");
        officalmaps.PushString("de_mirage");
        officalmaps.PushString("de_nuke");
        officalmaps.PushString("de_overpass");
        officalmaps.PushString("de_safehouse");
        officalmaps.PushString("de_shipped");
        officalmaps.PushString("de_shortdust");
        officalmaps.PushString("de_shortnuke");
        officalmaps.PushString("de_stmarc");
        officalmaps.PushString("de_sugarcane");
        officalmaps.PushString("de_train");
        officalmaps.PushString("gd_rialto");
        officalmaps.PushString("training1");
    }

    return (officalmaps.FindString(map) > -1);
}

#pragma semicolon 1
#pragma newdecls required

#include <mapchooser_redux>

int g_iMapCount = 0;

ConVar mcr_delete_offical_map;
ConVar mcr_generate_mapcycle;
ConVar mcr_generate_mapgroup;

public Plugin myinfo =
{
    name        = "Map Lister Redux",
    author      = "Kyle",
    description = "Automated Map Voting with Extensions",
    version     = MCR_VERSION,
    url         = "https://kxnrl.com"
};

public void OnPluginStart()
{
    mcr_delete_offical_map = CreateConVar("mcr_delete_offical_map", "1", "auto-delete offical maps", _, true, 0.0, true, 1.0);
    mcr_generate_mapcycle  = CreateConVar("mcr_generate_mapcycle",  "1", "auto-generate map list in mapcycle.txt", _, true, 0.0, true, 1.0);
    mcr_generate_mapgroup  = CreateConVar("mcr_generate_mapgroup",  "1", "auto-generate map group in gamemodes_server.txt", _, true, 0.0, true, 1.0);

    if(!DirExists("cfg/sourcemod/mapchooser"))
        if(!CreateDirectory("cfg/sourcemod/mapchooser", 511))
            SetFailState("Failed to create folder \"cfg/sourcemod/mapchooser\"");

    AutoExecConfig(true, "maplister", "sourcemod/mapchooser");

    g_iMapCount = GetMapCount();

    IloveSaSuSi_but_Idontlikeheranymore_DeleteMap();
    IloveSaSuSi_but_Idontlikeheranymore_MapCycle();
    IloveSaSuSi_but_Idontlikeheranymore_MapGroup();

    CreateTimer(600.0, Timer_Detected, _, TIMER_REPEAT);
}

public Action Timer_Detected(Handle timer)
{
    int count = GetMapCount();
    if(count != g_iMapCount)
    {
        LogMessage("Detected: Map count was changed! last check: %d  current: %d", g_iMapCount, count);
        IloveSaSuSi_but_Idontlikeheranymore_DeleteMap();
        IloveSaSuSi_but_Idontlikeheranymore_MapCycle();
        IloveSaSuSi_but_Idontlikeheranymore_MapGroup();
    }
    return Plugin_Continue;
}

static int GetMapCount()
{
    DirectoryListing dir = OpenDirectory("maps");
    if(dir == null)
        ThrowError("Failed to open maps.");

    int count = 0;

    FileType type = FileType_Unknown;
    char map[128];
    while(dir.GetNext(map, 128, type))
    {
        if(type != FileType_File || StrContains(map, ".bsp", false) == -1)
            continue;

        count++;
    }
    delete dir;

    return count;
}

static void IloveSaSuSi_but_Idontlikeheranymore_DeleteMap()
{
    if(!mcr_delete_offical_map.BoolValue)
        return;

    LogMessage("Process delete offical maps ...");

    DirectoryListing dir = OpenDirectory("maps");
    if(dir == null)
    {
        LogError("IloveSaSuSi_but_Idontlikeheranymore_DeleteMap -> Failed to open maps");
        return;
    }

    g_iMapCount = 0;

    FileType type = FileType_Unknown;
    char map[128];
    while(dir.GetNext(map, 128, type))
    {
        if(type != FileType_File || StrContains(map, ".bsp", false) == -1)
            continue;

        int c = FindCharInString(map, '.', true);
        map[c] = '\0';

        if(!IsOfficalMap(map))
        {
            g_iMapCount++;
            continue;
        }

        Format(map, 128, "maps/%s.bsp", map);

        LogMessage("%s delete offical map [%s]", DeleteFile(map) ? "Successful" : "Failed", map);
    }
    delete dir;
}

static void IloveSaSuSi_but_Idontlikeheranymore_MapCycle()
{
    if(!mcr_generate_mapcycle.BoolValue)
        return;

    LogMessage("Process generate mapcycle ...");

    File file = OpenFile("mapcycle.txt", "r+");
    if(file == null)
    {
        LogError("IloveSaSuSi_but_Idontlikeheranymore_MapCycle -> Failed to open mapcycle.txt");
        return;
    }

    DirectoryListing dir = OpenDirectory("maps");
    if(dir == null)
    {
        LogError("IloveSaSuSi_but_Idontlikeheranymore_MapCycle -> Failed to open maps");
        return;
    }

    FileType type = FileType_Unknown;
    char map[128];
    while(dir.GetNext(map, 128, type))
    {
        if(type != FileType_File || StrContains(map, ".bsp", false) == -1)
            continue;

        int c = FindCharInString(map, '.', true);
        map[c] = '\0';

        file.WriteLine(map);
    }
    delete dir;
    delete file;
}

static void IloveSaSuSi_but_Idontlikeheranymore_MapGroup()
{
    if(!mcr_generate_mapgroup.BoolValue)
        return;

    LogMessage("Process generate mapgroup ...");

    KeyValues kv = new KeyValues("GameModes_Server.txt");

    if(FileExists("gamemodes_server.txt"))
        kv.ImportFromFile("gamemodes_server.txt");

    kv.JumpToKey("mapgroups", true);

    if(kv.JumpToKey("custom_maps", false))
    {
        kv.GoBack();
        kv.DeleteKey("custom_maps");
    }

    kv.JumpToKey("custom_maps", true);

    kv.SetString("name", "custom_maps");

    kv.JumpToKey("maps", true);

    // foreach
    DirectoryListing dir = OpenDirectory("maps");
    if(dir == null)
    {
        LogError("IloveSaSuSi_but_Idontlikeheranymore_MapGroup -> Failed to open maps");
        delete kv;
        return;
    }
    FileType type = FileType_Unknown;
    char map[128];
    while(dir.GetNext(map, 128, type))
    {
        if(type != FileType_File || StrContains(map, ".bsp", false) == -1)
            continue;

        int c = FindCharInString(map, '.', true);
        map[c] = '\0';

        kv.SetString(map, " ");
    }
    delete dir;

    kv.Rewind();
    kv.ExportToFile("gamemodes_server.txt");

    delete kv;
}

static bool IsOfficalMap(const char[] map)
{
    static ArrayList officalmaps = null;
    if(officalmaps == null)
    {
        // create
        officalmaps = new ArrayList(ByteCountToCells(32));

        // input
        officalmaps.PushString("ar_baggage");
        officalmaps.PushString("ar_dizzy");
        officalmaps.PushString("ar_monastery");
        officalmaps.PushString("ar_shoots");
        officalmaps.PushString("cs_agency");
        officalmaps.PushString("cs_assault");
        officalmaps.PushString("cs_insertion");
        officalmaps.PushString("cs_italy");
        officalmaps.PushString("cs_office");
        officalmaps.PushString("de_austria");
        officalmaps.PushString("de_bank");
        officalmaps.PushString("de_cache");
        officalmaps.PushString("de_canals");
        officalmaps.PushString("de_cbble");
        officalmaps.PushString("de_dust2");
        officalmaps.PushString("de_inferno");
        officalmaps.PushString("de_lake");
        officalmaps.PushString("de_mirage");
        officalmaps.PushString("de_nuke");
        officalmaps.PushString("de_overpass");
        officalmaps.PushString("de_safehouse");
        officalmaps.PushString("de_shipped");
        officalmaps.PushString("de_shortdust");
        officalmaps.PushString("de_shortnuke");
        officalmaps.PushString("de_stmarc");
        officalmaps.PushString("de_sugarcane");
        officalmaps.PushString("de_train");
        officalmaps.PushString("gd_rialto");
        officalmaps.PushString("training1");
    }

    return (officalmaps.FindString(map) > -1);
}


Menu Client Validate

Menu Client Validate

#pragma semicolon 1

#define PLUGIN_AUTHOR "RumbleFrog, SourceBans++ Dev Team"
#define PLUGIN_VERSION "1.6.3-rc.1"

#include <sourcemod>
#include <sourcebans>

#pragma newdecls required

#define Chat_Prefix "[SourceBans++] "

enum
{
	Cooldown = 0,
	MinLen,
	Settings_Count
};

ConVar Convars[Settings_Count];

bool bInReason[MAXPLAYERS + 1];

int iMinLen = 10
	, iTargetCache[MAXPLAYERS + 1];

float fCooldown = 60.0
	, fNextUse[MAXPLAYERS + 1];

public Plugin myinfo =
{
	name = "SourceBans++ Report Plugin",
	author = PLUGIN_AUTHOR,
	description = "Adds ability for player to report offending players",
	version = PLUGIN_VERSION,
	url = "https://sbpp.github.io"
};

public void OnPluginStart()
{
	CreateConVar("sbpp_report_version", PLUGIN_VERSION, "SBPP Report Version", FCVAR_REPLICATED | FCVAR_SPONLY | FCVAR_DONTRECORD | FCVAR_NOTIFY);

	Convars[Cooldown] = CreateConVar("sbpp_report_cooldown", "60.0", "Cooldown in seconds between per report per user", FCVAR_NONE, true, 0.0, false);
	Convars[MinLen] = CreateConVar("sbpp_report_minlen", "10", "Minimum reason length", FCVAR_NONE, true, 0.0, false);

	LoadTranslations("sbpp_report.phrases");

	RegConsoleCmd("sm_report", CmdReport, "Initialize Report");

	Convars[Cooldown].AddChangeHook(OnConvarChanged);
	Convars[MinLen].AddChangeHook(OnConvarChanged);
}

public Action CmdReport(int iClient, int iArgs)
{
	if (!IsValidClient(iClient))
		return Plugin_Handled;

	if (OnCooldown(iClient))
	{
		PrintToChat(iClient, "%s%T", Chat_Prefix, "In Cooldown", GetRemainingTime(iClient));

		return Plugin_Handled;
	}

	Menu PList = new Menu(ReportMenu);

	char sName[MAX_NAME_LENGTH], sIndex[4];

	for (int i = 0; i <= MaxClients; i++)
	{
		if (!IsValidClient(i))
			continue;

		GetClientName(i, sName, sizeof sName);
		IntToString(i, sIndex, sizeof sIndex);

		PList.AddItem(sIndex, sName);
	}

	PList.Display(iClient, MENU_TIME_FOREVER);

	return Plugin_Handled;
}

public int ReportMenu(Menu menu, MenuAction action, int iClient, int iItem)
{
	switch (action)
	{
		case MenuAction_Select:
		{
			char sIndex[4];

			menu.GetItem(iItem, sIndex, sizeof sIndex);

			iTargetCache[iClient] = StringToInt(sIndex);

			bInReason[iClient] = true;

			PrintToChat(iClient, "%s%T", Chat_Prefix, "Reason Prompt");
		}
		case MenuAction_End:
			delete menu;
	}
}

public Action OnClientSayCommand(int iClient, const char[] sCommand, const char[] sArgs)
{
	if (!bInReason[iClient])
		return Plugin_Continue;

	if (!IsValidClient(iClient) || (iTargetCache[iClient] != -1 && !IsValidClient(iTargetCache[iClient])))
	{
		ResetInReason(iClient);

		return Plugin_Continue;
	}

	if (StrEqual(sArgs, "cancel", false))
	{
		PrintToChat(iClient, "%s%T", Chat_Prefix, "Report Canceled");

		ResetInReason(iClient);

		return Plugin_Stop;
	}

	if (strlen(sArgs) < iMinLen)
	{
		PrintToChat(iClient, "%s%T", Chat_Prefix, "Reason Short Need More");

		return Plugin_Stop;
	}

	SourceBans_ReportPlayer(iClient, iTargetCache[iClient], sArgs);

	AddCooldown(iClient);

	ResetInReason(iClient);

	PrintToChat(iClient, "%s%T", Chat_Prefix, "Report Sent");

	return Plugin_Stop;
}

void ResetInReason(int iClient)
{
	bInReason[iClient] = false;
	iTargetCache[iClient] = -1;
}

void AddCooldown(int iClient)
{
	fNextUse[iClient] = GetGameTime() + fCooldown;
}

bool OnCooldown(int iClient)
{
	return (fNextUse[iClient] - GetGameTime()) > 0.0;
}

float GetRemainingTime(int iClient)
{
	float fOffset = fNextUse[iClient] - GetGameTime();

	if (fOffset > 0.0)
		return fOffset;
	else
		return 0.0;
}

public void OnConvarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
{
	if (convar == Convars[Cooldown])
		fCooldown = Convars[Cooldown].FloatValue;
	else if (convar == Convars[MinLen])
		iMinLen = Convars[MinLen].IntValue;
}

stock bool IsValidClient(int iClient, bool bAlive = false)
{
	if (iClient >= 1 &&
	iClient <= MaxClients &&
	IsClientConnected(iClient) &&
	IsClientInGame(iClient) &&
	!IsFakeClient(iClient) &&
	(bAlive == false || IsPlayerAlive(iClient)))
	{
		return true;
	}

	return false;
}

#pragma semicolon 1

#define PLUGIN_AUTHOR "RumbleFrog, SourceBans++ Dev Team"
#define PLUGIN_VERSION "1.6.3-rc.1"

#include <sourcemod>
#include <sourcebans>

#pragma newdecls required

#define Chat_Prefix "[SourceBans++] "

enum
{
	Cooldown = 0,
	MinLen,
	Settings_Count
};

ConVar Convars[Settings_Count];

bool bInReason[MAXPLAYERS + 1];

int iMinLen = 10
	, iTargetCache[MAXPLAYERS + 1];

float fCooldown = 60.0
	, fNextUse[MAXPLAYERS + 1];

public Plugin myinfo =
{
	name = "SourceBans++ Report Plugin",
	author = PLUGIN_AUTHOR,
	description = "Adds ability for player to report offending players",
	version = PLUGIN_VERSION,
	url = "https://sbpp.github.io"
};

public void OnPluginStart()
{
	CreateConVar("sbpp_report_version", PLUGIN_VERSION, "SBPP Report Version", FCVAR_REPLICATED | FCVAR_SPONLY | FCVAR_DONTRECORD | FCVAR_NOTIFY);

	Convars[Cooldown] = CreateConVar("sbpp_report_cooldown", "60.0", "Cooldown in seconds between per report per user", FCVAR_NONE, true, 0.0, false);
	Convars[MinLen] = CreateConVar("sbpp_report_minlen", "10", "Minimum reason length", FCVAR_NONE, true, 0.0, false);

	LoadTranslations("sbpp_report.phrases");

	RegConsoleCmd("sm_report", CmdReport, "Initialize Report");

	Convars[Cooldown].AddChangeHook(OnConvarChanged);
	Convars[MinLen].AddChangeHook(OnConvarChanged);
}

public Action CmdReport(int iClient, int iArgs)
{
	if (!IsValidClient(iClient))
		return Plugin_Handled;

	if (OnCooldown(iClient))
	{
		PrintToChat(iClient, "%s%T", Chat_Prefix, "In Cooldown", GetRemainingTime(iClient));

		return Plugin_Handled;
	}

	Menu PList = new Menu(ReportMenu);

	char sName[MAX_NAME_LENGTH], sIndex[4];

	for (int i = 0; i <= MaxClients; i++)
	{
		GetClientName(i, sName, sizeof sName);
		IntToString(i, sIndex, sizeof sIndex);

		PList.AddItem(sIndex, sName);
	}

	PList.Display(iClient, MENU_TIME_FOREVER);

	return Plugin_Handled;
}

public int ReportMenu(Menu menu, MenuAction action, int iClient, int iItem)
{
	switch (action)
	{
		case MenuAction_Select:
		{
			char sIndex[4];

			menu.GetItem(iItem, sIndex, sizeof sIndex);

			iTargetCache[iClient] = StringToInt(sIndex);

			bInReason[iClient] = true;

			PrintToChat(iClient, "%s%T", Chat_Prefix, "Reason Prompt");
		}
		case MenuAction_End:
			delete menu;
	}
}

public Action OnClientSayCommand(int iClient, const char[] sCommand, const char[] sArgs)
{
	if (!bInReason[iClient])
		return Plugin_Continue;

	if (!IsValidClient(iClient) || (iTargetCache[iClient] != -1 && !IsValidClient(iTargetCache[iClient])))
	{
		ResetInReason(iClient);

		return Plugin_Continue;
	}

	if (StrEqual(sArgs, "cancel", false))
	{
		PrintToChat(iClient, "%s%T", Chat_Prefix, "Report Canceled");

		ResetInReason(iClient);

		return Plugin_Stop;
	}

	if (strlen(sArgs) < iMinLen)
	{
		PrintToChat(iClient, "%s%T", Chat_Prefix, "Reason Short Need More");

		return Plugin_Stop;
	}

	SourceBans_ReportPlayer(iClient, iTargetCache[iClient], sArgs);

	AddCooldown(iClient);

	ResetInReason(iClient);

	PrintToChat(iClient, "%s%T", Chat_Prefix, "Report Sent");

	return Plugin_Stop;
}

void ResetInReason(int iClient)
{
	bInReason[iClient] = false;
	iTargetCache[iClient] = -1;
}

void AddCooldown(int iClient)
{
	fNextUse[iClient] = GetGameTime() + fCooldown;
}

bool OnCooldown(int iClient)
{
	return (fNextUse[iClient] - GetGameTime()) > 0.0;
}

float GetRemainingTime(int iClient)
{
	float fOffset = fNextUse[iClient] - GetGameTime();

	if (fOffset > 0.0)
		return fOffset;
	else
		return 0.0;
}

public void OnConvarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
{
	if (convar == Convars[Cooldown])
		fCooldown = Convars[Cooldown].FloatValue;
	else if (convar == Convars[MinLen])
		iMinLen = Convars[MinLen].IntValue;
}

stock bool IsValidClient(int iClient, bool bAlive = false)
{
	if (iClient >= 1 &&
	iClient <= MaxClients &&
	IsClientConnected(iClient) &&
	IsClientInGame(iClient) &&
	!IsFakeClient(iClient) &&
	(bAlive == false || IsPlayerAlive(iClient)))
	{
		return true;
	}

	return false;
}


Remove old test file.

Remove old test file.

#pragma newdecls required
#pragma semicolon 1

#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <tf2_stocks>
#include <tf2>
#include <morecolors>
#define PLUGIN_VERSION "1.2.1"

bool bBossBattleStarted;

//--------------------//

public Plugin myinfo = {
	name = "[NGS] Events",
	author = "TheXeon",
	description = "Events for NGS people.",
	version = PLUGIN_VERSION,
	url = "https://matespastdates.servegame.com"
}

public void OnPluginStart()
{
	RegAdminCmd("sm_startbossbattle", CommandStartBossBattle, ADMFLAG_GENERIC, "Starts a boss battle");
	LoadTranslations("common.phrases");
}

public Action CommandStartBossBattle(int client, int args)
{
	if (args < 1)
	{
		CReplyToCommand(client, "{GREEN}[SM]{DEFAULT} Usage: sm_startbossbattle [target]");
		return Plugin_Handled;
	}
	char arg1[32];	GetCmdArg(1, arg1, sizeof(arg1));
	char arg2[32];	GetCmdArg(2, arg2, sizeof(arg2));
	char arg3[32];	GetCmdArg(3, arg3, sizeof(arg3));
	char arg4[32];	GetCmdArg(4, arg4, sizeof(arg4));
	char arg5[32];	GetCmdArg(5, arg5, sizeof(arg5));

	SpawnBoss

	return Plugin_Handled;
}

public void SpawnBoss(char[] cBossName, int iBossAmount = 1, int iBossHealth = 5000, int iBossSize bool bCrits = false)
{

}

public bool IsValidClient (int client)
{
	if(client > 4096) client = EntRefToEntIndex(client);
	if(client < 1 || client > MaxClients) return false;
	if(!IsClientInGame(client)) return false;
	if(IsFakeClient(client)) return false;
	if(GetEntProp(client, Prop_Send, "m_bIsCoaching")) return false;
	return true;
}


A-durr.

A-durr.

#include <sdktools>
#include <sdkhooks>

public Plugin:myinfo =
{
  name = "Weapon function times",
  author = "darkid",
  description = "Calculates the speed of projectiles, and firing speed of weapons. Created for the TF2 Wiki.",
  version = "3.2",
}

new deferredEntity = -1;
new deferredEntity2 = -1;

public OnPluginStart() {
  RegConsoleCmd("sm_setspell", SetSpell);
}

public Action:SetSpell(client, args) {
  if (args == 0) {
    ReplyToCommand(client, "Usage: sm_setspell <id>\n\
0\tFireball\n\
1\tBall O' Bats\n\
2\tUber Heal\n\
3\tPumpkin MIRV\n\
4\tBlast Jump\n\
5\tStealth\n\
6\tTeleport\n\
7\tBall O' Lightning\n\
8\tMinify\n\
9\tMeteor Storm\n\
10\tSummon MONOCULUS\n\
11\tSummon Skeletons (Spawns 3)\n\
12\tBoxing Rocket\n\
13\tB.A.S.E. Jump\n\
14\tUber Heal (Bumper Cars version)\n\
15\tBombinomicon Head\n\
");
  }
  new String:arg[16];
  GetCmdArg(1, arg, sizeof(arg));
  new spellbook = FindEntityByClassname(0, "tf_weapon_spellbook");
  SetEntProp(spellbook, Prop_Send, "m_iSelectedSpellIndex", StringToInt(arg));
  SetEntProp(spellbook, Prop_Send, "m_iSpellCharges", 999999);
  return Plugin_Handled;
}

public OnEntityCreated(entity, const String:classname[]) {
  deferredEntity = entity;
}

public Action:TF2_CalcIsAttackCritical(client, weapon, String:weaponname[], &bool:result) {
  deferredEntity2 = GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon");
}

public Float:GetSpeed(Float:velocity[3]) {
  return SquareRoot(Pow(velocity[0], 2.0)+Pow(velocity[1], 2.0)+Pow(velocity[2], 2.0));
}

public OnGameFrame() {
  if (deferredEntity2 != -1) {
    new Float:enginetime = GetGameTime();
    PrintToChat(1, "Next Primary Attack: %f", GetEntPropFloat(deferredEntity2, Prop_Send, "m_flNextPrimaryAttack") - enginetime);
    PrintToChat(1, "Next Secondary Attack: %f", GetEntPropFloat(deferredEntity2, Prop_Send, "m_flNextSecondaryAttack") - enginetime);
    PrintToChat(1, "Ammo Loaded: %d", GetEntProp(deferredEntity2, Prop_Send, "m_iClip1")); // Not working for minigun?
    deferredEntity2 = -1;
  }
  if (deferredEntity != -1 && IsValidEntity(deferredEntity)) {
    decl Float:velocity[3];
    new offset = GetEntSendPropOffs(deferredEntity, "m_vInitialVelocity");
    if (offset == -1) { // Not a projectile, since it doesn't have velocity property
      offset = 572; // Try using the magic number for CBaseProjectile
    }

    static Float:averageSpeed = 0.0;
    static numTrials = 0;
    static Float:minSpeed = 9999999.9;
    static Float:maxSpeed = 0.0;

    GetEntDataVector(deferredEntity, offset, velocity);
    new Float:speed = GetSpeed(velocity);
    if (speed > 0.0) {
      PrintToChat(1, "Projectile speed: %f", speed);
      averageSpeed += speed;
      numTrials++;
      if (speed < minSpeed) minSpeed = speed;
      if (speed > maxSpeed) maxSpeed = speed;
      PrintToChat(1, "N: %d AVG: %f MIN: %f MAX: %f", numTrials, averageSpeed/numTrials, minSpeed, maxSpeed);
    }
    deferredEntity = -1;
  }
}

#include <sdktools>
#include <sdkhooks>

public Plugin:myinfo =
{
  name = "Weapon function times",
  author = "darkid",
  description = "Calculates the speed of projectiles, and firing speed of weapons. Created for the TF2 Wiki.",
  version = "3.2",
}

new deferredEntity = -1;
new deferredEntity2 = -1;

public OnPluginStart() {
  RegConsoleCmd("sm_setspell", SetSpell);
}

public Action:SetSpell(client, args) {
  if (args == 0) {
    ReplyToCommand(client, "Usage: sm_setspell <id>\n\
0\tFireball\n\
1\tBall O' Bats\n\
2\tUber Heal\n\
3\tPumpkin MIRV\n\
4\tBlast Jump\n\
5\tStealth\n\
6\tTeleport\n\
7\tBall O' Lightning\n\
8\tMinify\n\
9\tMeteor Storm\n\
10\tSummon MONOCULUS\n\
11\tSummon Skeletons (Spawns 3)\n\
12\tBoxing Rocket\n\
13\tB.A.S.E. Jump\n\
14\tUber Heal (Bumper Cars version)\n\
15\tBombinomicon Head\n\
");
  }
  new String:arg[16];
  GetCmdArg(1, arg, sizeof(arg));
  new spellbook = FindEntityByClassname(0, "tf_weapon_spellbook");
  SetEntProp(spellbook, Prop_Send, "m_iSelectedSpellIndex", StringToInt(arg));
  SetEntProp(spellbook, Prop_Send, "m_iSpellCharges", 999999);
  return Plugin_Handled;
}

public OnEntityCreated(entity, const String:classname[]) {
  deferredEntity = entity;
}

public Action:TF2_CalcIsAttackCritical(client, weapon, String:weaponname[], &bool:result) {
  deferredEntity2 = GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon");
}

public Float:GetSpeed(Float:velocity[3]) {
  return SquareRoot(Pow(velocity[0], 2.0)+Pow(velocity[1], 2.0)+Pow(velocity[2], 2.0));
}

public OnGameFrame() {
  if (deferredEntity2 != -1 && false) {
    new Float:enginetime = GetGameTime();
    PrintToChat(1, "Next Primary Attack: %f", GetEntPropFloat(deferredEntity2, Prop_Send, "m_flNextPrimaryAttack") - enginetime);
    PrintToChat(1, "Next Secondary Attack: %f", GetEntPropFloat(deferredEntity2, Prop_Send, "m_flNextSecondaryAttack") - enginetime);
    PrintToChat(1, "Ammo Loaded: %d", GetEntProp(deferredEntity2, Prop_Send, "m_iClip1")); // Not working for minigun?
    deferredEntity2 = -1;
  }
  if (deferredEntity != -1 && IsValidEntity(deferredEntity)) {
    decl Float:velocity[3];
    new offset = GetEntSendPropOffs(deferredEntity, "m_vInitialVelocity");
    if (offset == -1) { // Not a projectile, since it doesn't have velocity property
      offset = 572; // Try using the magic number for CBaseProjectile
    }

    static Float:averageSpeed = 0.0;
    static numTrials = 0;
    static Float:minSpeed = 9999999.9;
    static Float:maxSpeed = 0.0;

    GetEntDataVector(deferredEntity, offset, velocity);
    new Float:speed = GetSpeed(velocity);
    if (speed > 0.0) {
      PrintToChat(1, "Projectile speed: %f", speed);
      averageSpeed += speed;
      numTrials++;
      if (speed < minSpeed) minSpeed = speed;
      if (speed > maxSpeed) maxSpeed = speed;
      PrintToChat(1, "N: %d AVG: %f MIN: %f MAX: %f", numTrials, averageSpeed/numTrials, minSpeed, maxSpeed);
    }
    deferredEntity = -1;
  }
}


Remove Str.Bool instead of Date.Bool in checking Pkg.last-updated

Maybe I should just get rid of Date.Bool altogether.

constant Int $:pkglist-stale = 60*60*24;

constant File $:pkglist-path = on {
    Debian { "/var/lib/apt/lists/"  }
    Alpine { "/var/cache/apk/"  }
    RHEL   { "/var/cache/yum"  }
}

constant Cmd $?pm is logged-as("\c[PACKAGE]") = on {
    Debian { 'apt-get' }
    Alpine { 'apk' }
    RHEL   { 'yum' }
}

#| a Pkg represents a package installable via the system's package
#| manager, like `apt-get` or `yum`.
#|{
    if not Pkg<curl> {
        .install;
        say "installed $_ {.version}";
    }
}
class Pkg {

    #| Tells the system specific package manager to update its list of pacakges.
    static method update-pkglist? on {
        Debian ${$?pm update >debug/warn}
        RHEL   {
            ${$?pm clean expire-cache >debug/warn} &&
              ${$?pm check-update >debug/warn};
            $? != 1
        }
                # apt is noisy for no reason so send it to debug instead of warn
        Alpine ${ $?pm update *>debug }
    }

    static method last-updated-->DateTime on {
        Debian {
            # "partial" seems to get touched whenever apt-get update is run
            $:pkglist-path.add("partial").ctime;
        }
        Alpine { $:pkglist-path.find(name => '*.gz')[0].ctime }
        RHEL ${
            date -d
            ${
                $?pm repolist enabled -v !>warn
                | grep -m1 Repo-expire
                | sed -r 's/.*last: |\)//g'
             }
            '+%FT%T.%3N'
        }
    }

    static method check-update? {
        my $last-updated = Pkg.last-updated;
        if ! ~$last-updated || now().posix - $last-updated.posix > $:pkglist-stale {
            info "Updating package list because it " ~ (
                ~$last-updated
                  ?? "was last updated at $last-updated"
                  !! "doesn't exist"
            );
            Pkg.update-pkglist;
        }
    }

    #| Installs the package via the builtin package manager.
    #| Returns true if the package was successfully installed.
    method install? {
        $self-->List[Pkg].install;
    }

    method ensure-install? {
        $self.installed || $self.install;
    }

    #| Returns True if a version of the package is installed.
    method installed? on {
        Debian ${dpkg -s $self *>X}
        RHEL   ${yum list installed $self *>X}
        Alpine ${apk info -e $self}
    }

    #| Gets the version of the currently installed package
    method version~ on {
        Debian ${dpkg -s $self |sed -n 's/^Version: //p' }
        RHEL   ${yum info installed $self |sed -n 's/Version *: //p'}
        Alpine ${apk version $self | sed -rn '2s/\w+-(\S*).*/\1/p' }
    }

    #| In Bool context Pkgs return `.installed`
    method Bool { $self.installed }

    method prompt-install {
        if prompt("This script requires the '$self' to be installed to continue.\ninstall?", :default) {
            $self.install;
        } else {
            die "unable to install $self";
        }
    }
}

augment List[Pkg] {

    #| Installs the package via the builtin package manager.
    #| Returns true if the package was successfully installed.
    method install? on {
        RHEL ${$?pm install -y @$self >debug/warn}
        Debian {
            Pkg.check-update;
            ${
                $?pm install >debug/warn :DEBIAN_FRONTEND<noninteractive>
                -y -q --no-install-recommends @$self
            }
        }
        Alpine {
            Pkg.check-update;
            ${$?pm add @$self --no-progress >debug/warn};
        }
    }
}

constant Int $:pkglist-stale = 60*60*24;

constant File $:pkglist-path = on {
    Debian { "/var/lib/apt/lists/"  }
    Alpine { "/var/cache/apk/"  }
    RHEL   { "/var/cache/yum"  }
}

constant Cmd $?pm is logged-as("\c[PACKAGE]") = on {
    Debian { 'apt-get' }
    Alpine { 'apk' }
    RHEL   { 'yum' }
}

#| a Pkg represents a package installable via the system's package
#| manager, like `apt-get` or `yum`.
#|{
    if not Pkg<curl> {
        .install;
        say "installed $_ {.version}";
    }
}
class Pkg {

    #| Tells the system specific package manager to update its list of pacakges.
    static method update-pkglist? on {
        Debian ${$?pm update >debug/warn}
        RHEL   {
            ${$?pm clean expire-cache >debug/warn} &&
              ${$?pm check-update >debug/warn};
            $? != 1
        }
                # apt is noisy for no reason so send it to debug instead of warn
        Alpine ${ $?pm update *>debug }
    }

    static method last-updated-->DateTime on {
        Debian {
            # "partial" seems to get touched whenever apt-get update is run
            $:pkglist-path.add("partial").ctime;
        }
        Alpine { $:pkglist-path.find(name => '*.gz')[0].ctime }
        RHEL ${
            date -d
            ${
                $?pm repolist enabled -v !>warn
                | grep -m1 Repo-expire
                | sed -r 's/.*last: |\)//g'
             }
            '+%FT%T.%3N'
        }
    }

    static method check-update? {
        my $last-updated = Pkg.last-updated;
        if !$last-updated || now().posix - $last-updated.posix > $:pkglist-stale {
            info "Updating package list because it " ~ (
                $last-updated
                  ?? "was last updated at $last-updated"
                  !! "doesn't exist"
            );
            Pkg.update-pkglist;
        }
    }

    #| Installs the package via the builtin package manager.
    #| Returns true if the package was successfully installed.
    method install? {
        $self-->List[Pkg].install;
    }

    method ensure-install? {
        $self.installed || $self.install;
    }

    #| Returns True if a version of the package is installed.
    method installed? on {
        Debian ${dpkg -s $self *>X}
        RHEL   ${yum list installed $self *>X}
        Alpine ${apk info -e $self}
    }

    #| Gets the version of the currently installed package
    method version~ on {
        Debian ${dpkg -s $self |sed -n 's/^Version: //p' }
        RHEL   ${yum info installed $self |sed -n 's/Version *: //p'}
        Alpine ${apk version $self | sed -rn '2s/\w+-(\S*).*/\1/p' }
    }

    #| In Bool context Pkgs return `.installed`
    method Bool { $self.installed }

    method prompt-install {
        if prompt("This script requires the '$self' to be installed to continue.\ninstall?", :default) {
            $self.install;
        } else {
            die "unable to install $self";
        }
    }
}

augment List[Pkg] {

    #| Installs the package via the builtin package manager.
    #| Returns true if the package was successfully installed.
    method install? on {
        RHEL ${$?pm install -y @$self >debug/warn}
        Debian {
            Pkg.check-update;
            ${
                $?pm install >debug/warn :DEBIAN_FRONTEND<noninteractive>
                -y -q --no-install-recommends @$self
            }
        }
        Alpine {
            Pkg.check-update;
            ${$?pm add @$self --no-progress >debug/warn};
        }
    }
}


Remove functype

Remove functype

/**
 * vim: set ts=4 :
 * =============================================================================
 * Jetpack Plus
 * Rewrite of the Sourcemod plugin to make it easier to extend and modify.
 *
 * Copyright 2014 CrimsonTautology
 * =============================================================================
 *
 */

#pragma semicolon 1

#include <sourcemod>
#include <sdktools>
#include <smlib/entities>

#define PLUGIN_VERSION "0.1"

#define MOVECOLLIDE_DEFAULT		0
#define MOVECOLLIDE_FLY_BOUNCE	1

public Plugin:myinfo =
{
    name = "Jetpack Plus",
    author = "CrimsonTautology",
    description = "Let client's fly around by holding jump.",
    version = PLUGIN_VERSION,
    url = "https://github.com/CrimsonTautology/sm_jetpack_plus"
};

new Handle:g_Cvar_Enabled = INVALID_HANDLE;
new Handle:g_Cvar_JetpackForce = INVALID_HANDLE;
new Handle:g_Cvar_JumpDelay = INVALID_HANDLE;

new Handle:g_Forward_OnStartJetpack = INVALID_HANDLE;
new Handle:g_Forward_OnStopJetpack = INVALID_HANDLE;
new Handle:g_Forward_OnJetpackStep= INVALID_HANDLE;

new g_Offset_movecollide = -1;

new bool:g_IsUsingJetpack[MAXPLAYERS+1] = {false, ...};

public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max)
{
    if (LibraryExists("jetpack_plus"))
    {
        strcopy(error, err_max, "Jetpack Plus already loaded, aborting.");
        return APLRes_Failure;
    }

    RegPluginLibrary("jetpack_plus");

    CreateNative("IsClientUsingJetpack", _IsClientUsingJetpack);
    CreateNative("AreJetpacksEnabled", _AreJetpacksEnabled);

    return APLRes_Success;
}

public OnPluginStart()
{
    LoadTranslations("jetpack_plus.phrases");

    g_Cvar_Enabled = CreateConVar(
            "sm_jetpack",
            "1",
            "Set to 1 to enable the jetpack plugin");
    g_Cvar_JetpackForce = CreateConVar(
            "sm_jetpack_force",
            "8.0",
            "Strength at which the jetpack pushes the player"
            );
    g_Cvar_JumpDelay = CreateConVar(
            "sm_jetpack_jump_delay",
            "0.15",
            "The time in seconds the jump key needs to be pressed before the jetpack starts"
            );

    HookConVarChange(g_Cvar_Enabled, OnJetpackEnabledChange);

    g_Forward_OnStartJetpack = CreateGlobalForward("OnStartJetpack", ET_Ignore, Param_Cell);
    g_Forward_OnStopJetpack =  CreateGlobalForward("OnStopJetpack",  ET_Ignore, Param_Cell);
    g_Forward_OnJetpackStep =  CreateGlobalForward("OnJetpackStep",  ET_Ignore, Param_Cell);

    if((g_Offset_movecollide = FindSendPropOffs("CBaseEntity", "movecollide")) == -1)
        LogError("Could not find offset for CBaseEntity::movecollide");
}

public OnClientDisconnect(client)
{
    StopJetpack(client);
}

public OnGameFrame()
{
    if(AreJetpacksEnabled())
    {
        for (new client=1; client <= MaxClients; client++)
        {
            //For each client using a jetpack
            if(IsClientUsingJetpack(client))
            {
                JetpackStep(client);
            }
        }
    }
}

public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon, &subtype, &cmdnum, &tickcount, &seed, mouse[2])
{
    if(!AreJetpacksEnabled()) return Plugin_Continue;

    if(!IsClientUsingJetpack(client) && buttons & IN_JUMP)
    {
        new player = GetClientUserId(client);
        new Float:delay = GetConVarFloat(g_Cvar_JumpDelay);
        CreateTimer(delay, HeldJump, player);
    }

    return Plugin_Continue;
}

//Call back for when a player presses jump.  Checks if jump is still held down
public Action:HeldJump(Handle:timer, any:player)
{
    new client = GetClientOfUserId(player);

    if(!IsClientInGame(client)) return Plugin_Handled;

    if(!IsClientUsingJetpack(client) && GetClientButtons(client) & IN_JUMP)
    {
        StartJetpack(client);
    }

    return Plugin_Handled;
}

public OnJetpackEnabledChange(Handle:convar, const String:old[], const String:new[])
{
    //When enabled state changes from enabled to disabled
    if(bool:StringToInt(old) && !bool:StringToInt(new))
    {
        // force stop jetpack for each client
        for (new client=1; client <= MaxClients; client++)
        {
            if(IsClientUsingJetpack(client))
            {
                StopJetpack(client);
            }
        }
    }
}

public _IsClientUsingJetpack(Handle:plugin, args) { return _:IsClientUsingJetpack(GetNativeCell(1)); }
bool:IsClientUsingJetpack(client)
{
    return g_IsUsingJetpack[client];
}

public _AreJetpacksEnabled(Handle:plugin, args) { return _:AreJetpacksEnabled(); }
bool:AreJetpacksEnabled()
{
    return GetConVarBool(g_Cvar_Enabled);
}

StartJetpack(client)
{
    //Forward event
    decl Action:result;
    Call_StartForward(g_Forward_OnStartJetpack);
    Call_PushCell(client);
    Call_Finish(result);
    if(result == Plugin_Handled) return;

    SetEntityMoveType(client, MOVETYPE_FLY);
    SetEntityMoveCollide(client, MOVECOLLIDE_FLY_BOUNCE);
    ChangeEdictState(client);
    g_IsUsingJetpack[client] = true;
}

StopJetpack(client)
{
    //Forward event
    decl Action:result;
    Call_StartForward(g_Forward_OnStopJetpack);
    Call_PushCell(client);
    Call_Finish(result);
    if(result == Plugin_Handled) return;

    SetEntityMoveType(client, MOVETYPE_WALK);
    SetEntityMoveCollide(client, MOVECOLLIDE_DEFAULT);
    ChangeEdictState(client);
    g_IsUsingJetpack[client] = false;
}

//Called each frame a client is using a jetpack
JetpackStep(client)
{
    new Float:force = GetConVarFloat(g_Cvar_JetpackForce);
    new bool:force_stop = false;

    //Forward event
    decl Action:result;
    Call_StartForward(g_Forward_OnJetpackStep);
    Call_PushCell(client);
    Call_PushFloatRef(force);
    Call_PushCellRef(force_stop);
    Call_Finish(result);
    if(result == Plugin_Handled) return;

    new buttons = GetClientButtons(client);
    if(!force_stop && IsPlayerAlive(client) && (buttons & IN_JUMP))
    {
        JetpackPush(client, force);
    }
    else
    {
        StopJetpack(client);
    }
}

JetpackPush(client, Float:force)
{
    new Float:vec[3];
    Entity_GetBaseVelocity(client, vec);
    vec[2] += force;
    Entity_SetBaseVelocity(client, vec);
    ChangeEdictState(client);
}

SetEntityMoveCollide(entity, movecollide)
{
    if(g_Offset_movecollide == -1) return;
    SetEntData(entity, g_Offset_movecollide, movecollide);
}

/**
 * vim: set ts=4 :
 * =============================================================================
 * Jetpack Plus
 * Rewrite of the Sourcemod plugin to make it easier to extend and modify.
 *
 * Copyright 2014 CrimsonTautology
 * =============================================================================
 *
 */

#pragma semicolon 1

#include <sourcemod>
#include <sdktools>
#include <smlib/entities>

#define PLUGIN_VERSION "0.1"

#define MOVECOLLIDE_DEFAULT		0
#define MOVECOLLIDE_FLY_BOUNCE	1

public Plugin:myinfo =
{
    name = "Jetpack Plus",
    author = "CrimsonTautology",
    description = "Let client's fly around by holding jump.",
    version = PLUGIN_VERSION,
    url = "https://github.com/CrimsonTautology/sm_jetpack_plus"
};

new Handle:g_Cvar_Enabled = INVALID_HANDLE;
new Handle:g_Cvar_JetpackForce = INVALID_HANDLE;
new Handle:g_Cvar_JumpDelay = INVALID_HANDLE;

new Handle:g_Forward_OnStartJetpack = INVALID_HANDLE;
new Handle:g_Forward_OnStopJetpack = INVALID_HANDLE;
new Handle:g_Forward_OnJetpackStep= INVALID_HANDLE;

new g_Offset_movecollide = -1;

new bool:g_IsUsingJetpack[MAXPLAYERS+1] = {false, ...};

public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max)
{
    if (LibraryExists("jetpack_plus"))
    {
        strcopy(error, err_max, "Jetpack Plus already loaded, aborting.");
        return APLRes_Failure;
    }

    RegPluginLibrary("jetpack_plus");

    CreateNative("IsClientUsingJetpack", _IsClientUsingJetpack);
    CreateNative("AreJetpacksEnabled", _AreJetpacksEnabled);

    return APLRes_Success;
}

public OnPluginStart()
{
    LoadTranslations("jetpack_plus.phrases");

    g_Cvar_Enabled = CreateConVar(
            "sm_jetpack",
            "1",
            "Set to 1 to enable the jetpack plugin");
    g_Cvar_JetpackForce = CreateConVar(
            "sm_jetpack_force",
            "8.0",
            "Strength at which the jetpack pushes the player"
            );
    g_Cvar_JumpDelay = CreateConVar(
            "sm_jetpack_jump_delay",
            "0.15",
            "The time in seconds the jump key needs to be pressed before the jetpack starts"
            );

    HookConVarChange(g_Cvar_Enabled, OnJetpackEnabledChange);

    g_Forward_OnStartJetpack = CreateGlobalForward("OnStartJetpack", ET_Ignore, Param_Cell);
    g_Forward_OnStopJetpack =  CreateGlobalForward("OnStopJetpack",  ET_Ignore, Param_Cell);
    g_Forward_OnJetpackStep =  CreateGlobalForward("OnJetpackStep",  ET_Ignore, Param_Cell);

    if((g_Offset_movecollide = FindSendPropOffs("CBaseEntity", "movecollide")) == -1)
        LogError("Could not find offset for CBaseEntity::movecollide");
}

public OnClientDisconnect(client)
{
    StopJetpack(client);
}

public OnGameFrame()
{
    if(AreJetpacksEnabled())
    {
        for (new client=1; client <= MaxClients; client++)
        {
            //For each client using a jetpack
            if(IsClientUsingJetpack(client))
            {
                JetpackStep(client);
            }
        }
    }
}

public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon, &subtype, &cmdnum, &tickcount, &seed, mouse[2])
{
    if(!AreJetpacksEnabled()) return Plugin_Continue;

    if(!IsClientUsingJetpack(client) && buttons & IN_JUMP)
    {
        new player = GetClientUserId(client);
        new Float:delay = GetConVarFloat(g_Cvar_JumpDelay);
        CreateTimer(delay, HeldJump, player);
    }

    return Plugin_Continue;
}

//Call back for when a player presses jump.  Checks if jump is still held down
public Action:HeldJump(Handle:timer, any:player)
{
    new client = GetClientOfUserId(player);

    if(!IsClientInGame(client)) return Plugin_Handled;

    if(!IsClientUsingJetpack(client) && GetClientButtons(client) & IN_JUMP)
    {
        StartJetpack(client);
    }

    return Plugin_Handled;
}

public ConVarChanged:OnJetpackEnabledChange(Handle:convar, const String:old[], const String:new[])
{
    //When enabled state changes from enabled to disabled
    if(bool:StringToInt(old) && !bool:StringToInt(new))
    {
        // force stop jetpack for each client
        for (new client=1; client <= MaxClients; client++)
        {
            if(IsClientUsingJetpack(client))
            {
                StopJetpack(client);
            }
        }
    }
}

public _IsClientUsingJetpack(Handle:plugin, args) { return _:IsClientUsingJetpack(GetNativeCell(1)); }
bool:IsClientUsingJetpack(client)
{
    return g_IsUsingJetpack[client];
}

public _AreJetpacksEnabled(Handle:plugin, args) { return _:AreJetpacksEnabled(); }
bool:AreJetpacksEnabled()
{
    return GetConVarBool(g_Cvar_Enabled);
}

StartJetpack(client)
{
    //Forward event
    decl Action:result;
    Call_StartForward(g_Forward_OnStartJetpack);
    Call_PushCell(client);
    Call_Finish(result);
    if(result == Plugin_Handled) return;

    SetEntityMoveType(client, MOVETYPE_FLY);
    SetEntityMoveCollide(client, MOVECOLLIDE_FLY_BOUNCE);
    ChangeEdictState(client);
    g_IsUsingJetpack[client] = true;
}

StopJetpack(client)
{
    //Forward event
    decl Action:result;
    Call_StartForward(g_Forward_OnStopJetpack);
    Call_PushCell(client);
    Call_Finish(result);
    if(result == Plugin_Handled) return;

    SetEntityMoveType(client, MOVETYPE_WALK);
    SetEntityMoveCollide(client, MOVECOLLIDE_DEFAULT);
    ChangeEdictState(client);
    g_IsUsingJetpack[client] = false;
}

//Called each frame a client is using a jetpack
JetpackStep(client)
{
    new Float:force = GetConVarFloat(g_Cvar_JetpackForce);
    new bool:force_stop = false;

    //Forward event
    decl Action:result;
    Call_StartForward(g_Forward_OnJetpackStep);
    Call_PushCell(client);
    Call_PushFloatRef(force);
    Call_PushCellRef(force_stop);
    Call_Finish(result);
    if(result == Plugin_Handled) return;

    new buttons = GetClientButtons(client);
    if(!force_stop && IsPlayerAlive(client) && (buttons & IN_JUMP))
    {
        JetpackPush(client, force);
    }
    else
    {
        StopJetpack(client);
    }
}

JetpackPush(client, Float:force)
{
    new Float:vec[3];
    Entity_GetBaseVelocity(client, vec);
    vec[2] += force;
    Entity_SetBaseVelocity(client, vec);
    ChangeEdictState(client);
}

SetEntityMoveCollide(entity, movecollide)
{
    if(g_Offset_movecollide == -1) return;
    SetEntData(entity, g_Offset_movecollide, movecollide);
}


curlfix

curlfix

//-------------------------------------------------------------------------------------------------
new g_curl_default_options[][2] = {
	{_:CURLOPT_NOSIGNAL,		1}, ///use for threaded only
	{_:CURLOPT_NOPROGRESS,		1},
	{_:CURLOPT_TIMEOUT,			60}, // allow user to specify?
	{_:CURLOPT_CONNECTTIMEOUT,	5},
	{_:CURLOPT_VERBOSE,			0}
};

//-------------------------------------------------------------------------------------------------
#define TRANSFER_ATTEMPTS 4

Handle:SetupCurl( Handle:kv, const String:url[], Handle:post=INVALID_HANDLE ) {
	decl String:tempfile[256];
	GetTempFile( tempfile, sizeof(tempfile) );
	KvSetString( kv, "file", tempfile );

	new Handle:curl = curl_easy_init();
	curl_easy_setopt_int_array( curl, g_curl_default_options, sizeof( g_curl_default_options ) );
	new Handle:outfile = curl_OpenFile( tempfile, "wb" );
	curl_easy_setopt_string( curl, CURLOPT_URL, url );
	curl_easy_setopt_handle( curl, CURLOPT_WRITEDATA, outfile );

	if( post != INVALID_HANDLE ) {
		curl_easy_setopt_handle( curl, CURLOPT_HTTPPOST, CURLBuildPost( post ) );
	}
	KvSetHandle( kv, "outfile", outfile );
	return curl;
}

//-------------------------------------------------------------------------------------------------
RemoteTransfer( const String:url[], TransferCompleteCallback:on_complete, any:data=0, Handle:post=INVALID_HANDLE ) {

	new Handle:kv = CreateKeyValues( "STDownload" );
	KvSetString( kv, "url", url );

	new Handle:curl = SetupCurl( kv, url, post );

	KvSetNum( kv, "attempt", 0 );
	KvSetHandle( kv, "post", post );
	KvSetNum( kv, "userdata", data );
	KvSetNum( kv, "on_complete", _:on_complete );

	curl_easy_perform_thread( curl, OnCURLTransferComplete, kv );
}

//-------------------------------------------------------------------------------------------------
CURLRetryTransfer( Handle:kv ) {
	decl String:url[512];
	KvGetString( kv, "url", url, sizeof url );
	new Handle:curl = SetupCurl( kv, url, KvGetHandle( kv, "post" ) );
	curl_easy_perform_thread( curl, OnCURLTransferComplete, kv );
}

//-------------------------------------------------------------------------------------------------
Handle:CURLBuildPost( Handle:data ) {
	ResetPack(data);
	decl String:postname[128];
	decl String:postdata[512];

	new Handle:post = curl_httppost();

	new index = 0;
	while( IsPackReadable(data,1) ) {
		ReadPackString( data, postname, sizeof postname );
		ReadPackString( data, postdata, sizeof postdata );
		curl_formadd( post, CURLFORM_COPYNAME, postname, CURLFORM_COPYCONTENTS, postdata, CURLFORM_END );
		index++;
	}

	return post;
}

//-------------------------------------------------------------------------------------------------
bool:CURLDeletePostPack( Handle:kv ) {
	new Handle:post = KvGetHandle( kv, "post" );
	if( post != INVALID_HANDLE ) {
		CloseHandle(post);
		KvSetHandle( kv, "post", INVALID_HANDLE );
		return true;
	}
	return false;
}

//-------------------------------------------------------------------------------------------------
public OnCURLTransferComplete( Handle:hndl, CURLcode:code, any:kv ) {

	CloseHandle( KvGetHandle( kv, "outfile" ) );

	const HTTP_RESPONSE_OK = 200;

	new response;
	curl_easy_getinfo_int( hndl, CURLINFO_RESPONSE_CODE, response );
	CloseHandle(hndl);
	if( code != CURLE_OK || response != HTTP_RESPONSE_OK  ) {

		decl String:file[128];
		KvGetString( kv, "file", file, sizeof file );
		TryDeleteFile( file );

		// retry if not 404 and not too many attempts
		new attempt = KvGetNum( kv, "attempt" );
		attempt++;
		if( attempt >= TRANSFER_ATTEMPTS || response == 404 ) {
			if( response == 404 ) {
				KvSetNum( kv, "notfound", 1 );
			}

			Call_StartFunction( INVALID_HANDLE, Function:KvGetNum( kv, "on_complete" ) );
			Call_PushCell( kv );
			Call_PushCell( false );
			Call_PushCell( KvGetNum( kv, "userdata" ) );
			Call_Finish();
			CURLDeletePostPack(kv);
			CloseHandle(kv);

			return;
		}

		// retry
		KvSetNum( kv, "attempt", attempt );
		CURLRetryTransfer( kv );
		return;

	} else {
		Call_StartFunction( INVALID_HANDLE, Function:KvGetNum( kv, "on_complete" ) );
		Call_PushCell( kv );
		Call_PushCell( true );
		Call_PushCell( KvGetNum( kv, "userdata" ) );
		Call_Finish();

		decl String:file[128];
		KvGetString( kv, "file", file, sizeof file );
		TryDeleteFile( file );

		CURLDeletePostPack(kv);
		CloseHandle(kv);

	}
}

//-------------------------------------------------------------------------------------------------
new g_curl_default_options[][2] = {
	{_:CURLOPT_NOSIGNAL,		1}, ///use for threaded only
	{_:CURLOPT_NOPROGRESS,		1},
	{_:CURLOPT_TIMEOUT,			60}, // allow user to specify?
	{_:CURLOPT_CONNECTTIMEOUT,	5},
	{_:CURLOPT_VERBOSE,			0}
};

//-------------------------------------------------------------------------------------------------
#define TRANSFER_ATTEMPTS 4

Handle:SetupCurl( const String:url[], Handle:post=INVALID_HANDLE ) {

	new Handle:curl = curl_easy_init();
	curl_easy_setopt_int_array( curl, g_curl_default_options, sizeof( g_curl_default_options ) );
	new Handle:outfile = curl_OpenFile( tempfile, "wb" );
	curl_easy_setopt_string( curl, CURLOPT_URL, url );
	curl_easy_setopt_handle( curl, CURLOPT_WRITEDATA, outfile );

	if( post != INVALID_HANDLE ) {
		curl_easy_setopt_handle( curl, CURLOPT_HTTPPOST, CURLBuildPost( post ) );
	}
}

//-------------------------------------------------------------------------------------------------
RemoteTransfer( const String:url[], TransferCompleteCallback:on_complete, any:data=0, Handle:post=INVALID_HANDLE ) {

	new Handle:kv = CreateKeyValues( "STDownload" );
	KvSetString( kv, "url", url );

	decl String:tempfile[256];
	GetTempFile( tempfile, sizeof(tempfile) );

	KvSetString( kv, "file", tempfile );

	new Handle:curl = SetupCurl( url, post );

	KvSetHandle( kv, "outfile", outfile );
	KvSetNum( kv, "attempt", 0 );
	KvSetHandle( kv, "post", post );
	KvSetNum( kv, "userdata", data );
	KvSetNum( kv, "on_complete", _:on_complete );

	curl_easy_perform_thread( curl, OnCURLTransferComplete, kv );
}

//-------------------------------------------------------------------------------------------------
CURLRetryTransfer( Handle:kv ) {
	decl String:url[512];
	KvGetString( kv, "url", url, sizeof url );
	decl String:tempfile[256];
	KvGetString( kv, "file", tempfile, sizeof tempfile );
	new Handle:post = Handle:KvGetNum( kv, "post" );
	//
	new Handle:curl = SetupCurl( url, post );

	KvSetHandle( kv, "outfile", outfile );
	curl_easy_perform_thread( curl, OnCURLTransferComplete, kv );
}

//-------------------------------------------------------------------------------------------------
Handle:CURLBuildPost( Handle:data ) {
	ResetPack(data);
	decl String:postname[128];
	decl String:postdata[512];

	new Handle:post = curl_httppost();

	new index = 0;
	while( IsPackReadable(data,1) ) {
		ReadPackString( data, postname, sizeof postname );
		ReadPackString( data, postdata, sizeof postdata );
		curl_formadd( post, CURLFORM_COPYNAME, postname, CURLFORM_COPYCONTENTS, postdata, CURLFORM_END );
		index++;
	}

	return post;
}

//-------------------------------------------------------------------------------------------------
bool:CURLDeletePostPack( Handle:kv ) {
	new Handle:post = KvGetHandle( kv, "post" );
	if( post != INVALID_HANDLE ) {
		CloseHandle(post);
		KvSetHandle( kv, "post", INVALID_HANDLE );
		return true;
	}
	return false;
}

//-------------------------------------------------------------------------------------------------
public OnCURLTransferComplete( Handle:hndl, CURLcode:code, any:kv ) {

	CloseHandle( KvGetHandle( kv, "outfile" ) );

	const HTTP_RESPONSE_OK = 200;

	new response;
	curl_easy_getinfo_int( hndl, CURLINFO_RESPONSE_CODE, response );
	CloseHandle(hndl);
	if( code != CURLE_OK || response != HTTP_RESPONSE_OK  ) {

		// retry if not 404 and not too many attempts
		new attempt = KvGetNum( kv, "attempt" );
		attempt++;
		if( attempt >= TRANSFER_ATTEMPTS || response == 404 ) {
			if( response == 404 ) {
				KvSetNum( kv, "notfound", 1 );
			}
			decl String:file[128];
			KvGetString( kv, "file", file, sizeof file );
			TryDeleteFile( file );

			Call_StartFunction( INVALID_HANDLE, Function:KvGetNum( kv, "on_complete" ) );
			Call_PushCell( kv );
			Call_PushCell( false );
			Call_PushCell( KvGetNum( kv, "userdata" ) );
			Call_Finish();
			CURLDeletePostPack(kv);
			CloseHandle(kv);

			return;
		}

		// retry
		KvSetNum( kv, "attempt", attempt );
		CURLRetryTransfer( kv );
		return;

	} else {
		Call_StartFunction( INVALID_HANDLE, Function:KvGetNum( kv, "on_complete" ) );
		Call_PushCell( kv );
		Call_PushCell( true );
		Call_PushCell( KvGetNum( kv, "userdata" ) );
		Call_Finish();

		decl String:file[128];
		KvGetString( kv, "file", file, sizeof file );
		TryDeleteFile( file );

		CURLDeletePostPack(kv);
		CloseHandle(kv);

	}
}


Delete ins_killnotice.sp

Delete ins_killnotice.sp

No longer required, fix applied by developers

/**
 * 0.3 = Add SQL. Death = Hook post.
 * 0.2 = Fixed removing unconnected players from array
 * 0.1a = Added test for suicides
*/

#include <sourcemod>

new Handle:g_knPlayers;
new Handle:g_knSQLPlayers;
new Handle:hDatabase = INVALID_HANDLE;

public Plugin myinfo =
{
        name = "[INS] Kill Notice",
        author = "GiZZoR",
        description = "Basic kill messages",
        version = "0.3",
        url = "https://github.com/GiZZoR/ins-sm-plugins"
};

public void OnPluginStart()
{
        AddCommandListener(kn_block_commands, "say");
        AddCommandListener(kn_block_commands, "say_team");
        HookEvent("player_death", Event_PlayerDeath, EventHookMode_Post);
        HookEvent("player_team", Event_PlayerConnect, EventHookMode_Post);
        g_knPlayers = CreateArray(32);
        g_knSQLPlayers = CreateArray(32);
        StartSQL();
}

public void OnMapStart()
{
        ClearArray(g_knPlayers);
        ClearArray(g_knSQLPlayers);
}

public Action:kn_block_commands(client, const String:command[], args)
{
        bool Active;
        Active = false;
        char name[MAX_NAME_LENGTH];
        char messagetext[32];
        GetClientName(client, name, sizeof(name));
        char message[64];
        GetCmdArg(1, message, sizeof(message));
        if (strcmp(message,"!on",false) == 0) {
                Active = true;
                bool KNAdd;
                KNAdd = AddPlayer(client);
                if (KNAdd == true) {
                                messagetext = "Kill Messages: Enabled";
                } else {
                                messagetext = "Kill Messages: Already Enabled";
                }
        }
        if (strcmp(message,"!off",false) == 0) {
                Active = true;
                bool KNRemove;
                KNRemove = RemovePlayer(client);
                if (KNRemove == true) {
                                messagetext = "Kill Messages: Disabled";
                } else {
                                messagetext = "Kill Messages: Already Disabled";
                }
        }
        if (Active == true) {
                PrintToChat(client,messagetext);
        }
        return Plugin_Continue;
}

bool AddPlayer(player)
{
        if(FindValueInArray(g_knPlayers, player) != -1) {
                return false;
        } else {
                PushArrayCell(g_knPlayers,player);
                char SteamID[64];
                GetClientAuthId(player, AuthId_Steam2, SteamID, sizeof(SteamID));
                new String:query[1024];
                if(FindValueInArray(g_knSQLPlayers, player) == -1) {
                        Format(query, sizeof(query), "INSERT INTO users (steamid, enabled) VALUS ('%s',true)",SteamID);
                } else {
                        Format(query, sizeof(query), "UPDATE users SET enabled = true WHERE steamid = '%s'",SteamID);
                }
                SQL_FastQuery(hDatabase, query);
                return true;
        }
}

bool RemovePlayer(player)
{
        int ArrayPos;
        ArrayPos = FindValueInArray(g_knPlayers, player);
        if(ArrayPos != -1) {
                RemoveFromArray(g_knPlayers,ArrayPos);
                char SteamID[64];
                GetClientAuthId(player, AuthId_Steam2, SteamID, sizeof(SteamID));
                new String:query[1024];
                Format(query, sizeof(query), "UPDATE users SET enabled = false WHERE steamid = '%s'",SteamID);
                return true;
        } else {
                return false;
        }
}

void IsPlayerEnabledInDb(player)
{
        char SteamID[64];
        GetClientAuthId(player, AuthId_Steam2, SteamID, sizeof(SteamID));
        new String:query[1024];
        Format(query, sizeof(query), "SELECT '%i' AS client, enabled FROM users WHERE steamid = '%s'",player,SteamID);
        SQL_TQuery(hDatabase, SQL_CheckCallback, query);
}

public SQL_CheckCallback(Handle:owner, Handle:hndl, const String:error[], any:data)
{
        if(SQL_GetRowCount(hndl) == 1)
        {
                if (SQL_FetchRow(hndl))
                {
                        new client = SQL_FetchInt(hndl,0);
                        new enabled = SQL_FetchInt(hndl,1);
                        if (enabled == 1) AddPlayer(client);
                        PushArrayCell(g_knSQLPlayers,client);
                }
        }
}

public Action:Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast)
{
        new attacker = GetClientOfUserId(GetEventInt(event, "attacker"));
        new victim = GetClientOfUserId(GetEventInt(event, "userid"));
        new String:attnick[32];
        new String:vicnick[32];
        new String: weapon[64];
        GetClientName(attacker,attnick,sizeof(attnick));
        GetClientName(victim,vicnick,sizeof(vicnick));
        GetEventString(event, "weapon", weapon, sizeof(weapon));
        int recipient;
        for(new i=0; i < GetArraySize(g_knPlayers); i++)
        {
                recipient = GetArrayCell(g_knPlayers,i);
                if(IsClientInGame(recipient)) {
                        if (victim == attacker) {
                                PrintToChat(recipient,"%s commited suicide with %s",attnick,weapon);
                        } else {
                                PrintToChat(recipient,"%s killed %s with %s",attnick,vicnick,weapon);
                        }
                } else {
                        RemovePlayer(recipient);
                }
        }
        return Plugin_Continue;
}

public Action:Event_PlayerConnect(Handle:event, const String:name[], bool:dontBroadcast) {
        new client = GetClientOfUserId(GetEventInt(event, "userid"));
        if (client == 0) return Plugin_Continue;
        char SteamID[64];
        GetClientAuthId(client, AuthId_Steam2, SteamID, sizeof(SteamID));
        if (StrEqual(SteamID,"BOT",false) == false) {
                IsPlayerEnabledInDb(client);
        }
        return Plugin_Continue;
}

public StartSQL()
{
    SQL_TConnect(GotDatabase,"killnotice");
}