Compare commits

..
119 Commits
Author SHA1 Message Date
jenz 789b8ebef9 now the menu displays the category in parantheses for each map 2026-09-11 16:05:36 +02:00
jenz 1ccb5cc387 Merge pull request 'Update lag compensation' (#4) from marisa-lagcomp into master
Reviewed-on: #4
2026-09-11 12:07:30 +02:00
marisa fbc8a56fe1 Update lag compensation 2026-09-11 12:06:03 +02:00
jenz 42ffd211e7 Merge pull request 'Add game_text style hud list for couch shooters, and remove the chat message' (#3) from Irineu/sm-plugins:master into master
Reviewed-on: #3
2026-09-09 17:56:14 +02:00
Irineu cfa37daeb0 Add game_text style hud list for couch shooters, and remove the chat message 2026-09-09 12:20:57 -03:00
jenz 07f9a6768e Merge pull request 'Allow USE anywhere to activate entWatch items' (#2) from marisa-entwatch-useanywhere into master
Reviewed-on: #2
Allow USE anywhere to activate entWatch items. now put into its own separate module.
2026-09-08 22:23:10 +02:00
marisa 6b7803d46e Allow USE anywhere to activate entWatch items 2026-09-08 21:16:04 +01:00
shino ac67f2e27e Update Hitmarker/scripting/Hitmarker.sp
increased the max number of skins
2026-09-06 16:21:41 +02:00
jenz ef4bc91712 now the event couch can go through portals 2026-09-04 18:12:42 +02:00
jenz e3e70fcb12 expanded array size 2026-08-29 23:22:05 +02:00
jenz 4fd3017e5f re-added feature to just have the full list instead 2026-08-29 15:30:52 +02:00
jenz b791b050fc a bit clean up on features we abandoned again. remaking logaction to logmessage and allowing the webclient to go through without being blocked by steamID check 2026-08-29 11:43:06 +02:00
jenz 48ff38522b added cvars for being enabled/disabled for specific maps 2026-08-24 21:20:51 +02:00
jenz 5a8c97e082 missing check 2026-08-24 15:47:36 +02:00
jenz d697faa470 forward for the clients steamID, mapchoice and vote weight 2026-08-20 14:42:08 +02:00
jenz cb8d244030 simple feature through cvar to report when people shoot the couch 2026-08-18 15:02:18 +02:00
jenz 2e21de0c47 potential self fixing mechanic in case a steam player would briefly be marked as nosteamer before the connect extension gets it right? 2026-08-18 13:55:39 +02:00
jenz 80642cb0f0 now reading tickrate from mapchooser config instead of separate file 2026-08-18 12:47:30 +02:00
jenz 06d0b43b9c if vote is in progress just put bosshp in centertext 2026-08-17 20:50:50 +02:00
jenz b6c0cb232d added category menu for nominations and putting maps into sub menus 2026-08-14 16:40:31 +02:00
jenz a02fea8cc8 reintroducing revotes again for normal mapvotes 2026-08-14 15:38:06 +02:00
jenz a4e2d541a9 further modifications to make it compatible with the entwatch bans website 2026-08-12 15:32:06 +02:00
jenz 1cb0905d78 oversight on my part 2026-08-11 16:29:34 +02:00
jenz 14e83ec9a3 modified to play along with the webpannel for knifebans as well 2026-08-11 13:24:37 +02:00
jenz a72b0d9a8d had forgotten checking if client index is valid even 2026-07-31 18:57:07 +02:00
jenz 4cf475c109 moving the trail a little out of the ground so its visible when standing on moving objects like boats 2026-07-30 22:07:00 +02:00
jenz ef5ba318c1 mistake 2026-07-28 22:55:43 +02:00
jenz 2bde95afcc added config file 2026-07-28 22:29:57 +02:00
jenz 1fa8a916d6 added cvar for trail lifetime, end and starth width 2026-07-28 21:54:40 +02:00
jenz 52a452708e added native in mapchooser for the trails entry for maps that enabled trails. also added the trails plugin itself 2026-07-28 20:05:15 +02:00
jenz 8ef2f2f2cc added forward from connect announce to log in live chat the connect message with steamID 2026-07-26 13:35:32 +02:00
jenz b527ce5473 added forward for the connect message so stoat can log it to livechat 2026-07-26 13:18:28 +02:00
jenz 921ae4e136 probably good enough for displaying in console who shot and who did not 2026-07-25 23:35:46 +02:00
jenz fd32ddc101 made it its own cvar 2026-07-25 14:32:29 +02:00
jenz 2b9224f11a only counting all cvars in real players now 2026-07-25 11:26:46 +02:00
jenz ef15dfc71c no zr edition for mg/zr 2026-07-24 11:08:49 +02:00
jenz 2d91202469 forwards finally detect the webclient, handling password and retry through the plugin for the webclient 2026-07-24 11:03:05 +02:00
jenz 622bc8da4e AI slop update that enables current leaders with rcon access to write clients to the leader file or remove them again from it 2026-07-20 23:08:44 +02:00
jenz 295c92f49f not counting the fakeclients again. done in the past as well. made sense to try again. 2026-07-20 20:31:36 +02:00
jenz 47460a2db4 forgot check 2026-07-14 14:18:00 +02:00
jenz a23be2483f minor correction check 2026-07-13 23:14:28 +02:00
jenz b6e7443448 i am just going to assume it logs correctly to console 2026-07-13 23:11:35 +02:00
jenz e3e5945e77 finally adapted the plugin a bit to the new stripper modification that changed the levelcounter to info_target as a permanent entity. also added some extra modes for the vote menu 2026-07-11 23:14:39 +02:00
jenz a8dbd00f89 why did i do that mistake, self mute also works as gag even with this enabled 2026-07-11 17:36:21 +02:00
jenz f6536fd3c5 just making sure all nosteamers always have steam players muted and not only the webclient 2026-07-09 15:42:52 +02:00
jenz 8ca6ecae97 not displaying on connect anymore, changed my mind 2026-07-06 12:35:30 +02:00
jenz 02a990a29f obvious oversight for steam clients connecting after the nosteam client connected 2026-07-04 20:46:12 +02:00
jenz 1139fd89d0 improved the check and tells how many people still are needed for self extend 2026-07-04 16:54:07 +02:00
jenz 5986bedc42 should prevent webclient from being mother zombie on maps where only 1-2 zms spawn 2026-07-04 15:43:34 +02:00
jenz ee18f49be0 missed checks 2026-07-04 02:18:27 +02:00
jenz 5a1ca4959d if its the webclient just filter out all chat messages with ; or " in them 2026-07-04 00:19:24 +02:00
jenz 4a9a8e06cf nvm 2026-07-03 22:45:17 +02:00
jenz 6b625bc7ea prevent users from literally copy pasting "; into the chat 2026-07-03 21:21:44 +02:00
jenz bf6ed6e4e1 tricking nosteamers into auto muting steam clients because of broadcast voice data using steam codec and not celt. however steam clients still hear sendvoicedata that transcodes opus to celt 2026-07-01 22:19:55 +02:00
jenz 4469d07602 very silly but the webclient is skipping all the connection related forwards, so doing this weird work around for it 2026-06-30 11:14:16 +02:00
jenz ce78793029 just using default priority 2026-06-26 00:45:32 +02:00
jenz 509bd521fb should quell the error message i suppose 2026-06-25 20:03:16 +02:00
jenz 71d8773767 added myactivity command cause machu asked 2026-06-25 19:41:36 +02:00
jenz 111cc27521 added new laserfag entry in mapchooser 2026-06-25 14:04:07 +02:00
jenz c03f450e8e added extra connect rank 2026-06-24 22:05:11 +02:00
jenz e2b3ead9c3 just the exact same plugin but without hlstatsx 2026-06-23 01:05:37 +02:00
jenz c379458632 uploading remade source code of neons grenadeskin plugin because he never uploaded it. also now has tier support 2026-06-20 14:14:53 +02:00
jenz 9e59258ab0 just blocking out the hide option from working in settings in case of not having reached the tier yet 2026-06-20 01:15:58 +02:00
jenz e2659d79a6 fixed check so admin nominate still works 2026-06-19 16:12:01 +02:00
jenz e74db611c4 zspawn and joinclass if afk for 1 minute and below mce_enable_map_cooldowns_player_count counted for real players 2026-06-19 15:07:07 +02:00
jenz fefad5ce8a now having 3 map nominations as a tier perk 2026-06-18 13:48:25 +02:00
jenz 3d7e279cc7 just a tiny plugin moving afk spectators to teams 2026-06-18 12:38:36 +02:00
jenz e86e90838a moved playtime restrictions from hour requirement over to tier requirement 2026-06-17 13:55:13 +02:00
jenz 7ec6fed775 replaced hour requirement with tier requirement 2026-06-17 10:54:56 +02:00
jenz e5974b7478 yeah no reason to display member anymore on connect 2026-06-16 23:12:31 +02:00
jenz 429a2d1b0f playerranking without hlstats 2026-06-16 22:31:06 +02:00
jenz 07c8d450b3 added new formatting based on tiers for the connect message 2026-06-16 01:32:18 +02:00
jenz a460fbeaeb initial commit of render distance controller for the webclient to compensate for lacking rasterize 2026-06-10 01:05:57 +02:00
jenz 4b89862452 probably a bit cheaper calculationwise 2026-06-08 23:07:13 +02:00
jenz 8be8ced61a tried changing mask slightly 2026-06-08 12:49:11 +02:00
jenz 88b153ea3c modified the render distance plugin from madness, could not get gamedata or translations to work so just threw those out 2026-06-08 12:30:58 +02:00
jenz e0672ab09b removed the map end version and avg version. now its just called unloze. it still has average and new features from mapend, but i removed the actual mapend functionality due to players always saying they were stucked by the scoreboard pannel 2026-06-07 12:15:39 +02:00
jenz 56c97b7d29 should not had checked alive, instead increased number 2026-06-05 17:51:02 +02:00
jenz bf4c76a17c redoing adjustments 2026-06-05 15:21:57 +02:00
jenz 06e5c325ac just a timer running each second deciding if nowinpannel is enabled or not 2026-06-02 16:52:14 +02:00
jenz 4914461539 hopefully that stops the scoreboard from blocking people from participating in the vote 2026-06-02 14:46:30 +02:00
jenz e3a85e1b65 just spamming the stub to make sure it gets through 2026-06-02 00:07:59 +02:00
jenz 5cce927ced updating README to point towards correct branch 2026-05-31 01:15:18 +02:00
jenz b8ac8cc571 comitting the sourcemod plugin part for voice extension update 2026-05-30 16:58:35 +02:00
jenz 723525f8c5 removed comment 2026-05-30 15:26:54 +02:00
jenz 890e2e1418 added a stringmap to store steam ID's so during plugins lifetime it only shows the menu once when connecting 2026-05-17 13:36:06 +02:00
jenz 61568dc032 preventing first map after server crash/restart to go on cooldown 2026-05-16 14:38:57 +02:00
jenz 8b6f2e0d96 adding top activity display ingame 2026-05-16 13:06:47 +02:00
jenz 9ff0faf337 added that admins can toggle easy help on and off 2026-05-07 10:44:55 +02:00
jenz b6a1c15b7e redoing timing a little 2026-05-06 00:16:12 +02:00
jenz 0866d58b59 using the nide config approach but actually works i guess 2026-05-05 11:38:07 +02:00
jenz 6acdc80767 uploading nides edition of fakeclients with sm_debugfakes added 2026-05-03 13:18:12 +02:00
jenz 80d0b85367 probably prevents current map from randomly showing up in the mapvote itself 2026-04-30 14:18:23 +02:00
jenz 1df4cdf8dc furhter adjustments based on time 2026-04-30 14:17:41 +02:00
jenz c819974dd6 just further adjustments to autism 2026-04-24 23:01:31 +02:00
jenz d48a5b14c1 changed dbprio to high from low to stop people from nominating the maps before the query finishes 2026-04-21 21:59:58 +02:00
jenz 45258da9e1 just adding a boolean check on mapend to skip updating playercount first time the timer triggers 2026-04-21 21:35:14 +02:00
jenz 8e46053c0b instead of checking player count on each round start its checked globally every 2 minutes so that the first round on new maps dont give the extra help just because of players joining late 2026-04-21 20:00:36 +02:00
jenz 2b67f52368 not checking autismbots and fakes any longer 2026-04-21 13:46:02 +02:00
jenz f5804eed72 more time 2026-04-21 13:45:04 +02:00
jenz c57aa5bcc2 updated so that low pop helper has its own configuration now in the .cfg to decide with how many people on each map to help with easy settings 2026-04-19 19:34:58 +02:00
jenz 4a1ac398d0 forgot updating port 2026-04-19 15:32:15 +02:00
jenz f590dcc7d1 added new cooldown system that tracks minutes played into database rows and sets maps on cooldown until they fallen down enough of the listing 2026-04-19 15:26:58 +02:00
jenz 01816792ae removing a bunch of unneeded things and assuring the nomlist wont confuse leader and regular nominations any more when displaying them 2026-04-17 20:29:12 +02:00
jenz f37711fbdf majorly redid fakeclients behaviour to be balanced, updated knockback modifier to only consider mapcooldowns of over 60 hours and to check the timeleft on maps to prevent triggering the condition hopefully too early 2026-04-17 20:15:42 +02:00
jenz 7d5e56540a redoing with new native to not screw up the nominations related native 2026-04-14 22:46:24 +02:00
jenz 8e33a8bd87 just moving stuff in fakeclients over to functions. in the low pop helper plugin using a new native from mapchooser. skipping boost if first round and also including spectators now 2026-04-14 22:45:35 +02:00
jenz 208d084024 added low player count feature that gives extra hp and infinite ammo on difficult maps with low population 2026-04-14 15:17:19 +02:00
jenz b4c4b11c3d the minutes displayed would go negative which was unintended 2026-04-14 15:16:49 +02:00
jenz 778fdd2f7a probably final redux of it 2026-04-14 15:16:14 +02:00
jenz d396e006b9 added natives in mapchooser for knockback low pop plugin which now on low pop gives infintie ammo and high HP for doing difficult maps 2026-04-13 14:23:11 +02:00
jenz d12aff14ac missed ingamecheck 2026-04-07 12:18:52 +02:00
jenz 7e3ad44699 probably last edits for now 2026-04-07 11:32:34 +02:00
jenz 13f4727826 further clean up of unneeded stuff 2026-04-06 23:28:09 +02:00
jenz 06734d1b6e adjustments 2026-04-06 15:07:24 +02:00
jenz ff012d2df5 this should now catch the player count correctly to set the cooldown and shared cooldowns 2026-04-02 20:47:46 +02:00
jenz ef537b8826 renamed variable for skipping all restrictions on low pop and now also made it skip cooldowns as well as adding a new variable that decides how many players are required before applying cooldowns at all. also changed player counting not consider fakes, autism bots, afks and spec anymore to make it a lot simpler to understand. 2026-03-31 21:26:26 +02:00
jenz 6790e463fc updated fakeclients slightly and changed mapchooser for loops to not miss the last client 2026-03-27 17:34:04 +01:00
jenz 6a5cbf74f1 had it wrong before, was meant to be total_votes and not num_votes 2026-03-26 20:54:04 +01:00
53 changed files with 9621 additions and 4463 deletions
+76
View File
@@ -0,0 +1,76 @@
#include <sourcemod>
#include <sdktools>
#include <cstrike>
#include <AFKManager>
int g_iPlayer_move_spec_count;
public Plugin myinfo =
{
name = "spectator_handler",
author = "jenz",
description = "moves afk spectators to team",
version = "1.3",
url = ""
};
public void OnPluginStart()
{
CreateTimer(60.0, CheckAfks, _, TIMER_REPEAT);
ConVar cvar;
HookConVarChange((cvar = CreateConVar("sm_move_spec_to_team_count", "30", "Move real players from spec to teams until this many real players are connected")), Cvar_move_spec_team);
g_iPlayer_move_spec_count = cvar.IntValue;
delete cvar;
}
public void Cvar_move_spec_team(ConVar convar, const char[] oldValue, const char[] newValue)
{
g_iPlayer_move_spec_count = convar.IntValue;
}
public Action CheckAfks(Handle timer)
{
int real_players = 0;
for (int i = 0; i < MaxClients; i++)
{
if (IsValidClient(i) && !IsFakeClient(i) && !IsClientSourceTV(i))
{
real_players++;
}
}
if (real_players < g_iPlayer_move_spec_count)
{
for (int i = 0; i < MaxClients; i++)
{
if (IsValidClient(i) && !IsFakeClient(i) && !IsClientSourceTV(i) && GetClientTeam(i) <= CS_TEAM_SPECTATOR && GetClientIdleTime(i) > 60)
{
ChangeClientTeam(i, CS_TEAM_T);
CreateTimer(1.0, zspawn, GetClientSerial(i));
}
}
}
return Plugin_Handled;
}
public Action zspawn(Handle hTimer, int Serial)
{
int client;
if ((client = GetClientFromSerial(Serial)) == 0)
{
return Plugin_Handled;
}
if (IsValidClient(client))
{
FakeClientCommandEx(client, "joinclass");
FakeClientCommandEx(client, "say /zspawn");
}
return Plugin_Handled;
}
stock bool IsValidClient(int client)
{
if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client))
return true;
return false;
}
+106 -31
View File
@@ -1,65 +1,140 @@
#include <sourcemod> #include <sourcemod>
#include <BotTargeting>
#include <cstrike> #include <cstrike>
#include <mapchooser_extended>
int g_iDoingMapTouristMode;
int g_iActivePlayerCount;
bool g_bMapended;
public Plugin myinfo = public Plugin myinfo =
{ {
name = "knockback low pop modifier", name = "knockback low pop modifier and helper",
author = "jenz", author = "jenz",
description = "balances knockback for low population", description = "balances knockback and human settings for low population",
version = "1.0.0", version = "2.1.0",
url = "" url = ""
} }
public void OnPluginStart() public void OnPluginStart()
{ {
HookEvent("round_start", OnRoundStart); HookEvent("round_start", OnRoundStart);
RegAdminCmd("sm_helpon", Cmd_enableHelp, ADMFLAG_GENERIC);
RegAdminCmd("sm_helpoff", Cmd_disableHelp, ADMFLAG_GENERIC);
CreateTimer(80.0, CheckPopulation, _, TIMER_REPEAT);
g_iDoingMapTouristMode = 0;
g_iActivePlayerCount = 0;
g_bMapended = false;
}
public Action Cmd_enableHelp(int client, int args)
{
PrintToChatAll("ADMIN ENABLED LOW POP HELP");
CreateTimer(1.0, SetHealthOnCT);
return Plugin_Handled;
}
public Action Cmd_disableHelp(int client, int args)
{
PrintToChatAll("ADMIN DISABLED LOW POP HELP");
ServerCommand("sm_iammo @all 0");
ServerCommand("sm_hp @ct 100");
return Plugin_Handled;
}
public Action CheckPopulation(Handle timer)
{
int TimeLeft;
if (GetMapTimeLeft(TimeLeft) && TimeLeft < 0)
{
return Plugin_Continue;
}
if (g_bMapended)
{
g_bMapended = false;
return Plugin_Continue;
}
g_iActivePlayerCount = 0;
for (int i = 1; i <= MaxClients; i++)
{
if (IsClientConnected(i) && IsClientInGame(i) && IsClientAuthorized(i))
{
g_iActivePlayerCount++;
}
}
return Plugin_Continue;
} }
public void OnPluginEnd() public void OnPluginEnd()
{ {
ServerCommand("zr_class_set_multiplier zombies knockback 1.0"); ServerCommand("zr_class_set_multiplier zombies knockback 1.0");
g_iDoingMapTouristMode = 0;
g_iActivePlayerCount = 0;
} }
public void OnMapEnd() public void OnMapEnd()
{ {
g_iDoingMapTouristMode = 0;
ServerCommand("zr_class_set_multiplier zombies knockback 1.0"); ServerCommand("zr_class_set_multiplier zombies knockback 1.0");
g_bMapended = true;
}
public void OnMapStart()
{
char map[PLATFORM_MAX_PATH];
GetCurrentMap(map, PLATFORM_MAX_PATH);
//skipping de_, cs_, zm_ maps
if (StrContains(map, "ze_") == 0)
{
//LowPopHelpCount
g_iDoingMapTouristMode = GetMapLowPopHelpCount(map);
}
} }
public void OnRoundStart(Event hEvent, const char[] sEvent, bool bDontBroadcast) public void OnRoundStart(Event hEvent, const char[] sEvent, bool bDontBroadcast)
{ {
int active_player_count = 0; ServerCommand("zr_class_set_multiplier zombies knockback 1.0");
ServerCommand("sm_iammo @all 0");
for (int i = 1; i <= MaxClients; i++) int choosen_number = 35;
{ if (g_iDoingMapTouristMode > g_iActivePlayerCount > 0)
if(IsClientConnected(i) && IsClientInGame(i) && IsClientAuthorized(i) && !IsFakeClient(i) && !IsClientAutismBot(i) && !IsClientSourceTV(i) && GetClientTeam(i) > CS_TEAM_SPECTATOR) {
{ CreateTimer(3.0, SetHealthOnCT);
active_player_count++; }
} else if (g_iActivePlayerCount < choosen_number)
} {
if (active_player_count < 24)
{
int zombie_ratio = GetConVarInt(FindConVar("zr_infect_mzombie_ratio")); int zombie_ratio = GetConVarInt(FindConVar("zr_infect_mzombie_ratio"));
int infectectable_players = 0;
float knockback_increase = float(zombie_ratio) / float(active_player_count); for (int i = 1; i <= MaxClients; i++)
{
if (IsClientConnected(i) && IsClientInGame(i) && IsClientAuthorized(i) && GetClientTeam(i) > CS_TEAM_SPECTATOR)
{
infectectable_players++;
}
}
float knockback_increase = float(zombie_ratio) / float(infectectable_players);
if (knockback_increase > 3.0) if (knockback_increase > 3.0)
knockback_increase = 3.0; knockback_increase = 3.0;
else if(knockback_increase < 1.0) else if(knockback_increase < 1.0)
knockback_increase = 1.0 knockback_increase = 1.0
if (knockback_increase > 1.0) if (knockback_increase > 1.0)
{ {
PrintToChatAll("LOW POP: increased zombie knockback to X%.2f to balance gameplay", knockback_increase); PrintToChatAll("LOW POP: increased zombie knockback to X%.2f to balance gameplay", knockback_increase);
PrintToChatAll("LOW POP: increased zombie knockback to X%.2f to balance gameplay", knockback_increase); PrintToChatAll("LOW POP: increased zombie knockback to X%.2f to balance gameplay", knockback_increase);
PrintToChatAll("LOW POP: increased zombie knockback to X%.2f to balance gameplay", knockback_increase); PrintToChatAll("LOW POP: increased zombie knockback to X%.2f to balance gameplay", knockback_increase);
} ServerCommand("zr_class_set_multiplier zombies knockback %.2f", knockback_increase);
}
ServerCommand("zr_class_set_multiplier zombies knockback %.2f", knockback_increase); }
} }
else
{ public Action SetHealthOnCT(Handle timer)
ServerCommand("zr_class_set_multiplier zombies knockback 1.0"); {
} PrintToChatAll("LOW POP ON DIFFICULT MAP: ENABLING INFINITE AMMO AND 500 HP FOR CT");
PrintToChatAll("LOW POP ON DIFFICULT MAP: ENABLING INFINITE AMMO AND 500 HP FOR CT");
PrintToChatAll("LOW POP ON DIFFICULT MAP: ENABLING INFINITE AMMO AND 500 HP FOR CT");
ServerCommand("sm_iammo @all 1");
ServerCommand("sm_hp @ct 500");
return Plugin_Handled;
} }
+42 -30
View File
@@ -21,7 +21,7 @@ ConVar g_hCvar_DebugMode;
char g_sHUDText[256]; char g_sHUDText[256];
Handle g_aHurtEntityToBoss[4096] = {INVALID_HANDLE, ...}; Handle g_aHurtEntityToBoss[8191] = {INVALID_HANDLE, ...};
public Plugin myinfo = public Plugin myinfo =
{ {
@@ -495,7 +495,7 @@ public void OnEntitySpawned(int entity, const char[] classname)
{ {
char sBoss[64]; char sBoss[64];
Config.GetName(sBoss, sizeof(sBoss)); Config.GetName(sBoss, sizeof(sBoss));
LogDebugMessage("Couldn't find boss \"%s\" for hurttrigger %s:%s", sBoss, sHurtTrigger, sHurtOutput); LogDebugMessage("Couldnt find boss \"%s\" for hurttrigger %s:%s", sBoss, sHurtTrigger, sHurtOutput);
continue; continue;
} }
@@ -931,33 +931,45 @@ public void OnGameFrame()
} }
} }
if(!IsVoteInProgress()) bool voteInProgress = IsVoteInProgress();
{ if(g_sHUDText[0])
if(g_sHUDText[0]) {
{ for(int client = 1; client <= MaxClients; client++)
for(int client = 1; client <= MaxClients; client++) {
{ if(IsClientInGame(client))
if(IsClientInGame(client)) {
{ if (voteInProgress)
PrintHintText(client, g_sHUDText); {
StopSound(client, SNDCHAN_STATIC, "UI/hint.wav"); PrintCenterText(client, g_sHUDText);
} }
} else
s_bLastHudPrinted = true; {
} PrintHintText(client, g_sHUDText);
else if(s_bLastHudPrinted) }
{ StopSound(client, SNDCHAN_STATIC, "UI/hint.wav");
for(int client = 1; client <= MaxClients; client++) }
{ }
if(IsClientInGame(client)) s_bLastHudPrinted = true;
{ }
PrintHintText(client, ""); else if(s_bLastHudPrinted)
StopSound(client, SNDCHAN_STATIC, "UI/hint.wav"); {
} for(int client = 1; client <= MaxClients; client++)
} {
s_bLastHudPrinted = false; if(IsClientInGame(client))
} {
} if (voteInProgress)
{
PrintCenterText(client, g_sHUDText);
}
else
{
PrintHintText(client, g_sHUDText);
}
StopSound(client, SNDCHAN_STATIC, "UI/hint.wav");
}
}
s_bLastHudPrinted = false;
}
} }
bool BossInit(CBoss _Boss) bool BossInit(CBoss _Boss)
@@ -1415,7 +1427,7 @@ bool BossProcess(CBoss _Boss)
_Boss.iLastChange = iLastChange; _Boss.iLastChange = iLastChange;
} }
// Boss hasn't initialized HP yet. // Boss hasnt initialized HP yet.
if(iHealth == 0 && iLastHealth == 0) if(iHealth == 0 && iLastHealth == 0)
{ {
// Boss invalid: Delete boss // Boss invalid: Delete boss
+16 -4
View File
@@ -1,7 +1,6 @@
#include <sourcemod> #include <sourcemod>
#include <BossHP> #include <BossHP>
#include <zombiereloaded> #include <zombiereloaded>
#include <hlstatsx_loghelper>
ArrayList g_hStats[MAXPLAYERS+1]; ArrayList g_hStats[MAXPLAYERS+1];
@@ -208,19 +207,16 @@ public void OnBossKilled(CBoss Boss, CConfig Config, int reason)
{ {
Format(sBuffer, sizeof(sBuffer), "%s\n1. %N - %d %s", sBuffer, iSortedList[0][0], iSortedList[0][1], sType); Format(sBuffer, sizeof(sBuffer), "%s\n1. %N - %d %s", sBuffer, iSortedList[0][0], iSortedList[0][1], sType);
LH_LogPlayerEvent(iSortedList[0][0], "triggered", "ze_boss_damage_first", true);
} }
if (iSortedList[1][0]) if (iSortedList[1][0])
{ {
Format(sBuffer, sizeof(sBuffer), "%s\n2. %N - %d %s", sBuffer, iSortedList[1][0], iSortedList[1][1], sType); Format(sBuffer, sizeof(sBuffer), "%s\n2. %N - %d %s", sBuffer, iSortedList[1][0], iSortedList[1][1], sType);
LH_LogPlayerEvent(iSortedList[1][0], "triggered", "ze_boss_damage_second", true);
} }
if (iSortedList[2][0]) if (iSortedList[2][0])
{ {
Format(sBuffer, sizeof(sBuffer), "%s\n3. %N - %d %s", sBuffer, iSortedList[2][0], iSortedList[2][1], sType); Format(sBuffer, sizeof(sBuffer), "%s\n3. %N - %d %s", sBuffer, iSortedList[2][0], iSortedList[2][1], sType);
LH_LogPlayerEvent(iSortedList[2][0], "triggered", "ze_boss_damage_third", true);
} }
Format(sBuffer, sizeof(sBuffer), "%s\n*************************", sBuffer); Format(sBuffer, sizeof(sBuffer), "%s\n*************************", sBuffer);
@@ -280,6 +276,22 @@ public void OnBossKilled(CBoss Boss, CConfig Config, int reason)
} }
else else
PrintToChatAll(sBuffer); PrintToChatAll(sBuffer);
for (int i = 0; i <= MaxClients; i++)
{
if (iSortedList[i][0])
{
char sBuffer_rest[512];
Format(sBuffer_rest, sizeof(sBuffer_rest), "%s\n%i. %N - %d %s", sBuffer_rest, i, iSortedList[i][0], iSortedList[i][1], sType);
PrintToConsoleAll(sBuffer_rest);
}
else if (IsValidClient(i))
{
char sBuffer_rest[512];
Format(sBuffer_rest, sizeof(sBuffer_rest), "%s\n-1. %N - Did not shoot.", sBuffer_rest, i);
PrintToConsoleAll(sBuffer_rest);
}
}
} }
} }
} }
@@ -0,0 +1,340 @@
#include <sourcemod>
#include <BossHP>
#include <zombiereloaded>
ArrayList g_hStats[MAXPLAYERS+1];
bool g_bZRLoaded;
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Plugin myinfo =
{
name = "BossHP - Ranking",
author = "Neon & zaCade",
description = "",
version = "1.0.0",
};
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnPluginStart()
{
HookEvent("player_death", EventHook_PlayerDeath, EventHookMode_Pre);
for (int client = 1; client <= MaxClients; client++)
{
if (!IsClientInGame(client))
continue;
OnClientPutInServer(client);
}
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnAllPluginsLoaded()
{
g_bZRLoaded = LibraryExists("zombiereloaded");
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnLibraryAdded(const char[] sName)
{
if (strcmp(sName, "zombiereloaded", false) == 0)
g_bZRLoaded = true;
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnLibraryRemoved(const char[] sName)
{
if (strcmp(sName, "zombiereloaded", false) == 0)
g_bZRLoaded = false;
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientPutInServer(int client)
{
g_hStats[client] = new ArrayList(64);
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientDisconnect(int client)
{
delete g_hStats[client];
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnBossDamaged(CBoss Boss, CConfig Config, int client, float damage)
{
if (!IsValidClient(client))
return;
int iMaxCash = GetConVarInt(FindConVar("sm_maxcash"));
if(!(GetEntProp(client, Prop_Send, "m_iAccount") >= iMaxCash))
SetEntProp(client, Prop_Send, "m_iAccount", GetEntProp(client, Prop_Send, "m_iAccount") + 2);
bool bBreakable;
CConfig _Config = view_as<CConfig>(Config);
if (_Config.IsBreakable)
bBreakable = true;
else
bBreakable = false;
delete _Config;
for (int index = 0; index < g_hStats[client].Length; index++)
{
int BossDamage[2];
g_hStats[client].GetArray(index, BossDamage, sizeof(BossDamage));
if (BossDamage[0] == view_as<int>(Boss))
{
if (bBreakable)
BossDamage[1] += RoundToNearest(damage);
else
BossDamage[1] += 1;
g_hStats[client].SetArray(index, BossDamage, sizeof(BossDamage));
return;
}
}
int BossDamage[2];
BossDamage[0] = view_as<int>(Boss);
if (bBreakable)
BossDamage[1] = RoundToNearest(damage);
else
BossDamage[1] = 1;
g_hStats[client].PushArray(BossDamage, sizeof(BossDamage));
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnBossKilled(CBoss Boss, CConfig Config, int reason)
{
if (reason == 0)
{
for (int client = 1; client <= MaxClients; client++)
{
if (!IsClientInGame(client))
continue;
for (int index = 0; index < g_hStats[client].Length; index++)
{
int BossDamage[2];
g_hStats[client].GetArray(index, BossDamage, sizeof(BossDamage));
if (BossDamage[0] == view_as<int>(Boss))
{
g_hStats[client].Erase(index);
break;
}
}
}
}
else
{
int iSortedList[MAXPLAYERS+1][2];
int iSortedCount;
for (int client = 1; client <= MaxClients; client++)
{
if (!IsClientInGame(client))
continue;
for (int index = 0; index < g_hStats[client].Length; index++)
{
int BossDamage[2];
g_hStats[client].GetArray(index, BossDamage, sizeof(BossDamage));
if (BossDamage[0] == view_as<int>(Boss))
{
iSortedList[iSortedCount][0] = client;
iSortedList[iSortedCount][1] = BossDamage[1];
iSortedCount++;
g_hStats[client].Erase(index);
break;
}
}
}
SortCustom2D(iSortedList, iSortedCount, SortBossHitsList);
if (iSortedCount)
{
CConfig _Config = view_as<CConfig>(Config);
char sBossName[64];
_Config.GetName(sBossName, sizeof(sBossName));
char sBuffer[512];
char sType[16];
if (_Config.IsBreakable)
{
sType = "damage"
Format(sBuffer, sizeof(sBuffer), "BOSS DAMAGE [%s]:", sBossName);
}
else
{
sType = "hits"
Format(sBuffer, sizeof(sBuffer), "BOSS HITS [%s]:", sBossName);
}
delete _Config;
Format(sBuffer, sizeof(sBuffer), "%s\n*************************", sBuffer);
if (iSortedList[0][0])
{
Format(sBuffer, sizeof(sBuffer), "%s\n1. %N - %d %s", sBuffer, iSortedList[0][0], iSortedList[0][1], sType);
}
if (iSortedList[1][0])
{
Format(sBuffer, sizeof(sBuffer), "%s\n2. %N - %d %s", sBuffer, iSortedList[1][0], iSortedList[1][1], sType);
}
if (iSortedList[2][0])
{
Format(sBuffer, sizeof(sBuffer), "%s\n3. %N - %d %s", sBuffer, iSortedList[2][0], iSortedList[2][1], sType);
}
Format(sBuffer, sizeof(sBuffer), "%s\n*************************", sBuffer);
Handle hMessage = StartMessageAll("HudMsg");
if (hMessage)
{
if (GetUserMessageType() == UM_Protobuf)
{
PbSetInt(hMessage, "channel", 50);
PbSetInt(hMessage, "effect", 0);
PbSetColor(hMessage, "clr1", {255, 255, 255, 255});
PbSetColor(hMessage, "clr2", {255, 255, 255, 255});
PbSetVector2D(hMessage, "pos", Float:{0.02, 0.45});
PbSetFloat(hMessage, "fade_in_time", 0.1);
PbSetFloat(hMessage, "fade_out_time", 0.1);
PbSetFloat(hMessage, "hold_time", 7.0);
PbSetFloat(hMessage, "fx_time", 0.0);
PbSetString(hMessage, "text", sBuffer);
EndMessage();
}
else
{
BfWriteByte(hMessage, 50);
BfWriteFloat(hMessage, 0.02);
BfWriteFloat(hMessage, 0.25);
BfWriteByte(hMessage, 255);
BfWriteByte(hMessage, 255);
BfWriteByte(hMessage, 0);
BfWriteByte(hMessage, 255);
BfWriteByte(hMessage, 255);
BfWriteByte(hMessage, 255);
BfWriteByte(hMessage, 255);
BfWriteByte(hMessage, 255);
BfWriteByte(hMessage, 0);
BfWriteFloat(hMessage, 0.1);
BfWriteFloat(hMessage, 0.1);
BfWriteFloat(hMessage, 7.0);
BfWriteFloat(hMessage, 0.0);
BfWriteString(hMessage, sBuffer);
EndMessage();
}
}
if(GetEngineVersion() == Engine_CSGO)
{
int iSplits
char sSplits[16][512];
if((iSplits = ExplodeString(sBuffer, "\n", sSplits, sizeof(sSplits), sizeof(sSplits[]))) != 0)
{
for (int iSplit; iSplit < iSplits; iSplit++)
{
PrintToChatAll(sSplits[iSplit]);
}
}
}
else
PrintToChatAll(sBuffer);
}
}
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action EventHook_PlayerDeath(Event hEvent, const char[] sEventName, bool bDontBroadcast)
{
if (!g_bZRLoaded)
return Plugin_Continue;
int iClient = GetClientOfUserId(hEvent.GetInt("userid"));
if (!IsValidClient(iClient))
return Plugin_Continue;
if (IsPlayerAlive(iClient) && !ZR_IsClientHuman(iClient))
return Plugin_Continue;
int iPacked = (iClient<<16) | (GetEntProp(iClient, Prop_Send, "m_iAccount")&0xFFFF);
RequestFrame(RequestFrame_Callback, iPacked);
return Plugin_Continue;
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
void RequestFrame_Callback(int iPacked)
{
int iOldCash = iPacked&0xFFFF;
int iClient = iPacked>>16;
if (!IsValidEntity(iClient) || !IsValidClient(iClient))
return;
SetEntProp(iClient, Prop_Send, "m_iAccount", iOldCash);
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int SortBossHitsList(int[] elem1, int[] elem2, const int[][] array, Handle hndl)
{
if (elem1[1] > elem2[1]) return -1;
if (elem1[1] < elem2[1]) return 1;
return 0;
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
stock int IsValidClient(int client, bool nobots = true)
{
if (client <= 0 || client > MaxClients || !IsClientConnected(client) || (nobots && IsFakeClient(client)))
return false;
return IsClientInGame(client);
}
+6
View File
@@ -0,0 +1,6 @@
this is used for the voice extension:
https://git.unloze.com/UNLOZE/sm-ext-Voice/src/branch/CeltOpusTranscoder_2026
//the voice chat is now transcoded so both celt and opus work by sending each stream to the player that needs it.
the include belongs to the voice extension but is also put here extra
+35
View File
@@ -0,0 +1,35 @@
#if defined _voice_included
#endinput
#endif
#define _voice_included
native bool IsClientTalking(int client);
native bool SetClientNoSteam(int client, bool isNosteam);
native bool SendCeltVoiceInit(int client);
native bool ClientMutedOtherClient(int client, int otherclient, bool muted);
/**
* Do not edit below this line!
*/
public Extension __ext_voice =
{
name = "Voice",
file = "Voice.ext",
#if defined AUTOLOAD_EXTENSIONS
autoload = 1,
#else
autoload = 0,
#endif
#if defined REQUIRE_EXTENSIONS
required = 1,
#else
required = 0,
#endif
};
#if !defined REQUIRE_EXTENSIONS
public __ext_voice_SetNTVOptional()
{
MarkNativeAsOptional("IsClientTalking");
}
#endif
+366
View File
@@ -0,0 +1,366 @@
#include <sourcemod>
#include <PlayerManager>
#include <sdktools>
#include <basecomm>
#include <ccc>
#include <clientprefs>
#include <SteamWorks>
#tryinclude <zombiereloaded>
#include <selfmute>
#include <connect>
#include <voice>
#pragma semicolon 1
#pragma newdecls required
Handle g_hCheckMutes = null;
Handle g_hCookieTorchMuted = null;
bool g_bWebclient[MAXPLAYERS + 1];
bool g_bReRunWebClientName;
bool g_bSkipInfection = false;
char g_sLastWebclientIp[64];
public Plugin myinfo =
{
name = "NoSteam CELT Voice override",
author = "jenz",
version = "1.5"
};
public void OnPluginStart()
{
Format(g_sLastWebclientIp, sizeof(g_sLastWebclientIp), "");
g_hCheckMutes = CreateTimer(2.0, check_mutes, _, TIMER_REPEAT);
g_hCookieTorchMuted = RegClientCookie("torch_muted", "is torch muted", CookieAccess_Protected);
}
public void OnPluginEnd()
{
if (g_hCheckMutes != null)
{
delete g_hCheckMutes;
}
}
public void set_nosteam_listen_override(int client)
{
for (int j = 1; j <= MaxClients; j++)
{
if (!IsValidClient(j) || client == j || IsFakeClient(j))
continue;
if (PM_IsPlayerSteam(j))
{
//the nosteam client is not allowed to hear the steam client because broadcastvoicedata would ear rape them.
//LogMessage("%N has muted %N", client, j);
SetListenOverride(client, j, Listen_No);
}
}
}
public Action check_mutes(Handle timer, any data)
{
for (int i = 1; i <= MaxClients; i++)
{
if (!IsValidClient(i) || IsFakeClient(i))
{
continue;
}
if (!PM_IsPlayerSteam(i))
{
set_nosteam_listen_override(i);
}
else
{
//maybe this is a fix? maybe not.
clear_steam_listen_override(i);
}
for (int j = 1; j <= MaxClients; j++)
{
if (!IsValidClient(j) || i == j || IsFakeClient(j))
{
continue;
}
bool isMuted = BaseComm_IsClientMuted(j);
if (!isMuted)
{
isMuted = SelfMute_IsIgnoring(i, j);
}
//PrintToChatAll("i: %N. j: %N. isMuted: %i", i, j, isMuted);
ClientMutedOtherClient(i, j, isMuted);
}
if (g_bReRunWebClientName && g_bWebclient[i])
{
char dummy[64];
OnClientAuthorized(i, dummy);
g_bReRunWebClientName = false;
}
}
//sourceTV special case, index 0.
for (int j = 1; j <= MaxClients; j++)
{
if (!IsValidClient(j) || IsFakeClient(j))
{
continue;
}
//yeah its monkey work but server can probably handle it fine.
char sBuffer[2];
GetClientCookie(j, g_hCookieTorchMuted, sBuffer, sizeof(sBuffer));
//PrintToChatAll("sBuffer: %s. j: %N", sBuffer, j);
if(sBuffer[0] != '\0')
{
ClientMutedOtherClient(j, 0, true);
}
else
{
ClientMutedOtherClient(j, 0, false);
}
}
//check if webclient has new IP every 2 seconds through endpoint.
PollWebclientCurrentIp();
return Plugin_Continue;
}
public void clear_steam_listen_override(int client)
{
for (int j = 1; j <= MaxClients; j++)
{
if (!IsValidClient(j) || client == j || IsFakeClient(j))
continue;
if (PM_IsPlayerSteam(j) && !BaseComm_IsClientMuted(j) && !SelfMute_IsIgnoring(client, j))
{
SetListenOverride(client, j, Listen_Default);
}
}
}
//AI slop
public void SendWebclientNameToSignaling(const char[] webclientName)
{
char url[256];
// Adjust port/path to match your signaling servers actual endpoint
FormatEx(url, sizeof(url), "http://127.0.0.1:3000/webclient-name");
Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodPOST, url);
if (hRequest == null)
{
return;
}
// Send the name as a POST body parameter
SteamWorks_SetHTTPRequestGetOrPostParameter(hRequest, "name", webclientName);
if (!SteamWorks_SetHTTPCallbacks(hRequest, OnWebclientNamePosted) ||
!SteamWorks_SendHTTPRequest(hRequest))
{
delete hRequest;
}
}
public int OnWebclientNamePosted(Handle hRequest, bool bFailure, bool bRequestSuccessful,
EHTTPStatusCode eStatusCode, any data)
{
// Fire-and-forget: we dont care about the response, just clean up.
delete hRequest;
return 0;
}
public void OnMapStart()
{
g_bReRunWebClientName = true;
}
public void OnClientDisconnect(int client)
{
g_bWebclient[client] = false;
}
public void OnClientPostAdminCheck(int client)
{
g_bWebclient[client] = false;
if (IsFakeClient(client))
{
return;
}
char sIP[32];
GetClientIP(client, sIP, sizeof(sIP));
char allowed_ips[128];
ConVar sv_set_steam_id_ips = FindConVar("sv_set_steam_id_ips");
if (sv_set_steam_id_ips != null)
{
sv_set_steam_id_ips.GetString(allowed_ips, sizeof(allowed_ips));
if (StrEqual(sIP, allowed_ips))
{
g_bWebclient[client] = true;
g_bSkipInfection = GetConVarInt(FindConVar("zr_infect_mzombie_ratio")) > 10 ? true : false;
//this works fine with one webclient only existing.
char webclientName[64];
GetConVarString(FindConVar("sv_webclient_name"), webclientName, sizeof(webclientName));
SetClientName(client, webclientName);
SendWebclientNameToSignaling(webclientName);
}
}
}
public void OnClientAuthorized(int client, const char[] auth)
{
if (IsFakeClient(client))
{
return;
}
SetClientNoSteam(client, false);
if (!PM_IsPlayerSteam(client))
{
SetClientNoSteam(client, true);
//LogMessage("here in onauthorized client: %N", client);
//setting it too early does not work, so some delay needed.
CreateTimer(10.0, Timer_SendVoiceInit, GetClientSerial(client));
CreateTimer(20.0, Timer_SendVoiceInit, GetClientSerial(client));
CreateTimer(30.0, Timer_SendVoiceInit, GetClientSerial(client));
CreateTimer(40.0, Timer_SendVoiceInit, GetClientSerial(client));
CreateTimer(50.0, Timer_SendVoiceInit, GetClientSerial(client));
CreateTimer(60.0, Timer_SendVoiceInit, GetClientSerial(client));
}
}
public Action CCC_OnChatMessage(int client, int author, const char[] message)
{
if (!g_bWebclient[client])
{
return Plugin_Continue;
}
int index = FindCharInString(message, '"', false);
int index1 = FindCharInString(message, ';', false);
if (index != -1 || index1 != -1)
{
return Plugin_Handled;
}
return Plugin_Continue;
}
#if defined _zr_included
public Action ZR_OnClientMotherZombieEligible(int client)
{
if (g_bWebclient[client] && g_bSkipInfection)
{
return Plugin_Handled;
}
return Plugin_Continue;
}
#endif
public Action Timer_SendVoiceInit(Handle timer, int Serial)
{
int client;
if ((client = GetClientFromSerial(Serial)) == 0)
{
return Plugin_Handled;
}
if (IsValidClient(client) && !PM_IsPlayerSteam(client))
{
SendCeltVoiceInit(client);
}
return Plugin_Handled;
}
/**
* Polls the signaling server for the current webclient controller's real IP.
* If the IP has changed since the last
* check and a webclient player is currently connected, forces them to
* reconnect with the new password via ClientCommand.
**/
public void PollWebclientCurrentIp()
{
Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, "http://127.0.0.1:3000/webclient-current-ip");
if (hRequest == null)
{
return;
}
if (!SteamWorks_SetHTTPCallbacks(hRequest, OnWebclientCurrentIpReceived) ||
!SteamWorks_SendHTTPRequest(hRequest))
{
delete hRequest;
}
}
public int OnWebclientCurrentIpReceived(Handle hRequest, bool bFailure, bool bRequestSuccessful,
EHTTPStatusCode eStatusCode, any data)
{
if (bFailure || !bRequestSuccessful || eStatusCode != k_EHTTPStatusCode200OK)
{
delete hRequest;
return 0;
}
int bodySize;
bool gotSize = SteamWorks_GetHTTPResponseBodySize(hRequest, bodySize);
char newIp[64];
newIp[0] = '\0';
if (gotSize && bodySize > 0 && bodySize < sizeof(newIp))
{
SteamWorks_GetHTTPResponseBodyData(hRequest, newIp, bodySize);
}
delete hRequest;
if (newIp[0] == '\0')
{
return 0;
}
if (StrEqual(newIp, g_sLastWebclientIp))
{
return 0;
}
for (int i = 1; i <= MaxClients; i++)
{
if (IsValidClient(i) && g_bWebclient[i])
{
strcopy(g_sLastWebclientIp, sizeof(g_sLastWebclientIp), newIp);
LogMessage("Forcing webclient reconnect for client %N with new IP: %s", i, newIp);
ClientCommand(i, "retry");
break;
}
}
return 0;
}
public EConnect OnClientPreConnectEx(const char[] sName, char sPassword[255], const char[] sIP, const char[] sSteam32ID, char sRejectReason[255])
{
char allowedIp[64];
ConVar sv_set_steam_id_ips = FindConVar("sv_set_steam_id_ips");
if (sv_set_steam_id_ips != null)
{
sv_set_steam_id_ips.GetString(allowedIp, sizeof(allowedIp));
//this is to handle that the connect extension receives the password parameter for the webclient as its real connecting IP.
//works both for the client command retry and for the case that somebody presses the connect button in the clients Menu as the same password
//is applied again.
if (StrEqual(sIP, allowedIp) && strlen(g_sLastWebclientIp) > 0)
{
strcopy(sPassword, 255, g_sLastWebclientIp);
LogMessage("Backfilled empty password for webclient with cached IP: %s", g_sLastWebclientIp);
}
}
// ET_LowEvent takes the LOWEST value returned across all plugins hooking this forward.
//this plugin returns 1 (Accept), meanwhile the reserved slot plugin still might return 0 (reject) or -1 (async) to overrule the decision from this return value.
return k_OnClientPreConnectEx_Accept;
}
stock bool IsValidClient(int client)
{
if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client))
return true;
return false;
}
@@ -0,0 +1,333 @@
#include <sourcemod>
#include <PlayerManager>
#include <sdktools>
#include <basecomm>
#include <ccc>
#include <clientprefs>
#include <SteamWorks>
#include <selfmute>
#include <connect>
#include <voice>
#pragma semicolon 1
#pragma newdecls required
Handle g_hCheckMutes = null;
Handle g_hCookieTorchMuted = null;
bool g_bWebclient[MAXPLAYERS + 1];
bool g_bReRunWebClientName;
char g_sLastWebclientIp[64];
public Plugin myinfo =
{
name = "NoSteam CELT Voice override",
author = "jenz",
version = "1.5"
};
public void OnPluginStart()
{
Format(g_sLastWebclientIp, sizeof(g_sLastWebclientIp), "");
g_hCheckMutes = CreateTimer(2.0, check_mutes, _, TIMER_REPEAT);
g_hCookieTorchMuted = RegClientCookie("torch_muted", "is torch muted", CookieAccess_Protected);
}
public void OnPluginEnd()
{
if (g_hCheckMutes != null)
{
delete g_hCheckMutes;
}
}
public void set_nosteam_listen_override(int client)
{
for (int j = 1; j <= MaxClients; j++)
{
if (!IsValidClient(j) || client == j || IsFakeClient(j))
continue;
if (PM_IsPlayerSteam(j))
{
//the nosteam client is not allowed to hear the steam client because broadcastvoicedata would ear rape them.
//LogMessage("%N has muted %N", client, j);
SetListenOverride(client, j, Listen_No);
}
}
}
public Action check_mutes(Handle timer, any data)
{
for (int i = 1; i <= MaxClients; i++)
{
if (!IsValidClient(i) || IsFakeClient(i))
{
continue;
}
if (!PM_IsPlayerSteam(i))
{
set_nosteam_listen_override(i);
}
for (int j = 1; j <= MaxClients; j++)
{
if (!IsValidClient(j) || i == j || IsFakeClient(j))
{
continue;
}
bool isMuted = BaseComm_IsClientMuted(j);
if (!isMuted)
{
isMuted = SelfMute_IsIgnoring(i, j);
}
//PrintToChatAll("i: %N. j: %N. isMuted: %i", i, j, isMuted);
ClientMutedOtherClient(i, j, isMuted);
}
if (g_bReRunWebClientName && g_bWebclient[i])
{
char dummy[64];
OnClientAuthorized(i, dummy);
g_bReRunWebClientName = false;
}
}
//sourceTV special case, index 0.
for (int j = 1; j <= MaxClients; j++)
{
if (!IsValidClient(j) || IsFakeClient(j))
{
continue;
}
//yeah its monkey work but server can probably handle it fine.
char sBuffer[2];
GetClientCookie(j, g_hCookieTorchMuted, sBuffer, sizeof(sBuffer));
//PrintToChatAll("sBuffer: %s. j: %N", sBuffer, j);
if(sBuffer[0] != '\0')
{
ClientMutedOtherClient(j, 0, true);
}
else
{
ClientMutedOtherClient(j, 0, false);
}
}
//check if webclient has new IP every 2 seconds through endpoint.
PollWebclientCurrentIp();
return Plugin_Continue;
}
//AI slop
public void SendWebclientNameToSignaling(const char[] webclientName)
{
char url[256];
// Adjust port/path to match your signaling servers actual endpoint
FormatEx(url, sizeof(url), "http://127.0.0.1:3000/webclient-name");
Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodPOST, url);
if (hRequest == null)
{
return;
}
// Send the name as a POST body parameter
SteamWorks_SetHTTPRequestGetOrPostParameter(hRequest, "name", webclientName);
if (!SteamWorks_SetHTTPCallbacks(hRequest, OnWebclientNamePosted) ||
!SteamWorks_SendHTTPRequest(hRequest))
{
delete hRequest;
}
}
public int OnWebclientNamePosted(Handle hRequest, bool bFailure, bool bRequestSuccessful,
EHTTPStatusCode eStatusCode, any data)
{
// Fire-and-forget: we dont care about the response, just clean up.
delete hRequest;
return 0;
}
public void OnMapStart()
{
g_bReRunWebClientName = true;
}
public void OnClientDisconnect(int client)
{
g_bWebclient[client] = false;
}
public void OnClientPostAdminCheck(int client)
{
g_bWebclient[client] = false;
if (IsFakeClient(client))
{
return;
}
char sIP[32];
GetClientIP(client, sIP, sizeof(sIP));
char allowed_ips[128];
ConVar sv_set_steam_id_ips = FindConVar("sv_set_steam_id_ips");
if (sv_set_steam_id_ips != null)
{
sv_set_steam_id_ips.GetString(allowed_ips, sizeof(allowed_ips));
if (StrEqual(sIP, allowed_ips))
{
g_bWebclient[client] = true;
//this works fine with one webclient only existing.
char webclientName[64];
GetConVarString(FindConVar("sv_webclient_name"), webclientName, sizeof(webclientName));
SetClientName(client, webclientName);
SendWebclientNameToSignaling(webclientName);
}
}
}
public void OnClientAuthorized(int client, const char[] auth)
{
if (IsFakeClient(client))
{
return;
}
SetClientNoSteam(client, false);
if (!PM_IsPlayerSteam(client))
{
SetClientNoSteam(client, true);
//LogMessage("here in onauthorized client: %N", client);
//setting it too early does not work, so some delay needed.
CreateTimer(10.0, Timer_SendVoiceInit, GetClientSerial(client));
CreateTimer(20.0, Timer_SendVoiceInit, GetClientSerial(client));
CreateTimer(30.0, Timer_SendVoiceInit, GetClientSerial(client));
CreateTimer(40.0, Timer_SendVoiceInit, GetClientSerial(client));
CreateTimer(50.0, Timer_SendVoiceInit, GetClientSerial(client));
CreateTimer(60.0, Timer_SendVoiceInit, GetClientSerial(client));
}
}
public Action CCC_OnChatMessage(int client, int author, const char[] message)
{
if (!g_bWebclient[client])
{
return Plugin_Continue;
}
int index = FindCharInString(message, '"', false);
int index1 = FindCharInString(message, ';', false);
if (index != -1 || index1 != -1)
{
return Plugin_Handled;
}
return Plugin_Continue;
}
public Action Timer_SendVoiceInit(Handle timer, int Serial)
{
int client;
if ((client = GetClientFromSerial(Serial)) == 0)
{
return Plugin_Handled;
}
if (IsValidClient(client))
{
SendCeltVoiceInit(client);
}
return Plugin_Handled;
}
/**
* Polls the signaling server for the current webclient controller's real IP.
* If the IP has changed since the last
* check and a webclient player is currently connected, forces them to
* reconnect with the new password via ClientCommand.
**/
public void PollWebclientCurrentIp()
{
Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, "http://127.0.0.1:3000/webclient-current-ip");
if (hRequest == null)
{
return;
}
if (!SteamWorks_SetHTTPCallbacks(hRequest, OnWebclientCurrentIpReceived) ||
!SteamWorks_SendHTTPRequest(hRequest))
{
delete hRequest;
}
}
public int OnWebclientCurrentIpReceived(Handle hRequest, bool bFailure, bool bRequestSuccessful,
EHTTPStatusCode eStatusCode, any data)
{
if (bFailure || !bRequestSuccessful || eStatusCode != k_EHTTPStatusCode200OK)
{
delete hRequest;
return 0;
}
int bodySize;
bool gotSize = SteamWorks_GetHTTPResponseBodySize(hRequest, bodySize);
char newIp[64];
newIp[0] = '\0';
if (gotSize && bodySize > 0 && bodySize < sizeof(newIp))
{
SteamWorks_GetHTTPResponseBodyData(hRequest, newIp, bodySize);
}
delete hRequest;
if (newIp[0] == '\0')
{
return 0;
}
if (StrEqual(newIp, g_sLastWebclientIp))
{
return 0;
}
for (int i = 1; i <= MaxClients; i++)
{
if (IsValidClient(i) && g_bWebclient[i])
{
strcopy(g_sLastWebclientIp, sizeof(g_sLastWebclientIp), newIp);
LogMessage("Forcing webclient reconnect for client %N with new IP: %s", i, newIp);
ClientCommand(i, "retry");
break;
}
}
return 0;
}
public EConnect OnClientPreConnectEx(const char[] sName, char sPassword[255], const char[] sIP, const char[] sSteam32ID, char sRejectReason[255])
{
char allowedIp[64];
ConVar sv_set_steam_id_ips = FindConVar("sv_set_steam_id_ips");
if (sv_set_steam_id_ips != null)
{
sv_set_steam_id_ips.GetString(allowedIp, sizeof(allowedIp));
//this is to handle that the connect extension receives the password parameter for the webclient as its real connecting IP.
//works both for the client command retry and for the case that somebody presses the connect button in the clients Menu as the same password
//is applied again.
if (StrEqual(sIP, allowedIp) && strlen(g_sLastWebclientIp) > 0)
{
strcopy(sPassword, 255, g_sLastWebclientIp);
LogMessage("Backfilled empty password for webclient with cached IP: %s", g_sLastWebclientIp);
}
}
// ET_LowEvent takes the LOWEST value returned across all plugins hooking this forward.
//this plugin returns 1 (Accept), meanwhile the reserved slot plugin still might return 0 (reject) or -1 (async) to overrule the decision from this return value.
return k_OnClientPreConnectEx_Accept;
}
stock bool IsValidClient(int client)
{
if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client))
return true;
return false;
}
@@ -0,0 +1 @@
{BLUE}{PLAYERTIER} {WHITE}{PLAYERTYPE} {GREEN}{NAME} {green}[{lightgreen}{STEAMID}{NOSTEAM}{green}] connected{COUNTRY}
+200 -1
View File
@@ -5,6 +5,7 @@
#include <multicolors> #include <multicolors>
#include <clientprefs> #include <clientprefs>
#include <PlayerManager> #include <PlayerManager>
#include <unloze_playtime>
#pragma newdecls required #pragma newdecls required
@@ -16,6 +17,8 @@ Database g_hDatabase;
Handle g_hCustomMessageFile; Handle g_hCustomMessageFile;
Handle g_hCustomMessageFile2; Handle g_hCustomMessageFile2;
static Handle g_hForwardConnectMessage;
bool g_bHideCsays[MAXPLAYERS + 1] = { false, ... }; bool g_bHideCsays[MAXPLAYERS + 1] = { false, ... };
Handle g_hCookieHideCsays = null; Handle g_hCookieHideCsays = null;
@@ -71,6 +74,17 @@ public void OnDatabaseConnect(Database db, const char[] error, any data)
g_hDatabase = db; g_hDatabase = db;
} }
public APLRes AskPluginLoad2(Handle myself, bool late, char [] error, int err_max)
{
g_hForwardConnectMessage = CreateGlobalForward("GetPlayerConnectMessage", ET_Ignore, Param_String);
return APLRes_Success;
}
public void OnPluginEnd()
{
CloseHandle(g_hForwardConnectMessage);
}
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// Purpose: // Purpose:
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -175,6 +189,7 @@ public int MenuHandler_MainMenu(Menu menu, MenuAction action, int client, int se
delete menu; delete menu;
} }
} }
return 0;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -290,6 +305,189 @@ public Action Command_ResetJoinMsg(int client, int args)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// Purpose: // Purpose:
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void GetPlayerTier(int client, int tier)
{
Handle hFile = OpenFile(g_sDataFile, "r");
static char sRawMsg[301];
if(hFile != INVALID_HANDLE)
{
ReadFileLine(hFile, sRawMsg, sizeof(sRawMsg));
TrimString(sRawMsg);
delete hFile;
}
else
{
LogError("[SM] File not found! (configs/ConnectAnnounce/settings.txt)");
return;
}
static char sIP[16];
static char sAuth[32];
static char sCountry[32];
static char sName[128];
GetClientAuthId(client, AuthId_Steam2, sAuth, sizeof(sAuth));
GetClientName(client, sName, sizeof(sName));
AdminId aid;
if(StrContains(sRawMsg, "{PLAYERTIER}"))
{
char s_tier[64];
Format(s_tier, sizeof(s_tier), "Tier %i", tier);
ReplaceString(sRawMsg, sizeof(sRawMsg), "{PLAYERTIER}", s_tier);
}
if(StrContains(sRawMsg, "{PLAYERTYPE}"))
{
aid = GetUserAdmin(client);
if(GetAdminFlag(aid, Admin_Cheats) || GetAdminFlag(aid, Admin_Root))
{
ReplaceString(sRawMsg, sizeof(sRawMsg), "{PLAYERTYPE}", "Root-Admin");
}
else if(GetAdminFlag(aid, Admin_Generic))
{
ReplaceString(sRawMsg, sizeof(sRawMsg), "{PLAYERTYPE}", "Admin");
}
else if(GetAdminFlag(aid, Admin_Custom1))
{
ReplaceString(sRawMsg, sizeof(sRawMsg), "{PLAYERTYPE}", "VIP");
}
/*
else if(GetAdminFlag(aid, Admin_Custom6))
{
ReplaceString(sRawMsg, sizeof(sRawMsg), "{PLAYERTYPE}", "Member");
}
*/
else
{
ReplaceString(sRawMsg, sizeof(sRawMsg), "{PLAYERTYPE}", "Player");
}
}
if(StrContains(sRawMsg, "{NOSTEAM}"))
{
if(!PM_IsPlayerSteam(client))
ReplaceString(sRawMsg, sizeof(sRawMsg), "{NOSTEAM}", " <NoSteam>");
else
ReplaceString(sRawMsg, sizeof(sRawMsg), "{NOSTEAM}", "");
}
if(StrContains(sRawMsg, "{STEAMID}"))
{
ReplaceString(sRawMsg, sizeof(sRawMsg), "{STEAMID}", sAuth);
}
if(StrContains(sRawMsg, "{NAME}"))
{
ReplaceString(sRawMsg, sizeof(sRawMsg), "{NAME}", sName);
}
if(StrContains(sRawMsg, "{COUNTRY}"))
{
if(GetClientIP(client, sIP, sizeof(sIP)) && GeoipCountry(sIP, sCountry, sizeof(sCountry)))
{
char sBuffer[128];
Format(sBuffer, sizeof(sBuffer), " from %s", sCountry);
ReplaceString(sRawMsg, sizeof(sRawMsg), "{COUNTRY}", sBuffer);
}
else
ReplaceString(sRawMsg, sizeof(sRawMsg), "{COUNTRY}", "");
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (!CheckCommandAccess(client, "sm_joinmsg", ADMFLAG_CUSTOM1))
{
CPrintToChatAll(sRawMsg);
Call_StartForward(g_hForwardConnectMessage);
Call_PushString(sRawMsg);
Call_Finish();
return;
}
delete g_hCustomMessageFile2;
g_hCustomMessageFile2 = CreateKeyValues("custom_messages");
if (!FileToKeyValues(g_hCustomMessageFile2, g_sCustomMessageFile))
{
SetFailState("[ConnectAnnounce] Config file missing!");
return;
}
KvRewind(g_hCustomMessageFile2);
char sBanned[16];
char sFinalMessage[512];
char sCustomMessage[256];
if (KvJumpToKey(g_hCustomMessageFile2, sAuth))
{
KvGetString(g_hCustomMessageFile2, "banned", sBanned, sizeof(sBanned), "");
KvGetString(g_hCustomMessageFile2, "message", sCustomMessage, sizeof(sCustomMessage), "");
if(StrEqual(sCustomMessage, "reset") || StrEqual(sBanned, "true"))
{
CPrintToChatAll(sRawMsg);
Call_StartForward(g_hForwardConnectMessage);
Call_PushString(sRawMsg);
Call_Finish();
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientInGame(i))
{
if(g_bHideCsays[i])
continue;
PrintCenterText(i, "%s %s %s", "[VIP]", sName, "connected");
}
}
}
else
{
Format(sFinalMessage, sizeof(sFinalMessage), "%s %s", sRawMsg, sCustomMessage);
CPrintToChatAll(sFinalMessage);
Call_StartForward(g_hForwardConnectMessage);
Call_PushString(sRawMsg);
Call_Finish();
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientInGame(i))
{
if(g_bHideCsays[i])
continue;
CRemoveTags(sCustomMessage, 256);
PrintCenterText(i, "%s %s %s %s", "[VIP]", sName, "connected", sCustomMessage);
}
}
}
}
else
{
CPrintToChatAll(sRawMsg);
Call_StartForward(g_hForwardConnectMessage);
Call_PushString(sRawMsg);
Call_Finish();
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientInGame(i))
{
if(g_bHideCsays[i])
continue;
PrintCenterText(i, "%s %s %s", "[VIP]", sName, "connected");
}
}
}
}
public void TQueryCB(Handle owner, Handle rs, const char[] error, any data) public void TQueryCB(Handle owner, Handle rs, const char[] error, any data)
{ {
int client = 0; int client = 0;
@@ -338,7 +536,6 @@ public void TQueryCB(Handle owner, Handle rs, const char[] error, any data)
if(StrContains(sRawMsg, "{PLAYERTYPE}")) if(StrContains(sRawMsg, "{PLAYERTYPE}"))
{ {
aid = GetUserAdmin(client); aid = GetUserAdmin(client);
if(GetAdminFlag(aid, Admin_Generic)) if(GetAdminFlag(aid, Admin_Generic))
@@ -492,7 +689,9 @@ public void OnClientPostAdminCheck(int client)
char sServer[16]; char sServer[16];
g_cvHlstatsServerName.GetString(sServer, sizeof(sServer)); g_cvHlstatsServerName.GetString(sServer, sizeof(sServer));
/*
char sQuery[512]; char sQuery[512];
Format(sQuery, sizeof(sQuery), "SELECT COUNT(*) AS 'rank' FROM hlstats_Players WHERE hlstats_Players.game = '%s' AND hideranking = 0 AND skill > (SELECT skill from hlstats_Players JOIN hlstats_PlayerUniqueIds ON hlstats_Players.playerId = hlstats_PlayerUniqueIds.playerId WHERE uniqueId = '%s' AND hlstats_PlayerUniqueIds.game = '%s')", sServer, sAuth, sServer); Format(sQuery, sizeof(sQuery), "SELECT COUNT(*) AS 'rank' FROM hlstats_Players WHERE hlstats_Players.game = '%s' AND hideranking = 0 AND skill > (SELECT skill from hlstats_Players JOIN hlstats_PlayerUniqueIds ON hlstats_Players.playerId = hlstats_PlayerUniqueIds.playerId WHERE uniqueId = '%s' AND hlstats_PlayerUniqueIds.game = '%s')", sServer, sAuth, sServer);
g_hDatabase.Query(TQueryCB, sQuery, GetClientUserId(client), DBPrio_High); g_hDatabase.Query(TQueryCB, sQuery, GetClientUserId(client), DBPrio_High);
*/
} }
@@ -0,0 +1,6 @@
#if defined _connect_announce_included_
#endinput
#endif
#define _connect_announce_included_
forward void GetPlayerConnectMessage(char[] message);
+50 -1
View File
@@ -5,6 +5,7 @@
#include <multicolors> #include <multicolors>
#include <sourcemod> #include <sourcemod>
#include <Discord_UNLOZE> #include <Discord_UNLOZE>
#include <connect_announce>
#define API_URL "" #define API_URL ""
#define BOT_TOKEN "" #define BOT_TOKEN ""
@@ -17,7 +18,7 @@ public Plugin myinfo =
name = "livechat stoat", name = "livechat stoat",
author = "jenz", author = "jenz",
description = "", description = "",
version = "1.1.0", version = "1.2.0",
url = "www.unloze.com" url = "www.unloze.com"
} }
@@ -73,6 +74,11 @@ public Action CommandListener_SmChat_stoat(int client, const char[] sCommand, in
if (client <= 0) if (client <= 0)
return Plugin_Continue; return Plugin_Continue;
if (!IsValidClient(client))
{
return Plugin_Continue;
}
char sText[256]; char sText[256];
char sUsername[32]; char sUsername[32];
@@ -192,6 +198,49 @@ public Action Command_PrintToAdminChat_stoat(int args)
return Plugin_Handled; return Plugin_Handled;
} }
//ai SLOP
void StripColorTags(char[] buffer, int maxlen)
{
int len = strlen(buffer);
int writeIndex = 0;
bool inside = false;
for (int i = 0; i < len; i++)
{
if (buffer[i] == '{')
{
inside = true;
continue;
}
else if (buffer[i] == '}')
{
inside = false;
continue;
}
if (!inside && writeIndex < maxlen - 1)
{
buffer[writeIndex] = buffer[i];
writeIndex++;
}
}
buffer[writeIndex] = '\0';
}
public void GetPlayerConnectMessage(char[] message)
{
StripColorTags(message, strlen(message));
if (i_port == 27015)
{
SendToStoat("", message, "");
}
else if (i_port == 27017)
{
SendToStoat("", message, "");
}
}
public void GetDiscordToStoat(const char[] username, const char[] message, int type) public void GetDiscordToStoat(const char[] username, const char[] message, int type)
{ {
//type = 1. ADMINLOGS //type = 1. ADMINLOGS
+80
View File
@@ -0,0 +1,80 @@
HAFL-LIFE_2
NoobDnoRaq
IMBA
ТАЩИР
ebaw-kak-t34
h4rdc0r3
omfg]wiz
GOdlikebAby
SHITSHITSHIT
-Impulse-
SLAVA_UKRAINE
4ik-pyk
BigBoss
lolkalalka
muhahahahaha
GFLClan.ru
nide.gg
vk.com/nide_css
alex481516
alahakbar
HeadShot
HolySHIT
CRAY_ZEE
mlpro
Deadmemories
MaGothic
ILoveYouBaby
nevazhno
Tauren
Calypso
Hawk
(1)HAFL-LIFE_2
(1)NoobDnoRaq
(1)Hawk
(1)Tauren
(1)mlpro
(1)CRAY_ZEE
(1)NF-CSS.RU
(1)Calypso
(1)BigBoss
HAFL-LIFE_2
NoobDnoRaq
IMBA
ТАЩИР
ebaw-kak-t34
h4rdc0r3
omfg]wiz
GOdlikebAby
SHITSHITSHIT
-Impulse-
SLAVA_UKRAINE
4ik-pyk
BigBoss
lolkalalka
muhahahahaha
cp.powerhub.ru
NiDE.GG
vk.com/nide_css
alex481516
alahakbar
HeadShot
HolySHIT
CRAY_ZEE
mlpro
Deadmemories
MaGothic
ILoveYouBaby
nevazhno
Tauren
Calypso
Hawk
(1)HAFL-LIFE_2
(1)NoobDnoRaq
(1)Hawk
(1)Tauren
(1)mlpro
(1)CRAY_ZEE
(1)NF-CSS.RU
(1)Calypso
(1)BigBoss
-114
View File
@@ -1,114 +0,0 @@
Dwelitram
Gwyri
Caredus
Arerawia
Vilali
Astiwiel
Vardonydd
Ybaossa
Umyk
Nico50Pax
Onand
Thelian
Nydaleth
Chomarin
Traedien
Miev
Kaaede
Koamond
TheRottenBenson
BigLegend2017
TRIGGEREDHarambexXx
InPepe2016
xXxMaster2012
InBoixXx
TheKopsing
Cornelius
Gustavo
Bryant
Winfred
Nicolas
Mitchel
Dana
Carrol
Darell
Ruben
Jeromy
Wade
Scotty
Salvatore
Kory
Don
Morgan
Kurtis
Federico
Darin
css-ru
aimbot
lastkraftwagenfahrzeug
edger
clownface
слово
счастливый
kara
puta
meow
uncle sam
FunBun
Counter-Strike.Com.Ua
For-css.Ru
BOBO
Z3r0
ZeTo
Sakharov
Sache11
Mr. Dogenberg
Maus
Magikarpet
Miles
magick
James Lebron
jiZZ
Dobel
THE POPE OF DOPE
The Joker
that guy over there
Be happy :)
KingKong
Figger Nucker
noname
alexdu63
I put babies in the microwave
Tango!!
faggot killer
admin pidaras
MESSI>RONALDO
Gabe Newell
acetylsalicylic acid
Country-Steak: Sauce
chlamydia harvester
kyle_69
Shaggy's dog
rEVERSE
Piment d'espelette
FireHawk
Sgt. Pepper
krix.
imPulse_^_
Lardon
CAPS LOCK
$pussymoneyweed$
Low5
Bonerfart
Shiny Thanos
MARK NUTT
Legless Runner
Banana is a berry
Gabriel
El Moustachio
James Bong
Disco Fever
Acacia
Sugared
ronald goddamn macdonald
pizza is life
+27
View File
@@ -0,0 +1,27 @@
"FakeClientsTiers"
{
"0" "23"
"3" "22"
"6" "21"
"9" "20"
"12" "19"
"15" "18"
"18" "17"
"21" "16"
"24" "15"
"27" "14"
"30" "13"
"33" "12"
"36" "11"
"39" "10"
"42" "9"
"45" "8"
"48" "7"
"51" "6"
"54" "5"
"55" "4"
"57" "3"
"60" "2"
"61" "1"
"62" "0"
}
+232 -311
View File
@@ -1,27 +1,18 @@
#include <sourcemod> #include <sourcemod>
#include <sdktools> #include <sdktools>
#include <zombiereloaded>
#include <BotTargeting>
#include <cstrike> #include <cstrike>
#pragma semicolon 1 #pragma semicolon 1
#pragma newdecls required #pragma newdecls required
#define MAXNAMES 500
ArrayList g_hNames; ArrayList g_hNames;
ArrayList g_hClanNames; ArrayList g_hClanNames;
bool g_bMapEnded;
int g_iBaseLatency[MAXPLAYERS + 1]; int g_iBaseLatency[MAXPLAYERS + 1];
int g_iLatency[MAXPLAYERS + 1]; int g_iLatency[MAXPLAYERS + 1];
int g_iPlayerCount;
int g_iAdminFakes; bool g_bMapended;
int g_iPopulation;
bool g_bCheckRequested;
bool g_bBlockInstantFakeConnects;
Database g_hDatabase; Database g_hDatabase;
Database g_hDatabase_hlstats; Database g_hDatabase_hlstats;
@@ -31,10 +22,10 @@ Database g_hDatabase_hlstats;
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public Plugin myinfo = public Plugin myinfo =
{ {
name = "ImprovedHitboxes", //camouflage name = "fakes",
author = "Neon + Dogan + Botox", author = "Neon + Dogan + Botox",
description = "Handle Hitboxes via Plugin", description = "Handle Hitboxes via Plugin",
version = "5.3.1", version = "5.4.1",
url = "https://steamcommunity.com/id/n3ontm" url = "https://steamcommunity.com/id/n3ontm"
}; };
@@ -45,28 +36,19 @@ public void OnPluginStart()
{ {
RegAdminCmd("sm_debugfakes", Command_DebugFakes, ADMFLAG_GENERIC, "Shows the amount of fake-clients on server"); RegAdminCmd("sm_debugfakes", Command_DebugFakes, ADMFLAG_GENERIC, "Shows the amount of fake-clients on server");
RegAdminCmd("sm_fakes", Command_Fakes, ADMFLAG_GENERIC, "Shows the fake-clients on server"); RegAdminCmd("sm_fakes", Command_Fakes, ADMFLAG_GENERIC, "Shows the fake-clients on server");
RegAdminCmd("sm_setfakes", Command_SetFakes, ADMFLAG_RCON, "Manually sets the amount of fake-clients");
int arraySize = ByteCountToCells(MAX_NAME_LENGTH); int arraySize = ByteCountToCells(MAX_NAME_LENGTH);
g_hNames = CreateArray(arraySize); g_hNames = CreateArray(arraySize);
g_hClanNames = CreateArray(arraySize); g_hClanNames = CreateArray(arraySize);
g_iAdminFakes = -1; CreateTimer(GetRandomFloat(20.0, 40.0), RunPopulationCheck, _, TIMER_REPEAT);
g_iPopulation = GetClientCount(false);
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientConnected(i) && IsFakeClient(i) && !IsClientSourceTV(i))
g_iPopulation--;
}
g_bMapEnded = false;
g_bBlockInstantFakeConnects = false;
CreateTimer(10.0, BlockInstantFakeConnects, _, TIMER_REPEAT);
CreateTimer(3.0, RandomizePing, _, TIMER_REPEAT); CreateTimer(3.0, RandomizePing, _, TIMER_REPEAT);
CreateTimer(150.0, RandomizeNames, _, TIMER_REPEAT); CreateTimer(600.0, RandomizeNames, _, TIMER_REPEAT);
CreateTimer(80.0, CheckPopulation_interval, _, TIMER_REPEAT);
HookUserMessage(GetUserMessageId("SayText2"), UserMessage_SayText2, true); HookUserMessage(GetUserMessageId("SayText2"), UserMessage_SayText2, true);
RequestFrame(CheckPopulation); g_bMapended = false;
if (!g_hDatabase) if (!g_hDatabase)
{ {
@@ -76,6 +58,7 @@ public void OnPluginStart()
{ {
Database.Connect(SQL_OnDatabaseConnect_hlstats, "hlstatsx"); Database.Connect(SQL_OnDatabaseConnect_hlstats, "hlstatsx");
} }
g_iPlayerCount = 0;
} }
public void SQL_OnDatabaseConnect_hlstats(Database db, const char[] error, any data) public void SQL_OnDatabaseConnect_hlstats(Database db, const char[] error, any data)
@@ -92,7 +75,7 @@ public void SQL_OnDatabaseConnect_hlstats(Database db, const char[] error, any d
public void randomize_clantags() public void randomize_clantags()
{ {
char sQuery[512]; char sQuery[512];
Format(sQuery, sizeof(sQuery), "select DISTINCT tag from unloze_stats.hlstats_Clans ORDER BY RAND() limit 500"); Format(sQuery, sizeof(sQuery), "select DISTINCT tag from unloze_stats.hlstats_Clans ORDER BY RAND() limit 1000");
g_hDatabase_hlstats.Query(SQL_OnQueryCompleted_hlstats, sQuery, DBPrio_High); g_hDatabase_hlstats.Query(SQL_OnQueryCompleted_hlstats, sQuery, DBPrio_High);
} }
@@ -110,7 +93,7 @@ public void SQL_OnDatabaseConnect(Database db, const char[] error, any data)
public void randomize_names() public void randomize_names()
{ {
char sQuery[512]; char sQuery[512];
Format(sQuery, sizeof(sQuery), "select name from unloze_racetimer_css.random_names ORDER BY RAND() limit 500"); Format(sQuery, sizeof(sQuery), "select name from unloze_racetimer_css.random_names ORDER BY RAND() limit 1000");
g_hDatabase.Query(SQL_OnQueryCompleted, sQuery, DBPrio_High); g_hDatabase.Query(SQL_OnQueryCompleted, sQuery, DBPrio_High);
} }
@@ -158,19 +141,9 @@ public void SQL_OnQueryCompleted(Database db, DBResultSet results, const char[]
delete results; delete results;
} }
//---------------------------------------------------------------------------------------------------- public void OnMapEnd()
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnPluginEnd()
{ {
for(int i = 1; i <= MaxClients; i++) g_bMapended = true;
{
if(IsClientConnected(i) && IsFakeClient(i) && !IsClientSourceTV(i))
{
g_iLatency[i] = 0;
KickClient(i, "Disconnect by user.");
}
}
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -178,80 +151,129 @@ public void OnPluginEnd()
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void OnMapStart() public void OnMapStart()
{ {
g_hNames.Clear(); KeyValues kv = CreateKeyValues("ints_used_already");
g_hClanNames.Clear(); int fakes_needed = getFakesNeeded();
if (!g_hDatabase) for (float i = 0.0; i < fakes_needed;)
{ {
Database.Connect(SQL_OnDatabaseConnect, "racetimercss"); int num = GetRandomInt(5, 45);
char strnum[16];
IntToString(num, strnum, sizeof(strnum));
int found = kv.GetNum(strnum, -1);
if (found != -1)
{
continue;
}
kv.SetNum(strnum, num);
i += 1.0;
CreateTimer(float(num), addfakes);
} }
else delete kv;
{
randomize_names();
}
if (!g_hDatabase_hlstats)
{
Database.Connect(SQL_OnDatabaseConnect_hlstats, "hlstatsx");
}
else
{
randomize_clantags();
}
/*
char sFile[PLATFORM_MAX_PATH];
char sLine[MAX_NAME_LENGTH];
BuildPath(Path_SM, sFile, sizeof(sFile), "configs/fakeclients_names.txt");
Handle hFile = OpenFile(sFile, "r");
if(hFile != INVALID_HANDLE)
{
int iLine = 0;
g_hNames.Clear();
while (!IsEndOfFile(hFile))
{
if (!ReadFileLine(hFile, sLine, sizeof(sLine)) || iLine >= MAXNAMES)
break;
TrimString(sLine);
g_hNames.PushString(sLine);
iLine++;
}
delete hFile;
}
else
SetFailState("Could not open file: configs/fakeclients_names.txt");
*/
g_bMapEnded = false;
g_bBlockInstantFakeConnects = false;
} }
//---------------------------------------------------------------------------------------------------- public int getFakesNeeded()
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnMapEnd()
{ {
g_bMapEnded = true; //copied from nide fakeclients plugin.
g_iAdminFakes = -1; char sPath[PLATFORM_MAX_PATH];
g_iPopulation = GetClientCount(false); BuildPath(Path_SM, sPath, sizeof(sPath), "configs/fakeclients_tiers.cfg");
KeyValues kv = new KeyValues("FakeClientsTiers");
if (!kv.ImportFromFile(sPath))
{
LogError("configs/fakeclients_tiers.cfg not found — falling back to sm_fakeclients_players");
delete kv;
return 0;
}
if (!kv.GotoFirstSubKey(false))
{
LogError("configs/fakeclients_tiers.cfg is empty or malformed");
delete kv;
return 0;
}
int prev_bots = 0;
do
{
char sKey[16], sVal[16];
kv.GetSectionName(sKey, sizeof(sKey));
kv.GetString(NULL_STRING, sVal, sizeof(sVal), "-1");
int bots = StringToInt(sVal);
int players = StringToInt(sKey);
if (players > g_iPlayerCount)
{
break;
}
prev_bots = bots;
} while (kv.GotoNextKey(false));
delete kv;
//LogMessage("prev_bots: %i", prev_bots);
return prev_bots;
}
public Action addfakes(Handle timer)
{
int limit = getFakesNeeded();
int fakes = 0;
for(int i = 1; i <= MaxClients; i++) for(int i = 1; i <= MaxClients; i++)
{ {
if(IsClientConnected(i) && IsFakeClient(i) && !IsClientSourceTV(i)) if (IsClientConnected(i) && IsClientInGame(i) && IsClientAuthorized(i))
g_iPopulation--; {
if (IsFakeClient(i) && !IsClientSourceTV(i))
{
fakes++;
}
}
} }
if (nightTime())
{
limit /= 2;
}
if (fakes < limit)
{
CreateFake();
}
return Plugin_Continue;
}
public Action CheckPopulation_interval(Handle timer)
{
int TimeLeft;
if (GetMapTimeLeft(TimeLeft) && TimeLeft < 0)
{
return Plugin_Continue;
}
if (g_bMapended)
{
g_bMapended = false;
return Plugin_Continue;
}
g_iPlayerCount = 0;
for(int i = 1; i <= MaxClients; i++)
{
if (IsClientConnected(i) && IsClientInGame(i) && IsClientAuthorized(i))
{
if (!IsFakeClient(i) && !IsClientSourceTV(i))
{
g_iPlayerCount++;
}
}
}
return Plugin_Handled;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// Purpose: // Purpose:
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public Action BlockInstantFakeConnects(Handle timer) public Action RunPopulationCheck(Handle timer)
{ {
g_bBlockInstantFakeConnects = false; CheckPopulation();
RequestFrame(CheckPopulation);
return Plugin_Continue; return Plugin_Continue;
} }
@@ -359,45 +381,17 @@ public Action Command_DebugFakes(int client, int argc)
{ {
continue; continue;
} }
if (IsFakeClient(i) || IsClientSourceTV(i)) if (IsFakeClient(i) && !IsClientSourceTV(i))
{ {
iFakes++; iFakes++;
iPlayers--; iPlayers--;
} }
if (IsFakeClient(i) && GetClientTeam(i) > 0) if (IsFakeClient(i) && GetClientTeam(i) > CS_TEAM_SPECTATOR)
iFakesInTeam++; iFakesInTeam++;
} }
ReplyToCommand(client, "[SM] There are currently %d Fake-Clients, from which %d are in Spectate.", iFakes, iFakes - iFakesInTeam); ReplyToCommand(client, "[SM] There are currently %d Fake-Clients, from which %d are in Spectate. Real Clients %d", iFakes, iFakes - iFakesInTeam, iPlayers);
ReplyToCommand(client, "[SM] Server Population at the end of the previous Map: %d.", g_iPopulation);
ReplyToCommand(client, "[SM] Current Server Population: %d. Difference: %d.", iPlayers, iPlayers - g_iPopulation);
return Plugin_Handled;
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action Command_SetFakes(int client, int argc)
{
if (argc < 1)
{
ReplyToCommand(client, "[SM] Usage: sm_setfakes <amount of fakes>");
return Plugin_Handled;
}
char sArgs[16];
GetCmdArg(1, sArgs, sizeof(sArgs));
if (!StringToIntEx(sArgs, g_iAdminFakes))
{
ReplyToCommand(client, "[SM] Invalid value");
return Plugin_Handled;
}
ReplyToCommand(client, "[SM] You set the amount of Fake-Clients to %d.", g_iAdminFakes);
CheckPopulation();
return Plugin_Handled; return Plugin_Handled;
} }
@@ -433,18 +427,6 @@ public Action Command_Fakes(int client, int args)
return Plugin_Handled; return Plugin_Handled;
} }
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientConnected(int client)
{
if (!g_bCheckRequested && !IsFakeClient(client) && !IsClientSourceTV(client))
{
RequestFrame(CheckPopulation);
g_bCheckRequested = true;
}
}
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// Purpose: // Purpose:
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -456,182 +438,131 @@ public void OnClientDisconnect(int client)
{ {
g_iLatency[client] = 0; g_iLatency[client] = 0;
} }
if (!g_bCheckRequested && !IsFakeClient(client) && !IsClientSourceTV(client))
{
RequestFrame(CheckPopulation);
g_bCheckRequested = true;
}
} }
} }
public Action repeatCheckPopulation(Handle timer)
{
CheckPopulation();
return Plugin_Continue;
}
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// Purpose: // Purpose:
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void CheckPopulation() public void CheckPopulation()
{
int fakes = 0;
int last_fake = 0;
for(int i = 1; i <= MaxClients; i++)
{
if (IsClientConnected(i) && IsClientInGame(i) && IsClientAuthorized(i))
{
if (IsFakeClient(i) && !IsClientSourceTV(i))
{
fakes++;
last_fake = i;
}
}
}
int fakes_needed = getFakesNeeded();
if (nightTime())
{
fakes_needed /= 2;
}
if (fakes > fakes_needed && last_fake != 0)
{
g_iLatency[last_fake] = 0;
KickClient(last_fake, "Disconnect by user.");
}
else if (fakes < fakes_needed)
{
CreateFake();
}
}
public bool nightTime()
{
char sTime[8];
FormatTime(sTime, sizeof(sTime), "%H%M");
int CurTime = StringToInt(sTime);
int MinTime = 2300;
int MaxTime = 400;
//Wrap around.
CurTime = (CurTime <= MinTime) ? CurTime + 2400 : CurTime;
MaxTime = (MaxTime <= MinTime) ? MaxTime + 2400 : MaxTime;
if ((MinTime <= CurTime <= MaxTime))
{
return true;
}
return false;
}
//not used anymore
public void SetFakeToTeam()
{
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientConnected(i) && IsFakeClient(i) && !IsClientSourceTV(i) && GetClientTeam(i) <= CS_TEAM_SPECTATOR)
{
ChangeClientTeam(i, CS_TEAM_CT);
FakeClientCommandEx(i, "joinclass");
break;
}
}
}
public void CreateFake()
{ {
if (g_hNames.Length == 0 || g_hClanNames.Length == 0) if (g_hNames.Length == 0 || g_hClanNames.Length == 0)
{ {
CreateTimer(5.0, repeatCheckPopulation);
return; return;
} }
g_bCheckRequested = false; ArrayList hNames = g_hNames.Clone();
char sName[MAX_NAME_LENGTH];
if(g_bMapEnded) for(int i = 1; i <= MaxClients; i++)
return;
int iPlayers = GetClientCount(false);
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientConnected(i) && IsClientInGame(i) && IsClientAuthorized(i) && (IsFakeClient(i) || IsClientAutismBot(i) || IsClientSourceTV(i) || GetClientTeam(i) == CS_TEAM_SPECTATOR))
iPlayers--;
}
int iFakes = 0;
int iFakesInTeam = 0;
for(int i = 1; i <= MaxClients; i++)
{
if (IsClientConnected(i) && IsFakeClient(i) && !IsClientSourceTV(i))
iFakes++;
}
int iFakesInTeamNeeded = iPlayers;
int iFakesNeeded = iPlayers;
int full_client_count = GetClientCount(false);
if (full_client_count > 50) //counting all clients in total.
{
iFakesInTeamNeeded = 0;
iFakesNeeded = 0;
}
else if (full_client_count >= 42)
{ {
if(IsClientConnected(i) && IsFakeClient(i) && !IsClientSourceTV(i))
{
GetClientName(i, sName, sizeof(sName));
int iPos = hNames.FindString(sName);
if (iPos > -1)
hNames.Erase(iPos);
}
}
int iRand = GetRandomInt(0, hNames.Length - 1);
hNames.GetString(iRand, sName, sizeof(sName));
delete hNames;
int iIndex = CreateFakeClient(sName);
if(iIndex < 1 || iIndex > MaxClients)
return; return;
SetEntityFlags(iIndex, FL_CLIENT);
DispatchKeyValue(iIndex, "classname", "player");
DispatchSpawn(iIndex);
g_iBaseLatency[iIndex] = GetRandomInt(20, 110);
g_iLatency[iIndex] = g_iBaseLatency[iIndex];
AdminId FakeAdmin = CreateAdmin();
SetAdminFlag(FakeAdmin, Admin_Custom6, true);
SetUserAdmin(iIndex, FakeAdmin, true);
if (GetRandomInt(0, 5) >= 3)
{
ArrayList hClanNames = g_hClanNames.Clone();
iRand = GetRandomInt(0, hClanNames.Length - 1);
hClanNames.GetString(iRand, sName, sizeof(sName));
delete hClanNames;
CS_SetClientClanTag(iIndex, sName);
} }
else else
{
iFakesInTeamNeeded = (iFakesNeeded / 5);
}
if (iFakesInTeamNeeded < 0)
{ {
iFakesInTeamNeeded = 0; CS_SetClientClanTag(iIndex, "");
} }
if (iFakes != iFakesNeeded)
{
while (iFakes < iFakesNeeded && !g_bBlockInstantFakeConnects)
{
ArrayList hNames = g_hNames.Clone();
char sName[MAX_NAME_LENGTH];
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientConnected(i) && IsFakeClient(i) && !IsClientSourceTV(i))
{
GetClientName(i, sName, sizeof(sName));
int iPos = hNames.FindString(sName);
if (iPos > -1)
hNames.Erase(iPos);
}
}
int iRand = GetRandomInt(0, hNames.Length - 1);
hNames.GetString(iRand, sName, sizeof(sName));
delete hNames;
int iIndex = CreateFakeClient(sName);
if(iIndex < 1 || iIndex > MaxClients)
return;
SetEntityFlags(iIndex, FL_CLIENT);
DispatchKeyValue(iIndex, "classname", "player");
DispatchSpawn(iIndex);
g_iBaseLatency[iIndex] = GetRandomInt(20, 110);
g_iLatency[iIndex] = g_iBaseLatency[iIndex];
AdminId FakeAdmin = CreateAdmin();
SetAdminFlag(FakeAdmin, Admin_Custom6, true);
SetUserAdmin(iIndex, FakeAdmin, true);
if (GetRandomInt(0, 5) >= 3)
{
ArrayList hClanNames = g_hClanNames.Clone();
iRand = GetRandomInt(0, hClanNames.Length - 1);
hClanNames.GetString(iRand, sName, sizeof(sName));
delete hClanNames;
CS_SetClientClanTag(iIndex, sName);
}
else
{
CS_SetClientClanTag(iIndex, "");
}
iFakes++;
g_bBlockInstantFakeConnects = true;
}
if (iFakes > iFakesNeeded)
{
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientConnected(i) && IsFakeClient(i) && !IsClientSourceTV(i))
{
g_iLatency[i] = 0;
KickClient(i, "Disconnect by user.");
iFakes--;
break;
}
}
}
}
for(int i = 1; i <= MaxClients; i++)
{
if (IsClientConnected(i) && IsFakeClient(i) && !IsClientSourceTV(i) && GetClientTeam(i) >= CS_TEAM_T)
iFakesInTeam++;
}
if (iFakesInTeam != iFakesInTeamNeeded && g_iAdminFakes == -1)
{
if (iFakesInTeam < iFakesInTeamNeeded)
{
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientConnected(i) && IsFakeClient(i) && !IsClientSourceTV(i) && GetClientTeam(i) <= CS_TEAM_SPECTATOR)
{
ChangeClientTeam(i, CS_TEAM_CT);
FakeClientCommandEx(i, "joinclass");
iFakesInTeam++;
break;
}
}
}
if (iFakesInTeam > iFakesInTeamNeeded)
{
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientConnected(i) && IsFakeClient(i) && !IsClientSourceTV(i) && GetClientTeam(i) >= CS_TEAM_T)
{
ChangeClientTeam(i, CS_TEAM_SPECTATOR);
iFakesInTeam--;
break;
}
}
}
}
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -652,13 +583,3 @@ public void OnGameFrame()
} }
} }
} }
/*
public Action ZR_OnClientMotherZombieEligible(int client)
{
if (IsClientConnected(i) && IsFakeClient(i) && !IsClientSourceTV(i))
return Plugin_Handled;
return Plugin_Continue;
}
*/
+480
View File
@@ -0,0 +1,480 @@
#pragma semicolon 1
#pragma newdecls required
#include <sourcemod>
#include <sdktools>
#include <cstrike>
#define MAX_TIERS 32
ConVar g_hCount;
ConVar g_hDelay;
ConVar g_hUseTiers;
ArrayList g_hNames;
int g_iTierThreshold[MAX_TIERS]; // real player count that triggers this tier
int g_iTierMaxBots[MAX_TIERS]; // max bots allowed for this tier
int g_iTierCount = 0;
int g_iPendingBots = 0;
bool g_bUseTiers = false;
public Plugin myinfo = {
name = "FakeClients",
author = "Tsunami, .Rushaway",
description = "Put fake clients in server with tier system",
version = "3.0.0",
url = "https://github.com/srcdslab/sm-plugin-FakeClients"
}
public void OnPluginStart()
{
g_hCount = CreateConVar("sm_fakeclients_players", "8", "Fallback: number of bots when tier system is disabled", _, true, 0.0, true, 64.0);
g_hDelay = CreateConVar("sm_fakeclients_delay", "120", "Delay after map change before fake clients join (seconds)", _, true, 0.0, true, 10000.0);
g_hUseTiers = CreateConVar("sm_fakeclients_tiers", "0", "Use tier system from fakeclients_tiers.cfg (1 = enabled, 0 = disabled)", _, true, 0.0, true, 1.0);
g_bUseTiers = g_hUseTiers.BoolValue;
g_hUseTiers.AddChangeHook(OnConVarChanged);
RegAdminCmd("sm_debugfakes", Command_DebugFakes, ADMFLAG_GENERIC, "Shows the amount of fake-clients on server");
RegAdminCmd("sm_fakes", Command_Fakes, ADMFLAG_GENERIC, "Shows the fake-clients on server");
AutoExecConfig(true);
}
public Action Command_DebugFakes(int client, int argc)
{
int iFakes = 0;
int iFakesInTeam = 0;
int iPlayers = GetClientCount(false);
for(int i = 1; i <= MaxClients; i++)
{
if (!IsClientConnected(i))
{
continue;
}
if (IsFakeClient(i) || IsClientSourceTV(i))
{
iFakes++;
iPlayers--;
}
if (IsFakeClient(i) && GetClientTeam(i) > CS_TEAM_SPECTATOR)
iFakesInTeam++;
}
ReplyToCommand(client, "[SM] There are currently %d Fake-Clients, from which %d are in Spectate. Real Clients %d", iFakes, iFakes - iFakesInTeam, iPlayers);
return Plugin_Handled;
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action Command_Fakes(int client, int args)
{
char aBuf[1024];
char aBuf2[MAX_NAME_LENGTH];
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientInGame(i))
{
if(IsClientConnected(i) && IsFakeClient(i) && !IsClientSourceTV(i))
{
GetClientName(i, aBuf2, sizeof(aBuf2));
StrCat(aBuf, sizeof(aBuf), aBuf2);
StrCat(aBuf, sizeof(aBuf), ", ");
}
}
}
if(strlen(aBuf))
{
aBuf[strlen(aBuf) - 2] = 0;
ReplyToCommand(client, "[SM] Fake-Clients online: %s", aBuf);
}
else
ReplyToCommand(client, "[SM] Fake-Clients online: none");
return Plugin_Handled;
}
public void OnMapStart()
{
ParseNames();
ParseTiers();
CreateTimer(g_hDelay.FloatValue, Timer_CreateFakeClients, _, TIMER_FLAG_NO_MAPCHANGE);
}
public void OnConVarChanged(ConVar hConVar, const char[] sOldValue, const char[] sNewValue)
{
if (hConVar == g_hUseTiers)
{
g_bUseTiers = g_hUseTiers.BoolValue;
LogMessage("Tier system %s", g_bUseTiers ? "enabled" : "disabled");
if (g_bUseTiers)
{
g_iPendingBots = 0;
for (int i = 1; i <= MaxClients; i++)
{
if (!IsClientConnected(i) || !IsClientInGame(i))
continue;
if (!IsFakeClient(i) || IsClientSourceTV(i))
continue;
KickClient(i, "Client Disconnect");
}
// Wait a moment for all bots to be kicked before trying to add new ones according to tiers.
CreateTimer(1.0, Timer_CreateFakeClients, _, TIMER_FLAG_NO_MAPCHANGE);
}
else
{
AdjustFakeClientsToTier();
}
}
}
/**
* Returns the target bot count based on the current number of real players.
* Falls back to sm_fakeclients_players if tiers are disabled or not loaded.
*/
int GetTargetBotCount(int iRealPlayers)
{
if (!g_bUseTiers || g_iTierCount == 0)
return g_hCount.IntValue;
// Walk tiers from highest threshold down, pick the first one that applies
for (int t = g_iTierCount - 1; t >= 0; t--)
{
if (iRealPlayers >= g_iTierThreshold[t])
return g_iTierMaxBots[t];
}
// No tier matched (e.g. config missing threshold "0")
LogMessage("Warning: no tier matched for %d real players, defaulting to 0 bots", iRealPlayers);
return 0;
}
/**
* Computes the clamped target bot count, accounting for available slots and
* server over-capacity. Shared by AdjustFakeClientsToTier and OnClientPutInServer.
*/
int ComputeTarget(int iBots, int iRealPlayers, int iReservedSlots)
{
int iTarget = GetTargetBotCount(iRealPlayers);
if (iTarget < 0)
iTarget = 0;
// Bots currently being added already count as occupied slots
int iEffectiveBots = iBots + g_iPendingBots;
int iFreeSlots = MaxClients - (iRealPlayers + iEffectiveBots + iReservedSlots);
if (iFreeSlots < 0)
{
iTarget = iEffectiveBots + iFreeSlots;
if (iTarget < 0)
iTarget = 0;
}
else
{
int iMaxBotsBySlots = iEffectiveBots + iFreeSlots;
if (iTarget > iMaxBotsBySlots)
iTarget = iMaxBotsBySlots;
}
return iTarget;
}
/**
* Kicks excess bots until the bot count reaches iTarget.
* Never kicks real players or SourceTV.
*/
void KickExcessBots(int iBots, int iRealPlayers, int iTarget)
{
int iToKick = iBots - iTarget;
int iKicked = 0;
for (int i = 1; i <= MaxClients && iKicked < iToKick; i++)
{
if (!IsClientConnected(i) || !IsClientInGame(i))
continue;
// Safety: never kick real players or SourceTV
if (!IsFakeClient(i) || IsClientSourceTV(i))
continue;
LogMessage("Kicking fake client '%N' (slot %d) — bots:%d target:%d", i, i, iBots, iTarget);
KickClient(i, "Client Disconnect");
iKicked++;
}
if (iKicked > 0)
LogMessage("Kicked %d bot(s) — real:%d bots:%d target:%d slots:%d", iKicked, iRealPlayers, iBots, iTarget, MaxClients);
}
/**
* Schedules staggered timers to add bots up to iToAdd, respecting free slots.
*/
void ScheduleBotsToAdd(int iToAdd, int iFreeSlots)
{
if (iFreeSlots <= 0 || iToAdd <= 0)
return;
if (iToAdd > iFreeSlots)
iToAdd = iFreeSlots;
// Keep a staggered cadence but add jitter so joins look less scripted.
float fNextDelay = GetRandomFloat(0.4, 1.2);
for (int j = 0; j < iToAdd; j++)
{
g_iPendingBots++;
CreateTimer(fNextDelay, Timer_CreateFakeClient, _, TIMER_FLAG_NO_MAPCHANGE);
fNextDelay += GetRandomFloat(0.7, 1.9);
}
}
/**
* Compares current bot count against the target and either kicks excess bots
* or schedules new ones to fill the gap.
*/
void AdjustFakeClientsToTier()
{
int iBots, iRealPlayers, iReservedSlots;
CollectClientCounts(iBots, iRealPlayers, iReservedSlots);
int iTarget = ComputeTarget(iBots, iRealPlayers, iReservedSlots);
int iFreeSlots = MaxClients - (iRealPlayers + iBots + iReservedSlots);
// Too many active bots -> kick extras
if (iBots > iTarget)
{
g_iPendingBots = 0;
KickExcessBots(iBots, iRealPlayers, iTarget);
}
// Active + pending bots are below target -> add missing bots
else if ((iBots + g_iPendingBots) < iTarget)
ScheduleBotsToAdd(iTarget - iBots - g_iPendingBots, iFreeSlots);
}
/**
* Collects fake bots, real players and reserved slots in a single client loop.
*/
void CollectClientCounts(int &iBots, int &iRealPlayers, int &iReservedSlots)
{
iBots = 0;
iRealPlayers = 0;
bool bHasSourceTV = false;
for (int i = 1; i <= MaxClients; i++)
{
if (!IsClientConnected(i))
continue;
if (IsClientSourceTV(i))
{
bHasSourceTV = true;
continue; // SourceTV occupies its own slot in MaxClients — do not count it as a bot
}
if (IsFakeClient(i))
iBots++;
else
iRealPlayers++;
}
// Reserve 1 free slot so a real player can always connect.
// When SourceTV is active, reserve 1 extra (SourceTV's slot is already in MaxClients).
iReservedSlots = bHasSourceTV ? 2 : 1;
}
public void OnClientPutInServer(int client)
{
// Skip fake clients: bot additions are managed via timers.
// Calling AdjustFakeClientsToTier on every bot join would cause cascading timers.
if (!client || IsFakeClient(client))
return;
// A real player joined: only kick excess bots, never schedule additions.
// Scheduling here would race with the staggered timers already in flight.
int iBots, iRealPlayers, iReservedSlots;
CollectClientCounts(iBots, iRealPlayers, iReservedSlots);
int iTarget = ComputeTarget(iBots, iRealPlayers, iReservedSlots);
if (iBots > iTarget)
KickExcessBots(iBots, iRealPlayers, iTarget);
}
public void OnClientDisconnect(int client)
{
// Ignore bot disconnects (caused by our own kicks) to avoid cascading timers.
if (IsFakeClient(client))
return;
CreateTimer(0.5, Timer_CreateFakeClients, _, TIMER_FLAG_NO_MAPCHANGE);
}
public Action Timer_CreateFakeClient(Handle timer)
{
g_iPendingBots--;
if (g_iPendingBots < 0)
g_iPendingBots = 0;
int iBots, iRealPlayers, iReservedSlots;
CollectClientCounts(iBots, iRealPlayers, iReservedSlots);
int iTarget = ComputeTarget(iBots, iRealPlayers, iReservedSlots);
int iFreeSlots = MaxClients - (iRealPlayers + iBots + iReservedSlots);
// Recheck: tier may have changed since this timer was scheduled
if (iFreeSlots <= 0 || iBots >= iTarget)
return Plugin_Handled;
char sName[MAX_NAME_LENGTH];
char sTarget[MAX_TARGET_LENGTH];
int iTargets[MAXPLAYERS];
bool bTN_Is_ML;
// Pick a random name, re-roll if it's already taken by a fake client.
// Stop after trying all available names to prevent an infinite loop when
// the name list is smaller than the number of bots (duplicates are allowed).
// If no names are configured, CreateFakeClient will assign a default name based on the engine.
int iNameCount = g_hNames.Length;
if (iNameCount > 0)
{
g_hNames.GetString(GetRandomInt(0, iNameCount - 1), sName, sizeof(sName));
for (int iAttempt = 1; iAttempt < iNameCount; iAttempt++)
{
if (ProcessTargetString(sName, 0, iTargets, MAXPLAYERS, COMMAND_FILTER_NO_MULTI, sTarget, MAX_TARGET_LENGTH, bTN_Is_ML) != 1 || !IsFakeClient(iTargets[0]))
break;
g_hNames.GetString(GetRandomInt(0, iNameCount - 1), sName, sizeof(sName));
}
}
CreateFakeClient(sName);
return Plugin_Handled;
}
public Action Timer_CreateFakeClients(Handle timer)
{
AdjustFakeClientsToTier();
return Plugin_Continue;
}
/**
* Loads tier thresholds from configs/fakeclients_tiers.cfg. Max 32 tiers.
* Format (KeyValues):
*
* "FakeClientsTiers"
* {
* "0" "12" // 0 real players → up to 12 bots
* "5" "10" // 5+ real players → up to 10 bots
* "15" "8" // And so on...
* }
*
* Entries are sorted by threshold automatically, so order in the file
* does not matter.
*/
stock void ParseTiers()
{
if (!g_bUseTiers)
return;
g_iTierCount = 0;
char sPath[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sPath, sizeof(sPath), "configs/fakeclients_tiers.cfg");
KeyValues kv = new KeyValues("FakeClientsTiers");
if (!kv.ImportFromFile(sPath))
{
LogError("configs/fakeclients_tiers.cfg not found — falling back to sm_fakeclients_players");
g_hUseTiers.BoolValue = false;
delete kv;
return;
}
if (!kv.GotoFirstSubKey(false))
{
LogError("configs/fakeclients_tiers.cfg is empty or malformed");
g_hUseTiers.BoolValue = false;
delete kv;
return;
}
do
{
if (g_iTierCount >= MAX_TIERS)
break;
char sKey[16], sVal[16];
kv.GetSectionName(sKey, sizeof(sKey));
kv.GetString(NULL_STRING, sVal, sizeof(sVal), "-1");
int iMaxBots = StringToInt(sVal);
if (iMaxBots < 0)
continue; // skip malformed lines
g_iTierThreshold[g_iTierCount] = StringToInt(sKey);
g_iTierMaxBots[g_iTierCount] = iMaxBots;
g_iTierCount++;
} while (kv.GotoNextKey(false));
delete kv;
// Bubble sort tiers by threshold (ascending) so GetTargetBotCount() works correctly
for (int i = 0; i < g_iTierCount - 1; i++)
{
for (int j = 0; j < g_iTierCount - 1 - i; j++)
{
if (g_iTierThreshold[j] > g_iTierThreshold[j + 1])
{
int tmp;
tmp = g_iTierThreshold[j]; g_iTierThreshold[j] = g_iTierThreshold[j + 1]; g_iTierThreshold[j + 1] = tmp;
tmp = g_iTierMaxBots[j]; g_iTierMaxBots[j] = g_iTierMaxBots[j + 1]; g_iTierMaxBots[j + 1] = tmp;
}
}
}
LogMessage("Loaded %d tier(s) from fakeclients_tiers.cfg", g_iTierCount);
}
/**
* Loads bot display names from configs/fakeclients.txt (one name per line).
*/
stock void ParseNames()
{
delete g_hNames;
g_hNames = new ArrayList(MAX_NAME_LENGTH);
char sBuffer[256];
BuildPath(Path_SM, sBuffer, sizeof(sBuffer), "configs/fakeclients.txt");
File hConfig = OpenFile(sBuffer, "r");
if (!hConfig)
{
LogError("configs/fakeclients.txt not found — using default engine name");
return;
}
while (hConfig.ReadLine(sBuffer, sizeof(sBuffer)))
{
TrimString(sBuffer);
if (strlen(sBuffer) > 0)
g_hNames.PushString(sBuffer);
}
delete hConfig;
if (!g_hNames.Length)
LogError("configs/fakeclients.txt is empty — using default engine name");
}
@@ -0,0 +1,80 @@
// Angery nut
materials/models/unloze/william/back.vmt
materials/models/unloze/william/back.vtf
materials/models/unloze/william/front.vmt
materials/models/unloze/william/front.vtf
models/unloze/william/angerynut.dx80.vtx
models/unloze/william/angerynut.dx90.vtx
models/unloze/william/angerynut.mdl
models/unloze/william/angerynut.sw.vtx
models/unloze/william/angerynut.vvd
//
//// Eevee
models\unloze\grenades\eevee.dx80.vtx
models\unloze\grenades\eevee.dx90.vtx
models\unloze\grenades\eevee.mdl
models\unloze\grenades\eevee.sw.vtx
models\unloze\grenades\eevee.vvd
materials\models\unloze\grenades\eevee\eevee_body.vtf
materials\models\unloze\grenades\eevee\eevee_body_shiny.vtf
materials\models\unloze\grenades\eevee\eevee_eye.vtf
materials\models\unloze\grenades\eevee\eevee_eye_shiny.vtf
materials\models\unloze\grenades\eevee\eevee_mouth.vtf
materials\models\unloze\grenades\eevee\eevee_mouth_shiny.vtf
materials\models\unloze\grenades\eevee\eievui.vmt
materials\models\unloze\grenades\eevee\eievuieye.vmt
materials\models\unloze\grenades\eevee\eievuieye_shiny.vmt
materials\models\unloze\grenades\eevee\eievuimouth.vmt
materials\models\unloze\grenades\eevee\eievuimouth_shiny.vmt
materials\models\unloze\grenades\eevee\eievui_shiny.vmt
//
//// Holy Grenade
models\unloze\grenades\holy_grenade.dx80.vtx
models\unloze\grenades\holy_grenade.dx90.vtx
models\unloze\grenades\holy_grenade.mdl
models\unloze\grenades\holy_grenade.phy
models\unloze\grenades\holy_grenade.sw.vtx
models\unloze\grenades\holy_grenade.vvd
materials\models\unloze\grenades\holy_grenade\holy_grenade.vmt
materials\models\unloze\grenades\holy_grenade\holy_grenade.vtf
//
//// Lenny
models\unloze\grenades\lenny.dx80.vtx
models\unloze\grenades\lenny.dx90.vtx
models\unloze\grenades\lenny.mdl
models\unloze\grenades\lenny.sw.vtx
models\unloze\grenades\lenny.vvd
models\unloze\grenades\lennysad.dx80.vtx
models\unloze\grenades\lennysad.dx90.vtx
models\unloze\grenades\lennysad.mdl
models\unloze\grenades\lennysad.sw.vtx
models\unloze\grenades\lennysad.vvd
materials\models\unloze\grenades\lenny\black.vmt
//
//// Pokeball
models\unloze\grenades\pokeball.dx80.vtx
models\unloze\grenades\pokeball.dx90.vtx
models\unloze\grenades\pokeball.mdl
models\unloze\grenades\pokeball.phy
models\unloze\grenades\pokeball.sw.vtx
models\unloze\grenades\pokeball.vvd
materials\models\unloze\grenades\pokeball\pokeball.vmt
materials\models\unloze\grenades\pokeball\pokeball.vtf
materials\models\unloze\grenades\pokeball\pokeball_great.vmt
materials\models\unloze\grenades\pokeball\pokeball_great.vtf
materials\models\unloze\grenades\pokeball\pokeball_gs.vmt
materials\models\unloze\grenades\pokeball\pokeball_gs.vtf
materials\models\unloze\grenades\pokeball\pokeball_master.vmt
materials\models\unloze\grenades\pokeball\pokeball_master.vtf
materials\models\unloze\grenades\pokeball\pokeball_ultra.vmt
materials\models\unloze\grenades\pokeball\pokeball_ultra.vtf
//
//// Soccer Ball
materials/models/unloze/soccer/soccerball.vmt
materials/models/unloze/soccer/soccerball_unloze.vtf
models/unloze/soccer/soccerball.dx80.vtx
models/unloze/soccer/soccerball.dx90.vtx
models/unloze/soccer/soccerball.mdl
models/unloze/soccer/soccerball.phy
models/unloze/soccer/soccerball.sw.vtx
models/unloze/soccer/soccerball.vvd
@@ -0,0 +1,193 @@
"Skins"
{
"0"
{
"Name" "Hula Doll"
"ModelPath" "models/props_lab/huladoll.mdl"
"Scale" "1.7"
"Tier" "1"
}
"1"
{
"Name" "Banana"
"ModelPath" "models/props/cs_italy/bananna.mdl"
"Tier" "2"
}
"2"
{
"Name" "Melon"
"ModelPath" "models/props_junk/watermelon01.mdl"
"Scale" "0.7"
"Tier" "2"
}
"3"
{
"Name" "Orange"
"ModelPath" "models/props/cs_italy/orange.mdl"
"Scale" "1.5"
"Tier" "3"
}
"4"
{
"Name" "Creepy Doll"
"ModelPath" "models/props_c17/doll01.mdl"
"Scale" "0.8"
"Tier" "3"
}
"5"
{
"Name" "Turtle"
"ModelPath" "models/props/de_tides/vending_turtle.mdl"
"Tier" "4"
}
"6"
{
"Name" "Goldfish"
"ModelPath" "models/props/de_inferno/goldfish.mdl"
"Tier" "5"
}
"7"
{
"Name" "River Fish"
"ModelPath" "models/props/cs_militia/fishriver01.mdl"
"Tier" "5"
}
"8"
{
"Name" "Snowman Head"
"ModelPath" "models/props/cs_office/snowman_face.mdl"
"Scale" "0.7"
"Tier" "6"
}
"9"
{
"Name" "Glass Bottle"
"ModelPath" "models/props/cs_militia/bottle01.mdl"
"Tier" "7"
}
"10"
{
"Name" "Gift"
"ModelPath" "models/items/cs_gift.mdl"
"Scale" "0.6"
"Tier" "8"
}
"11"
{
"Name" "Rollermine"
"ModelPath" "models/roller_spikes.mdl"
"VIP" "1"
"Scale" "0.7"
}
"12"
{
"Name" "Helicopter Bomb"
"ModelPath" "models/combine_helicopter/helicopter_bomb01.mdl"
"VIP" "1"
"Scale" "0.35"
}
"13"
{
"Name" "Explosive Barrel"
"ModelPath" "models/props_c17/oildrum001_explosive.mdl"
"VIP" "1"
"Scale" "0.25"
}
"14"
{
"Name" "Skull"
"ModelPath" "models/gibs/agibs.mdl"
"VIP" "1"
"Scale" "1.3"
}
"15"
{
"Name" "Angery Nut"
"ModelPath" "models/unloze/william/angerynut.mdl"
"VIP" "1"
"Scale" "0.8"
}
"16"
{
"Name" "Holy Grenade"
"ModelPath" "models/unloze/grenades/holy_grenade.mdl"
"Scale" "0.6"
"VIP" "1"
}
"17"
{
"Name" "Lenny Face"
"ModelPath" "models/unloze/grenades/lenny.mdl"
"VIP" "1"
"Scale" "0.8"
}
"18"
{
"Name" "Lenny Sad"
"ModelPath" "models/unloze/grenades/lennysad.mdl"
"VIP" "1"
"Scale" "0.8"
}
"19"
{
"Name" "Soccer Ball"
"ModelPath" "models/unloze/soccer/soccerball.mdl"
"VIP" "1"
"Scale" "0.4"
}
"20"
{
"Name" "Eevee"
"ModelPath" "models/unloze/grenades/eevee.mdl"
"VIP" "1"
"Scale" "0.5"
}
"21"
{
"Name" "Shiny Eevee"
"ModelPath" "models/unloze/grenades/eevee.mdl"
"VIP" "1"
"Skin" "1"
"Scale" "0.5"
}
"22"
{
"Name" "Poke Ball"
"ModelPath" "models/unloze/grenades/pokeball.mdl"
"VIP" "1"
"Scale" "1.5"
}
"23"
{
"Name" "Great Ball"
"ModelPath" "models/unloze/grenades/pokeball.mdl"
"VIP" "1"
"Skin" "1"
"Scale" "1.5"
}
"24"
{
"Name" "Ultra Ball"
"ModelPath" "models/unloze/grenades/pokeball.mdl"
"VIP" "1"
"Skin" "4"
"Scale" "1.5"
}
"25"
{
"Name" "Master Ball"
"ModelPath" "models/unloze/grenades/pokeball.mdl"
"VIP" "1"
"Skin" "3"
"Scale" "1.5"
}
"26"
{
"Name" "GS Ball"
"ModelPath" "models/unloze/grenades/pokeball.mdl"
"VIP" "1"
"Skin" "2"
"Scale" "1.5"
}
}
@@ -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);
}
+79 -2
View File
@@ -25,7 +25,7 @@ bool g_bHitmarkerSound[MAXPLAYERS+1];
int g_iHitmarkerSoundVolume[MAXPLAYERS+1] = {100,...}; int g_iHitmarkerSoundVolume[MAXPLAYERS+1] = {100,...};
int g_iHitmarkerSkin[MAXPLAYERS+1]; int g_iHitmarkerSkin[MAXPLAYERS+1];
#define MAXIMUMSKINS 6 #define MAXIMUMSKINS 12
char g_sHitmarkerSkins[MAXIMUMSKINS][PLATFORM_MAX_PATH]; char g_sHitmarkerSkins[MAXIMUMSKINS][PLATFORM_MAX_PATH];
char g_sHitmarkerSkinsNames[MAXIMUMSKINS][PLATFORM_MAX_PATH]; char g_sHitmarkerSkinsNames[MAXIMUMSKINS][PLATFORM_MAX_PATH];
@@ -38,6 +38,7 @@ Handle g_hCookie_HitmarkerSoundVolume;
Handle g_hCookie_HitmarkerSkin; Handle g_hCookie_HitmarkerSkin;
ConVar g_hCVar_Debug; ConVar g_hCVar_Debug;
ConVar g_hCVar_HitmarkerEnabled;
bool g_bLate; bool g_bLate;
@@ -87,7 +88,9 @@ public void OnPluginStart()
g_hCookie_HitmarkerSkin = RegClientCookie("hitmarker_skin", "", CookieAccess_Private); g_hCookie_HitmarkerSkin = RegClientCookie("hitmarker_skin", "", CookieAccess_Private);
g_hCVar_Debug = CreateConVar("sm_hitmarker_debug", "0", "", FCVAR_NONE, true, 0.0, true, 1.0); g_hCVar_Debug = CreateConVar("sm_hitmarker_debug", "0", "", FCVAR_NONE, true, 0.0, true, 1.0);
AutoExecConfig(); g_hCVar_HitmarkerEnabled = CreateConVar("sm_hitmarker_enabled", "1", "", FCVAR_NONE, true, 0.0, true, 1.0);
g_hCVar_HitmarkerEnabled.AddChangeHook(OnConVarChanged);
AutoExecConfig(true);
RegConsoleCmd("sm_hm", OnHitmarkerSettings); RegConsoleCmd("sm_hm", OnHitmarkerSettings);
RegConsoleCmd("sm_hitmarker", OnHitmarkerSettings); RegConsoleCmd("sm_hitmarker", OnHitmarkerSettings);
@@ -109,6 +112,14 @@ public void OnPluginStart()
} }
} }
public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
{
if(g_hCVar_HitmarkerEnabled.BoolValue)
CPrintToChatAll("{cyan}[Hitmarker] {white}has been allowed.");
else
CPrintToChatAll("{cyan}[Hitmarker] {white}has been disabled.");
}
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// Purpose: // Purpose:
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -120,6 +131,11 @@ public void OnMapStart()
g_sHitmarkerSkinsNames[i] = ""; g_sHitmarkerSkinsNames[i] = "";
} }
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return;
}
char sConfigFile[PLATFORM_MAX_PATH]; char sConfigFile[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), "configs/Hitmarkers.cfg"); BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), "configs/Hitmarkers.cfg");
@@ -184,6 +200,11 @@ public void OnMapStart()
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void OnClientCookiesCached(int client) public void OnClientCookiesCached(int client)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return;
}
char sBuffer[PLATFORM_MAX_PATH]; char sBuffer[PLATFORM_MAX_PATH];
GetClientCookie(client, g_hCookie_ShowBossHitmarker, sBuffer, sizeof(sBuffer)); GetClientCookie(client, g_hCookie_ShowBossHitmarker, sBuffer, sizeof(sBuffer));
@@ -243,6 +264,10 @@ public void OnClientDisconnect(int client)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public Action OnHitmarkerSettings(int client, int args) public Action OnHitmarkerSettings(int client, int args)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return Plugin_Handled;
}
ShowSettingsMenu(client); ShowSettingsMenu(client);
return Plugin_Handled; return Plugin_Handled;
} }
@@ -252,6 +277,10 @@ public Action OnHitmarkerSettings(int client, int args)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public Action OnToggleBossHitmarker(int client, int args) public Action OnToggleBossHitmarker(int client, int args)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return Plugin_Handled;
}
ToggleBossHitmarker(client); ToggleBossHitmarker(client);
return Plugin_Handled; return Plugin_Handled;
} }
@@ -275,6 +304,10 @@ public void ToggleBossHitmarker(int client)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public Action OnToggleZombieHitmarker(int client, int args) public Action OnToggleZombieHitmarker(int client, int args)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return Plugin_Handled;
}
ToggleZombieHitmarker(client); ToggleZombieHitmarker(client);
return Plugin_Handled; return Plugin_Handled;
} }
@@ -284,6 +317,10 @@ public Action OnToggleZombieHitmarker(int client, int args)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void ToggleZombieHitmarker(int client) public void ToggleZombieHitmarker(int client)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return;
}
g_bShowZombieHitmarker[client] = !g_bShowZombieHitmarker[client]; g_bShowZombieHitmarker[client] = !g_bShowZombieHitmarker[client];
SetClientCookie(client, g_hCookie_ShowZombieHitmarker, g_bShowZombieHitmarker[client] ? "1" : ""); SetClientCookie(client, g_hCookie_ShowZombieHitmarker, g_bShowZombieHitmarker[client] ? "1" : "");
@@ -298,6 +335,10 @@ public void ToggleZombieHitmarker(int client)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public Action OnToggleHitmarkerSound(int client, int args) public Action OnToggleHitmarkerSound(int client, int args)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return Plugin_Handled;
}
ToggleHitmarkerSound(client); ToggleHitmarkerSound(client);
return Plugin_Handled; return Plugin_Handled;
} }
@@ -307,6 +348,10 @@ public Action OnToggleHitmarkerSound(int client, int args)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void ToggleHitmarkerSound(int client) public void ToggleHitmarkerSound(int client)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return;
}
g_bHitmarkerSound[client] = !g_bHitmarkerSound[client]; g_bHitmarkerSound[client] = !g_bHitmarkerSound[client];
SetClientCookie(client, g_hCookie_HitmarkerSound, g_bHitmarkerSound[client] ? "1" : ""); SetClientCookie(client, g_hCookie_HitmarkerSound, g_bHitmarkerSound[client] ? "1" : "");
@@ -321,6 +366,10 @@ public void ToggleHitmarkerSound(int client)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void ToggleHitmarkerSoundVolume(int client) public void ToggleHitmarkerSoundVolume(int client)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return;
}
g_iHitmarkerSoundVolume[client] += 25; g_iHitmarkerSoundVolume[client] += 25;
if(g_iHitmarkerSoundVolume[client] > 100) if(g_iHitmarkerSoundVolume[client] > 100)
@@ -339,6 +388,10 @@ public void ToggleHitmarkerSoundVolume(int client)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void ToggleHitmarkerSkin(int client) public void ToggleHitmarkerSkin(int client)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return;
}
g_iHitmarkerSkin[client]++; g_iHitmarkerSkin[client]++;
if (StrEqual(g_sHitmarkerSkins[g_iHitmarkerSkin[client]], "")) if (StrEqual(g_sHitmarkerSkins[g_iHitmarkerSkin[client]], ""))
@@ -354,6 +407,10 @@ public void ToggleHitmarkerSkin(int client)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void ShowSettingsMenu(int client) public void ShowSettingsMenu(int client)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return;
}
Menu menu = new Menu(MenuHandler_MainMenu); Menu menu = new Menu(MenuHandler_MainMenu);
menu.SetTitle("Hitmarker Settings", client); menu.SetTitle("Hitmarker Settings", client);
@@ -434,6 +491,10 @@ public int MenuHandler_MainMenu(Menu menu, MenuAction action, int client, int se
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void OnEntitySpawned(int Entity, const char[] sClassname) public void OnEntitySpawned(int Entity, const char[] sClassname)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return;
}
int ent = EntRefToEntIndex(Entity); int ent = EntRefToEntIndex(Entity);
if (0 < ent < MAX_EDICTS) if (0 < ent < MAX_EDICTS)
@@ -451,6 +512,10 @@ public void OnEntitySpawned(int Entity, const char[] sClassname)
/* /*
public void OnBossDamaged(CBoss Boss, CConfig Config, int client, float damage) public void OnBossDamaged(CBoss Boss, CConfig Config, int client, float damage)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return;
}
if (!IsValidClient(client)) if (!IsValidClient(client))
return; return;
@@ -475,6 +540,10 @@ public void OnBossDamaged(CBoss Boss, CConfig Config, int client, float damage)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public MRESReturn Detour_OnTakeDamage(int entity, Handle hReturn, Handle hParams) public MRESReturn Detour_OnTakeDamage(int entity, Handle hReturn, Handle hParams)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return MRES_Ignored;
}
//https://github.com/alliedmodders/hl2sdk/blob/css/game/shared/takedamageinfo.h#L115 //https://github.com/alliedmodders/hl2sdk/blob/css/game/shared/takedamageinfo.h#L115
int iHealth = GetEntProp(entity, Prop_Data, "m_iHealth"); int iHealth = GetEntProp(entity, Prop_Data, "m_iHealth");
int client = DHookGetParamObjectPtrVar(hParams, 1, 3*(3*4) + 0, ObjectValueType_Ehandle); int client = DHookGetParamObjectPtrVar(hParams, 1, 3*(3*4) + 0, ObjectValueType_Ehandle);
@@ -514,6 +583,10 @@ public MRESReturn Detour_OnTakeDamage(int entity, Handle hReturn, Handle hParams
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void OnClientHurt(Event hEvent, const char[] sEvent, bool bDontBroadcast) public void OnClientHurt(Event hEvent, const char[] sEvent, bool bDontBroadcast)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return;
}
int client = GetClientOfUserId(hEvent.GetInt("attacker")); int client = GetClientOfUserId(hEvent.GetInt("attacker"));
int victim = GetClientOfUserId(hEvent.GetInt("userid")); int victim = GetClientOfUserId(hEvent.GetInt("userid"));
@@ -544,6 +617,10 @@ public void OnClientHurt(Event hEvent, const char[] sEvent, bool bDontBroadcast)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
void ShowOverlay(int client, float fTime = 0.3) void ShowOverlay(int client, float fTime = 0.3)
{ {
if(!g_hCVar_HitmarkerEnabled.BoolValue)
{
return;
}
if (g_bHitmarkerSound[client]) if (g_bHitmarkerSound[client])
{ {
float fVolume = g_iHitmarkerSoundVolume[client] / 100.0; float fVolume = g_iHitmarkerSoundVolume[client] / 100.0;
+234 -3
View File
@@ -12,6 +12,8 @@
char g_sBanListFilePath[256]; char g_sBanListFilePath[256];
Database g_hDatabase;
bool g_bKnifeBanned[MAXPLAYERS + 1]; bool g_bKnifeBanned[MAXPLAYERS + 1];
bool g_bKnifeBan; bool g_bKnifeBan;
@@ -53,6 +55,7 @@ public void OnPluginStart()
SetFailState("Couldnt find CBaseCombatCharacter::m_hActiveWeapon"); SetFailState("Couldnt find CBaseCombatCharacter::m_hActiveWeapon");
CreateTimer(5.0, CheckKnifeBans, _, TIMER_REPEAT); CreateTimer(5.0, CheckKnifeBans, _, TIMER_REPEAT);
CreateTimer(300.0, CheckKnifeBansFromWeb, _, TIMER_REPEAT); //check every 5 minutes if something new was done on webpannel
g_TempBanned = new ArrayList(); g_TempBanned = new ArrayList();
@@ -68,6 +71,29 @@ public void OnPluginStart()
if(IsClientInGame(i)) if(IsClientInGame(i))
OnClientPostAdminCheck(i); OnClientPostAdminCheck(i);
} }
if (!g_hDatabase)
{
Database.Connect(SQL_OnDatabaseConnect, "unloze_knifeban_web");
}
}
public void OnMapStart()
{
if (!g_hDatabase)
{
Database.Connect(SQL_OnDatabaseConnect, "unloze_knifeban_web");
}
}
public void SQL_OnDatabaseConnect(Database db, const char[] error, any data)
{
if(!db || strlen(error))
{
LogError("Database error: %s", error);
return;
}
g_hDatabase = db;
} }
public void OnPluginEnd() public void OnPluginEnd()
@@ -99,9 +125,6 @@ public void OnClientPostAdminCheck(int client)
SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage); SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);
} }
g_iClientHours[client] = 0;
g_iClientMinutes[client] = 0;
char sAuth[32]; char sAuth[32];
GetClientAuthId(client, AuthId_Steam2, sAuth, sizeof(sAuth)); GetClientAuthId(client, AuthId_Steam2, sAuth, sizeof(sAuth));
@@ -141,6 +164,134 @@ public void OnMapEnd()
g_TempBanned.Clear(); g_TempBanned.Clear();
} }
public Action CheckKnifeBansFromWeb(Handle timer)
{
char sQuery[512];
Format(sQuery, sizeof(sQuery), "select client_steamid, web_addban_required, web_unban_required, web_ban_delete, web_edit_required, time_played_start, length, krcb.admin_name from `KbRestrict_CurrentBans` krcb where krcb.web_addban_required = 1 or krcb.web_unban_required = 1 or krcb.web_ban_delete = 1 or krcb.web_edit_required = 1");
g_hDatabase.Query(SQL_OnQueryCompletedWebKbans, sQuery);
return Plugin_Continue;
}
public void SQL_OnQueryCompletedWebKbans(Database db, DBResultSet results, const char[] error, int iSerial)
{
if (!db || strlen(error))
{
delete results;
LogError("Query error 3: %s", error);
return;
}
while (results.RowCount && results.FetchRow())
{
char sSID[64];
results.FetchString(0, sSID, sizeof(sSID));
int web_addban_required = results.FetchInt(1);
int web_unban_required = results.FetchInt(2);
int web_ban_delete = results.FetchInt(3);
int web_edit_required = results.FetchInt(4);
int time_played_start = results.FetchInt(5);
int length = results.FetchInt(6);
char admin_name[255];
results.FetchString(7, admin_name, sizeof(admin_name));
char sQuery[512];
if (web_addban_required)
{
file_addban(sSID, time_played_start, length, admin_name);
Format(sQuery, sizeof(sQuery), "update `KbRestrict_CurrentBans` set web_addban_required = 0 where client_steamid = '%s' and web_addban_required = 1", sSID);
g_hDatabase.Query(SQL_FinishedQuery, sQuery);
}
else if (web_unban_required)
{
file_unban(sSID);
Format(sQuery, sizeof(sQuery), "update `KbRestrict_CurrentBans` set web_unban_required = 0 where client_steamid = '%s' and web_unban_required = 1", sSID);
g_hDatabase.Query(SQL_FinishedQuery, sQuery);
}
else if (web_ban_delete)
{
file_unban(sSID);
Format(sQuery, sizeof(sQuery), "delete from `KbRestrict_CurrentBans` where client_steamid = '%s' and web_ban_delete = 1", sSID);
g_hDatabase.Query(SQL_FinishedQuery, sQuery);
}
else if (web_edit_required)
{
file_edit_ban(sSID, length);
Format(sQuery, sizeof(sQuery), "update `KbRestrict_CurrentBans` set web_edit_required = 0 where client_steamid = '%s' and web_edit_required = 1", sSID);
g_hDatabase.Query(SQL_FinishedQuery, sQuery);
}
}
delete results;
}
public void file_edit_ban(char sAuth[64], int length)
{
int length_hours = length / 60;
int length_minutes = length % 60;
if(Banlist.JumpToKey(sAuth))
{
Banlist.SetNum("duration", length_hours);
Banlist.SetNum("duration_minutes", length_minutes);
Banlist.Rewind();
Banlist.ExportToFile(g_sBanListFilePath);
}
}
public void file_unban(char sAuth[64])
{
if(Banlist.JumpToKey(sAuth))
{
int history = Banlist.GetNum("history");
Banlist.SetNum("history", history - 1);
Banlist.SetNum("time", 0);
Banlist.SetNum("time_minutes", 0);
Banlist.SetNum("duration", 0);
Banlist.SetNum("duration_minutes", 0);
Banlist.SetString("admin", "");
Banlist.Rewind();
Banlist.ExportToFile(g_sBanListFilePath);
}
}
public void file_addban(char sAuth[64], int time_played_start, int length, char sAdmin[255])
{
int time = time_played_start / 60;
int time_minutes = time_played_start & 60;
int length_hours = length / 60;
int length_minutes = length % 60;
if( length_hours || length_minutes)
{
if(Banlist.JumpToKey(sAuth, true))
{
int history = Banlist.GetNum("history");
Banlist.SetNum("history", history + 1);
Banlist.SetNum("time", time);
Banlist.SetNum("time_minutes", time_minutes);
Banlist.SetNum("duration", length_hours);
Banlist.SetNum("duration_minutes", length_minutes);
Banlist.SetString("admin", sAdmin);
Banlist.Rewind();
Banlist.ExportToFile(g_sBanListFilePath);
}
}
else
{
if(Banlist.JumpToKey(sAuth, true))
{
int history = Banlist.GetNum("history");
Banlist.SetNum("history", history + 1);
Banlist.SetNum("time", time);
Banlist.SetNum("time_minutes", time_minutes);
Banlist.SetNum("duration", -1);
Banlist.SetNum("duration_minutes", -1);
Banlist.SetString("admin", sAdmin);
Banlist.Rewind();
Banlist.ExportToFile(g_sBanListFilePath);
}
}
}
public Action CheckKnifeBans(Handle timer) public Action CheckKnifeBans(Handle timer)
{ {
for(int i = 1; i <= MaxClients; i++) for(int i = 1; i <= MaxClients; i++)
@@ -208,6 +359,7 @@ public void CheckIfClientIsStillKnifeBanned(char sAuth[32], int client, int time
Banlist.SetString("admin", ""); Banlist.SetString("admin", "");
Banlist.Rewind(); Banlist.Rewind();
Banlist.ExportToFile(g_sBanListFilePath); Banlist.ExportToFile(g_sBanListFilePath);
update_knife_unban_mysql(client);
} }
} }
} }
@@ -321,6 +473,8 @@ public Action Command_Knifeban(int client, int args)
Banlist.SetString("admin", sAdmin); Banlist.SetString("admin", sAdmin);
Banlist.Rewind(); Banlist.Rewind();
Banlist.ExportToFile(g_sBanListFilePath); Banlist.ExportToFile(g_sBanListFilePath);
insert_knifeban_mysql(client, target, length_hours, length_minutes, time, time_minutes);
} }
} }
else else
@@ -338,6 +492,8 @@ public Action Command_Knifeban(int client, int args)
Banlist.SetString("admin", sAdmin); Banlist.SetString("admin", sAdmin);
Banlist.Rewind(); Banlist.Rewind();
Banlist.ExportToFile(g_sBanListFilePath); Banlist.ExportToFile(g_sBanListFilePath);
insert_knifeban_mysql(client, target, -1, -1, time, time_minutes);
} }
} }
} }
@@ -362,6 +518,60 @@ public Action Command_Knifeban(int client, int args)
return Plugin_Handled; return Plugin_Handled;
} }
public void insert_knifeban_mysql(int admin, int knife_banned_player, int length_hours, int length_minutes, int time_start_playertime_hours, int time_start_playertime_minutes)
{
char sNameAdmin[MAX_NAME_LENGTH];
GetClientName(admin, sNameAdmin, sizeof(sNameAdmin));
int size2 = 2 * strlen(sNameAdmin) + 1;
char[] sEscapedNameAdmin = new char[size2 + 1];
g_hDatabase.Escape(sNameAdmin, sEscapedNameAdmin, size2 + 1);
char sSIDAdmin[64];
GetClientAuthId(admin, AuthId_Steam2, sSIDAdmin, sizeof(sSIDAdmin));
char sNameClient[MAX_NAME_LENGTH];
GetClientName(knife_banned_player, sNameClient, sizeof(sNameClient));
size2 = 2 * strlen(sNameClient) + 1;
char[] sEscapedNameClient = new char[size2 + 1];
g_hDatabase.Escape(sNameClient, sEscapedNameClient, size2 + 1);
char sSIDClient[64];
GetClientAuthId(knife_banned_player, AuthId_Steam2, sSIDClient, sizeof(sSIDClient));
char sIP[32];
GetClientIP(knife_banned_player, sIP, sizeof(sIP));
char currentMap[64];
GetCurrentMap(currentMap, sizeof(currentMap));
char sQuery[512];
//length is assumed to be minutes.
int length = (length_hours * 60) + length_minutes;
if (length_hours == -1)
{
length = 0;
}
int playtime_start_client = (time_start_playertime_hours * 60) + time_start_playertime_minutes;
int playtime_end_client = playtime_start_client + length;
if (length_hours == -1)
{
playtime_end_client = -1;
playtime_start_client = -1;
}
Format(sQuery, sizeof(sQuery), "INSERT INTO `KbRestrict_CurrentBans` (`client_name`, `client_steamid`, `client_ip`, `admin_name`, `admin_steamid`, `reason`, `map`, `length`, `time_played_start`, `time_played_end`, `is_expired`, `is_removed`, `admin_name_removed`, `admin_steamid_removed`, `time_stamp_removed`, `reason_removed`) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%i', '%i', '%i', 0, 0, ' ', ' ', 0, ' ')", sEscapedNameClient, sSIDClient, sIP, sEscapedNameAdmin, sSIDAdmin, "get fucked", currentMap, length, playtime_start_client, playtime_end_client);
g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Normal);
}
public void SQL_FinishedQuery(Database db, DBResultSet results, const char[] error, any data)
{
if (!db || strlen(error))
{
LogError("Query error 3: %s", error);
}
delete results;
}
public Action Command_Knifeunban(int client, int args) public Action Command_Knifeunban(int client, int args)
{ {
if(!GetCmdArgs()) if(!GetCmdArgs())
@@ -400,6 +610,7 @@ public Action Command_Knifeunban(int client, int args)
Banlist.SetString("admin", ""); Banlist.SetString("admin", "");
Banlist.Rewind(); Banlist.Rewind();
Banlist.ExportToFile(g_sBanListFilePath); Banlist.ExportToFile(g_sBanListFilePath);
update_knife_unban_mysql(target);
} }
int accountid = GetSteamAccountID(target); int accountid = GetSteamAccountID(target);
@@ -416,6 +627,16 @@ public Action Command_Knifeunban(int client, int args)
return Plugin_Handled; return Plugin_Handled;
} }
public void update_knife_unban_mysql(int knife_unbanned_client)
{
char sSIDClient[64];
GetClientAuthId(knife_unbanned_client, AuthId_Steam2, sSIDClient, sizeof(sSIDClient));
char sQuery[512];
Format(sQuery, sizeof(sQuery), "update `KbRestrict_CurrentBans` set is_expired = 1 where client_steamid = '%s' and is_expired = 0", sSIDClient);
g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Normal);
}
public Action Command_Knifestatus(int client, int args) public Action Command_Knifestatus(int client, int args)
{ {
if(CheckCommandAccess(client, "", ADMFLAG_BAN) && GetCmdArgs()) if(CheckCommandAccess(client, "", ADMFLAG_BAN) && GetCmdArgs())
@@ -477,6 +698,11 @@ public Action Command_Knifestatus(int client, int args)
int iTimeRemaining = length_hours - timesinceknifeban; int iTimeRemaining = length_hours - timesinceknifeban;
int iTimeRemaining_minutes = length_minutes - timesinceknifeban_minutes; int iTimeRemaining_minutes = length_minutes - timesinceknifeban_minutes;
if (iTimeRemaining_minutes < 0)
{
iTimeRemaining_minutes += 60;
iTimeRemaining--;
}
Format(sTimeRemaining, sizeof(sTimeRemaining), "%d Hours and %d minutes playtime", iTimeRemaining, iTimeRemaining_minutes); Format(sTimeRemaining, sizeof(sTimeRemaining), "%d Hours and %d minutes playtime", iTimeRemaining, iTimeRemaining_minutes);
CReplyToCommand(client, "\x07%s[KnifeBan] \x07%s%N\x07%s is currently knifebanned for another \x07%s%s\x07%s.", "E01B5D", "EDEDED", target, "F16767", "EDEDED", sTimeRemaining, "F16767"); CReplyToCommand(client, "\x07%s[KnifeBan] \x07%s%N\x07%s is currently knifebanned for another \x07%s%s\x07%s.", "E01B5D", "EDEDED", target, "F16767", "EDEDED", sTimeRemaining, "F16767");
@@ -534,6 +760,11 @@ public Action Command_Knifestatus(int client, int args)
int iTimeRemaining = length_hours - timesinceknifeban; int iTimeRemaining = length_hours - timesinceknifeban;
int iTimeRemaining_minutes = length_minutes - timesinceknifeban_minutes; int iTimeRemaining_minutes = length_minutes - timesinceknifeban_minutes;
if (iTimeRemaining_minutes < 0)
{
iTimeRemaining_minutes += 60;
iTimeRemaining--;
}
Format(sTimeRemaining, sizeof(sTimeRemaining), "%d Hours and %d minutes playtime", iTimeRemaining, iTimeRemaining_minutes); Format(sTimeRemaining, sizeof(sTimeRemaining), "%d Hours and %d minutes playtime", iTimeRemaining, iTimeRemaining_minutes);
CReplyToCommand(client, "\x07%s[KnifeBan] \x07%sYou are currently knifebanned for another \x07%s%s\x07%s.", "E01B5D", "F16767", "EDEDED", sTimeRemaining, "F16767"); CReplyToCommand(client, "\x07%s[KnifeBan] \x07%sYou are currently knifebanned for another \x07%s%s\x07%s.", "E01B5D", "F16767", "EDEDED", sTimeRemaining, "F16767");
+46
View File
@@ -0,0 +1,46 @@
-- knifeban_web.KbRestrict_CurrentBans definition
CREATE TABLE `KbRestrict_CurrentBans` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`client_name` varchar(64) NOT NULL,
`client_steamid` varchar(64) NOT NULL,
`client_ip` varchar(64) NOT NULL,
`admin_name` varchar(64) NOT NULL,
`admin_steamid` varchar(64) NOT NULL,
`reason` varchar(255) NOT NULL,
`map` varchar(64) NOT NULL,
`length` int(11) NOT NULL,
`time_stamp_start` datetime DEFAULT current_timestamp(),
`time_played_start` int(11) NOT NULL,
`time_played_end` int(11) NOT NULL,
`is_expired` int(11) NOT NULL,
`is_removed` int(11) NOT NULL,
`time_stamp_removed` int(20) NOT NULL,
`admin_name_removed` varchar(255) NOT NULL,
`admin_steamid_removed` varchar(255) NOT NULL,
`reason_removed` varchar(255) NOT NULL,
`web_unban_required` tinyint(1) NOT NULL DEFAULT 0,
`web_addban_required` tinyint(1) NOT NULL DEFAULT 0,
`web_ban_delete` tinyint(1) NOT NULL DEFAULT 0,
`web_edit_required` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `idx_steamid_search` (`client_steamid`),
KEY `idx_ip_search` (`client_ip`),
KEY `idx_admin_steamid` (`admin_steamid`),
KEY `idx_status` (`is_expired`,`is_removed`),
KEY `idx_steamid_ip_status` (`client_steamid`,`client_ip`,`is_expired`,`is_removed`),
KEY `idx_web_unban_required` (`web_unban_required`),
KEY `idx_web_addban_required` (`web_addban_required`),
KEY `idx_web_ban_delete` (`web_ban_delete`),
KEY `idx_web_edit_required` (`web_edit_required`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE IF NOT EXISTS knifeban_web.KbRestrict_weblogs (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`message` varchar(200) NOT NULL,
`admin_name` varchar(255) NOT NULL,
`admin_steamid` varchar(64) NOT NULL,
`client_name` varchar(255) NOT NULL,
`client_steamid` varchar(64) NOT NULL,
`time_stamp` int(20) NOT NULL,
PRIMARY KEY(`id`));
@@ -18,7 +18,7 @@ public Plugin myinfo =
name = "LagCompensation", name = "LagCompensation",
author = "BotoX, Vauff, .Rushaway, maxime1907", author = "BotoX, Vauff, .Rushaway, maxime1907",
description = "", description = "",
version = "1.0.6", version = "1.1.0",
url = "" url = ""
}; };
@@ -28,7 +28,7 @@ bool g_bHasOnEntitySpawned = false;
bool g_bCheckPing = false; bool g_bCheckPing = false;
int g_iCompenseEntityClass; int g_iCompenseEntityClass;
// Dont change this. // Don't change this.
#define MAX_EDICTS 2048 #define MAX_EDICTS 2048
#define FSOLID_FORCE_WORLD_ALIGNED 0x0040 #define FSOLID_FORCE_WORLD_ALIGNED 0x0040
#define FSOLID_ROOT_PARENT_ALIGNED 0x0100 #define FSOLID_ROOT_PARENT_ALIGNED 0x0100
@@ -104,6 +104,7 @@ enum struct EntityLagData
int iNotMoving; int iNotMoving;
bool bRestore; bool bRestore;
bool bLateKill; bool bLateKill;
char sClassname[64];
} }
LagRecord g_aaLagRecords[MAX_ENTITIES][MAX_RECORDS]; LagRecord g_aaLagRecords[MAX_ENTITIES][MAX_RECORDS];
@@ -159,10 +160,11 @@ int g_aaFilterClientSolidTouch[((MAXPLAYERS + 1) * MAX_EDICTS) / 32];
int g_aBlockTriggerMoved[MAX_EDICTS / 32]; int g_aBlockTriggerMoved[MAX_EDICTS / 32];
int g_aBlacklisted[MAX_EDICTS / 32]; int g_aBlacklisted[MAX_EDICTS / 32];
Handle g_hCookie_EnableLagComp; Handle g_hCookie_LagCompSettings;
Handle g_hCookie_LagCompMessages; bool g_bDisableLagComp[MAXPLAYERS + 1];
bool g_bEnableLagComp[MAXPLAYERS + 1]; bool g_bPlayerLaserCompensated[MAXPLAYERS + 1];
bool g_bLagCompMessages[MAXPLAYERS + 1]; bool g_bLagCompMessages[MAXPLAYERS + 1];
bool g_bSettingsTouched[MAXPLAYERS + 1];
int g_iDisableLagComp[MAXPLAYERS + 1]; int g_iDisableLagComp[MAXPLAYERS + 1];
ConVar g_cvCompenseEntityClass; ConVar g_cvCompenseEntityClass;
ConVar g_cvCheckUserPing; ConVar g_cvCheckUserPing;
@@ -173,8 +175,8 @@ public void OnPluginStart()
LoadTranslations("common.phrases"); LoadTranslations("common.phrases");
g_cvCompenseEntityClass = CreateConVar("sm_lagcomp_entityclass", "0", "Only lagcompensate: [0 = All | 1 = func_physbox only]", _, true, 0.0, true, 1.0); g_cvCompenseEntityClass = CreateConVar("sm_lagcomp_entityclass", "0", "Only lagcompensate: [0 = All | 1 = func_physbox only]", _, true, 0.0, true, 1.0);
g_cvCheckUserPing = CreateConVar("sm_lagcomp_checkuserping", "0", "Check users ping before lagcompensating them [0 = Disabled | 1 = Enabled]", _, true, 0.0, true, 1.0); g_cvCheckUserPing = CreateConVar("sm_lagcomp_checkuserping", "0", "Check user's ping before lagcompensating them [0 = Disabled | 1 = Enabled]", _, true, 0.0, true, 1.0);
g_cvMinimumPing = CreateConVar("sm_lagcomp_ping", "150", "Minimum ping threshold to apply lagcomp on a client", _, true, 0.0); g_cvMinimumPing = CreateConVar("sm_lagcomp_ping", "180", "Minimum ping threshold to apply lagcomp on a client", _, true, 0.0);
AutoExecConfig(true); AutoExecConfig(true);
@@ -347,16 +349,16 @@ public void OnPluginStart()
HookConVarChange(g_cvMinimumPing, OnConVarChanged); HookConVarChange(g_cvMinimumPing, OnConVarChanged);
g_hCookie_EnableLagComp = RegClientCookie("enable_lagcomp", "Client LagComp Status", CookieAccess_Private); g_hCookie_LagCompSettings = RegClientCookie("lagcomp_settings", "LagCompensation Settings", CookieAccess_Private);
g_hCookie_LagCompMessages = RegClientCookie("lagcomp_messages", "Print LagComp messages in chat", CookieAccess_Private); RegConsoleCmd("sm_lagcomp", OnLagCompSettings);
RegConsoleCmd("sm_lagcomp", OnToggleLagCompSettings);
RegConsoleCmd("sm_0ping", OnToggleLagCompSettings); RegConsoleCmd("sm_0ping", OnToggleLagCompSettings);
RegConsoleCmd("sm_0pinglasers", OnToggleLagCompLasersSettings);
RegConsoleCmd("sm_checklag", CheckLagComp); RegConsoleCmd("sm_checklag", CheckLagComp);
SetCookieMenuItem(MenuHandler_CookieMenu, 0, "LagCompensation"); SetCookieMenuItem(MenuHandler_CookieMenu, 0, "LagCompensation");
CreateTimer(0.1, DisableLagCompTimer, _, TIMER_REPEAT); CreateTimer(0.1, DisableLagCompTimer, _, TIMER_REPEAT);
RegAdminCmd("sm_unlag", Command_AddLagCompensation, ADMFLAG_ROOT, "sm_unlag <entidx>"); RegAdminCmd("sm_unlag", Command_AddLagCompensation, ADMFLAG_ROOT, "sm_unlag <entidx> [late]");
RegAdminCmd("sm_lagged", Command_CheckLagCompensated, ADMFLAG_ROOT, "sm_lagged"); RegAdminCmd("sm_lagged", Command_CheckLagCompensated, ADMFLAG_ROOT, "sm_lagged");
FilterClientSolidTouch(g_aaFilterClientSolidTouch, true); FilterClientSolidTouch(g_aaFilterClientSolidTouch, true);
@@ -486,18 +488,27 @@ public void OnMapEnd()
public void OnClientConnected(int client) public void OnClientConnected(int client)
{ {
g_bEnableLagComp[client] = false; // Must match the defaults in ParseClientCookie() for clients whose cookies never cache.
g_bDisableLagComp[client] = false;
g_bPlayerLaserCompensated[client] = true;
g_bLagCompMessages[client] = false;
g_bSettingsTouched[client] = false;
g_iDisableLagComp[client] = 0; g_iDisableLagComp[client] = 0;
g_aLerpTicks[client] = 0; g_aLerpTicks[client] = 0;
} }
public void OnClientCookiesCached(int client) public void OnClientCookiesCached(int client)
{ {
char sBuffer[16]; // A toggle made before the cookies arrived wins, so flush it instead of
GetClientCookie(client, g_hCookie_EnableLagComp, sBuffer, sizeof(sBuffer)); // overwriting the client's choice with the stored value.
g_bEnableLagComp[client] = StringToInt(sBuffer) != 0; //this wording should make more sense, if the cookie exists its true to enable it. if(g_bSettingsTouched[client])
GetClientCookie(client, g_hCookie_LagCompMessages, sBuffer, sizeof(sBuffer)); {
g_bLagCompMessages[client] = StringToInt(sBuffer) != 0; SaveLagCompSettings(client);
return;
}
// Load all settings from single cookie
ParseClientCookie(client, g_bDisableLagComp[client], g_bPlayerLaserCompensated[client], g_bLagCompMessages[client]);
} }
public void OnClientSettingsChanged(int client) public void OnClientSettingsChanged(int client)
@@ -511,7 +522,10 @@ public void OnClientSettingsChanged(int client)
public void OnClientDisconnect(int client) public void OnClientDisconnect(int client)
{ {
g_bEnableLagComp[client] = false; g_bDisableLagComp[client] = false;
g_bPlayerLaserCompensated[client] = true;
g_bLagCompMessages[client] = false;
g_bSettingsTouched[client] = false;
g_iDisableLagComp[client] = 0; g_iDisableLagComp[client] = 0;
} }
@@ -529,8 +543,9 @@ public void OnEntityCreated(int entity, const char[] classname)
DHookEntity(g_hAcceptInput, true, entity); DHookEntity(g_hAcceptInput, true, entity);
} }
if (!g_bHasOnEntitySpawned && (!strncmp(classname, "func_physbox", 12, false) || (g_iCompenseEntityClass == 0 && strcmp(classname, "trigger_hurt", false) == 0 || if (!g_bHasOnEntitySpawned && (!strncmp(classname, "func_physbox", 12, false) ||
strcmp(classname, "trigger_push", false) == 0 || strcmp(classname, "trigger_teleport", false) == 0))) (g_iCompenseEntityClass == 0 && (strcmp(classname, "trigger_hurt", false) == 0 ||
strcmp(classname, "trigger_push", false) == 0 || strcmp(classname, "trigger_teleport", false) == 0))))
{ {
SDKHook(entity, SDKHook_SpawnPost, OnSDKHookEntitySpawnPost); SDKHook(entity, SDKHook_SpawnPost, OnSDKHookEntitySpawnPost);
} }
@@ -570,7 +585,7 @@ public MRESReturn Hook_AcceptInput(int entity, Handle hReturn, Handle hParams)
if(iCaller <= 0 || iCaller >= MAX_EDICTS) if(iCaller <= 0 || iCaller >= MAX_EDICTS)
return MRES_Ignored; return MRES_Ignored;
// Dont lagcompensate anything that has a game_ui button in their hierarchy. // Don't lagcompensate anything that has a game_ui button in their hierarchy.
BlacklistFamily(iCaller); BlacklistFamily(iCaller);
return MRES_Ignored; return MRES_Ignored;
@@ -623,7 +638,7 @@ void BlacklistChildren(int parent)
bool CheckEntityForLagComp(int entity, const char[] classname, bool bRecursive=false, bool bGoodParents=false) bool CheckEntityForLagComp(int entity, const char[] classname, bool bRecursive=false, bool bGoodParents=false)
{ {
if(entity < 0 || entity > MAX_EDICTS) if(entity < 0 || entity >= MAX_EDICTS)
return false; return false;
if(!IsValidEntity(entity)) if(!IsValidEntity(entity))
@@ -668,7 +683,7 @@ bool CheckEntityForLagComp(int entity, const char[] classname, bool bRecursive=f
return false; return false;
} }
if(CheckBit(g_aBlacklisted, entity)) if(CheckBit(g_aBlacklisted, iParent))
{ {
return false; return false;
} }
@@ -736,7 +751,7 @@ public void OnEntityDestroyed(int entity)
if(g_bCleaningUp) if(g_bCleaningUp)
return; return;
if(entity < 0 || entity > MAX_EDICTS) if(entity < 0 || entity >= MAX_EDICTS)
return; return;
ClearBit(g_aBlacklisted, entity); ClearBit(g_aBlacklisted, entity);
@@ -758,7 +773,7 @@ public MRESReturn Detour_OnUTIL_Remove(Handle hParams)
return MRES_Ignored; return MRES_Ignored;
int entity = DHookGetParamObjectPtrVar(hParams, 1, g_iNetworkableOuter, ObjectValueType_CBaseEntityPtr); int entity = DHookGetParamObjectPtrVar(hParams, 1, g_iNetworkableOuter, ObjectValueType_CBaseEntityPtr);
if(entity < 0 || entity > MAX_EDICTS) if(entity < 0 || entity >= MAX_EDICTS)
return MRES_Ignored; return MRES_Ignored;
int iIndex = g_aLagCompensated[entity]; int iIndex = g_aLagCompensated[entity];
@@ -858,8 +873,8 @@ public MRESReturn Detour_OnFrameUpdatePostEntityThink()
for(int i = 0; i < g_iNumEntities; i++) for(int i = 0; i < g_iNumEntities; i++)
{ {
// Dont make the entity check untouch in FrameUpdatePostEntityThink. // Dont make the entity check untouch in FrameUpdatePostEntityThink.
// If the player didnt get simulated in the current frame then // If the player didn't get simulated in the current frame then
// they didnt have a chance to touch this entity. // they didn't have a chance to touch this entity.
// Hence the touchlink could be broken and we only let the player check untouch. // Hence the touchlink could be broken and we only let the player check untouch.
int EFlags = GetEntData(g_aEntityLagData[i].iEntity, g_iEFlags); int EFlags = GetEntData(g_aEntityLagData[i].iEntity, g_iEFlags);
EFlags &= ~EFL_CHECK_UNTOUCH; EFlags &= ~EFL_CHECK_UNTOUCH;
@@ -877,7 +892,7 @@ public void OnRunThinkFunctions(bool simulating)
public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2]) public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2])
{ {
if(!IsPlayerAlive(client) || IsFakeClient(client)) if(!IsClientInGame(client) || !IsPlayerAlive(client) || IsFakeClient(client))
return Plugin_Continue; return Plugin_Continue;
int iTargetTick = tickcount - g_aLerpTicks[client]; int iTargetTick = tickcount - g_aLerpTicks[client];
@@ -928,6 +943,13 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
continue; continue;
int iRecord = iDelta; int iRecord = iDelta;
if(!g_bPlayerLaserCompensated[client] &&
(strcmp(g_aEntityLagData[i].sClassname, "trigger_hurt", false) == 0 ||
strcmp(g_aEntityLagData[i].sClassname, "trigger_push", false) == 0 ||
strcmp(g_aEntityLagData[i].sClassname, "trigger_teleport", false) == 0))
iRecord = 0;
if(iRecord >= g_aEntityLagData[i].iNumRecords) if(iRecord >= g_aEntityLagData[i].iNumRecords)
iRecord = g_aEntityLagData[i].iNumRecords - 1; iRecord = g_aEntityLagData[i].iNumRecords - 1;
@@ -1112,6 +1134,10 @@ bool AddEntityForLagCompensation(int iEntity, bool bLateKill)
if(g_bCleaningUp) if(g_bCleaningUp)
return false; return false;
// sm_unlag takes an arbitrary index from the console, so validate before indexing anything.
if(iEntity < 0 || iEntity >= MAX_EDICTS || !IsValidEntity(iEntity))
return false;
if(g_aLagCompensated[iEntity] != -1) if(g_aLagCompensated[iEntity] != -1)
return false; return false;
@@ -1144,6 +1170,7 @@ bool AddEntityForLagCompensation(int iEntity, bool bLateKill)
g_aEntityLagData[i].iNotMoving = MAX_RECORDS; g_aEntityLagData[i].iNotMoving = MAX_RECORDS;
g_aEntityLagData[i].bRestore = false; g_aEntityLagData[i].bRestore = false;
g_aEntityLagData[i].bLateKill = bLateKill; g_aEntityLagData[i].bLateKill = bLateKill;
g_aEntityLagData[i].sClassname = sClassname;
if(bLateKill) if(bLateKill)
{ {
@@ -1226,6 +1253,7 @@ void EntityLagData_Copy(EntityLagData obj, const EntityLagData other)
obj.iNotMoving = other.iNotMoving; obj.iNotMoving = other.iNotMoving;
obj.bRestore = other.bRestore; obj.bRestore = other.bRestore;
obj.bLateKill = other.bLateKill; obj.bLateKill = other.bLateKill;
obj.sClassname = other.sClassname;
} }
void LagRecord_Copy(LagRecord obj, const LagRecord other) void LagRecord_Copy(LagRecord obj, const LagRecord other)
@@ -1253,6 +1281,59 @@ bool CompareVectors(const float vec1[3], const float vec2[3])
return vec1[0] == vec2[0] && vec1[1] == vec2[1] && vec1[2] == vec2[2]; return vec1[0] == vec2[0] && vec1[1] == vec2[1] && vec1[2] == vec2[2];
} }
void SaveLagCompSettings(int client)
{
// Remember that this client chose something, so OnClientCookiesCached
// flushes it rather than loading over the top of it.
g_bSettingsTouched[client] = true;
// Cookie reads/writes are meaningless until the cookies arrive; we get called back then.
if(!AreClientCookiesCached(client))
return;
// Read current cookie values
bool currentDisableLagComp, currentPlayerLaserCompensated, currentLagCompMessages;
ParseClientCookie(client, currentDisableLagComp, currentPlayerLaserCompensated, currentLagCompMessages);
// Check if values have changed
bool disableChanged = g_bDisableLagComp[client] != currentDisableLagComp;
bool laserChanged = g_bPlayerLaserCompensated[client] != currentPlayerLaserCompensated;
bool messagesChanged = g_bLagCompMessages[client] != currentLagCompMessages;
// If no values have changed, no need to save
if (!disableChanged && !laserChanged && !messagesChanged) {
return;
}
// Otherwise, save the chain format
char sBuffer[8];
Format(sBuffer, sizeof(sBuffer), "%d%d%d",
g_bDisableLagComp[client] ? 1 : 0,
g_bPlayerLaserCompensated[client] ? 1 : 0,
g_bLagCompMessages[client] ? 1 : 0);
SetClientCookie(client, g_hCookie_LagCompSettings, sBuffer);
}
void ParseClientCookie(int client, bool &disableLagComp, bool &playerLaserCompensated, bool &lagCompMessages)
{
char buffer[16];
GetClientCookie(client, g_hCookie_LagCompSettings, buffer, sizeof(buffer));
// Parse chain format: disable|laser|messages
if (strlen(buffer) >= 3)
{
disableLagComp = (buffer[0] == '1');
playerLaserCompensated = (buffer[1] == '1');
lagCompMessages = (buffer[2] == '1');
}
else
{
// Default values
disableLagComp = false;
playerLaserCompensated = true;
lagCompMessages = false;
}
}
public Action Command_AddLagCompensation(int client, int argc) public Action Command_AddLagCompensation(int client, int argc)
{ {
@@ -1355,9 +1436,9 @@ stock void PrintToBoth(const char[] format, any ...)
for(int client = 1; client <= MaxClients; client++) for(int client = 1; client <= MaxClients; client++)
{ {
if (IsClientInGame(client) && g_bLagCompMessages[client]) if (IsClientInGame(client) && g_bLagCompMessages[client] && CheckCommandAccess(client, "sm_lagged", ADMFLAG_ROOT))
{ {
PrintToChat(client, "%s", buffer); PrintToConsole(client, "%s", buffer);
} }
} }
} }
@@ -1370,22 +1451,25 @@ public Action DisableLagCompTimer(Handle timer)
continue; continue;
// https://github.com/ValveSoftware/source-sdk-2013/blob/master/sp/src/game/server/util.cpp#L747 // https://github.com/ValveSoftware/source-sdk-2013/blob/master/sp/src/game/server/util.cpp#L747
// Lag compensation only kicks in above the ping threshold, so ramp it off below it.
if (g_bCheckPing) if (g_bCheckPing)
{ {
int iAvgPing = RoundFloat(GetClientAvgLatency(client, NetFlow_Outgoing) * 1000); int iAvgPing = RoundFloat(GetClientAvgLatency(client, NetFlow_Outgoing) * 1000);
if (iAvgPing > g_iMinPing) if (iAvgPing <= g_iMinPing)
{ {
g_iDisableLagComp[client]++; if(g_iDisableLagComp[client] < MAX_RECORDS)
return Plugin_Continue; g_iDisableLagComp[client]++;
continue;
} }
} }
if(!g_bEnableLagComp[client] && g_iDisableLagComp[client] < MAX_RECORDS) if(g_bDisableLagComp[client] && g_iDisableLagComp[client] < MAX_RECORDS)
{ {
g_iDisableLagComp[client]++; g_iDisableLagComp[client]++;
} }
else if(g_bEnableLagComp[client] && g_iDisableLagComp[client] > 0) else if(!g_bDisableLagComp[client] && g_iDisableLagComp[client] > 0)
{ {
g_iDisableLagComp[client]--; g_iDisableLagComp[client]--;
} }
@@ -1406,33 +1490,52 @@ public Action OnToggleLagCompSettings(int client, int args)
return Plugin_Handled; return Plugin_Handled;
} }
public Action OnToggleLagCompLasersSettings(int client, int args)
{
ToggleLagCompLasers(client);
return Plugin_Handled;
}
public void ToggleLagCompSettings(int client) public void ToggleLagCompSettings(int client)
{ {
if(!client) if(!client || !IsClientInGame(client) || IsFakeClient(client))
return; return;
g_bEnableLagComp[client] = !g_bEnableLagComp[client]; g_bDisableLagComp[client] = !g_bDisableLagComp[client];
SetClientCookie(client, g_hCookie_EnableLagComp, g_bEnableLagComp[client] ? "1" : ""); SaveLagCompSettings(client);
CPrintToChat(client, "%s LagCompensation has been %s.", PREFIX, g_bEnableLagComp[client] ? "enabled" : "disabled"); CPrintToChat(client, "%s LagCompensation has been %s.", PREFIX, g_bDisableLagComp[client] ? "disabled" : "enabled");
}
public void ToggleLagCompLasers(int client)
{
if(!client || !IsClientInGame(client) || IsFakeClient(client))
return;
g_bPlayerLaserCompensated[client] = !g_bPlayerLaserCompensated[client];
SaveLagCompSettings(client);
CPrintToChat(client, "%s LagCompensation for Lasers has been %s.", PREFIX, g_bPlayerLaserCompensated[client] ? "enabled" : "disabled");
if (g_bCheckPing && g_bPlayerLaserCompensated[client])
CPrintToChat(client, "%s It will take effect if your real ping is higher than %dms.", PREFIX, g_iMinPing);
} }
public void ToggleLagCompMessages(int client) public void ToggleLagCompMessages(int client)
{ {
if(!client) if(!client || !IsClientInGame(client) || IsFakeClient(client))
return; return;
g_bLagCompMessages[client] = !g_bLagCompMessages[client]; g_bLagCompMessages[client] = !g_bLagCompMessages[client];
SetClientCookie(client, g_hCookie_LagCompMessages, g_bLagCompMessages[client] ? "1" : ""); SaveLagCompSettings(client);
CPrintToChat(client, "%s LagCompensation messages have been %s.", PREFIX, g_bLagCompMessages[client] ? "enabled" : "disabled"); CPrintToChat(client, "%s LagCompensation messages have been %s.", PREFIX, g_bLagCompMessages[client] ? "enabled" : "disabled");
} }
public Action CheckLagComp(int client, int args) public Action CheckLagComp(int client, int args)
{ {
if (args > 1) if (args > 1 || (args == 0 && !client))
{ {
CPrintToChat(client, "%s Usage sm_checklag <client>", PREFIX); CReplyToCommand(client, "%s Usage: sm_checklag <client>", PREFIX);
return Plugin_Handled; return Plugin_Handled;
} }
@@ -1455,7 +1558,14 @@ public Action CheckLagComp(int client, int args)
return Plugin_Handled; return Plugin_Handled;
} }
CPrintToChat(client, "%s LagCompensation is %s for {olive}%N", PREFIX, g_bEnableLagComp[target] ? sEnable : "disabled", target); CReplyToCommand(client, "%s LagCompensation is %s for {olive}%N", PREFIX, g_bDisableLagComp[target] ? "disabled" : sEnable, target);
CReplyToCommand(client, "%s Laser compensation: %s", PREFIX, g_bPlayerLaserCompensated[target] ? "enabled" : "disabled");
// g_iDisableLagComp also ramps from the ping threshold, so report it when they haven't opted out.
if(!g_bDisableLagComp[target] && g_iDisableLagComp[target] > 0)
CReplyToCommand(client, "%s Currently reduced: %d of %d ticks skipped%s.", PREFIX,
g_iDisableLagComp[target], MAX_RECORDS,
g_bCheckPing ? " (ping at or below the threshold ramps this up)" : "");
return Plugin_Handled; return Plugin_Handled;
} }
@@ -1463,15 +1573,17 @@ public Action CheckLagComp(int client, int args)
public void ShowSettingsMenu(int client) public void ShowSettingsMenu(int client)
{ {
Menu menu = new Menu(MenuHandler_MainMenu); Menu menu = new Menu(MenuHandler_MainMenu);
menu.SetTitle("LagCompensation Settings", client); menu.SetTitle("LagCompensation Settings");
menu.ExitBackButton = true; menu.ExitBackButton = true;
char buffer[128], msg_buffer[128]; char buffer[128], buffer_lasers[128], msg_buffer[128];
Format(buffer, sizeof(buffer), "LagCompensation: %s", g_bEnableLagComp[client] ? "Enabled" : "Disabled"); Format(buffer, sizeof(buffer), "LagCompensation: %s", g_bDisableLagComp[client] ? "Disabled" : "Enabled");
Format(buffer_lasers, sizeof(buffer_lasers), "LagCompensation for Lasers: %s", g_bPlayerLaserCompensated[client] ? "Enabled" : "Disabled");
Format(msg_buffer, sizeof(msg_buffer), "LagCompensation Messages: %s", g_bLagCompMessages[client] ? "Enabled" : "Disabled"); Format(msg_buffer, sizeof(msg_buffer), "LagCompensation Messages: %s", g_bLagCompMessages[client] ? "Enabled" : "Disabled");
menu.AddItem("0", buffer); menu.AddItem("0", buffer);
menu.AddItem("1", msg_buffer); menu.AddItem("1", buffer_lasers);
menu.AddItem("2", msg_buffer, CheckCommandAccess(client, "sm_lagged", ADMFLAG_ROOT) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
menu.Display(client, MENU_TIME_FOREVER); menu.Display(client, MENU_TIME_FOREVER);
} }
@@ -1482,7 +1594,7 @@ public void MenuHandler_CookieMenu(int client, CookieMenuAction action, any info
{ {
case(CookieMenuAction_DisplayOption): case(CookieMenuAction_DisplayOption):
{ {
Format(buffer, maxlen, "LagCompensation", client); strcopy(buffer, maxlen, "LagCompensation");
} }
case(CookieMenuAction_SelectOption): case(CookieMenuAction_SelectOption):
{ {
@@ -1500,7 +1612,8 @@ public int MenuHandler_MainMenu(Menu menu, MenuAction action, int client, int se
switch(selection) switch(selection)
{ {
case(0): ToggleLagCompSettings(client); case(0): ToggleLagCompSettings(client);
case(1): ToggleLagCompMessages(client); case(1): ToggleLagCompLasers(client);
case(2): ToggleLagCompMessages(client);
} }
ShowSettingsMenu(client); ShowSettingsMenu(client);
+282
View File
@@ -1030,6 +1030,13 @@ public void LeaderMenu(int client)
AddMenuItem(menu, "ping", "Ping Menu"); AddMenuItem(menu, "ping", "Ping Menu");
AddMenuItem(menu, "beacon", "Toggle Beacon"); AddMenuItem(menu, "beacon", "Toggle Beacon");
// RCON-only options
if (CheckCommandAccess(client, "", ADMFLAG_RCON, false))
{
AddMenuItem(menu, "addleader", "[RCON] Add Leader to File");
AddMenuItem(menu, "removeleader", "[RCON] Remove Leader from File");
}
SetMenuExitButton(menu, true); SetMenuExitButton(menu, true);
DisplayMenu(menu, client, MENU_TIME_FOREVER); DisplayMenu(menu, client, MENU_TIME_FOREVER);
} }
@@ -1046,6 +1053,23 @@ public int LeaderMenu_Handler(Handle menu, MenuAction action, int client, int po
char info[32]; char info[32];
GetMenuItem(menu, position, info, sizeof(info)); GetMenuItem(menu, position, info, sizeof(info));
if(StrEqual(info, "addleader"))
{
if(CheckCommandAccess(client, "", ADMFLAG_RCON, false))
{
AddLeaderMenu(client);
}
}
if(StrEqual(info, "removeleader"))
{
if(CheckCommandAccess(client, "", ADMFLAG_RCON, false))
{
RemoveLeaderMenu(client);
}
}
if(StrEqual(info, "resign")) if(StrEqual(info, "resign"))
{ {
RemoveLeader(client); RemoveLeader(client);
@@ -1070,7 +1094,260 @@ public int LeaderMenu_Handler(Handle menu, MenuAction action, int client, int po
delete menu; delete menu;
} }
} }
return 0;
}
//----------------------------------------------------------------------------------------------------
// Purpose: RCON - shows connected players to add to the leaders file
//----------------------------------------------------------------------------------------------------
public void AddLeaderMenu(int client)
{
Handle menu = CreateMenu(AddLeaderMenu_Handler);
SetMenuTitle(menu, "Select a player to ADD as Leader");
char info[12], display[MAX_NAME_LENGTH];
bool any = false;
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientInGame(i) && !IsFakeClient(i))
{
any = true;
IntToString(GetClientUserId(i), info, sizeof(info));
GetClientName(i, display, sizeof(display));
AddMenuItem(menu, info, display);
}
}
if(!any)
{
AddMenuItem(menu, "", "No players connected", ITEMDRAW_DISABLED);
}
SetMenuExitBackButton(menu, true);
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, MENU_TIME_FOREVER);
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int AddLeaderMenu_Handler(Handle menu, MenuAction action, int client, int position)
{
if(action == MenuAction_Select)
{
if(!CheckCommandAccess(client, "", ADMFLAG_RCON, false))
{
PrintToChat(client, "[SM] You no longer have access to this.");
return 0;
}
char info[12];
GetMenuItem(menu, position, info, sizeof(info));
int target = GetClientOfUserId(StringToInt(info));
if(target == 0)
{
PrintToChat(client, "[SM] That player is no longer available.");
}
else
{
AddLeaderToFile(client, target);
}
LeaderMenu(client);
}
else if(action == MenuAction_End)
{
delete menu;
}
else if(action == MenuAction_Cancel && position == MenuCancel_ExitBack)
{
LeaderMenu(client);
}
return 0;
}
//AI slop
//----------------------------------------------------------------------------------------------------
// Purpose: RCON - shows connected players to remove from the leaders file
//----------------------------------------------------------------------------------------------------
public void RemoveLeaderMenu(int client)
{
Handle menu = CreateMenu(RemoveLeaderMenu_Handler);
SetMenuTitle(menu, "Select a player to REMOVE as Leader");
char info[12], display[MAX_NAME_LENGTH];
bool any = false;
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientInGame(i) && !IsFakeClient(i))
{
any = true;
IntToString(GetClientUserId(i), info, sizeof(info));
GetClientName(i, display, sizeof(display));
AddMenuItem(menu, info, display);
}
}
if(!any)
{
AddMenuItem(menu, "", "No players connected", ITEMDRAW_DISABLED);
}
SetMenuExitBackButton(menu, true);
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, MENU_TIME_FOREVER);
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int RemoveLeaderMenu_Handler(Handle menu, MenuAction action, int client, int position)
{
if(action == MenuAction_Select)
{
if(!CheckCommandAccess(client, "", ADMFLAG_RCON, false))
{
PrintToChat(client, "[SM] You no longer have access to this.");
return 0;
}
char info[12];
GetMenuItem(menu, position, info, sizeof(info));
int target = GetClientOfUserId(StringToInt(info));
if(target == 0)
{
PrintToChat(client, "[SM] That player is no longer available.");
}
else
{
RemoveLeaderFromFile(client, target);
}
LeaderMenu(client);
}
else if(action == MenuAction_End)
{
delete menu;
}
else if(action == MenuAction_Cancel && position == MenuCancel_ExitBack)
{
LeaderMenu(client);
}
return 0;
}
//----------------------------------------------------------------------------------------------------
// Purpose: Appends a targets SteamID2 to the leaders file with their name as a comment
//----------------------------------------------------------------------------------------------------
public void AddLeaderToFile(int admin, int target)
{
char sAuth[64], sName[MAX_NAME_LENGTH];
if(!GetClientAuthId(target, AuthId_Steam2, sAuth, sizeof(sAuth)))
{
PrintToChat(admin, "[SM] Could not resolve a SteamID for that player yet, try again in a moment.");
return;
}
GetClientName(target, sName, sizeof(sName));
if(IsPossibleLeader(target))
{
PrintToChat(admin, "[SM] %N is already in the leaders file.", target);
return;
}
File fFile = OpenFile(g_sDataFile, "a");
if(!fFile)
{
PrintToChat(admin, "[SM] Failed to open the leaders file for writing.");
return;
}
fFile.WriteLine("\"%s\" //%s", sAuth, sName);
fFile.Close();
UpdateLeaders();
PrintToChatAll("[SM] %N added %N to the leaders list.", admin, target);
LogAction(admin, target, "\"%L\" added \"%L\" to the leaders file", admin, target);
}
//----------------------------------------------------------------------------------------------------
// Purpose: Removes a targets SteamID2 line from the leaders file, if present
//----------------------------------------------------------------------------------------------------
public void RemoveLeaderFromFile(int admin, int target)
{
char sAuth[64];
if(!GetClientAuthId(target, AuthId_Steam2, sAuth, sizeof(sAuth)))
{
PrintToChat(admin, "[SM] Could not resolve a SteamID for that player yet, try again in a moment.");
return;
}
File fRead = OpenFile(g_sDataFile, "rt");
if(!fRead)
{
PrintToChat(admin, "[SM] Failed to open the leaders file for reading.");
return;
}
ArrayList lines = new ArrayList(ByteCountToCells(255));
char line[255];
bool found = false;
while(!fRead.EndOfFile() && fRead.ReadLine(line, sizeof(line)))
{
// Only skip the first line that actually contains this SteamID (inside the quotes)
if(!found && StrContains(line, sAuth) != -1)
{
found = true;
continue;
}
lines.PushString(line);
}
fRead.Close();
if(!found)
{
delete lines;
PrintToChat(admin, "[SM] %N was not found in the leaders file.", target);
return;
}
File fWrite = OpenFile(g_sDataFile, "wt");
if(!fWrite)
{
delete lines;
PrintToChat(admin, "[SM] Failed to open the leaders file for writing.");
return;
}
int count = lines.Length;
for(int i = 0; i < count; i++)
{
lines.GetString(i, line, sizeof(line));
fWrite.WriteLine(line);
}
fWrite.Close();
delete lines;
UpdateLeaders();
PrintToChatAll("[SM] %N removed %N from the leaders list.", admin, target);
LogAction(admin, target, "\"%L\" removed \"%L\" from the leaders file", admin, target);
// If the person removed is the current leader, kick them out of the role too
if(target == leaderClient)
{
RemoveLeader(target);
PrintToChatAll("[SM] %N is no longer a valid leader and has been removed from the leader role.", target);
}
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -1191,6 +1468,7 @@ public int SpriteMenu_Handler(Handle menu, MenuAction action, int client, int po
LeaderMenu(client); LeaderMenu(client);
} }
} }
return 0;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -1320,6 +1598,7 @@ public int PingMenu_Handler(Handle menu, MenuAction action, int client, int posi
LeaderMenu(client); LeaderMenu(client);
} }
} }
return 0;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -1353,6 +1632,7 @@ public Action Event_PlayerDeath(Handle event, char[] name, bool dontBroadcast)
PrintToChatAll("[SM] The leader has died!"); PrintToChatAll("[SM] The leader has died!");
RemoveLeader(client); RemoveLeader(client);
} }
return Plugin_Handled;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -1413,6 +1693,7 @@ public Action Event_RoundEnd(Handle event, char[] name, bool dontBroadcast)
pingEntity1 = -1; pingEntity1 = -1;
pingEntity2 = -1; pingEntity2 = -1;
pingEntity3 = -1; pingEntity3 = -1;
return Plugin_Handled;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -1463,6 +1744,7 @@ public int Native_CurrentLeader(Handle plugin, int numParams)
public int Native_SetLeader(Handle plugin, int numParams) public int Native_SetLeader(Handle plugin, int numParams)
{ {
SetLeader(GetNativeCell(1)); SetLeader(GetNativeCell(1));
return 0;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// Purpose: // Purpose:
+102 -16
View File
@@ -7,16 +7,7 @@
#pragma semicolon 1 #pragma semicolon 1
#pragma newdecls required #pragma newdecls required
public Plugin myinfo = #define NUMBEROFSTAGES 7
{
name = "MakoVoteSystem",
author = "Neon",
description = "MakoVoteSystem",
version = "1.1",
url = "https://steamcommunity.com/id/n3ontm"
}
#define NUMBEROFSTAGES 6
bool g_bVoteFinished = true; bool g_bVoteFinished = true;
bool g_bIsRevote = false; bool g_bIsRevote = false;
@@ -24,13 +15,15 @@ bool g_bStartVoteNextRound = false;
bool g_bPlayedZM = false; bool g_bPlayedZM = false;
bool g_bOnCooldown[NUMBEROFSTAGES]; bool g_bOnCooldown[NUMBEROFSTAGES];
static char g_sStageName[NUMBEROFSTAGES][32] = {"Extreme 2", "Extreme 2 (Heal + Ultima)", "Extreme 3 (ZED)", "Extreme 3 (Hellz)", "Race Mode", "Zombie Mode"}; static char g_sStageName[NUMBEROFSTAGES][32] = {"Extreme 2 (Heal + Ultima)", "Extreme 3 (ZED)", "Extreme 3 (Hellz)", "Race Mode", "Zombie Mode", "Extreme 4 RMZS", "Ext2 Special Lasers"};
int g_Winnerstage; int g_Winnerstage;
Handle g_VoteMenu = INVALID_HANDLE; Handle g_VoteMenu = INVALID_HANDLE;
Handle g_StageList = INVALID_HANDLE; Handle g_StageList = INVALID_HANDLE;
Handle g_CountdownTimer = INVALID_HANDLE; Handle g_CountdownTimer = INVALID_HANDLE;
bool g_bCorrectMap = false;
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// Purpose: // Purpose:
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -57,6 +50,7 @@ public void OnPluginStart()
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void OnMapStart() public void OnMapStart()
{ {
g_bCorrectMap = false;
VerifyMap(); VerifyMap();
g_bStartVoteNextRound = false; g_bStartVoteNextRound = false;
@@ -76,17 +70,22 @@ public Action VerifyMap()
if (!StrEqual(currentMap, "ze_ffvii_mako_reactor_v5_3", false)) if (!StrEqual(currentMap, "ze_ffvii_mako_reactor_v5_3", false))
{ {
//plugin unloading can make map switches very slow
/*
char sFilename[256]; char sFilename[256];
GetPluginFilename(INVALID_HANDLE, sFilename, sizeof(sFilename)); GetPluginFilename(INVALID_HANDLE, sFilename, sizeof(sFilename));
ServerCommand("sm plugins unload %s", sFilename); ServerCommand("sm plugins unload %s", sFilename);
*/
} }
else else
{ {
g_bCorrectMap = true;
PrecacheSound("#unloze/Pendulum - Witchcraft.mp3", true); PrecacheSound("#unloze/Pendulum - Witchcraft.mp3", true);
AddFileToDownloadsTable("sound/unloze/Pendulum - Witchcraft.mp3"); AddFileToDownloadsTable("sound/unloze/Pendulum - Witchcraft.mp3");
} }
return Plugin_Handled;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -94,6 +93,10 @@ public Action VerifyMap()
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void OnEntitySpawned(int iEntity, const char[] sClassname) public void OnEntitySpawned(int iEntity, const char[] sClassname)
{ {
if (!g_bCorrectMap)
{
return;
}
if (!IsValidEntity(iEntity) || g_bVoteFinished) if (!IsValidEntity(iEntity) || g_bVoteFinished)
return; return;
@@ -109,6 +112,10 @@ public void OnEntitySpawned(int iEntity, const char[] sClassname)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void OnRoundStart(Event hEvent, const char[] sEvent, bool bDontBroadcast) public void OnRoundStart(Event hEvent, const char[] sEvent, bool bDontBroadcast)
{ {
if (!g_bCorrectMap)
{
return;
}
if (g_bStartVoteNextRound) if (g_bStartVoteNextRound)
{ {
g_bVoteFinished = false; g_bVoteFinished = false;
@@ -160,9 +167,12 @@ public void OnRoundStart(Event hEvent, const char[] sEvent, bool bDontBroadcast)
if (iButton5 != INVALID_ENT_REFERENCE) if (iButton5 != INVALID_ENT_REFERENCE)
AcceptEntityInput(iButton5, "Lock"); AcceptEntityInput(iButton5, "Lock");
int iCounter = FindEntityByTargetname(INVALID_ENT_REFERENCE, "LevelCounter", "math_counter"); //its now a permanent entity so really dont kill it.
/*
int iCounter = FindEntityByTargetname(INVALID_ENT_REFERENCE, "LevelCounter", "info_target");
if (iCounter != INVALID_ENT_REFERENCE) if (iCounter != INVALID_ENT_REFERENCE)
AcceptEntityInput(iCounter, "Kill"); AcceptEntityInput(iCounter, "Kill");
*/
int iFilter = FindEntityByTargetname(INVALID_ENT_REFERENCE, "humanos", "filter_activator_team"); int iFilter = FindEntityByTargetname(INVALID_ENT_REFERENCE, "humanos", "filter_activator_team");
if (iFilter != INVALID_ENT_REFERENCE) if (iFilter != INVALID_ENT_REFERENCE)
@@ -245,6 +255,10 @@ public void OnRoundStart(Event hEvent, const char[] sEvent, bool bDontBroadcast)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void GenerateArray() public void GenerateArray()
{ {
if (!g_bCorrectMap)
{
return;
}
int iBlockSize = ByteCountToCells(PLATFORM_MAX_PATH); int iBlockSize = ByteCountToCells(PLATFORM_MAX_PATH);
g_StageList = CreateArray(iBlockSize); g_StageList = CreateArray(iBlockSize);
@@ -270,6 +284,11 @@ public void GenerateArray()
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public Action Command_StartVote(int args) public Action Command_StartVote(int args)
{ {
if (!g_bCorrectMap)
{
return Plugin_Handled;
}
int iCurrentStage = GetCurrentStage(); int iCurrentStage = GetCurrentStage();
if (iCurrentStage > 0) if (iCurrentStage > 0)
@@ -302,6 +321,10 @@ public Action Command_StartVote(int args)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public Action StartVote(Handle timer) public Action StartVote(Handle timer)
{ {
if (!g_bCorrectMap)
{
return Plugin_Handled;
}
static int iCountDown = 5; static int iCountDown = 5;
PrintCenterTextAll("[MakoVote] Starting Vote in %ds", iCountDown); PrintCenterTextAll("[MakoVote] Starting Vote in %ds", iCountDown);
@@ -312,6 +335,7 @@ public Action StartVote(Handle timer)
g_CountdownTimer = INVALID_HANDLE; g_CountdownTimer = INVALID_HANDLE;
InitiateVote(); InitiateVote();
} }
return Plugin_Handled;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -319,6 +343,10 @@ public Action StartVote(Handle timer)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void InitiateVote() public void InitiateVote()
{ {
if (!g_bCorrectMap)
{
return;
}
if(IsVoteInProgress()) if(IsVoteInProgress())
{ {
CPrintToChatAll("{green}[Mako Vote] {white}Another vote is currently in progress, retrying again in 5s."); CPrintToChatAll("{green}[Mako Vote] {white}Another vote is currently in progress, retrying again in 5s.");
@@ -347,7 +375,7 @@ public void InitiateVote()
} }
} }
SetMenuOptionFlags(g_VoteMenu, MENUFLAG_BUTTON_NOVOTE); //SetMenuOptionFlags(g_VoteMenu, MENUFLAG_BUTTON_NOVOTE);
SetMenuTitle(g_VoteMenu, "What stage to play next?"); SetMenuTitle(g_VoteMenu, "What stage to play next?");
SetVoteResultCallback(g_VoteMenu, Handler_SettingsVoteFinished); SetVoteResultCallback(g_VoteMenu, Handler_SettingsVoteFinished);
VoteMenuToAll(g_VoteMenu, 20); VoteMenuToAll(g_VoteMenu, 20);
@@ -358,6 +386,10 @@ public void InitiateVote()
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public int Handler_MakoVoteMenu(Handle menu, MenuAction action, int param1, int param2) public int Handler_MakoVoteMenu(Handle menu, MenuAction action, int param1, int param2)
{ {
if (!g_bCorrectMap)
{
return 0;
}
switch(action) switch(action)
{ {
case MenuAction_End: case MenuAction_End:
@@ -385,10 +417,15 @@ public int MenuHandler_NotifyPanel(Menu hMenu, MenuAction iAction, int iParam1,
case MenuAction_Select, MenuAction_Cancel: case MenuAction_Select, MenuAction_Cancel:
delete hMenu; delete hMenu;
} }
return 0;
} }
public void Handler_SettingsVoteFinished(Handle menu, int num_votes, int num_clients, const int[][] client_info, int num_items, const int[][] item_info) public void Handler_SettingsVoteFinished(Handle menu, int num_votes, int num_clients, const int[][] client_info, int num_items, const int[][] item_info)
{ {
if (!g_bCorrectMap)
{
return;
}
int highest_votes = item_info[0][VOTEINFO_ITEM_VOTES]; int highest_votes = item_info[0][VOTEINFO_ITEM_VOTES];
int required_percent = 60; int required_percent = 60;
int required_votes = RoundToCeil(float(num_votes) * float(required_percent) / 100); int required_votes = RoundToCeil(float(num_votes) * float(required_percent) / 100);
@@ -416,6 +453,10 @@ public void Handler_SettingsVoteFinished(Handle menu, int num_votes, int num_cli
public void Handler_VoteFinishedGeneric(Handle menu, int num_votes, int num_clients, const int[][] client_info, int num_items, const int[][] item_info) public void Handler_VoteFinishedGeneric(Handle menu, int num_votes, int num_clients, const int[][] client_info, int num_items, const int[][] item_info)
{ {
if (!g_bCorrectMap)
{
return;
}
g_bVoteFinished = true; g_bVoteFinished = true;
char sWinner[128]; char sWinner[128];
GetMenuItem(menu, item_info[0][VOTEINFO_ITEM_INDEX], sWinner, sizeof(sWinner)); GetMenuItem(menu, item_info[0][VOTEINFO_ITEM_INDEX], sWinner, sizeof(sWinner));
@@ -429,7 +470,42 @@ public void Handler_VoteFinishedGeneric(Handle menu, int num_votes, int num_clie
g_Winnerstage = i; g_Winnerstage = i;
} }
ServerCommand("sm_stage %d", (g_Winnerstage + 4)); //ServerCommand("sm_stage %d", (g_Winnerstage + 4));
char winner_stage[64];
if (StrEqual(sWinner, "Extreme 3 (Hellz)"))
{
Format(winner_stage, sizeof(winner_stage), "hellz");
}
else if (StrEqual(sWinner, "Extreme 2"))
{
Format(winner_stage, sizeof(winner_stage), "extreme2");
}
else if (StrEqual(sWinner, "Extreme 2 (Heal + Ultima)"))
{
Format(winner_stage, sizeof(winner_stage), "ultiheal");
}
else if (StrEqual(sWinner, "Extreme 3 (ZED)"))
{
Format(winner_stage, sizeof(winner_stage), "zombieden");
}
else if (StrEqual(sWinner, "Race Mode"))
{
Format(winner_stage, sizeof(winner_stage), "race");
}
else if (StrEqual(sWinner, "Zombie Mode"))
{
Format(winner_stage, sizeof(winner_stage), "zm");
}
else if (StrEqual(sWinner, "Extreme 4 RMZS"))
{
Format(winner_stage, sizeof(winner_stage), "rmzs");
}
else if (StrEqual(sWinner, "Ext2 Special Lasers"))
{
Format(winner_stage, sizeof(winner_stage), "laser");
}
ServerCommand("sm_stage %s", winner_stage);
float fDelay = 3.0; float fDelay = 3.0;
CS_TerminateRound(fDelay, CSRoundEnd_GameStart, false); CS_TerminateRound(fDelay, CSRoundEnd_GameStart, false);
@@ -437,7 +513,13 @@ public void Handler_VoteFinishedGeneric(Handle menu, int num_votes, int num_clie
public int GetCurrentStage() public int GetCurrentStage()
{ {
int iLevelCounterEnt = FindEntityByTargetname(INVALID_ENT_REFERENCE, "LevelCounter", "math_counter"); if (!g_bCorrectMap)
{
return 0;
}
//int iLevelCounterEnt = FindEntityByTargetname(INVALID_ENT_REFERENCE, "LevelCounter", "math_counter");
//due to the stripper its now an info_target and not math_counter.
int iLevelCounterEnt = FindEntityByTargetname(INVALID_ENT_REFERENCE, "LevelCounter", "info_target");
int offset = FindDataMapInfo(iLevelCounterEnt, "m_OutValue"); int offset = FindDataMapInfo(iLevelCounterEnt, "m_OutValue");
int iCounterVal = RoundFloat(GetEntDataFloat(iLevelCounterEnt, offset)); int iCounterVal = RoundFloat(GetEntDataFloat(iLevelCounterEnt, offset));
@@ -463,6 +545,10 @@ public int GetCurrentStage()
public int FindEntityByTargetname(int entity, const char[] sTargetname, const char[] sClassname) public int FindEntityByTargetname(int entity, const char[] sTargetname, const char[] sClassname)
{ {
if (!g_bCorrectMap)
{
return 0;
}
if(sTargetname[0] == '#') // HammerID if(sTargetname[0] == '#') // HammerID
{ {
int HammerID = StringToInt(sTargetname[1]); int HammerID = StringToInt(sTargetname[1]);
@@ -488,4 +574,4 @@ public int FindEntityByTargetname(int entity, const char[] sTargetname, const ch
} }
} }
return INVALID_ENT_REFERENCE; return INVALID_ENT_REFERENCE;
} }
+26 -17
View File
@@ -37,7 +37,7 @@ public void OnPluginStart()
ConVar cvar; ConVar cvar;
HookConVarChange((cvar = CreateConVar("sm_admin_afk_time", "30", "Time in seconds until an admin is considered as AFK.")), Cvar_AdminAFKTime); HookConVarChange((cvar = CreateConVar("sm_admin_afk_time", "30", "Time in seconds until an admin is considered as AFK.")), Cvar_AdminAFKTime);
g_iAdminAFKTime = cvar.IntValue; g_iAdminAFKTime = cvar.IntValue;
HookConVarChange((cvar = CreateConVar("sm_selfextend_amount", "2", "Amount of sm_selfextend's allowed.")), Cvar_SelfExtendsAmount); HookConVarChange((cvar = CreateConVar("sm_selfextend_amount", "2", "Amount of sm_selfextends allowed.")), Cvar_SelfExtendsAmount);
g_iSelfMaxExtendsAmount = cvar.IntValue; g_iSelfMaxExtendsAmount = cvar.IntValue;
HookConVarChange((cvar = CreateConVar("sm_selfextend_time", "10", "How long to extend in minutes when sm_selfextend passes through.")), Cvar_SelfExtendsTime); HookConVarChange((cvar = CreateConVar("sm_selfextend_time", "10", "How long to extend in minutes when sm_selfextend passes through.")), Cvar_SelfExtendsTime);
g_iSelfExtendsTime = cvar.IntValue; g_iSelfExtendsTime = cvar.IntValue;
@@ -175,24 +175,14 @@ public Action Command_DisplayActiveAdmins(int client, int args)
public Action Command_SelfExtend(int client, int args) public Action Command_SelfExtend(int client, int args)
{ {
int iAdminActivity = 0;
for(int i = 1; i <= MaxClients; i++)
if(g_bActiveAdmin[i])
iAdminActivity++;
if(GetExtendsLeft() > 0) if(GetExtendsLeft() > 0)
{ {
ReplyToCommand(client, "[SM] Not available because not all regular extends have been depleted."); ReplyToCommand(client, "[SM] Not available because not all regular extends have been depleted.");
return Plugin_Handled; return Plugin_Handled;
} }
if(iAdminActivity > 0)
{
ReplyToCommand(client, "[SM] Not available because there is atleast one active Admin who can extend. Please ask the Admins.");
return Plugin_Handled;
}
if(!g_bSelfExtendsAllowed) if(!g_bSelfExtendsAllowed)
{ {
ReplyToCommand(client, "[SM] Not available because it's still too early in the map."); ReplyToCommand(client, "[SM] Not available because its still too early in the map.");
return Plugin_Handled; return Plugin_Handled;
} }
if(g_iSelfMaxExtendsAmount <= g_iSelfExtends) if(g_iSelfMaxExtendsAmount <= g_iSelfExtends)
@@ -201,14 +191,34 @@ public Action Command_SelfExtend(int client, int args)
return Plugin_Handled; return Plugin_Handled;
} }
int iPlayers;
int iSelfExtendsPlayers;
int iPlayersNeeded;
for(int i = 1; i <= MaxClients; i++)
{
if(IsValidClient(i))
iPlayers++;
if(g_bSelfExtends[i])
iSelfExtendsPlayers++;
}
iPlayersNeeded = RoundToFloor(float(iPlayers) * g_fSelfExtendsRatio);
if (iPlayersNeeded == 0)
{
iPlayersNeeded = 1;
}
if(!g_bSelfExtends[client]) if(!g_bSelfExtends[client])
{ {
g_bSelfExtends[client] = true; g_bSelfExtends[client] = true;
PrintToChatAll("[SM] %N wants to self-extend the map.", client); PrintToChatAll("[SM] %N wants to self-extend the map. %i/%i", client, iSelfExtendsPlayers + 1, iPlayersNeeded);
CheckRatio(); CheckRatio();
} }
else else
ReplyToCommand(client, "[SM] You have already voted to self-extend the map."); {
ReplyToCommand(client, "[SM] You have already voted to self-extend the map. %i/%i", iSelfExtendsPlayers, iPlayersNeeded);
}
return Plugin_Handled; return Plugin_Handled;
} }
@@ -233,7 +243,7 @@ public void CheckRatio()
iPlayersNeeded = RoundToFloor(float(iPlayers) * g_fSelfExtendsRatio); iPlayersNeeded = RoundToFloor(float(iPlayers) * g_fSelfExtendsRatio);
if(iSelfExtendsPlayers >= iPlayersNeeded && iPlayersNeeded != 0) if(iSelfExtendsPlayers >= iPlayersNeeded && iSelfExtendsPlayers > 0)
{ {
PrintToChatAll("[SM] Enough Players voted to self-extend the map. Adding %d minutes to the timelimit.", g_iSelfExtendsTime); PrintToChatAll("[SM] Enough Players voted to self-extend the map. Adding %d minutes to the timelimit.", g_iSelfExtendsTime);
LogMessage("Enough Players voted to self-extend the map. Adding %d minutes to the timelimit.", g_iSelfExtendsTime); LogMessage("Enough Players voted to self-extend the map. Adding %d minutes to the timelimit.", g_iSelfExtendsTime);
@@ -243,7 +253,6 @@ public void CheckRatio()
for(int j; j <= MaxClients; j++) for(int j; j <= MaxClients; j++)
g_bSelfExtends[j] = false; g_bSelfExtends[j] = false;
} }
return; return;
} }
@@ -257,4 +266,4 @@ static stock bool IsValidClient(int client)
{ {
return false; return false;
} }
} }
@@ -11,7 +11,6 @@
ConVar g_hCvar_BlockSpoof; ConVar g_hCvar_BlockSpoof;
ConVar g_hCvar_BlockAdmin; ConVar g_hCvar_BlockAdmin;
ConVar g_hCvar_BlockVoice; ConVar g_hCvar_BlockVoice;
ConVar g_hCvar_AuthenticationTime;
/* DATABASE */ /* DATABASE */
Database g_hDatabase; Database g_hDatabase;
@@ -53,7 +52,6 @@ public void OnPluginStart()
g_hCvar_BlockSpoof = CreateConVar("sm_manager_block_spoof", "1", "Kick unauthenticated people that join with known steamids.", FCVAR_NONE, true, 0.0, true, 1.0); g_hCvar_BlockSpoof = CreateConVar("sm_manager_block_spoof", "1", "Kick unauthenticated people that join with known steamids.", FCVAR_NONE, true, 0.0, true, 1.0);
g_hCvar_BlockAdmin = CreateConVar("sm_manager_block_admin", "1", "Should unauthenticated people be blocked from admin?", FCVAR_NONE, true, 0.0, true, 1.0); g_hCvar_BlockAdmin = CreateConVar("sm_manager_block_admin", "1", "Should unauthenticated people be blocked from admin?", FCVAR_NONE, true, 0.0, true, 1.0);
g_hCvar_BlockVoice = CreateConVar("sm_manager_block_voice", "1", "Should unauthenticated people be blocked from voice?", FCVAR_NONE, true, 0.0, true, 1.0); g_hCvar_BlockVoice = CreateConVar("sm_manager_block_voice", "1", "Should unauthenticated people be blocked from voice?", FCVAR_NONE, true, 0.0, true, 1.0);
g_hCvar_AuthenticationTime = CreateConVar("sm_manager_authentication_time", "15", "Time in seconds after which a client needs to be assigned to a SteamID", FCVAR_NONE, true, 1.0);
AddMultiTargetFilter("@steam", Filter_Steam, "Steam Players", false); AddMultiTargetFilter("@steam", Filter_Steam, "Steam Players", false);
AddMultiTargetFilter("@nosteam", Filter_NoSteam, "No-Steam Players", false); AddMultiTargetFilter("@nosteam", Filter_NoSteam, "No-Steam Players", false);
@@ -258,14 +256,6 @@ public EConnect OnClientPreConnectEx(const char[] sName, char sPassword[255], co
return k_OnClientPreConnectEx_Accept; return k_OnClientPreConnectEx_Accept;
} }
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientPutInServer(int client)
{
//CreateTimer(g_hCvar_AuthenticationTime.FloatValue, CheckAuth, GetClientSerial(client), TIMER_FLAG_NO_MAPCHANGE);
}
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// Purpose: // Purpose:
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -273,9 +263,22 @@ public void OnClientAuthorized(int client, const char[] sAuthID)
{ {
char sAddress[16]; char sAddress[16];
GetClientIP(client, sAddress, sizeof(sAddress)); GetClientIP(client, sAddress, sizeof(sAddress));
static char sCountry[32]; //if its the webclient its not a malicious steam ID steal, just pure coincidence if it were to hit a real steam players steamID.
char allowed_ips[128];
ConVar sv_set_steam_id_ips = FindConVar("sv_set_steam_id_ips");
if (sv_set_steam_id_ips != null)
{
sv_set_steam_id_ips.GetString(allowed_ips, sizeof(allowed_ips));
if (StrEqual(sAddress, allowed_ips))
{
return;
}
}
//just kicking all nosteamers from algeria. not very cool but so be it. //just kicking all nosteamers from algeria. not very cool but so be it.
/* /*
static char sCountry[32];
if (GeoipCountry(sAddress, sCountry, sizeof(sCountry)) && StrEqual(sCountry, "Algeria", false)) if (GeoipCountry(sAddress, sCountry, sizeof(sCountry)) && StrEqual(sCountry, "Algeria", false))
{ {
if (!SteamClientAuthenticatedEx(sAuthID)) if (!SteamClientAuthenticatedEx(sAuthID))
@@ -334,61 +337,6 @@ public void OnClientPostAdminCheck(int client)
char sAuthID[32]; char sAuthID[32];
GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false); GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
/*
if(!SteamClientAuthenticatedEx(sAuthID))
{
LogMessage("%L was not authenticated with steam, muting client.", client);
BaseComm_SetClientMute(client, true);
return;
}
*/
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action CheckAuth(Handle timer, int data)
{
int client;
if ((client = GetClientFromSerial(data)) == 0)
return Plugin_Stop;
char sAuthID[32];
if(!GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), true))
{
LogMessage("%L could not be assigned to a SteamID, kicking client.", client);
//KickClient(client, "Invalid STEAMID");
if (IsValidClient(client))
{
Panel hNotifyPanel = new Panel(GetMenuStyleHandle(MenuStyle_Radio));
hNotifyPanel.DrawItem("WARNING: Your SteamID is Invalid: Reconnecting you to the server in 8 Seconds.", ITEMDRAW_RAWLINE);
hNotifyPanel.DrawItem("", ITEMDRAW_SPACER);
hNotifyPanel.DrawItem("IMPORTANT: You may disconnect, reconnect if necessary!", ITEMDRAW_RAWLINE);
hNotifyPanel.Send(client, MenuHandler_NotifyPanel, 8);
delete hNotifyPanel;
for (int i = 0; i < 8; i++)
{
PrintToChat(client, "WARNING: Your SteamID is Invalid: Reconnecting you to the server in 8 Seconds.");
}
CreateTimer(8.0, forceClientRetry, GetClientSerial(client));
}
}
return Plugin_Stop;
}
public Action forceClientRetry(Handle timer, int data)
{
int client;
if ((client = GetClientFromSerial(data)) == 0)
return Plugin_Stop;
if (IsValidClient(client))
{
ClientCommand(client, "retry");
}
return Plugin_Handled;
} }
stock bool IsValidClient(int client) stock bool IsValidClient(int client)
@@ -398,16 +346,6 @@ stock bool IsValidClient(int client)
return false; return false;
} }
int MenuHandler_NotifyPanel(Menu hMenu, MenuAction iAction, int iParam1, int iParam2)
{
switch (iAction)
{
case MenuAction_Select, MenuAction_Cancel:
delete hMenu;
}
return 0;
}
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// Purpose: // Purpose:
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -474,13 +412,12 @@ public void SQL_OnQueryCompleted(Database db, DBResultSet results, const char[]
{ {
if(StrEqual(sAddress, sResultAddress, false)) if(StrEqual(sAddress, sResultAddress, false))
{ {
LogMessage("%L tried to join with a legitimate steamid while not authenticated with steam. Allowing connection, IPs match. (Known: %s)", client, sAddress); LogMessage("%N tried to join with a legitimate steamid while not authenticated with steam. Allowing connection, IPs match. (Known: %s)", client, sAddress);
return; return;
} }
else else
{ {
LogAction(client, -1, "\"%L\" tried to join with a legitimate steamid while not authenticated with steam. Refusing connection, IPs dont match. (Known: %s | Current: %s)", client, sResultAddress, sAddress); LogMessage("%N tried to join with a legitimate steamid while not authenticated with steam. Refusing connection, IPs dont match. (Known: %s | Current: %s)", client, sResultAddress, sAddress);
static char sCountry[32];
KickClient(client, "Trying to join with a legitimate steamid while not authenticated with steam."); KickClient(client, "Trying to join with a legitimate steamid while not authenticated with steam.");
return; return;
} }
File diff suppressed because it is too large Load Diff
+171 -2
View File
@@ -1,6 +1,7 @@
#pragma semicolon 1 #pragma semicolon 1
#include <sourcemod> #include <sourcemod>
#include <sdktools> #include <sdktools>
#include <sdkhooks>
public Plugin myinfo = public Plugin myinfo =
{ {
@@ -19,6 +20,17 @@ Menu g_NpcMenu = null;
KeyValues g_Models; KeyValues g_Models;
ConVar g_cvNotifyShot;
ConVar g_cvNotifyTimer;
ArrayList g_aSpawnedProps; // Tracks entity indices of props spawned by this plugin so we can unhook them
ArrayList g_aNotifyList;
enum struct NotifyListData
{
int client;
Handle timer;
}
public void OnPluginStart() public void OnPluginStart()
{ {
@@ -42,6 +54,50 @@ public void OnPluginStart()
g_Models.Rewind(); // Go back to the root node g_Models.Rewind(); // Go back to the root node
RegAdminCmd("sm_propspawner", Command_MainMenu, ADMFLAG_CHANGEMAP); //g RegAdminCmd("sm_propspawner", Command_MainMenu, ADMFLAG_CHANGEMAP); //g
g_cvNotifyShot = CreateConVar("sm_propspawner_notify_shot", "0", "If set to 1, announces in chat when a plugin-spawned prop is shot.", FCVAR_NOTIFY, true, 0.0, true, 1.0);
g_cvNotifyTimer = CreateConVar("sm_propspawner_notify_shot_timer", "0.5", "How long a player stays in the \"shooting couch\" list.");
AutoExecConfig(true, "PropSpawner");
g_aSpawnedProps = new ArrayList();
g_aNotifyList = new ArrayList();
HookEvent("round_end", Event_RoundEnd);
}
public void OnEntityDestroyed(int entity)
{
// Safety net: if a tracked prop is removed by any means other than DeleteProp()
// (e.g. an explosion, another plugin, map cleanup), stop tracking it here too.
if (entity <= 0 || g_aSpawnedProps == null)
return;
int index = g_aSpawnedProps.FindValue(entity);
if (index != -1)
{
g_aSpawnedProps.Erase(index);
}
}
public void Event_RoundEnd(Event event, const char[] name, bool dontBroadcast)
{
UnhookAllSpawnedProps();
}
void UnhookAllSpawnedProps()
{
if (g_aSpawnedProps == null || !g_cvNotifyShot.BoolValue)
return;
for (int i = 0; i < g_aSpawnedProps.Length; i++)
{
int prop = g_aSpawnedProps.Get(i);
if (IsValidEntity(prop))
{
SDKUnhook(prop, SDKHook_OnTakeDamage, OnPropTakeDamage);
}
}
g_aSpawnedProps.Clear();
} }
public void OnMapStart() public void OnMapStart()
@@ -82,6 +138,8 @@ public void OnMapEnd()
delete(g_NpcMenu); delete(g_NpcMenu);
g_NpcMenu = null; g_NpcMenu = null;
} }
UnhookAllSpawnedProps();
} }
/* ----------------------------------- */ /* ----------------------------------- */
@@ -177,6 +235,7 @@ public int MainMenuHandler(Menu menu, MenuAction action, int client, int param2)
} }
} }
} }
return 0;
} }
public RotationHandler(Menu menu, MenuAction action, int client, int param2) public RotationHandler(Menu menu, MenuAction action, int client, int param2)
@@ -320,6 +379,15 @@ void DeleteProp(int client){
GetEdictClassname(DeleteIndex, classname, sizeof(classname)); GetEdictClassname(DeleteIndex, classname, sizeof(classname));
if(isAProp(classname)) if(isAProp(classname))
{ {
if (g_cvNotifyShot.BoolValue)
{
int propIndex = g_aSpawnedProps.FindValue(DeleteIndex);
if (propIndex != -1)
{
SDKUnhook(DeleteIndex, SDKHook_OnTakeDamage, OnPropTakeDamage);
g_aSpawnedProps.Erase(propIndex);
}
}
AcceptEntityInput(DeleteIndex, "Kill", -1, -1, 0); AcceptEntityInput(DeleteIndex, "Kill", -1, -1, 0);
ShowActivity2(client, "\x01[SM] \x04", "deleted a prop."); ShowActivity2(client, "\x01[SM] \x04", "deleted a prop.");
LogAction(client, -1, "\"%L\" deleted a prop.", client); LogAction(client, -1, "\"%L\" deleted a prop.", client);
@@ -405,7 +473,7 @@ void prop_any_create(int client)
char sModelExplodeRadius[11]; char sModelExplodeRadius[11];
int iModelExplode = g_Models.GetNum("explode",0); // if "explode" is not set, then it's 0 int iModelExplode = g_Models.GetNum("explode",0); // if "explode" is not set, then it's 0
g_Models.GetString("health", sModelHealth, sizeof(sModelHealth),"0"); // if "health" is not set, then it's 0 g_Models.GetString("health", sModelHealth, sizeof(sModelHealth),"0"); // if "health" is not set, then its 0
g_Models.GetString("explodedamage", sModelExplodeDamage, sizeof(sModelExplodeDamage),"1"); g_Models.GetString("explodedamage", sModelExplodeDamage, sizeof(sModelExplodeDamage),"1");
g_Models.GetString("exploderadius", sModelExplodeRadius, sizeof(sModelExplodeRadius),"1"); g_Models.GetString("exploderadius", sModelExplodeRadius, sizeof(sModelExplodeRadius),"1");
@@ -484,7 +552,108 @@ void prop_any_create(int client)
DispatchSpawn(prop); DispatchSpawn(prop);
AcceptEntityInput(prop, "TurnOn", prop, prop, 0); AcceptEntityInput(prop, "TurnOn", prop, prop, 0);
AcceptEntityInput(prop, "EnableCollision"); AcceptEntityInput(prop, "EnableCollision");
// Hook the prop so we can detect when it gets shot/damaged, and track it so we can unhook later
if (g_cvNotifyShot.BoolValue)
{
SetEntityFlags(prop, FL_CLIENT); //Now youre thinking with portals
SDKHook(prop, SDKHook_OnTakeDamage, OnPropTakeDamage);
g_aSpawnedProps.Push(prop);
}
ShowActivity2(client, "\x01[SM] \x04", "\x01Spawned \x04%s\x01.", sModelName); ShowActivity2(client, "\x01[SM] \x04", "\x01Spawned \x04%s\x01.", sModelName);
LogAction(client, -1, "\"%L\" Spawned \"%s\".", client, sModelName); LogAction(client, -1, "\"%L\" Spawned \"%s\".", client, sModelName);
} }
/* ----------------------------------- */
public Action OnPropTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float damageForce[3], float damagePosition[3], int damagecustom)
{
if (!g_cvNotifyShot.BoolValue)
return Plugin_Continue;
if (attacker < 1 || attacker > MaxClients || !IsClientInGame(attacker))
return Plugin_Continue;
Handle timer = CreateTimer(g_cvNotifyTimer.FloatValue, OnNotifyTimer, attacker);
int idx = FindInNotifyList(attacker);
if (idx == -1)
{
NotifyListData data;
data.client = attacker;
data.timer = timer;
g_aNotifyList.PushArray(data, sizeof(NotifyListData));
}
else
{
NotifyListData buf;
g_aNotifyList.GetArray(idx, buf, sizeof(NotifyListData));
if (buf.timer != INVALID_HANDLE)
KillTimer(buf.timer);
buf.timer = timer;
g_aNotifyList.SetArray(idx, buf, sizeof(NotifyListData));
}
DisplayNotifyList();
return Plugin_Continue;
}
void DisplayNotifyList()
{
static int channel = -1;
char text[255];
strcopy(text, sizeof(text), "Shooting Couch:\n");
for (int i = g_aNotifyList.Length - 1; i >= 0; i--)
{
NotifyListData buf;
g_aNotifyList.GetArray(i, buf, sizeof(NotifyListData));
if (!IsClientInGame(buf.client))
{
if (buf.timer != INVALID_HANDLE)
KillTimer(buf.timer);
g_aNotifyList.Erase(i);
continue;
}
char clientName[32];
GetClientName(buf.client, clientName, sizeof(clientName));
StrCat(text, sizeof(text), clientName);
StrCat(text, sizeof(text), "\n");
}
SetHudTextParams(0.8, -1.0, g_cvNotifyTimer.FloatValue, 255, 255, 255, 255, 0, 0.0, 0.0, 0.0);
for (int i = 1; i <= MaxClients; i++)
{
if (IsClientInGame(i))
channel = ShowHudText(i, channel, text);
}
}
void OnNotifyTimer(Handle timer, any data)
{
int client = view_as<int>(data);
int idx = FindInNotifyList(client);
if (idx != -1)
g_aNotifyList.Erase(idx);
if (g_aNotifyList.Length)
DisplayNotifyList();
}
int FindInNotifyList(int client)
{
for (int i = 0; i < g_aNotifyList.Length; i++)
{
NotifyListData buf;
g_aNotifyList.GetArray(i, buf, sizeof(NotifyListData));
if (buf.client == client)
return i;
}
return -1;
}
@@ -0,0 +1,129 @@
#pragma semicolon 1
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <clientprefs>
#include <multicolors>
#pragma newdecls required
static const char entityList[][] = { "env_entity_igniter", "env_explosion", "env_fade", "env_fire", "env_hudhint", \
"env_physexplosion", "env_sprite", "env_sun", \
"func_breakable", "func_brush", "func_bomb_target", "func_button", "func_door", \
"func_dustmotes", "func_physbox_multiplayer", "info_overlay", "info_particle_system", \
"info_player_counterterrorist", "info_player_terrorist", "infodecal", \
"item_assaultsuit", "item_defuser", "item_kevlar", \
"light", "light_environment", "light_spot", "move_rope", "path_track", "planted_c4", \
"point_viewcontrol", "shadow_control", "vgui_screen", "func_tracktrain", "worldspawn", \
"func_tanktrain"};
bool bEnabled[MAXPLAYERS + 1];
int iDistance[MAXPLAYERS + 1];
float g_fClientOrigin[MAXPLAYERS + 1][3];
public void OnPluginStart()
{
// Run the cache timer every 0.5 seconds globally
CreateTimer(0.5, Timer_CacheOrigins, _, TIMER_REPEAT);
}
public Action Timer_CacheOrigins(Handle timer)
{
for (int i = 1; i <= MaxClients; i++)
{
if (IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i))
{
GetClientAbsOrigin(i, g_fClientOrigin[i]);
}
}
return Plugin_Continue;
}
public Plugin myinfo =
{
name = "Render Distance Control",
author = "null138 & (ty ZombieFeyk), modified for webclient on unloze",
description = "Sets entities render distance and etc for players",
version = "3.0.5",
url = "https://steamcommunity.com/id/null138/"
}
public void OnClientAuthorized(int client, const char[] auth)
{
bEnabled[client] = false;
iDistance[client] = 800;
char sIP[32];
GetClientIP(client, sIP, sizeof(sIP));
char allowed_ips[128];
ConVar sv_set_steam_id_ips = FindConVar("sv_set_steam_id_ips");
sv_set_steam_id_ips.GetString(allowed_ips, sizeof(allowed_ips));
if (StrEqual(sIP, allowed_ips))
{
bEnabled[client] = true;
iDistance[client] = 1200;
}
}
public void OnEntityCreated(int entity, const char[] classname)
{
bool hook = false;
if (!strncmp(classname, "prop_", 5))
{
hook = true;
}
else
{
for(int i; i < sizeof(entityList); i++)
{
if(!strcmp(classname, entityList[i]))
{
hook = true;
break;
}
}
}
if (hook)
{
SDKHook(entity, SDKHook_SetTransmit, DoTransmit);
}
}
public Action DoTransmit(int entity, int client)
{
if (IsFakeClient(client) || !bEnabled[client])
return Plugin_Continue;
if (GetEdictFlags(entity) & FL_EDICT_ALWAYS)
SetEdictFlags(entity, GetEdictFlags(entity) ^ FL_EDICT_ALWAYS);
// Get Entity Origin
static float entVec[3];
if (HasEntProp(entity, Prop_Send, "m_vecOrigin"))
{
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", entVec);
}
else
{
return Plugin_Continue; // If it doesnt have an origin, let it render safely
}
// Use GetVectorDistance with UseSquared=true (avoids an expensive Square Root calculation)
float maxDist = float(iDistance[client]);
float distanceSq = ((g_fClientOrigin[client][0] - entVec[0]) * (g_fClientOrigin[client][0] - entVec[0])) +
((g_fClientOrigin[client][1] - entVec[1]) * (g_fClientOrigin[client][1] - entVec[1])) +
((g_fClientOrigin[client][2] - entVec[2]) * (g_fClientOrigin[client][2] - entVec[2]));
if (distanceSq > (maxDist * maxDist))
{
return Plugin_Handled; // Out of range, hide it from the software renderer!
}
return Plugin_Continue;
}
File diff suppressed because it is too large Load Diff
+6
View File
@@ -0,0 +1,6 @@
#if defined _selfmute_included_
#endinput
#endif
#define _selfmute_included_
native bool SelfMute_IsIgnoring(int client, int target);
+6 -17
View File
@@ -38,7 +38,7 @@ ConVar g_cvarUseProximityCheck = null;
ConVar g_cvarSendSpraysToConnectingClients = null; ConVar g_cvarSendSpraysToConnectingClients = null;
ConVar g_cvarUsePersistentSprays = null; ConVar g_cvarUsePersistentSprays = null;
ConVar g_cvarMaxSprayLifetime = null; ConVar g_cvarMaxSprayLifetime = null;
ConVar g_cvarHourRequirement = null; ConVar g_cvarSprayTierRequired = null;
int g_iNSFWDecalIndex; int g_iNSFWDecalIndex;
int g_iHiddenDecalIndex; int g_iHiddenDecalIndex;
@@ -53,7 +53,6 @@ bool g_bGotBlacklist;
bool g_bGotNSFWList; bool g_bGotNSFWList;
bool g_bFullyConnected; bool g_bFullyConnected;
bool g_bSkipDecalHook; bool g_bSkipDecalHook;
bool g_bFullFillHourRequirement[MAXPLAYERS + 1] = {false,...};
char g_sBanIssuer[MAXPLAYERS + 1][64]; char g_sBanIssuer[MAXPLAYERS + 1][64];
char g_sBanIssuerSID[MAXPLAYERS + 1][32]; char g_sBanIssuerSID[MAXPLAYERS + 1][32];
@@ -61,8 +60,6 @@ char g_sBanReason[MAXPLAYERS + 1][32];
char g_sSprayHash[MAXPLAYERS + 1][16]; char g_sSprayHash[MAXPLAYERS + 1][16];
char g_csSID[MAXPLAYERS + 1][65]; char g_csSID[MAXPLAYERS + 1][65];
int g_iClientHoursNotFullFilled[MAXPLAYERS + 1];
int g_iClientMinutesNotFullFilled[MAXPLAYERS + 1];
int g_iClientToClientSprayLifetime[MAXPLAYERS + 1][MAXPLAYERS + 1]; int g_iClientToClientSprayLifetime[MAXPLAYERS + 1][MAXPLAYERS + 1];
int g_iClientSprayLifetime[MAXPLAYERS + 1] = { 2, ... }; int g_iClientSprayLifetime[MAXPLAYERS + 1] = { 2, ... };
int g_iSprayLifetime[MAXPLAYERS + 1]; int g_iSprayLifetime[MAXPLAYERS + 1];
@@ -163,7 +160,7 @@ public void OnPluginStart()
g_cvarMaxSprayLifetime = CreateConVar("sm_spraymanager_maxspraylifetime", "2", "If not using persistent sprays, remove sprays after their global lifetime (in rounds) exceeds this number"); g_cvarMaxSprayLifetime = CreateConVar("sm_spraymanager_maxspraylifetime", "2", "If not using persistent sprays, remove sprays after their global lifetime (in rounds) exceeds this number");
g_cvarHourRequirement = CreateConVar("sm_spraymanager_hour_requirement", "5", "Using the unloze play time plugin to set a minimum amount of hours for allowing players access to spraying."); g_cvarSprayTierRequired = CreateConVar("sm_spraymanager_tier_required", "1", "Using the unloze play time plugin to set a minimum tier for allowing players access to spraying.");
AutoExecConfig(true, "plugin.SprayManager"); AutoExecConfig(true, "plugin.SprayManager");
@@ -339,13 +336,6 @@ public void OnClientPostAdminCheck(int client)
UpdateHideSprays(); UpdateHideSprays();
} }
public void GetPlayerHoursServer(int client, int hours, int minutes)
{
g_iClientHoursNotFullFilled[client] = hours;
g_iClientMinutesNotFullFilled[client] = minutes;
g_bFullFillHourRequirement[client] = g_iClientHoursNotFullFilled[client] > g_cvarHourRequirement.IntValue ? true : false;
}
public void update_client_online(int client, int is_online) public void update_client_online(int client, int is_online)
{ {
if (!g_hDatabase) if (!g_hDatabase)
@@ -2277,9 +2267,11 @@ public Action HookDecal(const char[] sTEName, const int[] iClients, int iNumClie
} }
//check for an arbitrary amount of hours before allowing spraying //check for an arbitrary amount of hours before allowing spraying
if (!g_bFullFillHourRequirement[client]) int clientTier = GetPlayerTier_native(client);
int TierRequired = g_cvarSprayTierRequired.IntValue;
if (TierRequired > clientTier)
{ {
PrintToChat(client, "\x01\x04[SprayManager]\x01 You cannot spray because you dont have enough play time yet. (You have \x04%i Hours and \x04%i minutes. You need \x04%i\x01 hours)", g_iClientHoursNotFullFilled[client], g_iClientMinutesNotFullFilled[client], g_cvarHourRequirement.IntValue); PrintToChat(client, "\x01\x04[SprayManager]\x01 You cannot spray because you dont have reached tier %i yet. (You have tier \x04%i)", TierRequired, clientTier);
return Plugin_Handled; return Plugin_Handled;
} }
@@ -3329,9 +3321,6 @@ stock void ClearPlayerInfo(int client)
g_SprayAABB[client] = view_as<float>({ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }); //??? g_SprayAABB[client] = view_as<float>({ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }); //???
g_bHasNSFWSpray[client] = false; g_bHasNSFWSpray[client] = false;
g_bMarkedNSFWByAdmin[client] = false; g_bMarkedNSFWByAdmin[client] = false;
g_bFullFillHourRequirement[client] = false;
g_iClientHoursNotFullFilled[client] = 0;
g_iClientMinutesNotFullFilled[client] = 0;
} }
stock void UpdateClientToClientSprayLifeTime(int client, int iLifeTime) stock void UpdateClientToClientSprayLifeTime(int client, int iLifeTime)
@@ -2,13 +2,13 @@
#include <sdktools> #include <sdktools>
#include <multicolors> #include <multicolors>
#include <zombiereloaded> #include <zombiereloaded>
#include <loghelper>
#pragma semicolon 1 #pragma semicolon 1
#pragma newdecls required #pragma newdecls required
/* CONVARS */ /* CONVARS */
ConVar g_hCVar_Delay; ConVar g_hCVar_Delay;
ConVar g_hCVar_KnifemadnessEnabled;
/* BOOLS */ /* BOOLS */
bool g_bClientKnifed[MAXPLAYERS+1]; bool g_bClientKnifed[MAXPLAYERS+1];
@@ -32,6 +32,9 @@ public Plugin myinfo =
public void OnPluginStart() public void OnPluginStart()
{ {
g_hCVar_Delay = CreateConVar("sm_knife_madness_kill_delay", "3", "Delay before ZMs die after being knifed by a human.", 0, true, 0.0); g_hCVar_Delay = CreateConVar("sm_knife_madness_kill_delay", "3", "Delay before ZMs die after being knifed by a human.", 0, true, 0.0);
g_hCVar_KnifemadnessEnabled = CreateConVar("sm_knifemadness_enabled", "0", "", FCVAR_NONE, true, 0.0, true, 1.0);
g_hCVar_KnifemadnessEnabled.AddChangeHook(OnConVarChanged);
AutoExecConfig(true);
HookEvent("player_spawn", OnClientSpawn, EventHookMode_Post); HookEvent("player_spawn", OnClientSpawn, EventHookMode_Post);
HookEvent("player_death", OnClientDeath, EventHookMode_Pre); HookEvent("player_death", OnClientDeath, EventHookMode_Pre);
@@ -39,11 +42,23 @@ public void OnPluginStart()
HookEvent("player_team", OnClientTeam, EventHookMode_Pre); HookEvent("player_team", OnClientTeam, EventHookMode_Pre);
} }
public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
{
if(g_hCVar_KnifemadnessEnabled.BoolValue)
CPrintToChatAll("{cyan}[Knifemadness] {white}has been allowed.");
else
CPrintToChatAll("{cyan}[Knifemadness] {white}has been disabled.");
}
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// Purpose: // Purpose:
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void OnClientSpawn(Event hEvent, const char[] sEvent, bool bDontBroadcast) public void OnClientSpawn(Event hEvent, const char[] sEvent, bool bDontBroadcast)
{ {
if(!g_hCVar_KnifemadnessEnabled.BoolValue)
{
return;
}
int client = GetClientOfUserId(hEvent.GetInt("userid")); int client = GetClientOfUserId(hEvent.GetInt("userid"));
g_bClientKnifed[client] = false; g_bClientKnifed[client] = false;
@@ -58,6 +73,10 @@ public void OnClientSpawn(Event hEvent, const char[] sEvent, bool bDontBroadcast
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public Action OnClientDeath(Event hEvent, const char[] sEvent, bool bDontBroadcast) public Action OnClientDeath(Event hEvent, const char[] sEvent, bool bDontBroadcast)
{ {
if(!g_hCVar_KnifemadnessEnabled.BoolValue)
{
return Plugin_Continue;
}
int client = GetClientOfUserId(hEvent.GetInt("userid")); int client = GetClientOfUserId(hEvent.GetInt("userid"));
if (g_bSupressDeath[client]) if (g_bSupressDeath[client])
@@ -74,6 +93,10 @@ public Action OnClientDeath(Event hEvent, const char[] sEvent, bool bDontBroadca
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void OnClientHurt(Event hEvent, const char[] sEvent, bool bDontBroadcast) public void OnClientHurt(Event hEvent, const char[] sEvent, bool bDontBroadcast)
{ {
if(!g_hCVar_KnifemadnessEnabled.BoolValue)
{
return;
}
int attacker = GetClientOfUserId(hEvent.GetInt("attacker")); int attacker = GetClientOfUserId(hEvent.GetInt("attacker"));
int victim = GetClientOfUserId(hEvent.GetInt("userid")); int victim = GetClientOfUserId(hEvent.GetInt("userid"));
@@ -107,12 +130,16 @@ public void OnClientHurt(Event hEvent, const char[] sEvent, bool bDontBroadcast)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void OnClientTeam(Event hEvent, const char[] sEvent, bool bDontBroadcast) public void OnClientTeam(Event hEvent, const char[] sEvent, bool bDontBroadcast)
{ {
if(!g_hCVar_KnifemadnessEnabled.BoolValue)
{
return;
}
int client = GetClientOfUserId(hEvent.GetInt("userid")); int client = GetClientOfUserId(hEvent.GetInt("userid"));
if (g_bClientKnifed[client]) if (g_bClientKnifed[client])
{ {
g_bClientKnifed[client] = false; g_bClientKnifed[client] = false;
LogPlayerEvent(client, "triggered", "switch_to_spec"); //LogPlayerEvent(client, "triggered", "switch_to_spec");
} }
} }
@@ -121,6 +148,10 @@ public void OnClientTeam(Event hEvent, const char[] sEvent, bool bDontBroadcast)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void ZR_OnClientInfected(int client, int attacker, bool motherInfect, bool respawnOverride, bool respawn) public void ZR_OnClientInfected(int client, int attacker, bool motherInfect, bool respawnOverride, bool respawn)
{ {
if(!g_hCVar_KnifemadnessEnabled.BoolValue)
{
return;
}
if (!IsValidClient(attacker)) if (!IsValidClient(attacker))
return; return;
@@ -137,6 +168,10 @@ public void ZR_OnClientInfected(int client, int attacker, bool motherInfect, boo
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public Action KillZM(Handle timer, DataPack pack) public Action KillZM(Handle timer, DataPack pack)
{ {
if(!g_hCVar_KnifemadnessEnabled.BoolValue)
{
return Plugin_Continue;
}
int attacker = 0; int attacker = 0;
int client = 0; int client = 0;
@@ -145,21 +180,21 @@ public Action KillZM(Handle timer, DataPack pack)
client = GetClientOfUserId(pack.ReadCell()); client = GetClientOfUserId(pack.ReadCell());
if (client == 0) if (client == 0)
return; return Plugin_Continue;
if (!(IsValidClient(client, false) && IsPlayerAlive(client) && ZR_IsClientZombie(client) && g_bClientKnifed[client])) if (!(IsValidClient(client, false) && IsPlayerAlive(client) && ZR_IsClientZombie(client) && g_bClientKnifed[client]))
return; return Plugin_Continue;
g_bSupressDeath[client] = true; g_bSupressDeath[client] = true;
ForcePlayerSuicide(client); ForcePlayerSuicide(client);
g_bClientKnifed[client] = false; g_bClientKnifed[client] = false;
if (!(IsValidClient(attacker, false))) if (!(IsValidClient(attacker, false)))
return; return Plugin_Continue;
Event hEvent = CreateEvent("player_death"); Event hEvent = CreateEvent("player_death");
if (hEvent == null) if (hEvent == null)
return; return Plugin_Continue;
hEvent.SetInt("userid", GetClientUserId(client)); hEvent.SetInt("userid", GetClientUserId(client));
hEvent.SetInt("attacker", GetClientUserId(attacker)); hEvent.SetInt("attacker", GetClientUserId(attacker));
@@ -168,6 +203,7 @@ public Action KillZM(Handle timer, DataPack pack)
hEvent.SetInt("dominated", 0); hEvent.SetInt("dominated", 0);
hEvent.SetInt("revenge", 0); hEvent.SetInt("revenge", 0);
hEvent.Fire(); hEvent.Fire();
return Plugin_Handled;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -190,6 +226,10 @@ public void QueryClient(int client)
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void OnConVarQueryFinished(QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue, int iSerial) public void OnConVarQueryFinished(QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue, int iSerial)
{ {
if(!g_hCVar_KnifemadnessEnabled.BoolValue)
{
return;
}
if (GetClientFromSerial(iSerial) != client) if (GetClientFromSerial(iSerial) != client)
return; return;
@@ -251,4 +291,4 @@ stock int IsValidClient(int client, bool nobots = true)
return false; return false;
return IsClientInGame(client); return IsClientInGame(client);
} }
+77
View File
@@ -3,6 +3,7 @@
#include <sdkhooks> #include <sdkhooks>
#include <sourcemod> #include <sourcemod>
#include <zombiereloaded> #include <zombiereloaded>
#include <unloze_playtime>
#include <TransmitManager> #include <TransmitManager>
#include <leader> #include <leader>
#include <entWatch_core> #include <entWatch_core>
@@ -15,6 +16,7 @@ bool g_bHidePlayers[MAXPLAYERS + 1][MAXPLAYERS + 1];
/* INTEGERS */ /* INTEGERS */
int g_iHideRange[MAXPLAYERS+1]; int g_iHideRange[MAXPLAYERS+1];
int g_iLeader = 0; int g_iLeader = 0;
int g_iTierHide = 0;
/* HANDLES */ /* HANDLES */
Handle g_hTimer; Handle g_hTimer;
@@ -72,6 +74,7 @@ public void OnPluginStart()
} }
SetCookieMenuItem(MenuHandler_CookieMenu, 0, "Hide"); SetCookieMenuItem(MenuHandler_CookieMenu, 0, "Hide");
g_hTimer = CreateTimer(1.0, UpdateHide, INVALID_HANDLE, TIMER_REPEAT); g_hTimer = CreateTimer(1.0, UpdateHide, INVALID_HANDLE, TIMER_REPEAT);
g_iTierHide = FindTierForCommandOverride("sm_hide");
} }
public void OnPluginEnd() public void OnPluginEnd()
@@ -316,11 +319,85 @@ public int MenuHandler_MainMenu(Menu menu, MenuAction action, int client, int se
return 0; return 0;
} }
stock int FindTierForCommandOverride(const char[] command)
{
char sPath[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sPath, sizeof(sPath), "configs/admin_groups.cfg");
KeyValues kv = new KeyValues("Groups");
if (!kv.ImportFromFile(sPath))
{
delete kv;
return -1;
}
// collect tier group names first
char groupNames[32][64];
int groupCount = 0;
if (kv.GotoFirstSubKey())
{
do
{
char sName[64];
kv.GetSectionName(sName, sizeof(sName));
if (StrContains(sName, "tier", false) == 0)
{
strcopy(groupNames[groupCount], 64, sName);
groupCount++;
}
}
while (kv.GotoNextKey() && groupCount < 32);
}
int foundTier = -1;
for (int i = 0; i < groupCount; i++)
{
kv.Rewind();
if (!kv.JumpToKey(groupNames[i]))
continue;
if (!kv.JumpToKey("Overrides"))
continue;
if (!kv.GotoFirstSubKey(false))
continue;
do
{
char overrideCmd[64];
kv.GetSectionName(overrideCmd, sizeof(overrideCmd));
if (StrEqual(overrideCmd, command, false))
{
char tierStr[8];
strcopy(tierStr, sizeof(tierStr), groupNames[i][4]); // skip "tier"
foundTier = StringToInt(tierStr);
break;
}
}
while (kv.GotoNextKey(false));
if (foundTier != -1)
break;
}
delete kv;
return foundTier;
}
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// Purpose: // Purpose:
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
public void MenuHandler_CookieMenu(int client, CookieMenuAction action, any info, char[] buffer, int maxlen) public void MenuHandler_CookieMenu(int client, CookieMenuAction action, any info, char[] buffer, int maxlen)
{ {
int client_tier = GetPlayerTier_native(client);
if (g_iTierHide > client_tier)
{
return;
}
switch(action) switch(action)
{ {
case(CookieMenuAction_DisplayOption): case(CookieMenuAction_DisplayOption):
@@ -2718,7 +2718,7 @@ public Action Event_PlayerSay(Handle event, const char[] name, bool dontBroadcas
{ {
if (IsClientInGame(client) && GetClientTeam(client) == team) if (IsClientInGame(client) && GetClientTeam(client) == team)
{ {
if(!g_Ignored[client * (MAXPLAYERS + 1) + g_msgAuthor] /*&& MessageForward(client, g_msgAuthor, g_msgText)*/ ) if(!g_Ignored[client * (MAXPLAYERS + 1) + g_msgAuthor] && MessageForward(client, g_msgAuthor, g_msgText) )
players[playersNum++] = client; players[playersNum++] = client;
} }
} }
@@ -2729,7 +2729,7 @@ public Action Event_PlayerSay(Handle event, const char[] name, bool dontBroadcas
{ {
if (IsClientInGame(client)) if (IsClientInGame(client))
{ {
if(!g_Ignored[client * (MAXPLAYERS + 1) + g_msgAuthor] /* && MessageForward(client, g_msgAuthor, g_msgText)*/ ) if(!g_Ignored[client * (MAXPLAYERS + 1) + g_msgAuthor] && MessageForward(client, g_msgAuthor, g_msgText) )
players[playersNum++] = client; players[playersNum++] = client;
} }
} }
@@ -18,6 +18,7 @@
//2026: add playtime requirements for being unrestricted //2026: add playtime requirements for being unrestricted
#include <unloze_playtime> #include <unloze_playtime>
Database g_hDatabase;
/* FORWARDS */ /* FORWARDS */
Handle g_hFwd_OnClientRestricted; Handle g_hFwd_OnClientRestricted;
@@ -35,7 +36,8 @@ Handle g_hCookie_RestrictLength_minutes;
/* BOOLEANS */ /* BOOLEANS */
bool g_bRestrictedTemp[MAXPLAYERS+1]; bool g_bRestrictedTemp[MAXPLAYERS+1];
bool g_bDontSpamMsg[MAXPLAYERS+1] bool g_bDontSpamMsg[MAXPLAYERS+1];
bool g_bActiveEban[MAXPLAYERS+1];
/* INTERGERS */ /* INTERGERS */
int g_iRestrictIssued[MAXPLAYERS+1]; int g_iRestrictIssued[MAXPLAYERS+1];
@@ -54,7 +56,7 @@ int g_iClientMinutes[MAXPLAYERS + 1];
StringMap g_hTrie_Storage; StringMap g_hTrie_Storage;
/* CONVARS */ /* CONVARS */
ConVar g_cvarHourRequirement = null; ConVar g_cvarItemTierRequirement = null;
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// Purpose: // Purpose:
@@ -118,7 +120,46 @@ public void OnPluginStart()
OnClientCookiesCached(client); OnClientCookiesCached(client);
} }
g_cvarHourRequirement = CreateConVar("sm_entwatch_hour_requirement", "10", "Using the unloze play time plugin to set a minimum amount of hours for allowing players access to items."); if (!g_hDatabase)
{
Database.Connect(SQL_OnDatabaseConnect, "unloze_entwatch_web");
}
CreateTimer(5.0, CheckIfEntwatchBanExpired, _, TIMER_REPEAT);
g_cvarItemTierRequirement = CreateConVar("sm_entwatch_tier_requirement", "1", "Using the unloze play time plugin to set a tier for allowing players access to items.");
}
//could probably fail at detecting when a client finally gets entwatch unbanned but risk is pretty small as they need the ingame playtime to accomplish it.
public Action CheckIfEntwatchBanExpired(Handle timer)
{
for (int client = 1; client <= MaxClients; client++)
{
if (Client_IsValid(client) && IsClientInGame(client))
{
//we only need to check for bans with durations. temporary and permanent bans dont need to be updated as expired obviusly
if (g_iRestrictIssued[client] && g_iRestrictExpire[client] >= g_iClientHours[client] && g_iClientHours[client] > 0) //assuring playtime is set for client
{
//example: client restricted until 1335 hours and currently has 1320
if (g_iRestrictExpire[client] > g_iClientHours[client])
{
g_bActiveEban[client] = true;
continue;
}
//example client restricted until 1335 hours and 45 minutes. currently has 1335 hours and 20 minutes.
if (g_iRestrictExpire_minutes[client] > g_iClientMinutes[client])
{
g_bActiveEban[client] = true;
continue;
}
if (g_bActiveEban[client])
{
g_bActiveEban[client] = false;
update_entwatchban_mysql_is_expired(client);
}
}
}
}
return Plugin_Continue;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -127,6 +168,20 @@ public void OnPluginStart()
public void OnMapStart() public void OnMapStart()
{ {
g_hTrie_Storage.Clear(); g_hTrie_Storage.Clear();
if (!g_hDatabase)
{
Database.Connect(SQL_OnDatabaseConnect, "unloze_entwatch_web");
}
}
public void SQL_OnDatabaseConnect(Database db, const char[] error, any data)
{
if(!db || strlen(error))
{
LogError("Database error: %s", error);
return;
}
g_hDatabase = db;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@@ -138,6 +193,7 @@ public void OnClientPutInServer(int client)
GetClientIP(client, sAddress, sizeof(sAddress)); GetClientIP(client, sAddress, sizeof(sAddress));
g_bDontSpamMsg[client] = false; g_bDontSpamMsg[client] = false;
g_bActiveEban[client] = false;
bool bRestrictedTemp; bool bRestrictedTemp;
if (g_hTrie_Storage.GetValue(sAddress, bRestrictedTemp)) if (g_hTrie_Storage.GetValue(sAddress, bRestrictedTemp))
{ {
@@ -175,6 +231,7 @@ public void OnClientDisconnect(int client)
g_bDontSpamMsg[client] = false; g_bDontSpamMsg[client] = false;
g_bRestrictedTemp[client] = false; g_bRestrictedTemp[client] = false;
g_bActiveEban[client] = false;
g_iRestrictIssued[client] = 0; g_iRestrictIssued[client] = 0;
g_iRestrictIssued_minutes[client] = 0; g_iRestrictIssued_minutes[client] = 0;
@@ -232,6 +289,7 @@ public Action Command_ClientRestrict(int client, int args)
CPrintToChatAll("\x07%s[entWatch] \x07%s%N\x07%s restricted \x07%s%N\x07%s permanently.", "E01B5D", "EDEDED", client, "F16767", "EDEDED", target, "F16767"); CPrintToChatAll("\x07%s[entWatch] \x07%s%N\x07%s restricted \x07%s%N\x07%s permanently.", "E01B5D", "EDEDED", client, "F16767", "EDEDED", target, "F16767");
LogAction(client, target, "%L restricted %L permanently.", client, target); LogAction(client, target, "%L restricted %L permanently.", client, target);
} }
insert_entwatchban_mysql(client, target);
} }
} }
else else
@@ -289,7 +347,8 @@ public Action Command_DisplayRestrictions(int client, int args)
{ {
if (ClientRestricted(i)) if (ClientRestricted(i))
{ {
if (g_iClientHours[i] < g_cvarHourRequirement.IntValue) int client_tier = GetPlayerTier_native(i);
if (client_tier < g_cvarItemTierRequirement.IntValue)
{ {
GetClientName(i, aBuf2_time_requirement, sizeof(aBuf2_time_requirement)); GetClientName(i, aBuf2_time_requirement, sizeof(aBuf2_time_requirement));
StrCat(aBuf_time_requirement, sizeof(aBuf_time_requirement), aBuf2_time_requirement); StrCat(aBuf_time_requirement, sizeof(aBuf_time_requirement), aBuf2_time_requirement);
@@ -316,10 +375,10 @@ public Action Command_DisplayRestrictions(int client, int args)
if (strlen(aBuf_time_requirement)) if (strlen(aBuf_time_requirement))
{ {
aBuf_time_requirement[strlen(aBuf_time_requirement) - 2] = 0; aBuf_time_requirement[strlen(aBuf_time_requirement) - 2] = 0;
CReplyToCommand(client, "\x07%s[entWatch] \x07%sCurrent clients with not enough playtime: \x07%s%s", "E01B5D", "F16767", "EDEDED", aBuf_time_requirement); CReplyToCommand(client, "\x07%s[entWatch] \x07%sCurrent clients with not high enough Tier: \x07%s%s", "E01B5D", "F16767", "EDEDED", aBuf_time_requirement);
} }
else else
CReplyToCommand(client, "\x07%s[entWatch] \x07%sCurrent clients with not enough playtime: \x07%snone", "E01B5D", "F16767", "EDEDED"); CReplyToCommand(client, "\x07%s[entWatch] \x07%sCurrent clients with not high enough Tier: \x07%snone", "E01B5D", "F16767", "EDEDED");
return Plugin_Handled; return Plugin_Handled;
} }
@@ -473,6 +532,7 @@ stock bool ClientRestrict(int client, int target, int length)
g_iRestrictIssued[target] = g_iClientHours[target]; g_iRestrictIssued[target] = g_iClientHours[target];
g_iRestrictExpire[target] = 0; g_iRestrictExpire[target] = 0;
g_iRestrictLength[target] = 0; g_iRestrictLength[target] = 0;
g_iRestrictLength_minutes[target] = 0;
SetClientCookieInt(target, g_hCookie_RestrictIssued, GetTime()); SetClientCookieInt(target, g_hCookie_RestrictIssued, GetTime());
SetClientCookieInt(target, g_hCookie_RestrictExpire, 0); SetClientCookieInt(target, g_hCookie_RestrictExpire, 0);
@@ -558,6 +618,8 @@ stock bool ClientUnrestrict(int client, int target)
SetClientCookieInt(target, g_hCookie_RestrictLength, 0); SetClientCookieInt(target, g_hCookie_RestrictLength, 0);
SetClientCookieInt(target, g_hCookie_RestrictLength_minutes, 0); SetClientCookieInt(target, g_hCookie_RestrictLength_minutes, 0);
update_entwatchban_mysql_is_expired(target);
Call_StartForward(g_hFwd_OnClientUnrestricted); Call_StartForward(g_hFwd_OnClientUnrestricted);
Call_PushCell(client); Call_PushCell(client);
@@ -602,12 +664,13 @@ stock bool ClientRestricted(int client)
} }
} }
//hour requirement for picking up items //tier requirement for picking up items
if (g_iClientHours[client] < g_cvarHourRequirement.IntValue) int client_tier = GetPlayerTier_native(client);
if (client_tier < g_cvarItemTierRequirement.IntValue)
{ {
if (!g_bDontSpamMsg[client]) if (!g_bDontSpamMsg[client])
{ {
CPrintToChat(client, "\x07%s[entWatch] \x07%s You have \x07%s%i\x07%s hours and \x07%s%i\x07%s minutes playtime and need %i hours for picking up items.", "E01B5D", "EDEDED", "EDEDED", g_iClientHours[client], "EDEDED", "EDEDED", g_iClientMinutes[client], "EDEDED", g_cvarHourRequirement.IntValue); CPrintToChat(client, "\x07%s[entWatch] \x07%s You need to reach Tier \x07%s%i\x07%s for picking up items.", "E01B5D", "EDEDED", "EDEDED", g_cvarItemTierRequirement.IntValue, "EDEDED");
g_bDontSpamMsg[client] = true; g_bDontSpamMsg[client] = true;
CreateTimer(1.0, allow_message_again, GetClientSerial(client)); CreateTimer(1.0, allow_message_again, GetClientSerial(client));
} }
@@ -672,6 +735,53 @@ public void GetPlayerHoursServer(int client, int hours, int minutes)
g_iClientMinutes[client] = minutes; g_iClientMinutes[client] = minutes;
} }
public void update_entwatchban_mysql_is_expired(int entwatch_banned_player)
{
char sSIDClient[64];
GetClientAuthId(entwatch_banned_player, AuthId_Steam2, sSIDClient, sizeof(sSIDClient));
char sQuery[512];
Format(sQuery, sizeof(sQuery), "update `EntWatch_Current_Eban` set is_expired = 1 where client_steamid = '%s' and is_expired = 0", sSIDClient);
g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Normal);
}
public void insert_entwatchban_mysql(int admin, int entwatch_banned_player)
{
char sNameAdmin[MAX_NAME_LENGTH];
GetClientName(admin, sNameAdmin, sizeof(sNameAdmin));
int size2 = 2 * strlen(sNameAdmin) + 1;
char[] sEscapedNameAdmin = new char[size2 + 1];
g_hDatabase.Escape(sNameAdmin, sEscapedNameAdmin, size2 + 1);
char sSIDAdmin[64];
GetClientAuthId(admin, AuthId_Steam2, sSIDAdmin, sizeof(sSIDAdmin));
char sNameClient[MAX_NAME_LENGTH];
GetClientName(entwatch_banned_player, sNameClient, sizeof(sNameClient));
size2 = 2 * strlen(sNameClient) + 1;
char[] sEscapedNameClient = new char[size2 + 1];
g_hDatabase.Escape(sNameClient, sEscapedNameClient, size2 + 1);
char sSIDClient[64];
GetClientAuthId(entwatch_banned_player, AuthId_Steam2, sSIDClient, sizeof(sSIDClient));
int playtime_start_client = (g_iRestrictIssued[entwatch_banned_player] * 60) + g_iRestrictIssued_minutes[entwatch_banned_player];
int playtime_end_client = (g_iRestrictExpire[entwatch_banned_player] * 60) + g_iRestrictExpire_minutes[entwatch_banned_player];
int length = (g_iRestrictLength[entwatch_banned_player] * 60) + g_iRestrictLength_minutes[entwatch_banned_player];
char sQuery[512];
Format(sQuery, sizeof(sQuery), "INSERT INTO `EntWatch_Current_Eban` (`client_name`, `client_steamid`, `admin_name`, `admin_steamid`, `duration`, `reason`, `time_played_start`, `time_played_end`) VALUES ('%s', '%s', '%s', '%s', '%i', '%s', '%i', '%i')", sEscapedNameClient, sSIDClient, sEscapedNameAdmin, sSIDAdmin, length, "get fucked", playtime_start_client, playtime_end_client);
g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Normal);
}
public void SQL_FinishedQuery(Database db, DBResultSet results, const char[] error, any data)
{
if (!db || strlen(error))
{
LogError("Query error 3: %s", error);
}
delete results;
}
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// Purpose: // Purpose:
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
+203
View File
@@ -0,0 +1,203 @@
//====================================================================================================
//
// Name: [entWatch] UseAnywhere
// Author: marisakirisame.net
// Description: Allow the owner of an item to activate it with their USE key anywhere
//
//====================================================================================================
#include <multicolors>
#pragma newdecls required
#include <sourcemod>
#include <sdkhooks>
#include <sdktools>
#include <clientprefs>
#include <entWatch_core>
#include <entWatch_helpers>
/* BOOLS */
bool g_bDisabled[MAXPLAYERS+1];
/* COOKIES */
Handle g_hCookie_Disabled;
/* INTEGERS */
int g_iLastButtons[MAXPLAYERS+1];
int g_iActivateTick[MAXPLAYERS+1];
int g_iActivateButton[MAXPLAYERS+1];
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Plugin myinfo =
{
name = "[entWatch] UseAnywhere",
author = "marisakirisame.net",
description = "Allow the owner of an item to activate it with their USE key anywhere",
version = "4.0.0"
};
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnPluginStart()
{
g_hCookie_Disabled = RegClientCookie("EW_UseAnywhereDisabled", "", CookieAccess_Private);
RegConsoleCmd("sm_euseanywhere", Command_ToggleUseAnywhere);
for (int client = 1; client <= MaxClients; client++)
{
if (!IsClientInGame(client) || IsFakeClient(client))
continue;
OnClientPutInServer(client);
if (AreClientCookiesCached(client))
OnClientCookiesCached(client);
}
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientPutInServer(int client)
{
g_bDisabled[client] = false;
g_iLastButtons[client] = 0;
g_iActivateTick[client] = 0;
g_iActivateButton[client] = INVALID_ENT_REFERENCE;
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientCookiesCached(int client)
{
g_bDisabled[client] = GetClientCookieBool(client, g_hCookie_Disabled);
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action Command_ToggleUseAnywhere(int client, int args)
{
if (!Client_IsValid(client))
return Plugin_Handled;
g_bDisabled[client] = !g_bDisabled[client];
if (g_bDisabled[client])
{
SetClientCookieBool(client, g_hCookie_Disabled, true);
CReplyToCommand(client, "\x07%s[entWatch] \x07%sYou will now have to aim at the item's trigger to use it.", "E01B5D", "F16767");
return Plugin_Handled;
}
else
{
SetClientCookieBool(client, g_hCookie_Disabled, false);
CReplyToCommand(client, "\x07%s[entWatch] \x07%sYou can now use your item by pressing your USE key anywhere.", "E01B5D", "F16767");
return Plugin_Handled;
}
}
//----------------------------------------------------------------------------------------------------
// Purpose: Activate the clients item on +use, without having to aim at its button.
//----------------------------------------------------------------------------------------------------
public Action OnPlayerRunCmd(int client, int &buttons)
{
bool bPressed = view_as<bool>((buttons & IN_USE) && !(g_iLastButtons[client] & IN_USE));
g_iLastButtons[client] = buttons;
if (!bPressed || g_bDisabled[client] || !IsPlayerAlive(client))
return Plugin_Continue;
int button = FindClientItemButton(client);
if (button == INVALID_ENT_REFERENCE)
return Plugin_Continue;
// Fires the buttons Use input, which runs the core's SDKHook_Use handler as if the
// client had aimed at it, so every cooldown, restriction and message is handled there.
AcceptEntityInput(button, "Use", client, client);
// Set after the input, so the press above is not blocked by its own guard.
g_iActivateTick[client] = GetGameTickCount();
g_iActivateButton[client] = button;
return Plugin_Continue;
}
//----------------------------------------------------------------------------------------------------
// Purpose: Ignore the engines own +use if we already fired this button for the client this tick,
// so aiming at the button while pressing USE cannot activate the item twice.
//----------------------------------------------------------------------------------------------------
public Action EW_OnClientItemCanActivate(int client, int index)
{
if (g_iActivateTick[client] != GetGameTickCount())
return Plugin_Continue;
CItem item = EW_GetItemData(index);
if (item.bButton && item.iButton == g_iActivateButton[client])
return Plugin_Handled;
return Plugin_Continue;
}
//----------------------------------------------------------------------------------------------------
// Purpose: Get the button of the clients item, but only if they carry exactly one.
//----------------------------------------------------------------------------------------------------
stock int FindClientItemButton(int client)
{
int iFound = -1;
for (int index; index < EW_GetItemCount(); index++)
{
CItem item = EW_GetItemData(index);
if (!(item.bClient && item.iClient == client))
continue;
if (iFound != -1)
return INVALID_ENT_REFERENCE;
iFound = index;
}
if (iFound != -1)
{
CItem itemFound = EW_GetItemData(iFound);
if (itemFound.bButton && Entity_IsValid(itemFound.iButton))
return itemFound.iButton;
}
return INVALID_ENT_REFERENCE;
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
stock void SetClientCookieBool(int client, Handle hCookie, bool value)
{
char sValue[32];
IntToString(view_as<int>(value), sValue, sizeof(sValue));
SetClientCookie(client, hCookie, sValue);
}
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
stock bool GetClientCookieBool(int client, Handle hCookie)
{
char sValue[32];
GetClientCookie(client, hCookie, sValue, sizeof(sValue));
return view_as<bool>(StringToInt(sValue));
}
+38
View File
@@ -0,0 +1,38 @@
-- entwatchban_web.EntWatch_Current_Eban definition
CREATE TABLE `EntWatch_Current_Eban` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`client_name` varchar(32) NOT NULL,
`client_steamid` varchar(64) NOT NULL,
`admin_name` varchar(32) NOT NULL,
`admin_steamid` varchar(64) NOT NULL,
`duration` int(10) unsigned NOT NULL,
`time_stamp_start` datetime DEFAULT current_timestamp(),
`reason` varchar(64) DEFAULT NULL,
`reason_unban` varchar(64) DEFAULT NULL,
`admin_name_unban` varchar(32) DEFAULT NULL,
`admin_steamid_unban` varchar(64) DEFAULT NULL,
`timestamp_unban` int(11) DEFAULT NULL,
`time_played_start` int(11) NOT NULL DEFAULT -1,
`time_played_end` int(11) NOT NULL DEFAULT -1,
`is_expired` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `idx_steamid_search` (`client_steamid`,`admin_steamid`),
KEY `idx_expiry_sort` (`time_stamp_start`,`duration`),
KEY `idx_server_expiry` (`duration`,`time_stamp_start`),
KEY `idx_is_expired` (`is_expired`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- entwatchban_web.web_logs definition
CREATE TABLE `web_logs` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`message` varchar(255) NOT NULL,
`admin_name` varchar(32) NOT NULL,
`admin_steamid` varchar(64) NOT NULL,
`client_name` varchar(32) NOT NULL,
`client_steamid` varchar(64) NOT NULL,
`time_stamp` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
@@ -0,0 +1,33 @@
"Games"
{
"cstrike"
{
"Signatures"
{
"CBasePlayer::InputSetFogController"
{
"library" "server"
"windows" "\x55\x8B\xEC\x56\x8B\xF1\x8B\x4D\x08\x83\xC1\x08\x83\x79\x10\x02\x75\x2A\x8B\x01\xBA\x2A\x2A\x2A\x2A\x85\xC0\x0F\x45\xD0\xEB\x2A\xE8\x2A\x2A\x2A\x2A\x8B\xD0\x6A\x00"
"linux" "@_ZN11CBasePlayer21InputSetFogControllerER11inputdata_t"
}
}
"Functions"
{
"CBasePlayer::InputSetFogController"
{
"signature" "CBasePlayer::InputSetFogController"
"callconv" "thiscall"
"return" "void"
"this" "entity"
"arguments"
{
"inputdata"
{
"type" "objectptr"
}
}
}
}
}
}
@@ -0,0 +1,278 @@
#include <sourcemod>
#include <sdktools>
#include <dhooks>
public Plugin myinfo =
{
name = "Render Distance Limiter",
author = "Dysphie, repurposed for unloze webclient using some AI",
description = "",
version = "",
url = ""
};
int g_iClientFogEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
float g_OverrideDist[MAXPLAYERS + 1] = { -1.0, ... };
bool bEnabled[MAXPLAYERS + 1];
float g_fClientEstimatedFPS[MAXPLAYERS + 1];
// New tracking arrays for your global variables section
float g_fLastStableDist[MAXPLAYERS + 1] = { -1.0, ... };
float g_fDistCooldown[MAXPLAYERS + 1] = { 0.0, ... };
int g_iLastCmdNum[MAXPLAYERS + 1];
float g_fFPSIntervalStart[MAXPLAYERS + 1];
int g_iCmdsInInterval[MAXPLAYERS + 1];
public void OnPluginStart()
{
SetupDetours();
CreateTimer(0.5, Timer_printFPS, _, TIMER_REPEAT);
}
//ai generated
public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2])
{
if (IsFakeClient(client) || !bEnabled[client])
return Plugin_Continue;
// Check if this is a brand new user command execution frame
if (cmdnum != g_iLastCmdNum[client])
{
g_iLastCmdNum[client] = cmdnum;
g_iCmdsInInterval[client]++;
}
float fCurrentTime = GetEngineTime();
float fTimeElapsed = fCurrentTime - g_fFPSIntervalStart[client];
// Evaluate the true input frequency every 0.5 seconds
if (fTimeElapsed >= 0.5)
{
if (g_fFPSIntervalStart[client] > 0.0)
{
// Raw calculated input framerate based on sequential command progression
float fCalculatedFPS = float(g_iCmdsInInterval[client]) / fTimeElapsed;
// FAST-DROP BYPASS: If the client just lost more than 25% of their frame rate instantly
// skip the dampening math and force the estimation down immediately.
if (fCalculatedFPS < (g_fClientEstimatedFPS[client] * 0.75))
{
g_fClientEstimatedFPS[client] = fCalculatedFPS; // Hard-drop the value
}
else
{
// Smoothly recover/climb when frame rates are stable or increasing
g_fClientEstimatedFPS[client] = (g_fClientEstimatedFPS[client] * 0.8) + (fCalculatedFPS * 0.2);
}
}
// Reset interval buckets
g_fFPSIntervalStart[client] = fCurrentTime;
g_iCmdsInInterval[client] = 0;
}
return Plugin_Continue;
}
//ai generated
public Action Timer_printFPS(Handle timer)
{
for (int i = 1; i <= MaxClients; i++)
{
if (IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i) && bEnabled[i])
{
float fCurrentFPS = g_fClientEstimatedFPS[i] - 4.0;
float currentDist = g_OverrideDist[i];
float targetDist = currentDist;
// 1. HARD CRASH: FPS has tanked down to unplayable levels.
if (fCurrentFPS <= 25.0)
{
// If we have a cached, proven stable distance, use it immediately!
if (g_fLastStableDist[i] != -1.0 && g_fLastStableDist[i] < currentDist)
{
targetDist = g_fLastStableDist[i];
}
else
{
// Emergency fallback steps if we dont have a cached history yet
if (currentDist == -1.0 || currentDist > 1200.0)
{
targetDist = 1200.0;
}
else
{
targetDist = 600.0;
}
}
// Penalize the cooldown heavily because we just choked on rendering
g_fDistCooldown[i] = GetEngineTime() + 15.0;
}
// 2. WARNING ZONE: Framerate is beginning to dip
else if (fCurrentFPS <= 38.0)
{
if (currentDist == -1.0 || currentDist > 2000.0)
{
targetDist = 2000.0;
g_fDistCooldown[i] = GetEngineTime() + 10.0;
}
}
// 3. RECOVERY ZONE: Performance is solid. Lets see if we can open up the view.
else if (fCurrentFPS >= 48.0)
{
if (currentDist != -1.0)
{
// Since the game is running flawlessly at this specific distance,
// we update our safety cache to remember this specific float.
g_fLastStableDist[i] = currentDist;
// Only venture out if our time barrier has expired
if (GetEngineTime() >= g_fDistCooldown[i])
{
if (currentDist == 600.0) targetDist = 1200.0;
else if (currentDist == 1200.0) targetDist = 2000.0;
else if (currentDist == 2000.0) targetDist = 4000.0;
else if (currentDist == 4000.0) targetDist = -1.0;
// Give the client a test window to sample the new distance
g_fDistCooldown[i] = GetEngineTime() + 8.0;
}
}
else
{
// If the client is running fine at infinite distance (-1.0),
// clear the history out so we can recalculate from a clean slate later
g_fLastStableDist[i] = -1.0;
}
}
if (targetDist != currentDist)
{
ApplyFogValues(i, targetDist);
}
}
}
return Plugin_Continue;
}
void ApplyFogValues(int client, float dist)
{
g_OverrideDist[client] = dist;
int fog = EntRefToEntIndex(g_iClientFogEntity[client]);
// Create the persistent entity once if it vanished or hasnt been created yet
if (fog == -1 || !IsValidEntity(fog))
{
fog = CreateEntityByName("env_fog_controller");
if (fog != -1)
{
DispatchSpawn(fog);
g_iClientFogEntity[client] = EntIndexToEntRef(fog);
}
}
if (fog != -1 && IsValidEntity(fog))
{
if (dist == -1.0)
{
// Back to map defaults safely
SetEntProp(fog, Prop_Send, "m_fog.enable", 0);
SetEntPropFloat(fog, Prop_Send, "m_fog.farz", 0.0);
}
else
{
// Apply strict culling boundaries explicitly
SetEntProp(fog, Prop_Send, "m_fog.enable", 1);
SetEntPropFloat(fog, Prop_Send, "m_fog.farz", dist);
SetEntPropFloat(fog, Prop_Send, "m_fog.end", dist);
SetEntPropFloat(fog, Prop_Send, "m_fog.maxdensity", 1.0);
}
// Keep the entity assigned cleanly inside data tables
SetFogController(client, fog);
// Single fire state changes to replicate out smoothly
ChangeEdictState(client, FindSendPropInfo("CBasePlayer", "m_hCtrl"));
}
}
public void OnClientDisconnect(int client)
{
// Clean up entity allocation to prevent lingering map errors
int fog = EntRefToEntIndex(g_iClientFogEntity[client]);
if (fog != -1 && IsValidEntity(fog))
{
RemoveEntity(fog);
}
g_iClientFogEntity[client] = INVALID_ENT_REFERENCE;
g_OverrideDist[client] = -1.0;
bEnabled[client] = false;
}
void SetupDetours()
{
GameData gamedata = new GameData("player-fog.games");
if (!gamedata) {
SetFailState("Missing gamedata file");
}
DynamicDetour detour = DynamicDetour.FromConf(gamedata, "CBasePlayer::InputSetFogController");
if (!detour)
SetFailState("Failed to find signature CBasePlayer::InputSetFogController");
detour.Enable(Hook_Pre, Detour_InputSetFogController);
delete detour;
}
MRESReturn Detour_InputSetFogController(int client, DHookParam params)
{
RequestFrame(Frame_FogControllerChanged, GetClientSerial(client));
return MRES_Ignored;
}
void FogControllerChanged(int client)
{
if (g_OverrideDist[client] != -1.0) {
ApplyFogValues(client, g_OverrideDist[client]);
}
}
void Frame_FogControllerChanged(int clientSerial)
{
int client = GetClientFromSerial(clientSerial);
if (client && IsClientInGame(client))
{
FogControllerChanged(client);
}
}
public void OnClientAuthorized(int client, const char[] auth)
{
bEnabled[client] = false;
g_OverrideDist[client] = -1.0;
g_iClientFogEntity[client] = INVALID_ENT_REFERENCE;
char sIP[32];
GetClientIP(client, sIP, sizeof(sIP));
char allowed_ips[128];
ConVar sv_set_steam_id_ips = FindConVar("sv_set_steam_id_ips");
if (sv_set_steam_id_ips != null)
{
sv_set_steam_id_ips.GetString(allowed_ips, sizeof(allowed_ips));
if (StrEqual(sIP, allowed_ips))
{
bEnabled[client] = true;
}
}
}
void SetFogController(int client, int fog)
{
SetEntPropEnt(client, Prop_Data, "m_hCtrl", fog);
}
@@ -78,6 +78,11 @@ forward void OnMapVoteStart();
*/ */
forward void OnMapVoteEnd(const char[] map); forward void OnMapVoteEnd(const char[] map);
/**
just send the steamID, vote choice and voteweight of the client as a forward
**/
forward void OnMapVoteClientResult(char[] steamID, char[] vote_choice, int voteweight);
/** /**
* Is a map on the current game's official list? * Is a map on the current game's official list?
* This should be treated as informative only. * This should be treated as informative only.
@@ -85,6 +90,7 @@ forward void OnMapVoteEnd(const char[] map);
* @param map Name of map to check * @param map Name of map to check
* @return true if it's on the list of official maps for this game * @return true if it's on the list of official maps for this game
*/ */
native bool IsMapOfficial(const char[] map); native bool IsMapOfficial(const char[] map);
/** /**
@@ -108,13 +114,22 @@ native CanNominateResult CanNominate();
native bool ExcludeMap(const char[] map, int cooldown = 0, int mode = 0); native bool ExcludeMap(const char[] map, int cooldown = 0, int mode = 0);
// Cooldown in seconds // Cooldown in seconds
native bool ExcludeMapTime(const char[] map, int cooldown = 0, int mode = 0); native bool ExcludeMapTime(const char[] map, int cooldown = 0, int mode = 0);
// cooldown based on mysql table rows listing
native bool ExcludeMapListingPriority(const char[] map, int index);
native int GetMapCooldown(const char[] map); native int GetMapCooldown(const char[] map);
native int GetMapCooldownTime(const char[] map); // in unix time native int GetMapCooldownTime(const char[] map); // in unix time
native int GetMapCooldownTime2(const char[] map); // in unix time
native int GetMapLowPopHelpCount(const char[] map);
native int GetMapLaserFag(const char[] map);
native int GetMapTrails(const char[] map);
native int GetMapTickRate(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);
native int GetMapMaxPlayers(const char[] map); native int GetMapMaxPlayers(const char[] map);
native int GetMapMinHoursAvg(const char[] map);
native int GetExcludedMapListingPriority(const char[] map);
// 0 = Okay // 0 = Okay
// >0 = Minutes till Okay // >0 = Minutes till Okay
@@ -0,0 +1,195 @@
#pragma semicolon 1
#define PLUGIN_AUTHOR "jenz"
#define PLUGIN_VERSION "1.0"
#include <sourcemod>
#include <cstrike>
#include <mapchooser_extended>
int g_iPlayerCount_time_track;
int g_iTopMapsToMarkWithCooldown;
int g_iUnmarkCooldowns;
int g_iCurrentPlayerCount;
int g_iMapStartTime;
Database g_hDatabase;
public Plugin myinfo =
{
name = "map_tracker_cooldown",
author = PLUGIN_AUTHOR,
description = "assigns cooldowns on maps and tracks their played time on the server",
version = PLUGIN_VERSION,
url = "www.unloze.com"
};
public void OnPluginStart()
{
if (!g_hDatabase)
{
Database.Connect(SQL_OnDatabaseConnect, "unloze_playtimestats");
}
ConVar cvar;
HookConVarChange((cvar = CreateConVar("mce_min_players_track_time", "20", "Playercount in full number required for tracking minutes spend on a map.")), Cvar_playersCount);
g_iPlayerCount_time_track = cvar.IntValue;
delete cvar;
ConVar cvar1;
HookConVarChange((cvar1 = CreateConVar("mce_top_ordered_maps_on_cooldown", "30", "These highest listed maps will receive the cooldown boolean")), Cvar_TopMarkedWithCooldown);
g_iTopMapsToMarkWithCooldown = cvar1.IntValue;
delete cvar1;
ConVar cvar2;
HookConVarChange((cvar2 = CreateConVar("mce_UnmarkCooldowns", "120", "How far down the list does a map need to be for getting unmarked again")), Cvar_UnmarkedCooldown);
g_iUnmarkCooldowns = cvar2.IntValue;
delete cvar2;
g_iCurrentPlayerCount = GetClientCount(false);
CreateTimer(30.0, CheckPlayerCount, _, TIMER_REPEAT);
}
public Action CheckPlayerCount(Handle timer)
{
g_iCurrentPlayerCount = GetClientCount(false);
return Plugin_Continue;
}
public void Cvar_playersCount(ConVar convar, const char[] oldValue, const char[] newValue)
{
g_iPlayerCount_time_track = convar.IntValue;
}
public void Cvar_TopMarkedWithCooldown(ConVar convar, const char[] oldValue, const char[] newValue)
{
g_iTopMapsToMarkWithCooldown = convar.IntValue;
}
public void Cvar_UnmarkedCooldown(ConVar convar, const char[] oldValue, const char[] newValue)
{
g_iUnmarkCooldowns = convar.IntValue;
}
public void SQL_OnDatabaseConnect(Database db, const char[] error, any data)
{
if(!db || strlen(error))
{
LogError("Database error: %s", error);
return;
}
g_hDatabase = db;
UpdateTopListedMapsWithCooldown();
}
public void OnMapStart()
{
int i_port = GetConVarInt(FindConVar("hostport"));
if (i_port != 27019 && i_port != 27015)
{
return;
}
g_iMapStartTime = GetTime();
if (!g_hDatabase)
{
Database.Connect(SQL_OnDatabaseConnect, "unloze_playtimestats");
}
else
{
UpdateTopListedMapsWithCooldown();
}
}
public void UpdateTopListedMapsWithCooldown()
{
//just set every map in top g_iTopMapsToMarkWithCooldown on cooldown
char sQuery[512];
Format(sQuery, sizeof(sQuery), "update unloze_playtimestats.map_minutes_played set on_cooldown = true where mapname in ( SELECT mapname FROM (select mmp.mapname from unloze_playtimestats.map_minutes_played mmp order by mmp.minutes desc limit %i) as top) and on_cooldown is false", g_iTopMapsToMarkWithCooldown);
g_hDatabase.Query(SQL_FinishedQuery1, sQuery, _, DBPrio_High);
}
public void SQL_FinishedQuery1(Database db, DBResultSet results, const char[] error, DataPack data)
{
delete results;
if (!db || strlen(error))
{
LogError("Query error: %s", error);
}
delete data;
UpdateUnmarkCooldown();
}
public void UpdateUnmarkCooldown()
{
//if map in listing fell below g_iUnmarkCooldowns then set the bool to false again.
char sQuery[512];
Format(sQuery, sizeof(sQuery), "update unloze_playtimestats.map_minutes_played set on_cooldown = false where mapname not in ( SELECT mapname FROM (select mmp.mapname from unloze_playtimestats.map_minutes_played mmp order by mmp.minutes desc limit %i) as top) and on_cooldown is true", g_iUnmarkCooldowns);
g_hDatabase.Query(SQL_FinishedQuery2, sQuery, _, DBPrio_High);
}
public void SQL_FinishedQuery2(Database db, DBResultSet results, const char[] error, DataPack data)
{
delete results;
if (!db || strlen(error))
{
LogError("Query error: %s", error);
}
delete data;
SelectMapsToCooldownForMapChooser();
}
public void SelectMapsToCooldownForMapChooser()
{
char sQuery[512];
Format(sQuery, sizeof(sQuery), "select mapname, map_list_index from (select mapname, ROW_NUMBER() OVER(ORDER BY minutes DESC) as map_list_index, mmp.on_cooldown from unloze_playtimestats.map_minutes_played mmp) as targets where on_cooldown");
g_hDatabase.Query(SQL_FinishedQuerySelectMaps, sQuery, _, DBPrio_High);
}
public void SQL_FinishedQuerySelectMaps(Database db, DBResultSet results, const char[] error, DataPack data)
{
if (!db || strlen(error))
{
LogError("Query error in SQL_FinishedQuerySelectMaps: %s", error);
delete results;
return;
}
while (results.RowCount && results.FetchRow())
{
char mapname[256];
results.FetchString(0, mapname, sizeof(mapname));
int map_list_index = results.FetchInt(1);
ExcludeMapListingPriority(mapname, g_iUnmarkCooldowns - map_list_index);
}
delete results;
}
public void OnMapEnd()
{
int i_port = GetConVarInt(FindConVar("hostport"));
if (i_port != 27019 && i_port != 27015)
{
return;
}
int elapsed = GetTime() - g_iMapStartTime;
int minutes = RoundToFloor(elapsed / 60.0);
char Mapname[128];
GetCurrentMap(Mapname, sizeof(Mapname));
//LogMessage("minutes: %i. map: %s", minutes, Mapname);
if (g_iCurrentPlayerCount > g_iPlayerCount_time_track)
{
char sQuery[512];
Format(sQuery, sizeof(sQuery), "INSERT INTO `map_minutes_played` (`mapname`, `minutes`, `updated_on`) VALUES ('%s', '%i', NOW()) ON DUPLICATE KEY UPDATE `minutes` = `minutes` + '%i', `updated_on` = NOW()", Mapname, minutes, minutes);
g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Low);
}
}
public void SQL_FinishedQuery(Database db, DBResultSet results, const char[] error, DataPack data)
{
delete results;
if (!db || strlen(error))
{
LogError("Query error: %s", error);
}
delete data;
}
File diff suppressed because it is too large Load Diff
@@ -71,6 +71,9 @@ Handle g_Cvar_VIPTimeframe = INVALID_HANDLE;
Handle g_Cvar_VIPTimeframeMinTime = INVALID_HANDLE; Handle g_Cvar_VIPTimeframeMinTime = INVALID_HANDLE;
Handle g_Cvar_VIPTimeframeMaxTime = INVALID_HANDLE; Handle g_Cvar_VIPTimeframeMaxTime = INVALID_HANDLE;
KeyValues g_Config;
int g_Player_NominationDelay[MAXPLAYERS+1]; int g_Player_NominationDelay[MAXPLAYERS+1];
int g_NominationDelay; int g_NominationDelay;
@@ -127,6 +130,26 @@ public void OnMapStart()
//we have too many dbs so i am just re-using racetimercss //we have too many dbs so i am just re-using racetimercss
Database.Connect(SQL_OnDatabaseConnect, "racetimercss"); Database.Connect(SQL_OnDatabaseConnect, "racetimercss");
} }
if(g_Config)
delete g_Config;
char sConfigFile[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), "configs/mapchooser_extended.cfg");
if(!FileExists(sConfigFile))
{
LogMessage("Could not find config: \"%s\"", sConfigFile);
return;
}
g_Config = new KeyValues("mapchooser_extended");
if(!g_Config.ImportFromFile(sConfigFile))
{
delete g_Config;
LogMessage("ImportFromFile() failed!");
return;
}
g_Config.Rewind();
} }
public void SQL_OnDatabaseConnect(Database db, const char[] error, any data) public void SQL_OnDatabaseConnect(Database db, const char[] error, any data)
@@ -327,47 +350,6 @@ public Action Command_Addmap(int client, int args)
AttemptAdminNominate(client, mapname); AttemptAdminNominate(client, mapname);
return Plugin_Handled; return Plugin_Handled;
} }
/*
int Cooldown1 = GetMapCooldownTime(mapname);
if(Cooldown1 > GetTime())
{
int Seconds = Cooldown1 - GetTime();
CPrintToChat(client, "[NE] %t", "Map Cooldown Time Error", Seconds / 3600, (Seconds % 3600) / 60);
return Plugin_Handled;
}
if(!CheckCommandAccess(client, "sm_nominate_ignore", ADMFLAG_KICK, true) )
{
bool RestrictionsActive = AreRestrictionsActive();
int TimeRestriction = GetMapTimeRestriction(mapname);
if(RestrictionsActive && TimeRestriction)
{
CPrintToChat(client, "[NE] %t", "Map Nominate Time Error", TimeRestriction / 60, TimeRestriction % 60);
return Plugin_Handled;
}
int AverageHourRestricted = GetAveragePlayerTimeOnServerMapRestriction(mapname);
if (RestrictionsActive && AverageHourRestricted > 0)
{
PrintToChat(client, "%s requires +%i hours average. Use sm_houravg to check average.", mapname, AverageHourRestricted);
return Plugin_Handled;
}
int PlayerRestriction = GetMapPlayerRestriction(mapname);
if(RestrictionsActive && PlayerRestriction)
{
if(PlayerRestriction < 0)
CPrintToChat(client, "[NE] %t", "Map Nominate MinPlayers Error", PlayerRestriction * -1);
else
CPrintToChat(client, "[NE] %t", "Map Nominate MaxPlayers Error", PlayerRestriction);
return Plugin_Handled;
}
}
*/
NominateResult result = NominateMap(mapname, true, 0); NominateResult result = NominateMap(mapname, true, 0);
@@ -570,12 +552,11 @@ public Action Command_Nominate(int client, int args)
return Plugin_Handled; return Plugin_Handled;
} }
int Cooldown1 = GetMapCooldownTime(mapname); //yeah admins and leaders cant bypass these restrictions, maybe the admins really are the problem sometimes for skipping restrictions.
if(Cooldown1 > GetTime()) int Index_Cooldown = GetExcludedMapListingPriority(mapname);
if (Index_Cooldown > 0)
{ {
int Seconds = Cooldown1 - GetTime(); CPrintToChat(client, "[NE] Map is on Cooldown for being overplayed. List Posistion: %i", Index_Cooldown);
CPrintToChat(client, "[NE] %t", "Map Cooldown Time Error", Seconds / 3600, (Seconds % 3600) / 60);
return Plugin_Handled; return Plugin_Handled;
} }
@@ -583,6 +564,17 @@ public Action Command_Nominate(int client, int args)
if(!CheckCommandAccess(client, "sm_nominate_ignore", ADMFLAG_KICK, true) && !Leader_Is(client)) if(!CheckCommandAccess(client, "sm_nominate_ignore", ADMFLAG_KICK, true) && !Leader_Is(client))
{ {
bool RestrictionsActive = AreRestrictionsActive(); bool RestrictionsActive = AreRestrictionsActive();
//restrictions not being active now also skips all the cooldowns.
int Cooldown1 = GetMapCooldownTime(mapname);
if(RestrictionsActive && Cooldown1 > GetTime())
{
int Seconds = Cooldown1 - GetTime();
CPrintToChat(client, "[NE] %t", "Map Cooldown Time Error", Seconds / 3600, (Seconds % 3600) / 60);
return Plugin_Handled;
}
bool VIPRestriction = GetMapVIPRestriction(mapname, client); bool VIPRestriction = GetMapVIPRestriction(mapname, client);
if(RestrictionsActive && VIPRestriction) if(RestrictionsActive && VIPRestriction)
{ {
@@ -731,26 +723,45 @@ public int Handler_NominateListMenu(Menu menu, MenuAction action, int param1, in
return 0; return 0;
} }
void SetNominateMenuTitle(Menu menu, int client)
{
int nominate_worth = GetPlayerWorthRTV_boost_(client);
if (Leader_Is(client))
SetMenuTitle(menu, "Nominate Map: (%i Nomination Boost Leader)", 999);
else
SetMenuTitle(menu, "Nominate Map: (%i Nomination Boost)", nominate_worth);
}
void AttemptNominate(int client, const char[] filter = "") void AttemptNominate(int client, const char[] filter = "")
{ {
if(!client) if(!client)
return; return;
Menu menu = g_MapMenu; Menu menu = g_MapMenu;
menu = BuildMapMenu(filter, client); if (filter[0])
int nominate_worth = GetPlayerWorthRTV_boost_(client);
if (Leader_Is(client))
{ {
SetMenuTitle(menu, "Nominate Map: (%i Nomination Boost Leader)", 999); // preserves the existing behavior for the "map wasnt found, try a substring search" fallback
menu = BuildMapMenu(filter, client);
} }
else else
{ {
SetMenuTitle(menu, "Nominate Map: (%i Nomination Boost)", nominate_worth); menu = BuildCategoryMenu(client);
} }
SetNominateMenuTitle(menu, client);
DisplayMenu(menu, client, MENU_TIME_FOREVER); DisplayMenu(menu, client, MENU_TIME_FOREVER);
} }
public void GetMapCategory(const char[] mapname, char[] output_category, int maxlen)
{
strcopy(output_category, maxlen, "Uncategorized");
if (g_Config && g_Config.JumpToKey(mapname))
{
g_Config.GetString("MapCategory", output_category, maxlen, "Uncategorized");
g_Config.Rewind();
}
}
void AttemptAdminNominate(int client, const char[] filter = "") void AttemptAdminNominate(int client, const char[] filter = "")
{ {
if(!client) if(!client)
@@ -817,6 +828,7 @@ bool PopulateNominateListMenu(Menu menu, int client, const char[] filter = "")
} }
StringMap sm = new StringMap(); StringMap sm = new StringMap();
StringMap sm_special_noms = new StringMap(); //storing leaders and admin noms.
static char map[PLATFORM_MAX_PATH]; static char map[PLATFORM_MAX_PATH];
static char display[PLATFORM_MAX_PATH]; static char display[PLATFORM_MAX_PATH];
for(int i = 0; i < GetArraySize(MapList); i++) for(int i = 0; i < GetArraySize(MapList); i++)
@@ -833,11 +845,12 @@ bool PopulateNominateListMenu(Menu menu, int client, const char[] filter = "")
if (!owner || Leader_Is(owner)) if (!owner || Leader_Is(owner))
{ {
nominate_count_for_particular_map = 1999; nominate_count_for_particular_map = 1999;
sm_special_noms.SetValue(map, owner); //admin noms and leaders are unique per each map, so cant be overwritten.
} }
else else
{ {
int nominate_worth = GetPlayerWorthRTV_boost_(owner); int nominate_worth = GetPlayerWorthRTV_boost_(owner);
//atm everybody just has equal voting again, so this is just += 1 //2026 march: the boosting can now range from 1 to 2. so for most its +=1 and for a few +=2.
nominate_count_for_particular_map += nominate_worth; nominate_count_for_particular_map += nominate_worth;
} }
sm.SetValue(map, nominate_count_for_particular_map, true); sm.SetValue(map, nominate_count_for_particular_map, true);
@@ -863,24 +876,26 @@ bool PopulateNominateListMenu(Menu menu, int client, const char[] filter = "")
{ {
int nominate_count_for_particular_map = 0; int nominate_count_for_particular_map = 0;
sm.GetValue(map, nominate_count_for_particular_map); sm.GetValue(map, nominate_count_for_particular_map);
int leader_or_admin_map_owner = -1;
sm_special_noms.GetValue(map, leader_or_admin_map_owner);
strcopy(display, sizeof(display), map); strcopy(display, sizeof(display), map);
bool VIPRestriction = GetMapVIPRestriction(map); bool VIPRestriction = GetMapVIPRestriction(map);
if((VIPRestriction) && AreRestrictionsActive()) if((VIPRestriction) && AreRestrictionsActive())
Format(display, sizeof(display), "%s (%T)", display, "VIP Nomination", client); Format(display, sizeof(display), "%s (%T)", display, "VIP Nomination", client);
int owner = GetArrayCell(OwnerList, i);
char spelling[8]; char spelling[8];
Format(spelling, sizeof(spelling), nominate_count_for_particular_map == 1 ? "Vote" : "Votes"); Format(spelling, sizeof(spelling), nominate_count_for_particular_map == 1 ? "Vote" : "Votes");
if (leader_or_admin_map_owner != -1)
if(!owner) {
Format(display, sizeof(display), "%s (Admin)", display); if(!leader_or_admin_map_owner)
else if (Leader_Is(owner)) Format(display, sizeof(display), "%s (Admin)", display);
Format(display, sizeof(display), "%s (Leader)", display); else
Format(display, sizeof(display), "%s (Leader)", display);
}
else else
Format(display, sizeof(display), "%s (%i %s)", display, nominate_count_for_particular_map, spelling); Format(display, sizeof(display), "%s (%i %s)", display, nominate_count_for_particular_map, spelling);
AddMenuItem(menu, map, display); AddMenuItem(menu, map, display);
} }
} }
@@ -889,15 +904,87 @@ bool PopulateNominateListMenu(Menu menu, int client, const char[] filter = "")
delete OwnerList; delete OwnerList;
delete SortedList; delete SortedList;
delete sm; delete sm;
delete sm_special_noms;
delete sm_snapshot; delete sm_snapshot;
return true; return true;
} }
Menu BuildMapMenu(const char[] filter, int client) Menu BuildCategoryMenu(int client)
{
Menu menu = CreateMenu(Handler_CategorySelectMenu, MENU_ACTIONS_DEFAULT);
//2023 edit to allow hiding/unhiding unavailable maps
char hiding_unavailable_maps[MAX_NAME_LENGTH];
if (g_bClientsIgnoring[client])
Format(hiding_unavailable_maps, sizeof(hiding_unavailable_maps), "Show all unavailable maps");
else
Format(hiding_unavailable_maps, sizeof(hiding_unavailable_maps), "Hide all unavailable maps");
AddMenuItem(menu, hiding_unavailable_maps, hiding_unavailable_maps);
ArrayList categories = CreateArray(ByteCountToCells(64));
static char map[PLATFORM_MAX_PATH];
static char category[64];
for (int i = 0; i < GetArraySize(g_MapList); i++)
{
GetArrayString(g_MapList, i, map, sizeof(map));
GetMapCategory(map, category, sizeof(category));
if (FindStringInArray(categories, category) == -1)
PushArrayString(categories, category);
}
SortADTArray(categories, Sort_Ascending, Sort_String);
for (int i = 0; i < GetArraySize(categories); i++)
{
GetArrayString(categories, i, category, sizeof(category));
AddMenuItem(menu, category, category);
}
AddMenuItem(menu, "Full Map list", "Full Map list");
delete categories;
SetMenuExitButton(menu, true);
return menu;
}
public int Handler_CategorySelectMenu(Menu menu, MenuAction action, int param1, int param2)
{
switch(action)
{
case MenuAction_End:
{
delete menu;
}
case MenuAction_Select:
{
static char item[64];
GetMenuItem(menu, param2, item, sizeof(item));
if (StrEqual(item, "Hide all unavailable maps") || StrEqual(item, "Show all unavailable maps"))
{
sql_insert_update_hiding_unavailable(param1);
Menu refreshed = BuildCategoryMenu(param1);
SetNominateMenuTitle(refreshed, param1);
DisplayMenu(refreshed, param1, MENU_TIME_FOREVER);
return 0;
}
Menu submenu = BuildMapMenu("", param1, item);
SetNominateMenuTitle(submenu, param1);
DisplayMenu(submenu, param1, MENU_TIME_FOREVER);
}
}
return 0;
}
Menu BuildMapMenu(const char[] filter, int client, const char[] category = "")
{ {
Menu menu = CreateMenu(Handler_MapSelectMenu, MENU_ACTIONS_DEFAULT|MenuAction_DrawItem|MenuAction_DisplayItem); Menu menu = CreateMenu(Handler_MapSelectMenu, MENU_ACTIONS_DEFAULT|MenuAction_DrawItem|MenuAction_DisplayItem);
static char map[PLATFORM_MAX_PATH * 2]; static char map[PLATFORM_MAX_PATH * 2];
static char mapCategory[64];
int arraySize = ByteCountToCells(PLATFORM_MAX_PATH); int arraySize = ByteCountToCells(PLATFORM_MAX_PATH);
ArrayList MapList = CreateArray(arraySize); ArrayList MapList = CreateArray(arraySize);
@@ -935,22 +1022,19 @@ Menu BuildMapMenu(const char[] filter, int client)
} }
} }
//2023 edit to allow hiding/unhiding unavailable maps
char hiding_unavailable_maps[MAX_NAME_LENGTH];
if (g_bClientsIgnoring[client])
{
Format(hiding_unavailable_maps, sizeof(hiding_unavailable_maps), "Show all unavailable maps");
}
else
{
Format(hiding_unavailable_maps, sizeof(hiding_unavailable_maps), "Hide all unavailable maps");
}
AddMenuItem(menu, hiding_unavailable_maps, hiding_unavailable_maps);
for(int i = 0; i < GetArraySize(g_MapList); i++) for(int i = 0; i < GetArraySize(g_MapList); i++)
{ {
GetArrayString(g_MapList, i, map, sizeof(map)); GetArrayString(g_MapList, i, map, sizeof(map));
if (category[0] && !StrEqual(category, "Full Map list"))
{
//only shows maps that are in this actual category.
GetMapCategory(map, mapCategory, sizeof(mapCategory));
if (!StrEqual(mapCategory, category))
continue;
}
if(!filter[0] || StrContains(map, filter, false) != -1) if(!filter[0] || StrContains(map, filter, false) != -1)
{ {
if (client != 0 && nominated_maps) if (client != 0 && nominated_maps)
@@ -973,11 +1057,9 @@ Menu BuildMapMenu(const char[] filter, int client)
} }
if (g_bClientsIgnoring[client]) if (g_bClientsIgnoring[client])
{ {
if (GetMapCooldownTime(map) > GetTime())
{
continue;
}
if(AreRestrictionsActive() && ( if(AreRestrictionsActive() && (
GetMapCooldownTime(map) > GetTime() ||
GetExcludedMapListingPriority(map) > 0 ||
GetMapTimeRestriction(map) || GetMapTimeRestriction(map) ||
GetMapPlayerRestriction(map) || GetMapPlayerRestriction(map) ||
GetAveragePlayerTimeOnServerMapRestriction(map) > 0 || GetAveragePlayerTimeOnServerMapRestriction(map) > 0 ||
@@ -994,7 +1076,10 @@ Menu BuildMapMenu(const char[] filter, int client)
delete OwnerList; delete OwnerList;
delete sm; delete sm;
SetMenuExitButton(menu, true); if (category[0])
SetMenuExitBackButton(menu, true);
else
SetMenuExitButton(menu, true);
return menu; return menu;
} }
@@ -1041,6 +1126,15 @@ public int Handler_MapSelectMenu(Menu menu, MenuAction action, int param1, int p
delete menu; delete menu;
} }
} }
case MenuAction_Cancel:
{
if (param2 == MenuCancel_ExitBack)
{
Menu back = BuildCategoryMenu(param1);
SetNominateMenuTitle(back, param1);
DisplayMenu(back, param1, MENU_TIME_FOREVER);
}
}
case MenuAction_Select: case MenuAction_Select:
{ {
//2023-03-22 edit since client sometimes is 0 which fucks up mapchooser //2023-03-22 edit since client sometimes is 0 which fucks up mapchooser
@@ -1056,30 +1150,18 @@ public int Handler_MapSelectMenu(Menu menu, MenuAction action, int param1, int p
char name[MAX_NAME_LENGTH]; char name[MAX_NAME_LENGTH];
GetMenuItem(menu, param2, map, sizeof(map)); GetMenuItem(menu, param2, map, sizeof(map));
if (StrEqual(map, "Hide all unavailable maps"))
{
PrintToChat(param1, "Hiding all unavailable maps from the nomination list");
sql_insert_update_hiding_unavailable(param1);
return 0;
}
if (StrEqual(map, "Show all unavailable maps"))
{
PrintToChat(param1, "Displaying all unavailable maps from the nomination list");
sql_insert_update_hiding_unavailable(param1);
return 0;
}
GetClientName(param1, name, MAX_NAME_LENGTH); GetClientName(param1, name, MAX_NAME_LENGTH);
int Index_Cooldown = GetExcludedMapListingPriority(map);
if (GetMapCooldownTime(map) > GetTime()) if (Index_Cooldown > 0)
{ {
PrintToChat(param1, "[NE] You cant nominate this map right now."); PrintToChat(param1, "[NE] You cant nominate this map right now. Overplayed Position: %i", Index_Cooldown);
return 0; return 0;
} }
if (!CheckCommandAccess(param1, "sm_nominate_ignore", ADMFLAG_KICK, true) && !Leader_Is(param1)) if (!CheckCommandAccess(param1, "sm_nominate_ignore", ADMFLAG_KICK, true) && !Leader_Is(param1))
{ {
if(AreRestrictionsActive() && ( if(AreRestrictionsActive() && (
GetMapCooldownTime(map) > GetTime() ||
GetMapTimeRestriction(map) || GetMapTimeRestriction(map) ||
GetMapPlayerRestriction(map) || GetMapPlayerRestriction(map) ||
GetAveragePlayerTimeOnServerMapRestriction(map) > 0 || GetAveragePlayerTimeOnServerMapRestriction(map) > 0 ||
@@ -1172,14 +1254,16 @@ public int Handler_MapSelectMenu(Menu menu, MenuAction action, int param1, int p
} }
delete MapList; delete MapList;
delete OwnerList; delete OwnerList;
if (GetMapCooldownTime(map) > GetTime())
int Index_Cooldown = GetExcludedMapListingPriority(map);
if (Index_Cooldown > 0)
{ {
return ITEMDRAW_DISABLED; return ITEMDRAW_DISABLED;
} }
if(!CheckCommandAccess(param1, "sm_nominate_ignore", ADMFLAG_KICK, true) && !Leader_Is(param1)) if(!CheckCommandAccess(param1, "sm_nominate_ignore", ADMFLAG_KICK, true) && !Leader_Is(param1))
{ {
if(AreRestrictionsActive() && ( if(AreRestrictionsActive() && (
GetMapCooldownTime(map) > GetTime() ||
GetMapTimeRestriction(map) || GetMapTimeRestriction(map) ||
GetMapPlayerRestriction(map) || GetMapPlayerRestriction(map) ||
GetAveragePlayerTimeOnServerMapRestriction(map) > 0 || GetAveragePlayerTimeOnServerMapRestriction(map) > 0 ||
@@ -1231,8 +1315,15 @@ public int Handler_MapSelectMenu(Menu menu, MenuAction action, int param1, int p
Format(buffer, sizeof(buffer), "%s (%T)", buffer, "VIP Restriction", param1); Format(buffer, sizeof(buffer), "%s (%T)", buffer, "VIP Restriction", param1);
} }
int Index_Cooldown = GetExcludedMapListingPriority(map);
if (Index_Cooldown > 0)
{
Format(display, sizeof(display), "%s (Overplayed pos: %i)", map, Index_Cooldown);
return RedrawMenuItem(display);
}
int Cooldown = GetMapCooldownTime(map); int Cooldown = GetMapCooldownTime(map);
if(Cooldown > GetTime()) if(RestrictionsActive && Cooldown > GetTime())
{ {
int Seconds = Cooldown - GetTime(); int Seconds = Cooldown - GetTime();
char time[16]; char time[16];
@@ -1340,6 +1431,7 @@ public int Handler_AdminMapSelectMenu(Menu menu, MenuAction action, int param1,
{ {
if(AreRestrictionsActive() && ( if(AreRestrictionsActive() && (
GetMapCooldownTime(map) > GetTime() || //this one is fine cause its admin nomination. GetMapCooldownTime(map) > GetTime() || //this one is fine cause its admin nomination.
GetExcludedMapListingPriority(map) > 0 ||
GetMapTimeRestriction(map) || GetMapTimeRestriction(map) ||
GetMapPlayerRestriction(map) || GetMapPlayerRestriction(map) ||
GetAveragePlayerTimeOnServerMapRestriction(map) > 0 || GetAveragePlayerTimeOnServerMapRestriction(map) > 0 ||
@@ -249,7 +249,7 @@ void UpdateRTV()
public int get_voted_rtv() public int get_voted_rtv()
{ {
int Votes = 0; int Votes = 0;
for (int i = 0; i < MaxClients; i++) for (int i = 0; i <= MaxClients; i++)
{ {
if (IsValidClient(i) && g_Voted[i]) if (IsValidClient(i) && g_Voted[i])
{ {
@@ -319,10 +319,10 @@ void AttemptRTV(int client)
return; return;
} }
update_g_VotesNeeded(); update_g_VotesNeeded();
int Votes = get_voted_rtv();
if (g_Voted[client]) if (g_Voted[client])
{ {
int Votes = get_voted_rtv();
ReplyToCommand(client, "[RTVE] You have already voted to Rock the Vote. (%i/%i Votes. (%i RTV boost))", Votes, g_VotesNeeded, GetPlayerWorthRTV_boost_(client)); ReplyToCommand(client, "[RTVE] You have already voted to Rock the Vote. (%i/%i Votes. (%i RTV boost))", Votes, g_VotesNeeded, GetPlayerWorthRTV_boost_(client));
return; return;
} }
@@ -332,7 +332,7 @@ void AttemptRTV(int client)
g_Voted[client] = true; g_Voted[client] = true;
Votes = get_voted_rtv(); int Votes = get_voted_rtv();
PrintToChatAll("[RTVE] %s wants to rock the vote. (%i/%i RTV reached) (%i RTV boost).", name, Votes, g_VotesNeeded, GetPlayerWorthRTV_boost_(client)); PrintToChatAll("[RTVE] %s wants to rock the vote. (%i/%i RTV reached) (%i RTV boost).", name, Votes, g_VotesNeeded, GetPlayerWorthRTV_boost_(client));
@@ -234,9 +234,10 @@ public MRESReturn TryPlayerMove_Dhook(Address pThis, Handle hReturn, Handle hPar
Address pFirstTrace = DHookGetParam(hParams, 2); Address pFirstTrace = DHookGetParam(hParams, 2);
DHookSetReturn(hReturn, TryPlayerMove(view_as<CGameMovement>(pThis), view_as<Vector>(pFirstDest), view_as<CGameTrace>(pFirstTrace))); DHookSetReturn(hReturn, TryPlayerMove(view_as<CGameMovement>(pThis), view_as<Vector>(pFirstDest), view_as<CGameTrace>(pFirstTrace)));
return MRES_Supercede;
} }
return MRES_Ignored;
return MRES_Supercede;
} }
int TryPlayerMove(CGameMovement pThis, Vector pFirstDest, CGameTrace pFirstTrace) int TryPlayerMove(CGameMovement pThis, Vector pFirstDest, CGameTrace pFirstTrace)
+189
View File
@@ -0,0 +1,189 @@
#pragma semicolon 1
#define PLUGIN_AUTHOR "jenz"
#define PLUGIN_VERSION "1.0"
#include <sourcemod>
Database g_hDatabase;
char g_cTimeRecords[18][256];
public Plugin myinfo =
{
name = "unloze top activity",
author = PLUGIN_AUTHOR,
description = "listing top activity on ze",
version = PLUGIN_VERSION,
url = "www.unloze.com"
};
public void OnPluginStart()
{
if (!g_hDatabase)
{
Database.Connect(SQL_OnDatabaseConnect, "unloze_playtimestats");
}
RegConsoleCmd("sm_activity", Command_topactivity, "retrieve top activity on ze for the week");
RegConsoleCmd("sm_myactivity", Command_myactivity, "retrieve your own activity on ze for the week");
CreateTimer(1800.0, update_top_activity, _, TIMER_REPEAT);
update_top_activity_ze();
}
public Action update_top_activity(Handle timer)
{
update_top_activity_ze();
return Plugin_Handled;
}
public void update_top_activity_ze()
{
if (!g_hDatabase)
{
Database.Connect(SQL_OnDatabaseConnect, "unloze_playtimestats");
return;
}
char sQuery[1024];
Format(sQuery, sizeof(sQuery), "select pt.steam_id, pt.player_name, SUM(pt.ze_time) - pa.ze_time_start_week AS time_this_week from unloze_playtimestats.player_activity_ze pa inner join unloze_playtimestats.player_time pt on pa.steamid = pt.steam_id where pa.steamid not in ('STEAM_0:0:518094602', 'STEAM_0:0:204398871', 'STEAM_0:1:60189040', 'STEAM_0:0:610560766') GROUP BY pt.steam_id ORDER BY time_this_week DESC limit 15");
g_hDatabase.Query(SQL_top_activity, sQuery, DBPrio_Low);
}
public void SQL_top_activity(Database db, DBResultSet results, const char[] error, int iSerial)
{
if (!db || strlen(error))
{
delete results;
LogError("Query error: %s", error);
return;
}
int counter = 0;
int counter_menu = 1;
Format(g_cTimeRecords[counter], sizeof(g_cTimeRecords[]), "Top activity: 5 days VIP");
counter++;
while (results.RowCount && results.FetchRow())
{
char sBuffer[528];
char sName[MAX_NAME_LENGTH];
results.FetchString(1, sName, sizeof(sName));
float time_this_week = results.FetchFloat(2);
int hours_server = RoundToFloor((time_this_week / 60) / 60);
int minutes_server = RoundToFloor((time_this_week / 60) % 60);
Format(sBuffer, sizeof(sBuffer), "%i %s %d Hours %d Minutes", counter_menu, sName, hours_server, minutes_server);
Format(g_cTimeRecords[counter], sizeof(g_cTimeRecords[]), sBuffer);
counter++;
counter_menu++;
if (counter == 6)
{
Format(g_cTimeRecords[counter], sizeof(g_cTimeRecords[]), "Top activity: 3 days VIP");
counter++;
}
if (counter == 11)
{
Format(g_cTimeRecords[counter], sizeof(g_cTimeRecords[]), "Top activity: 1 day VIP");
counter++;
}
}
delete results;
}
public void SQL_OnDatabaseConnect(Database db, const char[] error, any data)
{
if(!db || strlen(error))
{
LogError("Database error: %s", error);
return;
}
g_hDatabase = db;
char sQuery[1024];
Format(sQuery, sizeof(sQuery), "select pt.steam_id, pt.player_name, SUM(pt.ze_time) - pa.ze_time_start_week AS time_this_week from unloze_playtimestats.player_activity_ze pa inner join unloze_playtimestats.player_time pt on pa.steamid = pt.steam_id where pa.steamid not in ('STEAM_0:0:518094602', 'STEAM_0:0:204398871', 'STEAM_0:1:60189040', 'STEAM_0:0:610560766') GROUP BY pt.steam_id ORDER BY time_this_week DESC limit 15");
g_hDatabase.Query(SQL_top_activity, sQuery, DBPrio_Low);
}
public Action Command_myactivity(int client, int args)
{
if (!g_hDatabase)
{
Database.Connect(SQL_OnDatabaseConnect, "unloze_playtimestats");
return Plugin_Handled;
}
char sSID[64];
GetClientAuthId(client, AuthId_Steam2, sSID, sizeof(sSID));
char sQuery[1024];
Format(sQuery, sizeof(sQuery), "select pt.steam_id, pt.player_name, SUM(pt.ze_time) - pa.ze_time_start_week AS time_this_week from unloze_playtimestats.player_activity_ze pa inner join unloze_playtimestats.player_time pt on pa.steamid = pt.steam_id where pa.steamid = '%s' GROUP BY pt.steam_id ORDER BY time_this_week DESC limit 15", sSID);
g_hDatabase.Query(SQL_my_activity, sQuery, GetClientSerial(client));
return Plugin_Handled;
}
public void SQL_my_activity(Database db, DBResultSet results, const char[] error, int iSerial)
{
if (!db || strlen(error))
{
delete results;
LogError("Query error: %s", error);
return;
}
int client;
if ((client = GetClientFromSerial(iSerial)) == 0)
{
delete results;
return;
}
char sTitle[64];
Format(sTitle, sizeof(sTitle), "[UNLOZE your weekly activity ZE]");
Menu menu = new Menu(MenuHandler1);
menu.SetTitle(sTitle);
if (results.RowCount && results.FetchRow())
{
char sBuffer[528];
char sName[MAX_NAME_LENGTH];
results.FetchString(1, sName, sizeof(sName));
float time_this_week = results.FetchFloat(2);
int hours_server = RoundToFloor((time_this_week / 60) / 60);
int minutes_server = RoundToFloor((time_this_week / 60) % 60);
Format(sBuffer, sizeof(sBuffer), "%s %d Hours %d Minutes", sName, hours_server, minutes_server);
menu.AddItem("-1", sBuffer, ITEMDRAW_DISABLED);
}
delete results;
menu.ExitButton = true;
menu.Display(client, 0);
}
public Action Command_topactivity(int client, int args)
{
if (!g_hDatabase)
{
Database.Connect(SQL_OnDatabaseConnect, "unloze_playtimestats");
return Plugin_Handled;
}
char sTitle[64];
Format(sTitle, sizeof(sTitle), "[UNLOZE weekly activity ZE]");
Menu menu = new Menu(MenuHandler1);
menu.SetTitle(sTitle);
for (int i = 0; i < sizeof(g_cTimeRecords); i++)
{
menu.AddItem("-1", g_cTimeRecords[i], ITEMDRAW_DISABLED);
}
menu.ExitButton = true;
menu.Display(client, 0);
return Plugin_Handled;
}
public int MenuHandler1(Menu menu, MenuAction action, int param1, int param2)
{
switch(action)
{
case MenuAction_End:
{
delete menu;
}
}
return 0;
}
+215
View File
@@ -0,0 +1,215 @@
"Trails"
{
"Dollars"
{
"material" "materials/sprites/store/trails/dollars.vmt"
"tier" "9"
}
"Donuts"
{
"material" "materials/sprites/store/trails/donuts.vmt"
"tier" "9"
}
"Double Rainbow"
{
"material" "materials/sprites/store/trails/doublerainbow.vmt"
"tier" "10"
}
"Dragon"
{
"material" "materials/sprites/store/trails/dragon.vmt"
"tier" "10"
}
"8Bit Mushroom"
{
"material" "materials/sprites/store/trails/8bitmushroom.vmt"
"tier" "11"
}
"Arrow Rainbow"
{
"material" "materials/sprites/store/trails/arrowrainbow.vmt"
"tier" "11"
}
"Arrows"
{
"material" "materials/sprites/store/trails/arrows.vmt"
"tier" "11"
}
"Assasin"
{
"material" "materials/sprites/store/trails/assasin.vmt"
"tier" "11"
}
"Awesome"
{
"material" "materials/sprites/store/trails/awesome.vmt"
"tier" "11"
"VIP" "1"
}
"8Bit Pow"
{
"material" "materials/sprites/store/trails/8bitpow.vmt"
"tier" "11"
"VIP" "1"
}
"Banknote"
{
"material" "materials/sprites/store/trails/banknote.vmt"
"tier" "12"
}
"Barcalona"
{
"material" "materials/sprites/store/trails/barcalona.vmt"
"tier" "12"
}
"Batman"
{
"material" "materials/sprites/store/trails/batman.vmt"
"tier" "12"
}
"Battlefield"
{
"material" "materials/sprites/store/trails/battlefield.vmt"
"tier" "12"
}
"Beer Mug"
{
"material" "materials/sprites/store/trails/beermug.vmt"
"tier" "12"
"VIP" "1"
}
"Blue Lightning"
{
"material" "materials/sprites/store/trails/bluelightning.vmt"
"tier" "13"
}
"BMW Logo"
{
"material" "materials/sprites/store/trails/bmwlogo.vmt"
"tier" "13"
}
"Bom Bomb"
{
"material" "materials/sprites/store/trails/bombomb.vmt"
"tier" "13"
}
"Boo"
{
"material" "materials/sprites/store/trails/boo.vmt"
"tier" "13"
"VIP" "1"
}
"Canada Flag"
{
"material" "materials/sprites/store/trails/canadaflag.vmt"
"tier" "14"
}
"Cereal-guy"
{
"material" "materials/sprites/store/trails/cereal-guy.vmt"
"tier" "14"
}
"Challenge"
{
"material" "materials/sprites/store/trails/challenge.vmt"
"tier" "14"
}
"Coca-Cola"
{
"material" "materials/sprites/store/trails/cocacola.vmt"
"tier" "14"
}
"Cookies"
{
"material" "materials/sprites/store/trails/cookies.vmt"
"tier" "15"
}
"Cracked Beam"
{
"material" "materials/sprites/store/trails/crackedbeam.vmt"
"tier" "15"
}
"Creed"
{
"material" "materials/sprites/store/trails/creed.vmt"
"tier" "15"
}
"Creeper"
{
"material" "materials/sprites/store/trails/creeper.vmt"
"tier" "15"
}
"Crown"
{
"material" "materials/sprites/store/trails/crown.vmt"
"tier" "15"
}
"Danish Flag"
{
"material" "materials/sprites/store/trails/danishflag.vmt"
"VIP" "1"
}
"Dark Knight"
{
"material" "materials/sprites/store/trails/darkknight.vmt"
"VIP" "1"
}
"Coca-Cola 2"
{
"material" "materials/sprites/store/trails/cocacola2.vmt"
"VIP" "1"
}
"Bullet Bill"
{
"material" "materials/sprites/store/trails/bulletbill.vmt"
"VIP" "1"
}
"Biohazard"
{
"material" "materials/sprites/store/trails/biohazard.vmt"
"VIP" "1"
}
"Apple"
{
"material" "materials/sprites/store/trails/apple.vmt"
"VIP" "1"
}
"Airforce"
{
"material" "materials/sprites/store/trails/airforce.vmt"
"VIP" "1"
}
"Airforce 2"
{
"material" "materials/sprites/store/trails/airforce2.vmt"
"VIP" "1"
}
}
+478
View File
@@ -0,0 +1,478 @@
#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
float g_fTrailsLifeTime = 1.0;
int g_iTrailsStartWidth = 10;
int g_iTrailsEndWidth = 6;
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));
ConVar cvar;
HookConVarChange((cvar = CreateConVar("sm_unloze_trails_lifetime", "1.0", "Lifetime of trails")), Cvar_TrailsLifeTime);
g_fTrailsLifeTime = cvar.FloatValue;
delete cvar;
ConVar cvar1;
HookConVarChange((cvar1 = CreateConVar("sm_unloze_trails_start_width", "10", "Start width of trails")), Cvar_TrailsStartWidth);
g_iTrailsStartWidth = cvar1.IntValue;
delete cvar1;
ConVar cvar2;
HookConVarChange((cvar2 = CreateConVar("sm_unloze_trails_end_width", "6", "End width of trails")), Cvar_TrailsEndWidth);
g_iTrailsEndWidth = cvar2.IntValue;
delete cvar2;
}
public void Cvar_TrailsEndWidth(ConVar convar, const char[] oldValue, const char[] newValue)
{
g_iTrailsEndWidth = convar.IntValue;
}
public void Cvar_TrailsStartWidth(ConVar convar, const char[] oldValue, const char[] newValue)
{
g_iTrailsStartWidth = convar.IntValue;
}
public void Cvar_TrailsLifeTime(ConVar convar, const char[] oldValue, const char[] newValue)
{
g_fTrailsLifeTime = convar.FloatValue;
}
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", g_fTrailsLifeTime);
char startwidth[16];
Format(startwidth, sizeof(startwidth), "%i", g_iTrailsStartWidth);
DispatchKeyValue(g_iSpriteModel[client], "startwidth", startwidth);
char endwidth[16];
Format(endwidth, sizeof(endwidth), "%i", g_iTrailsEndWidth);
DispatchKeyValue(g_iSpriteModel[client], "endwidth", endwidth);
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] = 5.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;
}