Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local stopSpectating, startFreeRoam
- local isSpectating = false
- local specEnt
- local thirdperson = true
- local isRoaming = false
- local roamPos -- the position when roaming free
- local roamVelocity = Vector(0)
- local thirdPersonDistance = 100
- --[[---------------------------------------------------------------------------
- startHooks
- FAdmin tab buttons
- ---------------------------------------------------------------------------]]
- hook.Add("Initialize", "FSpectate", function()
- surface.CreateFont("UiBold", {
- size = 16,
- weight = 800,
- antialias = true,
- shadow = false,
- font = "Default"
- })
- if not FAdmin then return end
- FAdmin.StartHooks["zzSpectate"] = function()
- FAdmin.Commands.AddCommand("Spectate", nil, "<Player>")
- -- Right click option
- FAdmin.ScoreBoard.Main.AddPlayerRightClick("Spectate", function(ply)
- if not IsValid(ply) then return end
- RunConsoleCommand("FSpectate", ply:UserID())
- end)
- local canSpectate = false
- CAMI.PlayerHasAccess(LocalPlayer(), "FSpectate", function(b, _)
- canSpectate = true
- end)
- -- Spectate option in player menu
- FAdmin.ScoreBoard.Player:AddActionButton("Spectate", "fadmin/icons/spectate", Color(0, 200, 0, 255), function(ply) return canSpectate and ply ~= LocalPlayer() end, function(ply)
- if not IsValid(ply) then return end
- RunConsoleCommand("FSpectate", ply:UserID())
- end)
- end
- end)
- --[[---------------------------------------------------------------------------
- Get the thirdperson position
- ---------------------------------------------------------------------------]]
- local function getThirdPersonPos(ent)
- local aimvector = LocalPlayer():GetAimVector()
- local startPos = ent:IsPlayer() and ent:GetShootPos() or ent:LocalToWorld(ent:OBBCenter())
- local endpos = startPos - aimvector * thirdPersonDistance
- local tracer = {
- start = startPos,
- endpos = endpos,
- filter = specEnt
- }
- local trace = util.TraceLine(tracer)
- return trace.HitPos + trace.HitNormal * 10
- end
- --[[---------------------------------------------------------------------------
- Get the CalcView table
- ---------------------------------------------------------------------------]]
- local view = {}
- local function getCalcView()
- if not isRoaming then
- if thirdperson then
- view.origin = getThirdPersonPos(specEnt)
- view.angles = LocalPlayer():EyeAngles()
- else
- view.origin = specEnt:IsPlayer() and specEnt:GetShootPos() or specEnt:LocalToWorld(specEnt:OBBCenter())
- view.angles = specEnt:IsPlayer() and specEnt:EyeAngles() or specEnt:GetAngles()
- end
- roamPos = view.origin
- view.drawviewer = false
- return view
- end
- view.origin = roamPos
- view.angles = LocalPlayer():EyeAngles()
- view.drawviewer = true
- return view
- end
- --[[---------------------------------------------------------------------------
- specCalcView
- Override the view for the player to look through the spectated player's eyes
- ---------------------------------------------------------------------------]]
- local function specCalcView(ply, origin, angles, fov)
- if not IsValid(specEnt) and not isRoaming then
- startFreeRoam()
- return
- end
- view = getCalcView()
- if IsValid(specEnt) then
- specEnt:SetNoDraw(not thirdperson)
- end
- return view
- end
- --[[---------------------------------------------------------------------------
- Find the right player to spectate
- ---------------------------------------------------------------------------]]
- local function findNearestObject()
- local aimvec = LocalPlayer():GetAimVector()
- local fromPos = isRoaming and roamPos or specEnt:EyePos()
- local lookingAt = util.QuickTrace(fromPos, aimvec * 5000, LocalPlayer())
- if IsValid(lookingAt.Entity) then return lookingAt.Entity end
- local foundPly, foundDot = nil, 0
- for _, ply in pairs(player.GetAll()) do
- if ply == LocalPlayer() then continue end
- local pos = ply:GetShootPos()
- local dot = (pos - fromPos):GetNormalized():Dot(aimvec)
- -- Discard players you're not looking at
- if dot < 0.97 then continue end
- -- not a better alternative
- if dot < foundDot then continue end
- local trace = util.QuickTrace(fromPos, pos - fromPos, ply)
- if trace.Hit then continue end
- foundPly, foundDot = ply, dot
- end
- return foundPly
- end
- --[[---------------------------------------------------------------------------
- Spectate the person you're looking at while you're roaming
- ---------------------------------------------------------------------------]]
- local function spectateLookingAt()
- local obj = findNearestObject()
- if not IsValid(obj) then return end
- isRoaming = false
- specEnt = obj
- net.Start("FSpectateTarget")
- net.WriteEntity(obj)
- net.SendToServer()
- end
- --[[---------------------------------------------------------------------------
- specBinds
- Change binds to perform spectate specific tasks
- ---------------------------------------------------------------------------]]
- -- Manual keysDown table, so I can return true in plyBindPress and still detect key presses
- local keysDown = {}
- local function specBinds(ply, bind, pressed)
- local key = input.LookupBinding(bind)
- if bind == "+jump" then
- stopSpectating()
- return true
- elseif bind == "+reload" and pressed then
- local pos = getCalcView().origin - Vector(0, 0, 64)
- RunConsoleCommand("FTPToPos", string.format("%d, %d, %d", pos.x, pos.y, pos.z), string.format("%d, %d, %d", roamVelocity.x, roamVelocity.y, roamVelocity.z))
- stopSpectating()
- elseif bind == "+attack" and pressed then
- if not isRoaming then
- startFreeRoam()
- else
- spectateLookingAt()
- end
- return true
- elseif bind == "+attack2" and pressed then
- if isRoaming then
- roamPos = roamPos + LocalPlayer():GetAimVector() * 500
- return true
- end
- thirdperson = not thirdperson
- return true
- elseif isRoaming and not LocalPlayer():KeyDown(IN_USE) then
- local keybind = string.lower(string.match(bind, "+([a-z A-Z 0-9]+)") or "")
- if not keybind or keybind == "use" or keybind == "showscores" or string.find(bind, "messagemode") then return end
- keysDown[keybind:upper()] = pressed
- return true
- elseif not isRoaming and thirdperson and (key == "MWHEELDOWN" or key == "MWHEELUP") then
- thirdPersonDistance = thirdPersonDistance + 10 * (key == "MWHEELDOWN" and 1 or -1)
- end
- -- Do not return otherwise, spectating admins should be able to move to avoid getting detected
- end
- --[[---------------------------------------------------------------------------
- Scoreboardshow
- Set to main view when roaming, open on a player when spectating
- ---------------------------------------------------------------------------]]
- local function fadminmenushow()
- if isRoaming then
- FAdmin.ScoreBoard.ChangeView("Main")
- elseif IsValid(specEnt) and specEnt:IsPlayer() then
- FAdmin.ScoreBoard.ChangeView("Main")
- FAdmin.ScoreBoard.ChangeView("Player", specEnt)
- end
- end
- --[[---------------------------------------------------------------------------
- RenderScreenspaceEffects
- Draws the lines from players' eyes to where they are looking
- ---------------------------------------------------------------------------]]
- local LineMat = Material("cable/new_cable_lit")
- local linesToDraw = {}
- local function lookingLines()
- if not linesToDraw[0] then return end
- render.SetMaterial(LineMat)
- cam.Start3D(view.origin, view.angles)
- for i = 0, #linesToDraw, 3 do
- render.DrawBeam(linesToDraw[i], linesToDraw[i + 1], 4, 0.01, 10, linesToDraw[i + 2])
- end
- cam.End3D()
- end
- --[[---------------------------------------------------------------------------
- gunpos
- Gets the position of a player's gun
- ---------------------------------------------------------------------------]]
- local function gunpos(ply)
- local wep = ply:GetActiveWeapon()
- if not IsValid(wep) then return ply:EyePos() end
- local att = wep:GetAttachment(1)
- if not att then return ply:EyePos() end
- return att.Pos
- end
- --[[---------------------------------------------------------------------------
- Spectate think
- Free roaming position updates
- ---------------------------------------------------------------------------]]
- local function specThink()
- local ply = LocalPlayer()
- -- Update linesToDraw
- local pls = player.GetAll()
- local lastPly = 0
- local skip = 0
- for i = 0, #pls - 1 do
- local p = pls[i + 1]
- if not isRoaming and p == specEnt and not thirdperson then
- skip = skip + 3
- continue
- end
- local tr = p:GetEyeTrace()
- local sp = gunpos(p)
- local pos = i * 3 - skip
- linesToDraw[pos] = tr.HitPos
- linesToDraw[pos + 1] = sp
- linesToDraw[pos + 2] = team.GetColor(p:Team())
- lastPly = i
- end
- -- Remove entries from linesToDraw that don't match with a player anymore
- for i = #linesToDraw, lastPly * 3 + 3, -1 do
- linesToDraw[i] = nil
- end
- if not isRoaming or keysDown["USE"] then return end
- local roamSpeed = 1000
- local aimVec = ply:GetAimVector()
- local direction
- local frametime = RealFrameTime()
- if keysDown["FORWARD"] then
- direction = aimVec
- elseif keysDown["BACK"] then
- direction = -aimVec
- end
- if keysDown["MOVELEFT"] then
- local right = aimVec:Angle():Right()
- direction = direction and (direction - right):GetNormalized() or -right
- elseif keysDown["MOVERIGHT"] then
- local right = aimVec:Angle():Right()
- direction = direction and (direction + right):GetNormalized() or right
- end
- if keysDown["SPEED"] then
- roamSpeed = 2500
- elseif keysDown["WALK"] or keysDown["DUCK"] then
- roamSpeed = 300
- end
- roamVelocity = (direction or Vector(0, 0, 0)) * roamSpeed
- roamPos = roamPos + roamVelocity * frametime
- end
- --[[---------------------------------------------------------------------------
- Draw help on the screen
- ---------------------------------------------------------------------------]]
- local uiForeground, uiBackground = Color(240, 240, 255, 255), Color(20, 20, 20, 120)
- local red = Color(255, 0, 0, 255)
- local function drawHelp()
- local scrHalfH = math.floor(ScrH() / 2)
- draw.WordBox(2, 10, scrHalfH, "Left click: (Un)select player to spectate", "UiBold", uiBackground, uiForeground)
- draw.WordBox(2, 10, scrHalfH + 20, isRoaming and "Right click: quickly move forwards" or "Right click: toggle thirdperson", "UiBold", uiBackground, uiForeground)
- draw.WordBox(2, 10, scrHalfH + 40, "Jump: Stop spectating", "UiBold", uiBackground, uiForeground)
- draw.WordBox(2, 10, scrHalfH + 60, "Reload: Stop spectating and teleport", "UiBold", uiBackground, uiForeground)
- if FAdmin then
- draw.WordBox(2, 10, scrHalfH + 80, "Opening FAdmin's menu while spectating a player", "UiBold", uiBackground, uiForeground)
- draw.WordBox(2, 10, scrHalfH + 100, "\twill open their page!", "UiBold", uiBackground, uiForeground)
- end
- local target = findNearestObject()
- local pls = player.GetAll()
- for i = 1, #pls do
- local ply = pls[i]
- if not isRoaming and ply == specEnt then continue end
- local pos = ply:GetShootPos():ToScreen()
- if not pos.visible then continue end
- local x, y = pos.x, pos.y
- draw.WordBox(2, x, y - alignment, ply:Nick(), "UiBold", uiBackground, uiForeground)
- if ply:Armor() == 0 then
- draw.WordBox(2, x, y - (alignment - 20), "Health: " .. ply:Health(), "UiBold", uiBackground, uiForeground)
- else
- draw.WordBox(2, x, y - (alignment - 20), "Health: " .. ply:Health() .. " / Armor: " .. ply:Armor(), "UiBold", uiBackground, uiForeground)
- end
- if ply:GetActiveWeapon():IsValid() then
- draw.WordBox(2, x, y - (alignment - 40), ply:GetActiveWeapon():GetPrintName(), "UiBold", uiBackground, uiForeground)
- draw.WordBox(2, x, y - (alignment - 60), ply:GetUserGroup(), "UiBold", uiBackground, uiForeground)
- draw.RoundedBox(2, x, y - (alignment - 80), 12, 12, team.GetColor(ply:Team()))
- else
- draw.WordBox(2, x, y - (alignment - 40), ply:GetUserGroup(), "UiBold", uiBackground, uiForeground)
- draw.RoundedBox(2, x, y - (alignment - 60), 12, 12, team.GetColor(ply:Team()))
- end
- end
- if not isRoaming then return end
- if not IsValid(target) then return end
- local center = target:LocalToWorld(target:OBBCenter())
- local eyeAng = EyeAngles()
- local rightUp = eyeAng:Right() * 16 + eyeAng:Up() * 36
- local topRight = (center + rightUp):ToScreen()
- local bottomLeft = (center - rightUp):ToScreen()
- draw.RoundedBox(12, bottomLeft.x, bottomLeft.y, math.max(20, topRight.x - bottomLeft.x), topRight.y - bottomLeft.y, red)
- draw.WordBox(2, bottomLeft.x, bottomLeft.y + 12, "Left click to spectate!", "UiBold", uiBackground, uiForeground)
- end
- --[[---------------------------------------------------------------------------
- Start roaming free, rather than spectating a given player
- ---------------------------------------------------------------------------]]
- startFreeRoam = function()
- if IsValid(specEnt) and specEnt:IsPlayer() then
- roamPos = thirdperson and getThirdPersonPos(specEnt) or specEnt:GetShootPos()
- specEnt:SetNoDraw(false)
- else
- roamPos = isSpectating and roamPos or LocalPlayer():GetShootPos()
- end
- specEnt = nil
- isRoaming = true
- keysDown = {}
- end
- --[[---------------------------------------------------------------------------
- specEnt
- Spectate a player
- ---------------------------------------------------------------------------]]
- local function startSpectate(um)
- isRoaming = net.ReadBool()
- specEnt = net.ReadEntity()
- specEnt = IsValid(specEnt) and specEnt or nil
- if isRoaming then
- startFreeRoam()
- end
- isSpectating = true
- keysDown = {}
- hook.Add("CalcView", "FSpectate", specCalcView)
- hook.Add("PlayerBindPress", "FSpectate", specBinds)
- hook.Add("ShouldDrawLocalPlayer", "FSpectate", function() return isRoaming or thirdperson end)
- hook.Add("Think", "FSpectate", specThink)
- hook.Add("HUDPaint", "FSpectate", drawHelp)
- hook.Add("FAdmin_ShowFAdminMenu", "FSpectate", fadminmenushow)
- hook.Add("RenderScreenspaceEffects", "FSpectate", lookingLines)
- timer.Create("FSpectatePosUpdate", 0.5, 0, function()
- if not isRoaming then return end
- RunConsoleCommand("_FSpectatePosUpdate", roamPos.x, roamPos.y, roamPos.z)
- end)
- end
- net.Receive("FSpectate", startSpectate)
- --[[---------------------------------------------------------------------------
- stopSpectating
- Stop spectating a player
- ---------------------------------------------------------------------------]]
- stopSpectating = function()
- hook.Remove("CalcView", "FSpectate")
- hook.Remove("PlayerBindPress", "FSpectate")
- hook.Remove("ShouldDrawLocalPlayer", "FSpectate")
- hook.Remove("Think", "FSpectate")
- hook.Remove("HUDPaint", "FSpectate")
- hook.Remove("FAdmin_ShowFAdminMenu", "FSpectate")
- hook.Remove("RenderScreenspaceEffects", "FSpectate")
- timer.Remove("FSpectatePosUpdate")
- if IsValid(specEnt) then
- specEnt:SetNoDraw(false)
- end
- RunConsoleCommand("FSpectate_StopSpectating")
- isSpectating = false
- end
- hook.Add("PlayerButtonDown", "CopySteamidToClipboard", function(ply, button)
- if button == KEY_E then
- if not IsFirstTimePredicted() then return end
- PlyTraceEye = ply:GetEyeTrace().Entity
- if PlyTraceEye:IsPlayer() then
- SetClipboardText(PlyTraceEye:SteamID())
- chat.AddText(Color(255, 0, 0), "SteamID de : ", Color(255, 255, 255), PlyTraceEye:Nick(), Color(255, 0, 0), " copié !")
- end
- end
- if button == KEY_A then
- if not IsFirstTimePredicted() then return end
- --HSVToColor( ( CurTime() * 100 ) % 360, 1, 1 )
- --Color(math.random(1, 255), math.random(1, 255), math.random(1, 255))
- for k, v in ipairs(player.GetAll()) do
- if v:IsAdmin() or v:IsSuperAdmin() then
- chat.AddText(HSVToColor((CurTime() * 100) % 360, 1, 1), "[" .. v:GetUserGroup() .. "] " .. v:Nick() .. " est un staff")
- end
- end
- end
- end)
- function BasicAim()
- local pls = player.GetAll()
- alignment = 66
- for i = 1, #pls do
- local ply = pls[i]
- if not isRoaming and ply == specEnt then continue end
- local pos = ply:GetShootPos():ToScreen()
- if not pos.visible then continue end
- local x, y = pos.x, pos.y
- if isSpectating then return end
- draw.WordBox(2, x, y - alignment, ply:Nick(), "UiBold", uiBackground, uiForeground)
- if ply:Armor() == 0 then
- draw.WordBox(2, x, y - (alignment - 20), "Health: " .. ply:Health(), "UiBold", uiBackground, uiForeground)
- else
- draw.WordBox(2, x, y - (alignment - 20), "Health: " .. ply:Health() .. " / Armor: " .. ply:Armor(), "UiBold", uiBackground, uiForeground)
- end
- if ply:GetActiveWeapon():IsValid() then
- draw.WordBox(2, x, y - (alignment - 40), ply:GetActiveWeapon():GetPrintName(), "UiBold", uiBackground, uiForeground)
- draw.WordBox(2, x, y - (alignment - 60), ply:GetUserGroup(), "UiBold", uiBackground, uiForeground)
- draw.RoundedBox(2, x, y - (alignment - 80), 12, 12, team.GetColor(ply:Team()))
- else
- draw.WordBox(2, x, y - (alignment - 40), ply:GetUserGroup(), "UiBold", uiBackground, uiForeground)
- draw.RoundedBox(2, x, y - (alignment - 60), 12, 12, team.GetColor(ply:Team()))
- end
- end
- end
- hook.Add("HUDPaint", "CoucouleBoss", BasicAim)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement