Couch fixes
This commit is contained in:
@@ -10,6 +10,13 @@
|
||||
"linux" "160"
|
||||
"windows" "159"
|
||||
}
|
||||
|
||||
// CBasePlayer::PlayerUse(). Same offsets as PropSpawner.
|
||||
"PlayerUse"
|
||||
{
|
||||
"linux" "414"
|
||||
"windows" "413"
|
||||
}
|
||||
}
|
||||
|
||||
"Signatures"
|
||||
|
||||
+79
-27
@@ -93,7 +93,10 @@ int g_iBeaconTick;
|
||||
|
||||
Handle g_hForceVPhysicsCollide;
|
||||
|
||||
// Couch bans: hits and +use are refused in OnCouchTakeDamage/OnCouchUse, and the vphysics collision filter is
|
||||
Handle g_hPlayerUse;
|
||||
ConVar g_cvTurboPhysics;
|
||||
|
||||
// Couch bans: hits and +use are refused in OnCouchTakeDamage/Hook_PlayerUse, and the vphysics collision filter is
|
||||
// detoured so a blocked player can't push it. The detour is only enabled while someone is blocked.
|
||||
Handle g_hShouldCollideDetour;
|
||||
Handle g_hCollisionRulesChanged;
|
||||
@@ -148,7 +151,7 @@ public void OnPluginStart()
|
||||
g_cvModel = CreateConVar("sm_couch_model", COUCH_DEFAULT_MODEL, "Model used for the couch. Applies to the next spawn.", FCVAR_NOTIFY);
|
||||
g_cvPushScale = CreateConVar("sm_couch_push_scale", "1.0", "Multiplier on the force bullets apply to the couch. 1.0 is the engine's own push.", FCVAR_NOTIFY, true, 0.0, true, 100.0);
|
||||
g_cvPistolOnly = CreateConVar("sm_couch_pistol_only", "0", "Only pistols and knives move the couch; other guns and grenades are ignored.", FCVAR_NOTIFY, true, 0.0, true, 1.0);
|
||||
g_cvAllowUse = CreateConVar("sm_allow_couch_use", "1", "Players may +use the couch to pick it up. 0 means it can only be moved by shooting it.", FCVAR_NOTIFY, true, 0.0, true, 1.0);
|
||||
g_cvAllowUse = CreateConVar("sm_allow_couch_use", "1", "Players may push the couch by holding +use on it. 0 means it can only be moved by shooting it.", FCVAR_NOTIFY, true, 0.0, true, 1.0);
|
||||
g_cvEffect = CreateConVar("sm_couch_effect", "0", "Colour cycle and pulsing light on the couch.", FCVAR_NOTIFY, true, 0.0, true, 1.0);
|
||||
g_cvEffectIntensity = CreateConVar("sm_couch_effect_intensity", "3", "Brightness of the couch effect light. 0 is off, 3 is the default, 8 is very bright. Applies immediately.", FCVAR_NOTIFY, true, 0.0, true, 10.0);
|
||||
g_cvIgnoreClip = CreateConVar("sm_couch_ignore_clip", "1", "Let the couch pass through func_clip_vphysics brushes.", FCVAR_NOTIFY, true, 0.0, true, 1.0);
|
||||
@@ -164,9 +167,17 @@ public void OnPluginStart()
|
||||
|
||||
HookEvent("round_start", Event_RoundStart, EventHookMode_Post);
|
||||
|
||||
g_cvTurboPhysics = FindConVar("sv_turbophysics");
|
||||
|
||||
LoadGameData();
|
||||
|
||||
// Late load: the clip brushes and buttons already exist, so hook them now.
|
||||
// Late load: the players, clip brushes and buttons already exist, so hook them now.
|
||||
for (int client = 1; client <= MaxClients; client++)
|
||||
{
|
||||
if (IsClientInGame(client))
|
||||
OnClientPutInServer(client);
|
||||
}
|
||||
|
||||
int entity = -1;
|
||||
if (g_hForceVPhysicsCollide != null)
|
||||
{
|
||||
@@ -223,6 +234,13 @@ public void OnEntityDestroyed(int entity)
|
||||
Call_Finish();
|
||||
}
|
||||
|
||||
// DHooks drops the hook with the entity.
|
||||
public void OnClientPutInServer(int client)
|
||||
{
|
||||
if (g_hPlayerUse != null)
|
||||
DHookEntity(g_hPlayerUse, false, client);
|
||||
}
|
||||
|
||||
// Slot flag only; persistence across reconnects is the ban plugin's job.
|
||||
public void OnClientDisconnect(int client)
|
||||
{
|
||||
@@ -431,7 +449,6 @@ int SpawnCouchAt(const float vecOrigin[3], const float vecAngles[3])
|
||||
|
||||
// SDKHooks drops the hooks with the entity.
|
||||
SDKHook(couch, SDKHook_OnTakeDamage, OnCouchTakeDamage);
|
||||
SDKHook(couch, SDKHook_Use, OnCouchUse);
|
||||
|
||||
// Takes the beacon's colour modulation at full opacity.
|
||||
SetEntityRenderMode(couch, RENDER_NORMAL);
|
||||
@@ -506,25 +523,49 @@ public Action OnCouchTakeDamage(int victim, int &attacker, int &inflictor, float
|
||||
return result;
|
||||
}
|
||||
|
||||
// +use on the couch: same ban and tier rules as shooting it, and off entirely with sm_allow_couch_use 0.
|
||||
// Plugin_Handled stops the pickup.
|
||||
public Action OnCouchUse(int entity, int activator, int caller, UseType type, float value)
|
||||
// Reach of the engine's +use push.
|
||||
#define USE_PUSH_DISTANCE 96.0
|
||||
|
||||
// Holding +use pushes the physics object in the crosshair (sv_turbophysics). The couch never gets a Use
|
||||
// input, so the push is stopped by skipping PlayerUse for the tick.
|
||||
public MRESReturn Hook_PlayerUse(int client)
|
||||
{
|
||||
if (activator < 1 || activator > MaxClients || !IsClientInGame(activator))
|
||||
return Plugin_Continue;
|
||||
if (!(GetClientButtons(client) & IN_USE))
|
||||
return MRES_Ignored;
|
||||
|
||||
// Ban and tier first; their message is the more useful one.
|
||||
if (IsClientRefused(entity, activator))
|
||||
return Plugin_Handled;
|
||||
if (g_cvTurboPhysics != null && !g_cvTurboPhysics.BoolValue)
|
||||
return MRES_Ignored;
|
||||
|
||||
if (!g_cvAllowUse.BoolValue)
|
||||
{
|
||||
PrintHintText(activator, "The couch can't be picked up. Shoot it to move it.");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
int couch = GetCouchIndex();
|
||||
if (couch == -1 || GetUsePushTarget(client) != couch)
|
||||
return MRES_Ignored;
|
||||
|
||||
ReportInteraction(entity, activator, CouchMethod_Use, "");
|
||||
return Plugin_Continue;
|
||||
// Runs every tick +use is held; only the press is told why.
|
||||
bool bPressed = view_as<bool>(GetEntProp(client, Prop_Data, "m_afButtonPressed") & IN_USE);
|
||||
|
||||
if (IsClientRefused(couch, client, bPressed) || !g_cvAllowUse.BoolValue)
|
||||
return MRES_Supercede;
|
||||
|
||||
ReportInteraction(couch, client, CouchMethod_Use, "");
|
||||
return MRES_Ignored;
|
||||
}
|
||||
|
||||
// Entities only, like the engine's trace.
|
||||
int GetUsePushTarget(int client)
|
||||
{
|
||||
float vecEye[3];
|
||||
float vecAngles[3];
|
||||
float vecForward[3];
|
||||
GetClientEyePosition(client, vecEye);
|
||||
GetClientEyeAngles(client, vecAngles);
|
||||
GetAngleVectors(vecAngles, vecForward, NULL_VECTOR, NULL_VECTOR);
|
||||
|
||||
float vecEnd[3];
|
||||
ScaleVector(vecForward, USE_PUSH_DISTANCE);
|
||||
AddVectors(vecEye, vecForward, vecEnd);
|
||||
|
||||
TR_TraceRayFilter(vecEye, vecEnd, MASK_SOLID, RayType_EndPoint, TraceFilter_NotSelf, client, TRACE_ENTITIES_ONLY);
|
||||
return TR_DidHit() ? TR_GetEntityIndex() : -1;
|
||||
}
|
||||
|
||||
// Works out how an accepted hit moved the couch. Skipped when nobody listens; it runs per pellet.
|
||||
@@ -571,22 +612,27 @@ void ReportInteraction(int couch, int client, CouchMethod method, const char[] s
|
||||
Call_Finish();
|
||||
}
|
||||
|
||||
// Couch ban or tier requirement. Tells the client why, or for a ban lets the ban plugin do so.
|
||||
bool IsClientRefused(int couch, int client)
|
||||
// Couch ban or tier requirement. With notify, tells the client why, or for a ban lets the ban plugin do so.
|
||||
bool IsClientRefused(int couch, int client, bool notify = true)
|
||||
{
|
||||
if (g_bBlocked[client])
|
||||
{
|
||||
Call_StartForward(g_fwdOnClientBlocked);
|
||||
Call_PushCell(couch);
|
||||
Call_PushCell(client);
|
||||
Call_Finish();
|
||||
if (notify)
|
||||
{
|
||||
Call_StartForward(g_fwdOnClientBlocked);
|
||||
Call_PushCell(couch);
|
||||
Call_PushCell(client);
|
||||
Call_Finish();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!MeetsTier(client, g_cvMoveTier.IntValue))
|
||||
{
|
||||
PrintHintText(client, "You need to be tier %d or higher to move the couch.", g_cvMoveTier.IntValue);
|
||||
if (notify)
|
||||
PrintHintText(client, "You need to be tier %d or higher to move the couch.", g_cvMoveTier.IntValue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -702,7 +748,7 @@ void LoadGameData()
|
||||
GameData gd = new GameData("Couch");
|
||||
if (gd == null)
|
||||
{
|
||||
LogError("Missing gamedata/Couch.txt; the couch will collide with func_clip_vphysics and couch-banned players can still push it.");
|
||||
LogError("Missing gamedata/Couch.txt; the couch will collide with func_clip_vphysics, couch-banned players can still push it, and +use pushing can't be restricted.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -717,6 +763,12 @@ void LoadGameData()
|
||||
DHookAddParam(g_hForceVPhysicsCollide, HookParamType_CBaseEntity);
|
||||
}
|
||||
|
||||
offset = gd.GetOffset("PlayerUse");
|
||||
if (offset == -1)
|
||||
LogError("Missing \"PlayerUse\" offset in gamedata/Couch.txt; sm_allow_couch_use, tiers and couch bans won't stop +use pushing.");
|
||||
else
|
||||
g_hPlayerUse = DHookCreate(offset, HookType_Entity, ReturnType_Void, ThisPointer_CBaseEntity, Hook_PlayerUse);
|
||||
|
||||
// Collision filter detour for couch bans; enabled only while someone is blocked.
|
||||
g_hShouldCollideDetour = DHookCreateDetour(Address_Null, CallConv_THISCALL, ReturnType_Int, ThisPointer_Address);
|
||||
if (!DHookSetFromConf(g_hShouldCollideDetour, gd, SDKConf_Signature, "CCollisionEvent::ShouldCollide"))
|
||||
|
||||
@@ -125,12 +125,12 @@ native bool Couch_IsPistolOnly();
|
||||
native void Couch_SetPistolOnly(bool enabled);
|
||||
|
||||
/**
|
||||
* Whether players may +use the couch to pick it up. Mirrors sm_allow_couch_use.
|
||||
* Whether players may push the couch by holding +use on it. Mirrors sm_allow_couch_use.
|
||||
*/
|
||||
native bool Couch_IsUseAllowed();
|
||||
|
||||
/**
|
||||
* Allows or forbids picking the couch up with +use; when forbidden it can only be shot. Writes sm_allow_couch_use.
|
||||
* Allows or forbids pushing the couch with +use; when forbidden it can only be shot. Writes sm_allow_couch_use.
|
||||
*/
|
||||
native void Couch_SetUseAllowed(bool allowed);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user