mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-29 03:01:42 +00:00
ADD - implement phone interaction animations
This commit is contained in:
@@ -235,6 +235,9 @@ function toggleOrientation(): void {
|
||||
},
|
||||
'*',
|
||||
)
|
||||
void nuiCall('camera:setOrientation', {
|
||||
landscape: phone.cameraLandscape,
|
||||
})
|
||||
}
|
||||
|
||||
function setZoom(zoom: (typeof zoomLevels)[number]): void {
|
||||
@@ -353,6 +356,7 @@ onMounted(() => {
|
||||
{ data: { landscape: false }, type: 'camera:orientation' },
|
||||
'*',
|
||||
)
|
||||
void nuiCall('camera:setOrientation', { landscape: false })
|
||||
window.postMessage(
|
||||
{ data: { zoom: selectedZoom.value }, type: 'camera:zoom' },
|
||||
'*',
|
||||
@@ -386,6 +390,7 @@ onBeforeUnmount(() => {
|
||||
'*',
|
||||
)
|
||||
window.postMessage({ type: 'camera:recordCancel' }, '*')
|
||||
void nuiCall('camera:setOrientation', { landscape: false })
|
||||
void nuiCall('camera:setFlash', { enabled: false })
|
||||
void nuiCall('camera:setActive', { active: false })
|
||||
})
|
||||
|
||||
@@ -34,6 +34,40 @@ Config.Calls = {
|
||||
RecentPageSize = 100,
|
||||
}
|
||||
|
||||
Config.Animations = {
|
||||
Enabled = true,
|
||||
PropModel = "prop_npc_phone_02",
|
||||
PropBone = 28422,
|
||||
LoadTimeoutMs = 5000,
|
||||
ContextPollMs = 250,
|
||||
Dictionaries = {
|
||||
OnFoot = "cellphone@",
|
||||
Driver = "anim@cellphone@in_car@ds",
|
||||
Passenger = "anim@cellphone@in_car@ps",
|
||||
Selfie = "anim@mp_player_intuppertake_selfie",
|
||||
},
|
||||
Clips = {
|
||||
TextIn = "cellphone_text_in",
|
||||
TextRead = "cellphone_text_read_base",
|
||||
TextOut = "cellphone_text_out",
|
||||
TextToCall = "cellphone_text_to_call",
|
||||
CallListen = "cellphone_call_listen_base",
|
||||
CallToText = "cellphone_call_to_text",
|
||||
CallOut = "cellphone_call_out",
|
||||
Selfie = "idle_a",
|
||||
},
|
||||
Transforms = {
|
||||
Portrait = {
|
||||
position = { x = 0.0, y = 0.0, z = 0.0 },
|
||||
rotation = { x = 0.0, y = 0.0, z = 0.0 },
|
||||
},
|
||||
Landscape = {
|
||||
position = { x = 0.0, y = 0.0, z = 0.0 },
|
||||
rotation = { x = 0.0, y = 0.0, z = 90.0 },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Config.Messages = {
|
||||
BodyMaxLength = 2000,
|
||||
ConversationScanLimit = 1000,
|
||||
|
||||
@@ -24,6 +24,7 @@ client_scripts {
|
||||
'config/locales/*.lua',
|
||||
'source/bridge/client/framework.lua',
|
||||
'source/bridge/client/callbacks.lua',
|
||||
'source/client/animations.lua',
|
||||
'source/client/camera.lua',
|
||||
'source/client/garage.lua',
|
||||
'source/client/main.lua',
|
||||
|
||||
@@ -0,0 +1,446 @@
|
||||
local MODE_HIDDEN = "hidden"
|
||||
local MODE_PHONE_READ = "phone_read"
|
||||
local MODE_CALL = "call"
|
||||
local MODE_CAMERA_REAR = "camera_rear"
|
||||
local MODE_CAMERA_SELFIE = "camera_selfie"
|
||||
local LOOPED_UPPER_BODY_FLAGS = 49
|
||||
local TRANSITION_UPPER_BODY_FLAGS = 48
|
||||
|
||||
local animation_state = {
|
||||
call_direction = nil,
|
||||
call_state = nil,
|
||||
camera_active = false,
|
||||
camera_front = false,
|
||||
camera_landscape = false,
|
||||
current_animation = nil,
|
||||
current_mode = MODE_HIDDEN,
|
||||
ped = nil,
|
||||
phone_open = false,
|
||||
prop = nil,
|
||||
revision = 0,
|
||||
watcher_active = false,
|
||||
}
|
||||
|
||||
local reevaluate
|
||||
|
||||
local function load_model(model_hash)
|
||||
RequestModel(model_hash)
|
||||
local deadline = GetGameTimer() + Config.Animations.LoadTimeoutMs
|
||||
while not HasModelLoaded(model_hash) do
|
||||
if GetGameTimer() >= deadline then
|
||||
Bridge.Debug(
|
||||
"error",
|
||||
"[sky_phone] Timed out loading phone prop model '%s'.",
|
||||
Config.Animations.PropModel
|
||||
)
|
||||
return false
|
||||
end
|
||||
Wait(0)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function load_animation_dictionary(dictionary)
|
||||
RequestAnimDict(dictionary)
|
||||
local deadline = GetGameTimer() + Config.Animations.LoadTimeoutMs
|
||||
while not HasAnimDictLoaded(dictionary) do
|
||||
if GetGameTimer() >= deadline then
|
||||
Bridge.Debug(
|
||||
"error",
|
||||
"[sky_phone] Timed out loading animation dictionary '%s'.",
|
||||
dictionary
|
||||
)
|
||||
return false
|
||||
end
|
||||
Wait(0)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function can_animate(ped)
|
||||
if not DoesEntityExist(ped) or IsEntityDead(ped) then
|
||||
return false
|
||||
end
|
||||
if IsPedRagdoll(ped) or IsPedFalling(ped) or IsPedClimbing(ped) then
|
||||
return false
|
||||
end
|
||||
if IsPedSwimming(ped) or IsPedSwimmingUnderWater(ped) or IsPedInParachuteFreeFall(ped) then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function get_phone_dictionary(ped)
|
||||
if not IsPedInAnyVehicle(ped, false) then
|
||||
return Config.Animations.Dictionaries.OnFoot, "on_foot"
|
||||
end
|
||||
|
||||
local vehicle = GetVehiclePedIsIn(ped, false)
|
||||
if GetPedInVehicleSeat(vehicle, -1) == ped then
|
||||
return Config.Animations.Dictionaries.Driver, "driver:" .. tostring(vehicle)
|
||||
end
|
||||
return Config.Animations.Dictionaries.Passenger, "passenger:" .. tostring(vehicle)
|
||||
end
|
||||
|
||||
local function derive_mode()
|
||||
if not Config.Animations.Enabled then
|
||||
return MODE_HIDDEN
|
||||
end
|
||||
if animation_state.call_state == "connected" then
|
||||
return MODE_CALL
|
||||
end
|
||||
if animation_state.call_state == "ringing" and animation_state.call_direction == "outgoing" then
|
||||
return MODE_CALL
|
||||
end
|
||||
if animation_state.camera_active and animation_state.camera_front then
|
||||
return MODE_CAMERA_SELFIE
|
||||
end
|
||||
if animation_state.camera_active then
|
||||
return MODE_CAMERA_REAR
|
||||
end
|
||||
if animation_state.call_state == "ringing" or animation_state.phone_open then
|
||||
return MODE_PHONE_READ
|
||||
end
|
||||
return MODE_HIDDEN
|
||||
end
|
||||
|
||||
local function stop_current_animation()
|
||||
local current = animation_state.current_animation
|
||||
if not current then
|
||||
return
|
||||
end
|
||||
|
||||
local ped = animation_state.ped
|
||||
if ped and DoesEntityExist(ped) then
|
||||
StopAnimTask(ped, current.dictionary, current.clip, 3.0)
|
||||
end
|
||||
animation_state.current_animation = nil
|
||||
end
|
||||
|
||||
local function delete_phone_prop()
|
||||
local prop = animation_state.prop
|
||||
if not prop then
|
||||
animation_state.ped = nil
|
||||
return true
|
||||
end
|
||||
if not DoesEntityExist(prop) then
|
||||
animation_state.prop = nil
|
||||
animation_state.ped = nil
|
||||
return true
|
||||
end
|
||||
|
||||
DetachEntity(prop, true, true)
|
||||
SetEntityAsMissionEntity(prop, true, true)
|
||||
DeleteEntity(prop)
|
||||
if DoesEntityExist(prop) then
|
||||
Bridge.Debug("error", "[sky_phone] Failed to delete the attached phone prop.")
|
||||
return false
|
||||
end
|
||||
|
||||
animation_state.prop = nil
|
||||
animation_state.ped = nil
|
||||
return true
|
||||
end
|
||||
|
||||
local function cleanup_phone()
|
||||
stop_current_animation()
|
||||
delete_phone_prop()
|
||||
end
|
||||
|
||||
local function ensure_phone_prop(ped, revision)
|
||||
if animation_state.prop and DoesEntityExist(animation_state.prop) and animation_state.ped == ped then
|
||||
return true
|
||||
end
|
||||
|
||||
if animation_state.prop then
|
||||
delete_phone_prop()
|
||||
end
|
||||
|
||||
local model_hash = joaat(Config.Animations.PropModel)
|
||||
if not load_model(model_hash) then
|
||||
return false
|
||||
end
|
||||
if animation_state.revision ~= revision then
|
||||
SetModelAsNoLongerNeeded(model_hash)
|
||||
return false
|
||||
end
|
||||
|
||||
local coords = GetEntityCoords(ped)
|
||||
local prop = CreateObject(model_hash, coords.x, coords.y, coords.z, true, true, false)
|
||||
SetModelAsNoLongerNeeded(model_hash)
|
||||
if not prop or prop == 0 or not DoesEntityExist(prop) then
|
||||
Bridge.Debug("error", "[sky_phone] Failed to create the phone prop.")
|
||||
return false
|
||||
end
|
||||
|
||||
SetEntityCollision(prop, false, false)
|
||||
animation_state.prop = prop
|
||||
animation_state.ped = ped
|
||||
return true
|
||||
end
|
||||
|
||||
local function get_transform(mode)
|
||||
if (mode == MODE_CAMERA_REAR or mode == MODE_CAMERA_SELFIE) and animation_state.camera_landscape then
|
||||
return Config.Animations.Transforms.Landscape
|
||||
end
|
||||
return Config.Animations.Transforms.Portrait
|
||||
end
|
||||
|
||||
local function attach_phone_prop(ped, mode)
|
||||
local transform = get_transform(mode)
|
||||
local position = transform.position
|
||||
local rotation = transform.rotation
|
||||
AttachEntityToEntity(
|
||||
animation_state.prop,
|
||||
ped,
|
||||
GetPedBoneIndex(ped, Config.Animations.PropBone),
|
||||
position.x,
|
||||
position.y,
|
||||
position.z,
|
||||
rotation.x,
|
||||
rotation.y,
|
||||
rotation.z,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
2,
|
||||
true
|
||||
)
|
||||
end
|
||||
|
||||
local function play_animation(ped, dictionary, clip, looped, revision)
|
||||
if not load_animation_dictionary(dictionary) or animation_state.revision ~= revision then
|
||||
return nil
|
||||
end
|
||||
|
||||
local duration = -1
|
||||
local flags = LOOPED_UPPER_BODY_FLAGS
|
||||
if not looped then
|
||||
local duration_seconds = GetAnimDuration(dictionary, clip)
|
||||
if duration_seconds <= 0.0 then
|
||||
Bridge.Debug(
|
||||
"error",
|
||||
"[sky_phone] Animation '%s' was not found in dictionary '%s'.",
|
||||
clip,
|
||||
dictionary
|
||||
)
|
||||
return nil
|
||||
end
|
||||
duration = math.max(1, math.floor(duration_seconds * 1000.0))
|
||||
flags = TRANSITION_UPPER_BODY_FLAGS
|
||||
end
|
||||
|
||||
stop_current_animation()
|
||||
TaskPlayAnim(ped, dictionary, clip, 4.0, -4.0, duration, flags, 1.0, false, false, false)
|
||||
animation_state.current_animation = {
|
||||
clip = clip,
|
||||
dictionary = dictionary,
|
||||
}
|
||||
return duration
|
||||
end
|
||||
|
||||
local function get_base_animation(ped, mode)
|
||||
local dictionary = get_phone_dictionary(ped)
|
||||
if mode == MODE_CALL then
|
||||
return dictionary, Config.Animations.Clips.CallListen
|
||||
end
|
||||
if mode == MODE_CAMERA_SELFIE and not IsPedInAnyVehicle(ped, false) then
|
||||
return Config.Animations.Dictionaries.Selfie, Config.Animations.Clips.Selfie
|
||||
end
|
||||
return dictionary, Config.Animations.Clips.TextRead
|
||||
end
|
||||
|
||||
local function get_transition_clip(previous_mode, mode)
|
||||
if previous_mode == MODE_HIDDEN then
|
||||
return Config.Animations.Clips.TextIn
|
||||
end
|
||||
if previous_mode == MODE_CALL and mode ~= MODE_CALL then
|
||||
return Config.Animations.Clips.CallToText
|
||||
end
|
||||
if previous_mode ~= MODE_CALL and mode == MODE_CALL then
|
||||
return Config.Animations.Clips.TextToCall
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function apply_visible_mode(previous_mode, mode, revision)
|
||||
local ped = PlayerPedId()
|
||||
if not can_animate(ped) or not ensure_phone_prop(ped, revision) then
|
||||
return
|
||||
end
|
||||
|
||||
attach_phone_prop(ped, mode)
|
||||
local transition_clip = get_transition_clip(previous_mode, mode)
|
||||
if transition_clip then
|
||||
local dictionary = get_phone_dictionary(ped)
|
||||
local duration = play_animation(ped, dictionary, transition_clip, false, revision)
|
||||
if not duration then
|
||||
cleanup_phone()
|
||||
return
|
||||
end
|
||||
Wait(duration)
|
||||
if animation_state.revision ~= revision or not can_animate(ped) then
|
||||
return
|
||||
end
|
||||
attach_phone_prop(ped, mode)
|
||||
end
|
||||
|
||||
local dictionary, clip = get_base_animation(ped, mode)
|
||||
if not play_animation(ped, dictionary, clip, true, revision) then
|
||||
cleanup_phone()
|
||||
end
|
||||
end
|
||||
|
||||
local function apply_hidden_mode(previous_mode, revision)
|
||||
local ped = animation_state.ped
|
||||
if not ped or not DoesEntityExist(ped) or not animation_state.prop or not DoesEntityExist(animation_state.prop) then
|
||||
cleanup_phone()
|
||||
return
|
||||
end
|
||||
|
||||
local clip = previous_mode == MODE_CALL and Config.Animations.Clips.CallOut or Config.Animations.Clips.TextOut
|
||||
local dictionary = get_phone_dictionary(ped)
|
||||
local duration = play_animation(ped, dictionary, clip, false, revision)
|
||||
if not duration then
|
||||
cleanup_phone()
|
||||
return
|
||||
end
|
||||
Wait(duration)
|
||||
if animation_state.revision == revision then
|
||||
cleanup_phone()
|
||||
end
|
||||
end
|
||||
|
||||
local function apply_mode(previous_mode, mode, revision)
|
||||
if mode == MODE_HIDDEN then
|
||||
apply_hidden_mode(previous_mode, revision)
|
||||
return
|
||||
end
|
||||
apply_visible_mode(previous_mode, mode, revision)
|
||||
end
|
||||
|
||||
local function ensure_context_watcher()
|
||||
if animation_state.watcher_active or derive_mode() == MODE_HIDDEN then
|
||||
return
|
||||
end
|
||||
|
||||
animation_state.watcher_active = true
|
||||
CreateThread(function()
|
||||
local observed_ped = nil
|
||||
local observed_context = nil
|
||||
local was_available = false
|
||||
while derive_mode() ~= MODE_HIDDEN do
|
||||
local ped = PlayerPedId()
|
||||
local available = can_animate(ped)
|
||||
local context = "unavailable"
|
||||
if available then
|
||||
local _, current_context = get_phone_dictionary(ped)
|
||||
context = current_context
|
||||
end
|
||||
|
||||
if not available and (was_available or animation_state.prop) then
|
||||
animation_state.revision = animation_state.revision + 1
|
||||
animation_state.current_mode = MODE_HIDDEN
|
||||
cleanup_phone()
|
||||
elseif available and (not was_available or observed_ped ~= ped or observed_context ~= context) then
|
||||
reevaluate(true)
|
||||
end
|
||||
|
||||
observed_ped = ped
|
||||
observed_context = context
|
||||
was_available = available
|
||||
Wait(Config.Animations.ContextPollMs)
|
||||
end
|
||||
animation_state.watcher_active = false
|
||||
end)
|
||||
end
|
||||
|
||||
reevaluate = function(force)
|
||||
local mode = derive_mode()
|
||||
local ped = PlayerPedId()
|
||||
if mode ~= MODE_HIDDEN and not can_animate(ped) then
|
||||
animation_state.revision = animation_state.revision + 1
|
||||
animation_state.current_mode = MODE_HIDDEN
|
||||
cleanup_phone()
|
||||
ensure_context_watcher()
|
||||
return
|
||||
end
|
||||
if mode == animation_state.current_mode and not force then
|
||||
ensure_context_watcher()
|
||||
return
|
||||
end
|
||||
|
||||
local previous_mode = animation_state.current_mode
|
||||
animation_state.current_mode = mode
|
||||
animation_state.revision = animation_state.revision + 1
|
||||
local revision = animation_state.revision
|
||||
ensure_context_watcher()
|
||||
CreateThread(function()
|
||||
apply_mode(previous_mode, mode, revision)
|
||||
end)
|
||||
end
|
||||
|
||||
local function reset_animation_state()
|
||||
animation_state.phone_open = false
|
||||
animation_state.call_state = nil
|
||||
animation_state.call_direction = nil
|
||||
animation_state.camera_active = false
|
||||
animation_state.camera_front = false
|
||||
animation_state.camera_landscape = false
|
||||
animation_state.current_mode = MODE_HIDDEN
|
||||
animation_state.revision = animation_state.revision + 1
|
||||
cleanup_phone()
|
||||
end
|
||||
|
||||
AddEventHandler("sky_phone:animation:phone", function(open)
|
||||
if type(open) ~= "boolean" then
|
||||
Bridge.Debug("warn", "[sky_phone] Ignored invalid phone animation state.")
|
||||
return
|
||||
end
|
||||
animation_state.phone_open = open
|
||||
|
||||
if not open then
|
||||
animation_state.camera_active = false
|
||||
animation_state.camera_front = false
|
||||
animation_state.camera_landscape = false
|
||||
|
||||
if derive_mode() == MODE_HIDDEN then
|
||||
animation_state.current_mode = MODE_HIDDEN
|
||||
animation_state.revision = animation_state.revision + 1
|
||||
cleanup_phone()
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
reevaluate(false)
|
||||
end)
|
||||
|
||||
AddEventHandler("sky_phone:animation:call", function(data)
|
||||
if type(data) ~= "table" or type(data.state) ~= "string" or type(data.direction) ~= "string" then
|
||||
Bridge.Debug("warn", "[sky_phone] Ignored invalid call animation state.")
|
||||
return
|
||||
end
|
||||
animation_state.call_state = data.state
|
||||
animation_state.call_direction = data.direction
|
||||
reevaluate(false)
|
||||
end)
|
||||
|
||||
AddEventHandler("sky_phone:animation:camera", function(data)
|
||||
if type(data) ~= "table" or type(data.active) ~= "boolean" then
|
||||
Bridge.Debug("warn", "[sky_phone] Ignored invalid camera animation state.")
|
||||
return
|
||||
end
|
||||
animation_state.camera_active = data.active and animation_state.phone_open
|
||||
animation_state.camera_front = data.front == true
|
||||
animation_state.camera_landscape = data.landscape == true
|
||||
reevaluate(true)
|
||||
end)
|
||||
|
||||
AddEventHandler("sky_phone:animation:reset", reset_animation_state)
|
||||
|
||||
AddEventHandler("onResourceStop", function(resource_name)
|
||||
if resource_name == GetCurrentResourceName() then
|
||||
reset_animation_state()
|
||||
end
|
||||
end)
|
||||
@@ -14,6 +14,7 @@ local camera_state = {
|
||||
focus_watcher = false,
|
||||
front_camera = false,
|
||||
front_camera_handle = nil,
|
||||
landscape = false,
|
||||
ultrawide_camera_handle = nil,
|
||||
nui_focused = true,
|
||||
previous_ped_view = nil,
|
||||
@@ -181,6 +182,7 @@ local function set_camera_active(active)
|
||||
camera_state.active = active
|
||||
if active then
|
||||
camera_state.front_camera = false
|
||||
camera_state.landscape = false
|
||||
camera_state.zoom = 1.0
|
||||
clear_front_camera()
|
||||
clear_ultrawide_camera()
|
||||
@@ -190,6 +192,11 @@ local function set_camera_active(active)
|
||||
DisplayRadar(false)
|
||||
set_camera_focus(true)
|
||||
apply_camera_view()
|
||||
TriggerEvent("sky_phone:animation:camera", {
|
||||
active = true,
|
||||
front = camera_state.front_camera,
|
||||
landscape = camera_state.landscape,
|
||||
})
|
||||
if camera_state.enforcing then
|
||||
return
|
||||
end
|
||||
@@ -240,6 +247,7 @@ local function set_camera_active(active)
|
||||
end
|
||||
set_flash_enabled(false)
|
||||
camera_state.front_camera = false
|
||||
camera_state.landscape = false
|
||||
clear_front_camera()
|
||||
clear_ultrawide_camera()
|
||||
restore_camera_view()
|
||||
@@ -248,6 +256,11 @@ local function set_camera_active(active)
|
||||
SetNuiFocusKeepInput(false)
|
||||
SetNuiFocus(true, true)
|
||||
end
|
||||
TriggerEvent("sky_phone:animation:camera", {
|
||||
active = false,
|
||||
front = false,
|
||||
landscape = false,
|
||||
})
|
||||
end
|
||||
|
||||
local function set_front_camera(active)
|
||||
@@ -268,6 +281,25 @@ local function set_front_camera(active)
|
||||
end
|
||||
end
|
||||
apply_camera_view()
|
||||
TriggerEvent("sky_phone:animation:camera", {
|
||||
active = true,
|
||||
front = camera_state.front_camera,
|
||||
landscape = camera_state.landscape,
|
||||
})
|
||||
end
|
||||
|
||||
local function set_camera_landscape(active)
|
||||
if camera_state.landscape == active then
|
||||
return
|
||||
end
|
||||
camera_state.landscape = active
|
||||
if camera_state.active then
|
||||
TriggerEvent("sky_phone:animation:camera", {
|
||||
active = true,
|
||||
front = camera_state.front_camera,
|
||||
landscape = camera_state.landscape,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
local function set_camera_zoom(zoom)
|
||||
@@ -314,6 +346,11 @@ RegisterNUICallback("camera:setFacing", function(data, cb)
|
||||
cb({ success = true })
|
||||
end)
|
||||
|
||||
RegisterNUICallback("camera:setOrientation", function(data, cb)
|
||||
set_camera_landscape(data and data.landscape == true)
|
||||
cb({ success = true })
|
||||
end)
|
||||
|
||||
RegisterNUICallback("camera:setZoom", function(data, cb)
|
||||
cb({ success = set_camera_zoom(tonumber(data and data.zoom)) })
|
||||
end)
|
||||
|
||||
@@ -124,6 +124,7 @@ end
|
||||
|
||||
local function close_phone()
|
||||
open_requested = false
|
||||
TriggerEvent("sky_phone:animation:phone", false)
|
||||
if not is_open then
|
||||
return
|
||||
end
|
||||
@@ -192,6 +193,7 @@ RegisterNUICallback("ui:opened", function(_, cb)
|
||||
is_open = true
|
||||
notification_focus = false
|
||||
SetNuiFocus(true, true)
|
||||
TriggerEvent("sky_phone:animation:phone", true)
|
||||
cb({ success = true })
|
||||
end)
|
||||
|
||||
@@ -351,6 +353,7 @@ end)
|
||||
RegisterNetEvent("sky_phone:device:invalidated", function()
|
||||
open_requested = false
|
||||
device_payload = nil
|
||||
TriggerEvent("sky_phone:animation:reset")
|
||||
close_phone()
|
||||
end)
|
||||
|
||||
@@ -465,6 +468,7 @@ end)
|
||||
RegisterNetEvent("sky_phone:call:incoming", function(data)
|
||||
notification_focus = true
|
||||
SetNuiFocus(true, true)
|
||||
TriggerEvent("sky_phone:animation:call", data)
|
||||
SendNUIMessage({ type = "call:incoming", data = data })
|
||||
end)
|
||||
|
||||
@@ -476,6 +480,7 @@ RegisterNetEvent("sky_phone:call:state", function(data)
|
||||
elseif data.state ~= "ringing" then
|
||||
leave_call_voice()
|
||||
end
|
||||
TriggerEvent("sky_phone:animation:call", data)
|
||||
SendNUIMessage({ type = "call:state", data = data })
|
||||
end)
|
||||
|
||||
@@ -494,6 +499,7 @@ AddEventHandler("onResourceStop", function(resource_name)
|
||||
SetNuiFocus(false, false)
|
||||
end
|
||||
|
||||
TriggerEvent("sky_phone:animation:reset")
|
||||
leave_call_voice()
|
||||
|
||||
if Config.Phone.DevelopmentCommand then
|
||||
|
||||
Reference in New Issue
Block a user