merged in selected changesets from 1.1 branch
--HG-- branch : sourcemod-1.0.x extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/branches/sourcemod-1.0.x%401990
This commit is contained in:
+18
-5
@@ -45,6 +45,8 @@ public Plugin:myinfo =
|
||||
url = "http://www.sourcemod.net/"
|
||||
};
|
||||
|
||||
new g_maxPlayers;
|
||||
|
||||
/* Forwards */
|
||||
new Handle:hOnAdminMenuReady = INVALID_HANDLE;
|
||||
new Handle:hOnAdminMenuCreated = INVALID_HANDLE;
|
||||
@@ -57,6 +59,8 @@ new TopMenuObject:obj_playercmds = INVALID_TOPMENUOBJECT;
|
||||
new TopMenuObject:obj_servercmds = INVALID_TOPMENUOBJECT;
|
||||
new TopMenuObject:obj_votingcmds = INVALID_TOPMENUOBJECT;
|
||||
|
||||
#include "adminmenu/dynamicmenu.sp"
|
||||
|
||||
public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max)
|
||||
{
|
||||
CreateNative("GetAdminTopMenu", __GetAdminTopMenu);
|
||||
@@ -91,27 +95,36 @@ public OnConfigsExecuted()
|
||||
}
|
||||
}
|
||||
|
||||
public OnMapStart()
|
||||
{
|
||||
g_maxPlayers = GetMaxClients();
|
||||
|
||||
ParseConfigs();
|
||||
}
|
||||
|
||||
public OnAllPluginsLoaded()
|
||||
{
|
||||
hAdminMenu = CreateTopMenu(CategoryHandler);
|
||||
hAdminMenu = CreateTopMenu(DefaultCategoryHandler);
|
||||
|
||||
obj_playercmds = AddToTopMenu(hAdminMenu,
|
||||
"PlayerCommands",
|
||||
TopMenuObject_Category,
|
||||
CategoryHandler,
|
||||
DefaultCategoryHandler,
|
||||
INVALID_TOPMENUOBJECT);
|
||||
|
||||
obj_servercmds = AddToTopMenu(hAdminMenu,
|
||||
"ServerCommands",
|
||||
TopMenuObject_Category,
|
||||
CategoryHandler,
|
||||
DefaultCategoryHandler,
|
||||
INVALID_TOPMENUOBJECT);
|
||||
|
||||
obj_votingcmds = AddToTopMenu(hAdminMenu,
|
||||
"VotingCommands",
|
||||
TopMenuObject_Category,
|
||||
CategoryHandler,
|
||||
DefaultCategoryHandler,
|
||||
INVALID_TOPMENUOBJECT);
|
||||
|
||||
BuildDynamicMenu();
|
||||
|
||||
Call_StartForward(hOnAdminMenuCreated);
|
||||
Call_PushCell(hAdminMenu);
|
||||
@@ -122,7 +135,7 @@ public OnAllPluginsLoaded()
|
||||
Call_Finish();
|
||||
}
|
||||
|
||||
public CategoryHandler(Handle:topmenu,
|
||||
public DefaultCategoryHandler(Handle:topmenu,
|
||||
TopMenuAction:action,
|
||||
TopMenuObject:object_id,
|
||||
param,
|
||||
|
||||
@@ -0,0 +1,623 @@
|
||||
|
||||
#define NAME_LENGTH 32
|
||||
#define CMD_LENGTH 255
|
||||
|
||||
#define ARRAY_STRING_LENGTH 32
|
||||
|
||||
enum GroupCommands
|
||||
{
|
||||
Handle:groupListName,
|
||||
Handle:groupListCommand
|
||||
};
|
||||
|
||||
new g_groupList[GroupCommands];
|
||||
new g_groupCount;
|
||||
|
||||
new Handle:g_configParser = INVALID_HANDLE;
|
||||
|
||||
enum Places
|
||||
{
|
||||
Place_Category,
|
||||
Place_Item,
|
||||
Place_ReplaceNum
|
||||
};
|
||||
|
||||
new String:g_command[MAXPLAYERS+1][CMD_LENGTH];
|
||||
new g_currentPlace[MAXPLAYERS+1][Places];
|
||||
|
||||
/**
|
||||
* What to put in the 'info' menu field (for PlayerList and Player_Team menus only)
|
||||
*/
|
||||
enum PlayerMethod
|
||||
{
|
||||
ClientId, /** Client id number ( 1 - Maxplayers) */
|
||||
UserId, /** Client userid */
|
||||
Name, /** Client Name */
|
||||
SteamId, /** Client Steamid */
|
||||
IpAddress, /** Client's Ip Address */
|
||||
UserId2 /** Userid (not prefixed with #) */
|
||||
};
|
||||
|
||||
enum ExecuteType
|
||||
{
|
||||
Execute_Player,
|
||||
Execute_Server
|
||||
}
|
||||
|
||||
enum SubMenu_Type
|
||||
{
|
||||
SubMenu_Group,
|
||||
SubMenu_GroupPlayer,
|
||||
SubMenu_Player,
|
||||
SubMenu_MapCycle,
|
||||
SubMenu_List,
|
||||
SubMenu_OnOff
|
||||
}
|
||||
|
||||
enum Item
|
||||
{
|
||||
String:Item_cmd[256],
|
||||
ExecuteType:Item_execute,
|
||||
Handle:Item_submenus
|
||||
}
|
||||
|
||||
enum Submenu
|
||||
{
|
||||
SubMenu_Type:Submenu_type,
|
||||
String:Submenu_title[32],
|
||||
PlayerMethod:Submenu_method,
|
||||
Submenu_listcount,
|
||||
Handle:Submenu_listdata
|
||||
}
|
||||
|
||||
new Handle:g_DataArray;
|
||||
|
||||
BuildDynamicMenu()
|
||||
{
|
||||
new itemInput[Item];
|
||||
g_DataArray = CreateArray(sizeof(itemInput));
|
||||
|
||||
new String:executeBuffer[32];
|
||||
|
||||
new Handle:kvMenu;
|
||||
kvMenu = CreateKeyValues("Commands");
|
||||
new String:file[256];
|
||||
BuildPath(Path_SM, file, 255, "configs/dynamicmenu/menu.ini");
|
||||
FileToKeyValues(kvMenu, file);
|
||||
|
||||
new String:name[NAME_LENGTH];
|
||||
new String:buffer[NAME_LENGTH];
|
||||
|
||||
KvSetEscapeSequences(kvMenu, true);
|
||||
|
||||
if (!KvGotoFirstSubKey(kvMenu))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
decl String:admin[30];
|
||||
|
||||
new TopMenuObject:categoryId;
|
||||
|
||||
do
|
||||
{
|
||||
KvGetSectionName(kvMenu, buffer, sizeof(buffer));
|
||||
|
||||
KvGetString(kvMenu, "admin", admin, sizeof(admin),"sm_admin");
|
||||
|
||||
if ((categoryId =FindTopMenuCategory(hAdminMenu, buffer)) == INVALID_TOPMENUOBJECT)
|
||||
{
|
||||
categoryId = AddToTopMenu(hAdminMenu,
|
||||
buffer,
|
||||
TopMenuObject_Category,
|
||||
DynamicMenuCategoryHandler,
|
||||
INVALID_TOPMENUOBJECT,
|
||||
admin,
|
||||
ADMFLAG_GENERIC,
|
||||
name);
|
||||
|
||||
}
|
||||
|
||||
if (!KvGotoFirstSubKey(kvMenu))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
KvGetSectionName(kvMenu, buffer, sizeof(buffer));
|
||||
|
||||
KvGetString(kvMenu, "admin", admin, sizeof(admin),"");
|
||||
|
||||
if (admin[0] == '\0')
|
||||
{
|
||||
//No 'admin' keyvalue was found
|
||||
//Use the first argument of the 'cmd' string instead
|
||||
|
||||
decl String:temp[64];
|
||||
KvGetString(kvMenu, "cmd", temp, sizeof(temp),"");
|
||||
|
||||
BreakString(temp, admin, sizeof(admin));
|
||||
}
|
||||
|
||||
|
||||
KvGetString(kvMenu, "cmd", itemInput[Item_cmd], sizeof(itemInput[Item_cmd]));
|
||||
KvGetString(kvMenu, "execute", executeBuffer, sizeof(executeBuffer));
|
||||
|
||||
if (StrEqual(executeBuffer, "server"))
|
||||
{
|
||||
itemInput[Item_execute] = Execute_Server;
|
||||
}
|
||||
else //assume player type execute
|
||||
{
|
||||
itemInput[Item_execute] = Execute_Player;
|
||||
}
|
||||
|
||||
/* iterate all submenus and load data into itemInput[Item_submenus] (adt array handle) */
|
||||
|
||||
new count = 1;
|
||||
decl String:countBuffer[10] = "1";
|
||||
|
||||
decl String:inputBuffer[32];
|
||||
|
||||
while (KvJumpToKey(kvMenu, countBuffer))
|
||||
{
|
||||
new submenuInput[Submenu];
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
itemInput[Item_submenus] = CreateArray(sizeof(submenuInput));
|
||||
}
|
||||
|
||||
KvGetString(kvMenu, "type", inputBuffer, sizeof(inputBuffer));
|
||||
|
||||
if (strncmp(inputBuffer,"group",5)==0)
|
||||
{
|
||||
if (StrContains(inputBuffer, "player") != -1)
|
||||
{
|
||||
submenuInput[Submenu_type] = SubMenu_GroupPlayer;
|
||||
}
|
||||
else
|
||||
{
|
||||
submenuInput[Submenu_type] = SubMenu_Group;
|
||||
}
|
||||
}
|
||||
else if (StrEqual(inputBuffer,"mapcycle"))
|
||||
{
|
||||
submenuInput[Submenu_type] = SubMenu_MapCycle;
|
||||
|
||||
KvGetString(kvMenu, "path", inputBuffer, sizeof(inputBuffer),"mapcycle.txt");
|
||||
|
||||
submenuInput[Submenu_listdata] = CreateDataPack();
|
||||
WritePackString(submenuInput[Submenu_listdata], inputBuffer);
|
||||
ResetPack(submenuInput[Submenu_listdata]);
|
||||
}
|
||||
else if (StrContains(inputBuffer, "player") != -1)
|
||||
{
|
||||
submenuInput[Submenu_type] = SubMenu_Player;
|
||||
}
|
||||
else if (StrEqual(inputBuffer,"onoff"))
|
||||
{
|
||||
submenuInput[Submenu_type] = SubMenu_OnOff;
|
||||
}
|
||||
else //assume 'list' type
|
||||
{
|
||||
submenuInput[Submenu_type] = SubMenu_List;
|
||||
|
||||
submenuInput[Submenu_listdata] = CreateDataPack();
|
||||
|
||||
new String:temp[6];
|
||||
new String:value[64];
|
||||
new String:text[64];
|
||||
new i=1;
|
||||
new bool:more = true;
|
||||
|
||||
new listcount = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Format(temp,3,"%i",i);
|
||||
KvGetString(kvMenu, temp, value, sizeof(value), "");
|
||||
|
||||
Format(temp,5,"%i.",i);
|
||||
KvGetString(kvMenu, temp, text, sizeof(text), value);
|
||||
|
||||
Format(temp,5,"%i*",i);
|
||||
KvGetString(kvMenu, temp, admin, sizeof(admin),"");
|
||||
|
||||
if (value[0]=='\0')
|
||||
{
|
||||
more = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
listcount++;
|
||||
WritePackString(submenuInput[Submenu_listdata], value);
|
||||
WritePackString(submenuInput[Submenu_listdata], text);
|
||||
WritePackString(submenuInput[Submenu_listdata], admin);
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
} while (more);
|
||||
|
||||
ResetPack(submenuInput[Submenu_listdata]);
|
||||
submenuInput[Submenu_listcount] = listcount;
|
||||
}
|
||||
|
||||
if ((submenuInput[Submenu_type] == SubMenu_Player) || (submenuInput[Submenu_type] == SubMenu_GroupPlayer))
|
||||
{
|
||||
KvGetString(kvMenu, "method", inputBuffer, sizeof(inputBuffer));
|
||||
|
||||
if (StrEqual(inputBuffer, "clientid"))
|
||||
{
|
||||
submenuInput[Submenu_method] = ClientId;
|
||||
}
|
||||
else if (StrEqual(inputBuffer, "steamid"))
|
||||
{
|
||||
submenuInput[Submenu_method] = SteamId;
|
||||
}
|
||||
else if (StrEqual(inputBuffer, "userid2"))
|
||||
{
|
||||
submenuInput[Submenu_method] = UserId2;
|
||||
}
|
||||
else if (StrEqual(inputBuffer, "userid"))
|
||||
{
|
||||
submenuInput[Submenu_method] = UserId;
|
||||
}
|
||||
else if (StrEqual(inputBuffer, "ip"))
|
||||
{
|
||||
submenuInput[Submenu_method] = IpAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
submenuInput[Submenu_method] = Name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
KvGetString(kvMenu, "title", inputBuffer, sizeof(inputBuffer));
|
||||
strcopy(submenuInput[Submenu_title], sizeof(submenuInput[Submenu_title]), inputBuffer);
|
||||
|
||||
count++;
|
||||
Format(countBuffer, sizeof(countBuffer), "%i", count);
|
||||
|
||||
PushArrayArray(itemInput[Item_submenus], submenuInput[0]);
|
||||
|
||||
KvGoBack(kvMenu);
|
||||
}
|
||||
|
||||
/* Save this entire item into the global items array and add it to the menu */
|
||||
|
||||
new location = PushArrayArray(g_DataArray, itemInput[0]);
|
||||
|
||||
decl String:locString[10];
|
||||
IntToString(location, locString, sizeof(locString));
|
||||
|
||||
AddToTopMenu(hAdminMenu,
|
||||
buffer,
|
||||
TopMenuObject_Item,
|
||||
DynamicMenuItemHandler,
|
||||
categoryId,
|
||||
admin,
|
||||
ADMFLAG_GENERIC,
|
||||
locString);
|
||||
|
||||
} while (KvGotoNextKey(kvMenu));
|
||||
|
||||
KvGoBack(kvMenu);
|
||||
|
||||
} while (KvGotoNextKey(kvMenu));
|
||||
|
||||
CloseHandle(kvMenu);
|
||||
}
|
||||
|
||||
ParseConfigs()
|
||||
{
|
||||
if (g_configParser == INVALID_HANDLE)
|
||||
{
|
||||
g_configParser = SMC_CreateParser();
|
||||
}
|
||||
|
||||
SMC_SetReaders(g_configParser, NewSection, KeyValue, EndSection);
|
||||
|
||||
if (g_groupList[groupListName] != INVALID_HANDLE)
|
||||
{
|
||||
CloseHandle(g_groupList[groupListName]);
|
||||
}
|
||||
|
||||
if (g_groupList[groupListCommand] != INVALID_HANDLE)
|
||||
{
|
||||
CloseHandle(g_groupList[groupListCommand]);
|
||||
}
|
||||
|
||||
g_groupList[groupListName] = CreateArray(ARRAY_STRING_LENGTH);
|
||||
g_groupList[groupListCommand] = CreateArray(ARRAY_STRING_LENGTH);
|
||||
|
||||
decl String:configPath[256];
|
||||
BuildPath(Path_SM, configPath, sizeof(configPath), "configs/dynamicmenu/adminmenu_grouping.txt");
|
||||
|
||||
if (!FileExists(configPath))
|
||||
{
|
||||
LogError("Unable to locate admin menu groups file, no groups loaded.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
new line;
|
||||
new SMCError:err = SMC_ParseFile(g_configParser, configPath, line);
|
||||
if (err != SMCError_Okay)
|
||||
{
|
||||
decl String:error[256];
|
||||
SMC_GetErrorString(err, error, sizeof(error));
|
||||
LogError("Could not parse file (line %d, file \"%s\"):", line, configPath);
|
||||
LogError("Parser encountered error: %s", error);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public SMCResult:NewSection(Handle:smc, const String:name[], bool:opt_quotes)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SMCResult:KeyValue(Handle:smc, const String:key[], const String:value[], bool:key_quotes, bool:value_quotes)
|
||||
{
|
||||
PushArrayString(g_groupList[groupListName], key);
|
||||
PushArrayString(g_groupList[groupListCommand], value);
|
||||
}
|
||||
|
||||
public SMCResult:EndSection(Handle:smc)
|
||||
{
|
||||
g_groupCount = GetArraySize(g_groupList[groupListName]);
|
||||
}
|
||||
|
||||
public DynamicMenuCategoryHandler(Handle:topmenu,
|
||||
TopMenuAction:action,
|
||||
TopMenuObject:object_id,
|
||||
param,
|
||||
String:buffer[],
|
||||
maxlength)
|
||||
{
|
||||
if ((action == TopMenuAction_DisplayTitle) || (action == TopMenuAction_DisplayOption))
|
||||
{
|
||||
GetTopMenuObjName(topmenu, object_id, buffer, maxlength);
|
||||
}
|
||||
}
|
||||
|
||||
public DynamicMenuItemHandler(Handle:topmenu,
|
||||
TopMenuAction:action,
|
||||
TopMenuObject:object_id,
|
||||
param,
|
||||
String:buffer[],
|
||||
maxlength)
|
||||
{
|
||||
if (action == TopMenuAction_DisplayOption)
|
||||
{
|
||||
GetTopMenuObjName(topmenu, object_id, buffer, maxlength);
|
||||
}
|
||||
else if (action == TopMenuAction_SelectOption)
|
||||
{
|
||||
new String:locString[10];
|
||||
GetTopMenuInfoString(topmenu, object_id, locString, sizeof(locString));
|
||||
|
||||
new location = StringToInt(locString);
|
||||
|
||||
new output[Item];
|
||||
GetArrayArray(g_DataArray, location, output[0]);
|
||||
|
||||
strcopy(g_command[param], sizeof(g_command[]), output[Item_cmd]);
|
||||
|
||||
g_currentPlace[param][Place_Item] = location;
|
||||
|
||||
ParamCheck(param);
|
||||
}
|
||||
}
|
||||
|
||||
public ParamCheck(client)
|
||||
{
|
||||
new String:buffer[6];
|
||||
new String:buffer2[6];
|
||||
|
||||
new outputItem[Item];
|
||||
new outputSubmenu[Submenu];
|
||||
|
||||
GetArrayArray(g_DataArray, g_currentPlace[client][Place_Item], outputItem[0]);
|
||||
|
||||
if (g_currentPlace[client][Place_ReplaceNum] < 1)
|
||||
{
|
||||
g_currentPlace[client][Place_ReplaceNum] = 1;
|
||||
}
|
||||
|
||||
Format(buffer, 5, "#%i", g_currentPlace[client][Place_ReplaceNum]);
|
||||
Format(buffer2, 5, "@%i", g_currentPlace[client][Place_ReplaceNum]);
|
||||
|
||||
if (StrContains(g_command[client], buffer) != -1 || StrContains(g_command[client], buffer2) != -1)
|
||||
{
|
||||
GetArrayArray(outputItem[Item_submenus], g_currentPlace[client][Place_ReplaceNum] - 1, outputSubmenu[0]);
|
||||
|
||||
new Handle:itemMenu = CreateMenu(Menu_Selection);
|
||||
|
||||
if ((outputSubmenu[Submenu_type] == SubMenu_Group) || (outputSubmenu[Submenu_type] == SubMenu_GroupPlayer))
|
||||
{
|
||||
decl String:nameBuffer[ARRAY_STRING_LENGTH];
|
||||
decl String:commandBuffer[ARRAY_STRING_LENGTH];
|
||||
|
||||
for (new i = 0; i<g_groupCount; i++)
|
||||
{
|
||||
GetArrayString(g_groupList[groupListName], i, nameBuffer, sizeof(nameBuffer));
|
||||
GetArrayString(g_groupList[groupListCommand], i, commandBuffer, sizeof(commandBuffer));
|
||||
AddMenuItem(itemMenu, commandBuffer, nameBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (outputSubmenu[Submenu_type] == SubMenu_MapCycle)
|
||||
{
|
||||
decl String:path[200];
|
||||
ReadPackString(outputSubmenu[Submenu_listdata], path, sizeof(path));
|
||||
ResetPack(outputSubmenu[Submenu_listdata]);
|
||||
|
||||
new Handle:file = OpenFile(path, "rt");
|
||||
new String:readData[128];
|
||||
|
||||
if(file != INVALID_HANDLE)
|
||||
{
|
||||
while(!IsEndOfFile(file) && ReadFileLine(file, readData, sizeof(readData)))
|
||||
{
|
||||
TrimString(readData);
|
||||
|
||||
if (IsMapValid(readData))
|
||||
{
|
||||
AddMenuItem(itemMenu, readData, readData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((outputSubmenu[Submenu_type] == SubMenu_Player) || (outputSubmenu[Submenu_type] == SubMenu_GroupPlayer))
|
||||
{
|
||||
new PlayerMethod:playermethod = outputSubmenu[Submenu_method];
|
||||
|
||||
new String:nameBuffer[32];
|
||||
new String:infoBuffer[32];
|
||||
new String:temp[4];
|
||||
|
||||
//loop through players. Add name as text and name/userid/steamid as info
|
||||
for (new i=1; i<=g_maxPlayers; i++)
|
||||
{
|
||||
if (IsClientInGame(i))
|
||||
{
|
||||
GetClientName(i, nameBuffer, 31);
|
||||
|
||||
switch (playermethod)
|
||||
{
|
||||
case UserId:
|
||||
{
|
||||
new userid = GetClientUserId(i);
|
||||
Format(infoBuffer, sizeof(infoBuffer), "#%i", userid);
|
||||
AddMenuItem(itemMenu, infoBuffer, nameBuffer);
|
||||
}
|
||||
case UserId2:
|
||||
{
|
||||
new userid = GetClientUserId(i);
|
||||
Format(infoBuffer, sizeof(infoBuffer), "%i", userid);
|
||||
AddMenuItem(itemMenu, infoBuffer, nameBuffer);
|
||||
}
|
||||
case SteamId:
|
||||
{
|
||||
GetClientAuthString(i, infoBuffer, sizeof(infoBuffer));
|
||||
AddMenuItem(itemMenu, infoBuffer, nameBuffer);
|
||||
}
|
||||
case IpAddress:
|
||||
{
|
||||
GetClientIP(i, infoBuffer, sizeof(infoBuffer));
|
||||
AddMenuItem(itemMenu, infoBuffer, nameBuffer);
|
||||
}
|
||||
case Name:
|
||||
{
|
||||
AddMenuItem(itemMenu, nameBuffer, nameBuffer);
|
||||
}
|
||||
default: //assume client id
|
||||
{
|
||||
Format(temp,3,"%i",i);
|
||||
AddMenuItem(itemMenu, temp, nameBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (outputSubmenu[Submenu_type] == SubMenu_OnOff)
|
||||
{
|
||||
AddMenuItem(itemMenu, "1", "On");
|
||||
AddMenuItem(itemMenu, "0", "Off");
|
||||
}
|
||||
else
|
||||
{
|
||||
new String:value[64];
|
||||
new String:text[64];
|
||||
|
||||
new String:admin[NAME_LENGTH];
|
||||
|
||||
for (new i=0; i<outputSubmenu[Submenu_listcount]; i++)
|
||||
{
|
||||
ReadPackString(outputSubmenu[Submenu_listdata], value, sizeof(value));
|
||||
ReadPackString(outputSubmenu[Submenu_listdata], text, sizeof(text));
|
||||
ReadPackString(outputSubmenu[Submenu_listdata], admin, sizeof(admin));
|
||||
|
||||
if (CheckCommandAccess(client, admin, 0))
|
||||
{
|
||||
AddMenuItem(itemMenu, value, text);
|
||||
}
|
||||
}
|
||||
|
||||
ResetPack(outputSubmenu[Submenu_listdata]);
|
||||
}
|
||||
|
||||
SetMenuTitle(itemMenu, outputSubmenu[Submenu_title]);
|
||||
|
||||
DisplayMenu(itemMenu, client, MENU_TIME_FOREVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
//nothing else need to be done. Run teh command.
|
||||
|
||||
DisplayTopMenu(hAdminMenu, client, TopMenuPosition_LastCategory);
|
||||
|
||||
if (outputItem[Item_execute] == Execute_Player) // assume 'player' type execute option
|
||||
{
|
||||
FakeClientCommand(client, g_command[client]);
|
||||
}
|
||||
else // assume 'server' type execute option
|
||||
{
|
||||
InsertServerCommand(g_command[client]);
|
||||
ServerExecute();
|
||||
}
|
||||
|
||||
g_command[client][0] = '\0';
|
||||
g_currentPlace[client][Place_ReplaceNum] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public Menu_Selection(Handle:menu, MenuAction:action, param1, param2)
|
||||
{
|
||||
if (action == MenuAction_End)
|
||||
{
|
||||
CloseHandle(menu);
|
||||
}
|
||||
|
||||
if (action == MenuAction_Select)
|
||||
{
|
||||
new String:info[NAME_LENGTH];
|
||||
|
||||
/* Get item info */
|
||||
new bool:found = GetMenuItem(menu, param2, info, sizeof(info));
|
||||
|
||||
if (!found)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
new String:buffer[6];
|
||||
new String:infobuffer[NAME_LENGTH+2];
|
||||
Format(infobuffer, sizeof(infobuffer), "\"%s\"", info);
|
||||
|
||||
Format(buffer, 5, "#%i", g_currentPlace[param1][Place_ReplaceNum]);
|
||||
ReplaceString(g_command[param1], sizeof(g_command[]), buffer, infobuffer);
|
||||
//replace #num with the selected option (quoted)
|
||||
|
||||
Format(buffer, 5, "@%i", g_currentPlace[param1][Place_ReplaceNum]);
|
||||
ReplaceString(g_command[param1], sizeof(g_command[]), buffer, info);
|
||||
//replace @num with the selected option (unquoted)
|
||||
|
||||
// Increment the parameter counter.
|
||||
g_currentPlace[param1][Place_ReplaceNum]++;
|
||||
|
||||
ParamCheck(param1);
|
||||
}
|
||||
|
||||
if (action == MenuAction_Cancel && param2 == MenuCancel_Exit)
|
||||
{
|
||||
//client exited we should go back to submenu i think
|
||||
DisplayTopMenu(hAdminMenu, param1, TopMenuPosition_LastCategory);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
#if defined _regex_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _regex_included
|
||||
|
||||
/**
|
||||
* @section Flags for compiling regex expressions. These come directly from the
|
||||
* pcre library and can be used in MatchRegex and CompileRegex.
|
||||
*/
|
||||
#define PCRE_CASELESS 0x00000001 /* Ignore Case */
|
||||
#define PCRE_MULTILINE 0x00000002 /* Multilines (affects ^ and $ so that they match the start/end of a line rather than matching the start/end of the string). */
|
||||
#define PCRE_DOTALL 0x00000004 /* Single line (affects . so that it matches any character, even new line characters). */
|
||||
#define PCRE_EXTENDED 0x00000008 /* Pattern extension (ignore whitespace and # comments). */
|
||||
#define PCRE_UNGREEDY 0x00000200 /* Invert greediness of quantifiers */
|
||||
#define PCRE_UTF8 0x00000800 /* Use UTF-8 Chars */
|
||||
#define PCRE_NO_UTF8_CHECK 0x00002000 /* Do not check the pattern for UTF-8 validity (only relevant if PCRE_UTF8 is set) */
|
||||
|
||||
|
||||
/**
|
||||
* Regex expression error codes.
|
||||
*/
|
||||
enum RegexError
|
||||
{
|
||||
REGEX_ERROR_NONE = 0, /* No error */
|
||||
REGEX_ERROR_NOMATCH = -1, /* No match was found */
|
||||
REGEX_ERROR_NULL = -2,
|
||||
REGEX_ERROR_BADOPTION = -3,
|
||||
REGEX_ERROR_BADMAGIC = -4,
|
||||
REGEX_ERROR_UNKNOWN_OPCODE = -5,
|
||||
REGEX_ERROR_NOMEMORY = -6,
|
||||
REGEX_ERROR_NOSUBSTRING = -7,
|
||||
REGEX_ERROR_MATCHLIMIT = -8,
|
||||
REGEX_ERROR_CALLOUT = -9, /* Never used by PCRE itself */
|
||||
REGEX_ERROR_BADUTF8 = -10,
|
||||
REGEX_ERROR_BADUTF8_OFFSET = -11,
|
||||
REGEX_ERROR_PARTIAL = -12,
|
||||
REGEX_ERROR_BADPARTIAL = -13,
|
||||
REGEX_ERROR_INTERNAL = -14,
|
||||
REGEX_ERROR_BADCOUNT = -15,
|
||||
REGEX_ERROR_DFA_UITEM = -16,
|
||||
REGEX_ERROR_DFA_UCOND = -17,
|
||||
REGEX_ERROR_DFA_UMLIMIT = -18,
|
||||
REGEX_ERROR_DFA_WSSIZE = -19,
|
||||
REGEX_ERROR_DFA_RECURSE = -20,
|
||||
REGEX_ERROR_RECURSIONLIMIT = -21,
|
||||
REGEX_ERROR_NULLWSLIMIT = -22, /* No longer actually used */
|
||||
REGEX_ERROR_BADNEWLINE = -23
|
||||
}
|
||||
|
||||
/**
|
||||
* Precompile a regular expression. Use this if you intend on using the
|
||||
* same expression multiple times. Pass the regex handle returned here to
|
||||
* MatchRegex to check for matches.
|
||||
*
|
||||
* @param pattern The regular expression pattern.
|
||||
* @param flags General flags for the regular expression.
|
||||
* @param error Error message encountered, if applicable.
|
||||
* @param maxLen Maximum string length of the error buffer.
|
||||
* @param errcode Regex type error code encountered, if applicable.
|
||||
* @return Valid regex handle on success, INVALID_HANDLE on failure.
|
||||
*/
|
||||
native Handle:CompileRegex(const String:pattern[], flags = 0, String:error[]="", maxLen = 0, &RegexError:errcode = REGEX_ERROR_NONE);
|
||||
|
||||
/**
|
||||
* Matches a string against a pre-compiled regular expression pattern.
|
||||
*
|
||||
* @param str The string to check.
|
||||
* @param regex Regex Handle from CompileRegex()
|
||||
* @param ret Error code, if applicable.
|
||||
* @return Number of substrings found or -1 on failure.
|
||||
*
|
||||
* @note Use the regex handle passed to this function to extract
|
||||
* matches with GetRegexSubString().
|
||||
*/
|
||||
native MatchRegex(Handle:regex, const String:str[], &RegexError:ret = REGEX_ERROR_NONE);
|
||||
|
||||
/**
|
||||
* Returns a matched substring from a regex handle.
|
||||
* Substring ids start at 0 and end at substrings-1, where substrings is the number returned
|
||||
* by MatchRegex
|
||||
*
|
||||
* @param regex The regex handle to extract data from.
|
||||
* @param str_id The index of the expression to get - starts at 0, and ends at substrings - 1.
|
||||
* @param buffer The buffer to set to the matching substring.
|
||||
* @param maxLen The maximum string length of the buffer.
|
||||
* @return True if a substring was found, False on fail/error
|
||||
*/
|
||||
native bool:GetRegexSubString(Handle:regex, str_id, String:buffer[], maxlen);
|
||||
|
||||
/**
|
||||
* Matches a string against a regular expression pattern.
|
||||
*
|
||||
* @note If you intend on using the same regular expression pattern
|
||||
* multiple times, consider using CompileRegex and MatchRegex
|
||||
* instead of making this function reparse the expression each time.
|
||||
*
|
||||
* @param str The string to check.
|
||||
* @param pattern The regular expression pattern.
|
||||
* @param flags General flags for the regular expression.
|
||||
* @param error Error message, if applicable.
|
||||
* @param maxLen Maximum length of the error buffer.
|
||||
* @return Number of substrings found or -1 on failure.
|
||||
*/
|
||||
stock SimpleRegexMatch(const String:str[], const String:pattern[], flags = 0, String:error[]="", maxLen = 0)
|
||||
{
|
||||
new Handle:regex = CompileRegex(pattern, flags, error, maxLen);
|
||||
|
||||
if (regex == INVALID_HANDLE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
new substrings = MatchRegex(regex, str);
|
||||
|
||||
CloseHandle(regex);
|
||||
|
||||
return substrings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @endsection
|
||||
*/
|
||||
|
||||
/**
|
||||
* Do not edit below this line!
|
||||
*/
|
||||
public Extension:__ext_regex =
|
||||
{
|
||||
name = "Regex Extension",
|
||||
file = "regex.ext",
|
||||
#if defined AUTOLOAD_EXTENSIONS
|
||||
autoload = 1,
|
||||
#else
|
||||
autoload = 0,
|
||||
#endif
|
||||
#if defined REQUIRE_EXTENSIONS
|
||||
required = 1,
|
||||
#else
|
||||
required = 0,
|
||||
#endif
|
||||
};
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <sdktools_tempents_stocks>
|
||||
#include <sdktools_voice>
|
||||
#include <sdktools_entinput>
|
||||
#include <sdktools_entoutput>
|
||||
|
||||
enum SDKCallType
|
||||
{
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is part of the SourceMod/SourcePawn SDK.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _sdktools_entoutput_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _sdktools_entoutput_included
|
||||
|
||||
/**
|
||||
* Called when an entity output is fired.
|
||||
*
|
||||
* @param output Name of the output that fired.
|
||||
* @param caller Entity index of the caller.
|
||||
* @param activator Entity index of the activator.
|
||||
* @param delay Delay in seconds? before the event gets fired.
|
||||
*/
|
||||
functag EntityOutput public(const String:output[], caller, activator, Float:delay);
|
||||
|
||||
/**
|
||||
* Add an entity output hook on a entity classname
|
||||
*
|
||||
* @param classname The classname to hook.
|
||||
* @param output The output name to hook.
|
||||
* @param callback An EntityOutput function pointer.
|
||||
* @noreturn
|
||||
* @error Entity Outputs disabled.
|
||||
*/
|
||||
native HookEntityOutput(const String:classname[], const String:output[], EntityOutput:callback);
|
||||
|
||||
/**
|
||||
* Remove an entity output hook.
|
||||
* @param classname The classname to hook.
|
||||
* @param output The output name to hook.
|
||||
* @param callback An EntityOutput function pointer.
|
||||
* @return True on success, false if no valid hook was found.
|
||||
* @error Entity Outputs disabled.
|
||||
*/
|
||||
native bool:UnhookEntityOutput(const String:classname[], const String:output[], EntityOutput:callback);
|
||||
|
||||
/**
|
||||
* Add an entity output hook on a single entity instance
|
||||
*
|
||||
* @param entity The entity on which to add a hook.
|
||||
* @param output The output name to hook.
|
||||
* @param callback An EntityOutput function pointer.
|
||||
* @param once Only fire this hook once and then remove itself.
|
||||
* @noreturn
|
||||
* @error Entity Outputs disabled or Invalid Entity index.
|
||||
*/
|
||||
native HookSingleEntityOutput(entity, const String:output[], EntityOutput:callback , bool:once=false);
|
||||
|
||||
/**
|
||||
* Remove a single entity output hook.
|
||||
*
|
||||
* @param entity The entity on which to remove the hook.
|
||||
* @param output The output name to hook.
|
||||
* @param callback An EntityOutput function pointer.
|
||||
* @return True on success, false if no valid hook was found.
|
||||
* @error Entity Outputs disabled or Invalid Entity index.
|
||||
*/
|
||||
native bool:UnhookSingleEntityOutput(entity, const String:output[], EntityOutput:callback);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is part of the SourceMod/SourcePawn SDK.
|
||||
@@ -283,3 +283,15 @@ native bool:GetPlayerDecalFile(client, String:hex[], maxlength);
|
||||
* @noreturn
|
||||
*/
|
||||
native GetServerNetStats(&Float:in, &Float:out);
|
||||
|
||||
|
||||
/**
|
||||
* Equip's a player's weapon.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param item CBaseCombatWeapon entity index.
|
||||
* @noreturn
|
||||
* @error Invalid client or entity, lack of mod support, or client not in
|
||||
* game.
|
||||
*/
|
||||
native EquipPlayerWeapon(client, weapon);
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is part of the SourceMod/SourcePawn SDK.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _tf2_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _tf2_included
|
||||
|
||||
enum TFClassType
|
||||
{
|
||||
TFClass_Unknown = 0,
|
||||
TFClass_Scout,
|
||||
TFClass_Sniper,
|
||||
TFClass_Soldier,
|
||||
TFClass_DemoMan,
|
||||
TFClass_Medic,
|
||||
TFClass_Heavy,
|
||||
TFClass_Pyro,
|
||||
TFClass_Spy,
|
||||
TFClass_Engineer
|
||||
}
|
||||
|
||||
enum TFTeam
|
||||
{
|
||||
TFTeam_Unassigned = 0,
|
||||
TFTeam_Spectator = 1,
|
||||
TFTeam_Red = 2,
|
||||
TFTeam_Blue = 3
|
||||
}
|
||||
|
||||
/**
|
||||
* Set's a Clients invulnrability status (ubercharge effect)
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @param enabled Enable/Disable invulnrability.
|
||||
* @noreturn
|
||||
* @error Invalid client index, client not in game, or no mod support.
|
||||
*/
|
||||
native TF2_SetPlayerInvuln(client, bool:enabled);
|
||||
|
||||
/**
|
||||
* Respawns a client
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @noreturn
|
||||
* @error Invalid client index, client not in game, or no mod support.
|
||||
*/
|
||||
native TF2_RespawnPlayer(client);
|
||||
|
||||
/**
|
||||
* Disguises a client to the given model and team. Only has an effect on spies.
|
||||
*
|
||||
* Note: This only starts the disguise process and a delay occurs before the spy is fully disguised
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @param team Team to disguise the player as (only TFTeam_Red and TFTeam_Blue have an effect)
|
||||
* @param class TFClassType class to disguise the player as
|
||||
* @noreturn
|
||||
* @error Invalid client index, client not in game, or no mod support.
|
||||
*/
|
||||
native TF2_DisguisePlayer(client, TFTeam:team, TFClassType:class);
|
||||
|
||||
/**
|
||||
* Removes the current disguise from a client. Only has an effect on spies.
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @noreturn
|
||||
* @error Invalid client index, client not in game, or no mod support.
|
||||
*/
|
||||
native TF2_RemovePlayerDisguise(client);
|
||||
|
||||
/**
|
||||
* Retrieves the entity index of the CPlayerResource entity
|
||||
*
|
||||
* @return The current resource entity index.
|
||||
*/
|
||||
native TF2_GetResourceEntity();
|
||||
|
||||
/**
|
||||
* Finds the TFClassType for a given class name.
|
||||
*
|
||||
* @param classname A classname string such as "sniper" or "demoman"
|
||||
* @return A TFClassType constant.
|
||||
*/
|
||||
native TFClassType:TF2_GetClass(const String:classname[]);
|
||||
|
||||
/**
|
||||
* Do not edit below this line!
|
||||
*/
|
||||
public Extension:__ext_tf2 =
|
||||
{
|
||||
name = "TF2 Tools",
|
||||
file = "game.tf2.ext",
|
||||
autoload = 1,
|
||||
#if defined REQUIRE_EXTENSIONS
|
||||
required = 1,
|
||||
#else
|
||||
required = 0,
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,333 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is part of the SourceMod/SourcePawn SDK.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _tf2_stocks_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _tf2_stocks_included
|
||||
|
||||
#include <tf2>
|
||||
#include <sdktools>
|
||||
|
||||
enum TFResourceType
|
||||
{
|
||||
TFResource_Ping,
|
||||
TFResource_Score,
|
||||
TFResource_Deaths,
|
||||
TFResource_TotalScore,
|
||||
TFResource_Captures,
|
||||
TFResource_Defenses,
|
||||
TFResource_Dominations,
|
||||
TFResource_Revenge,
|
||||
TFResource_BuildingsDestroyed,
|
||||
TFResource_Headshots,
|
||||
TFResource_Backstabs,
|
||||
TFResource_HealPoints,
|
||||
TFResource_Invulns,
|
||||
TFResource_Teleports,
|
||||
TFResource_ResupplyPoints,
|
||||
TFResource_KillAssists,
|
||||
TFResource_MaxHealth,
|
||||
TFResource_PlayerClass
|
||||
};
|
||||
|
||||
static const String:TFResourceNames[TFResourceType][] =
|
||||
{
|
||||
"m_iPing",
|
||||
"m_iScore",
|
||||
"m_iDeaths",
|
||||
"m_iTotalScore",
|
||||
"m_iCaptures",
|
||||
"m_iDefenses",
|
||||
"m_iDominations",
|
||||
"m_iRevenge",
|
||||
"m_iBuildingsDestroyed",
|
||||
"m_iHeadshots",
|
||||
"m_iBackstabs",
|
||||
"m_iHealPoints",
|
||||
"m_iInvulns",
|
||||
"m_iTeleports",
|
||||
"m_iResupplyPoints",
|
||||
"m_iKillAssists",
|
||||
"m_iMaxHealth",
|
||||
"m_iPlayerClass"
|
||||
};
|
||||
|
||||
/**
|
||||
* Get's a Clients current class.
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @param class TFClassType to change to.
|
||||
* @noreturn
|
||||
* @error Invalid client index.
|
||||
*/
|
||||
stock TFClassType:TF2_GetPlayerClass(client)
|
||||
{
|
||||
return TFClassType:GetEntProp(client, Prop_Send, "m_iClass");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set's a Clients class.
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @param class TFClassType class symbol.
|
||||
* @param weapons If true, changes the players weapon set to that of the new class.
|
||||
* @noreturn
|
||||
* @error Invalid client index.
|
||||
*/
|
||||
stock TF2_SetPlayerClass(client, TFClassType:class, bool:weapons=true)
|
||||
{
|
||||
SetEntProp(client, Prop_Send, "m_iClass", _:class);
|
||||
SetEntProp(client, Prop_Send, "m_iDesiredPlayerClass", _:class);
|
||||
TF2_SetPlayerResourceData(client, TFResource_PlayerClass, class);
|
||||
|
||||
if (weapons)
|
||||
{
|
||||
TF2_RemoveAllWeapons(client);
|
||||
TF2_EquipPlayerClassWeapons(client, class)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves client data from the resource entity
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @param type ResourceType constant
|
||||
* @return Value or -1 on failure.
|
||||
* @error Invalid client index, client not in game or failed to find resource entity.
|
||||
*/
|
||||
stock TF2_GetPlayerResourceData(client, TFResourceType:type)
|
||||
{
|
||||
if (!IsClientConnected(client))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static offset;
|
||||
static set = false;
|
||||
|
||||
if (!set)
|
||||
{
|
||||
offset = FindSendPropInfo("CTFPlayerResource", TFResourceNames[type]);
|
||||
set = true;
|
||||
}
|
||||
|
||||
if (offset < 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
new entity = TF2_GetResourceEntity();
|
||||
|
||||
if (entity == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return GetEntData(entity, offset + (client*4));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets client data in the resource entity
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @param type ResourceType constant
|
||||
* @param value Value to set.
|
||||
* @return Value or -1 on failure.
|
||||
* @error Invalid client index, client not in game or failed to find resource entity.
|
||||
*/
|
||||
stock bool:TF2_SetPlayerResourceData(client, TFResourceType:type, any:value)
|
||||
{
|
||||
if (!IsClientConnected(client))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static offset;
|
||||
static set = false;
|
||||
|
||||
if (!set)
|
||||
{
|
||||
offset = FindSendPropInfo("CTFPlayerResource", TFResourceNames[type]);
|
||||
set = true;
|
||||
}
|
||||
|
||||
if (offset < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
new entity = TF2_GetResourceEntity();
|
||||
|
||||
if (entity == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SetEntData(entity, offset + (client*4), value)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all weapons from a client's weapon slot
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @param slot Slot index (0-5)
|
||||
* @noreturn
|
||||
* @error Invalid client, invalid slot or lack of mod support
|
||||
*/
|
||||
stock TF2_RemoveWeaponSlot(client, slot)
|
||||
{
|
||||
new weaponIndex;
|
||||
while ((weaponIndex = GetPlayerWeaponSlot(client, slot)) != -1)
|
||||
{
|
||||
RemovePlayerItem(client, weaponIndex);
|
||||
RemoveEdict(weaponIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all weapons from a client
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @noreturn
|
||||
*/
|
||||
stock TF2_RemoveAllWeapons(client)
|
||||
{
|
||||
for (new i = 0; i <= 5; i++)
|
||||
{
|
||||
TF2_RemoveWeaponSlot(client, i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives a named weapon to a client
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @param weapon Weapon name
|
||||
* @return False if weapon could not be created, true on success
|
||||
* @error Invalid client index or lack of mod support
|
||||
*/
|
||||
stock bool:TF2_GivePlayerWeapon(client, const String:weapon[])
|
||||
{
|
||||
new weaponIndex = GivePlayerItem(client, weapon);
|
||||
if (weaponIndex == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
EquipPlayerWeapon(client, weaponIndex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equips a client with a class's weapons. This does not remove existing weapons.
|
||||
*
|
||||
* Note: Some class specific items such tf_weapon_pda_engineer_build are only given
|
||||
* if the client is the correct class.
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @param class TFClasssType class symbol.
|
||||
* @noreturn
|
||||
*/
|
||||
stock TF2_EquipPlayerClassWeapons(client, TFClassType:class)
|
||||
{
|
||||
switch(class)
|
||||
{
|
||||
case TFClass_Scout:
|
||||
{
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_scattergun");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_pistol_scout");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_bat");
|
||||
}
|
||||
case TFClass_Sniper:
|
||||
{
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_sniperrifle");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_smg");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_club");
|
||||
}
|
||||
case TFClass_Soldier:
|
||||
{
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_rocketlauncher");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_shotgun_soldier");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_shovel");
|
||||
}
|
||||
case TFClass_DemoMan:
|
||||
{
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_pipebomblauncher");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_grenadelauncher");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_bottle");
|
||||
}
|
||||
case TFClass_Medic:
|
||||
{
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_syringegun_medic");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_medigun");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_bonesaw");
|
||||
}
|
||||
case TFClass_Heavy:
|
||||
{
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_minigun");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_shotgun_hwg");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_fists");
|
||||
}
|
||||
case TFClass_Pyro:
|
||||
{
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_flamethrower");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_shotgun_pyro");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_fireaxe");
|
||||
}
|
||||
case TFClass_Spy:
|
||||
{
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_revolver");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_knife");
|
||||
|
||||
if (TF2_GetPlayerClass(client) != TFClass_Spy)
|
||||
return;
|
||||
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_pda_spy");
|
||||
}
|
||||
case TFClass_Engineer:
|
||||
{
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_shotgun_primary");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_pistol");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_wrench");
|
||||
|
||||
if (TF2_GetPlayerClass(client) != TFClass_Engineer)
|
||||
return;
|
||||
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_pda_engineer_build");
|
||||
TF2_GivePlayerWeapon(client, "tf_weapon_pda_engineer_destroy");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#include <sourcemod>
|
||||
#include <sdktools>
|
||||
|
||||
public Plugin:myinfo =
|
||||
{
|
||||
name = "Entity Output Hook Testing",
|
||||
author = "AlliedModders LLC",
|
||||
description = "Test suite for Entity Output Hooks",
|
||||
version = "1.0.0.0",
|
||||
url = "http://www.sourcemod.net/"
|
||||
};
|
||||
|
||||
public OnPluginStart()
|
||||
{
|
||||
HookEntityOutput("point_spotlight", "OnLightOn", OutputHook);
|
||||
|
||||
HookEntityOutput("func_door", "OnOpen", OutputHook);
|
||||
HookEntityOutput("func_door_rotating", "OnOpen", OutputHook);
|
||||
HookEntityOutput("func_door", "OnClose", OutputHook);
|
||||
HookEntityOutput("func_door_rotating", "OnClose", OutputHook);
|
||||
}
|
||||
|
||||
public OutputHook(const String:name[], caller, activator, Float:delay)
|
||||
{
|
||||
LogMessage("[ENTOUTPUT] %s", name);
|
||||
}
|
||||
|
||||
public OnMapStart()
|
||||
{
|
||||
new ent = FindEntityByClassname(-1, "point_spotlight");
|
||||
|
||||
if (ent == -1)
|
||||
{
|
||||
LogError("Could not find a point_spotlight");
|
||||
ent = CreateEntityByName("point_spotlight");
|
||||
DispatchSpawn(ent);
|
||||
}
|
||||
|
||||
HookSingleEntityOutput(ent, "OnLightOn", OutputHook, true);
|
||||
HookSingleEntityOutput(ent, "OnLightOff", OutputHook, true);
|
||||
|
||||
AcceptEntityInput(ent, "LightOff", ent, ent);
|
||||
AcceptEntityInput(ent, "LightOn", ent, ent);
|
||||
|
||||
AcceptEntityInput(ent, "LightOff", ent, ent);
|
||||
AcceptEntityInput(ent, "LightOn", ent, ent);
|
||||
|
||||
HookSingleEntityOutput(ent, "OnLightOn", OutputHook, false);
|
||||
HookSingleEntityOutput(ent, "OnLightOff", OutputHook, false);
|
||||
|
||||
AcceptEntityInput(ent, "LightOff", ent, ent);
|
||||
AcceptEntityInput(ent, "LightOn", ent, ent);
|
||||
AcceptEntityInput(ent, "LightOff", ent, ent);
|
||||
AcceptEntityInput(ent, "LightOn", ent, ent);
|
||||
|
||||
//Comment these out (and reload the plugin heaps) to test for leaks on plugin unload
|
||||
UnhookSingleEntityOutput(ent, "OnLightOn", OutputHook);
|
||||
UnhookSingleEntityOutput(ent, "OnLightOff", OutputHook);
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
#include <sourcemod>
|
||||
#include <sdktools>
|
||||
#include <tf2>
|
||||
#include <tf2_stocks>
|
||||
|
||||
public Plugin:myinfo =
|
||||
{
|
||||
name = "TF2 Test",
|
||||
author = "pRED*",
|
||||
description = "Test of Tf2 functions",
|
||||
version = "1.0",
|
||||
url = "www.sourcemod.net"
|
||||
}
|
||||
|
||||
public OnPluginStart()
|
||||
{
|
||||
RegConsoleCmd("sm_burnme", Command_Burn);
|
||||
RegConsoleCmd("sm_invuln", Command_Invuln);
|
||||
RegConsoleCmd("sm_respawn", Command_Respawn);
|
||||
RegConsoleCmd("sm_disguise", Command_Disguise);
|
||||
RegConsoleCmd("sm_remdisguise", Command_RemDisguise);
|
||||
RegConsoleCmd("sm_class", Command_Class);
|
||||
RegConsoleCmd("sm_remove", Command_Remove);
|
||||
RegConsoleCmd("sm_changeclass", Command_ChangeClass);
|
||||
}
|
||||
|
||||
public Action:Command_Class(client, args)
|
||||
{
|
||||
TF2_RemoveAllWeapons(client);
|
||||
|
||||
decl String:text[10];
|
||||
GetCmdArg(1, text, sizeof(text));
|
||||
|
||||
new one = StringToInt(text);
|
||||
|
||||
TF2_EquipPlayerClassWeapons(client, TFClassType:one);
|
||||
|
||||
PrintToChat(client, "Test: sniper's classnum is %i (should be %i)", TF2_GetClass("sniper"), TFClass_Sniper);
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action:Command_Remove(client, args)
|
||||
{
|
||||
decl String:text[10];
|
||||
GetCmdArg(1, text, sizeof(text));
|
||||
|
||||
new one = StringToInt(text);
|
||||
|
||||
TF2_RemoveWeaponSlot(client, one);
|
||||
|
||||
PrintToChat(client, "Test: heavy's classnum is %i (should be %i)", TF2_GetClass("heavy"), TFClass_Heavy);
|
||||
|
||||
new doms = TF2_GetPlayerResourceData(client, TFResource_Dominations);
|
||||
PrintToChat(client, "Dominations read test: %i", doms);
|
||||
|
||||
TF2_SetPlayerResourceData(client, TFResource_Dominations, doms + 10);
|
||||
doms = TF2_GetPlayerResourceData(client, TFResource_Dominations);
|
||||
PrintToChat(client, "Dominations write test: %i", doms);
|
||||
|
||||
/* Note: This didn't appear to change my dominations value when I pressed tab. */
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action:Command_ChangeClass(client, args)
|
||||
{
|
||||
decl String:text[10];
|
||||
GetCmdArg(1, text, sizeof(text));
|
||||
|
||||
new one = StringToInt(text);
|
||||
|
||||
PrintToChat(client, "Current class is :%i", TF2_GetPlayerClass(client));
|
||||
|
||||
TF2_SetPlayerClass(client, TFClassType:one);
|
||||
|
||||
PrintToChat(client, "New class is :%i", TF2_GetPlayerClass(client));
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Action:Command_Burn(client, args)
|
||||
{
|
||||
if (client == 0)
|
||||
{
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
TF2_IgnitePlayer(client, client);
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action:Command_Invuln(client, args)
|
||||
{
|
||||
if (client == 0)
|
||||
{
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
if (args < 1)
|
||||
{
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
decl String:text[10];
|
||||
GetCmdArg(1, text, sizeof(text));
|
||||
|
||||
new bool:one = !!StringToInt(text);
|
||||
|
||||
TF2_SetPlayerInvuln(client, one)
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action:Command_Disguise(client, args)
|
||||
{
|
||||
if (client == 0)
|
||||
{
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
if (args < 2)
|
||||
{
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
decl String:text[10];
|
||||
decl String:text2[10];
|
||||
GetCmdArg(1, text, sizeof(text));
|
||||
GetCmdArg(2, text2, sizeof(text2));
|
||||
|
||||
new one = StringToInt(text);
|
||||
new two = StringToInt(text2);
|
||||
|
||||
TF2_DisguisePlayer(client, TFTeam:one, TFClassType:two);
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action:Command_RemDisguise(client, args)
|
||||
{
|
||||
if (client == 0)
|
||||
{
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
TF2_RemovePlayerDisguise(client);
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
|
||||
public Action:Command_Respawn(client, args)
|
||||
{
|
||||
if (client == 0)
|
||||
{
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
|
||||
TF2_RespawnPlayer(client);
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
Reference in New Issue
Block a user