Add sm_gotocouch & effect intensity

This commit is contained in:
2026-09-29 02:41:20 +01:00
parent 867b3bfbba
commit 598dc20ae3
3 changed files with 133 additions and 2 deletions
+91 -1
View File
@@ -64,6 +64,7 @@ ConVar g_cvModel;
ConVar g_cvPushScale;
ConVar g_cvPistolOnly;
ConVar g_cvEffect;
ConVar g_cvEffectIntensity;
ConVar g_cvIgnoreClip;
ConVar g_cvCollisionGroup;
@@ -116,6 +117,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
CreateNative("Couch_IsPlaced", Native_IsPlaced);
CreateNative("Couch_Spawn", Native_Spawn);
CreateNative("Couch_Bring", Native_Bring);
CreateNative("Couch_Goto", Native_Goto);
CreateNative("Couch_Remove", Native_Remove);
CreateNative("Couch_IsEffectEnabled", Native_IsEffectEnabled);
CreateNative("Couch_SetEffectEnabled", Native_SetEffectEnabled);
@@ -141,12 +143,14 @@ public void OnPluginStart()
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_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);
g_cvTierRequirement = CreateConVar("sm_couch_tier_requirement", "0", "Minimum playtime tier needed to shoot the couch.", FCVAR_NOTIFY, true, 0.0);
g_cvCollisionGroup = CreateConVar("sm_couch_collision_group", "5", "Collision group given to the couch at spawn. 5 (player), 0 (prop)", FCVAR_NOTIFY, true, 0.0, true, 20.0);
g_cvModel.AddChangeHook(OnModelChanged);
g_cvEffect.AddChangeHook(OnEffectChanged);
g_cvEffectIntensity.AddChangeHook(OnEffectIntensityChanged);
AutoExecConfig(true, "Couch");
@@ -338,6 +342,56 @@ bool TraceFilter_NotSelfOrCouch(int entity, int contentsMask, any client)
return entity != client && entity != GetCouchIndex();
}
// Landing spot for a player sent to the couch: on top of it when it is upright, otherwise beside it.
// The couch is kept solid in the trace so the player never arrives inside it.
#define COUCH_GOTO_LIFT 8.0
#define COUCH_GOTO_SIDE_GAP 24.0
bool FindCouchLandingSpot(int client, int couch, float vecSpot[3])
{
float vecOrigin[3];
float vecMaxs[3];
GetEntPropVector(couch, Prop_Send, "m_vecOrigin", vecOrigin);
GetEntPropVector(couch, Prop_Send, "m_vecMaxs", vecMaxs);
// Tried in order: on top when upright, on top when tipped over, then each side.
float fTop = vecMaxs[2] + COUCH_GOTO_LIFT;
float fTipped = GetVectorLength(vecMaxs) + COUCH_GOTO_LIFT;
float fSideX = vecMaxs[0] + COUCH_GOTO_SIDE_GAP;
float fSideY = vecMaxs[1] + COUCH_GOTO_SIDE_GAP;
float vecOffsets[6][3];
vecOffsets[0][2] = fTop;
vecOffsets[1][2] = fTipped;
vecOffsets[2][0] = fSideX; vecOffsets[2][2] = COUCH_GOTO_LIFT;
vecOffsets[3][0] = -fSideX; vecOffsets[3][2] = COUCH_GOTO_LIFT;
vecOffsets[4][1] = fSideY; vecOffsets[4][2] = COUCH_GOTO_LIFT;
vecOffsets[5][1] = -fSideY; vecOffsets[5][2] = COUCH_GOTO_LIFT;
float vecMins[3];
float vecPlayerMaxs[3];
GetClientMins(client, vecMins);
GetClientMaxs(client, vecPlayerMaxs);
for (int i = 0; i < sizeof(vecOffsets); i++)
{
AddVectors(vecOrigin, vecOffsets[i], vecSpot);
TR_TraceHullFilter(vecSpot, vecSpot, vecMins, vecPlayerMaxs, MASK_PLAYERSOLID, TraceFilter_NotSelf, client);
if (!TR_DidHit())
return true;
}
// Nothing clear; go high above the couch so the command still does something.
AddVectors(vecOrigin, vecOffsets[1], vecSpot);
return false;
}
bool TraceFilter_NotSelf(int entity, int contentsMask, any client)
{
return entity != client;
}
// The only place the couch is created. Returns the entity or -1.
int SpawnCouchAt(const float vecOrigin[3], const float vecAngles[3])
{
@@ -664,6 +718,22 @@ public void OnEffectChanged(ConVar convar, const char[] oldValue, const char[] n
ApplyEffectState();
}
public void OnEffectIntensityChanged(ConVar convar, const char[] oldValue, const char[] newValue)
{
ApplyLightIntensity();
}
// light_dynamic takes brightness as an input, so a running light updates in place.
void ApplyLightIntensity()
{
int light = GetLightIndex();
if (light == -1)
return;
SetVariantInt(g_cvEffectIntensity.IntValue);
AcceptEntityInput(light, "brightness");
}
// Brings the light and beacon in line with sm_couch_effect. Safe to call at any time.
void ApplyEffectState()
{
@@ -699,7 +769,7 @@ int SpawnCouchLight(int couch)
DispatchKeyValue(light, "pitch", "-90");
DispatchKeyValue(light, "angles", "0 0 0");
DispatchKeyValue(light, "_light", "255 255 255 255");
DispatchKeyValue(light, "brightness", "3");
DispatchKeyValueInt(light, "brightness", g_cvEffectIntensity.IntValue);
DispatchKeyValue(light, "distance", "130");
DispatchKeyValue(light, "spotlight_radius", "70");
@@ -839,6 +909,26 @@ public any Native_Bring(Handle plugin, int numParams)
return true;
}
public any Native_Goto(Handle plugin, int numParams)
{
int client = GetNativeCell(1);
if (client < 1 || client > MaxClients || !IsClientInGame(client))
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not in game", client);
int couch = GetCouchIndex();
if (couch == -1)
return false;
float vecSpot[3];
FindCouchLandingSpot(client, couch, vecSpot);
// Arrives still, keeps their view angles.
float vecStill[3];
TeleportEntity(client, vecSpot, NULL_VECTOR, vecStill);
return true;
}
public any Native_Remove(Handle plugin, int numParams)
{
bool bHadSomething = g_bPlaced || GetCouchIndex() != -1;