2464 lines
90 KiB
SourcePawn
2464 lines
90 KiB
SourcePawn
#pragma semicolon 1
|
|
#define PLUGIN_AUTHOR "jenz, https://steamcommunity.com/id/type_moon/"
|
|
#define PLUGIN_VERSION "1.3"
|
|
#define g_dIndexes 128
|
|
#define g_dLength 256
|
|
#define CSGO_KNOCKBACK_BOOST 251.0
|
|
#define CSGO_KNOCKBACK_BOOST_MAX 350.0
|
|
#define HEGrenadeOffset 11 // (11 * 4)
|
|
#define FlashbangOffset 12 // (12 * 4)
|
|
#define SmokegrenadeOffset 13 // (13 * 4)
|
|
#include <sourcemod>
|
|
#include <sdktools>
|
|
#include <cstrike>
|
|
#include <sdkhooks>
|
|
#include <dhooks>
|
|
#include <clientprefs>
|
|
#include <smlib>
|
|
|
|
//smrpg not letting health be overwritten by zr classes
|
|
#tryinclude <smrpg_health>
|
|
|
|
#pragma newdecls required
|
|
//#pragma dynamic 131072
|
|
char g_cDaysTitles[100][512];
|
|
static char g_cPathsClassHuman[PLATFORM_MAX_PATH];
|
|
static char g_cPathsClassZM[PLATFORM_MAX_PATH];
|
|
static char g_cPathsDownload[PLATFORM_MAX_PATH];
|
|
static char g_cPathsWaveSettings[PLATFORM_MAX_PATH];
|
|
static char g_cPathsWeapons[PLATFORM_MAX_PATH];
|
|
static char g_cPathsExtra[PLATFORM_MAX_PATH];
|
|
char g_cUniqueName[g_dIndexes][g_dLength];
|
|
char g_cZMRoundClasses[g_dIndexes][g_dLength];
|
|
char g_cHumanClasses[g_dIndexes][g_dLength];
|
|
char g_cTeam[g_dIndexes][g_dLength];
|
|
char g_cGroup[g_dIndexes][g_dLength];
|
|
char g_cSMFLAGS[g_dIndexes][g_dLength];
|
|
char g_cModelPath[g_dIndexes][g_dLength];
|
|
char g_cNoFallDmg[g_dIndexes][g_dLength];
|
|
char g_cHealth[g_dIndexes][g_dLength];
|
|
char g_cSpeed[g_dIndexes][g_dLength];
|
|
char g_cKnockback[g_dIndexes][g_dLength];
|
|
char g_cJumpHeight[g_dIndexes][g_dLength];
|
|
char g_cJumpDistance[g_dIndexes][g_dLength];
|
|
char g_cDamageMultiplier[g_dIndexes][g_dLength];
|
|
char g_cAdminGroups[g_dIndexes][g_dIndexes][g_dLength];
|
|
char g_cZMSounds[g_dIndexes][g_dLength];
|
|
char g_cWeaponEntity[g_dIndexes][g_dLength];
|
|
char g_cWeaponNames[g_dIndexes][g_dLength];
|
|
char g_cWeaponCommand[g_dIndexes][g_dLength];
|
|
char g_cBossSound[512];
|
|
char g_cAmbientSOund[64][512];
|
|
|
|
float g_fAmbientSoundLoopDuration;
|
|
float g_fBossSoundLoopDuration;
|
|
int g_iLength = g_dLength - 1;
|
|
int g_iWave;
|
|
int g_iSpeedDelayClient[MAXPLAYERS + 1];
|
|
float g_iZMScaleability;
|
|
int g_iZMCount;
|
|
int g_iToolsVelocity; //from zombie reloaded
|
|
int g_iClientZMClasses[g_dIndexes];
|
|
int g_iClientHumanClasses[g_dIndexes];
|
|
int g_iClientRespawnCount[g_dIndexes];
|
|
int g_iWeaponSlot[g_dIndexes];
|
|
int g_iWeaponPrice[g_dIndexes];
|
|
int g_iBotStuckindex[g_dIndexes];
|
|
int g_iClientRespawnCountNum;
|
|
int g_iZMBeginindex;
|
|
int g_iSoundIndexes;
|
|
int g_iWeaponIndex;
|
|
int g_iBotStuckCounts;
|
|
int g_iLoadClassesIndex;
|
|
int g_iHumanCount;
|
|
int g_iZombieCount;
|
|
int g_iZombieBossIndex[g_dIndexes];
|
|
int g_iBossBotCount;
|
|
|
|
float g_fKnockBackIndex[g_dIndexes + 1];
|
|
float g_fJumpHeightIndex[g_dIndexes + 1];
|
|
float g_fJumpDistanceIndex[g_dIndexes + 1];
|
|
float g_fDamageMultiplier[g_dIndexes + 1];
|
|
float g_fSwitchingTimer;
|
|
float g_fZMSpawnProtection;
|
|
float g_fHumanSpawnProtection;
|
|
float g_fZMHealthScaleability;
|
|
float g_fRespawnTimer;
|
|
float g_fZMSounds;
|
|
float g_fBotStuckPush;
|
|
|
|
bool g_bSwitchingIndex;
|
|
bool g_bRoundInProgress;
|
|
bool g_bFallDamage[g_dIndexes];
|
|
bool g_bClientProtection[g_dIndexes];
|
|
bool g_bIsBossRound;
|
|
bool g_bClientIsBoss[MAXPLAYERS + 1];
|
|
|
|
Handle g_hClientZMCookie;
|
|
Handle g_hClientHumanCookie;
|
|
Handle g_hCheckBotStuck = null;
|
|
Handle g_hZombieSounds = null;
|
|
Handle g_hFixKNife = null;
|
|
Handle g_hAmbient = null;
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Plugin myinfo =
|
|
{
|
|
name = "Unloze Zombie Riot",
|
|
author = PLUGIN_AUTHOR,
|
|
description = "Zombie Riot mod. originally for csgo but remade for css",
|
|
version = PLUGIN_VERSION,
|
|
url = "www.unloze.com"
|
|
};
|
|
|
|
public bool select_map_specific_waves()
|
|
{
|
|
char mapname[512];
|
|
char mapdaystitle[512];
|
|
GetCurrentMap(mapname, sizeof(mapname));
|
|
Format(mapdaystitle, sizeof(mapdaystitle), "configs/unloze_zr/mapwaves/%s_daystitle.txt", mapname);
|
|
Format(mapname, sizeof(mapname), "configs/unloze_zr/mapwaves/%s.txt", mapname);
|
|
|
|
BuildPath(Path_SM, mapname, sizeof(mapname), mapname);
|
|
BuildPath(Path_SM, mapdaystitle, sizeof(mapdaystitle), mapdaystitle);
|
|
if (FileExists(mapdaystitle) && FileExists(mapname))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void loadDays()
|
|
{
|
|
char localPath[512];
|
|
if (select_map_specific_waves())
|
|
{
|
|
char mapname[512];
|
|
GetCurrentMap(mapname, sizeof(mapname));
|
|
Format(mapname, sizeof(mapname), "configs/unloze_zr/mapwaves/%s_daystitle.txt", mapname);
|
|
BuildPath(Path_SM, localPath, sizeof(localPath), mapname);
|
|
}
|
|
else
|
|
{
|
|
BuildPath(Path_SM, localPath, sizeof(localPath), "configs/unloze_zr/daystitle.txt");
|
|
}
|
|
Handle fileHandle = OpenFile(localPath, "r");
|
|
char lineBuffer[512];
|
|
int count = 0;
|
|
while( !IsEndOfFile( fileHandle ) && ReadFileLine( fileHandle, lineBuffer, sizeof( lineBuffer ) ) )
|
|
{
|
|
TrimString( lineBuffer );
|
|
Format(g_cDaysTitles[count], sizeof(g_cDaysTitles[]), lineBuffer);
|
|
count++;
|
|
}
|
|
CloseHandle( fileHandle );
|
|
}
|
|
|
|
public void OnPluginStart()
|
|
{
|
|
//processstring
|
|
LoadTranslations("common.phrases.txt");
|
|
|
|
//cookies
|
|
if (g_hClientZMCookie == null)
|
|
g_hClientZMCookie = RegClientCookie("unloze_zr_classprefZM", "Cookie for ZM classes", CookieAccess_Protected);
|
|
|
|
if (g_hClientHumanCookie == null)
|
|
g_hClientHumanCookie = RegClientCookie("unloze_zr_classprefHuman", "Cookie for Human classes", CookieAccess_Protected);
|
|
|
|
BuildPath(Path_SM, g_cPathsClassZM, sizeof(g_cPathsClassZM), "configs/unloze_zr/classeszm.txt");
|
|
BuildPath(Path_SM, g_cPathsClassHuman, sizeof(g_cPathsClassHuman), "configs/unloze_zr/classeshuman.txt");
|
|
BuildPath(Path_SM, g_cPathsExtra, sizeof(g_cPathsExtra), "configs/unloze_zr/extra.txt");
|
|
BuildPath(Path_SM, g_cPathsDownload, sizeof(g_cPathsDownload), "configs/unloze_zr/download.txt");
|
|
BuildPath(Path_SM, g_cPathsWaveSettings, sizeof(g_cPathsWaveSettings), "configs/unloze_zr/wavesettings.txt");
|
|
BuildPath(Path_SM, g_cPathsWeapons, sizeof(g_cPathsWeapons), "configs/unloze_zr/weapons.txt");
|
|
|
|
//hooks
|
|
HookEvent("player_spawn", ApplySettings, EventHookMode_Post);
|
|
HookEvent("round_start", Event_roundStart, EventHookMode_Post);
|
|
HookEvent("player_death", Event_OnPlayerDeath, EventHookMode_Post);
|
|
HookEvent("player_hurt", EventPlayerHurt, EventHookMode_Pre);
|
|
HookEvent("player_jump", EventPlayerJump, EventHookMode_Post);
|
|
HookEvent("player_team", EventPlayerTeam, EventHookMode_Post);
|
|
|
|
//commands
|
|
RegConsoleCmd("say", Cmd_Say);
|
|
RegConsoleCmd("sm_zclass", Cmd_Zclass, "Class Prefferences"); //named like zombiereloaded for ease of use
|
|
RegConsoleCmd("sm_zmarket", Cmd_zmarket, "weapon Prefferences"); //named like zombiereloaded for ease of use
|
|
RegConsoleCmd("sm_market", Cmd_zmarket, "weapon Prefferences"); //named like zombiereloaded for ease of use
|
|
RegConsoleCmd("sm_buy", Cmd_zmarket, "weapon Prefferences"); //named like zombiereloaded for ease of use
|
|
RegAdminCmd("sm_LoadClasses", Cmd_LoadManually, ADMFLAG_RCON);
|
|
RegAdminCmd("sm_wave", Cmd_ChangeWave, ADMFLAG_RCON);
|
|
RegAdminCmd("sm_human", Cmd_Humanize, ADMFLAG_BAN);
|
|
RegAdminCmd("sm_infect", Cmd_Zombienize, ADMFLAG_BAN);
|
|
|
|
g_hCheckBotStuck = CreateTimer(2.0, Timer_CheckIfBotsStuck, INVALID_HANDLE, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
|
|
g_hZombieSounds = CreateTimer(g_fZMSounds, Timer_zombieSounds, INVALID_HANDLE, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
|
|
g_hFixKNife = CreateTimer(2.0, Timer_FixKNife, INVALID_HANDLE, TIMER_REPEAT);
|
|
|
|
for (int i = 1; i < MaxClients; i++)
|
|
{
|
|
if (IsValidClient(i))
|
|
{
|
|
OnClientPostAdminCheck(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void OnPluginEnd()
|
|
{
|
|
if (g_hCheckBotStuck != null)
|
|
delete g_hCheckBotStuck;
|
|
if (g_hZombieSounds != null)
|
|
delete g_hZombieSounds;
|
|
if (g_hFixKNife != null)
|
|
delete g_hFixKNife;
|
|
if (g_hAmbient != null)
|
|
delete g_hAmbient;
|
|
}
|
|
|
|
public Action CheckPlayerTeam(Handle timer, any userid)
|
|
{
|
|
int client = GetClientOfUserId(userid);
|
|
if (client == 0)
|
|
return Plugin_Continue;
|
|
|
|
checkIfRestartNeeded();
|
|
if (!IsValidClient(client) || IsPlayerAlive(client) || (GetClientTeam(client) != CS_TEAM_T && GetClientTeam(client) != CS_TEAM_CT)
|
|
|| IsFakeClient(client))
|
|
{
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
if (g_iClientRespawnCount[client] > 0)
|
|
{
|
|
ChangeClientTeam(client, CS_TEAM_CT); //default putting humans to CT team
|
|
PrintToChat(client, "You have %i respawns left as human. You will respawn in %f seconds.", g_iClientRespawnCount[client], g_fRespawnTimer);
|
|
CreateTimer(g_fRespawnTimer, Timer_Respawn, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
|
|
}
|
|
else
|
|
{
|
|
ChangeClientTeam(client, CS_TEAM_T); //default putting humans to ZM
|
|
PrintToChat(client, "You will respawn as a zombie in %f seconds.", g_fRespawnTimer);
|
|
CreateTimer(g_fRespawnTimer, Timer_Respawn, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
|
|
}
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action EventPlayerTeam(Event event, const char[] name, bool dontBroadcast)
|
|
{
|
|
int client = GetClientOfUserId(event.GetInt("userid"));
|
|
CreateTimer(1.0, CheckPlayerTeam, GetClientUserId(client));
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Timer_CheckIfRestartNeeded(Handle timer, any userid)
|
|
{
|
|
//the bots dont spawn right away. therefore we have the 6 seconds delay for them to actually spawn in.
|
|
int activeBots = 0;
|
|
for (int i = 1; i < MaxClients; i++)
|
|
{
|
|
if (IsValidClient(i) && IsFakeClient(i) && !IsClientSourceTV(i))
|
|
{
|
|
activeBots++;
|
|
}
|
|
if (activeBots > 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (activeBots == 0)
|
|
{
|
|
//bots did still not spawn. we need the restart to spawn them in.
|
|
PrintToChatAll("First Player joining. Restarting the round...");
|
|
CS_TerminateRound(4.0, CSRoundEnd_Draw, true);
|
|
}
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public void checkIfRestartNeeded()
|
|
{
|
|
int activeBots = 0;
|
|
int activePlayers = 0;
|
|
for (int i = 1; i < MaxClients; i++)
|
|
{
|
|
//if a guy sits in spec it does not restart the round. needed IsPlayerAlive.
|
|
if (!IsValidClient(i) || IsClientSourceTV(i) || !IsPlayerAlive(i))
|
|
{
|
|
continue;
|
|
}
|
|
if (IsFakeClient(i))
|
|
{
|
|
activeBots++;
|
|
}
|
|
else
|
|
{
|
|
activePlayers++;
|
|
}
|
|
if (activeBots > 0 && activePlayers > 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (activeBots == 0 && activePlayers == 1)
|
|
{
|
|
CreateTimer(10.0, Timer_CheckIfRestartNeeded); //if only one guy is on a team we force a restart to spawn the bots.
|
|
}
|
|
}
|
|
|
|
public Action ApplySettings(Event event, const char[] name, bool dontBroadcast)
|
|
{
|
|
checkIfRestartNeeded();
|
|
|
|
int client = GetClientOfUserId(event.GetInt("userid"));
|
|
if (!IsValidClient(client) || !IsPlayerAlive(client) || IsClientSourceTV(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
//when zombies spawn remove every weapon they have except of knife. When their spawn protection runs out we also check if they have a knife.
|
|
int l_iWeapon;
|
|
if (GetClientTeam(client) == CS_TEAM_T)
|
|
{
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
l_iWeapon = GetPlayerWeaponSlot(client, i);
|
|
if (l_iWeapon != -1 && i != 2)
|
|
{
|
|
RemovePlayerItem(client, l_iWeapon);
|
|
}
|
|
}
|
|
}
|
|
|
|
//removing guns from zombies when they spawn.
|
|
|
|
if (!IsFakeClient(client) && g_iClientRespawnCount[client] < 1) //player ran out of human respawns and will be zm instead.
|
|
{
|
|
SelectWaveBasedZM(client, 1);
|
|
}
|
|
else if (IsFakeClient(client)) //bot getting respawned as zm
|
|
{
|
|
CreateTimer(0.3, Timer_delayedSelectWaveBasedZM, GetClientUserId(client));
|
|
}
|
|
else
|
|
{
|
|
SelectWavebasedHuman(client); //player getting respawned as human
|
|
}
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Timer_delayedSelectWaveBasedZM(Handle timer, any userid)
|
|
{
|
|
int client = GetClientOfUserId(userid);
|
|
if (!IsValidClient(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
SelectWaveBasedZM(client, 0);
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Cmd_LoadManually(int client, int args)
|
|
{
|
|
AddDownloadContent();
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Cmd_zmarket(int client, int args)
|
|
{
|
|
Zmarket(client);
|
|
return Plugin_Handled;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Cmd_Humanize(int client, int args)
|
|
{
|
|
InfectionSlashHumanHandling(client, args, 0);
|
|
return Plugin_Handled;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Cmd_Zombienize(int client, int args)
|
|
{
|
|
InfectionSlashHumanHandling(client, args, 1);
|
|
return Plugin_Handled;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Cmd_Zclass(int client, int args)
|
|
{
|
|
Zclass(client);
|
|
return Plugin_Handled;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Cmd_ChangeWave(int client, int args)
|
|
{
|
|
char l_cChangeWave[4];
|
|
int l_iWave;
|
|
GetCmdArg(1, l_cChangeWave, sizeof(l_cChangeWave));
|
|
l_iWave = StringToInt(l_cChangeWave);
|
|
if (l_iWave > 0)
|
|
{
|
|
g_iWave = l_iWave;
|
|
PrintToChatAll("Admin %N Changing to Day %i: %s", client, g_iWave, g_cDaysTitles[g_iWave - 1]);
|
|
CS_TerminateRound(4.0, CSRoundEnd_Draw, true);
|
|
}
|
|
else
|
|
{
|
|
ReplyToCommand(client, "Incorrect input");
|
|
}
|
|
return Plugin_Handled;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Cmd_Say(int client, int args)
|
|
{
|
|
/*
|
|
getclientteam might be checked unnecesarily this way because its also checking in ZmarketGetWeapon
|
|
but this way most can be stopped to interferre from triggering cmd_say
|
|
*/
|
|
if (!IsValidClient(client))
|
|
{
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
if (GetClientTeam(client) != CS_TEAM_CT || !IsPlayerAlive(client))
|
|
return Plugin_Continue;
|
|
char l_cBuffer[g_dLength];
|
|
char l_cBuffer2[g_dLength];
|
|
GetCmdArgString(l_cBuffer, sizeof(l_cBuffer));
|
|
if (StrContains(l_cBuffer, "!") == -1 && StrContains(l_cBuffer, "/") == -1)
|
|
return Plugin_Continue;
|
|
ReplaceString(l_cBuffer, sizeof(l_cBuffer), "\"", "");
|
|
ReplaceString(l_cBuffer, sizeof(l_cBuffer), "/", "");
|
|
ReplaceString(l_cBuffer, sizeof(l_cBuffer), "!", "");
|
|
if (StrContains(l_cBuffer, "sm_") == -1)
|
|
{
|
|
Format(l_cBuffer2, sizeof(l_cBuffer2), "sm_");
|
|
StrCat(l_cBuffer2, sizeof(l_cBuffer2), l_cBuffer);
|
|
}
|
|
for (int i = 0; i <= g_iWeaponIndex; i++)
|
|
{
|
|
if (strlen(g_cWeaponCommand[i][g_iLength]) < 1)
|
|
continue;
|
|
if (StrEqual(l_cBuffer, g_cWeaponCommand[i][g_iLength], false) || StrEqual(l_cBuffer2, g_cWeaponCommand[i][g_iLength], false))
|
|
{
|
|
ZmarketGetWeapon(client, i);
|
|
break;
|
|
}
|
|
}
|
|
return Plugin_Continue;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action InfectionSlashHumanHandling(int client, int args, int state)
|
|
{
|
|
if (args < 1)
|
|
{
|
|
ReplyToCommand(client, "[SM] Usage: sm_human <#userid|name>");
|
|
ReplyToCommand(client, "[SM] Usage: sm_infect <#userid|name>");
|
|
return Plugin_Handled;
|
|
}
|
|
findTarget(client, state);
|
|
return Plugin_Continue;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void findTarget(int client, int state)
|
|
{
|
|
//state 0 human, state 1 zm
|
|
char target[MAX_NAME_LENGTH];
|
|
char targetname[MAX_NAME_LENGTH];
|
|
int targets[g_dLength];
|
|
int result;
|
|
bool tn_is_ml;
|
|
GetCmdArg(1, target, sizeof(target));
|
|
// Find a target.
|
|
result = ProcessTargetString(target, client, targets, sizeof(targets), COMMAND_FILTER_ALIVE , targetname, sizeof(targetname), tn_is_ml);
|
|
// Check if there was a problem finding a client.
|
|
if (result != 1)
|
|
{
|
|
PrintToChat(client, "Found no specific Target!");
|
|
return;
|
|
}
|
|
if (!IsPlayerAlive(targets[0]))
|
|
{
|
|
PrintToChat(client, "Target is not alive. Cant be turned human or zombie.");
|
|
return;
|
|
}
|
|
if (state == 0)
|
|
{
|
|
PrintToChat(client, "Humanized: %N", targets[0]);
|
|
SelectWavebasedHuman(targets[0]);
|
|
g_iClientRespawnCount[client] = g_iClientRespawnCountNum;
|
|
}
|
|
else
|
|
{
|
|
g_iClientRespawnCount[client] = 0;
|
|
PrintToChat(client, "Infected: %N", targets[0]);
|
|
SelectWaveBasedZM(targets[0], 1);
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void Zmarket(int client)
|
|
{
|
|
Menu ZmarketMenu = CreateMenu(Zmarket_menu);
|
|
ZmarketMenu.SetTitle("Weapon Selection");
|
|
for (int i = 0; i < g_iWeaponIndex; i++)
|
|
{
|
|
ZmarketMenu.AddItem(g_cWeaponNames[i][g_iLength], g_cWeaponNames[i][g_iLength]);
|
|
}
|
|
ZmarketMenu.ExitButton = true;
|
|
ZmarketMenu.ExitBackButton = true;
|
|
ZmarketMenu.Display(client, 0);
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
static void Zclass(int client)
|
|
{
|
|
char l_cHuman[g_dLength];
|
|
char l_cZM[g_dLength];
|
|
int l_iZMIndex = g_iClientZMClasses[client];
|
|
int l_iHumanIndex = g_iClientHumanClasses[client];
|
|
Menu ZclassMenu = CreateMenu(Zclass_Menu);
|
|
|
|
//if you did not pick a zm skin it picks the first for you
|
|
if (strlen(g_cZMRoundClasses[l_iZMIndex][g_iLength]) < 1)
|
|
{
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (strlen(g_cZMRoundClasses[i][g_iLength]) < 1)
|
|
continue;
|
|
l_iZMIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//if you did not pick a human skin it picks the first for you
|
|
if (strlen(g_cHumanClasses[l_iHumanIndex][g_iLength]) < 1)
|
|
{
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (strlen(g_cHumanClasses[i][g_iLength]) < 1)
|
|
continue;
|
|
l_iHumanIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
Format(l_cZM, sizeof(l_cZM), "Active Zombie Class: %s", g_cZMRoundClasses[l_iZMIndex][g_iLength]);
|
|
Format(l_cHuman, sizeof(l_cHuman), "Active Human Class: %s", g_cHumanClasses[l_iHumanIndex][g_iLength]);
|
|
ZclassMenu.SetTitle("TeamClass Selection");
|
|
ZclassMenu.AddItem("", "Human Classes");
|
|
ZclassMenu.AddItem("", l_cHuman, ITEMDRAW_DISABLED);
|
|
ZclassMenu.AddItem("", "Zombie Classes");
|
|
ZclassMenu.AddItem("", l_cZM, ITEMDRAW_DISABLED);
|
|
ZclassMenu.ExitButton = true;
|
|
ZclassMenu.ExitBackButton = true;
|
|
ZclassMenu.Display(client, 0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public int Zmarket_menu(Menu menu, MenuAction action, int client, int selection)
|
|
{
|
|
if (action == MenuAction_Select && IsValidClient(client))
|
|
{
|
|
char info[64];
|
|
menu.GetItem(selection, info, sizeof(info));
|
|
|
|
int weapon_index = 0;
|
|
for (int i = 0; i < g_iWeaponIndex; i++)
|
|
{
|
|
if (StrEqual(g_cWeaponNames[i][g_iLength], info))
|
|
{
|
|
weapon_index = i;
|
|
break;
|
|
}
|
|
}
|
|
ZmarketGetWeapon(client, weapon_index);
|
|
}
|
|
else if (action == MenuAction_End)
|
|
{
|
|
delete(menu);
|
|
}
|
|
return 0;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public int Zclass_Menu(Menu menu, MenuAction action, int client, int selection)
|
|
{
|
|
if (action == MenuAction_Select && IsValidClient(client))
|
|
{
|
|
ZclassTeamMenu(client, selection);
|
|
}
|
|
else if (action == MenuAction_End)
|
|
{
|
|
delete(menu);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int GetClientHEGrenades(int client)
|
|
{
|
|
return GetEntProp(client, Prop_Data, "m_iAmmo", _, HEGrenadeOffset);
|
|
}
|
|
|
|
int GetClientSmokeGrenades(int client)
|
|
{
|
|
return GetEntProp(client, Prop_Data, "m_iAmmo", _, SmokegrenadeOffset);
|
|
}
|
|
|
|
int GetClientFlashbangs(int client)
|
|
{
|
|
return GetEntProp(client, Prop_Data, "m_iAmmo", _, FlashbangOffset);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose: //https://forums.alliedmods.net/showthread.php?t=305092
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void ZmarketGetWeapon(int client, int index)
|
|
{
|
|
if (!IsValidClient(client) || GetClientTeam(client) != CS_TEAM_CT || !IsPlayerAlive(client))
|
|
{
|
|
PrintToChat(client, "You have to be Human for obtaining weapons");
|
|
return;
|
|
}
|
|
int l_iClientCash = GetEntProp(client, Prop_Send, "m_iAccount");
|
|
int l_iEntity;
|
|
int l_iWeapon;
|
|
float l_fClientPos[3];
|
|
if (g_iWeaponPrice[index] <= l_iClientCash)
|
|
{
|
|
l_iEntity = CreateEntityByName(g_cWeaponEntity[index][g_iLength]);
|
|
if (l_iEntity == -1)
|
|
{
|
|
ReplyToCommand(client, "Error occured. cry to jenz");
|
|
return;
|
|
}
|
|
GetClientAbsOrigin(client, l_fClientPos);
|
|
l_iWeapon = GetPlayerWeaponSlot(client, g_iWeaponSlot[index]);
|
|
|
|
int has_hegrenade = GetClientHEGrenades(client);
|
|
int has_smoke = GetClientSmokeGrenades(client);
|
|
int has_flashbang = GetClientFlashbangs(client);
|
|
if (StrEqual(g_cWeaponNames[index][g_iLength], "HEGrenade",false) && has_hegrenade)
|
|
{
|
|
return;
|
|
}
|
|
if (StrEqual(g_cWeaponNames[index][g_iLength], "Smokegrenade",false) && has_smoke)
|
|
{
|
|
return;
|
|
}
|
|
if (StrEqual(g_cWeaponNames[index][g_iLength], "Flashbang",false) && has_flashbang)
|
|
{
|
|
return;
|
|
}
|
|
if (IsValidEntity(l_iWeapon))
|
|
{
|
|
if (GetEntPropEnt(l_iWeapon, Prop_Send, "m_hOwnerEntity") != client)
|
|
{
|
|
SetEntPropEnt(l_iWeapon, Prop_Send, "m_hOwnerEntity", client);
|
|
}
|
|
if (g_iWeaponSlot[index] != 3)
|
|
{
|
|
CS_DropWeapon(client, l_iWeapon, false, true);
|
|
AcceptEntityInput(l_iWeapon, "Kill");
|
|
}
|
|
}
|
|
TeleportEntity(l_iEntity, l_fClientPos, NULL_VECTOR, NULL_VECTOR);
|
|
DispatchKeyValueInt(l_iEntity, "ammo", 4500);
|
|
DispatchSpawn(l_iEntity);
|
|
SetEntProp(client, Prop_Send, "m_iAccount", l_iClientCash - g_iWeaponPrice[index]);
|
|
PrintToChat(client, "you purchased: %s", g_cWeaponNames[index][g_iLength]);
|
|
}
|
|
else
|
|
{
|
|
PrintToChat(client, "Not enough money, requires: %i", g_iWeaponPrice[index]);
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
static void ZclassTeamMenu(int client, int state)
|
|
{
|
|
//0 human, 2 zm
|
|
Menu zclassMenu;
|
|
AdminId l_AdminID = GetUserAdmin(client);
|
|
int l_iAdminGroupCount = GetAdminGroupCount(l_AdminID);
|
|
int l_iFound;
|
|
int l_iFlags;
|
|
if (state == 2)
|
|
{
|
|
zclassMenu = CreateMenu(Zombieclass_Menu);
|
|
zclassMenu.SetTitle("Playerclass Zombie Selection");
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (strlen(g_cZMRoundClasses[i][g_iLength]) < 1)
|
|
continue;
|
|
|
|
if (strlen(g_cGroup[i][g_iLength]) < 1 && strlen(g_cSMFLAGS[i][g_iLength]) < 1)
|
|
{
|
|
zclassMenu.AddItem(g_cZMRoundClasses[i][g_iLength], g_cZMRoundClasses[i][g_iLength]);
|
|
l_iFound++;
|
|
}
|
|
else
|
|
{
|
|
l_iFound = 0;
|
|
if (strlen(g_cGroup[i][g_iLength]) > 0)
|
|
{
|
|
for (int j = 0; j < l_iAdminGroupCount; j++)
|
|
{
|
|
if (StrEqual(g_cGroup[i][g_iLength], g_cAdminGroups[client][j][g_iLength]))
|
|
{
|
|
zclassMenu.AddItem(g_cZMRoundClasses[i][g_iLength], g_cZMRoundClasses[i][g_iLength]);
|
|
l_iFound++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
l_iFlags = ReadFlagString(g_cSMFLAGS[i][g_iLength]);
|
|
if (GetUserFlagBits(client) & l_iFlags && l_iFound < 1 && strlen(g_cSMFLAGS[i][g_iLength]) > 0)
|
|
{
|
|
zclassMenu.AddItem(g_cZMRoundClasses[i][g_iLength], g_cZMRoundClasses[i][g_iLength]);
|
|
l_iFound++;
|
|
}
|
|
if (l_iFound == 0)
|
|
{
|
|
zclassMenu.AddItem(g_cZMRoundClasses[i][g_iLength], g_cZMRoundClasses[i][g_iLength], ITEMDRAW_DISABLED);
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
zclassMenu = CreateMenu(Humanclass_Menu);
|
|
zclassMenu.SetTitle("Active Playerclass Human Selection");
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (strlen(g_cHumanClasses[i][g_iLength]) < 1)
|
|
continue;
|
|
|
|
if (strlen(g_cGroup[i][g_iLength]) < 1 && strlen(g_cSMFLAGS[i][g_iLength]) < 1)
|
|
{
|
|
zclassMenu.AddItem(g_cHumanClasses[i][g_iLength], g_cHumanClasses[i][g_iLength]);
|
|
l_iFound++;
|
|
}
|
|
else
|
|
{
|
|
l_iFound = 0;
|
|
if (strlen(g_cGroup[i][g_iLength]) > 0)
|
|
{
|
|
for (int j = 0; j < l_iAdminGroupCount; j++)
|
|
{
|
|
if (StrEqual(g_cGroup[i][g_iLength], g_cAdminGroups[client][j][g_iLength]))
|
|
{
|
|
zclassMenu.AddItem(g_cHumanClasses[i][g_iLength], g_cHumanClasses[i][g_iLength]);
|
|
l_iFound++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
l_iFlags = ReadFlagString(g_cSMFLAGS[i][g_iLength]);
|
|
if (GetUserFlagBits(client) & l_iFlags && l_iFound < 1 && strlen(g_cSMFLAGS[i][g_iLength]) > 0)
|
|
{
|
|
zclassMenu.AddItem(g_cHumanClasses[i][g_iLength], g_cHumanClasses[i][g_iLength]);
|
|
l_iFound++;
|
|
}
|
|
if (l_iFound == 0)
|
|
{
|
|
zclassMenu.AddItem(g_cHumanClasses[i][g_iLength], g_cHumanClasses[i][g_iLength], ITEMDRAW_DISABLED);
|
|
}
|
|
}
|
|
}
|
|
zclassMenu.ExitButton = true;
|
|
zclassMenu.ExitBackButton = true;
|
|
zclassMenu.Display(client, 0);
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public int Zombieclass_Menu(Menu menu, MenuAction action, int client, int selection)
|
|
{
|
|
if (action == MenuAction_Select && IsValidClient(client))
|
|
{
|
|
char info[64];
|
|
menu.GetItem(selection, info, sizeof(info));
|
|
//going through all zm classes by name until finding the one that matches the menu selection.
|
|
for (int i = g_iZMBeginindex; i < g_iLoadClassesIndex; i++)
|
|
{
|
|
if (StrEqual(g_cZMRoundClasses[i][g_iLength], info))
|
|
{
|
|
g_iClientZMClasses[client] = i; //we found the zm class selected in the menu
|
|
break;
|
|
}
|
|
}
|
|
char l_cInfo[4];
|
|
IntToString(g_iClientZMClasses[client], l_cInfo, sizeof(l_cInfo));
|
|
SetClientCookie(client, g_hClientZMCookie, l_cInfo);
|
|
|
|
if (g_bSwitchingIndex && GetClientTeam(client) == CS_TEAM_T && IsPlayerAlive(client)) //beginning of round, is correct team and alive
|
|
{
|
|
SelectWaveBasedZM(client, 1);
|
|
}
|
|
}
|
|
else if (action == MenuAction_End)
|
|
{
|
|
delete(menu);
|
|
}
|
|
return 0;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public int Humanclass_Menu(Menu menu, MenuAction action, int client, int selection)
|
|
{
|
|
if (action == MenuAction_Select && IsValidClient(client))
|
|
{
|
|
char info[64];
|
|
menu.GetItem(selection, info, sizeof(info));
|
|
//going through all human classes by name until finding the one that matches the menu selection.
|
|
for (int i = 0; i < g_iZMBeginindex; i++)
|
|
{
|
|
if (StrEqual(g_cHumanClasses[i][g_iLength], info))
|
|
{
|
|
g_iClientHumanClasses[client] = i; //we found the human class selected in the menu
|
|
break;
|
|
}
|
|
}
|
|
|
|
char l_cInfo[4];
|
|
IntToString(g_iClientHumanClasses[client], l_cInfo, sizeof(l_cInfo));
|
|
SetClientCookie(client, g_hClientHumanCookie, l_cInfo);
|
|
|
|
if (g_bSwitchingIndex && GetClientTeam(client) == CS_TEAM_CT && IsPlayerAlive(client)) //beginning of round, is correct team and alive
|
|
{
|
|
SelectWavebasedHuman(client);
|
|
}
|
|
}
|
|
else if (action == MenuAction_End)
|
|
{
|
|
delete(menu);
|
|
}
|
|
return 0;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action AddDownloadContent()
|
|
{
|
|
Handle l_hFile = INVALID_HANDLE;
|
|
char l_cLine[g_dLength];
|
|
l_hFile = OpenFile(g_cPathsDownload, "r");
|
|
if (l_hFile == INVALID_HANDLE)
|
|
{
|
|
Handle l_kv = CreateKeyValues("DownloadTable");
|
|
KeyValuesToFile(l_kv, g_cPathsDownload);
|
|
CloseHandle(l_kv);
|
|
delete l_hFile;
|
|
return Plugin_Handled;
|
|
}
|
|
while (!IsEndOfFile(l_hFile) && ReadFileLine(l_hFile, l_cLine, sizeof(l_cLine)))
|
|
{
|
|
TrimString(l_cLine);
|
|
if (strlen(l_cLine) > 0 && StrContains(l_cLine, "//") == -1 && StrContains(l_cLine, "\"") == -1 && StrContains(l_cLine, "{") == -1 &&
|
|
StrContains(l_cLine, "}") == -1)
|
|
{
|
|
AddFileToDownloadsTable(l_cLine);
|
|
}
|
|
}
|
|
delete l_hFile;
|
|
return Plugin_Handled;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void LoadExtraSettings()
|
|
{
|
|
g_iSoundIndexes = 0; //forgot to reset, would run out bounds as well.
|
|
|
|
|
|
Handle l_hFile = INVALID_HANDLE;
|
|
char l_cLine[g_dLength];
|
|
if (!FileExists(g_cPathsExtra))
|
|
{
|
|
delete l_hFile;
|
|
LogError("create a extrasettings.txt file!");
|
|
return;
|
|
}
|
|
l_hFile = OpenFile(g_cPathsExtra, "r");
|
|
while (!IsEndOfFile(l_hFile) && ReadFileLine(l_hFile, l_cLine, sizeof(l_cLine)))
|
|
{
|
|
if (StrContains(l_cLine, "Respawn Time") > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "Respawn Time");
|
|
if (StringToFloat(l_cLine) > 0.0)
|
|
g_fRespawnTimer = StringToFloat(l_cLine);
|
|
else
|
|
g_fRespawnTimer = 5.0;
|
|
}
|
|
if (StrContains(l_cLine, "Global command") > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "Global command");
|
|
if (strlen(l_cLine) > 1)
|
|
ServerCommand(l_cLine);
|
|
}
|
|
if (StrContains(l_cLine, "round start zclass time") > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "round start zclass time");
|
|
if (StringToFloat(l_cLine) > 0.0)
|
|
g_fSwitchingTimer = StringToFloat(l_cLine);
|
|
else
|
|
g_fSwitchingTimer = 15.0;
|
|
}
|
|
if (StrContains(l_cLine, "zm spawn protection") > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "zm spawn protection");
|
|
if (StringToFloat(l_cLine) > 0.0)
|
|
g_fZMSpawnProtection = StringToFloat(l_cLine);
|
|
else
|
|
g_fZMSpawnProtection = 1.0;
|
|
}
|
|
if (StrContains(l_cLine, "human spawn protection") > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "human spawn protection");
|
|
if (StringToFloat(l_cLine) > 0.0)
|
|
g_fHumanSpawnProtection = StringToFloat(l_cLine);
|
|
else
|
|
g_fHumanSpawnProtection = 4.0;
|
|
}
|
|
if (StrContains(l_cLine, "zmsoundInterval") > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "zmsoundInterval");
|
|
if (StringToFloat(l_cLine) > 0.0)
|
|
g_fZMSounds = StringToFloat(l_cLine);
|
|
else
|
|
g_fZMSounds = 15.0;
|
|
}
|
|
if (StrContains(l_cLine, "botStuckCount") > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "botStuckCount");
|
|
if (StringToInt(l_cLine) > 1)
|
|
g_iBotStuckCounts = StringToInt(l_cLine);
|
|
else
|
|
g_iBotStuckCounts = 3;
|
|
}
|
|
if (StrContains(l_cLine, "botStuckPush") > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "botStuckPush");
|
|
if (StringToInt(l_cLine) > 1)
|
|
g_fBotStuckPush = StringToFloat(l_cLine);
|
|
else
|
|
g_fBotStuckPush = 250.0;
|
|
}
|
|
if (StrContains(l_cLine, "zmsoundsFile") > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "zmsoundsFile");
|
|
ReplaceString(l_cLine, sizeof(l_cLine), "sound/", "*/");
|
|
Format(g_cZMSounds[g_iSoundIndexes][g_iLength], sizeof(g_cZMSounds), l_cLine);
|
|
PrecacheSound(g_cZMSounds[g_iSoundIndexes][g_iLength]);
|
|
g_iSoundIndexes++;
|
|
}
|
|
if (StrContains(l_cLine, "ambientSound", false) > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "ambientSound");
|
|
ExplodeString(l_cLine, ",", g_cAmbientSOund, 64, 512);
|
|
}
|
|
if (StrContains(l_cLine, "ambientLoopDuration") > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "ambientLoopDuration");
|
|
if (StringToInt(l_cLine) > 1)
|
|
g_fAmbientSoundLoopDuration = StringToFloat(l_cLine);
|
|
else
|
|
g_fAmbientSoundLoopDuration = 10.0;
|
|
}
|
|
if (StrContains(l_cLine, "bossSound", false) > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "bossSound");
|
|
Format(g_cBossSound, sizeof(g_cBossSound), l_cLine);
|
|
}
|
|
|
|
if (StrContains(l_cLine, "bossLoopDuration") > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "bossLoopDuration");
|
|
if (StringToInt(l_cLine) > 1)
|
|
g_fBossSoundLoopDuration = StringToFloat(l_cLine);
|
|
else
|
|
g_fBossSoundLoopDuration = 10.0;
|
|
}
|
|
}
|
|
delete l_hFile;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void loadWeapons()
|
|
{
|
|
KeyValues kv = CreateKeyValues("Weapons");
|
|
if (!FileExists(g_cPathsWeapons))
|
|
{
|
|
delete kv;
|
|
LogError("create kv file");
|
|
return;
|
|
}
|
|
g_iWeaponIndex = 0; //ofc this has to be reset, otherwise it ends up going out of bounds dx
|
|
kv.ImportFromFile(g_cPathsWeapons);
|
|
kv.GotoFirstSubKey();
|
|
kv.GetString("weaponentity", g_cWeaponEntity[g_iWeaponIndex][g_iLength], sizeof(g_cWeaponEntity));
|
|
kv.GetString("zmarketname", g_cWeaponNames[g_iWeaponIndex][g_iLength], sizeof(g_cWeaponNames));
|
|
g_iWeaponSlot[g_iWeaponIndex] = kv.GetNum("weaponslot");
|
|
g_iWeaponPrice[g_iWeaponIndex] = kv.GetNum("zmarketprice");
|
|
kv.GetString("zmarketcommand", g_cWeaponCommand[g_iWeaponIndex][g_iLength], sizeof(g_cWeaponCommand));
|
|
g_iWeaponIndex++;
|
|
while (kv.GotoNextKey())
|
|
{
|
|
kv.GetString("weaponentity", g_cWeaponEntity[g_iWeaponIndex][g_iLength], sizeof(g_cWeaponEntity));
|
|
kv.GetString("zmarketname", g_cWeaponNames[g_iWeaponIndex][g_iLength], sizeof(g_cWeaponNames));
|
|
g_iWeaponSlot[g_iWeaponIndex] = kv.GetNum("weaponslot");
|
|
g_iWeaponPrice[g_iWeaponIndex] = kv.GetNum("zmarketprice");
|
|
kv.GetString("zmarketcommand", g_cWeaponCommand[g_iWeaponIndex][g_iLength], sizeof(g_cWeaponCommand));
|
|
g_iWeaponIndex++;
|
|
}
|
|
delete kv;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action LoadClasses()
|
|
{
|
|
Handle l_hFile = INVALID_HANDLE;
|
|
Handle l_hFileZM = INVALID_HANDLE;
|
|
char l_cLine[g_dLength];
|
|
g_iLoadClassesIndex = 0;
|
|
l_hFile = OpenFile(g_cPathsClassHuman, "r");
|
|
l_hFileZM = OpenFile(g_cPathsClassZM, "r");
|
|
if (!FileExists(g_cPathsClassHuman) || !FileExists(g_cPathsClassZM))
|
|
{
|
|
delete l_hFile;
|
|
delete l_hFileZM;
|
|
LogError("You need to create the classeshuman.txt and the classeszm.txt");
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
//first indexes go to human classes, all afterfollowing to zms
|
|
while (!IsEndOfFile(l_hFile) && ReadFileLine(l_hFile, l_cLine, sizeof(l_cLine)))
|
|
{
|
|
ReadingClassValuesFromFile(g_iLoadClassesIndex, l_cLine);
|
|
}
|
|
//after going through humans are all remaining indexes for zombies.
|
|
g_iZMBeginindex = g_iLoadClassesIndex;
|
|
while (!IsEndOfFile(l_hFileZM) && ReadFileLine(l_hFileZM, l_cLine, sizeof(l_cLine)))
|
|
{
|
|
ReadingClassValuesFromFile(g_iLoadClassesIndex, l_cLine);
|
|
}
|
|
delete l_hFileZM;
|
|
delete l_hFile;
|
|
return Plugin_Handled;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void OnMapStart()
|
|
{
|
|
g_iToolsVelocity = FindDataMapInfo(0, "m_vecAbsVelocity");
|
|
g_iWave = 1;
|
|
//load content
|
|
AddDownloadContent();
|
|
LoadClasses();
|
|
LoadExtraSettings();
|
|
loadWeapons();
|
|
loadDays();
|
|
}
|
|
|
|
//just checking the knife when they spawn is appereantly not good enough. this is just repeating what Timer_StopProtection does.
|
|
public Action Timer_FixKNife(Handle timer, any userid)
|
|
{
|
|
for (int client = 0; client < MaxClients; client++)
|
|
{
|
|
if (IsValidClient(client) && IsPlayerAlive(client))
|
|
{
|
|
//the fucking forwards wont give the bots the client tags. it should obviously work. cause it works on ze.
|
|
//too bad!
|
|
if (IsFakeClient(client))
|
|
{
|
|
char tag[64];
|
|
Format(tag, sizeof(tag), "UNLOZE ");
|
|
CS_SetClientClanTag(client, tag);
|
|
}
|
|
|
|
if (GetClientTeam(client) == CS_TEAM_T)
|
|
{
|
|
if (GetPlayerWeaponSlot(client, CS_SLOT_KNIFE) == -1) //just making sure everybody has a knife. otherwise giving them one
|
|
{
|
|
GivePlayerItem(client, "weapon_knife");
|
|
CreateTimer(1.0, Timer_SwitchKnife, GetClientOfUserId(client));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void OnClientPostAdminCheck(int client)
|
|
{
|
|
g_iSpeedDelayClient[client] = 0;
|
|
g_bClientProtection[client] = false;
|
|
g_bFallDamage[client] = false;
|
|
g_fKnockBackIndex[client] = 1.0;
|
|
g_fJumpHeightIndex[client] = 1.0;
|
|
g_fJumpDistanceIndex[client] = 1.0;
|
|
g_fDamageMultiplier[client] = 1.0;
|
|
g_bClientIsBoss[client] = false;
|
|
g_iClientRespawnCount[client] = g_iClientRespawnCountNum;
|
|
char sCookieValue[12];
|
|
GetClientCookie(client, g_hClientZMCookie, sCookieValue, sizeof(sCookieValue));
|
|
if (sCookieValue[0])
|
|
{
|
|
g_iClientZMClasses[client] = StringToInt(sCookieValue);
|
|
}
|
|
else
|
|
{
|
|
g_iClientZMClasses[client] = g_iZMBeginindex;
|
|
}
|
|
GetClientCookie(client, g_hClientHumanCookie, sCookieValue, sizeof(sCookieValue));
|
|
if (sCookieValue[0])
|
|
{
|
|
g_iClientHumanClasses[client] = StringToInt(sCookieValue);
|
|
}
|
|
else
|
|
{
|
|
g_iClientHumanClasses[client] = 0;
|
|
}
|
|
SetAdminGroups(client);
|
|
}
|
|
|
|
public void OnClientPutInServer(int client)
|
|
{
|
|
SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);
|
|
SDKHook(client, SDKHook_WeaponEquip, OnWeaponEquip);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void SetAdminGroups(int client)
|
|
{
|
|
AdminId l_AdminID = GetUserAdmin(client);
|
|
int l_iAdminGroupCount = GetAdminGroupCount(l_AdminID);
|
|
char l_cbuffer[g_dLength];
|
|
for (int j = 0; j < l_iAdminGroupCount; j++)
|
|
{
|
|
GetAdminGroup(l_AdminID, j, l_cbuffer, sizeof(l_cbuffer));
|
|
Format(g_cAdminGroups[client][j][g_iLength], sizeof(g_cAdminGroups), l_cbuffer);
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void OnClientDisconnect(int client)
|
|
{
|
|
g_iSpeedDelayClient[client] = 0;
|
|
g_bClientProtection[client] = false;
|
|
g_bFallDamage[client] = false;
|
|
g_fKnockBackIndex[client] = 1.0;
|
|
g_fJumpHeightIndex[client] = 1.0;
|
|
g_fJumpDistanceIndex[client] = 1.0;
|
|
g_fDamageMultiplier[client] = 1.0;
|
|
g_iClientRespawnCount[client] = 0;
|
|
g_bClientIsBoss[client] = false;
|
|
SDKUnhook(client, SDKHook_OnTakeDamage, OnTakeDamage);
|
|
SDKUnhook(client, SDKHook_WeaponEquip, OnWeaponEquip);
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void Event_roundStart(Handle event, const char[] name, bool dontBroadcast)
|
|
{
|
|
g_iHumanCount = 999;
|
|
g_iZombieCount = 999;
|
|
g_bRoundInProgress = false;
|
|
g_bSwitchingIndex = true;
|
|
g_iBossBotCount = 0;
|
|
CreateTimer(g_fSwitchingTimer, Timer_switchingModel, INVALID_HANDLE);
|
|
|
|
if (g_hAmbient != null)
|
|
delete g_hAmbient;
|
|
if (StrContains(g_cDaysTitles[g_iWave - 1], "BOSS", false) != -1) //the daystitle contains the word boss in it
|
|
{
|
|
g_bIsBossRound = true; //boss rounds need BOSS in the title
|
|
EmitAmbience(g_cBossSound); //nobody will ever understand why megalovania was on the servers since 2020.
|
|
g_hAmbient = CreateTimer(g_fBossSoundLoopDuration, Timer_Ambient, INVALID_HANDLE, TIMER_REPEAT); // 0.3 seconds without sound
|
|
}
|
|
else
|
|
{
|
|
g_bIsBossRound = false; //boss rounds need BOSS in the title
|
|
int index = ambient_index();
|
|
EmitAmbience(g_cAmbientSOund[index]);
|
|
g_hAmbient = CreateTimer(g_fAmbientSoundLoopDuration, Timer_Ambient, INVALID_HANDLE, TIMER_REPEAT); // 0.3 seconds without sound
|
|
}
|
|
RetrieveWaveSettings(g_iWave);
|
|
|
|
for (int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if (IsValidClient(i) && !IsClientSourceTV(i))
|
|
{
|
|
if (IsFakeClient(i))
|
|
{
|
|
g_bClientIsBoss[i] = false;
|
|
CreateTimer(0.3, Timer_delayedSelectWaveBasedZM, GetClientUserId(i));
|
|
continue;
|
|
}
|
|
g_iClientRespawnCount[i] = g_iClientRespawnCountNum; //even if not spawned in yet it should be set for every real player.
|
|
if (IsPlayerAlive(i))
|
|
{
|
|
SelectWavebasedHuman(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public int ambient_index()
|
|
{
|
|
int index = 0;
|
|
for (int i = 0; i < sizeof(g_cAmbientSOund); i++)
|
|
{
|
|
if (strlen(g_cAmbientSOund[i]) == 0)
|
|
{
|
|
index = (g_iWave - 1) % i;
|
|
break;
|
|
}
|
|
}
|
|
return index;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action RetrieveWaveSettings(int wave)
|
|
{
|
|
int total_days = 23;
|
|
for (int i = 0; i < sizeof(g_cDaysTitles); i++)
|
|
{
|
|
if (strlen(g_cDaysTitles[i]) == 0)
|
|
{
|
|
total_days = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
char hostname[512];
|
|
Format(hostname, sizeof(hostname), "UNLOZE | [ZRiot: Day %i/%i] %s | Ranking", wave, total_days, g_cDaysTitles[wave - 1]);
|
|
ServerCommand("hostname \"%s\"", hostname);
|
|
PrintToChatAll("Day %i: %s", wave, g_cDaysTitles[wave - 1]);
|
|
LoadWave(wave);
|
|
return Plugin_Handled;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Timer_switchingModel(Handle timer, any data)
|
|
{
|
|
g_bSwitchingIndex = false;
|
|
return Plugin_Handled;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void LoadWave(int wave)
|
|
{
|
|
KeyValues kv = CreateKeyValues("Waves");
|
|
KeyValues kv1 = CreateKeyValues("Waves");
|
|
int l_iBotQuote;
|
|
char l_cJumptokey[16];
|
|
char l_cJumptokey1[16];
|
|
char l_cLine[g_dLength];
|
|
bool l_bKeyIndex = false;
|
|
Handle l_hFile = INVALID_HANDLE;
|
|
if (select_map_specific_waves())
|
|
{
|
|
char mapname[512];
|
|
GetCurrentMap(mapname, sizeof(mapname));
|
|
Format(mapname, sizeof(mapname), "configs/unloze_zr/mapwaves/%s.txt", mapname);
|
|
BuildPath(Path_SM, mapname, sizeof(mapname), mapname);
|
|
l_hFile = OpenFile(mapname, "r");
|
|
kv.ImportFromFile(mapname);
|
|
kv1.ImportFromFile(mapname);
|
|
}
|
|
else
|
|
{
|
|
l_hFile = OpenFile(g_cPathsWaveSettings, "r");
|
|
kv.ImportFromFile(g_cPathsWaveSettings);
|
|
kv1.ImportFromFile(g_cPathsWaveSettings);
|
|
}
|
|
Format(l_cJumptokey, sizeof(l_cJumptokey), "Wave %i", wave);
|
|
Format(l_cJumptokey1, sizeof(l_cJumptokey1), "Wave %i", wave +1);
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
//resetting human and zombie classes each round/wave.
|
|
Format(g_cHumanClasses[i][g_iLength], sizeof(g_cHumanClasses), "");
|
|
Format(g_cZMRoundClasses[i][g_iLength], sizeof(g_cZMRoundClasses), "");
|
|
}
|
|
if (!kv1.JumpToKey(l_cJumptokey1, false))
|
|
{
|
|
//next wave does not exist, so we reached end wave right now.
|
|
//according to the random guy from italy who made his identity smoking weed we force mapvotes on last day and then forcertv when restarting
|
|
//from day 1
|
|
PrintToChatAll("Reached last day. Initiating the mapvote!");
|
|
ServerCommand("sm_mapvote"); //old zombieRiot did this so just copying it
|
|
}
|
|
if (kv.JumpToKey(l_cJumptokey, false))
|
|
{
|
|
g_bRoundInProgress = true;
|
|
g_iZMScaleability = kv.GetFloat("PlayerScaleAbility", 5.0);
|
|
g_fZMHealthScaleability = kv.GetFloat("HealthScaleAbility", 1.0);
|
|
g_iZMCount = kv.GetNum("Zombie Count", 5);
|
|
|
|
int additional_zombie_per_player = RoundFloat(g_iZMCount * g_iZMScaleability);
|
|
|
|
int l_iPlayers;
|
|
for (int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if (IsValidClient(i) && !IsFakeClient(i) && CS_TEAM_CT == GetClientTeam(i))
|
|
{
|
|
l_iPlayers++;
|
|
}
|
|
}
|
|
|
|
l_iPlayers -= 1; //first player equals the zombie count.
|
|
//first player takes the zombie count, each additional player adds to additional_zombie_per_player
|
|
//if 1 player then additional_zombie_per_player * 0. so just g_iZMCount
|
|
g_iZMCount += additional_zombie_per_player * l_iPlayers;
|
|
|
|
g_iClientRespawnCountNum = kv.GetNum("Respawns", 5);
|
|
l_iBotQuote = kv.GetNum("bot_scaling", 1);
|
|
int l_iBotQuoteStatic = kv.GetNum("bot_static", 1);
|
|
|
|
l_iPlayers = 0; //counting legit players for bot scaling.
|
|
for (int i = 1; i < MaxClients; i++)
|
|
{
|
|
if (IsValidClient(i) && !IsFakeClient(i) && CS_TEAM_CT == GetClientTeam(i))
|
|
{
|
|
l_iPlayers++;
|
|
}
|
|
}
|
|
|
|
if (g_bIsBossRound)
|
|
{
|
|
//its boss round. bot_scaling is used for minion bots. bot_static is used for boss bot amount
|
|
// bot_static + bot_scaling
|
|
addBots(l_iBotQuoteStatic + (l_iPlayers * l_iBotQuote));
|
|
g_iBossBotCount = l_iBotQuoteStatic;
|
|
}
|
|
else
|
|
{
|
|
//its not boss round.
|
|
if (l_iBotQuote == 0) //we use static bot amount instead of scaling bots based on playercount.
|
|
{
|
|
addBots(l_iBotQuoteStatic);
|
|
}
|
|
else
|
|
{
|
|
//we use bot_scaling.
|
|
addBots(l_iPlayers * l_iBotQuote);
|
|
}
|
|
}
|
|
while (!IsEndOfFile(l_hFile) && ReadFileLine(l_hFile, l_cLine, sizeof(l_cLine)))
|
|
{
|
|
if (StrContains(l_cLine, l_cJumptokey) == -1 && !l_bKeyIndex)
|
|
{
|
|
continue;
|
|
}
|
|
l_bKeyIndex = true;
|
|
if (StrContains(l_cLine, "wavecommand") > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "wavecommand");
|
|
if (strlen(l_cLine) > 0)
|
|
ServerCommand(l_cLine);
|
|
}
|
|
else if (StrContains(l_cLine, "Zombie Class") > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "Zombie Class");
|
|
if (StrContains(l_cLine, "@all") > -1)
|
|
{
|
|
//in this case it just goes through all zombie classes
|
|
for (int i = g_iZMBeginindex; i < g_iLoadClassesIndex; i++)
|
|
{
|
|
Format(g_cZMRoundClasses[i][g_iLength], sizeof(g_cZMRoundClasses), g_cUniqueName[i][g_iLength]);
|
|
}
|
|
}
|
|
else if (StrContains(l_cLine, "@groups") > -1)
|
|
{
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (skipIndex(i))
|
|
{
|
|
continue;
|
|
}
|
|
if ((strlen(g_cGroup[i][g_iLength]) > 0) && StrEqual(g_cTeam[i][g_iLength], "ZM"))
|
|
{
|
|
Format(g_cZMRoundClasses[i][g_iLength], sizeof(g_cZMRoundClasses), g_cUniqueName[i][g_iLength]);
|
|
}
|
|
}
|
|
}
|
|
else if (StrContains(l_cLine, "@flags") > -1)
|
|
{
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (skipIndex(i))
|
|
{
|
|
continue;
|
|
}
|
|
if (strlen(g_cSMFLAGS[i][g_iLength]) > 0 && StrEqual(g_cTeam[i][g_iLength], "ZM"))
|
|
{
|
|
Format(g_cZMRoundClasses[i][g_iLength], sizeof(g_cZMRoundClasses), g_cUniqueName[i][g_iLength]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (skipIndex(i))
|
|
{
|
|
continue;
|
|
}
|
|
if (StrEqual(l_cLine, g_cUniqueName[i][g_iLength], false))
|
|
{
|
|
Format(g_cZMRoundClasses[i][g_iLength], sizeof(g_cZMRoundClasses), g_cUniqueName[i][g_iLength]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (StrContains(l_cLine, "Human Class") > -1)
|
|
{
|
|
ReplaceStrings(l_cLine, "Human Class");
|
|
if (StrContains(l_cLine, "@all") > -1)
|
|
{
|
|
for (int i = 0; i < g_iZMBeginindex; i++)
|
|
{
|
|
Format(g_cHumanClasses[i][g_iLength], sizeof(g_cHumanClasses), g_cUniqueName[i][g_iLength]);
|
|
}
|
|
}
|
|
else if (StrContains(l_cLine, "@groups") > -1)
|
|
{
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (skipIndex(i))
|
|
{
|
|
continue;
|
|
}
|
|
if (strlen(g_cGroup[i][g_iLength]) > 0 && StrEqual(g_cTeam[i][g_iLength], "Human"))
|
|
{
|
|
Format(g_cHumanClasses[i][g_iLength], sizeof(g_cHumanClasses), g_cUniqueName[i][g_iLength]);
|
|
}
|
|
}
|
|
}
|
|
else if (StrContains(l_cLine, "@flags") > -1)
|
|
{
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (skipIndex(i))
|
|
{
|
|
continue;
|
|
}
|
|
if (strlen(g_cSMFLAGS[i][g_iLength]) > 0 && StrEqual(g_cTeam[i][g_iLength], "Human"))
|
|
{
|
|
Format(g_cHumanClasses[i][g_iLength], sizeof(g_cHumanClasses), g_cUniqueName[i][g_iLength]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (skipIndex(i))
|
|
{
|
|
continue;
|
|
}
|
|
if (StrEqual(l_cLine, g_cUniqueName[i][g_iLength], false))
|
|
{
|
|
Format(g_cHumanClasses[i][g_iLength], sizeof(g_cHumanClasses), g_cUniqueName[i][g_iLength]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (StrContains(l_cLine, l_cJumptokey1) > -1)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_iWave = 1;
|
|
PrintToChatAll("Finished last Day! Forcing map change...");
|
|
ServerCommand("sm_forcertv"); //old zombieRiot did this so just copying it
|
|
CS_TerminateRound(4.0, CSRoundEnd_CTWin, true); //without this it wont change map i guess? or at least without it they get a wave without settings set.
|
|
}
|
|
delete kv;
|
|
delete kv1;
|
|
delete l_hFile;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void addBots(int botcount)
|
|
{
|
|
if (botcount > 44)
|
|
{
|
|
botcount = 44;
|
|
}
|
|
ServerCommand("bot_quota %i", botcount);
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public bool skipIndex(int index)
|
|
{
|
|
if (strlen(g_cTeam[index][g_iLength]) < 1 || strlen(g_cUniqueName[index][g_iLength]) < 1)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void ReadingClassValuesFromFile(int index, char[] Line)
|
|
{
|
|
char li_c[g_dLength];
|
|
Format(li_c, sizeof(li_c), Line);
|
|
if (StrContains(Line, "unique name") > -1)
|
|
{
|
|
ReplaceStrings(li_c, "unique name");
|
|
Format(g_cUniqueName[index][g_iLength], sizeof(g_cUniqueName), li_c);
|
|
}
|
|
else if (StrContains(Line, "team") > -1)
|
|
{
|
|
ReplaceStrings(li_c, "team");
|
|
Format(g_cTeam[index][g_iLength], sizeof(g_cTeam), li_c);
|
|
}
|
|
else if (StrContains(Line, "group") > -1)
|
|
{
|
|
ReplaceStrings(li_c, "group");
|
|
Format(g_cGroup[index][g_iLength], sizeof(g_cGroup), li_c);
|
|
}
|
|
else if (StrContains(Line, "sm_flags") > -1)
|
|
{
|
|
ReplaceStrings(li_c, "sm_flags");
|
|
Format(g_cSMFLAGS[index][g_iLength], sizeof(g_cSMFLAGS), li_c);
|
|
}
|
|
else if (StrContains(Line, "model path") > -1)
|
|
{
|
|
ReplaceStrings(li_c, "model path");
|
|
Format(g_cModelPath[index][g_iLength], sizeof(g_cModelPath), li_c);
|
|
PrecacheModel(li_c);
|
|
}
|
|
else if (StrContains(Line, "no_fall_damage") > -1)
|
|
{
|
|
ReplaceStrings(li_c, "no_fall_damage");
|
|
Format(g_cNoFallDmg[index][g_iLength], sizeof(g_cNoFallDmg), li_c);
|
|
}
|
|
else if (StrContains(Line, "health") > -1)
|
|
{
|
|
ReplaceStrings(li_c, "health");
|
|
Format(g_cHealth[index][g_iLength], sizeof(g_cHealth), li_c);
|
|
}
|
|
else if (StrContains(Line, "speed") > -1)
|
|
{
|
|
ReplaceStrings(li_c, "speed");
|
|
Format(g_cSpeed[index][g_iLength], sizeof(g_cSpeed), li_c);
|
|
}
|
|
else if (StrContains(Line, "knockback") > -1)
|
|
{
|
|
ReplaceStrings(li_c, "knockback");
|
|
Format(g_cKnockback[index][g_iLength], sizeof(g_cKnockback), li_c);
|
|
}
|
|
else if (StrContains(Line, "jump_height") > -1)
|
|
{
|
|
ReplaceStrings(li_c, "jump_height");
|
|
Format(g_cJumpHeight[index][g_iLength], sizeof(g_cJumpHeight), li_c);
|
|
}
|
|
else if (StrContains(Line, "jump_distance") > -1)
|
|
{
|
|
ReplaceStrings(li_c, "jump_distance");
|
|
Format(g_cJumpDistance[index][g_iLength], sizeof(g_cJumpDistance), li_c);
|
|
}
|
|
else if (StrContains(Line, "damage_multiplier") > -1)
|
|
{
|
|
ReplaceStrings(li_c, "damage_multiplier");
|
|
Format(g_cDamageMultiplier[index][g_iLength], sizeof(g_cDamageMultiplier), li_c);
|
|
}
|
|
else if (StrContains(Line, "boss_class") > -1)
|
|
{
|
|
ReplaceStrings(li_c, "boss_class");
|
|
g_iZombieBossIndex[index] = StringToInt(li_c);
|
|
g_iLoadClassesIndex++; //use this at the last keyvalue to indicate we are done.
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
//we should only be able to land in here if terrorist or CT.
|
|
public Action SelectWavebasedHuman(int client)
|
|
{
|
|
if (!IsValidClient(client))
|
|
return Plugin_Handled;
|
|
|
|
if (GetClientTeam(client) == CS_TEAM_T)
|
|
{
|
|
ChangeClientTeam(client, CS_TEAM_CT); //default putting humans to CT team
|
|
CreateTimer(1.0, Timer_delayedRespawn, GetClientUserId(client));
|
|
return Plugin_Continue;
|
|
}
|
|
if (!IsPlayerAlive(client) && CS_TEAM_CT) //this should help if you spawn late into a round so that you actually respawn
|
|
{
|
|
CreateTimer(1.0, Timer_delayedRespawn, GetClientUserId(client));
|
|
return Plugin_Continue;
|
|
}
|
|
ModelSelection(client, 2, g_iClientHumanClasses[client]);
|
|
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
public Action Timer_delayedRespawn(Handle timer, any userid)
|
|
{
|
|
int client = GetClientOfUserId(userid);
|
|
if (!IsValidClient(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
CS_RespawnPlayer(client); //respawning because changeclientteam kills the player on css
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action SelectWaveBasedZM(int client, int state)
|
|
{
|
|
if (!IsValidClient(client))
|
|
return Plugin_Handled;
|
|
|
|
if (GetClientTeam(client) == CS_TEAM_CT)
|
|
{
|
|
ChangeClientTeam(client, CS_TEAM_T); //default putting bots to t
|
|
CreateTimer(0.3, Timer_delayedRespawn, GetClientUserId(client));
|
|
return Plugin_Handled;
|
|
}
|
|
//state 0 was bot, state 1 was real player.
|
|
if (!IsValidClient(client))
|
|
return Plugin_Handled;
|
|
int l_iZMIndex;
|
|
int l_ibotIndex;
|
|
|
|
if (state == 0)
|
|
{
|
|
if (g_bIsBossRound && g_iBossBotCount > 0 && !g_bClientIsBoss[client]) //does not work setting on roundstart. so instead doing when applying ZM skin.
|
|
{
|
|
g_bClientIsBoss[client] = true;
|
|
g_iBossBotCount--; //picking certain bots as the boss bots. all other bots are the minions.
|
|
}
|
|
|
|
if (g_bIsBossRound)
|
|
{
|
|
if (g_bClientIsBoss[client])
|
|
{
|
|
//its boss round and we set class for a boss bot
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (strlen(g_cZMRoundClasses[i][g_iLength]) > 0 && strlen(g_cGroup[i][g_iLength]) < 1 && strlen(g_cSMFLAGS[i][g_iLength]) < 1
|
|
&& g_iZombieBossIndex[i])
|
|
{
|
|
l_iZMIndex++; //we set amount of boss classes that the boss bot can pick between.
|
|
}
|
|
}
|
|
|
|
l_ibotIndex = GetRandomInt(0, l_iZMIndex -1);
|
|
l_iZMIndex = 0;
|
|
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (strlen(g_cZMRoundClasses[i][g_iLength]) > 0 && strlen(g_cGroup[i][g_iLength]) < 1 && strlen(g_cSMFLAGS[i][g_iLength]) < 1)
|
|
{
|
|
if (!g_iZombieBossIndex[i])
|
|
{
|
|
continue;
|
|
}
|
|
else if (l_ibotIndex == l_iZMIndex)
|
|
{
|
|
g_iClientZMClasses[client] = i;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
l_iZMIndex++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//its boss round and we set class for a minion bot
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (strlen(g_cZMRoundClasses[i][g_iLength]) > 0 && strlen(g_cGroup[i][g_iLength]) < 1 && strlen(g_cSMFLAGS[i][g_iLength]) < 1
|
|
&& !g_iZombieBossIndex[i])
|
|
{
|
|
l_iZMIndex++; //we set amount of normal zombie classes the minion bot can pick between. skipping out the boss classes.
|
|
}
|
|
}
|
|
|
|
l_ibotIndex = GetRandomInt(0, l_iZMIndex -1);
|
|
l_iZMIndex = 0;
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (strlen(g_cZMRoundClasses[i][g_iLength]) > 0 && strlen(g_cGroup[i][g_iLength]) < 1 && strlen(g_cSMFLAGS[i][g_iLength]) < 1)
|
|
{
|
|
if (g_iZombieBossIndex[i])
|
|
{
|
|
continue;
|
|
}
|
|
else if (l_ibotIndex == l_iZMIndex)
|
|
{
|
|
g_iClientZMClasses[client] = i;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
l_iZMIndex++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//its normal round. just setting the classes randomly.
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (strlen(g_cZMRoundClasses[i][g_iLength]) > 0 && strlen(g_cGroup[i][g_iLength]) < 1 && strlen(g_cSMFLAGS[i][g_iLength]) < 1)
|
|
{
|
|
l_iZMIndex++; //here we get to know what the last index is, that way the randomint can pick between index 0 and last index for ZM classes.
|
|
}
|
|
}
|
|
|
|
l_ibotIndex = GetRandomInt(0, l_iZMIndex -1);
|
|
l_iZMIndex = 0;
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (strlen(g_cZMRoundClasses[i][g_iLength]) > 0 && strlen(g_cGroup[i][g_iLength]) < 1 && strlen(g_cSMFLAGS[i][g_iLength]) < 1)
|
|
{
|
|
if (l_ibotIndex == l_iZMIndex)
|
|
{
|
|
g_iClientZMClasses[client] = i;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
l_iZMIndex++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//if no model selected just picks the first available for players
|
|
else if (strlen(g_cZMRoundClasses[g_iClientZMClasses[client]][g_iLength]) < 1)
|
|
{
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (strlen(g_cZMRoundClasses[i][g_iLength]) > 0)
|
|
{
|
|
g_iClientZMClasses[client] = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//im just getting desperate at this point for fixing the client crash by adding random ass delays.
|
|
CreateTimer(0.3, Timer_delayedModelSelection, GetClientUserId(client));
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Timer_delayedModelSelection(Handle timer, any userid)
|
|
{
|
|
int client = GetClientOfUserId(userid);
|
|
if (!IsValidClient(client) || !IsPlayerAlive(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
ModelSelection(client, 1, g_iClientZMClasses[client]);
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action ModelSelection(int client, int state, int modelIndex)
|
|
{
|
|
//state 1 = zombie players, state 2 = human players
|
|
char l_cUniqueModel[g_dLength];
|
|
int l_iModelIndex;
|
|
l_iModelIndex = modelIndex;
|
|
if (state < 2)
|
|
{
|
|
Format(l_cUniqueModel, sizeof(l_cUniqueModel), g_cZMRoundClasses[l_iModelIndex][g_iLength]);
|
|
}
|
|
else if (state == 2)
|
|
{
|
|
Format(l_cUniqueModel, sizeof(l_cUniqueModel), g_cHumanClasses[l_iModelIndex][g_iLength]);
|
|
}
|
|
|
|
|
|
for (int i = 0; i < g_dIndexes; i++)
|
|
{
|
|
if (strlen(g_cUniqueName[i][g_iLength]) < 1)
|
|
{
|
|
continue;
|
|
}
|
|
if (StrContains(g_cUniqueName[i][g_iLength], l_cUniqueModel, false) > -1)
|
|
{
|
|
|
|
if (StrContains(g_cModelPath[i][g_iLength], ".mdl") != -1)
|
|
{
|
|
//if its a public skin we go in here. we skip this if its the "store skin". in those cases we let the store decide the .mdl for the player.
|
|
//otherwise we assign the .mdl here.
|
|
//in practise only one human skin will not have .mdl set. we only do not end here when its that one human model.
|
|
SetEntityModel(client, g_cModelPath[i][g_iLength]);
|
|
}
|
|
|
|
g_bClientProtection[client] = true;
|
|
if (StrContains(g_cNoFallDmg[i][g_iLength], "YES") > -1)
|
|
g_bFallDamage[client] = true;
|
|
else
|
|
g_bFallDamage[client] = false;
|
|
g_iSpeedDelayClient[client] = i;
|
|
|
|
//setting this shit with a delay because it otherwise causes client crashes.
|
|
CreateTimer(3.0, Timer_SetSpeed, GetClientUserId(client));
|
|
if (state < 2)
|
|
{
|
|
CreateTimer(g_fZMSpawnProtection, Timer_StopProtection, GetClientUserId(client));
|
|
}
|
|
else
|
|
{
|
|
CreateTimer(g_fHumanSpawnProtection, Timer_StopProtection, GetClientUserId(client));
|
|
}
|
|
g_fKnockBackIndex[client] = StringToFloat(g_cKnockback[i][g_iLength]);
|
|
g_fJumpHeightIndex[client] = StringToFloat(g_cJumpHeight[i][g_iLength]);
|
|
g_fJumpDistanceIndex[client] = StringToFloat(g_cJumpDistance[i][g_iLength]);
|
|
g_fDamageMultiplier[client] = StringToFloat(g_cDamageMultiplier[i][g_iLength]);
|
|
return Plugin_Handled;
|
|
}
|
|
}
|
|
return Plugin_Handled;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Timer_CheckIfBotsStuck(Handle timer, any userid)
|
|
{
|
|
float l_fClientVelocity[3];
|
|
for (int i = 1; i < MaxClients; i++)
|
|
{
|
|
if (IsValidClient(i) && IsFakeClient(i) && IsPlayerAlive(i))
|
|
{
|
|
GetEntPropVector(i, Prop_Data, "m_vecAbsVelocity", l_fClientVelocity);
|
|
if (l_fClientVelocity[0] < 30.0 && l_fClientVelocity[0] > -30.0 &&
|
|
l_fClientVelocity[1] < 30.0 && l_fClientVelocity[1] > -30.0)
|
|
{
|
|
g_iBotStuckindex[i]++;
|
|
}
|
|
else
|
|
{
|
|
g_iBotStuckindex[i] = 0;
|
|
}
|
|
if (g_iBotStuckindex[i] > g_iBotStuckCounts)
|
|
{
|
|
l_fClientVelocity[0] -= GetRandomInt(50, 250);
|
|
l_fClientVelocity[1] -= GetRandomInt(50, 250);
|
|
l_fClientVelocity[2] = g_fBotStuckPush * 5;
|
|
Entity_SetAbsVelocity(i, l_fClientVelocity);
|
|
g_iBotStuckindex[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
return Plugin_Handled;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Timer_zombieSounds(Handle timer, any userid)
|
|
{
|
|
int[] l_clients = new int[MaxClients + 1];
|
|
int l_client;
|
|
int l_iclientCount;
|
|
int l_iSoundIndexes;
|
|
for (int i = 1; i < MaxClients; i++)
|
|
{
|
|
if (IsValidClient(i) && GetClientTeam(i) == CS_TEAM_T)
|
|
{
|
|
l_clients[l_iclientCount++] = i;
|
|
}
|
|
}
|
|
l_client = l_clients[GetRandomInt(0, l_iclientCount - 1)];
|
|
l_iSoundIndexes = GetRandomInt(0, g_iSoundIndexes - 1);
|
|
for (int i = 1; i < MaxClients; i++)
|
|
{
|
|
if (IsValidClient(i) && !IsFakeClient(i))
|
|
{
|
|
EmitSoundToClient(i, g_cZMSounds[l_iSoundIndexes][g_iLength], l_client);
|
|
}
|
|
}
|
|
return Plugin_Handled;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Timer_Respawn(Handle timer, any userid)
|
|
{
|
|
int client = GetClientOfUserId(userid);
|
|
if (client == 0)
|
|
return Plugin_Continue;
|
|
|
|
if (!IsValidClient(client) || IsPlayerAlive(client) || (GetClientTeam(client) != CS_TEAM_T && GetClientTeam(client) != CS_TEAM_CT))
|
|
{
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
UpdateWaveCount(client);
|
|
if (!IsFakeClient(client) && g_iClientRespawnCount[client] < 1)
|
|
{
|
|
ChangeClientTeam(client, CS_TEAM_T); //ran out of respawns for CT
|
|
}
|
|
else if (IsFakeClient(client) && GetClientTeam(client) != CS_TEAM_T)
|
|
{
|
|
ChangeClientTeam(client, CS_TEAM_T);
|
|
}
|
|
else if (!IsFakeClient(client) && GetClientTeam(client) != CS_TEAM_CT)
|
|
{
|
|
ChangeClientTeam(client, CS_TEAM_CT); //default putting humans to CT team
|
|
}
|
|
CreateTimer(1.0, Timer_delayedRespawn, GetClientUserId(client));
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
//this shit has to be delayed because it otherwise causes client crashes
|
|
public Action Timer_SetSpeed(Handle timer, any userid)
|
|
{
|
|
int client = GetClientOfUserId(userid);
|
|
if (client == 0)
|
|
return Plugin_Continue;
|
|
if (IsValidClient(client) && IsPlayerAlive(client) && g_iSpeedDelayClient[client] != 0)
|
|
{
|
|
//setting the class speed simply.
|
|
SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", StringToFloat(g_cSpeed[g_iSpeedDelayClient[client]][g_iLength]));
|
|
|
|
if (GetClientTeam(client) == CS_TEAM_T) //setting the zombie health here using the HealthScaleAbility.
|
|
{
|
|
int l_iPlayers;
|
|
for (int j = 1; j <= MaxClients; j++)
|
|
{
|
|
if (IsValidClient(j) && !IsFakeClient(j) && CS_TEAM_CT == GetClientTeam(j))
|
|
{
|
|
l_iPlayers++;
|
|
}
|
|
}
|
|
l_iPlayers -= 1; //first player indicates the full health of the class, each additional uses scaleability health.
|
|
int additional_zombie_health_per_player = RoundFloat(g_fZMHealthScaleability * StringToInt(g_cHealth[g_iSpeedDelayClient[client]][g_iLength]));
|
|
SetEntityHealth(client, StringToInt(g_cHealth[g_iSpeedDelayClient[client]][g_iLength]) + (additional_zombie_health_per_player * l_iPlayers));
|
|
}
|
|
else if (CS_TEAM_CT == GetClientTeam(client))
|
|
{
|
|
// smrpg
|
|
//checking if the health perk is used by the player, this basically makes the hp setting in the config useless most of the time.
|
|
//but looks like people just anyways will want CT to always have 100 HP.
|
|
if (SMRPG_Health_GetClientMaxHealth(client) == 100)
|
|
{
|
|
SetEntityHealth(client, StringToInt(g_cHealth[g_iSpeedDelayClient[client]][g_iLength]));
|
|
}
|
|
}
|
|
}
|
|
return Plugin_Handled;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Timer_StopProtection(Handle timer, any userid)
|
|
{
|
|
int client = GetClientOfUserId(userid);
|
|
if (client == 0)
|
|
return Plugin_Continue;
|
|
if (IsValidClient(client) && IsPlayerAlive(client))
|
|
{
|
|
g_bClientProtection[client] = false;
|
|
if (GetClientTeam(client) == CS_TEAM_T)
|
|
{
|
|
Client_ChangeWeapon(client, "weapon_knife");
|
|
}
|
|
if (GetPlayerWeaponSlot(client, CS_SLOT_KNIFE) == -1) //just making sure everybody has a knife. otherwise giving them one
|
|
{
|
|
GivePlayerItem(client, "weapon_knife");
|
|
if (GetClientTeam(client) == CS_TEAM_T)
|
|
{
|
|
CreateTimer(1.0, Timer_SwitchKnife, GetClientOfUserId(client));
|
|
}
|
|
}
|
|
}
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Timer_SwitchKnife(Handle timer, any userid)
|
|
{
|
|
int client = GetClientOfUserId(userid);
|
|
if (client == 0)
|
|
return Plugin_Continue;
|
|
|
|
if (!IsValidClient(client) || !IsPlayerAlive(client))
|
|
{
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
Client_ChangeWeapon(client, "weapon_knife");
|
|
return Plugin_Handled;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Event_OnPlayerDeath(Handle event, const char[] name, bool dontBroadcast)
|
|
{
|
|
int client = GetClientOfUserId(GetEventInt(event, "userid"));
|
|
if(!client || !IsClientInGame(client))
|
|
return Plugin_Continue;
|
|
|
|
if (IsFakeClient(client))
|
|
{
|
|
CreateTimer(1.0, Timer_Respawn, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
|
|
}
|
|
else
|
|
{
|
|
if (g_iClientRespawnCount[client] > 0)
|
|
{
|
|
PrintToChat(client, "You have %i respawns left as human. You will respawn in %f seconds.", g_iClientRespawnCount[client], g_fRespawnTimer);
|
|
}
|
|
else
|
|
{
|
|
PrintToChat(client, "You will respawn as a zombie in %f seconds.", g_fRespawnTimer);
|
|
}
|
|
CreateTimer(g_fRespawnTimer, Timer_Respawn, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
|
|
}
|
|
return Plugin_Continue;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action UpdateWaveCount(int client)
|
|
{
|
|
if (GetClientTeam(client) == CS_TEAM_CT)
|
|
{
|
|
g_iClientRespawnCount[client]--;
|
|
for (int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if (IsValidClient(i) && IsPlayerAlive(i) && GetClientTeam(i) == CS_TEAM_CT)
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
}
|
|
PrintToChatAll("All Humans died!");
|
|
CS_TerminateRound(4.0, CSRoundEnd_TerroristWin, true);
|
|
return Plugin_Handled;
|
|
}
|
|
else if (GetClientTeam(client) == CS_TEAM_T)
|
|
{
|
|
int zombieCount = 0;
|
|
int humanCount = 0;
|
|
for (int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if (IsValidClient(i))
|
|
{
|
|
if (GetClientTeam(i) == CS_TEAM_CT)
|
|
{
|
|
humanCount++;
|
|
}
|
|
else if (GetClientTeam(i) == CS_TEAM_T)
|
|
{
|
|
zombieCount++;
|
|
}
|
|
}
|
|
}
|
|
if (g_bIsBossRound)
|
|
{
|
|
//we only reduce zombie count if the killed bot had a boss zombie class.
|
|
//if the killed bot instead had a zombie class of a minion we do not reduce the zombie count.
|
|
if (g_bClientIsBoss[client])
|
|
{
|
|
g_iZMCount--;
|
|
PrintHintTextToAll("Day %i: %s\nRemaining Zombies: %i\nHumans: %i\nZombies: %i", g_iWave, g_cDaysTitles[g_iWave - 1], g_iZMCount, humanCount, zombieCount);
|
|
g_iHumanCount = humanCount;
|
|
g_iZombieCount = zombieCount;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_iZMCount--;
|
|
PrintHintTextToAll("Day %i: %s\nRemaining Zombies: %i\nHumans: %i\nZombies: %i", g_iWave, g_cDaysTitles[g_iWave - 1], g_iZMCount, humanCount, zombieCount);
|
|
g_iHumanCount = humanCount;
|
|
g_iZombieCount = zombieCount;
|
|
}
|
|
}
|
|
if (g_iZMCount <= 0 && g_bRoundInProgress)
|
|
{
|
|
PrintToChatAll("Won Round!");
|
|
CS_TerminateRound(4.0, CSRoundEnd_CTWin, true);
|
|
g_iWave++;
|
|
g_bRoundInProgress = false;
|
|
}
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
public Action CS_OnTerminateRound(float& delay, CSRoundEndReason& reason)
|
|
{
|
|
//generally we only want to block round termination when all (or the only) zombies are dead but the count requires that there
|
|
//are more left to kill. we wait for the zombie to respawn so we can kill him again until g_iZMCount reaches 0.
|
|
if (g_iZMCount > 0)
|
|
{
|
|
for (int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if (IsValidClient(i) && IsPlayerAlive(i) && GetClientTeam(i) == CS_TEAM_CT)
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
}
|
|
}
|
|
return Plugin_Changed;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action OnTakeDamage(int client, int &attacker, int &inflictor, float &damage, int &damagetype)
|
|
{
|
|
//it was requested that if round ended that CT and ZM should not be able to damage each other anymore.
|
|
if (!g_bRoundInProgress)
|
|
return Plugin_Handled;
|
|
|
|
if (g_bClientProtection[client])
|
|
return Plugin_Handled;
|
|
else if (damagetype & DMG_FALL && g_bFallDamage[client])
|
|
return Plugin_Handled;
|
|
if (IsValidClient(attacker) && !IsFakeClient(attacker))
|
|
{
|
|
if (g_iHumanCount != 999) //very lazy fix so its not looking stupid at round start when no zombie died yet.
|
|
{
|
|
PrintHintText(attacker, "Zombie HP: %i\nDay %i: %s\nRemaining Zombies: %i\nHumans: %i\nZombies: %i",
|
|
GetClientHealth(client) , g_iWave, g_cDaysTitles[g_iWave - 1], g_iZMCount, g_iHumanCount, g_iZombieCount);
|
|
}
|
|
else
|
|
{
|
|
PrintHintText(attacker, "Zombie HP: %i\nDay %i: %s\nRemaining Zombies: %i",
|
|
GetClientHealth(client) , g_iWave, g_cDaysTitles[g_iWave - 1], g_iZMCount);
|
|
}
|
|
}
|
|
if (IsValidClient(attacker) && g_fDamageMultiplier[attacker] != 1.0) //damage multiplier
|
|
{
|
|
//value lower than 1.0 will reduce the actual damage.
|
|
damage *= g_fDamageMultiplier[attacker];
|
|
return Plugin_Changed;
|
|
}
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
//why do retards suggest using OnWeaponCanUse instead when its not even stopping zombies from using weapons that you drop to them.
|
|
public Action OnWeaponEquip(int client, int weapon)
|
|
{
|
|
if (GetClientTeam(client) == CS_TEAM_T)
|
|
{
|
|
char sWeapon[64];
|
|
GetEdictClassname(weapon, sWeapon, sizeof(sWeapon));
|
|
if(!StrEqual(sWeapon, "weapon_knife"))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
}
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose: zombie reloaded copied knockback
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action EventPlayerHurt(Handle event, const char[] name, bool dontBroadcast)
|
|
{
|
|
// Get all required event info.
|
|
int client = GetClientOfUserId(GetEventInt(event, "userid"));
|
|
int attacker = GetClientOfUserId(GetEventInt(event, "attacker"));
|
|
int l_iDmg_health = GetEventInt(event, "dmg_health");
|
|
char l_cWeapon[g_dIndexes];
|
|
if (client < 1 || attacker < 1)
|
|
{
|
|
return Plugin_Continue;
|
|
}
|
|
if (GetClientTeam(client) != CS_TEAM_T || GetClientTeam(attacker) != CS_TEAM_CT)
|
|
{
|
|
return Plugin_Continue;
|
|
}
|
|
GetEventString(event, "weapon", l_cWeapon, sizeof(l_cWeapon));
|
|
KnockbackOnClientHurt(client, attacker, l_cWeapon, l_iDmg_health);
|
|
return Plugin_Continue;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose: zombie reloaded copy paste
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void KnockbackOnClientHurt(int client, int attacker, const char[] weapon, int dmg_health)
|
|
{
|
|
float l_fKnockback = g_fKnockBackIndex[client];
|
|
float l_fClientloc[3];
|
|
float l_fAttackerloc[3];
|
|
GetClientAbsOrigin(client, l_fClientloc);
|
|
if (StrEqual(weapon, "hegrenade"))
|
|
{
|
|
if (KnockbackFindExplodingGrenade(l_fAttackerloc) == -1)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GetClientEyePosition(attacker, l_fAttackerloc);
|
|
float l_fAttackerange[3];
|
|
GetClientEyeAngles(attacker, l_fAttackerange);
|
|
TR_TraceRayFilter(l_fAttackerloc, l_fAttackerange, MASK_ALL, RayType_Infinite, KnockbackTRFilter);
|
|
TR_GetEndPosition(l_fClientloc);
|
|
}
|
|
l_fKnockback *= float(dmg_health);
|
|
KnockbackSetVelocity(client, l_fAttackerloc, l_fClientloc, l_fKnockback);
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose: Zombie reloaded knockback
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void KnockbackSetVelocity(int client, const float startpoint[3], const float endpoint[3], float magnitude)
|
|
{
|
|
float vector[3];
|
|
MakeVectorFromPoints(startpoint, endpoint, vector);
|
|
NormalizeVector(vector, vector);
|
|
ScaleVector(vector, magnitude);
|
|
if (GetEngineVersion() == Engine_CSGO)
|
|
{
|
|
int flags = GetEntityFlags(client);
|
|
float velocity[3];
|
|
//tools_functions.inc
|
|
ToolsGetClientVelocity(client, velocity);
|
|
if (velocity[2] > CSGO_KNOCKBACK_BOOST_MAX)
|
|
{
|
|
vector[2] = 0.0;
|
|
}
|
|
else if (flags & FL_ONGROUND && vector[2] < CSGO_KNOCKBACK_BOOST)
|
|
{
|
|
vector[2] = CSGO_KNOCKBACK_BOOST;
|
|
}
|
|
}
|
|
// ADD the given vector to the clients current velocity. tools_functions.inc
|
|
ToolsClientVelocity(client, vector);
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose: Zombie reloaded trfilter
|
|
//----------------------------------------------------------------------------------------------------
|
|
public bool KnockbackTRFilter(int entity, int contentsMask)
|
|
{
|
|
if (entity > 0 && entity < MAXPLAYERS)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose: Zombie reloaded applying grenades
|
|
//----------------------------------------------------------------------------------------------------
|
|
public int KnockbackFindExplodingGrenade(float heLoc[3])
|
|
{
|
|
char l_cClassname[g_dIndexes];
|
|
// Find max entities and loop through all of them.
|
|
int l_iMaxentities = GetMaxEntities();
|
|
for (int x = MaxClients; x <= l_iMaxentities; x++)
|
|
{
|
|
// If entity is invalid, then stop.
|
|
if (!IsValidEdict(x))
|
|
{
|
|
continue;
|
|
}
|
|
// If entity isnt a grenade, then stop.
|
|
GetEdictClassname(x, l_cClassname, sizeof(l_cClassname));
|
|
if (!StrEqual(l_cClassname, "hegrenade_projectile", false))
|
|
{
|
|
continue;
|
|
}
|
|
// If m_takedamage is set to 0, we found our grenade.
|
|
int takedamage = GetEntProp(x, Prop_Data, "m_takedamage");
|
|
if (takedamage == 0)
|
|
{
|
|
// Return its location.
|
|
GetEntPropVector(x, Prop_Send, "m_vecOrigin", heLoc);
|
|
// Return its entity index.
|
|
return x;
|
|
}
|
|
}
|
|
// Didnt find the grenade.
|
|
return -1;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose: zombie reloaded jump height
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action EventPlayerJump(Handle event, const char[] name, bool dontBroadcast)
|
|
{
|
|
// Get all required event info.
|
|
int index = GetClientOfUserId(GetEventInt(event, "userid"));
|
|
// Fire post player_jump event.
|
|
CreateTimer(0.0, EventPlayerJumpPost, GetClientUserId(index));
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action EventPlayerJumpPost(Handle timer, any userid)
|
|
{
|
|
int client = GetClientOfUserId(userid);
|
|
if (!IsValidClient(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
// If client isnt in-game, then stop.
|
|
if (!IsClientInGame(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
// Get class jump multipliers.
|
|
float distancemultiplier = g_fJumpDistanceIndex[client];
|
|
float heightmultiplier = g_fJumpHeightIndex[client];
|
|
|
|
// If both are set to 1.0, then stop here to save some work.
|
|
if (distancemultiplier == 1.0 && heightmultiplier == 1.0)
|
|
{
|
|
return Plugin_Continue;
|
|
}
|
|
float vecVelocity[3];
|
|
// Get clients current velocity.
|
|
ToolsClientVelocity(client, vecVelocity, false);
|
|
//maybe check JumpBoostIsBHop here
|
|
|
|
// Apply height multiplier to jump vector.
|
|
vecVelocity[2] *= heightmultiplier;
|
|
// Set new velocity.
|
|
ToolsClientVelocity(client, vecVelocity, true, false);
|
|
return Plugin_Continue;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
stock bool IsValidClient(int client)
|
|
{
|
|
if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
stock void ToolsGetClientVelocity(int client, float vecVelocity[3])
|
|
{
|
|
GetEntDataVector(client, g_iToolsVelocity, vecVelocity);
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
stock void ToolsClientVelocity(int client, float vecVelocity[3], bool apply = true, bool stack = true)
|
|
{
|
|
// If retrieve is true, then get clients velocity.
|
|
if (!apply)
|
|
{
|
|
ToolsGetClientVelocity(client, vecVelocity);
|
|
// Stop here.
|
|
return;
|
|
}
|
|
// If stack is true, then add clients velocity.
|
|
if (stack)
|
|
{
|
|
// Get clients velocity.
|
|
float vecClientVelocity[3];
|
|
ToolsGetClientVelocity(client, vecClientVelocity);
|
|
AddVectors(vecClientVelocity, vecVelocity, vecVelocity);
|
|
}
|
|
// Apply velocity on client.
|
|
SetEntDataVector(client, g_iToolsVelocity, vecVelocity);
|
|
}
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
stock void ReplaceStrings(char[] str, char[] strReplace)
|
|
{
|
|
char l_cstrFix[g_dLength];
|
|
Format(l_cstrFix, sizeof(l_cstrFix), str);
|
|
ReplaceString(l_cstrFix, sizeof(l_cstrFix), "\"", "");
|
|
ReplaceString(l_cstrFix, sizeof(l_cstrFix), strReplace, "");
|
|
TrimString(l_cstrFix);
|
|
Format(str, sizeof(l_cstrFix), l_cstrFix);
|
|
}
|
|
|
|
//ambience
|
|
void EmitAmbience(const char[] sound)
|
|
{
|
|
PrecacheSound(sound);
|
|
StopAmbience(sound);
|
|
EmitSoundToAll(sound, SOUND_FROM_PLAYER, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, 1.0, SNDPITCH_NORMAL, -1, NULL_VECTOR, NULL_VECTOR, true, 0.0);
|
|
}
|
|
|
|
void StopAmbience(const char []sound)
|
|
{
|
|
for (int i = 0; i < MaxClients; i++)
|
|
{
|
|
if (!IsValidClient(i))
|
|
{
|
|
continue;
|
|
}
|
|
StopSound(i, SNDCHAN_AUTO, sound);
|
|
}
|
|
}
|
|
|
|
public Action Timer_Ambient(Handle timer, any userid)
|
|
{
|
|
if (StrContains(g_cDaysTitles[g_iWave - 1], "BOSS", false) != -1) //the daystitle contains the word boss in it
|
|
{
|
|
EmitAmbience(g_cBossSound); //nobody will ever understand why megalovania was on the servers since 2020.
|
|
}
|
|
else
|
|
{
|
|
int index = ambient_index();
|
|
EmitAmbience(g_cAmbientSOund[index]);
|
|
}
|
|
return Plugin_Handled;
|
|
}
|