Scripts/resources/[custom_script]/keep-companion/client/menu.lua

849 lines
28 KiB
Lua
Raw Normal View History

2024-12-29 19:48:41 +00:00
QBCore = exports['qb-core']:GetCoreObject()
local isMenuOpen = false
PlayerData = nil
PlayerJob = nil
local alreadyHunting = {
state = false
}
local function updatePlayerJob()
repeat
Wait(10)
until QBCore.Functions.GetPlayerData().job ~= nil
PlayerJob = QBCore.Functions.GetPlayerData().job
end
local function isModelK9(model)
for key, k9 in pairs(Config.k9.models) do
if model == k9 then
return true
end
end
return false
end
-- action menu
local menu = {
[1] = {
lable = Lang:t('menu.action_menu.follow'),
TYPE = 'Follow',
-- triggerNotification = {'onSuccess', 'onFailed'},
-- and action should retrun a bool value true == onSuccess ,false == onFailed
triggerNotification = { 'PETNAME følger dig!', 'PETNAME stoppede med at følge dig!' },
action = function(plyped, activePed)
doSomethingIfPedIsInsideVehicle(activePed.entity)
return TaskFollowTargetedPlayer(activePed.entity, plyped, 3.0, false)
end
},
[2] = {
lable = Lang:t('menu.action_menu.hunt'),
TYPE = 'Hunt',
triggerNotification = { 'PETNAME er på jagt!', 'PETNAME er ikke i stand til det!' },
action = function(plyped, activePed)
local min_lvl_to_hunt = Config.Settings.minHuntingAbilityLevel
if activePed.canHunt ~= true then
QBCore.Functions.Notify(Lang:t('menu.action_menu.error.pet_unable_to_hunt'), 'error', 5000)
return false
end
if alreadyHunting.state ~= false then
QBCore.Functions.Notify(Lang:t('menu.action_menu.error.already_hunting_something'), 'error', 5000)
return
end
if activePed.itemData.info.level <= min_lvl_to_hunt then
local msg = Lang:t('menu.action_menu.error.not_meet_min_requirement_to_hunt')
msg = string.format(msg, min_lvl_to_hunt)
QBCore.Functions.Notify(msg, 'error', 5000)
return false
end
doSomethingIfPedIsInsideVehicle(activePed.entity)
return attackLogic(alreadyHunting)
end
},
[3] = {
lable = Lang:t('menu.action_menu.hunt_and_grab'),
TYPE = 'HuntandGrab',
action = function(plyped, activePed)
local min_lvl_to_hunt = Config.Settings.minHuntingAbilityLevel
if activePed.canHunt ~= true then
QBCore.Functions.Notify(Lang:t('menu.action_menu.error.pet_unable_to_hunt'), 'error', 5000)
return false
end
if activePed.itemData.info.level <= min_lvl_to_hunt then
local msg = Lang:t('menu.action_menu.error.not_meet_min_requirement_to_hunt')
msg = string.format(msg, min_lvl_to_hunt)
QBCore.Functions.Notify(msg, 'error', 5000)
return false
end
doSomethingIfPedIsInsideVehicle(activePed.entity)
HuntandGrab(plyped, activePed)
return true
end
},
[4] = {
lable = Lang:t('menu.action_menu.go_there'),
TYPE = 'There',
action = function(plyped, activePed)
doSomethingIfPedIsInsideVehicle(activePed.entity)
goThere(activePed.entity)
end
},
[5] = {
lable = Lang:t('menu.action_menu.wait'),
TYPE = 'Wait',
action = function(plyped, activePed)
doSomethingIfPedIsInsideVehicle(activePed.entity)
ClearPedTasks(activePed.entity)
end
},
[6] = {
lable = Lang:t('menu.action_menu.get_in_car'),
TYPE = 'GetinCar',
action = function(plyped, activePed)
getIntoCar()
end
},
[7] = {
lable = 'Søg person',
TYPE = 'SearchPerson',
action = function(plyped, activePed)
SearchLogic(plyped, activePed)
end
},
[8] = {
lable = 'Søg bil',
TYPE = 'SearchCar',
show = function(activePed)
if not PlayerJob then return false end
if not (PlayerJob.name == 'police') then return false end
return isModelK9(activePed.model)
end,
action = function(plyped, activePed)
local vehicle = QBCore.Functions.GetClosestVehicle()
k9SearchVehicle(vehicle, activePed)
end
}
}
local coo = {
[1] = {
offset = vector4(-1.5, 0.0, 0.0, -90.0),
},
[2] = {
offset = vector4(0.0, -2.8, 0.0, 0.0),
},
-- [3] = {
-- offset = vector4(1.5, 0.0, 0.0, -270.0),
-- },
}
function k9SearchVehicle(veh, activePed)
if not isModelK9(activePed.model) then
QBCore.Functions.Notify('Det kan dit dyr ikke!', "error", 1500)
return
end
if not PlayerJob then return end
if not (PlayerJob.name == 'police') then
QBCore.Functions.Notify('Det må du ikke', "error", 1500)
return
end
if not PlayerJob.onduty == true then
QBCore.Functions.Notify('Det må du ikke', "error", 1500)
return
end
for key, value in pairs(coo) do
local vehHead = GetEntityHeading(veh)
local plate = GetVehicleNumberPlateText(veh)
local pos = GetOffsetFromEntityInWorldCoords(veh, value.offset.x, value.offset.y, value.offset.z)
TaskFollowNavMeshToCoord(activePed.entity, pos, 3.0, -1, 0.0, true, 0)
Wait(4000)
TaskAchieveHeading(activePed.entity, vehHead + value.offset.w, -1)
Wait(2000)
QBCore.Functions.TriggerCallback('keep-companion:server:search_vehicle', function(result)
if result then
SetAnimalMood(activePed.entity, 1)
PlayAnimalVocalization(activePed.entity, 3, 'bark')
Animator(activePed.entity, activePed.model, 'misc', {
animation = 'indicate_high',
sequentialTimings = {
-- How close the value is to the Timeout value determines how fast the script moves to the next animation.
[1] = 6, -- start animation Timeout ==> 1sec(6s-5s) to loop
[2] = 0, -- loop animation Timeout ==> 6sec(6s-0s) to exit
[3] = 2, -- exit animation Timeout ==> 4sec(6s-2s) to end
step = 1,
Timeout = 6
}
})
return
end
Animator(activePed.entity, activePed.model, 'siting', {
animation = 'sit',
sequentialTimings = {
-- How close the value is to the Timeout value determines how fast the script moves to the next animation.
[1] = 6, -- start animation Timeout ==> 1sec(6s-5s) to loop
[2] = 0, -- loop animation Timeout ==> 6sec(6s-0s) to exit
[3] = 2, -- exit animation Timeout ==> 4sec(6s-2s) to end
step = 1,
Timeout = 6
}
})
end, {
key = key,
plate = plate
})
Wait(3000)
end
end
function k9EnterVehicle(k9, veh)
local vehCoords = GetEntityCoords(veh)
local forwardX = GetEntityForwardX(veh) * 2.0
local forwardY = GetEntityForwardY(veh) * 2.0
SetVehicleDoorOpen(veh, 5, false)
TaskFollowNavMeshToCoord(k9, vehCoords.x - forwardX, vehCoords.y - forwardY, vehCoords.z, 4.0, -1, 1.0, 1, 1)
Wait(5000)
TaskAchieveHeading(k, GetEntityHeading(veh), -1)
RequestAnimDict("creatures@rottweiler@in_vehicle@van", true)
RequestAnimDict("creatures@rottweiler@amb@world_dog_sitting@base", true)
while not HasAnimDictLoaded("creatures@rottweiler@in_vehicle@van") or
not HasAnimDictLoaded("creatures@rottweiler@amb@world_dog_sitting@base") do
Citizen.Wait(0)
end
TaskPlayAnim(k9, "creatures@rottweiler@in_vehicle@van", "get_in", 8.0, -4.0, -1, 2, 0.0, false, false, false)
Wait(1100)
ClearPedTasks(k9)
AttachEntityToEntity(k9, veh, GetEntityBoneIndexByName(veh, "chassis"), 0.0, -0.8, 0.6, 0.0, 0.0, 0.0, false, false,
false, false, 0, true)
TaskPlayAnim(k9, "creatures@rottweiler@amb@world_dog_sitting@base", "base", 8.0, -4.0, -1, 1, 0.0, false, false,
false)
Wait(500)
SetVehicleDoorShut(veh, 5, false)
end
-- tricks menu
local menu2 = {
[1] = {
lable = Lang:t('menu.action_menu.beg'),
TYPE = 'Beg',
icon = 'fa-solid fa-arrows-rotate',
action = function(plyped, activePed)
Animator(activePed.entity, activePed.model, 'tricks', {
animation = 'beg',
sequentialTimings = {
-- How close the value is to the Timeout value determines how fast the script moves to the next animation.
[1] = 6, -- start animation Timeout ==> 1sec(6s-5s) to loop
[2] = 0, -- loop animation Timeout ==> 6sec(6s-0s) to exit
[3] = 2, -- exit animation Timeout ==> 4sec(6s-2s) to end
step = 1,
Timeout = 6
}
})
end
},
[2] = {
lable = Lang:t('menu.action_menu.paw'),
TYPE = 'Paw',
icon = 'fa-solid fa-paw',
action = function(plyped, activePed)
Animator(activePed.entity, activePed.model, 'tricks', {
animation = 'paw'
})
end
},
[3] = {
lable = Lang:t('menu.action_menu.play_dead'),
TYPE = 'Playdead',
icon = 'fa-solid fa-face-dizzy',
action = function(plyped, activePed)
-- PlayFacialAnim(activePed.entity, "dying_facial", "creatures@rottweiler@move")
Animator(activePed.entity, activePed.model, 'misc', {
animation = 'play_dead',
c_timings = 'STOP_LAST_FRAME'
})
end
},
}
local function replaceString(s)
local x
x = s:gsub("PETNAME", ActivePed.read().itemData.info.name)
return x
end
-- Command
AddEventHandler('keep-companion:client:actionMenuDispatcher', function(option)
local plyped = PlayerPedId()
local activePed = ActivePed.read()
activePed.entity = NetworkGetEntityFromNetworkId(activePed.netId)
for key, values in pairs(option.menu) do
if option.type == values.TYPE then
if values.action(plyped, activePed) == true then
if values.triggerNotification ~= nil then
QBCore.Functions.Notify(replaceString(values.triggerNotification[1]), 'success', 1500)
end
else
if values.triggerNotification ~= nil then
QBCore.Functions.Notify(replaceString(values.triggerNotification[2]))
end
end
end
end
end)
function get_correct_icon(model)
for key, value in pairs(Config.pets) do
if model == value.model then
for w in value.distinct:gmatch("%S+") do
if w == 'dog' then
return 'fa-solid fa-dog'
elseif w == 'rabbit' then
return 'fa-solid fa-paw'
elseif w == 'hen' then
return 'fa-solid fa-kiwi-bird'
end
end
end
end
return 'fa-solid fa-cat'
end
AddEventHandler('keep-companion:client:main_menu', function()
local name = ActivePed.read().itemData.info.name
local model = ActivePed.read().model
local icon = get_correct_icon(model)
local header = string.format(Lang:t('menu.main_menu.header'), name)
local sub_header = Lang:t('menu.main_menu.sub_header')
-- header
local openMenu = { {
header = header,
txt = sub_header,
icon = icon,
isMenuHeader = true
}, {
header = Lang:t('menu.main_menu.btn_actions'),
icon = 'fa-solid fa-circle-play',
params = {
event = "keep-companion:client:action_menu"
}
}, {
header = Lang:t('menu.main_menu.btn_switchcontrol'),
txt = "",
icon = 'fa-solid fa-repeat',
params = {
event = "keep-companion:client:switchControl_menu"
}
}, {
header = Lang:t('menu.general_menu_items.btn_leave'),
txt = "",
icon = 'fa-solid fa-circle-xmark',
params = {
event = "qb-menu:closeMenu"
}
} }
exports['qb-menu']:openMenu(openMenu)
end)
AddEventHandler('keep-companion:client:action_menu', function()
local name = ActivePed.read().itemData.info.name
local header = string.format(Lang:t('menu.action_menu.header'), name)
local sub_header = Lang:t('menu.action_menu.sub_header')
local model = ActivePed.read().model
local icon = get_correct_icon(model)
-- header
local openMenu = {
{
header = Lang:t('menu.general_menu_items.btn_back'),
icon = 'fa-solid fa-angle-left',
params = {
event = "keep-companion:client:main_menu",
}
},
{
header = header,
txt = sub_header,
icon = icon,
isMenuHeader = true
}
}
for key, value in ipairs(menu) do
if value.show then
if not value.show(ActivePed.read()) then
goto here
end
end
openMenu[#openMenu + 1] = {
header = value.lable,
icon = 'fa-solid fa-' .. key,
txt = value.desc or "",
params = {
event = "keep-companion:client:actionMenuDispatcher",
args = {
type = value.TYPE,
menu = menu
}
}
}
::here::
end
openMenu[#openMenu + 1] = {
header = Lang:t('menu.action_menu.tricks'),
icon = 'fa-solid fa-' .. #openMenu - 1,
txt = "",
params = {
event = "keep-companion:client:tricks_menu"
}
}
-- leave menu
openMenu[#openMenu + 1] = {
header = Lang:t('menu.general_menu_items.btn_leave'),
txt = "",
icon = 'fa-solid fa-circle-xmark',
params = {
event = "qb-menu:closeMenu"
}
}
exports['qb-menu']:openMenu(openMenu)
end)
AddEventHandler('keep-companion:client:tricks_menu', function()
local name = ActivePed.read().itemData.info.name
local header = string.format(Lang:t('menu.tricks.header'), name)
local sub_header = Lang:t('menu.tricks.sub_header')
local model = ActivePed.read().model
local icon = get_correct_icon(model)
-- header
local openMenu = {
{
header = Lang:t('menu.general_menu_items.btn_back'),
icon = 'fa-solid fa-angle-left',
params = {
event = "keep-companion:client:action_menu",
}
},
{
header = header,
txt = sub_header,
icon = icon,
isMenuHeader = true
}
}
for key, value in pairs(menu2) do
openMenu[#openMenu + 1] = {
header = value.lable,
txt = value.desc or "",
icon = value.icon,
params = {
event = "keep-companion:client:actionMenuDispatcher",
args = {
type = value.TYPE,
menu = menu2
}
}
}
end
-- leave menu
openMenu[#openMenu + 1] = {
header = Lang:t('menu.general_menu_items.btn_leave'),
txt = "",
icon = 'fa-solid fa-circle-xmark',
params = {
event = "qb-menu:closeMenu"
}
}
exports['qb-menu']:openMenu(openMenu)
end)
AddEventHandler('keep-companion:client:switchControl_menu', function()
local name = ActivePed.read().itemData.info.name
local header = string.format(Lang:t('menu.switchControl_menu.header'), name)
local sub_header = name
-- header
local openMenu = {
{
header = Lang:t('menu.general_menu_items.btn_back'),
icon = 'fa-solid fa-angle-left',
params = {
event = "keep-companion:client:main_menu",
}
},
{
header = header,
txt = sub_header,
icon = 'fa-solid fa-list-check',
isMenuHeader = true
}
}
for key, value in pairs(ActivePed:petsList()) do
openMenu[#openMenu + 1] = {
header = value.name,
icon = 'fa-solid fa-' .. key,
params = {
event = "keep-companion:client:switchControl_event",
args = {
index = value.key
}
}
}
end
-- leave menu
openMenu[#openMenu + 1] = {
header = Lang:t('menu.general_menu_items.btn_leave'),
txt = "",
icon = 'fa-solid fa-circle-xmark',
params = {
event = "qb-menu:closeMenu"
}
}
exports['qb-menu']:openMenu(openMenu)
end)
AddEventHandler('keep-companion:client:switchControl_event', function(option)
if option.index < 0 then
return
end
ActivePed:switchControl(option.index)
TriggerEvent('keep-companion:client:action_menu')
end)
local function IsPoliceOrEMS()
return (PlayerJob.name == "police" or PlayerJob.name == "ambulance")
end
local function IsDowned()
return (PlayerData.metadata["isdead"] or PlayerData.metadata["inlaststand"])
end
local function Ishandcuffed()
return PlayerData.metadata["ishandcuffed"]
end
RegisterKeyMapping('+showMenu', 'Vis kæledyrsmenu', 'keyboard', Config.Settings.petMenuKeybind)
RegisterCommand('+showMenu', function()
updatePlayerJob()
if ((IsDowned() and IsPoliceOrEMS()) or not IsDowned()) and not Ishandcuffed() and not IsPauseMenuActive() and
not isMenuOpen then
local doesPlayerHavePet = ActivePed:read()
if doesPlayerHavePet == nil then
QBCore.Functions.Notify(Lang:t('error.no_pet_under_control'), 'error', 5000)
return
end
TriggerEvent('keep-companion:client:main_menu')
end
end, false)
-- This will update all the PlayerData that doesn't get updated with a specific event other than this like the metadata
RegisterNetEvent('QBCore:Player:SetPlayerData', function(val)
PlayerData = val
end)
-- =======================================
-- Customization menu
-- =======================================
RegisterNetEvent('keep-companion:client:start_grooming_process', function()
local activePed = ActivePed:read()
if type(activePed) ~= "table" then
QBCore.Functions.Notify(Lang:t('error.no_pet_under_control'), 'error', 5000)
return
end
TriggerServerEvent('keep-companion:server:grooming_process', activePed.itemData)
end)
RegisterNetEvent('keep-companion:client:initialization_process', function(item, pet_information)
if type(item) ~= "table" then
QBCore.Functions.Notify(Lang:t('error.failed_to_start_procces'), 'error', 5000)
return
end
if pet_information.type == 'init' then
TriggerEvent('keep-companion:client:openMenu_customization', {
item = item, pet_information = pet_information
})
return
end
local hasitem = QBCore.Functions.HasItem(Config.core_items.groomingkit.item_name)
if not hasitem then QBCore.Functions.Notify('Du skal bruge et frisøt sæt', 'error', 5000) return end
TriggerEvent('keep-companion:client:openMenu_customization', {
item = item, pet_information = pet_information
})
end)
AddEventHandler('keep-companion:client:openMenu_customization', function(data)
openMenu_customization(data)
end)
AddEventHandler('keep-companion:client:openMenu_customization_rename', function(data)
openMenu_customization_rename(data)
end)
local function rename(data)
local inputData = exports['qb-input']:ShowInput(
{
header = Lang:t('menu.customization_menu.rename.inputs.header'),
submitText = Lang:t('menu.general_menu_items.confirm'),
inputs = {
{
type = 'text',
isRequired = true,
name = 'name',
text = "name"
},
}
}
)
if inputData then
if not inputData.name then
return
end
local validation = ValidatePetName(inputData.name, 12)
if type(validation) == "table" and next(validation) ~= nil then
QBCore.Functions.Notify(Lang:t('error.failed_to_validate_name'), 'error', 5000)
if validation.reason == 'badword' then
QBCore.Functions.Notify(Lang:t('error.badword_inside_pet_name'), 'error', 5000)
print_table(validation.words)
TriggerEvent('keep-companion:client:openMenu_customization_rename', data)
return
elseif validation.reason == 'maxCharacter' then
QBCore.Functions.Notify(Lang:t('error.more_than_one_word_as_name'), 'error', 5000)
TriggerEvent('keep-companion:client:openMenu_customization_rename', data)
return
end
return
end
data.item.info.name = inputData.name
TriggerEvent('keep-companion:client:openMenu_customization_rename', data)
end
end
AddEventHandler('keep-companion:client:openMenu_customization_rename:rename', function(data)
rename(data)
end)
AddEventHandler('keep-companion:client:openMenu_customization_select_variation', function(data)
if data.selected ~= nil then
data.item.info.variation = data.selected
end
openMenu_customization_select_variation(data)
end)
local function change_variation(data)
local item = data.item
local pet_information = data.pet_information
local openMenu = {
{
header = Lang:t('menu.general_menu_items.btn_back'),
icon = 'fa-solid fa-angle-left',
params = {
event = "keep-companion:client:openMenu_customization_select_variation",
args = {
item = item,
pet_information = pet_information
}
}
},
{
header = Lang:t('menu.variation_menu.selection_menu.header'),
icon = 'fa-solid fa-rectangle-list',
isMenuHeader = true,
disabled = true
},
}
for key, value in pairs(pet_information.pet_variation_list) do
openMenu[#openMenu + 1] = {
header = Lang:t('menu.variation_menu.selection_menu.btn_variation_items') .. value,
txt = Lang:t('menu.variation_menu.selection_menu.btn_desc'),
icon = 'fa-solid fa-brush',
params = {
event = "keep-companion:client:openMenu_customization_select_variation",
args = {
selected = value,
item = item,
pet_information = pet_information
}
}
}
end
exports['qb-menu']:openMenu(openMenu)
end
AddEventHandler('keep-companion:client:openMenu_customization_variation:variation_menu', function(data)
change_variation(data)
end)
-- customization menu
function openMenu_customization(data)
-- header
local c_name = data.item.info.name
local c_variation = data.item.info.variation
local openMenu = {
{
header = Lang:t('menu.customization_menu.header'),
txt = Lang:t('menu.customization_menu.sub_header'),
icon = 'fa-solid fa-pen-to-square',
isMenuHeader = true
},
{
header = Lang:t('menu.customization_menu.btn_rename'),
txt = Lang:t('menu.customization_menu.btn_txt_btn_rename') .. c_name,
icon = 'fa-regular fa-keyboard',
disabled = data.pet_information.disable.rename,
params = {
event = "keep-companion:client:openMenu_customization_rename",
args = {
item = data.item,
pet_information = data.pet_information
},
}
},
{
header = Lang:t('menu.customization_menu.btn_select_variation'),
txt = Lang:t('menu.customization_menu.btn_txt_select_variation') .. c_variation,
icon = 'fa-solid fa-brush',
params = {
event = "keep-companion:client:openMenu_customization_select_variation",
args = {
item = data.item,
pet_information = data.pet_information
},
}
},
{
header = Lang:t('menu.general_menu_items.confirm'),
icon = 'fa-solid fa-circle-check',
params = {
event = "keep-companion:client:openMenu_customization:confirm",
args = {
item = data.item,
pet_information = data.pet_information
}
}
},
{
header = Lang:t('menu.general_menu_items.btn_leave'),
txt = "",
icon = 'fa-solid fa-circle-xmark',
params = {
event = "qb-menu:closeMenu"
}
}
}
exports['qb-menu']:openMenu(openMenu)
end
function openMenu_customization_rename(data)
local item = data.item
local pet_information = data.pet_information
local c_name = item.info.name
-- header
local openMenu = {
{
header = Lang:t('menu.general_menu_items.btn_back'),
icon = 'fa-solid fa-angle-left',
params = {
event = "keep-companion:client:openMenu_customization",
args = {
item = item,
pet_information = pet_information
},
}
},
{
header = Lang:t('menu.rename_menu.header'),
icon = 'fa-solid fa-pen-to-square',
txt = c_name,
isMenuHeader = true,
disabled = true
},
{
header = Lang:t('menu.rename_menu.btn_rename'),
icon = 'fa-regular fa-keyboard',
params = {
event = "keep-companion:client:openMenu_customization_rename:rename",
args = {
item = item,
pet_information = pet_information
},
}
},
}
exports['qb-menu']:openMenu(openMenu)
end
function openMenu_customization_select_variation(data)
-- header
local item = data.item
local pet_information = data.pet_information
local openMenu = {
{
header = Lang:t('menu.general_menu_items.btn_back'),
icon = 'fa-solid fa-angle-left',
params = {
event = "keep-companion:client:openMenu_customization",
args = {
item = item,
pet_information = pet_information
}
}
},
{
header = Lang:t('menu.variation_menu.header'),
txt = item.info.variation,
icon = 'fa-solid fa-palette',
isMenuHeader = true,
disabled = true
},
{
header = Lang:t('menu.variation_menu.btn_select_variation'),
txt = Lang:t('menu.variation_menu.btn_txt_select_variation'),
icon = 'fa-solid fa-brush',
params = {
event = "keep-companion:client:openMenu_customization_variation:variation_menu",
args = {
item = item,
pet_information = pet_information
}
}
},
}
exports['qb-menu']:openMenu(openMenu)
end
AddEventHandler('keep-companion:client:openMenu_customization:confirm', function(data)
TriggerServerEvent('keep-companion:server:compelete_initialization_process', data.item, data.pet_information.type)
end)