#pragma semicolon 1
#pragma newdecls required
#include <cstrike>
#include <sdktools_gamerules>
#include <vip_core>
Handle g_hTimer = null;
StringMap g_hAuthTrie;
ConVar
cvLimit,
cvAutoReaspawn,
cvMinAliveMode,
cvEnable,
cvMapLimit,
cvEndDuration,
cvMinAlive;
bool
g_bAutoRespawn[MAXPLAYERS+1],
g_bEnabledRespawn;
int
g_iClientRespawns[MAXPLAYERS+1],
g_iRoundStartTime;
float g_fDeathTime[MAXPLAYERS+1];
static const char
g_szFeature[] = "Respawn",
g_szFeatureRespawnWaitTime[] = "RespawnWaitTime",
g_szFeatureAutoRespawn[] = "AutoRespawn";
public void OnPluginStart()
{
g_hAuthTrie = new StringMap();
cvLimit = CreateConVar("sm_vip_respawn_limit", "-1", "Режим работы лимита: 1 - X раз за раунд, 0 - X раз за карту; -1 выключен", 0, true, 0.0, true, 1.0);
cvAutoReaspawn = CreateConVar("sm_vip_respawn_autoreaspawn", "0", "Использовать ли Авто Возрождение", 0, true, 0.0, true, 1.0);
cvMinAliveMode = CreateConVar("sm_vip_respawn_minalivemod", "0", "режим автрореспавна: 0 — выкл, 1 — по своей команде, 2 — по противнику, 3 — по обеим командам.", 0, true, 0.0, true, 3.0);
cvEnable = CreateConVar("sm_vip_respawn_enable", "1", "Включен ли плагин (0 - Отключен, 1 - Включен)", 0, true, -1.0, true, 1.0);
cvMapLimit = CreateConVar("sm_vip_respawn_map_limit", "-1", "Ограничение респавнов за раунд/карту для карты (-1 - нет ограничения, 0 - запрещено, 1 и больше)", 0, true, -1.0);
cvEndDuration = CreateConVar("sm_vip_respawn_end_duration", "0.0", "Сколько секунд после начала раунда игрок может возрождаться (0.0 - Отключено)", 0, true, 0.0);
cvMinAlive = CreateConVar("sm_vip_respawn_min_alive", "0", "Сколько минимально должно быть живых игроков в команде чтобы игрок мог возрождаться (0 - Отключено)", 0, true, 0.0);
AutoExecConfig(true, "VIP_Respawn", "vip");
RegConsoleCmd("sm_respawn", Cmd_Respawn);
HookEventEx("round_freeze_end", Event_RoundStart, EventHookMode_PostNoCopy);
HookEvent("round_end", Event_RoundEnd, EventHookMode_PostNoCopy);
HookEvent("player_death", Event_PlayerDeath);
LoadTranslations("vip_respawn.phrases");
LoadTranslations("vip_modules.phrases");
LoadTranslations("vip_core.phrases");
if(VIP_IsVIPLoaded())
{
VIP_OnVIPLoaded();
}
}
public void VIP_OnVIPLoaded()
{
VIP_RegisterFeature(g_szFeature, INT, SELECTABLE, OnSelectItem, OnDisplayItem);
VIP_RegisterFeature(g_szFeatureRespawnWaitTime, INT, HIDE);
if(cvAutoReaspawn.BoolValue)
VIP_RegisterFeature(g_szFeatureAutoRespawn, BOOL, TOGGLABLE, OnToggleItem, _, OnDrawItem);
}
public void OnPluginEnd()
{
if(CanTestFeatures() && GetFeatureStatus(FeatureType_Native, "VIP_UnregisterFeature") == FeatureStatus_Available)
{
VIP_UnregisterFeature(g_szFeature);
VIP_UnregisterFeature(g_szFeatureRespawnWaitTime);
if(cvAutoReaspawn.BoolValue)
VIP_UnregisterFeature(g_szFeatureAutoRespawn);
}
}
public void OnMapStart()
{
if(cvLimit.IntValue != 0)
return;
g_hAuthTrie.Clear();
for(int i = 1; i <= MaxClients; ++i) g_iClientRespawns[i] = 0;
}
public Action Cmd_Respawn(int iClient, int args)
{
if(iClient)
{
if(!cvEnable.BoolValue)
{
VIP_PrintToChatClient(iClient, "%t", "RESPAWN_OFF");
}
if(VIP_IsClientVIP(iClient) && VIP_IsClientFeatureUse(iClient, g_szFeature))
{
RespawnClient(iClient);
}
else
{
VIP_PrintToChatClient(iClient, "%t", "COMMAND_NO_ACCESS");
}
}
return Plugin_Handled;
}
public void Event_RoundStart(Event hEvent, const char[] name, bool dontBroadcast)
{
if(cvLimit.IntValue == 1)
{
g_hAuthTrie.Clear();
for(int i = 1; i <= MaxClients; ++i)
g_iClientRespawns[i] = 0;
}
if (g_hTimer)
delete g_hTimer;
g_bEnabledRespawn = true;
if (cvEndDuration.FloatValue)
{
g_hTimer = CreateTimer(cvEndDuration.FloatValue, Timer_DisableRespawn);
}
g_iRoundStartTime = GetTime();
}
public Action Timer_DisableRespawn(Handle hTimer)
{
g_bEnabledRespawn = false;
g_hTimer = null;
return Plugin_Stop;
}
public void Event_RoundEnd(Event hEvent, const char[] name, bool dontBroadcast)
{
g_bEnabledRespawn = false;
if (g_hTimer)
delete g_hTimer;
}
public void OnClientPutInServer(int iClient)
{
if(cvAutoReaspawn.BoolValue)
g_bAutoRespawn[iClient] = false;
g_iClientRespawns[iClient] = 0;
char sAuth[32];
GetClientAuthId(iClient, AuthId_Engine, sAuth, sizeof(sAuth));
g_hAuthTrie.GetValue(sAuth, g_iClientRespawns[iClient]);
}
public void Event_PlayerDeath(Event hEvent, const char[] name, bool dontBroadcast)
{
int iClient = GetClientOfUserId(hEvent.GetInt("userid"));
g_fDeathTime[iClient] = GetGameTime();
if (!cvAutoReaspawn.BoolValue)
return;
if (!g_bAutoRespawn[iClient])
return;
if (!IsAllowedTimeAfterRoundStart(iClient))
return;
CreateTimer(1.0, Timer_RespawnClient, GetClientUserId(iClient), TIMER_FLAG_NO_MAPCHANGE);
}
public Action Timer_RespawnClient(Handle hTimer, any iUserID)
{
if(!cvAutoReaspawn.BoolValue)
return Plugin_Stop;
int iClient = GetClientOfUserId(iUserID);
if(iClient && IsClientInGame(iClient) && CheckRespawn(iClient, false))
{
VIP_PrintToChatClient(iClient, "%t", "AUTORESPAWN_NOTIFY");
RespawnClient(iClient, false);
}
return Plugin_Stop;
}
stock void RespawnClient(int iClient, bool bCheck = true)
{
if(bCheck && !CheckRespawn(iClient, true))
{
return;
}
++g_iClientRespawns[iClient];
char sAuth[32];
GetClientAuthId(iClient, AuthId_Engine, sAuth, sizeof(sAuth));
g_hAuthTrie.SetValue(sAuth, g_iClientRespawns[iClient]);
CS_RespawnPlayer(iClient);
}
stock bool Fail(int iClient, bool bNotify, const char[] msg)
{
if (bNotify)
VIP_PrintToChatClient(iClient, "%t", msg);
return false;
}
stock bool CheckRespawn(int iClient, bool bNotify)
{
if (!cvEnable.BoolValue)
return Fail(iClient, bNotify, "RESPAWN_OFF");
if (cvMapLimit.IntValue == 0)
return Fail(iClient, bNotify, "RESPAWN_OFF");
if (!g_bEnabledRespawn)
return Fail(iClient, bNotify, "RESPAWN_FORBIDDEN");
if (GetGameTime() < g_fDeathTime[iClient] + 1.0)
return false;
int iClientTeam = GetClientTeam(iClient);
if (iClientTeam < 2)
return Fail(iClient, bNotify, "YOU_MUST_BE_ON_TEAM");
if (IsPlayerAlive(iClient))
return Fail(iClient, bNotify, "YOU_MUST_BE_DEAD");
if (!IsAllowedTimeAfterRoundStart(iClient))
return Fail(iClient, bNotify, "RESPAWN_NOT_AVAILABLE_YET");
int iLimit = VIP_GetClientFeatureInt(iClient, g_szFeature);
int iMapLimit = cvMapLimit.IntValue;
if ((iMapLimit != -1 && (iLimit == -1 || iMapLimit < iLimit) && g_iClientRespawns[iClient] >= iMapLimit) ||
(iLimit != -1 && g_iClientRespawns[iClient] >= iLimit))
{
return Fail(
iClient,
bNotify,
cvLimit.IntValue == 1 ? "REACHED_ROUND_LIMIT" : "REACHED_MAP_LIMIT"
);
}
if (cvMinAlive.IntValue)
{
int iPlayers[2], iTeam;
for (int i = 1; i <= MaxClients; i++)
{
if (IsClientInGame(i) && IsPlayerAlive(i) && (iTeam = GetClientTeam(i)) > 1)
iPlayers[iTeam - 2]++;
}
bool bNotEnough;
int min = cvMinAlive.IntValue;
switch (cvMinAliveMode.IntValue)
{
case 0: bNotEnough = (iPlayers[iClientTeam == 2 ? 0 : 1] < min);
case 1: bNotEnough = (iPlayers[iClientTeam == 2 ? 1 : 0] < min);
case 2: bNotEnough = (iPlayers[0] + iPlayers[1] < min);
case 3: bNotEnough = (iPlayers[0] < min || iPlayers[1] < min);
}
if (bNotEnough)
return Fail(iClient, bNotify, "NOT_ENOUGH_ALIVE_PLAYERS");
}
return true;
}
stock bool IsAllowedTimeAfterRoundStart(int iClient)
{
int iWaitRespawn = VIP_GetClientFeatureInt(iClient, g_szFeatureRespawnWaitTime);
if (iWaitRespawn)
{
return (GetTime() < g_iRoundStartTime + iWaitRespawn);
}
return true;
}
public bool OnSelectItem(int iClient, const char[] sFeatureName)
{
if (cvEnable.BoolValue && CheckRespawn(iClient, true))
RespawnClient(iClient);
return true;
}
public bool OnDisplayItem(int iClient, const char[] sFeatureName, char[] sDisplay, int maxlen)
{
if(VIP_GetClientFeatureStatus(iClient, g_szFeature) == ENABLED)
{
int iLimit = VIP_GetClientFeatureInt(iClient, g_szFeature);
if(iLimit != -1)
{
int iMapLimit = cvMapLimit.IntValue;
if(iMapLimit != -1 && iMapLimit < iLimit)
{
iLimit = iMapLimit - g_iClientRespawns[iClient];
}
else
{
iLimit -= g_iClientRespawns[iClient];
}
FormatEx(sDisplay, maxlen, "%T [%T]", g_szFeature, iClient, "Left", iClient, iLimit);
return true;
}
}
return false;
}
public Action OnToggleItem(int iClient, const char[] sFeatureName, VIP_ToggleState OldStatus, VIP_ToggleState &NewStatus)
{
if(cvAutoReaspawn.BoolValue)
return Plugin_Continue;
g_bAutoRespawn[iClient] = (VIP_IsClientFeatureUse(iClient, g_szFeature) && NewStatus == ENABLED);
return Plugin_Continue;
}
public int OnDrawItem(int iClient, const char[] sFeatureName, int iStyle)
{
if(cvAutoReaspawn.BoolValue)
return ITEMDRAW_RAWLINE;
if(VIP_GetClientFeatureStatus(iClient, g_szFeature) == ENABLED && VIP_GetClientFeatureStatus(iClient, g_szFeatureAutoRespawn) != NO_ACCESS)
{
return ITEMDRAW_DEFAULT;
}
return ITEMDRAW_RAWLINE;
}
public void VIP_OnVIPClientLoaded(int iClient)
{
if(cvAutoReaspawn.BoolValue)
return;
g_bAutoRespawn[iClient] = VIP_IsClientFeatureUse(iClient, g_szFeature) && VIP_IsClientFeatureUse(iClient, g_szFeatureAutoRespawn);
}