You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

446 lines
11 KiB

/* Plugin Template generated by Pawn Studio */
#include <sourcemod>
#include <tf2>
#include <tf2_stocks>
#include <sdkhooks>
new String:clientParticle[MAXPLAYERS+1][256];
new Handle:hProjectileArray[56];
new curSecCount=-1;
new Handle:hDb = INVALID_HANDLE;
public Plugin:myinfo =
{
name = "ClientParticles",
author = "Chefe",
description = "Set your own particle effect",
version = "1.0",
url = "oktoberfest-servers.net"
}
public OnPluginStart()
{
RegConsoleCmd("sm_particles", Command_Particles, "Set your own custom projectile particle effects");
HookEvent("player_changeclass", Event_PlayerChangeClass);
InitDB();
ProcessConfigFile("configs/clientparticles.cfg");
}
InitDB()
{
SQL_TConnect(InitDBHnld, "clientparticles");
}
public InitDBHnld(Handle:owner, Handle:hndl, const String:error[], any:data)
{
if (hndl == INVALID_HANDLE)
{
SetFailState("Database connection failed: %s", error);
}
else
{
hDb = hndl;
}
}
public Event_PlayerChangeClass(Handle:event,const String:name[],bool:dontBroadcast)
{
new client = GetClientOfUserId(GetEventInt(event, "userid"));
PrintToServer("Class changed, update requested");
CreateTimer(0.5, Timer_Update, client);
}
public Action:Timer_Update(Handle:timer, any:client)
{
updateClientParticle(client);
}
stock ProcessConfigFile(const String:file[])
{
new String:sConfigFile[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), file);
if (!FileExists(sConfigFile))
{
/**
Config file doesn't exists, stop the plugin
*/
LogError("[CP] Plugin startup failed! Could not find file %s", sConfigFile);
SetFailState("Could not find file %s", sConfigFile);
}
else if (!ParseConfigFile(sConfigFile))
{
/**
Couldn't parse the file, stop the plugin
*/
LogError("[SM] Plugin is not running! Failed to parse %s", sConfigFile);
SetFailState("Parse error on file %s", sConfigFile);
}
}
stock bool:ParseConfigFile(const String:file[])
{
new Handle:hParser = SMC_CreateParser();
new String:error[128];
new line = 0;
new col = 0;
/**
Define the parser functions
*/
SMC_SetReaders(hParser, Config_NewSection, Config_KeyValue, Config_EndSection);
SMC_SetParseEnd(hParser, Config_End);
/**
Parse the file and get the result
*/
new SMCError:result = SMC_ParseFile(hParser, file, line, col);
CloseHandle(hParser);
if (result != SMCError_Okay)
{
SMC_GetErrorString(result, error, sizeof(error));
LogError("%s on line %d, col %d of %s", error, line, col, file);
}
return (result == SMCError_Okay);
}
public SMCResult:Config_NewSection(Handle:parser, const String:section[], bool:quotes)
{
if (StrEqual(section, "projectiles"))
{
return SMCParse_Continue;
}
curSecCount++;
hProjectileArray[curSecCount] = CreateArray(32, 0);
PushArrayString(hProjectileArray[curSecCount], section);
return SMCParse_Continue;
}
public SMCResult:Config_KeyValue(Handle:parser, const String:key[], const String:value[], bool:key_quotes, bool:value_quotes)
{
if(StrEqual(key, "display", false))
{
PushArrayString(hProjectileArray[curSecCount], value);
PrintToServer("[PC_DEBUG] New value %s to key %s to array %i", value, key, curSecCount);
}
else if (StrEqual(key, "effect", false))
{
new index = PushArrayString(hProjectileArray[curSecCount], value);
PrintToServer("[PC_DEBUG] New value %s to key %s to array %i with index %i", value, key, curSecCount, index);
}
return SMCParse_Continue;
}
public SMCResult:Config_EndSection(Handle:parser)
{
return SMCParse_Continue;
}
public Config_End(Handle:parser, bool:halted, bool:failed)
{
if (failed)
{
SetFailState("Plugin configuration error");
}
}
public Action:Command_Particles(client, args)
{
new Handle:menu = CreateMenu(Menu_Particles);
SetMenuTitle(menu, "Choose the projectile");
for (new i=0; i<32; i++)
{
if (hProjectileArray[i] != INVALID_HANDLE && hProjectileArray[i])
{
new String:projectileName[256];
GetArrayString(hProjectileArray[i], 0, projectileName, sizeof(projectileName));
new String:displayName[256];
GetArrayString(hProjectileArray[i], 1, displayName, sizeof(displayName));
//new String:secNum[5];
//IntToString(i, secNum, sizeof(secNum));
AddMenuItem(menu, projectileName, displayName);
}
}
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, MENU_TIME_FOREVER);
return Plugin_Handled;
}
public Menu_Particles(Handle:menu, MenuAction:action, param1, param2)
{
/* If an option was selected, tell the client about the item. */
if (action == MenuAction_Select)
{
new String:projectile[256];
GetMenuItem(menu, param2, projectile, sizeof(projectile));
new Handle:effectmenu = CreateMenu(Menu_Effect);
SetMenuTitle(effectmenu, "Choose your effect");
new client = param1;
for (new a=0; a<32; a++)
{
if (hProjectileArray[a] != INVALID_HANDLE && hProjectileArray[a])
{
new String:projectileName[256];
GetArrayString(hProjectileArray[a], 0, projectileName, sizeof(projectileName));
if (StrEqual(projectile, projectileName))
{
for (new g=1; g<=(GetArraySize(hProjectileArray[a])-2); g++)
{
new String:myNewItem[256];
GetArrayString(hProjectileArray[a], g+1, myNewItem, sizeof(myNewItem));
if (!StrEqual(myNewItem, NULL_STRING))
{
AddMenuItem(effectmenu, myNewItem, myNewItem);
}
}
break;
}
}
}
// Pass projetile to menu as item for next menu handler
AddMenuItem(effectmenu, projectile, "", ITEMDRAW_IGNORE);
SetMenuExitButton(effectmenu, true);
DisplayMenu(effectmenu, client, MENU_TIME_FOREVER);
}
/* If the menu was cancelled, print a message to the server about it. */
else if (action == MenuAction_Cancel)
{
}
/* If the menu has ended, destroy it */
else if (action == MenuAction_End)
{
CloseHandle(menu);
}
}
public Menu_Effect(Handle:menu, MenuAction:action, param1, param2)
{
/* If an option was selected, tell the client about the item. */
if (action == MenuAction_Select)
{
new String:effect[256];
GetMenuItem(menu, param2, effect, sizeof(effect));
new String:projectile[256];
GetMenuItem(menu, GetMenuItemCount(menu)-1, projectile, sizeof(projectile));
PrintToChat(param1, "[CP] Effect: %s", effect);
new String:steamid[256];
GetClientAuthString(param1, steamid, sizeof(steamid));
new String:sqlstr[1024];
Format(sqlstr, sizeof(sqlstr), "SELECT particle FROM clientParticles WHERE steamid='%s' AND proj='%s'", steamid, projectile);
new Handle:pck = CreateDataPack();
WritePackCell(pck, param1);
WritePackString(pck, steamid);
WritePackString(pck, projectile);
WritePackString(pck, effect);
SQL_TQuery(hDb, searchClassEffect, sqlstr, pck);
}
/* If the menu was cancelled, print a message to the server about it. */
else if (action == MenuAction_Cancel)
{
}
/* If the menu has ended, destroy it */
else if (action == MenuAction_End)
{
CloseHandle(menu);
}
}
public searchClassEffect(Handle:owner, Handle:hndl, const String:error[], any:data)
{
if (hndl == INVALID_HANDLE || strlen(error) > 0)
{
LogError("Query error: %s", error);
return;
}
ResetPack(data);
new client = ReadPackCell(data);
new String:steamid[256];
ReadPackString(data, steamid, sizeof(steamid));
new String:projectile[256];
ReadPackString(data, projectile, sizeof(projectile));
new String:effect[256];
ReadPackString(data, effect, sizeof(effect));
if (SQL_GetRowCount(hndl)) {
while (SQL_FetchRow(hndl))
{
new String:name[150];
SQL_FetchString(hndl, 0, name, sizeof(name))
if (strcmp(name, projectile) != 0)
{
PrintToServer("%s was foudn in db. Update!", name);
new String:sqlstr[1024];
Format(sqlstr, sizeof(sqlstr), "UPDATE clientParticles SET particle = '%s' WHERE steamid='%s' AND proj='%s'", effect, steamid, projectile);
SQL_TQuery(hDb, noRtnCllbck, sqlstr);
CreateTimer(0.5, Timer_Update, client);
}
}
}
else
{
PrintToServer("NOT foudn in db. Insert!");
new String:sqlstr[1024];
Format(sqlstr, sizeof(sqlstr), "INSERT INTO clientParticles (steamid,proj,particle) VALUES ('%s','%s','%s')", steamid, projectile, effect);
SQL_TQuery(hDb, noRtnCllbck, sqlstr);
CreateTimer(0.5, Timer_Update, client);
}
}
public noRtnCllbck(Handle:owner, Handle:hndl, const String:error[], any:data)
{
if (hndl == INVALID_HANDLE || strlen(error) > 0)
{
LogError("Query error: %s", error);
return;
}
}
stock updateClientParticle(client)
{
if (IsClientInGame(client))
{
new String:steamid[256];
GetClientAuthString(client, steamid, sizeof(steamid));
new TFClassType:class = TF2_GetPlayerClass(client);
new String:proj[256];
if (class == TFClass_Soldier)
{
proj = "tf_projectile_rocket";
} else if (class == TFClass_DemoMan)
{
proj = "tf_projectile_pipe_remote";
} else
{
clientParticle[client] = NULL_STRING;
return;
}
new String:sqlstr[1024];
Format(sqlstr, sizeof(sqlstr), "SELECT particle FROM clientParticles WHERE steamid='%s' AND proj='%s'", steamid, proj);
SQL_TQuery(hDb, updateClientParticleDbCallback, sqlstr, client);
}
}
public updateClientParticleDbCallback(Handle:owner, Handle:hndl, const String:error[], any:data)
{
if (hndl == INVALID_HANDLE || strlen(error) > 0)
{
LogError("Query error: %s", error);
return;
}
if (SQL_GetRowCount(hndl)) {
while (SQL_FetchRow(hndl))
{
new String:effect[256];
SQL_FetchString(hndl, 0, effect, sizeof(effect));
clientParticle[data] = effect;
PrintToServer("Effect for %N activated: %s", data, effect);
}
}
}
public OnEntityCreated(entity, const String:classname[])
{
if (StrEqual(classname, "tf_projectile_rocket") || StrEqual(classname, "tf_projectile_pipe_remote")) {
SDKHook(entity, SDKHook_Spawn, OnEntitySpawned);
}
}
public OnEntitySpawned(entity)
{
new client = GetEntPropEnt(entity, Prop_Data, "m_hOwnerEntity");
if (client > 0 && IsClientInGame(client) && !StrEqual(clientParticle[client], NULL_STRING))
{
AddParticle(client, entity);
}
SDKUnhook(entity, SDKHook_Spawn, OnEntitySpawned);
}
stock AddParticle(client, entity)
{
new iClusters = 5, iIndex = -1;
new String:sParticle[256];
sParticle = clientParticle[client];
decl String:sExtras[64];
for (new i = 0; i < iClusters; i++)
{
while ((iIndex = SplitString(sParticle, ",", sExtras, sizeof(sExtras))) > -1)
{
CreateParticle(entity, sExtras, true);
strcopy(sParticle, sizeof(sParticle), sParticle[iIndex]);
}
CreateParticle(entity, sParticle, true);
}
}
stock CreateParticle(iEntity, String:sParticle[], bool:bAttach = false)
{
new iParticle = CreateEntityByName("info_particle_system");
if (IsValidEdict(iParticle))
{
decl Float:fPosition[3];
GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fPosition);
TeleportEntity(iParticle, fPosition, NULL_VECTOR, NULL_VECTOR);
DispatchKeyValue(iParticle, "effect_name", sParticle);
if (bAttach)
{
SetVariantString("!activator");
AcceptEntityInput(iParticle, "SetParent", iEntity, iParticle, 0);
}
DispatchSpawn(iParticle);
ActivateEntity(iParticle);
AcceptEntityInput(iParticle, "Start");
}
return iParticle;
}