added native in mapchooser for the trails entry for maps that enabled trails. also added the trails plugin itself

This commit is contained in:
jenz 2026-07-28 20:05:15 +02:00
parent 8ef2f2f2cc
commit 52a452708e
3 changed files with 462 additions and 0 deletions

View File

@ -116,6 +116,7 @@ native int GetMapCooldownTime(const char[] map); // in unix time
native int GetMapCooldownTime2(const char[] map); // in unix time native int GetMapCooldownTime2(const char[] map); // in unix time
native int GetMapLowPopHelpCount(const char[] map); native int GetMapLowPopHelpCount(const char[] map);
native int GetMapLaserFag(const char[] map); native int GetMapLaserFag(const char[] map);
native int GetMapTrails(const char[] map);
native int GetMapMinTime(const char[] map); native int GetMapMinTime(const char[] map);
native int GetMapMaxTime(const char[] map); native int GetMapMaxTime(const char[] map);
native int GetMapMinPlayers(const char[] map); native int GetMapMinPlayers(const char[] map);

View File

@ -477,6 +477,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
CreateNative("GetMapCooldownTime2", Native_GetMapCooldownTime2); CreateNative("GetMapCooldownTime2", Native_GetMapCooldownTime2);
CreateNative("GetMapLowPopHelpCount", Native_GetMapLowPopHelpCount); CreateNative("GetMapLowPopHelpCount", Native_GetMapLowPopHelpCount);
CreateNative("GetMapLaserFag", Native_GetMapLaserFag); CreateNative("GetMapLaserFag", Native_GetMapLaserFag);
CreateNative("GetMapTrails", Native_GetMapTrails);
CreateNative("GetMapMinTime", Native_GetMapMinTime); CreateNative("GetMapMinTime", Native_GetMapMinTime);
CreateNative("GetMapMaxTime", Native_GetMapMaxTime); CreateNative("GetMapMaxTime", Native_GetMapMaxTime);
CreateNative("GetMapMinPlayers", Native_GetMapMinPlayers); CreateNative("GetMapMinPlayers", Native_GetMapMinPlayers);
@ -2676,6 +2677,27 @@ public int Native_GetMapCooldownTime2(Handle plugin, int numParams)
return InternalGetMapCooldownTime2(map); return InternalGetMapCooldownTime2(map);
} }
//GetMapTrails
public int Native_GetMapTrails(Handle plugin, int numParams)
{
int len;
GetNativeStringLength(1, len);
if(len <= 0)
return false;
char[] map = new char[len+1];
GetNativeString(1, map, len+1);
int count = 0;
if (g_Config && g_Config.JumpToKey(map))
{
count = g_Config.GetNum("Trails", count);
g_Config.Rewind();
}
return count;
}
//GetMapLaserFag //GetMapLaserFag
public int Native_GetMapLaserFag(Handle plugin, int numParams) public int Native_GetMapLaserFag(Handle plugin, int numParams)
{ {

View File

@ -0,0 +1,439 @@
#pragma semicolon 1
#define PLUGIN_AUTHOR "jenz"
#define PLUGIN_VERSION "1.0"
#include <unloze_playtime>
#include <clientprefs>
#include <mapchooser_extended>
#include <zombiereloaded>
#include <sdkhooks>
#include <sdktools>
bool g_bTrailsEnabled;
bool g_bRoundStartSpawnTrails;
int g_iSpriteModel[MAXPLAYERS + 1] = {-1, ...};
int g_iClientTrail[MAXPLAYERS + 1] = { -1, ... }; // index into g_hTrails, -1 = none
Handle g_hCookie_trailName;
Handle g_hCookie_trailHide;
bool g_bHideTrails[MAXPLAYERS + 1];
public Plugin myinfo =
{
name = "unloze trails",
author = PLUGIN_AUTHOR,
description = "adds trails based on tier, vip and maps",
version = PLUGIN_VERSION,
url = "www.unloze.com"
};
enum struct TrailData
{
char name[128];
char material[512];
int tier;
int vip;
}
ArrayList g_hTrails;
public void OnPluginStart()
{
RegConsoleCmd("sm_trails", Command_Trail, "The Trails menu");
RegConsoleCmd("sm_trail", Command_Trail, "The Trails menu");
HookEvent("round_start", Event_RoundStart, EventHookMode_PostNoCopy);
HookEvent("round_end", Event_RoundEnd, EventHookMode_PostNoCopy);
HookEvent("player_death", PlayerDeath);
g_hCookie_trailName = RegClientCookie("unloze_trail", "Select your trail", CookieAccess_Protected);
g_hCookie_trailHide = RegClientCookie("unloze_trail_hide", "Hide trails", CookieAccess_Protected);
SetCookieMenuItem(MenuHandler_CookieMenu, 0, "Unloze Trails");
g_hTrails = new ArrayList(sizeof(TrailData));
}
public void MenuHandler_CookieMenu(int client, CookieMenuAction action, any info, char[] buffer, int maxlen)
{
switch (action)
{
case CookieMenuAction_DisplayOption:
{
Format(buffer, maxlen, "Trails");
}
case CookieMenuAction_SelectOption:
{
if (!g_bTrailsEnabled)
{
PrintToChat(client, "[Trails] Trails are disabled on this map.");
return;
}
OpenTrailsMenu(client);
}
}
}
public void PlayerDeath(Handle:event,const String:name[],bool:dontBroadcast)
{
int client = GetClientOfUserId(GetEventInt(event, "userid"));
KillTrail(client);
}
public void Event_RoundEnd(Handle event, const char[] name, bool dontBroadcast)
{
if (!g_bTrailsEnabled)
{
return;
}
for (int client = 1; client <= MAXPLAYERS; client++)
{
KillTrail(client);
}
}
public void Event_RoundStart(Handle event, const char[] name, bool dontBroadcast)
{
if (!g_bTrailsEnabled)
{
return;
}
g_bRoundStartSpawnTrails = false;
//From Round start we wait 5 seconds before spawning trails so map has time to load its edicts for the round.
CreateTimer(5.0, allow_spawning_trails);
}
public Action allow_spawning_trails(Handle hTimer)
{
g_bRoundStartSpawnTrails = true;
for (int client = 1; client <= MAXPLAYERS; client++)
{
if (IsValidClient(client) && g_iClientTrail[client] != -1 && IsPlayerAlive(client) && ZR_IsClientHuman(client))
{
SpawnTrail(client);
}
}
return Plugin_Handled;
}
public Action Command_Trail(int client, int args)
{
if (!g_bTrailsEnabled)
{
PrintToChat(client, "[Trails] Trails are disabled on this map.");
return Plugin_Handled;
}
OpenTrailsMenu(client);
return Plugin_Handled;
}
void OpenTrailsMenu(int client)
{
Menu menu = new Menu(MenuHandler_Trails);
menu.SetTitle("Trails Menu");
if (g_bHideTrails[client])
{
menu.AddItem("-1", "Unhide Trails");
}
else
{
menu.AddItem("-1", "Hide Trails");
}
int count = g_hTrails.Length;
int clientTier = GetPlayerTier_native(client);
bool vipAccess = CheckCommandAccess(client, "", ADMFLAG_RESERVATION, false);
for (int i = 0; i < count; i++)
{
TrailData trail;
g_hTrails.GetArray(i, trail);
char info[128];
IntToString(i, info, sizeof(info));
if (trail.tier >= clientTier)
{
char displayName[128];
Format(displayName, sizeof(displayName), "%s (Tier %d)", trail.name, trail.tier);
menu.AddItem(info, displayName, ITEMDRAW_DISABLED);
}
else if (trail.vip && !vipAccess)
{
char displayName[128];
Format(displayName, sizeof(displayName), "%s (VIP)", trail.name);
menu.AddItem(info, displayName, ITEMDRAW_DISABLED);
}
else
{
menu.AddItem(info, trail.name);
}
}
menu.ExitButton = true;
menu.Display(client, MENU_TIME_FOREVER);
}
public int MenuHandler_Trails(Menu menu, MenuAction action, int param1, int param2)
{
switch (action)
{
case MenuAction_Select:
{
char info[8];
menu.GetItem(param2, info, sizeof(info));
int index = StringToInt(info);
g_iClientTrail[param1] = index;
if (index == -1)
{
g_bHideTrails[param1] = !g_bHideTrails[param1];
PrintToChat(param1, "Trails are now %s", g_bHideTrails[param1]? "Hidden": "Unhidden");
SetClientCookie(param1, g_hCookie_trailName, "");
KillTrail(param1);
return 0;
}
else
{
TrailData trail;
g_hTrails.GetArray(index, trail);
PrintToChat(param1, "[Trails] Trail set to: %s", trail.name);
SetClientCookie(param1, g_hCookie_trailName, trail.name);
if (IsPlayerAlive(param1) && ZR_IsClientHuman(param1))
{
SpawnTrail(param1);
}
else
{
PrintToChat(param1, "Not Applying trail right now since you are not alive as human.");
}
}
//OpenTrailsMenu(param1); // reopen
}
case MenuAction_End:
{
delete menu;
}
}
return 0;
}
public OnMapEnd()
{
for (int client = 1; client <= MAXPLAYERS; client++)
{
KillTrail(client);
}
for (int client = 1; client <= MAXPLAYERS; client++)
{
g_iSpriteModel[client] = -1;
}
}
public void OnClientDisconnect(client)
{
g_bHideTrails[client] = false;
KillTrail(client);
g_iClientTrail[client] = -1;
}
public void OnClientCookiesCached(int client)
{
char sBuffer[512];
GetClientCookie(client, g_hCookie_trailHide, sBuffer, sizeof(sBuffer));
if (sBuffer[0])
{
g_bHideTrails[client] = StringToInt(sBuffer) != 0 ? true : false;
}
else
{
g_bHideTrails[client] = false;
}
GetClientCookie(client, g_hCookie_trailName, sBuffer, sizeof(sBuffer));
if (sBuffer[0])
{
g_iClientTrail[client] = -1;
int count = g_hTrails.Length;
for (int i = 0; i < count; i++)
{
TrailData trail;
g_hTrails.GetArray(i, trail);
if (StrEqual(trail.name, sBuffer, true))
{
g_iClientTrail[client] = i;
break;
}
}
}
else
{
g_iClientTrail[client] = -1;
}
}
public void OnClientPostAdminCheck(int client)
{
g_iSpriteModel[client] = -1;
}
public void OnMapStart()
{
char Mapname[128];
GetCurrentMap(Mapname, sizeof(Mapname));
g_bTrailsEnabled = GetMapTrails(Mapname) != 0 ? true : false;
LoadTrails();
}
public void LoadTrails()
{
g_hTrails.Clear();
char path[PLATFORM_MAX_PATH];
BuildPath(Path_SM, path, sizeof(path), "configs/unloze_trails.cfg");
KeyValues kv = new KeyValues("Trails");
if (!kv.ImportFromFile(path))
{
LogError("[trails] Could not load %s", path);
delete kv;
return;
}
// Enter the root "Trails" section, then iterate its children
if (kv.GotoFirstSubKey())
{
do
{
TrailData trail;
kv.GetSectionName(trail.name, sizeof(trail.name));
kv.GetString("material", trail.material, sizeof(trail.material), "");
trail.tier = kv.GetNum("tier", 0);
trail.vip = kv.GetNum("VIP", 0);
g_hTrails.PushArray(trail);
PrecacheModel(trail.material, false);
AddFileToDownloadsTable(trail.material);
char vtf_download[512];
strcopy(vtf_download, sizeof(vtf_download), trail.material);
//modifying last two characters so its .vtf
int len = strlen(vtf_download);
vtf_download[len - 2] = 't';
vtf_download[len - 1] = 'f';
AddFileToDownloadsTable(vtf_download);
}
while (kv.GotoNextKey());
}
delete kv;
}
public void ZR_OnClientInfected(int client, int attacker, bool motherInfect, bool respawnOverride, bool respawn)
{
KillTrail(client);
}
public void KillTrail(int client)
{
if (g_iSpriteModel[client] > MaxClients && IsValidEdict(g_iSpriteModel[client]))
{
SDKUnhook(g_iSpriteModel[client], SDKHook_SetTransmit, Hook_TrailShouldHide);
AcceptEntityInput(g_iSpriteModel[client], "kill");
}
g_iSpriteModel[client] = -1;
}
public void SpawnTrail(int client)
{
KillTrail(client);
if (!g_bRoundStartSpawnTrails)
{
PrintToChat(client, "Cant spawn trails this early in the round.");
return;
}
//we got 2048 edicts in total
int edict_limit = 1700;
int edict_count = GetEntityCount();
if (edict_count > edict_limit)
{
PrintToChat(client, "Not spawning your trail due to edict limitations");
return;
}
g_iSpriteModel[client] = CreateEntityByName("env_spritetrail");
if (g_iSpriteModel[client] != -1)
{
DispatchKeyValueFloat(g_iSpriteModel[client], "lifetime", 2.0);
DispatchKeyValue(g_iSpriteModel[client], "startwidth", "10");
DispatchKeyValue(g_iSpriteModel[client], "endwidth", "6");
TrailData trail;
g_hTrails.GetArray(g_iClientTrail[client], trail);
DispatchKeyValue(g_iSpriteModel[client], "spritename", trail.material);
DispatchKeyValue(g_iSpriteModel[client], "renderamt", "255");
DispatchKeyValue(g_iSpriteModel[client], "rendercolor", "255 255 255 255");
DispatchKeyValue(g_iSpriteModel[client], "rendermode", "1");
// We give the name for our entities here
char buffer[1024];
Format(buffer, sizeof(buffer), "unloze_trails_%d", g_iSpriteModel[client]);
DispatchKeyValue(g_iSpriteModel[client], "targetname", buffer);
DispatchSpawn(g_iSpriteModel[client]);
float dest_vector[3];
dest_vector[0] = 0.0;
dest_vector[1] = 0.0;
dest_vector[2] = 0.0;
float or[3];
float ang[3];
float fForward[3];
float fRight[3];
float fUp[3];
GetClientAbsOrigin(client, or);
GetClientAbsAngles(client, ang);
GetAngleVectors(ang, fForward, fRight, fUp);
or[0] += fRight[0]*dest_vector[0] + fForward[0]*dest_vector[1] + fUp[0]*dest_vector[2];
or[1] += fRight[1]*dest_vector[0] + fForward[1]*dest_vector[1] + fUp[1]*dest_vector[2];
or[2] += fRight[2]*dest_vector[0] + fForward[2]*dest_vector[1] + fUp[2]*dest_vector[2];
TeleportEntity(g_iSpriteModel[client], or, NULL_VECTOR, NULL_VECTOR);
SetVariantString("!activator");
AcceptEntityInput(g_iSpriteModel[client], "SetParent", client);
SetEntPropFloat(g_iSpriteModel[client], Prop_Send, "m_flTextureRes", 0.05);
SetEntPropEnt(g_iSpriteModel[client], Prop_Send, "m_hOwnerEntity", client);
SDKHook(g_iSpriteModel[client], SDKHook_SetTransmit, Hook_TrailShouldHide);
}
}
public Action Hook_TrailShouldHide(int entity, int client)
{
if (g_bHideTrails[client])
{
return Plugin_Handled;
}
return Plugin_Continue;
}
stock bool IsValidClient(int client)
{
if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client))
return true;
return false;
}