192 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			192 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| local Wait = Citizen.Wait
 | |
| local vector3 = vector3
 | |
| local IsPauseMenuActive = IsPauseMenuActive
 | |
| local GetSmartControlNormal = GetSmartControlNormal
 | |
| 
 | |
| local SETTINGS = _G.CONTROL_SETTINGS
 | |
| local CONTROLS = _G.CONTROL_MAPPING
 | |
| 
 | |
| -------------------------------------------------------------------------------
 | |
| local function GetSpeedMultiplier()
 | |
|   local fastNormal = GetSmartControlNormal(CONTROLS.MOVE_FAST)
 | |
|   local slowNormal = GetSmartControlNormal(CONTROLS.MOVE_SLOW)
 | |
| 
 | |
|   local baseSpeed = SETTINGS.BASE_MOVE_MULTIPLIER
 | |
|   local fastSpeed = 1 + ((SETTINGS.FAST_MOVE_MULTIPLIER - 1) * fastNormal)
 | |
|   local slowSpeed = 1 + ((SETTINGS.SLOW_MOVE_MULTIPLIER - 1) * slowNormal)
 | |
| 
 | |
|   local frameMultiplier = GetFrameTime() * 60
 | |
|   local speedMultiplier = baseSpeed * fastSpeed / slowSpeed
 | |
| 
 | |
|   return speedMultiplier * frameMultiplier
 | |
| end
 | |
| 
 | |
| local function UpdateCamera()
 | |
|   if not IsFreecamActive() or IsPauseMenuActive() then
 | |
|     return
 | |
|   end
 | |
| 
 | |
|   if not IsFreecamFrozen() then
 | |
|     local vecX, vecY = GetFreecamMatrix()
 | |
|     local vecZ = vector3(0, 0, 1)
 | |
| 
 | |
|     local pos = GetFreecamPosition()
 | |
|     local rot = GetFreecamRotation()
 | |
| 
 | |
|     -- Get speed multiplier for movement
 | |
|     local speedMultiplier = GetSpeedMultiplier()
 | |
| 
 | |
|     -- Get rotation input
 | |
|     local lookX = GetSmartControlNormal(CONTROLS.LOOK_X)
 | |
|     local lookY = GetSmartControlNormal(CONTROLS.LOOK_Y)
 | |
| 
 | |
|     -- Get position input
 | |
|     local moveX = GetSmartControlNormal(CONTROLS.MOVE_X)
 | |
|     local moveY = GetSmartControlNormal(CONTROLS.MOVE_Y)
 | |
|     local moveZ = GetSmartControlNormal(CONTROLS.MOVE_Z)
 | |
| 
 | |
|     -- Calculate new rotation.
 | |
|     local rotX = rot.x + (-lookY * SETTINGS.LOOK_SENSITIVITY_X)
 | |
|     local rotZ = rot.z + (-lookX * SETTINGS.LOOK_SENSITIVITY_Y)
 | |
|     local rotY = rot.y
 | |
| 
 | |
|     -- Adjust position relative to camera rotation.
 | |
|     pos = pos + (vecX * moveX * speedMultiplier)
 | |
|     pos = pos + (vecY * -moveY * speedMultiplier)
 | |
|     pos = pos + (vecZ * moveZ * speedMultiplier)
 | |
| 
 | |
|     -- Adjust new rotation
 | |
|     rot = vector3(rotX, rotY, rotZ)
 | |
| 
 | |
|     -- Update camera
 | |
| 
 | |
|     if pos ~= GetFreecamPosition() then
 | |
|       SetFreecamPosition(pos)
 | |
|     end
 | |
| 
 | |
|     SetFreecamRotation(rot)
 | |
| 
 | |
|     return pos, rotZ
 | |
|   end
 | |
| 
 | |
|   -- Trigger a tick event. Resources depending on the freecam position can
 | |
|   -- make use of this event.
 | |
|   -- TriggerEvent('freecam:onTick')
 | |
| end
 | |
| 
 | |
| -------------------------------------------------------------------------------
 | |
| function StartFreecamThread()
 | |
|   -- Camera/Pos updating thread
 | |
|   Citizen.CreateThread(function()
 | |
|     local ped = cache.ped
 | |
|     SetFreecamPosition(GetEntityCoords(ped))
 | |
| 
 | |
|     local function updatePos(pos, rotZ)
 | |
|       -- Update ped
 | |
|       SetEntityCoords(ped, pos.x, pos.y, pos.z, true, false, false, false)
 | |
| 
 | |
|       -- Update veh
 | |
|       local veh = cache.seat == -1 and cache.vehicle
 | |
| 
 | |
|       if veh then
 | |
|         SetEntityCoords(veh, pos.x, pos.y, pos.z, true, false, false, false)
 | |
|       end
 | |
| 
 | |
|       SetEntityHeading(ped, rotZ)
 | |
|     end
 | |
| 
 | |
|     local frameCounter = 0
 | |
|     local loopPos, loopRotZ
 | |
|     while IsFreecamActive() do
 | |
|       loopPos, loopRotZ = UpdateCamera()
 | |
|       frameCounter += 1
 | |
|       if frameCounter > 100 then
 | |
|         frameCounter = 0
 | |
|         if loopPos then
 | |
|           updatePos(loopPos, loopRotZ)
 | |
|         end
 | |
|       end
 | |
|       Wait(0)
 | |
|     end
 | |
| 
 | |
|     -- One last time due to the optimization
 | |
|     updatePos(loopPos, loopRotZ)
 | |
|   end)
 | |
| 
 | |
|   local function InstructionalButton(controlButton, text)
 | |
|     ScaleformMovieMethodAddParamPlayerNameString(controlButton)
 | |
|     BeginTextCommandScaleformString("STRING")
 | |
|     AddTextComponentSubstringKeyboardDisplay(text)
 | |
|     EndTextCommandScaleformString()
 | |
|   end
 | |
| 
 | |
|   --Scaleform drawing thread
 | |
|   Citizen.CreateThread(function()
 | |
|     local scaleform = RequestScaleformMovie("instructional_buttons")
 | |
|     while not HasScaleformMovieLoaded(scaleform) do
 | |
|       Wait(1)
 | |
|     end
 | |
|     BeginScaleformMovieMethod(scaleform, "CLEAR_ALL")
 | |
|     EndScaleformMovieMethod()
 | |
| 
 | |
|     BeginScaleformMovieMethod(scaleform, "SET_CLEAR_SPACE")
 | |
|     ScaleformMovieMethodAddParamInt(200)
 | |
|     EndScaleformMovieMethod()
 | |
| 
 | |
|     BeginScaleformMovieMethod(scaleform, "SET_DATA_SLOT")
 | |
|     ScaleformMovieMethodAddParamInt(0)
 | |
|     InstructionalButton(GetControlInstructionalButton(0, CONTROLS.MOVE_FAST, true), "Faster")
 | |
|     EndScaleformMovieMethod()
 | |
| 
 | |
|     BeginScaleformMovieMethod(scaleform, "SET_DATA_SLOT")
 | |
|     ScaleformMovieMethodAddParamInt(1)
 | |
|     InstructionalButton(GetControlInstructionalButton(0, CONTROLS.MOVE_SLOW, true), "Slower")
 | |
|     EndScaleformMovieMethod()
 | |
| 
 | |
|     BeginScaleformMovieMethod(scaleform, "SET_DATA_SLOT")
 | |
|     ScaleformMovieMethodAddParamInt(2)
 | |
|     InstructionalButton(GetControlInstructionalButton(0, CONTROLS.MOVE_Y, true), "Fwd/Back")
 | |
|     EndScaleformMovieMethod()
 | |
| 
 | |
|     BeginScaleformMovieMethod(scaleform, "SET_DATA_SLOT")
 | |
|     ScaleformMovieMethodAddParamInt(3)
 | |
|     InstructionalButton(GetControlInstructionalButton(0, CONTROLS.MOVE_X, true), "Left/Right")
 | |
|     EndScaleformMovieMethod()
 | |
| 
 | |
|     BeginScaleformMovieMethod(scaleform, "SET_DATA_SLOT")
 | |
|     ScaleformMovieMethodAddParamInt(4)
 | |
|     InstructionalButton(GetControlInstructionalButton(0, CONTROLS.MOVE_Z[2], true), "Down")
 | |
|     EndScaleformMovieMethod()
 | |
| 
 | |
|     BeginScaleformMovieMethod(scaleform, "SET_DATA_SLOT")
 | |
|     ScaleformMovieMethodAddParamInt(5)
 | |
|     InstructionalButton(GetControlInstructionalButton(0, CONTROLS.MOVE_Z[1], true), "Up")
 | |
|     EndScaleformMovieMethod()
 | |
| 
 | |
|     BeginScaleformMovieMethod(scaleform, "DRAW_INSTRUCTIONAL_BUTTONS")
 | |
|     EndScaleformMovieMethod()
 | |
| 
 | |
|     BeginScaleformMovieMethod(scaleform, "SET_BACKGROUND_COLOUR")
 | |
|     ScaleformMovieMethodAddParamInt(0)
 | |
|     ScaleformMovieMethodAddParamInt(0)
 | |
|     ScaleformMovieMethodAddParamInt(0)
 | |
|     ScaleformMovieMethodAddParamInt(80)
 | |
|     EndScaleformMovieMethod()
 | |
| 
 | |
|     while IsFreecamActive() do
 | |
|       DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255, 0)
 | |
|       Wait(0)
 | |
|     end
 | |
| 
 | |
|     SetScaleformMovieAsNoLongerNeeded(scaleform)
 | |
|   end)
 | |
| end
 | |
| 
 | |
| --------------------------------------------------------------------------------
 | |
| 
 | |
| -- When the resource is stopped, make sure to return the camera to the player.
 | |
| AddEventHandler('onResourceStop', function(resourceName)
 | |
|   if resourceName == GetCurrentResourceName() then
 | |
|     SetFreecamActive(false)
 | |
|   end
 | |
| end)
 | 
