local thirdperson = CreateConVar("3rdperson", "0", FCVAR_USERINFO) local m_yaw = GetConVar("m_yaw"):GetFloat() local m_pitch = GetConVar("m_pitch"):GetFloat() local view_angle, view_origin = EyeAngles(), EyePos() hook.Add("CalcView", "Cool 3rd Person", function(ply, origin, angles) if not thirdperson:GetBool() then return end -- Use a hull trace to prevent the camera clipping through the world view_origin = util.TraceHull({ start = origin, endpos = origin - view_angle:Forward() * 100 + view_angle:Right() * 15, filter = ply, mask = MASK_SHOT, mins = Vector(-5, -5, -5), maxs = Vector(5, 5, 5), }).HitPos return { angles = view_angle, -- Set the camera view to the calculated angle origin = view_origin, -- Set the origin to be thirdperson drawviewer = true, } end) hook.Add("StartCommand", "Cool 3rd Person", function(ply, cmd) if not thirdperson:GetBool() then return end -- We need to calculate mouse movement ourselves since we need to set the view angles view_angle = view_angle + Angle(cmd:GetMouseY() * m_pitch, cmd:GetMouseX() * -m_yaw, 0) view_angle[1] = math.Clamp(view_angle[1], -89, 89) view_angle[2] = math.NormalizeAngle(view_angle[2]) -- Movement will get wonky in any other MOVETYPE if ply:GetMoveType() == MOVETYPE_WALK then -- Run a trace from the 3rd person camera local view_trace = util.TraceLine({ start = view_origin, endpos = view_origin + view_angle:Forward() * 1e4, filter = ply, mask = MASK_SHOT, }).HitPos -- Update view angles so we're facing where the camera trace hit cmd:SetViewAngles((view_trace - ply:GetShootPos()):Angle()) -- Because we've meddled with the view angle we need to update the movement so it works as expected local move_fix = Vector(cmd:GetForwardMove(), cmd:GetSideMove(), 0) move_fix = (move_fix:Angle() + (cmd:GetViewAngles() - view_angle)):Forward() * move_fix:Length() cmd:SetForwardMove(move_fix[1]) cmd:SetSideMove(move_fix[2]) else cmd:SetViewAngles(view_angle) end end)