227 lines
8.6 KiB
Lua
227 lines
8.6 KiB
Lua
|
|
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
|
||
|
|
}
|