mirror of
https://github.com/creazy231/cs2-css-flashlight.git
synced 2026-09-27 20:17:04 +02:00
The light was positioned once at toggle time and then handed to the engine via SetParent + SetParentAttachmentMaintainOffset on the pawn's `axis_of_intent` attachment. That attachment carries the body's yaw but not the view pitch, so once parented the beam could only ever rotate horizontally — looking up or down did nothing. Drop the parenting and drive the light's transform ourselves every tick from the pawn's live AbsOrigin and V_angle, which is how the plugin behaved before 0.1.1 replaced the per-tick teleport with a parented entity. Also: - OnTick no longer short-circuits on !AllowUseKey, which otherwise stopped the light updating for servers that only expose css_fl_toggle. - ForwardDistance now offsets the light horizontally only. Applying it along the pitched forward vector put the light below ground when looking straight down (crouched eye height 46 minus 54). - Sweep up the light when the pawn is dead; an un-parented entity no longer dies with its pawn. - Remove the now-unused AttachmentName config key. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
115 lines
3.5 KiB
C#
115 lines
3.5 KiB
C#
using System.Numerics;
|
|
|
|
namespace Flashlight;
|
|
|
|
/// <summary>
|
|
/// Position and orientation to apply to the flashlight entity.
|
|
/// <paramref name="Angles"/> is a Source QAngle laid out as (pitch, yaw, roll).
|
|
/// </summary>
|
|
public readonly record struct LightTransform(Vector3 Origin, Vector3 Angles);
|
|
|
|
public static class FlashlightLogic
|
|
{
|
|
public static bool TryToggle(ref bool isOn, ref bool canToggle)
|
|
{
|
|
if (!canToggle)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
isOn = !isOn;
|
|
canToggle = false;
|
|
return true;
|
|
}
|
|
|
|
public static bool IsUsePressedEdge(bool usePressed, bool wasUsePressed)
|
|
{
|
|
return usePressed && !wasUsePressed;
|
|
}
|
|
|
|
public static float GetEyeOffsetZ(bool isCrouching, float standOffset, float crouchOffset)
|
|
{
|
|
return isCrouching ? crouchOffset : standOffset;
|
|
}
|
|
|
|
public static Vector3 CalculateLightOrigin(
|
|
Vector3 pawnOrigin,
|
|
Vector3 forward,
|
|
float eyeOffsetZ,
|
|
float forwardDistance)
|
|
{
|
|
return new Vector3(
|
|
pawnOrigin.X + forward.X * forwardDistance,
|
|
pawnOrigin.Y + forward.Y * forwardDistance,
|
|
pawnOrigin.Z + eyeOffsetZ + forward.Z * forwardDistance);
|
|
}
|
|
|
|
public static Vector3 ForwardFromAnglesDegrees(float pitch, float yaw)
|
|
{
|
|
var pitchRad = pitch * (MathF.PI / 180f);
|
|
var yawRad = yaw * (MathF.PI / 180f);
|
|
var cosPitch = MathF.Cos(pitchRad);
|
|
|
|
return new Vector3(
|
|
cosPitch * MathF.Cos(yawRad),
|
|
cosPitch * MathF.Sin(yawRad),
|
|
-MathF.Sin(pitchRad));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Forward vector on the horizontal plane only, ignoring pitch.
|
|
/// </summary>
|
|
public static Vector3 HorizontalForwardFromYawDegrees(float yaw)
|
|
{
|
|
var yawRad = yaw * (MathF.PI / 180f);
|
|
|
|
return new Vector3(MathF.Cos(yawRad), MathF.Sin(yawRad), 0f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// World transform for the flashlight given the player's current pawn origin and view angles.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The angles carry the full view rotation so the beam tracks pitch as well as yaw, while the
|
|
/// origin is only pushed forward on the horizontal plane. Offsetting the origin along the full
|
|
/// pitched forward vector would drop the light through the floor when looking straight down
|
|
/// (a crouched eye height of 46 minus a 54 unit offset ends up below the ground).
|
|
/// </remarks>
|
|
public static LightTransform CalculateLightTransform(
|
|
Vector3 pawnOrigin,
|
|
float pitch,
|
|
float yaw,
|
|
float roll,
|
|
float eyeOffsetZ,
|
|
float forwardDistance)
|
|
{
|
|
var forward = HorizontalForwardFromYawDegrees(yaw);
|
|
var origin = CalculateLightOrigin(pawnOrigin, forward, eyeOffsetZ, forwardDistance);
|
|
|
|
return new LightTransform(origin, new Vector3(pitch, yaw, roll));
|
|
}
|
|
|
|
public static bool ShouldCreateLight(bool isOn, bool hasValidLight)
|
|
{
|
|
return isOn && !hasValidLight;
|
|
}
|
|
|
|
public static bool ShouldDestroyLight(bool isOn, bool hasValidLight)
|
|
{
|
|
return !isOn && hasValidLight;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns whether <paramref name="team"/> may use the flashlight.
|
|
/// Team values match CS2: 2 = Terrorist, 3 = Counter-Terrorist.
|
|
/// </summary>
|
|
public static bool IsTeamAllowed(string allowedTeam, byte team)
|
|
{
|
|
return allowedTeam switch
|
|
{
|
|
"T" => team == 2,
|
|
"CT" => team == 3,
|
|
_ => true
|
|
};
|
|
}
|
|
}
|