sm-plugins/Spectate/scripting/Spectate.sp

224 lines
5.4 KiB
SourcePawn
Raw Normal View History

2016-05-10 15:15:16 +02:00
#pragma semicolon 1
#include <sourcemod>
#include <sdktools>
#include <cstrike>
2017-05-20 05:08:31 +02:00
#include <zombiereloaded>
2018-08-07 22:39:17 +02:00
#include "loghelper.inc"
#pragma newdecls required
2016-05-10 15:15:16 +02:00
2018-11-21 00:24:07 +01:00
Handle g_hFwd_SpectateByCommand;
2016-05-10 15:15:16 +02:00
public Plugin myinfo =
{
name = "Spectate",
description = "Adds a command to spectate specific players and removes broken spectate mode.",
author = "Obus + BotoX",
version = "1.1",
2016-05-10 15:15:16 +02:00
url = ""
}
// Spectator Movement modes (from smlib)
enum Obs_Mode
{
OBS_MODE_NONE = 0, // not in spectator mode
OBS_MODE_DEATHCAM, // special mode for death cam animation
OBS_MODE_FREEZECAM, // zooms to a target, and freeze-frames on them
OBS_MODE_FIXED, // view from a fixed camera position
OBS_MODE_IN_EYE, // follow a player in first person view
OBS_MODE_CHASE, // follow a player in third person view
OBS_MODE_POI, // PASSTIME point of interest - game objective, big fight, anything interesting; added in the middle of the enum due to tons of hard-coded "<ROAMING" enum compares
OBS_MODE_ROAMING, // free roaming
NUM_OBSERVER_MODES
};
public void OnPluginStart()
{
LoadTranslations("common.phrases");
RegConsoleCmd("sm_spectate", Command_Spectate, "Spectate a player.");
RegConsoleCmd("sm_spec", Command_Spectate, "Spectate a player.");
AddCommandListener(Command_Suicide, "spectate");
AddCommandListener(Command_Suicide, "kill");
AddCommandListener(Command_Goto, "spec_goto");
2018-11-21 00:24:07 +01:00
g_hFwd_SpectateByCommand = CreateGlobalForward("OnPlayerSwitchedToSpectateByCommand", ET_Ignore, Param_Cell);
2016-05-10 15:15:16 +02:00
}
2018-08-07 22:39:17 +02:00
public void OnMapStart()
{
GetTeams();
}
2016-05-10 15:15:16 +02:00
public void OnClientSettingsChanged(int client)
{
static char sSpecMode[8];
GetClientInfo(client, "cl_spec_mode", sSpecMode, sizeof(sSpecMode));
Obs_Mode iObserverMode = view_as<Obs_Mode>(StringToInt(sSpecMode));
// Skip broken OBS_MODE_POI
if (iObserverMode == OBS_MODE_POI)
{
ClientCommand(client, "cl_spec_mode %d", OBS_MODE_ROAMING);
if(IsClientInGame(client) && !IsPlayerAlive(client))
2016-05-10 15:15:16 +02:00
SetEntProp(client, Prop_Send, "m_iObserverMode", OBS_MODE_ROAMING);
}
}
public Action Command_Spectate(int client, int argc)
{
if (!client)
{
PrintToServer("[SM] Cannot use command from server console.");
return Plugin_Handled;
}
2017-05-20 05:08:31 +02:00
if (IsPlayerAlive(client) && ZR_IsClientZombie(client))
{
bool bOnlyZombie = true;
for (int i = 1; i <= MaxClients; i++)
{
if (i != client && IsClientInGame(i) && IsPlayerAlive(i) && ZR_IsClientZombie(i))
{
bOnlyZombie = false;
break;
}
}
if (bOnlyZombie)
{
PrintToChat(client, "[SM] Can not switch to spectate as the last zombie!");
return Plugin_Handled;
}
}
2016-05-10 15:15:16 +02:00
if (!argc)
{
if (GetClientTeam(client) != CS_TEAM_SPECTATOR)
{
if ((IsPlayerAlive(client) && ZR_IsClientHuman(client)) && GetTeamAliveClientCount(CS_TEAM_T) > 0)
2018-08-07 22:39:17 +02:00
LogPlayerEvent(client, "triggered", "switch_to_spec");
2018-11-21 00:24:07 +01:00
Call_StartForward(g_hFwd_SpectateByCommand);
Call_PushCell(client);
Call_Finish();
StripPlayerWeapons(client);
2016-05-10 15:15:16 +02:00
ForcePlayerSuicide(client);
ChangeClientTeam(client, CS_TEAM_SPECTATOR);
}
return Plugin_Handled;
}
char sTarget[MAX_TARGET_LENGTH];
GetCmdArg(1, sTarget, sizeof(sTarget));
int iTarget;
2016-05-10 23:05:52 +02:00
if ((iTarget = FindTarget(client, sTarget, false, false)) <= 0)
2016-05-10 15:15:16 +02:00
return Plugin_Handled;
if (!IsPlayerAlive(iTarget))
{
ReplyToCommand(client, "[SM] %t", "Target must be alive");
return Plugin_Handled;
}
if (GetClientTeam(client) != CS_TEAM_SPECTATOR)
{
if ((IsPlayerAlive(client) && ZR_IsClientHuman(client)) && GetTeamAliveClientCount(CS_TEAM_T) > 0)
2018-08-07 22:39:17 +02:00
LogPlayerEvent(client, "triggered", "switch_to_spec");
2018-11-21 00:24:07 +01:00
Call_StartForward(g_hFwd_SpectateByCommand);
Call_PushCell(client);
Call_Finish();
StripPlayerWeapons(client);
2016-05-10 15:15:16 +02:00
ForcePlayerSuicide(client);
ChangeClientTeam(client, CS_TEAM_SPECTATOR);
}
SetEntPropEnt(client, Prop_Send, "m_hObserverTarget", iTarget);
Obs_Mode iObserverMode = view_as<Obs_Mode>(GetEntProp(client, Prop_Send, "m_iObserverMode"));
2016-05-10 15:15:16 +02:00
// If the client is currently in free roaming then switch them to first person view
if (iObserverMode == OBS_MODE_ROAMING)
{
ClientCommand(client, "cl_spec_mode %d", OBS_MODE_IN_EYE);
2016-05-10 15:15:16 +02:00
SetEntProp(client, Prop_Send, "m_iObserverMode", OBS_MODE_IN_EYE);
}
PrintToChat(client, "\x01[SM] Spectating \x04%N\x01.", iTarget);
return Plugin_Handled;
}
public Action Command_Suicide(int client, char[] command, int args)
2018-11-21 00:24:07 +01:00
{
if ((IsPlayerAlive(client) && ZR_IsClientHuman(client)) && GetTeamAliveClientCount(CS_TEAM_T) > 0)
2018-11-21 00:24:07 +01:00
LogPlayerEvent(client, "triggered", "switch_to_spec");
return Plugin_Continue;
}
// Fix spec_goto crash exploit
public Action Command_Goto(int client, const char[] command, int argc)
{
if(argc == 5)
{
for(int i = 1; i <= 3; i++)
{
char sArg[64];
GetCmdArg(i, sArg, 64);
float fArg = StringToFloat(sArg);
if(FloatAbs(fArg) > 5000000000.0)
{
PrintToServer("%d -> %f > %f", i, FloatAbs(fArg), 5000000000.0);
return Plugin_Handled;
}
}
}
return Plugin_Continue;
}
2018-08-07 22:39:17 +02:00
stock int GetTeamAliveClientCount(int iTeam)
{
int ret = 0;
for (int i = 1; i <= MaxClients; i++)
{
if (!IsClientInGame(i) || GetClientTeam(i) != iTeam)
continue;
if (!IsPlayerAlive(i))
continue;
ret++;
}
return ret;
}
stock void StripPlayerWeapons(int client)
{
for(int i = 0; i < 5; i++)
{
int w = -1;
while ((w = GetPlayerWeaponSlot(client, i)) != -1)
{
if(IsValidEntity(w) && IsValidEdict(w))
{
RemovePlayerItem(client, w);
AcceptEntityInput(w, "Kill");
}
}
}
2018-11-21 00:24:07 +01:00
}