168 lines
7.1 KiB
Lua
168 lines
7.1 KiB
Lua
Scaleform = Scaleform or Require("client/scaleform.lua")
|
|||
|
|
Utility = Utility or Require("client/utility.lua")
|
||
|
|
Gizmo = Gizmo or Require("client/gizmo.lua")
|
||
|
|
|
||
|
|
PlaceableObject = PlaceableObject or {}
|
||
|
|
local data = {
|
||
|
|
entity = nil,
|
||
|
|
placing = false,
|
||
|
|
}
|
||
|
|
|
||
|
|
function PlaceableObject.Eyetrace(depth, disableSphere)
|
||
|
|
local screenX = GetDisabledControlNormal(0, 239)
|
||
|
|
local screenY = GetDisabledControlNormal(0, 240)
|
||
|
|
|
||
|
|
local world, normal = GetWorldCoordFromScreenCoord(screenX, screenY)
|
||
|
|
local playerPos = GetEntityCoords(PlayerPedId())
|
||
|
|
local target = playerPos + normal * depth
|
||
|
|
if not disableSphere then
|
||
|
|
DrawSphere(target.x, target.y, target.z, 0.5, 255, 0, 0, 0.5)
|
||
|
|
end
|
||
|
|
return target
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Creates a placeable object in the game world.
|
||
|
|
-- @param model (string) The model of the object to create.
|
||
|
|
-- @param onConfirm (function) [optional] The callback function to execute when the object is confirmed.
|
||
|
|
-- @param onUpdate (function) [optional] The callback function to execute when the object is moved.
|
||
|
|
-- @param onCancel (function) [optional] The callback function to execute when the object is canceled.
|
||
|
|
-- @param settings (table) [optional] Additional settings for the placeable object.
|
||
|
|
-- - depthMin (number) The minimum depth for the object placement. Default is 2.0.
|
||
|
|
-- - depthMax (number) The maximum depth for the object placement. Default is 10.0.
|
||
|
|
-- - rotationStep (number) The rotation step for the object. Default is 15.0.
|
||
|
|
-- - depthStep (number) The depth step for the object. Default is 1.0.
|
||
|
|
function PlaceableObject.Create(data, model, onConfirm, onUpdate, onCancel, settings, config)
|
||
|
|
local settings = settings or {}
|
||
|
|
local depthMin = settings.depthMin or 2.0
|
||
|
|
depthMax = settings.depthMax or 10.0
|
||
|
|
rotationStep = settings.rotationStep or 15.0
|
||
|
|
depthStep = settings.depthStep or 1.0
|
||
|
|
local depth = settings.depth or 10.0
|
||
|
|
print(depth)
|
||
|
|
data.placing = true
|
||
|
|
data.paused = false
|
||
|
|
local initialPos = nil
|
||
|
|
local placeOnGround = true
|
||
|
|
|
||
|
|
--scaleform
|
||
|
|
local scaleform = Scaleform.SetupInstructionalButtons({
|
||
|
|
{type = "CLEAR_ALL"},
|
||
|
|
{type = "SET_CLEAR_SPACE", int = 200},
|
||
|
|
{type = "SET_DATA_SLOT", name = config?.place_object?.name or 'Place Object:', keyIndex = config?.place_object?.key or {223}, int = 5},
|
||
|
|
{type = "SET_DATA_SLOT", name = config?.cancel_placement?.name or 'Cancel Placement:', keyIndex = config?.cancel_placement?.key or {222}, int = 4},
|
||
|
|
{type = "SET_DATA_SLOT", name = config?.snap_to_ground?.name or 'Snap to Ground:', keyIndex = config?.snap_to_ground?.key or {19}, int = 1},
|
||
|
|
{type = "SET_DATA_SLOT", name = config?.rotate?.name or 'Rotate:', keyIndex = config?.rotate?.key or {14, 15}, int = 2},
|
||
|
|
{type = "SET_DATA_SLOT", name = config?.distance?.name or 'Distance:', keyIndex = config?.distance?.key or {14,15,36}, int = 3},
|
||
|
|
{type = "SET_DATA_SLOT", name = config?.toggle_placement?.name or 'Toggle Placement:', keyIndex = config?.toggle_placement?.key or {199}, int = 0},
|
||
|
|
{type = "SET_DATA_SLOT", name = config?.gizmo?.name or 'Toggle Gizmo:', keyIndex = config?.gizmo?.key or {38}, int = 6},
|
||
|
|
{type = "DRAW_INSTRUCTIONAL_BUTTONS"},
|
||
|
|
{type = "SET_BACKGROUND_COLOUR"},
|
||
|
|
})
|
||
|
|
CreateThread(function()
|
||
|
|
local heading = -GetEntityHeading(PlayerPedId())
|
||
|
|
|
||
|
|
local pos = PlaceableObject.Eyetrace(depth)
|
||
|
|
if not data.spawned and model then
|
||
|
|
--get player heading
|
||
|
|
local obj = Utility.CreateProp(model, pos, vector3(0, 0, heading), nil)
|
||
|
|
data.spawned = obj
|
||
|
|
end
|
||
|
|
assert(data.spawned, "Failed to create object")
|
||
|
|
SetEntityCollision(data.spawned, false, false)
|
||
|
|
SetEntityAlpha(data.spawned, 150, false)
|
||
|
|
|
||
|
|
SetPedConfigFlag(PlayerPedId(), 146, true)
|
||
|
|
SetCanClimbOnEntity(data.spawned, false)
|
||
|
|
SetEntityCompletelyDisableCollision(data.spawned, true, false)
|
||
|
|
SetEntityNoCollisionEntity(PlayerPedId(), data.spawned, false)
|
||
|
|
|
||
|
|
while data.placing do
|
||
|
|
if data.paused then goto continue end
|
||
|
|
DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255, 0)
|
||
|
|
DisableControlAction(0, 24, true) -- Attack
|
||
|
|
DisableControlAction(0, 25, true) -- Aim
|
||
|
|
DisableControlAction(0, 36, true) -- INPUT_DUCK.
|
||
|
|
|
||
|
|
if IsControlJustPressed(0, 223) then -- left click
|
||
|
|
if onConfirm and type(onConfirm) == 'function' then onConfirm(data.spawned, pos, heading) end
|
||
|
|
data.placing = false
|
||
|
|
end
|
||
|
|
|
||
|
|
if IsControlJustPressed(0, 222) then -- right click
|
||
|
|
data.placing = false
|
||
|
|
if onCancel and type(onCancel) == 'function' then
|
||
|
|
onCancel(data.spawned, pos, heading)
|
||
|
|
else
|
||
|
|
DeleteEntity(data.spawned)
|
||
|
|
end
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
if IsControlPressed(0,19) then
|
||
|
|
placeOnGround = not (placeOnGround or false)
|
||
|
|
end
|
||
|
|
|
||
|
|
if IsControlJustPressed(0, 38) then -- TAB key to switch to gizmo
|
||
|
|
data.placing = false
|
||
|
|
return Gizmo.UseGizmo(data.spawned, onConfirm, onUpdate, onCancel)
|
||
|
|
end
|
||
|
|
|
||
|
|
if IsControlPressed(0,224) then -- left ctrl
|
||
|
|
if IsControlJustPressed(0, 261) then -- scroll up
|
||
|
|
depth = depth + depthStep
|
||
|
|
if depth > depthMax then
|
||
|
|
depth = depthMax
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if IsControlJustPressed(0, 262) then -- scroll down
|
||
|
|
depth = depth - depthStep
|
||
|
|
if depth < depthMin then
|
||
|
|
depth = depthMin
|
||
|
|
end
|
||
|
|
end
|
||
|
|
else
|
||
|
|
if IsControlJustPressed(0, 261) then -- scroll up
|
||
|
|
heading = heading + rotationStep
|
||
|
|
if heading > 360 then
|
||
|
|
heading = 0
|
||
|
|
end
|
||
|
|
end
|
||
|
|
if IsControlJustPressed(0, 262) then -- scroll down
|
||
|
|
heading = heading - rotationStep
|
||
|
|
if heading < 0 then
|
||
|
|
heading = 360
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
pos = PlaceableObject.Eyetrace(depth)
|
||
|
|
if data.spawned then
|
||
|
|
SetEntityCoords(data.spawned, pos.x, pos.y, pos.z)
|
||
|
|
SetEntityHeading(data.spawned, heading)
|
||
|
|
if placeOnGround then
|
||
|
|
PlaceObjectOnGroundProperly(data.spawned)
|
||
|
|
pos = GetEntityCoords(data.spawned)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
if onUpdate and type(onUpdate) == 'function' then onUpdate(data.spawned, pos, heading) end
|
||
|
|
::continue::
|
||
|
|
if IsControlJustPressed(0, 199) then -- home
|
||
|
|
data.paused = not data.paused
|
||
|
|
end
|
||
|
|
Wait(1)
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
RegisterCommand("testers", function()
|
||
|
|
PlaceableObject.Create({}, "prop_beachflag_01", function(entity, pos, heading)
|
||
|
|
|
||
|
|
end, function(entity, pos, heading)
|
||
|
|
|
||
|
|
end, function(entity, pos, heading)
|
||
|
|
|
||
|
|
end)
|
||
|
|
end)
|