--[[ ESX Property - Properties Made Right! Copyright (C) 2025 ESX-Framework This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ]] function CCTV(PropertyID) DoScreenFadeOut(500) Wait(500) local Property = Properties[PropertyID] local CamTakePic = true if Property.cctv.enabled then ESX.TriggerServerCallback("esx_property:CCTV", function(CanCCTV) if CanCCTV then InCCTV = true local NightVision = false local function InstructionButtonMessage(text) BeginTextCommandScaleformString("STRING") AddTextComponentScaleform(text) EndTextCommandScaleformString() end local function CreateInstuctionScaleform(scaleform) local scaleform = RequestScaleformMovie(scaleform) while not HasScaleformMovieLoaded(scaleform) do Wait(0) end PushScaleformMovieFunction(scaleform, "CLEAR_ALL") PopScaleformMovieFunctionVoid() PushScaleformMovieFunction(scaleform, "SET_CLEAR_SPACE") PushScaleformMovieFunctionParameterInt(200) PopScaleformMovieFunctionVoid() if Config.CCTV.PictureWebook ~= "" then PushScaleformMovieFunction(scaleform, "SET_DATA_SLOT") PushScaleformMovieFunctionParameterInt(1) ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(1, Config.CCTV.Controls.Screenshot, true)) InstructionButtonMessage(TranslateCap("take_picture")) PopScaleformMovieFunctionVoid() end PushScaleformMovieFunction(scaleform, "SET_DATA_SLOT") PushScaleformMovieFunctionParameterInt(2) ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(1, Config.CCTV.Controls.Right, true)) ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(1, Config.CCTV.Controls.Left, true)) InstructionButtonMessage(TranslateCap("rot_left_right")) PopScaleformMovieFunctionVoid() PushScaleformMovieFunction(scaleform, "SET_DATA_SLOT") PushScaleformMovieFunctionParameterInt(3) ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(1, Config.CCTV.Controls.Down, true)) ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(1, Config.CCTV.Controls.Up, true)) InstructionButtonMessage(TranslateCap("rot_up_down")) PopScaleformMovieFunctionVoid() PushScaleformMovieFunction(scaleform, "SET_DATA_SLOT") PushScaleformMovieFunctionParameterInt(4) ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(1, Config.CCTV.Controls.ZoomOut, true)) ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(1, Config.CCTV.Controls.ZoomIn, true)) InstructionButtonMessage(TranslateCap("zoom")) PopScaleformMovieFunctionVoid() PushScaleformMovieFunction(scaleform, "SET_DATA_SLOT") PushScaleformMovieFunctionParameterInt(5) ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(1, Config.CCTV.Controls.NightVision, true)) InstructionButtonMessage(TranslateCap("night_vision")) PopScaleformMovieFunctionVoid() PushScaleformMovieFunction(scaleform, "SET_DATA_SLOT") PushScaleformMovieFunctionParameterInt(0) ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(1, Config.CCTV.Controls.Exit, true)) InstructionButtonMessage(TranslateCap("exit")) PopScaleformMovieFunctionVoid() PushScaleformMovieFunction(scaleform, "DRAW_INSTRUCTIONAL_BUTTONS") PopScaleformMovieFunctionVoid() PushScaleformMovieFunction(scaleform, "SET_BACKGROUND_COLOUR") PushScaleformMovieFunctionParameterInt(0) PushScaleformMovieFunctionParameterInt(0) PushScaleformMovieFunctionParameterInt(0) PushScaleformMovieFunctionParameterInt(80) PopScaleformMovieFunctionVoid() return scaleform end ESX.CloseContext() local cctvcam = nil ClearFocus() local playerPed = PlayerPedId() cctvcam = CreateCamWithParams("DEFAULT_SCRIPTED_CAMERA", vector3(Property.Entrance.x, Property.Entrance.y, Property.Entrance.z + Config.CCTV.HeightAboveDoor), 0, 0, 0, Config.CCTV.FOV) SetCamRot(cctvcam, Property.cctv.rot.x, Property.cctv.rot.y, Property.cctv.rot.z, 2) SetCamActive(cctvcam, true) SetTimecycleModifier("scanline_cam_cheap") TriggerServerEvent("p_instance:s:leave") DisableAllControlActions(0) FreezeEntityPosition(playerPed, true) SetEntityCollision(playerPed, false, true) local ShowButtons = true SetEntityVisible(playerPed, false) SetTimecycleModifierStrength(2.0) SetFocusArea(Property.Entrance.x, Property.Entrance.y, Property.Entrance.z, 0.0, 0.0, 0.0) PointCamAtCoord(cctvcam, vector3(Property.Entrance.x, Property.Entrance.y, Property.Entrance.z + Config.CCTV.HeightAboveDoor)) RenderScriptCams(true, false, 1, true, false) Wait(1000) DoScreenFadeIn(500) RequestAmbientAudioBank("Phone_Soundset_Franklin", 0, 0) RequestAmbientAudioBank("HintCamSounds", 0, 0) while IsCamActive(cctvcam) do Wait(5) DisableAllControlActions(0) EnableControlAction(0, 245, true) EnableControlAction(0, 246, true) EnableControlAction(0, 249, true) HideHudComponentThisFrame(7) HideHudComponentThisFrame(8) HideHudComponentThisFrame(9) HideHudComponentThisFrame(6) HideHudComponentThisFrame(19) HideHudAndRadarThisFrame() if ShowButtons then local instructions = CreateInstuctionScaleform("instructional_buttons") DrawScaleformMovieFullscreen(instructions, 255, 255, 255, 255, 0) end -- ROTATE LEFT local getCameraRot = GetCamRot(cctvcam, 2) if IsDisabledControlPressed(0, Config.CCTV.Controls.Left) and getCameraRot.z < Property.cctv.maxleft then PlaySoundFrontend(-1, " FocusIn", "HintCamSounds", false) SetCamRot(cctvcam, getCameraRot.x, 0.0, getCameraRot.z + Config.CCTV.RotateSpeed, 2) end -- ROTATE RIGHT if IsDisabledControlPressed(0, Config.CCTV.Controls.Right) and getCameraRot.z > Property.cctv.maxright then PlaySoundFrontend(-1, " FocusIn", "HintCamSounds", false) SetCamRot(cctvcam, getCameraRot.x, 0.0, getCameraRot.z - Config.CCTV.RotateSpeed, 2) end -- ROTATE UP if IsDisabledControlPressed(0, Config.CCTV.Controls.Up) and getCameraRot.x < Config.CCTV.MaxUpRotation then PlaySoundFrontend(-1, " FocusIn", "HintCamSounds", false) SetCamRot(cctvcam, getCameraRot.x + Config.CCTV.RotateSpeed, 0.0, getCameraRot.z, 2) end if IsDisabledControlPressed(0, Config.CCTV.Controls.Down) and getCameraRot.x > Config.CCTV.MaxDownRotation then PlaySoundFrontend(-1, " FocusIn", "HintCamSounds", false) SetCamRot(cctvcam, getCameraRot.x - Config.CCTV.RotateSpeed, 0.0, getCameraRot.z, 2) end if IsDisabledControlPressed(0, Config.CCTV.Controls.ZoomIn) and GetCamFov(cctvcam) > Config.CCTV.MaxZoom then SetCamFov(cctvcam, GetCamFov(cctvcam) - 1.0) end if IsDisabledControlPressed(0, Config.CCTV.Controls.ZoomOut) and GetCamFov(cctvcam) < Config.CCTV.MinZoom then SetCamFov(cctvcam, GetCamFov(cctvcam) + 1.0) end if IsDisabledControlPressed(0, Config.CCTV.Controls.Down) and getCameraRot.x > Config.CCTV.MaxDownRotation then PlaySoundFrontend(-1, " FocusIn", "HintCamSounds", false) SetCamRot(cctvcam, getCameraRot.x - Config.CCTV.RotateSpeed, 0.0, getCameraRot.z, 2) end SetTextFont(4) SetTextScale(0.8, 0.8) SetTextColour(255, 255, 255, 255) SetTextDropshadow(0.1, 3, 27, 27, 255) BeginTextCommandDisplayText('STRING') AddTextComponentSubstringPlayerName(Property.setName ~= "" and Property.setName or Property.Name) EndTextCommandDisplayText(0.01, 0.01) SetTextFont(4) SetTextScale(0.7, 0.7) SetTextColour(255, 255, 255, 255) SetTextDropshadow(0.1, 3, 27, 27, 255) BeginTextCommandDisplayText('STRING') local year --[[ integer ]] , month --[[ integer ]] , day --[[ integer ]] , hour --[[ integer ]] , minute --[[ integer ]] , second --[[ integer ]] = GetPosixTime() AddTextComponentSubstringPlayerName("" .. day .. "/" .. month .. "/" .. year .. " " .. hour .. ":" .. minute .. ":" .. second) EndTextCommandDisplayText(0.01, 0.055) SetTextFont(4) SetTextScale(0.6, 0.6) SetTextColour(255, 255, 255, 255) SetTextDropshadow(0.1, 3, 27, 27, 255) BeginTextCommandDisplayText('STRING') local Zoom = ((Config.CCTV.FOV - GetCamFov(cctvcam)) / GetCamFov(cctvcam)) * 100 AddTextComponentSubstringPlayerName(TranslateCap("zoom_level", math.floor(Zoom))) EndTextCommandDisplayText(0.01, 0.09) SetTextFont(4) SetTextScale(0.6, 0.6) SetTextColour(255, 255, 255, 255) SetTextDropshadow(0.1, 3, 27, 27, 255) BeginTextCommandDisplayText('STRING') AddTextComponentSubstringPlayerName(NightVision and "Night Vision: Active" or "CCTV System: Active") EndTextCommandDisplayText(0.01, 0.12) if IsDisabledControlPressed(0, Config.CCTV.Controls.Down) and getCameraRot.x > Config.CCTV.MaxDownRotation then PlaySoundFrontend(-1, " FocusIn", "HintCamSounds", false) SetCamRot(cctvcam, getCameraRot.x - Config.CCTV.RotateSpeed, 0.0, getCameraRot.z, 2) end if IsDisabledControlJustPressed(0, 38) then NightVision = not NightVision SetNightvision(NightVision) SetTimecycleModifier("scanline_cam") end if Config.CCTV.PictureWebook ~= "" and IsDisabledControlJustPressed(0, 201) then if CamTakePic then ShowButtons = false Wait(1) PlaySoundFrontend(-1, "Camera_Shoot", "Phone_Soundset_Franklin", 1) ESX.TriggerServerCallback("esx_property:GetWebhook", function(hook) if hook then exports['screenshot-basic']:requestScreenshotUpload(hook, "files[]", function(data) local image = json.decode(data) ESX.ShowNotification(TranslateCap("picture_taken"), "success") SendNUIMessage({link = image.attachments[1].proxy_url}) ESX.ShowNotification(TranslateCap("clipboard"), "success") ShowButtons = true CamTakePic = false SetTimeout(5000, function() CamTakePic = true end) end) end end) else ESX.ShowNotification(TranslateCap("please_wait"), "error") end end if IsDisabledControlPressed(1, Config.CCTV.Controls.Exit) then DoScreenFadeOut(1000) ESX.TriggerServerCallback("esx_property:ExitCCTV", function(CanExit) if CanExit then InCCTV = false Wait(1000) ClearFocus() ClearTimecycleModifier() ClearExtraTimecycleModifier() RenderScriptCams(false, false, 0, true, false) DestroyCam(cctvcam, false) SetFocusEntity(playerPed) SetNightvision(false) SetSeethrough(false) SetEntityCollision(playerPed, true, true) FreezeEntityPosition(playerPed, false) SetEntityVisible(playerPed, true) Wait(1500) DoScreenFadeIn(1000) end end, PropertyID) break end end end end, PropertyID) end end