Initial commit
This commit is contained in:
524
scripting/tf2items_manager.sp
Normal file
524
scripting/tf2items_manager.sp
Normal file
@@ -0,0 +1,524 @@
|
||||
#pragma semicolon 1 // Force strict semicolon mode.
|
||||
|
||||
// ====[ INCLUDES ]====================================================
|
||||
#include <sourcemod>
|
||||
#define REQUIRE_EXTENSIONS
|
||||
#include <tf2items>
|
||||
|
||||
// ====[ CONSTANTS ]===================================================
|
||||
#define PLUGIN_NAME "[TF2Items] Manager"
|
||||
#define PLUGIN_AUTHOR "Damizean & Asherkin"
|
||||
#define PLUGIN_VERSION "1.4.3"
|
||||
#define PLUGIN_CONTACT "http://limetech.org/"
|
||||
|
||||
#define ARRAY_SIZE 2
|
||||
#define ARRAY_ITEM 0
|
||||
#define ARRAY_FLAGS 1
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
// ====[ VARIABLES ]===================================================
|
||||
new Handle:g_hPlayerInfo;
|
||||
new Handle:g_hPlayerArray;
|
||||
new Handle:g_hGlobalSettings;
|
||||
new Handle:g_hCvarEnabled;
|
||||
new bool:g_bPlayerEnabled[MAXPLAYERS + 1] = { true, ... };
|
||||
new Handle:g_hCvarPlayerControlEnabled;
|
||||
|
||||
// ====[ PLUGIN ]======================================================
|
||||
public Plugin:myinfo =
|
||||
{
|
||||
name = PLUGIN_NAME,
|
||||
author = PLUGIN_AUTHOR,
|
||||
description = PLUGIN_NAME,
|
||||
version = PLUGIN_VERSION,
|
||||
url = PLUGIN_CONTACT
|
||||
};
|
||||
|
||||
// ====[ FUNCTIONS ]===================================================
|
||||
|
||||
/* OnPluginStart()
|
||||
*
|
||||
* When the plugin starts up.
|
||||
* -------------------------------------------------------------------------- */
|
||||
public OnPluginStart()
|
||||
{
|
||||
// Create convars
|
||||
CreateConVar("tf2items_manager_version", PLUGIN_VERSION, PLUGIN_NAME, FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY);
|
||||
g_hCvarEnabled = CreateConVar("tf2items_manager", "1", "Enables/disables the manager (0 - Disabled / 1 - Enabled", FCVAR_REPLICATED|FCVAR_NOTIFY);
|
||||
g_hCvarPlayerControlEnabled = CreateConVar("tf2items_manager_playercontrol", "1", "Enables/disables the player's ability to control the manager (0 - Disabled / 1 - Enabled");
|
||||
|
||||
// Register console commands
|
||||
RegAdminCmd("tf2items_manager_reload", CmdReload, ADMFLAG_GENERIC);
|
||||
|
||||
RegConsoleCmd("tf2items_enable", CmdEnable);
|
||||
RegConsoleCmd("tf2items_disable", CmdDisable);
|
||||
|
||||
// Parse the items list
|
||||
ParseItems();
|
||||
}
|
||||
|
||||
/* TF2Items_OnGiveNamedItem()
|
||||
*
|
||||
* When an item is about to be given to a client.
|
||||
* -------------------------------------------------------------------------- */
|
||||
public Action:TF2Items_OnGiveNamedItem(iClient, String:strClassName[], iItemDefinitionIndex, &Handle:hItemOverride)
|
||||
{
|
||||
// If disabled, use the default values.
|
||||
if (!GetConVarBool(g_hCvarEnabled) || (GetConVarBool(g_hCvarPlayerControlEnabled) && !g_bPlayerEnabled[iClient]))
|
||||
return Plugin_Continue;
|
||||
|
||||
// If another plugin already tryied to override the item, let him go ahead.
|
||||
if (hItemOverride != INVALID_HANDLE)
|
||||
return Plugin_Continue; // Plugin_Changed
|
||||
|
||||
// Find item. If any is found, override the attributes with these.
|
||||
new Handle:hItem = FindItem(iClient, iItemDefinitionIndex);
|
||||
if (hItem != INVALID_HANDLE)
|
||||
{
|
||||
hItemOverride = hItem;
|
||||
return Plugin_Changed;
|
||||
}
|
||||
|
||||
// None found, use default values.
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
// Fuck it, only one is needed.
|
||||
// Doing this for just-in-casenesses sake
|
||||
|
||||
public OnClientConnected(client)
|
||||
{
|
||||
g_bPlayerEnabled[client] = true;
|
||||
}
|
||||
|
||||
public OnClientDisconnect(client)
|
||||
{
|
||||
g_bPlayerEnabled[client] = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------
|
||||
* ______ __
|
||||
* / ____/___ ____ ___ ____ ___ ____ _____ ____/ /____
|
||||
* / / / __ \/ __ `__ \/ __ `__ \/ __ `/ __ \/ __ / ___/
|
||||
* / /___/ /_/ / / / / / / / / / / / /_/ / / / / /_/ (__ )
|
||||
* \____/\____/_/ /_/ /_/_/ /_/ /_/\__,_/_/ /_/\__,_/____/
|
||||
* ------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* CmdReload()
|
||||
**
|
||||
** Reloads the item list.
|
||||
** -------------------------------------------------------------------------- */
|
||||
public Action:CmdReload(iClient, iAction)
|
||||
{
|
||||
// Fire a message telling about the operation.
|
||||
if (iClient)
|
||||
ReplyToCommand(iClient, "Reloading items list");
|
||||
else
|
||||
LogMessage("Reloading items list");
|
||||
|
||||
// Call the ParseItems function.
|
||||
ParseItems();
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action:CmdEnable(iClient, iAction)
|
||||
{
|
||||
if (!GetConVarBool(g_hCvarPlayerControlEnabled))
|
||||
{
|
||||
ReplyToCommand(iClient, "The server administrator has disabled this command.");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
ReplyToCommand(iClient, "Re-enabling TF2Items for you.");
|
||||
g_bPlayerEnabled[iClient] = true;
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action:CmdDisable(iClient, iAction)
|
||||
{
|
||||
if (!GetConVarBool(g_hCvarPlayerControlEnabled))
|
||||
{
|
||||
ReplyToCommand(iClient, "The server administrator has disabled this command.");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
ReplyToCommand(iClient, "Disabling TF2Items for you.");
|
||||
g_bPlayerEnabled[iClient] = false;
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------
|
||||
* __ ___ __
|
||||
* / |/ /___ _____ ____ _____ ____ ____ ___ ___ ____ / /_
|
||||
* / /|_/ / __ `/ __ \/ __ `/ __ `/ _ \/ __ `__ \/ _ \/ __ \/ __/
|
||||
* / / / / /_/ / / / / /_/ / /_/ / __/ / / / / / __/ / / / /_
|
||||
* /_/ /_/\__,_/_/ /_/\__,_/\__, /\___/_/ /_/ /_/\___/_/ /_/\__/
|
||||
* /____/
|
||||
* ------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* FindItem()
|
||||
**
|
||||
** Tryies to find a custom item usable by the client.
|
||||
** -------------------------------------------------------------------------- */
|
||||
Handle:FindItem(iClient, iItemDefinitionIndex)
|
||||
{
|
||||
// Check if the player is valid
|
||||
if (!IsValidClient(iClient))
|
||||
return INVALID_HANDLE;
|
||||
|
||||
// Retrieve the STEAM auth string
|
||||
new String:strAuth[64];
|
||||
GetClientAuthString(iClient, strAuth, sizeof(strAuth));
|
||||
|
||||
// Check if it's on the list. If not, try with the global settings.
|
||||
new Handle:hItemArray = INVALID_HANDLE;
|
||||
GetTrieValue(g_hPlayerInfo, strAuth, hItemArray);
|
||||
|
||||
// Check for each.
|
||||
new Handle:hOutput;
|
||||
hOutput = FindItemOnArray(iClient, hItemArray, iItemDefinitionIndex);
|
||||
if (hOutput == INVALID_HANDLE)
|
||||
hOutput = FindItemOnArray(iClient, g_hGlobalSettings, iItemDefinitionIndex);
|
||||
|
||||
// Done
|
||||
return hOutput;
|
||||
}
|
||||
|
||||
/* FindItemOnArray()
|
||||
**
|
||||
**
|
||||
** -------------------------------------------------------------------------- */
|
||||
Handle:FindItemOnArray(iClient, Handle:hArray, iItemDefinitionIndex)
|
||||
{
|
||||
// Check if the array is valid.
|
||||
if (hArray == INVALID_HANDLE)
|
||||
return INVALID_HANDLE;
|
||||
|
||||
new Handle:hWildcardItem = INVALID_HANDLE;
|
||||
|
||||
// Iterate through each item entry and close the handle.
|
||||
for (new iItem = 0; iItem < GetArraySize(hArray); iItem++)
|
||||
{
|
||||
// Retrieve item
|
||||
new Handle:hItem = GetArrayCell(hArray, iItem, ARRAY_ITEM);
|
||||
new iItemFlags = GetArrayCell(hArray, iItem, ARRAY_FLAGS);
|
||||
if (hItem == INVALID_HANDLE)
|
||||
continue;
|
||||
|
||||
// Is a wildcard item? If so, store it.
|
||||
if (TF2Items_GetItemIndex(hItem) == -1 && hWildcardItem == INVALID_HANDLE)
|
||||
if (CheckItemUsage(iClient, iItemFlags))
|
||||
hWildcardItem = hItem;
|
||||
|
||||
// Is the item we're looking for? If so return item, but first
|
||||
// check if it's possible due to the
|
||||
if (TF2Items_GetItemIndex(hItem) == iItemDefinitionIndex)
|
||||
if (CheckItemUsage(iClient, iItemFlags))
|
||||
return hItem;
|
||||
}
|
||||
|
||||
// Done, returns wildcard item if it exists.
|
||||
return hWildcardItem;
|
||||
}
|
||||
|
||||
/* CheckItemUsage()
|
||||
*
|
||||
* Checks if a client has any of the specified flags.
|
||||
* -------------------------------------------------------------------------- */
|
||||
bool:CheckItemUsage(iClient, iFlags)
|
||||
{
|
||||
if (iFlags == 0)
|
||||
return true;
|
||||
|
||||
new iClientFlags = GetUserFlagBits(iClient);
|
||||
if (iClientFlags & ADMFLAG_ROOT)
|
||||
return true;
|
||||
else
|
||||
return (iClientFlags & iFlags) != 0;
|
||||
}
|
||||
|
||||
/* ParseItems()
|
||||
*
|
||||
* Reads up the items information from the Key-Values.
|
||||
* -------------------------------------------------------------------------- */
|
||||
ParseItems()
|
||||
{
|
||||
decl String:strBuffer[256];
|
||||
decl String:strSplit[16][64];
|
||||
|
||||
// Destroy the current items data.
|
||||
DestroyItems();
|
||||
|
||||
// Create key values object and parse file.
|
||||
BuildPath(Path_SM, strBuffer, sizeof(strBuffer), "configs/tf2items.weapons.txt");
|
||||
new Handle:hKeyValues = CreateKeyValues("TF2Items");
|
||||
if (FileToKeyValues(hKeyValues, strBuffer) == false)
|
||||
SetFailState("Error, can't read file containing the item list : %s", strBuffer);
|
||||
|
||||
// Check the version
|
||||
KvGetSectionName(hKeyValues, strBuffer, sizeof(strBuffer));
|
||||
if (StrEqual("custom_weapons_v3", strBuffer) == false)
|
||||
SetFailState("tf2items.weapons.txt structure corrupt or incorrect version: \"%s\"", strBuffer);
|
||||
|
||||
// Create the array and trie to store & access the item information.
|
||||
g_hPlayerArray = CreateArray();
|
||||
g_hPlayerInfo = CreateTrie();
|
||||
|
||||
#if defined DEBUG
|
||||
LogMessage("Parsing items");
|
||||
LogMessage("{");
|
||||
#endif
|
||||
|
||||
// Jump into the first subkey and go on.
|
||||
if (KvGotoFirstSubKey(hKeyValues))
|
||||
{
|
||||
do
|
||||
{
|
||||
// Retrieve player information and split into multiple strings.
|
||||
KvGetSectionName(hKeyValues, strBuffer, sizeof(strBuffer));
|
||||
new iNumAuths = ExplodeString(strBuffer, ";", strSplit, 16, 64);
|
||||
|
||||
// Create new array entry and upload to the array.
|
||||
new Handle:hEntry = CreateArray(2);
|
||||
PushArrayCell(g_hPlayerArray, hEntry);
|
||||
|
||||
#if defined DEBUG
|
||||
LogMessage(" Entry", strBuffer);
|
||||
LogMessage(" {");
|
||||
LogMessage(" Used by:");
|
||||
#endif
|
||||
|
||||
// Iterate through each player auth strings and make an
|
||||
// entry for each.
|
||||
for (new iAuth = 0; iAuth < iNumAuths; iAuth++)
|
||||
{
|
||||
TrimString(strSplit[iAuth]);
|
||||
SetTrieValue(g_hPlayerInfo, strSplit[iAuth], hEntry);
|
||||
|
||||
#if defined DEBUG
|
||||
LogMessage(" \"%s\"", strSplit[iAuth]);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined DEBUG
|
||||
LogMessage("");
|
||||
#endif
|
||||
|
||||
// Read all the item entries
|
||||
ParseItemsEntry(hKeyValues, hEntry);
|
||||
|
||||
#if defined DEBUG
|
||||
LogMessage(" }");
|
||||
#endif
|
||||
}
|
||||
while (KvGotoNextKey(hKeyValues));
|
||||
KvGoBack(hKeyValues);
|
||||
}
|
||||
|
||||
// Close key values
|
||||
CloseHandle(hKeyValues);
|
||||
|
||||
// Try to find the global item settings.
|
||||
GetTrieValue(g_hPlayerInfo, "*", g_hGlobalSettings);
|
||||
|
||||
// Done.
|
||||
#if defined DEBUG
|
||||
LogMessage("}");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ParseItemsEntry()
|
||||
*
|
||||
* Reads up a particular items entry.
|
||||
* -------------------------------------------------------------------------- */
|
||||
ParseItemsEntry(Handle:hKeyValues, Handle:hEntry)
|
||||
{
|
||||
decl String:strBuffer[64];
|
||||
decl String:strBuffer2[64];
|
||||
decl String:strSplit[2][64];
|
||||
|
||||
// Jump into the first subkey.
|
||||
if (KvGotoFirstSubKey(hKeyValues))
|
||||
{
|
||||
do
|
||||
{
|
||||
new Handle:hItem = TF2Items_CreateItem(OVERRIDE_ALL);
|
||||
new iItemFlags = 0;
|
||||
|
||||
// Retrieve item definition index and store.
|
||||
KvGetSectionName(hKeyValues, strBuffer, sizeof(strBuffer));
|
||||
if (strBuffer[0] == '*')
|
||||
TF2Items_SetItemIndex(hItem, -1);
|
||||
else
|
||||
TF2Items_SetItemIndex(hItem, StringToInt(strBuffer));
|
||||
|
||||
#if defined DEBUG
|
||||
LogMessage(" Item: %i", TF2Items_GetItemIndex(hItem));
|
||||
LogMessage(" {");
|
||||
#endif
|
||||
|
||||
// Retrieve entity level
|
||||
new iLevel = KvGetNum(hKeyValues, "level", -1);
|
||||
if (iLevel != -1)
|
||||
{
|
||||
TF2Items_SetLevel(hItem, iLevel);
|
||||
iItemFlags |= OVERRIDE_ITEM_LEVEL;
|
||||
}
|
||||
|
||||
#if defined DEBUG
|
||||
if (iItemFlags & OVERRIDE_ITEM_LEVEL)
|
||||
LogMessage(" Level: %i", TF2Items_GetLevel(hItem));
|
||||
#endif
|
||||
|
||||
// Retrieve entity quality
|
||||
new iQuality = KvGetNum(hKeyValues, "quality", -1);
|
||||
if (iQuality != -1)
|
||||
{
|
||||
TF2Items_SetQuality(hItem, iQuality);
|
||||
iItemFlags |= OVERRIDE_ITEM_QUALITY;
|
||||
}
|
||||
|
||||
#if defined DEBUG
|
||||
if (iItemFlags & OVERRIDE_ITEM_QUALITY)
|
||||
LogMessage(" Quality: %i", TF2Items_GetQuality(hItem));
|
||||
#endif
|
||||
|
||||
// Check for attribute preservation key
|
||||
new iPreserve = KvGetNum(hKeyValues, "preserve-attributes", -1);
|
||||
if (iPreserve == 1)
|
||||
{
|
||||
iItemFlags |= PRESERVE_ATTRIBUTES;
|
||||
} else {
|
||||
iPreserve = KvGetNum(hKeyValues, "preserve_attributes", -1);
|
||||
if (iPreserve == 1)
|
||||
iItemFlags |= PRESERVE_ATTRIBUTES;
|
||||
}
|
||||
|
||||
#if defined DEBUG
|
||||
LogMessage(" Preserve Attributes: %s", (iItemFlags & PRESERVE_ATTRIBUTES)?"true":"false");
|
||||
#endif
|
||||
|
||||
// Read all the attributes
|
||||
new iAttributeCount = 0;
|
||||
for (;;)
|
||||
{
|
||||
// Format the attribute entry name
|
||||
Format(strBuffer, sizeof(strBuffer), "%i", iAttributeCount+1);
|
||||
|
||||
// Try to read the attribute
|
||||
KvGetString(hKeyValues, strBuffer, strBuffer2, sizeof(strBuffer2));
|
||||
|
||||
// If not found, break.
|
||||
if (strBuffer2[0] == '\0') break;
|
||||
|
||||
// Split the information in two buffers
|
||||
ExplodeString(strBuffer2, ";", strSplit, 2, 64);
|
||||
new iAttributeIndex = StringToInt(strSplit[0]);
|
||||
new Float:fAttributeValue = StringToFloat(strSplit[1]);
|
||||
|
||||
// Attribute found, set information.
|
||||
TF2Items_SetAttribute(hItem, iAttributeCount, iAttributeIndex, fAttributeValue);
|
||||
|
||||
#if defined DEBUG
|
||||
LogMessage(" Attribute[%i] : %i / %f",
|
||||
iAttributeCount,
|
||||
TF2Items_GetAttributeId(hItem, iAttributeCount),
|
||||
TF2Items_GetAttributeValue(hItem, iAttributeCount)
|
||||
);
|
||||
#endif
|
||||
|
||||
// Increase attribute count and continue.
|
||||
iAttributeCount++;
|
||||
}
|
||||
|
||||
// Done, set attribute count and upload.
|
||||
if (iAttributeCount != 0)
|
||||
{
|
||||
TF2Items_SetNumAttributes(hItem, iAttributeCount);
|
||||
iItemFlags |= OVERRIDE_ATTRIBUTES;
|
||||
}
|
||||
|
||||
// Retrieve the admin flags
|
||||
KvGetString(hKeyValues, "admin-flags", strBuffer, sizeof(strBuffer), "");
|
||||
new iFlags = ReadFlagString(strBuffer);
|
||||
|
||||
// Set flags and upload.
|
||||
TF2Items_SetFlags(hItem, iItemFlags);
|
||||
PushArrayCell(hEntry, 0);
|
||||
SetArrayCell(hEntry, GetArraySize(hEntry)-1, hItem, ARRAY_ITEM);
|
||||
SetArrayCell(hEntry, GetArraySize(hEntry)-1, iFlags, ARRAY_FLAGS);
|
||||
|
||||
#if defined DEBUG
|
||||
LogMessage(" Flags: %05b", TF2Items_GetFlags(hItem));
|
||||
LogMessage(" Admin: %s", ((iFlags == 0)? "(none)":strBuffer));
|
||||
LogMessage(" }");
|
||||
#endif
|
||||
}
|
||||
while (KvGotoNextKey(hKeyValues));
|
||||
KvGoBack(hKeyValues);
|
||||
}
|
||||
}
|
||||
|
||||
/* DestroyItems()
|
||||
*
|
||||
* Destroys the current list for items.
|
||||
* -------------------------------------------------------------------------- */
|
||||
DestroyItems()
|
||||
{
|
||||
if (g_hPlayerArray != INVALID_HANDLE)
|
||||
{
|
||||
// Iterate through each player and retrieve the internal
|
||||
// weapon list.
|
||||
for (new iEntry = 0; iEntry < GetArraySize(g_hPlayerArray); iEntry++)
|
||||
{
|
||||
// Retrieve the item array.
|
||||
new Handle:hItemArray = GetArrayCell(g_hPlayerArray, iEntry);
|
||||
if (hItemArray == INVALID_HANDLE)
|
||||
continue;
|
||||
|
||||
// Iterate through each item entry and close the handle.
|
||||
for (new iItem = 0; iItem < GetArraySize(hItemArray); iItem++)
|
||||
{
|
||||
// Retrieve item
|
||||
new Handle:hItem = GetArrayCell(hItemArray, iItem);
|
||||
if (hItem == INVALID_HANDLE)
|
||||
continue;
|
||||
|
||||
// Close handle
|
||||
CloseHandle(hItem);
|
||||
}
|
||||
}
|
||||
|
||||
// Done, free array
|
||||
CloseHandle(g_hPlayerArray);
|
||||
}
|
||||
|
||||
// Free player trie
|
||||
if (g_hPlayerInfo != INVALID_HANDLE)
|
||||
{
|
||||
CloseHandle(g_hPlayerInfo);
|
||||
}
|
||||
|
||||
// Done
|
||||
g_hPlayerInfo = INVALID_HANDLE;
|
||||
g_hPlayerArray = INVALID_HANDLE;
|
||||
g_hGlobalSettings = INVALID_HANDLE;
|
||||
}
|
||||
|
||||
/* IsValidClient()
|
||||
*
|
||||
* Checks if a client is valid.
|
||||
* -------------------------------------------------------------------------- */
|
||||
bool:IsValidClient(iClient)
|
||||
{
|
||||
if (iClient < 1 || iClient > MaxClients)
|
||||
return false;
|
||||
if (!IsClientConnected(iClient))
|
||||
return false;
|
||||
return IsClientInGame(iClient);
|
||||
}
|
Reference in New Issue
Block a user