forked from UNLOZE/sm-plugins
uploading remade source code of neons grenadeskin plugin because he never uploaded it. also now has tier support
This commit is contained in:
@@ -0,0 +1,416 @@
|
||||
#pragma semicolon 1
|
||||
#include <sourcemod>
|
||||
#include <clientprefs>
|
||||
#include <sdktools>
|
||||
#include <sdkhooks>
|
||||
#include <unloze_playtime>
|
||||
|
||||
#pragma newdecls required
|
||||
|
||||
#define MAX_SKINS 64
|
||||
|
||||
enum struct GrenadeSkin
|
||||
{
|
||||
char ModelPath[128];
|
||||
char Name[128];
|
||||
int VIP;
|
||||
int Tier;
|
||||
float Scale;
|
||||
int Skin;
|
||||
}
|
||||
|
||||
GrenadeSkin g_aGrenadeSkins[MAX_SKINS];
|
||||
int g_iSkinCount = 0;
|
||||
|
||||
int g_iGrenadeSkin[MAXPLAYERS + 1] = { -1, ... };
|
||||
bool g_bAdminChecked[MAXPLAYERS + 1];
|
||||
|
||||
Handle g_hCookie_GrenadeSkin;
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "Grenade Skins",
|
||||
description = "grenade skins but source code actually provided",
|
||||
author = "redone by claude ai mostly, slight human adjustments",
|
||||
version = "1.0",
|
||||
url = ""
|
||||
};
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
RegConsoleCmd("sm_grenadeskin", Cmd_GrenadeSkinSettings);
|
||||
RegConsoleCmd("sm_grenadeskins", Cmd_GrenadeSkinSettings);
|
||||
|
||||
g_hCookie_GrenadeSkin = RegClientCookie("grenade_skin", "Selected grenade skin", CookieAccess_Protected);
|
||||
|
||||
SetCookieMenuItem(MenuHandler_CookieMenu, 0, "Grenade Skin");
|
||||
|
||||
for (int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
if (IsValidClient(i, true) && AreClientCookiesCached(i))
|
||||
{
|
||||
OnClientCookiesCached(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMapStart()
|
||||
{
|
||||
LoadDownloads();
|
||||
LoadSkinsConfig();
|
||||
}
|
||||
|
||||
void LoadDownloads()
|
||||
{
|
||||
char sDownloadsFile[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, sDownloadsFile, sizeof(sDownloadsFile), "configs/grenade_skins/downloads.txt");
|
||||
|
||||
File hFile = OpenFile(sDownloadsFile, "r");
|
||||
if (!hFile)
|
||||
{
|
||||
SetFailState("Could not open file: configs/grenade_skins/downloads.txt");
|
||||
}
|
||||
|
||||
char sLine[1024];
|
||||
while (hFile.ReadLine(sLine, sizeof(sLine)))
|
||||
{
|
||||
TrimString(sLine);
|
||||
|
||||
// Skip empty lines and comment lines (lines starting with "//" with no file extension).
|
||||
if (sLine[0] == '\0')
|
||||
continue;
|
||||
|
||||
if (StrContains(sLine, ".", false) == -1)
|
||||
continue;
|
||||
|
||||
if (FileExists(sLine, false, "GAME"))
|
||||
{
|
||||
AddFileToDownloadsTable(sLine);
|
||||
}
|
||||
}
|
||||
|
||||
delete hFile;
|
||||
}
|
||||
|
||||
void LoadSkinsConfig()
|
||||
{
|
||||
// Clear existing skins.
|
||||
for (int i = 0; i < MAX_SKINS; i++)
|
||||
{
|
||||
g_aGrenadeSkins[i].ModelPath[0] = '\0';
|
||||
g_aGrenadeSkins[i].Name[0] = '\0';
|
||||
g_aGrenadeSkins[i].VIP = 0;
|
||||
g_aGrenadeSkins[i].Tier = 0;
|
||||
g_aGrenadeSkins[i].Scale = 1.0;
|
||||
g_aGrenadeSkins[i].Skin = 0;
|
||||
}
|
||||
g_iSkinCount = 0;
|
||||
|
||||
char sConfigFile[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), "configs/grenade_skins/skins.cfg");
|
||||
|
||||
if (!FileExists(sConfigFile, false, "GAME"))
|
||||
{
|
||||
SetFailState("Could not find: \"%s\"", sConfigFile);
|
||||
}
|
||||
|
||||
KeyValues kv = new KeyValues("Skins");
|
||||
if (!kv.ImportFromFile(sConfigFile))
|
||||
{
|
||||
delete kv;
|
||||
SetFailState("ImportFromFile() failed!");
|
||||
}
|
||||
|
||||
if (!kv.GotoFirstSubKey(true))
|
||||
{
|
||||
delete kv;
|
||||
SetFailState("Unable to goto first sub key in: \"%s\"", sConfigFile);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
do
|
||||
{
|
||||
if (i >= MAX_SKINS)
|
||||
{
|
||||
LogError("grenade_skins: skins.cfg has more than %d entries, ignoring the rest.", MAX_SKINS);
|
||||
break;
|
||||
}
|
||||
|
||||
kv.GetString("ModelPath", g_aGrenadeSkins[i].ModelPath, sizeof(g_aGrenadeSkins[].ModelPath), "error");
|
||||
if (StrEqual(g_aGrenadeSkins[i].ModelPath, "error", true))
|
||||
{
|
||||
SetFailState("Unable to read Path");
|
||||
}
|
||||
|
||||
kv.GetString("Name", g_aGrenadeSkins[i].Name, sizeof(g_aGrenadeSkins[].Name), "error");
|
||||
if (StrEqual(g_aGrenadeSkins[i].Name, "error", true))
|
||||
{
|
||||
SetFailState("Unable to read Name");
|
||||
}
|
||||
|
||||
g_aGrenadeSkins[i].VIP = kv.GetNum("VIP", 0);
|
||||
g_aGrenadeSkins[i].Tier = kv.GetNum("tier", 0);
|
||||
g_aGrenadeSkins[i].Scale = kv.GetFloat("Scale", 1.0);
|
||||
g_aGrenadeSkins[i].Skin = kv.GetNum("Skin", 0);
|
||||
|
||||
PrecacheModel(g_aGrenadeSkins[i].ModelPath, false);
|
||||
|
||||
i++;
|
||||
}
|
||||
while (kv.GotoNextKey(true));
|
||||
|
||||
g_iSkinCount = i;
|
||||
|
||||
delete kv;
|
||||
}
|
||||
|
||||
public void OnClientCookiesCached(int client)
|
||||
{
|
||||
char sBuffer[256];
|
||||
GetClientCookie(client, g_hCookie_GrenadeSkin, sBuffer, sizeof(sBuffer));
|
||||
|
||||
if (sBuffer[0])
|
||||
{
|
||||
g_iGrenadeSkin[client] = -1;
|
||||
|
||||
for (int i = 0; i < g_iSkinCount; i++)
|
||||
{
|
||||
if (StrEqual(g_aGrenadeSkins[i].ModelPath, sBuffer, true))
|
||||
{
|
||||
g_iGrenadeSkin[client] = i;
|
||||
|
||||
if (g_bAdminChecked[client] && !ClientHasSkinAccess(client, i))
|
||||
{
|
||||
g_iGrenadeSkin[client] = -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_iGrenadeSkin[client] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnClientDisconnect(int client)
|
||||
{
|
||||
g_iGrenadeSkin[client] = -1;
|
||||
g_bAdminChecked[client] = false;
|
||||
}
|
||||
|
||||
public void OnClientPostAdminCheck(int client)
|
||||
{
|
||||
g_bAdminChecked[client] = true;
|
||||
|
||||
if (AreClientCookiesCached(client) && g_iGrenadeSkin[client] != -1)
|
||||
{
|
||||
if (!ClientHasSkinAccess(client, g_iGrenadeSkin[client]))
|
||||
{
|
||||
g_iGrenadeSkin[client] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a client has access to a given skin index,
|
||||
* taking both the legacy VIP flag and the new tier requirement into account.
|
||||
*/
|
||||
bool ClientHasSkinAccess(int client, int skinIndex)
|
||||
{
|
||||
if (g_aGrenadeSkins[skinIndex].VIP && !CheckCommandAccess(client, "", ADMFLAG_RESERVATION, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_aGrenadeSkins[skinIndex].Tier > 0 && GetPlayerTier_native(client) < g_aGrenadeSkins[skinIndex].Tier)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnEntitySpawned(int entity, const char[] sClassname)
|
||||
{
|
||||
if (StrContains(sClassname, "_projectile", false) == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int iOwner = GetEntPropEnt(entity, Prop_Send, "m_hOwnerEntity");
|
||||
|
||||
if (!IsValidClient(iOwner, true) || g_iGrenadeSkin[iOwner] == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int skinIndex = g_iGrenadeSkin[iOwner];
|
||||
|
||||
SetEntityRenderMode(entity, RENDER_TRANSALPHA);
|
||||
|
||||
float fNadeOrigin[3];
|
||||
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", fNadeOrigin);
|
||||
|
||||
int iNadeProp = CreateEntityAtOrigin("prop_dynamic_override", fNadeOrigin);
|
||||
|
||||
DispatchKeyValue(iNadeProp, "disableshadows", "1");
|
||||
DispatchKeyValue(iNadeProp, "disablereceiveshadows", "1");
|
||||
DispatchKeyValue(iNadeProp, "DisableBoneFollowers", "1");
|
||||
DispatchKeyValue(iNadeProp, "solid", "0");
|
||||
DispatchKeyValue(iNadeProp, "model", g_aGrenadeSkins[skinIndex].ModelPath);
|
||||
|
||||
char sScale[32];
|
||||
FloatToString(g_aGrenadeSkins[skinIndex].Scale, sScale, sizeof(sScale));
|
||||
DispatchKeyValue(iNadeProp, "modelscale", sScale);
|
||||
|
||||
SpawnAndActivate(iNadeProp);
|
||||
ParentToEntity(iNadeProp, entity);
|
||||
|
||||
if (g_aGrenadeSkins[skinIndex].Skin > 0)
|
||||
{
|
||||
char sSkinBuf[16];
|
||||
IntToString(g_aGrenadeSkins[skinIndex].Skin, sSkinBuf, sizeof(sSkinBuf));
|
||||
SetVariantString(sSkinBuf);
|
||||
AcceptEntityInput(iNadeProp, "Skin");
|
||||
}
|
||||
}
|
||||
|
||||
public Action Cmd_GrenadeSkinSettings(int client, int args)
|
||||
{
|
||||
ShowSettingsMenu(client);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public void MenuHandler_CookieMenu(int client, CookieMenuAction action, any info, char[] buffer, int maxlen)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case CookieMenuAction_DisplayOption:
|
||||
{
|
||||
Format(buffer, maxlen, "Grenade Skin");
|
||||
}
|
||||
case CookieMenuAction_SelectOption:
|
||||
{
|
||||
ShowSettingsMenu(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShowSettingsMenu(int client)
|
||||
{
|
||||
Menu menu = new Menu(MenuHandler_MainMenu);
|
||||
menu.SetTitle("Grenade Skin");
|
||||
|
||||
char sBuffer[128];
|
||||
Format(sBuffer, sizeof(sBuffer), "No Skin%s", (g_iGrenadeSkin[client] == -1) ? " (Selected)" : "");
|
||||
menu.AddItem("-1", sBuffer, (g_iGrenadeSkin[client] == -1) ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT);
|
||||
|
||||
for (int i = 0; i < g_iSkinCount; i++)
|
||||
{
|
||||
bool bSelected = (i == g_iGrenadeSkin[client]);
|
||||
bool bHasAccess = ClientHasSkinAccess(client, i);
|
||||
bool bUnavailable = bSelected || !bHasAccess;
|
||||
|
||||
char sSuffix[32];
|
||||
sSuffix[0] = '\0';
|
||||
|
||||
if (!bHasAccess)
|
||||
{
|
||||
if (g_aGrenadeSkins[i].VIP && !CheckCommandAccess(client, "", ADMFLAG_RESERVATION, false))
|
||||
{
|
||||
Format(sSuffix, sizeof(sSuffix), " [VIP]");
|
||||
}
|
||||
else if (g_aGrenadeSkins[i].Tier > 0 && GetPlayerTier_native(client) < g_aGrenadeSkins[i].Tier)
|
||||
{
|
||||
Format(sSuffix, sizeof(sSuffix), " [Tier %i]", g_aGrenadeSkins[i].Tier);
|
||||
}
|
||||
}
|
||||
else if (bSelected)
|
||||
{
|
||||
Format(sSuffix, sizeof(sSuffix), " (Selected)");
|
||||
}
|
||||
|
||||
Format(sBuffer, sizeof(sBuffer), "%s%s", g_aGrenadeSkins[i].Name, sSuffix);
|
||||
|
||||
char sInfo[8];
|
||||
IntToString(i, sInfo, sizeof(sInfo));
|
||||
|
||||
menu.AddItem(sInfo, sBuffer, bUnavailable ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT);
|
||||
}
|
||||
|
||||
menu.ExitBackButton = true;
|
||||
menu.Display(client, MENU_TIME_FOREVER);
|
||||
}
|
||||
|
||||
public int MenuHandler_MainMenu(Menu menu, MenuAction action, int client, int selection)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case MenuAction_Select:
|
||||
{
|
||||
char sInfo[8];
|
||||
menu.GetItem(selection, sInfo, sizeof(sInfo));
|
||||
|
||||
int chosen = StringToInt(sInfo);
|
||||
g_iGrenadeSkin[client] = chosen;
|
||||
|
||||
if (chosen == -1)
|
||||
{
|
||||
SetClientCookie(client, g_hCookie_GrenadeSkin, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetClientCookie(client, g_hCookie_GrenadeSkin, g_aGrenadeSkins[chosen].ModelPath);
|
||||
}
|
||||
|
||||
ShowSettingsMenu(client);
|
||||
}
|
||||
case MenuAction_Cancel:
|
||||
{
|
||||
if (selection == MenuCancel_ExitBack)
|
||||
{
|
||||
// Re-open the cookie/settings menu if desired; original plugin
|
||||
// routed back into the cookie menu here.
|
||||
}
|
||||
}
|
||||
case MenuAction_End:
|
||||
{
|
||||
delete menu;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Helper stocks (ported from decompiled output)
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
stock bool IsValidClient(int client, bool noBots)
|
||||
{
|
||||
if (client <= 0 || client > MaxClients || !IsClientConnected(client) || (noBots && IsFakeClient(client)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return IsClientInGame(client);
|
||||
}
|
||||
|
||||
stock int CreateEntityAtOrigin(const char[] classname, const float origin[3])
|
||||
{
|
||||
int entity = CreateEntityByName(classname);
|
||||
TeleportEntity(entity, origin, NULL_VECTOR, NULL_VECTOR);
|
||||
return entity;
|
||||
}
|
||||
|
||||
stock void SpawnAndActivate(int entity)
|
||||
{
|
||||
DispatchSpawn(entity);
|
||||
ActivateEntity(entity);
|
||||
}
|
||||
|
||||
stock void ParentToEntity(int entity, int parent)
|
||||
{
|
||||
SetVariantString("!activator");
|
||||
AcceptEntityInput(entity, "SetParent", parent, parent);
|
||||
}
|
||||
Reference in New Issue
Block a user