forked from UNLOZE/sm-plugins
PropSpawner: Added sm_propspawner_use_mode to determine what should happen when a plugin spawned prop is +use'd
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
"Games"
|
||||||
|
{
|
||||||
|
"cstrike"
|
||||||
|
{
|
||||||
|
"Offsets"
|
||||||
|
{
|
||||||
|
"PlayerUse"
|
||||||
|
{
|
||||||
|
"linux" "414"
|
||||||
|
"windows" "413"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
#include <sourcemod>
|
#include <sourcemod>
|
||||||
#include <sdktools>
|
#include <sdktools>
|
||||||
#include <sdkhooks>
|
#include <sdkhooks>
|
||||||
|
#include <dhooks>
|
||||||
|
#include <cstrike>
|
||||||
|
|
||||||
public Plugin myinfo =
|
public Plugin myinfo =
|
||||||
{
|
{
|
||||||
@@ -23,12 +25,15 @@ KeyValues g_Models;
|
|||||||
|
|
||||||
ConVar g_cvNotifyShot;
|
ConVar g_cvNotifyShot;
|
||||||
ConVar g_cvNotifyTimer;
|
ConVar g_cvNotifyTimer;
|
||||||
|
ConVar g_cvUseMode;
|
||||||
|
|
||||||
ArrayList g_aSpawnedProps; // Tracks entity indices of props spawned by this plugin so we can unhook them
|
ArrayList g_aSpawnedProps; // Tracks entity indices of props spawned by this plugin so we can unhook them
|
||||||
ArrayList g_aNotifyList;
|
ArrayList g_aNotifyList;
|
||||||
|
|
||||||
int g_aPlayerPropColor[MAXPLAYERS + 1][3];
|
int g_aPlayerPropColor[MAXPLAYERS + 1][3];
|
||||||
|
|
||||||
|
Handle g_PlayerUseSetup = INVALID_HANDLE;
|
||||||
|
|
||||||
enum struct NotifyListData
|
enum struct NotifyListData
|
||||||
{
|
{
|
||||||
int client;
|
int client;
|
||||||
@@ -94,11 +99,33 @@ public void OnPluginStart()
|
|||||||
}
|
}
|
||||||
g_Models.Rewind(); // Go back to the root node
|
g_Models.Rewind(); // Go back to the root node
|
||||||
|
|
||||||
|
GameData gd = new GameData("PropSpawner");
|
||||||
|
if (gd == null)
|
||||||
|
{
|
||||||
|
LogError("PropSpawner: Missing gamedata file");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int PlayerUseOffset = gd.GetOffset("PlayerUse");
|
||||||
|
if (PlayerUseOffset == -1)
|
||||||
|
{
|
||||||
|
LogError("PropSpawner: Missing \"PlayerUse\" offset in gamedata file");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_PlayerUseSetup = DHookCreate(PlayerUseOffset, HookType_Entity, ReturnType_Void, ThisPointer_CBaseEntity, PlayerUse_Hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete gd;
|
||||||
|
}
|
||||||
|
|
||||||
RegAdminCmd("sm_propspawner", Command_MainMenu, ADMFLAG_CHANGEMAP); //g
|
RegAdminCmd("sm_propspawner", Command_MainMenu, ADMFLAG_CHANGEMAP); //g
|
||||||
RegAdminCmd("sm_setpropcolor", Command_SetPropColor, ADMFLAG_CHANGEMAP, "Set PropSpawner color by RGB value, or \"rainbow\" for that.");
|
RegAdminCmd("sm_setpropcolor", Command_SetPropColor, ADMFLAG_CHANGEMAP, "Set PropSpawner color by RGB value, or \"rainbow\" for that.");
|
||||||
|
|
||||||
g_cvNotifyShot = CreateConVar("sm_propspawner_notify_shot", "0", "If set to 1, announces in chat when a plugin-spawned prop is shot.", FCVAR_NOTIFY, true, 0.0, true, 1.0);
|
g_cvNotifyShot = CreateConVar("sm_propspawner_notify_shot", "0", "If set to 1, announces in chat when a plugin-spawned prop is shot.", FCVAR_NOTIFY, true, 0.0, true, 1.0);
|
||||||
g_cvNotifyTimer = CreateConVar("sm_propspawner_notify_shot_timer", "0.5", "How long a player stays in the \"shooting couch\" list.");
|
g_cvNotifyTimer = CreateConVar("sm_propspawner_notify_shot_timer", "0.5", "How long a player stays in the \"shooting couch\" list.");
|
||||||
|
g_cvUseMode = CreateConVar("sm_propspawner_use_mode", "0", "What should happen when a prop is +use'd. " ...
|
||||||
|
"0 = Normal. 1 = Disallow CTs moving plugin spawned props. 2 = Add player to notify list.");
|
||||||
AutoExecConfig(true, "PropSpawner");
|
AutoExecConfig(true, "PropSpawner");
|
||||||
|
|
||||||
g_aSpawnedProps = new ArrayList();
|
g_aSpawnedProps = new ArrayList();
|
||||||
@@ -707,26 +734,7 @@ public Action OnPropTakeDamage(int victim, int &attacker, int &inflictor, float
|
|||||||
if (attacker < 1 || attacker > MaxClients || !IsClientInGame(attacker))
|
if (attacker < 1 || attacker > MaxClients || !IsClientInGame(attacker))
|
||||||
return Plugin_Continue;
|
return Plugin_Continue;
|
||||||
|
|
||||||
Handle timer = CreateTimer(g_cvNotifyTimer.FloatValue, OnNotifyTimer, attacker);
|
AddToNotifyList(attacker);
|
||||||
int idx = FindInNotifyList(attacker);
|
|
||||||
if (idx == -1)
|
|
||||||
{
|
|
||||||
NotifyListData data;
|
|
||||||
data.client = attacker;
|
|
||||||
data.timer = timer;
|
|
||||||
g_aNotifyList.PushArray(data, sizeof(NotifyListData));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NotifyListData buf;
|
|
||||||
g_aNotifyList.GetArray(idx, buf, sizeof(NotifyListData));
|
|
||||||
if (buf.timer != INVALID_HANDLE)
|
|
||||||
KillTimer(buf.timer);
|
|
||||||
|
|
||||||
buf.timer = timer;
|
|
||||||
g_aNotifyList.SetArray(idx, buf, sizeof(NotifyListData));
|
|
||||||
}
|
|
||||||
|
|
||||||
DisplayNotifyList();
|
DisplayNotifyList();
|
||||||
|
|
||||||
return Plugin_Continue;
|
return Plugin_Continue;
|
||||||
@@ -793,6 +801,8 @@ int FindInNotifyList(int client)
|
|||||||
public void OnClientPutInServer(int client)
|
public void OnClientPutInServer(int client)
|
||||||
{
|
{
|
||||||
g_aPlayerPropColor[client] = {255, 255, 255};
|
g_aPlayerPropColor[client] = {255, 255, 255};
|
||||||
|
DHookEntity(g_PlayerUseSetup, false, client);
|
||||||
|
DHookEntity(g_PlayerUseSetup, true, client, INVALID_FUNCTION, PlayerUse_HookPost);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnRainbowTimer(Handle timer, any data)
|
void OnRainbowTimer(Handle timer, any data)
|
||||||
@@ -818,3 +828,124 @@ void ApplyRainbow(int ent, float Frequency)
|
|||||||
|
|
||||||
SetEntityRenderColor(ent, Red, Green, Blue, 255);
|
SetEntityRenderColor(ent, Red, Green, Blue, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddToNotifyList(int client)
|
||||||
|
{
|
||||||
|
if (GetClientTeam(client) != CS_TEAM_CT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Handle timer = CreateTimer(g_cvNotifyTimer.FloatValue, OnNotifyTimer, client);
|
||||||
|
int idx = FindInNotifyList(client);
|
||||||
|
if (idx == -1)
|
||||||
|
{
|
||||||
|
NotifyListData data;
|
||||||
|
data.client = client;
|
||||||
|
data.timer = timer;
|
||||||
|
g_aNotifyList.PushArray(data, sizeof(NotifyListData));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NotifyListData buf;
|
||||||
|
g_aNotifyList.GetArray(idx, buf, sizeof(NotifyListData));
|
||||||
|
if (buf.timer != INVALID_HANDLE)
|
||||||
|
KillTimer(buf.timer);
|
||||||
|
|
||||||
|
buf.timer = timer;
|
||||||
|
g_aNotifyList.SetArray(idx, buf, sizeof(NotifyListData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConVar sv_pushaway_force = null;
|
||||||
|
float g_flPushawayRestore = 0.0;
|
||||||
|
|
||||||
|
MRESReturn PlayerUse_Hook(int pThis)
|
||||||
|
{
|
||||||
|
static ConVar sv_turbophysics = null;
|
||||||
|
if (!sv_pushaway_force)
|
||||||
|
sv_pushaway_force = FindConVar("sv_pushaway_force");
|
||||||
|
|
||||||
|
if (!sv_turbophysics)
|
||||||
|
sv_turbophysics = FindConVar("sv_turbophysics");
|
||||||
|
|
||||||
|
if (!sv_pushaway_force || !sv_turbophysics)
|
||||||
|
return MRES_Ignored;
|
||||||
|
|
||||||
|
if (!sv_turbophysics.BoolValue)
|
||||||
|
return MRES_Ignored;
|
||||||
|
|
||||||
|
if (g_cvUseMode.IntValue != 1 && g_cvUseMode.IntValue != 2)
|
||||||
|
return MRES_Ignored;
|
||||||
|
|
||||||
|
// ZMs can always push it
|
||||||
|
if (GetClientTeam(pThis) != CS_TEAM_CT)
|
||||||
|
return MRES_Ignored;
|
||||||
|
|
||||||
|
if ((GetClientButtons(pThis) & IN_USE) == 0)
|
||||||
|
return MRES_Ignored;
|
||||||
|
|
||||||
|
float eyePos[3];
|
||||||
|
float eyeAng[3];
|
||||||
|
float eyeFwd[3];
|
||||||
|
float endPos[3];
|
||||||
|
GetClientEyePosition(pThis, eyePos);
|
||||||
|
GetClientEyeAngles(pThis, eyeAng);
|
||||||
|
GetAngleVectors(eyeAng, eyeFwd, NULL_VECTOR, NULL_VECTOR);
|
||||||
|
|
||||||
|
endPos[0] = eyePos[0] + (eyeFwd[0] * 96.0);
|
||||||
|
endPos[1] = eyePos[1] + (eyeFwd[1] * 96.0);
|
||||||
|
endPos[2] = eyePos[2] + (eyeFwd[2] * 96.0);
|
||||||
|
|
||||||
|
Handle tr = TR_TraceRayFilterEx(eyePos, endPos, MASK_SOLID, RayType_EndPoint, UsePushFilter, 0, TRACE_ENTITIES_ONLY);
|
||||||
|
|
||||||
|
if (TR_DidHit(tr))
|
||||||
|
{
|
||||||
|
int entHit = TR_GetEntityIndex(tr);
|
||||||
|
|
||||||
|
// This currently only works if sm_propspawner_notify_shot is enabled
|
||||||
|
if (g_aSpawnedProps.FindValue(entHit) != -1)
|
||||||
|
{
|
||||||
|
switch (g_cvUseMode.IntValue)
|
||||||
|
{
|
||||||
|
// Prevent the prop from being moved
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
g_flPushawayRestore = sv_pushaway_force.FloatValue;
|
||||||
|
sv_pushaway_force.FloatValue = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to the shooting couch list
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
AddToNotifyList(pThis);
|
||||||
|
DisplayNotifyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(tr);
|
||||||
|
return MRES_Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
MRESReturn PlayerUse_HookPost(int pThis)
|
||||||
|
{
|
||||||
|
if (sv_pushaway_force && g_flPushawayRestore != 0.0)
|
||||||
|
{
|
||||||
|
sv_pushaway_force.FloatValue = g_flPushawayRestore;
|
||||||
|
g_flPushawayRestore = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MRES_Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UsePushFilter(int entity, int contentsMask)
|
||||||
|
{
|
||||||
|
// Checking if the entity has a physics object
|
||||||
|
int offs = FindDataMapInfo(entity, "m_pPhysicsObject");
|
||||||
|
int pt1 = LoadFromAddress(GetEntityAddress(entity) + view_as<Address>(offs), NumberType_Int32);
|
||||||
|
int pt2 = view_as<int>(Address_PointerSize) == 8 ? LoadFromAddress(GetEntityAddress(entity) + view_as<Address>(offs + 4), NumberType_Int32) : 0;
|
||||||
|
if (pt1 == 0 && pt2 == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user