--by pavetr.top/ds if CLIENT then -- Camera configuration local CAMERA_FORWARD = -5 -- Distance from the face local CAMERA_UP = 2.40 -- Camera height local CAMERA_RIGHT = 0.14 -- Side offset local SHOW_DEBUG = false -- Create ConVar for settings local cv_laser = CreateClientConVar("cl_custom_laser", "0", true, false, "Enable/Disable laser sight") local cv_disable_crosshair = CreateClientConVar("cl_disable_crosshair", "1", true, false, "Disable default crosshair") local cv_dynamic_crosshair = CreateClientConVar("cl_dynamic_crosshair", "1", true, false, "Enable dynamic crosshair") -- Add settings menu hook.Add("PopulateToolMenu", "CustomLaserSettings", function() spawnmenu.AddToolMenuOption("Utilities", "User", "CustomLaserSettings", "First Person Settings", "", "", function(panel) panel:ClearControls() panel:CheckBox("Enable laser sight", "cl_custom_laser") panel:CheckBox("Disable default crosshair", "cl_disable_crosshair") panel:CheckBox("Enable dynamic crosshair", "cl_dynamic_crosshair") end) end) -- Hook to always draw the player model in first-person hook.Add("ShouldDrawLocalPlayer", "CustomFP_DrawBody", function(ply) return true end) -- Camera Position Fix hook.Add("CalcView", "CustomFP_PreciseCamera", function(ply, pos, ang, fov) if not IsValid(ply) or not ply:Alive() then return end local headPos = ply:GetShootPos() + Vector(0,0,5) local headAng = ply:EyeAngles() -- Get actual head bone position local boneIndex = ply:LookupBone("ValveBiped.Bip01_Head1") if boneIndex then local bonePos, boneAng = ply:GetBonePosition(boneIndex) if bonePos then headPos = bonePos boneAng:RotateAroundAxis(boneAng:Right(), -90) boneAng:RotateAroundAxis(boneAng:Up(), 90) headAng = boneAng end end local cameraPos = headPos + headAng:Forward() * CAMERA_FORWARD + headAng:Right() * CAMERA_RIGHT + headAng:Up() * CAMERA_UP if SHOW_DEBUG then debugoverlay.Cross(headPos, 5, 0.1, Color(255,0,0)) debugoverlay.Line(headPos, cameraPos, 0.1, Color(0,255,0)) end return { origin = cameraPos, angles = ply:EyeAngles(), fov = fov, drawviewer = false } end) if exechack_api then exechack_api.CalcViewOverlayHook = function(ply, pos, ang, fov) if not IsValid(ply) or not ply:Alive() then return end local headPos = ply:GetShootPos() + Vector(0,0,5) local headAng = ply:EyeAngles() -- Get actual head bone position local boneIndex = ply:LookupBone("ValveBiped.Bip01_Head1") if boneIndex then local bonePos, boneAng = ply:GetBonePosition(boneIndex) if bonePos then headPos = bonePos boneAng:RotateAroundAxis(boneAng:Right(), -90) boneAng:RotateAroundAxis(boneAng:Up(), 90) headAng = boneAng end end local cameraPos = headPos + headAng:Forward() * CAMERA_FORWARD + headAng:Right() * CAMERA_RIGHT + headAng:Up() * CAMERA_UP if SHOW_DEBUG then debugoverlay.Cross(headPos, 5, 0.1, Color(255,0,0)) debugoverlay.Line(headPos, cameraPos, 0.1, Color(0,255,0)) end return { origin = cameraPos, angles = ply:EyeAngles(), fov = fov, drawviewer = false } end end -- Hide ViewModel hook.Add("PreDrawViewModel", "CustomFP_HideVM", function() return true end) -- Laser sight (only visible if enabled) hook.Add("PostDrawOpaqueRenderables", "Custom_LaserPointer", function() if not cv_laser:GetBool() then return end local ply = LocalPlayer() local weapon = ply:GetActiveWeapon() if not IsValid(weapon) then return end local att = weapon:GetAttachment(1) if not att then return end local muzzlePos = att.Pos local muzzleDir = att.Ang:Forward() -- Trace for laser hit position local trace = util.TraceLine({ start = muzzlePos, --endpos = muzzlePos + muzzleDir * 714420, endpos = muzzlePos + muzzleDir * 5000, filter = ply }) -- Draw laser beam render.SetMaterial(Material("cable/redlaser")) render.DrawBeam(muzzlePos, trace.HitPos, 1, 0, 1, Color(255, 0, 0, 255)) -- Draw laser hit sprite render.SetMaterial(Material("sprites/light_glow02_add")) render.DrawSprite(trace.HitPos, 4, 4, Color(255, 0, 0, 255)) end) -- Отключение стандартного прицела hook.Add("HUDShouldDraw", "Custom_DisableDefaultCrosshair", function(name) if cv_disable_crosshair:GetBool() and name == "CHudCrosshair" then return false end end) -- Динамический прицел local function DrawDynamicCrosshair() if not cv_dynamic_crosshair:GetBool() then return end local ply = LocalPlayer() local weapon = ply:GetActiveWeapon() if not IsValid(weapon) then return end -- Получаем позицию и направление ствола local att = weapon:GetAttachment(1) if not att then return end -- Трассировка для определения точки попадания local trace = util.TraceLine({ start = att.Pos, endpos = att.Pos + att.Ang:Forward() * 5000, filter = ply }) -- Преобразуем 3D позицию в 2D экранные координаты local screenPos = trace.HitPos:ToScreen() -- Рисуем прицел в точке попадания surface.SetDrawColor(255, 255, 255, 255) local crossSize = 8 surface.DrawLine( screenPos.x - crossSize, screenPos.y, screenPos.x + crossSize, screenPos.y ) surface.DrawLine( screenPos.x, screenPos.y - crossSize, screenPos.x, screenPos.y + crossSize ) end -- Хук для отрисовки динамического прицела hook.Add("HUDPaint", "Custom_DynamicCrosshair", DrawDynamicCrosshair) end