Files

93 lines
3.1 KiB
Lua
Raw Permalink Normal View History

Dialogue = {}
2025-02-22 06:42:11 -06:00
local promises = {}
2025-02-23 08:42:57 -06:00
local activeDialogue = nil
local pendingCameraDestroy = false
local cam = nil
local npc = nil
2025-02-21 11:02:18 -06:00
2025-02-23 18:04:53 -06:00
function Dialogue.Close(name)
2025-02-23 08:42:57 -06:00
-- Instead of destroying immediately, wait to see if new dialogue opens
pendingCameraDestroy = true
activeDialogue = nil
2025-03-07 04:24:35 -05:00
2025-02-23 08:42:57 -06:00
SetNuiFocus(false, false)
2025-02-22 06:42:11 -06:00
SendNUIMessage({
type = "close",
name = name
})
2025-02-23 08:42:57 -06:00
-- Wait brief moment to see if new dialogue opens
CreateThread(function()
2025-11-14 18:36:35 -06:00
Wait(200) -- Small delay to allow new dialogue to open
2025-02-23 08:42:57 -06:00
if pendingCameraDestroy and not activeDialogue then
-- No new dialogue opened, safe to destroy camera
RenderScriptCams(false, true, 1000, true, false)
2025-02-23 08:42:57 -06:00
SetCamActive(cam, false)
DestroyCam(cam, false)
cam = nil
end
end)
2025-03-07 04:24:35 -05:00
2025-02-22 06:42:11 -06:00
promises[name] = nil
end
2025-02-21 11:02:18 -06:00
--- Open a dialogue with the player
---@param name string
---@param dialogue string
---@param characterOptions number|table entity or entity and offset/rotationOffset
---@param dialogueOptions table
---@param onSelected function
---@return any
2025-02-23 18:04:53 -06:00
function Dialogue.Open( name, dialogue, characterOptions, dialogueOptions, onSelected)
2025-02-23 10:23:07 -06:00
assert(name, "Name is required")
assert(dialogue, "Dialogue is required")
assert(dialogueOptions, "Dialogue options are required")
assert(characterOptions, "CharacterOptions must be a number or table containing an entity")
local isCharacterATable = type(characterOptions) == "table"
local entity = isCharacterATable and characterOptions.entity or tonumber(characterOptions)
local offset = isCharacterATable and characterOptions.offset or vector3(0, 0, 0)
local rotationOffset = isCharacterATable and characterOptions.rotationOffset or vector3(0, 0, 0)
2025-02-23 08:42:57 -06:00
-- Cancel any pending camera destroy
pendingCameraDestroy = false
activeDialogue = name
2025-03-07 04:24:35 -05:00
if entity then
2025-06-04 18:06:53 -05:00
Wait(500)
2025-11-14 19:34:47 -06:00
local endLocation = GetOffsetFromEntityInWorldCoords(entity, offset.x, offset.y + 2.0, offset.z)
local pedHeading = GetEntityHeading(entity) -- Get position in front of ped based on their heading
2025-03-07 04:24:35 -05:00
if not cam then cam = CreateCam("DEFAULT_SCRIPTED_CAMERA", true) end
2025-06-04 18:06:53 -05:00
local camAngle = (pedHeading + 180.0) % 360.0
SetCamRot(cam, rotationOffset.x, rotationOffset.y, camAngle + rotationOffset.z, 2)
SetCamCoord(cam, endLocation.x, endLocation.y, endLocation.z)
RenderScriptCams(true, true, 1000, true, false)
SetCamActive(cam, true)
2025-02-23 08:42:57 -06:00
end
2025-02-21 11:02:18 -06:00
SendNUIMessage({
type = "open",
text = dialogue,
name = name,
2025-02-23 10:23:07 -06:00
options = dialogueOptions
2025-02-21 11:02:18 -06:00
})
2025-02-22 06:42:11 -06:00
SetNuiFocus(true, true)
2025-03-07 04:24:35 -05:00
2025-02-28 16:08:18 -06:00
local prom = promise.new()
2025-03-07 04:24:35 -05:00
local wrappedFunction = function(selected)
2025-02-22 06:42:11 -06:00
SetNuiFocus(false, false)
2025-02-23 18:04:53 -06:00
Dialogue.Close(name)
2025-02-28 16:08:18 -06:00
if onSelected then onSelected(selected) end
prom:resolve(selected)
2025-02-22 06:42:11 -06:00
end
promises[name] = wrappedFunction
2025-02-28 16:08:18 -06:00
return Citizen.Await(prom)
2025-02-21 11:02:18 -06:00
end
2025-02-22 06:42:11 -06:00
RegisterNuiCallback("dialogue:SelectOption", function(data)
local promis = promises[data.name]
if not promis then return end
promis(data.id)
end)
2025-02-21 11:02:18 -06:00
return Dialogue