227 lines
8.6 KiB
Lua
Raw Normal View History

2025-04-07 01:41:12 +00:00
local angleY = 0.0
local angleZ = 0.0
local cam = nil
local running = false
local gEntity = nil
local gRadius = nil
local gRadiusMax = nil
local gRadiusMin = nil
local scaleform = nil
local scrollIncrements = nil
local isFirstPersonView = false
local function cos(degrees)
return math.cos(math.rad(degrees))
end
local function sin(degrees)
return math.sin(math.rad(degrees))
end
local function setCamPosition()
local entityCoords = GetEntityCoords(gEntity)
local mouseX = GetDisabledControlNormal(0, 1) * 8.0 -- 8x multiplier to make it more sensitive
local mouseY = GetDisabledControlNormal(0, 2) * 8.0
angleZ = angleZ - mouseX -- left / right
angleY = angleY + mouseY -- up / down
angleY = lib.math.clamp(angleY, 0.0, 89.0) -- >=90 degrees will flip the camera, < 0 is underground
local cosAngleZ = cos(angleZ)
local cosAngleY = cos(angleY)
local sinAngleZ = sin(angleZ)
local sinAngleY = sin(angleY)
local offset = vec3(
((cosAngleZ * cosAngleY) + (cosAngleY * cosAngleZ)) / 2 * gRadius,
((sinAngleZ * cosAngleY) + (cosAngleY * sinAngleZ)) / 2 * gRadius,
((sinAngleY)) * gRadius
)
local camPos = vec3(entityCoords.x + offset.x, entityCoords.y + offset.y, entityCoords.z + offset.z)
SetCamCoord(cam, camPos.x, camPos.y, camPos.z)
PointCamAtCoord(cam, entityCoords.x, entityCoords.y, entityCoords.z + 0.5)
end
local function disablePlayerMovement()
DisableControlAction(0, 21, true) -- INPUT_SPRINT | LEFT SHIFT
DisableControlAction(0, 24, true) -- INPUT_ATTACK | LEFT MOUSE BUTTON
DisableControlAction(0, 25, true) -- INPUT_AIM | RIGHT MOUSE BUTTON
DisableControlAction(0, 30, true) -- INPUT_MOVE_LR | D
DisableControlAction(0, 31, true) -- INPUT_MOVE_UD | S
DisableControlAction(0, 36, true) -- INPUT_DUCK | LEFT CTRL
DisableControlAction(0, 47, true) -- INPUT_DETONATE | G
DisableControlAction(0, 58, true) -- INPUT_THROW_GRENADE | G
DisableControlAction(0, 69, true) -- INPUT_VEH_ATTACK | LEFT MOUSE BUTTON
DisableControlAction(0, 75, true) -- INPUT_VEH_EXIT | F
DisableControlAction(0, 140, true) -- INPUT_MELEE_ATTACK_LIGHT | R
DisableControlAction(0, 141, true) -- INPUT_MELEE_ATTACK_HEAVY | Q
DisableControlAction(0, 142, true) -- INPUT_MELEE_ATTACK_ALTERNATE | LEFT MOUSE BUTTON
DisableControlAction(0, 143, true) -- INPUT_MELEE_BLOCK | SPACEBAR
DisableControlAction(0, 257, true) -- INPUT_ATTACK2 | LEFT MOUSE BUTTON
DisableControlAction(0, 263, true) -- INPUT_MELEE_ATTACK1 | R
DisableControlAction(0, 264, true) -- INPUT_MELEE_ATTACK2 | Q
end
local function disableCamMovement()
DisableControlAction(0, 1, true) -- INPUT_LOOK_LR | MOUSE RIGHT
DisableControlAction(0, 2, true) -- INPUT_LOOK_UD | MOUSE DOWN
DisableControlAction(0, 3, true) -- INPUT_LOOK_UP_ONLY | (NONE)
DisableControlAction(0, 4, true) -- INPUT_LOOK_DOWN_ONLY | MOUSE DOWN
DisableControlAction(0, 5, true) -- INPUT_LOOK_LEFT_ONLY | (NONE)
DisableControlAction(0, 6, true) -- INPUT_LOOK_RIGHT_ONLY | MOUSE RIGHT
DisableControlAction(0, 12, true) -- INPUT_WEAPON_WHEEL_UD | MOUSE DOWN
DisableControlAction(0, 13, true) -- INPUT_WEAPON_WHEEL_LR | MOUSE RIGHT
DisableControlAction(0, 200, true) -- INPUT_FRONTEND_PAUSE_ALTERNATE | ESC
end
local function mouseDownListener()
CreateThread(function()
while running do
setCamPosition()
if IsDisabledControlJustReleased(0, 24) or IsControlJustReleased(0, 24) then
SetMouseCursorSprite(3)
return
end
Wait(0)
end
end)
end
local function inputListener()
setCamPosition() -- Set initial cam position, otherwise cam will remain at player until first left click
CreateThread(function()
while running do
DisableControlAction(0, 0, true) -- INPUT_NEXT_CAMERA | V
disablePlayerMovement()
if not isFirstPersonView then
SetMouseCursorActiveThisFrame()
disableCamMovement()
if IsDisabledControlJustPressed(0, 24) or IsControlJustPressed(0, 24) then
SetMouseCursorSprite(4)
mouseDownListener()
end
end
if IsDisabledControlJustReleased(0, 14) or IsControlJustReleased(0, 14) then
if gRadius + scrollIncrements <= gRadiusMax then
gRadius += scrollIncrements
setCamPosition()
end
elseif IsDisabledControlJustReleased(0, 15) or IsControlJustReleased(0, 15) then
if gRadius - scrollIncrements >= gRadiusMin then
gRadius -= scrollIncrements
setCamPosition()
end
end
if IsControlJustPressed(0, 22) or IsControlJustPressed(0, 22) then
local doors = GetNumberOfVehicleDoors(cache.vehicle)
for i = 0, doors do
if GetVehicleDoorAngleRatio(cache.vehicle, i) > 0 then
SetVehicleDoorShut(cache.vehicle, i, false)
else
SetVehicleDoorOpen(cache.vehicle, i, false, false)
end
end
end
if IsDisabledControlJustPressed(0, 0) or IsDisabledControlJustPressed(0, 0) then
isFirstPersonView = not isFirstPersonView
if isFirstPersonView then
SetCamViewModeForContext(1, 4)
RenderScriptCams(false, true, 0, true, false)
else
RenderScriptCams(true, true, 0, true, false)
end
end
Wait(0)
end
end)
end
local function instructionalButton(controlId, text)
ScaleformMovieMethodAddParamPlayerNameString(GetControlInstructionalButton(0, controlId, true))
BeginTextCommandScaleformString('STRING')
AddTextComponentSubstringKeyboardDisplay(text)
EndTextCommandScaleformString()
end
local function showInstructionalButtons()
CreateThread(function()
scaleform = RequestScaleformMovie('instructional_buttons')
while not HasScaleformMovieLoaded(scaleform) do
Wait(0)
end
BeginScaleformMovieMethod(scaleform, 'CLEAR_ALL')
EndScaleformMovieMethod()
BeginScaleformMovieMethod(scaleform, 'SET_DATA_SLOT')
ScaleformMovieMethodAddParamInt(1)
instructionalButton(14, locale('dragCam.zoomOut'))
EndScaleformMovieMethod()
BeginScaleformMovieMethod(scaleform, 'SET_DATA_SLOT')
ScaleformMovieMethodAddParamInt(2)
instructionalButton(15, locale('dragCam.zoomIn'))
EndScaleformMovieMethod()
BeginScaleformMovieMethod(scaleform, 'SET_DATA_SLOT')
ScaleformMovieMethodAddParamInt(3)
instructionalButton(22, locale('dragCam.toggleDoors'))
EndScaleformMovieMethod()
BeginScaleformMovieMethod(scaleform, 'SET_DATA_SLOT')
ScaleformMovieMethodAddParamInt(4)
instructionalButton(0, locale('dragCam.changeView'))
EndScaleformMovieMethod()
BeginScaleformMovieMethod(scaleform, 'DRAW_INSTRUCTIONAL_BUTTONS')
EndScaleformMovieMethod()
BeginScaleformMovieMethod(scaleform, 'SET_BACKGROUND_COLOUR')
ScaleformMovieMethodAddParamInt(0)
ScaleformMovieMethodAddParamInt(0)
ScaleformMovieMethodAddParamInt(0)
ScaleformMovieMethodAddParamInt(80)
EndScaleformMovieMethod()
while running do
DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255, 0)
Wait(0)
end
end)
end
---@param entity integer
---@param radiusOptions? {initial?: number, min?: number, max?: number, scrollIncrements?: number}
local function startDragCam(entity, radiusOptions)
running = true
gEntity = entity
gRadius = radiusOptions?.initial or 5.0
gRadiusMin = radiusOptions?.min or 2.5
gRadiusMax = radiusOptions?.max or 10.0
scrollIncrements = radiusOptions?.scrollIncrements or 0.5
cam = CreateCam('DEFAULT_SCRIPTED_CAMERA', true)
RenderScriptCams(true, true, 0, true, false)
showInstructionalButtons()
inputListener()
end
local function stopDragCam()
running = false
RenderScriptCams(false, true, 0, true, false)
DestroyCam(cam, true)
SetCamViewModeForContext(1, 1)
SetScaleformMovieAsNoLongerNeeded(scaleform)
end
return {
startDragCam = startDragCam,
stopDragCam = stopDragCam
}