-- ============================================================ -- advancedgarages | Système de caméra d'inactivité -- ============================================================ LocalData = { CurrentPlayerCamera = nil, CurrentPlayerCamera_CameraTo = nil, CurrentPlayerCamera_CameraToPosition = { x = 0.0, y = 0.0, z = 0.0 }, IsInVehicle = false, } inactive = false lastInputTime = GetGameTimer() -- ============================================================ -- StartIdleCam : lance la caméra d'inactivité en boucle -- entity : entité autour de laquelle tourner les caméras -- startPos : index de départ dans CameraAnimations (optionnel) -- ============================================================ function StartIdleCam(entity, startPos) if LocalData.CurrentPlayerCamera ~= nil then return end Debug("Starting idle camera", entity, "position", startPos) if #Config.CameraAnimations < 2 then print("No valid camera positions found in config. Please add at least 2 positions.") return end DoScreenFadeOut(1000) CreateThread(function() local animIndex = startPos or 1 if Config.RandomizedPositions and not startPos then animIndex = math.random(1, #Config.CameraAnimations) end while true do if not LocalData.CurrentPlayerCamera then break end local anim = Config.CameraAnimations[animIndex] local fromPos = GetRelativePosition(entity, anim.from, anim.distance) local toPos = GetRelativePosition(entity, anim.to, anim.distance) local entityRot = GetEntityRotation(entity, 2) DoScreenFadeIn(1000) StartCameraTransition(fromPos, entityRot, toPos, entityRot, Config.CameraDuration, anim.fovFrom, anim.fovTo, entity) Wait(Config.CameraDuration - 3000) -- Si on a fourni un startPos fixe, on ne boucle qu'une fois if startPos then break end DoScreenFadeOut(3000) if LocalData.CurrentPlayerCamera == nil then StopCamera() return end Wait(3000) if LocalData.CurrentPlayerCamera == nil then StopCamera() return end animIndex = animIndex + 1 if Config.RandomizedPositions and not startPos then animIndex = math.random(1, #Config.CameraAnimations) end if animIndex > #Config.CameraAnimations then animIndex = 1 end end if not LocalData.CurrentPlayerCamera then StopCamera() end end) end -- ============================================================ -- StartCameraTransition : crée deux caméras et interpole -- fromPos/fromRot : position et rotation de départ -- toPos/toRot : position et rotation de destination -- duration : durée de la transition en ms -- fovFrom/fovTo : champ de vision de départ et d'arrivée -- targetEntity : entité vers laquelle pointer les caméras -- ============================================================ function StartCameraTransition(fromPos, fromRot, toPos, toRot, duration, fovFrom, fovTo, targetEntity) if LocalData.CurrentPlayerCamera then DestroyCam(LocalData.CurrentPlayerCamera) end if LocalData.CurrentPlayerCamera_CameraTo then DestroyCam(LocalData.CurrentPlayerCamera_CameraTo) end LocalData.CurrentPlayerCamera = CreateCamWithParams( "DEFAULT_SCRIPTED_CAMERA", fromPos.x, fromPos.y, fromPos.z, fromRot.x, fromRot.y, fromRot.z, fovFrom, true, 2 ) LocalData.CurrentPlayerCamera_CameraTo = CreateCamWithParams( "DEFAULT_SCRIPTED_CAMERA", toPos.x, toPos.y, toPos.z, toRot.x, toRot.y, toRot.z, fovTo, true, 2 ) PointCamAtEntity(LocalData.CurrentPlayerCamera, targetEntity, 0.0, 0.0, 0.0) PointCamAtEntity(LocalData.CurrentPlayerCamera_CameraTo, targetEntity, 0.0, 0.0, 0.0) SetCamActive(LocalData.CurrentPlayerCamera, true) RenderScriptCams(true, false, 0, true, true) SetCamActiveWithInterp( LocalData.CurrentPlayerCamera_CameraTo, LocalData.CurrentPlayerCamera, duration, 100, 50 ) end -- ============================================================ -- GetRelativePosition : calcule une position autour d'une entité -- entity : entité de référence -- direction : clé de direction ("front-left", "right", "top-middle"…) -- distance : distance depuis le centre de l'entité -- ============================================================ function GetRelativePosition(entity, direction, distance) local entityPos = GetEntityCoords(entity) local forward = GetEntityForwardVector(entity) local up = vector3(0.0, 0.0, 1.0) local right = vector3(-forward.y, forward.x, 0.0) local minDim, maxDim = GetModelDimensions(GetEntityModel(entity)) local height = (maxDim.z - minDim.z) * 2 local width = (maxDim.x - minDim.x) * 2 local halfWidth = width * 0.5 local positions = { ["front-left"] = forward * distance - right * (halfWidth + distance * 0.5), ["front-middle"] = forward * distance, ["front-right"] = forward * distance + right * (halfWidth + distance * 0.5), ["back-left"] = -forward * distance - right * (halfWidth + distance * 0.5), ["back-middle"] = -forward * distance, ["back-right"] = -forward * distance + right * (halfWidth + distance * 0.5), ["left"] = -right * (distance + halfWidth), ["right"] = right * (distance + halfWidth), ["top-left"] = forward * distance - right * (halfWidth + distance * 0.5) + up * (height + distance), ["top-middle"] = up * (height + distance), ["top-right"] = forward * distance + right * (halfWidth + distance * 0.5) + up * (height + distance), ["center"] = vector3(0.0, 0.0, height), ["front-left-diagonal"] = forward * distance * 0.7 - right * (halfWidth + distance * 0.7), ["front-right-diagonal"] = forward * distance * 0.7 + right * (halfWidth + distance * 0.7), ["back-left-diagonal"] = -forward * distance * 0.7 - right * (halfWidth + distance * 0.7), ["back-right-diagonal"] = -forward * distance * 0.7 + right * (halfWidth + distance * 0.7), } return entityPos + positions[direction] end -- ============================================================ -- StopCamera : arrête et détruit les caméras actives -- ============================================================ function StopCamera() if LocalData.CurrentPlayerCamera ~= nil then DestroyCam(LocalData.CurrentPlayerCamera) end if LocalData.CurrentPlayerCamera_CameraTo ~= nil then DestroyCam(LocalData.CurrentPlayerCamera_CameraTo) end LocalData.CurrentPlayerCamera = nil LocalData.CurrentPlayerCamera_CameraTo = nil DoScreenFadeIn(1000) end