2025-06-07 08:51:21 +02:00
|
|
|
local isSearching = false
|
|
|
|
local rightPosition = { x = 1430, y = 200 }
|
|
|
|
local leftPosition = { x = 0, y = 200 }
|
|
|
|
local menuPosition = { x = 0, y = 200 }
|
|
|
|
local menuHeader = "shopui_title_sm_hangar"
|
|
|
|
|
|
|
|
if GetAspectRatio() > 2.0 then
|
|
|
|
rightPosition = { x = 1200, y = 100 }
|
|
|
|
leftPosition = { x = -250, y = 100 }
|
|
|
|
end
|
|
|
|
|
|
|
|
if Config.MenuPosition then
|
|
|
|
if Config.MenuPosition == "left" then
|
|
|
|
menuPosition = leftPosition
|
|
|
|
elseif Config.MenuPosition == "right" then
|
|
|
|
menuPosition = rightPosition
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if Config.CustomMenuEnabled then
|
|
|
|
local txd = CreateRuntimeTxd('Custom_Menu_Head')
|
|
|
|
CreateRuntimeTextureFromImage(txd, 'Custom_Menu_Head', 'header.png')
|
|
|
|
menuHeader = "Custom_Menu_Head"
|
|
|
|
end
|
|
|
|
|
|
|
|
local _menuPool = NativeUI.CreatePool()
|
|
|
|
local mainMenu = NativeUI.CreateMenu(Config.MenuTitle or "", "", menuPosition["x"], menuPosition["y"], menuHeader, menuHeader)
|
|
|
|
_menuPool:Add(mainMenu)
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
local sharemenu, shareddancemenu, infomenu
|
2025-06-07 08:51:21 +02:00
|
|
|
|
|
|
|
local EmoteTable = {}
|
|
|
|
local DanceTable = {}
|
|
|
|
local AnimalTable = {}
|
2025-06-12 03:36:12 +02:00
|
|
|
local PropTable = {}
|
2025-06-07 08:51:21 +02:00
|
|
|
local WalkTable = {}
|
|
|
|
local FaceTable = {}
|
|
|
|
local ShareTable = {}
|
|
|
|
|
|
|
|
|
|
|
|
function AddEmoteMenu(menu)
|
|
|
|
local submenu = _menuPool:AddSubMenu(menu, Translate('emotes'), "", true, true)
|
|
|
|
if Config.Search then
|
|
|
|
submenu:AddItem(NativeUI.CreateItem(Translate('searchemotes'), ""))
|
|
|
|
table.insert(EmoteTable, Translate('searchemotes'))
|
|
|
|
end
|
|
|
|
local dancemenu = _menuPool:AddSubMenu(submenu, Translate('danceemotes'), "", true, true)
|
|
|
|
local animalmenu
|
|
|
|
if Config.AnimalEmotesEnabled then
|
|
|
|
animalmenu = _menuPool:AddSubMenu(submenu, Translate('animalemotes'), "", true, true)
|
|
|
|
table.insert(EmoteTable, Translate('animalemotes'))
|
|
|
|
end
|
|
|
|
local propmenu = _menuPool:AddSubMenu(submenu, Translate('propemotes'), "", true, true)
|
|
|
|
table.insert(EmoteTable, Translate('danceemotes'))
|
|
|
|
table.insert(EmoteTable, Translate('danceemotes'))
|
|
|
|
|
|
|
|
if Config.SharedEmotesEnabled then
|
|
|
|
sharemenu = _menuPool:AddSubMenu(submenu, Translate('shareemotes'),
|
|
|
|
Translate('shareemotesinfo'), true, true)
|
|
|
|
shareddancemenu = _menuPool:AddSubMenu(sharemenu, Translate('sharedanceemotes'), "", true, true)
|
|
|
|
table.insert(ShareTable, 'none')
|
|
|
|
table.insert(EmoteTable, Translate('shareemotes'))
|
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
if Config.Keybinding then
|
2025-06-07 08:51:21 +02:00
|
|
|
table.insert(EmoteTable, "keybinds")
|
|
|
|
submenu:AddItem(NativeUI.CreateItem(Translate('keybinds'), Translate('keybindsinfo') .. " /emotebind [~y~num4-9~w~] [~g~emotename~w~]"))
|
|
|
|
end
|
|
|
|
|
|
|
|
for a, b in PairsByKeys(RP.Emotes) do
|
|
|
|
local x, y, z = table.unpack(b)
|
|
|
|
submenu:AddItem(NativeUI.CreateItem(z, "/e (" .. a .. ")"))
|
|
|
|
table.insert(EmoteTable, a)
|
|
|
|
end
|
|
|
|
|
|
|
|
for a, b in PairsByKeys(RP.Dances) do
|
2025-06-12 03:36:12 +02:00
|
|
|
local name = '🤼 ' .. b[3]
|
|
|
|
dancemenu:AddItem(NativeUI.CreateItem(name, "/e (" .. a .. ")"))
|
2025-06-07 08:51:21 +02:00
|
|
|
if Config.SharedEmotesEnabled then
|
2025-06-12 03:36:12 +02:00
|
|
|
shareddancemenu:AddItem(NativeUI.CreateItem(name, "/nearby (" .. a .. ")"))
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
table.insert(DanceTable, a)
|
|
|
|
end
|
|
|
|
|
|
|
|
if Config.AnimalEmotesEnabled then
|
|
|
|
for a, b in PairsByKeys(RP.AnimalEmotes) do
|
2025-06-12 03:36:12 +02:00
|
|
|
local name = '🐶 ' .. b[3]
|
|
|
|
animalmenu:AddItem(NativeUI.CreateItem(name, "/e (" .. a .. ")"))
|
2025-06-07 08:51:21 +02:00
|
|
|
table.insert(AnimalTable, a)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if Config.SharedEmotesEnabled then
|
|
|
|
for a, b in PairsByKeys(RP.Shared) do
|
2025-06-12 03:36:12 +02:00
|
|
|
local name = b[3]
|
|
|
|
local shareitem = NativeUI.CreateItem(name, "/nearby (~g~" .. a .. "~w~)" .. (otheremotename and " " .. Translate('makenearby') .. " (~y~" .. otheremotename .. "~w~)" or ""))
|
2025-06-07 08:51:21 +02:00
|
|
|
sharemenu:AddItem(shareitem)
|
|
|
|
table.insert(ShareTable, a)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
for a, b in PairsByKeys(RP.PropEmotes) do
|
2025-06-12 03:36:12 +02:00
|
|
|
local name = '📦 ' .. b[3]
|
2025-06-07 08:51:21 +02:00
|
|
|
local propitem = b.AnimationOptions.PropTextureVariations and
|
2025-06-12 03:36:12 +02:00
|
|
|
NativeUI.CreateListItem(name, b.AnimationOptions.PropTextureVariations, 1, "/e (" .. a .. ")") or
|
|
|
|
NativeUI.CreateItem(name, "/e (" .. a .. ")")
|
2025-06-07 08:51:21 +02:00
|
|
|
|
|
|
|
propmenu:AddItem(propitem)
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
table.insert(PropTable, a)
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
-- Ped Emote on Change Index
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
dancemenu.OnIndexChange = function(_, newindex)
|
2025-06-07 08:51:21 +02:00
|
|
|
ClearPedTaskPreview()
|
2025-06-12 03:36:12 +02:00
|
|
|
EmoteMenuStartClone(DanceTable[newindex], "Dances")
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
propmenu.OnIndexChange = function(_, newindex)
|
2025-06-07 08:51:21 +02:00
|
|
|
ClearPedTaskPreview()
|
2025-06-12 03:36:12 +02:00
|
|
|
EmoteMenuStartClone(PropTable[newindex], "PropEmotes")
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
submenu.OnIndexChange = function(_, newindex)
|
|
|
|
if newindex > 5 then
|
2025-06-07 08:51:21 +02:00
|
|
|
ClearPedTaskPreview()
|
2025-06-12 03:36:12 +02:00
|
|
|
EmoteMenuStartClone(EmoteTable[newindex], "Emotes")
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
dancemenu.OnMenuClosed = function()
|
2025-06-07 08:51:21 +02:00
|
|
|
ClearPedTaskPreview()
|
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
dancemenu.OnItemSelect = function(_, _, index)
|
|
|
|
EmoteMenuStart(DanceTable[index], "Dances")
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
if Config.AnimalEmotesEnabled then
|
2025-06-12 03:36:12 +02:00
|
|
|
animalmenu.OnItemSelect = function(_, _, index)
|
|
|
|
EmoteMenuStart(AnimalTable[index], "AnimalEmotes")
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if Config.SharedEmotesEnabled then
|
2025-06-12 03:36:12 +02:00
|
|
|
sharemenu.OnItemSelect = function(_, _, index)
|
2025-06-07 08:51:21 +02:00
|
|
|
if ShareTable[index] ~= 'none' then
|
|
|
|
local target, distance = GetClosestPlayer()
|
|
|
|
if (distance ~= -1 and distance < 3) then
|
2025-06-12 03:36:12 +02:00
|
|
|
TriggerServerEvent("rpemotes:server:requestEmote", GetPlayerServerId(target), ShareTable[index])
|
2025-06-07 08:51:21 +02:00
|
|
|
SimpleNotify(Translate('sentrequestto') .. GetPlayerName(target))
|
|
|
|
else
|
|
|
|
SimpleNotify(Translate('nobodyclose'))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
shareddancemenu.OnItemSelect = function(_, _, index)
|
2025-06-07 08:51:21 +02:00
|
|
|
local target, distance = GetClosestPlayer()
|
|
|
|
if (distance ~= -1 and distance < 3) then
|
2025-06-12 03:36:12 +02:00
|
|
|
TriggerServerEvent("rpemotes:server:requestEmote", GetPlayerServerId(target), DanceTable[index], 'Dances')
|
2025-06-07 08:51:21 +02:00
|
|
|
SimpleNotify(Translate('sentrequestto') .. GetPlayerName(target))
|
|
|
|
else
|
|
|
|
SimpleNotify(Translate('nobodyclose'))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
propmenu.OnItemSelect = function(_, _, index)
|
|
|
|
EmoteMenuStart(PropTable[index], "PropEmotes")
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
propmenu.OnListSelect = function(_, item, itemIndex, listIndex)
|
|
|
|
EmoteMenuStart(PropTable[itemIndex], "PropEmotes", item:IndexToItem(listIndex).Value)
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
submenu.OnItemSelect = function(_, _, index)
|
2025-06-07 08:51:21 +02:00
|
|
|
if Config.Search and EmoteTable[index] == Translate('searchemotes') then
|
|
|
|
EmoteMenuSearch(submenu)
|
2025-06-12 03:36:12 +02:00
|
|
|
else
|
|
|
|
EmoteMenuStart(EmoteTable[index], "Emotes")
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
submenu.OnMenuClosed = function()
|
2025-06-07 08:51:21 +02:00
|
|
|
if not isSearching then
|
|
|
|
ClosePedMenu()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
if Config.Search then
|
|
|
|
local ignoredCategories = {
|
|
|
|
["Walks"] = true,
|
|
|
|
["Expressions"] = true,
|
|
|
|
["Shared"] = not Config.SharedEmotesEnabled
|
|
|
|
}
|
|
|
|
|
|
|
|
function EmoteMenuSearch(lastMenu)
|
|
|
|
ClosePedMenu()
|
|
|
|
AddTextEntry("PM_NAME_CHALL", Translate('searchinputtitle'))
|
|
|
|
DisplayOnscreenKeyboard(1, "PM_NAME_CHALL", "", "", "", "", "", 30)
|
|
|
|
while UpdateOnscreenKeyboard() == 0 do
|
|
|
|
DisableAllControlActions(0)
|
|
|
|
Wait(100)
|
|
|
|
end
|
|
|
|
local input = GetOnscreenKeyboardResult()
|
|
|
|
if input ~= nil then
|
|
|
|
local results = {}
|
2025-06-12 03:36:12 +02:00
|
|
|
for a, b in pairs(RP) do
|
|
|
|
if not ignoredCategories[b.category] then
|
|
|
|
if string.find(string.lower(a), string.lower(input)) or (b[3] ~= nil and string.find(string.lower(b[3]), string.lower(input))) then
|
|
|
|
table.insert(results, { table = b.category, name = a, data = b })
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if #results > 0 then
|
|
|
|
isSearching = true
|
|
|
|
|
|
|
|
local searchMenu = _menuPool:AddSubMenu(lastMenu, string.format('%s '..Translate('searchmenudesc')..' ~r~%s~w~', #results, input), "", true, true)
|
|
|
|
local sharedDanceMenu
|
|
|
|
|
|
|
|
if Config.SharedEmotesEnabled then
|
|
|
|
sharedDanceMenu = _menuPool:AddSubMenu(searchMenu, Translate('sharedanceemotes'), "", true, true)
|
|
|
|
end
|
|
|
|
|
|
|
|
table.sort(results, function(a, b) return a.name < b.name end)
|
|
|
|
for k, v in pairs(results) do
|
|
|
|
local desc = ""
|
|
|
|
if v.table == "Shared" then
|
|
|
|
local otheremotename = v.data[4]
|
|
|
|
if otheremotename == nil then
|
|
|
|
desc = "/nearby (~g~" .. v.name .. "~w~)"
|
|
|
|
else
|
|
|
|
desc = "/nearby (~g~" .. v.name .. "~w~) " .. Translate('makenearby') .. " (~y~" .. otheremotename .. "~w~)"
|
|
|
|
end
|
|
|
|
else
|
2025-06-12 03:36:12 +02:00
|
|
|
desc = "/e (" .. v.name .. ")"
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
if v.data.AnimationOptions and v.data.AnimationOptions.PropTextureVariations then
|
|
|
|
searchMenu:AddItem(NativeUI.CreateListItem(v.data[3], v.data.AnimationOptions.PropTextureVariations, 1, desc))
|
|
|
|
else
|
|
|
|
searchMenu:AddItem(NativeUI.CreateItem(v.data[3], desc))
|
|
|
|
end
|
|
|
|
|
|
|
|
if v.table == "Dances" and Config.SharedEmotesEnabled then
|
|
|
|
sharedDanceMenu:AddItem(NativeUI.CreateItem(v.data[3], ""))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
searchMenu.OnMenuChanged = function()
|
2025-06-07 08:51:21 +02:00
|
|
|
isSearching = false
|
|
|
|
ShowPedMenu()
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
searchMenu.OnIndexChange = function(_, newindex)
|
2025-06-07 08:51:21 +02:00
|
|
|
local data = results[newindex]
|
|
|
|
|
|
|
|
ClearPedTaskPreview()
|
2025-06-12 03:36:12 +02:00
|
|
|
EmoteMenuStartClone(data.name, data.data.category)
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
searchMenu.OnItemSelect = function(_, _, index)
|
2025-06-07 08:51:21 +02:00
|
|
|
local data = results[index]
|
|
|
|
|
|
|
|
if data == Translate('sharedanceemotes') then return end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
if data.table == "Shared" then
|
2025-06-07 08:51:21 +02:00
|
|
|
local target, distance = GetClosestPlayer()
|
|
|
|
if (distance ~= -1 and distance < 3) then
|
2025-06-12 03:36:12 +02:00
|
|
|
TriggerServerEvent("rpemotes:server:requestEmote", GetPlayerServerId(target), data.name)
|
2025-06-07 08:51:21 +02:00
|
|
|
SimpleNotify(Translate('sentrequestto') .. GetPlayerName(target))
|
|
|
|
else
|
|
|
|
SimpleNotify(Translate('nobodyclose'))
|
|
|
|
end
|
2025-06-12 03:36:12 +02:00
|
|
|
else
|
|
|
|
EmoteMenuStart(data.name, data.data.category)
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
searchMenu.OnListSelect = function(_, item, itemIndex, listIndex)
|
|
|
|
EmoteMenuStart(results[itemIndex].name, "PropEmotes", item:IndexToItem(listIndex).Value)
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
if Config.SharedEmotesEnabled then
|
|
|
|
if #sharedDanceMenu.Items > 0 then
|
2025-06-12 03:36:12 +02:00
|
|
|
table.insert(results, 1, Translate('sharedanceemotes'))
|
|
|
|
sharedDanceMenu.OnItemSelect = function(_, _, index)
|
2025-06-07 08:51:21 +02:00
|
|
|
if not LocalPlayer.state.canEmote then return end
|
|
|
|
|
|
|
|
local data = results[index]
|
|
|
|
local target, distance = GetClosestPlayer()
|
|
|
|
if (distance ~= -1 and distance < 3) then
|
2025-06-12 03:36:12 +02:00
|
|
|
TriggerServerEvent("rpemotes:server:requestEmote", GetPlayerServerId(target), data.name, 'Dances')
|
2025-06-07 08:51:21 +02:00
|
|
|
SimpleNotify(Translate('sentrequestto') .. GetPlayerName(target))
|
|
|
|
else
|
|
|
|
SimpleNotify(Translate('nobodyclose'))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
else
|
|
|
|
sharedDanceMenu:Clear()
|
2025-06-12 03:36:12 +02:00
|
|
|
searchMenu:RemoveItemAt(1)
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
searchMenu.OnMenuClosed = function()
|
|
|
|
searchMenu:Clear()
|
|
|
|
lastMenu:RemoveItemAt(#lastMenu.Items)
|
|
|
|
_menuPool:RefreshIndex()
|
|
|
|
results = {}
|
|
|
|
end
|
|
|
|
|
|
|
|
_menuPool:RefreshIndex()
|
|
|
|
_menuPool:CloseAllMenus()
|
|
|
|
searchMenu:Visible(true)
|
|
|
|
ShowPedMenu()
|
|
|
|
else
|
|
|
|
SimpleNotify(string.format(Translate('searchnoresult')..' ~r~%s~w~', input))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function AddCancelEmote(menu)
|
|
|
|
local newitem = NativeUI.CreateItem(Translate('cancelemote'), Translate('cancelemoteinfo'))
|
|
|
|
menu:AddItem(newitem)
|
|
|
|
newitem.Activated = function()
|
|
|
|
EmoteCancel()
|
|
|
|
DestroyAllProps()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
ShowPedPreview = function(menu)
|
2025-06-12 03:36:12 +02:00
|
|
|
menu.OnItemSelect = function(_, _, index)
|
|
|
|
if index == 1 then
|
2025-06-07 08:51:21 +02:00
|
|
|
isSearching = false
|
|
|
|
ShowPedMenu()
|
|
|
|
elseif index == 4 then
|
|
|
|
ShowPedMenu(true)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function AddWalkMenu(menu)
|
|
|
|
local submenu = _menuPool:AddSubMenu(menu, Translate('walkingstyles'), "", true, true)
|
|
|
|
|
|
|
|
local walkreset = NativeUI.CreateItem(Translate('normalreset'), Translate('resetdef'))
|
|
|
|
submenu:AddItem(walkreset)
|
|
|
|
table.insert(WalkTable, Translate('resetdef'))
|
|
|
|
|
|
|
|
local sortedWalks = {}
|
|
|
|
for a, b in PairsByKeys(RP.Walks) do
|
2025-06-12 03:36:12 +02:00
|
|
|
if b[1] == "move_m@injured" then
|
|
|
|
table.insert(sortedWalks, 1, {label = a, anim = b[1]})
|
2025-06-07 08:51:21 +02:00
|
|
|
else
|
2025-06-12 03:36:12 +02:00
|
|
|
table.insert(sortedWalks, {label = a, anim = b[1]})
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
for _, walk in ipairs(sortedWalks) do
|
|
|
|
submenu:AddItem(NativeUI.CreateItem(walk.label, "/walk (" .. string.lower(walk.label) .. ")"))
|
2025-06-12 03:36:12 +02:00
|
|
|
table.insert(WalkTable, walk.label)
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
submenu.OnItemSelect = function(_, item, index)
|
2025-06-07 08:51:21 +02:00
|
|
|
if item == walkreset then
|
|
|
|
ResetWalk()
|
|
|
|
DeleteResourceKvp("walkstyle")
|
|
|
|
else
|
|
|
|
WalkMenuStart(WalkTable[index])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function AddFaceMenu(menu)
|
|
|
|
local submenu = _menuPool:AddSubMenu(menu, Translate('moods'), "", true, true)
|
|
|
|
|
|
|
|
local facereset = NativeUI.CreateItem(Translate('normalreset'), Translate('resetdef'))
|
|
|
|
submenu:AddItem(facereset)
|
|
|
|
table.insert(FaceTable, "")
|
|
|
|
|
|
|
|
for name, data in PairsByKeys(RP.Expressions) do
|
|
|
|
local faceitem = NativeUI.CreateItem(data[2] or name, "")
|
|
|
|
submenu:AddItem(faceitem)
|
|
|
|
table.insert(FaceTable, name)
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
submenu.OnIndexChange = function(_, newindex)
|
|
|
|
EmoteMenuStartClone(FaceTable[newindex], "Expressions")
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
submenu.OnItemSelect = function(_, item, index)
|
|
|
|
if item == facereset then
|
|
|
|
DeleteResourceKvp("Expressions")
|
2025-06-07 08:51:21 +02:00
|
|
|
ClearFacialIdleAnimOverride(PlayerPedId())
|
2025-06-12 03:36:12 +02:00
|
|
|
else
|
|
|
|
EmoteMenuStart(FaceTable[index], "Expressions")
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
end
|
2025-06-12 03:36:12 +02:00
|
|
|
|
|
|
|
submenu.OnMenuClosed = function()
|
|
|
|
ClosePedMenu()
|
|
|
|
end
|
2025-06-07 08:51:21 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
function AddInfoMenu(menu)
|
2025-06-12 03:36:12 +02:00
|
|
|
infomenu = _menuPool:AddSubMenu(menu, Translate('infoupdate'), "~h~~y~The RPEmotes Developers~h~~y~", true, true)
|
2025-06-07 08:51:21 +02:00
|
|
|
|
|
|
|
for _,v in ipairs(Config.Credits) do
|
|
|
|
local item = NativeUI.CreateItem(v.title,v.subtitle or "")
|
|
|
|
infomenu:AddItem(item)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function OpenEmoteMenu()
|
|
|
|
if IsEntityDead(PlayerPedId()) then
|
|
|
|
-- show in chat
|
|
|
|
TriggerEvent('chat:addMessage', {
|
|
|
|
color = {255, 0, 0},
|
|
|
|
multiline = true,
|
|
|
|
args = {"RPEmotes", Translate('dead')}
|
|
|
|
})
|
|
|
|
return
|
|
|
|
end
|
|
|
|
if (IsPedSwimming(PlayerPedId()) or IsPedSwimmingUnderWater(PlayerPedId())) and not Config.AllowInWater then
|
|
|
|
-- show in chat
|
|
|
|
TriggerEvent('chat:addMessage', {
|
|
|
|
color = {255, 0, 0},
|
|
|
|
multiline = true,
|
|
|
|
args = {"RPEmotes", Translate('swimming')}
|
|
|
|
})
|
|
|
|
return
|
|
|
|
end
|
|
|
|
if _menuPool:IsAnyMenuOpen() then
|
|
|
|
_menuPool:CloseAllMenus()
|
|
|
|
else
|
|
|
|
mainMenu:Visible(true)
|
|
|
|
ProcessMenu()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
CreateThread(function()
|
|
|
|
LoadAddonEmotes()
|
|
|
|
AddEmoteMenu(mainMenu)
|
|
|
|
AddCancelEmote(mainMenu)
|
|
|
|
if Config.PreviewPed then
|
|
|
|
ShowPedPreview(mainMenu)
|
|
|
|
end
|
|
|
|
if Config.WalkingStylesEnabled then
|
|
|
|
AddWalkMenu(mainMenu)
|
|
|
|
end
|
|
|
|
if Config.ExpressionsEnabled then
|
|
|
|
AddFaceMenu(mainMenu)
|
|
|
|
end
|
|
|
|
AddInfoMenu(mainMenu)
|
|
|
|
|
|
|
|
_menuPool:RefreshIndex()
|
2025-06-07 08:51:21 +02:00
|
|
|
|
2025-06-12 03:36:12 +02:00
|
|
|
local newRP = {}
|
|
|
|
for emoteType, content in pairs(RP) do
|
|
|
|
for emoteName, emoteData in pairs(content) do
|
|
|
|
local shouldRemove = false
|
|
|
|
|
|
|
|
if Config.AdultEmotesDisabled and emoteData.AdultAnimation then
|
|
|
|
shouldRemove = true
|
|
|
|
end
|
|
|
|
if newRP[emoteName] then
|
|
|
|
print('WARNING - Duplicate emote name found: ' .. emoteName .. ' in ' .. emoteType .. ' and ' .. newRP[emoteName].category)
|
|
|
|
end
|
|
|
|
if shouldRemove then
|
|
|
|
elseif type(emoteData) == "table" then
|
|
|
|
newRP[emoteName] = {}
|
|
|
|
for k, v in pairs(emoteData) do
|
|
|
|
newRP[emoteName][k] = v
|
|
|
|
end
|
|
|
|
newRP[emoteName].category = emoteType
|
|
|
|
else
|
|
|
|
newRP[emoteName] = { emoteData }
|
|
|
|
newRP[emoteName].category = emoteType
|
|
|
|
end
|
|
|
|
end
|
|
|
|
newRP[emoteType] = nil
|
|
|
|
end
|
|
|
|
RP = newRP
|
|
|
|
CONVERTED = true
|
|
|
|
end)
|
2025-06-07 08:51:21 +02:00
|
|
|
|
|
|
|
local isMenuProcessing = false
|
|
|
|
function ProcessMenu()
|
|
|
|
if isMenuProcessing then return end
|
|
|
|
isMenuProcessing = true
|
|
|
|
while _menuPool:IsAnyMenuOpen() do
|
|
|
|
_menuPool:ProcessMenus()
|
|
|
|
Wait(0)
|
|
|
|
end
|
|
|
|
isMenuProcessing = false
|
|
|
|
end
|
|
|
|
|
|
|
|
-- While ped is dead, don't show menus
|
|
|
|
CreateThread(function()
|
|
|
|
while true do
|
|
|
|
Wait(500)
|
|
|
|
if IsEntityDead(PlayerPedId()) then
|
|
|
|
_menuPool:CloseAllMenus()
|
|
|
|
end
|
|
|
|
if (IsPedSwimming(PlayerPedId()) or IsPedSwimmingUnderWater(PlayerPedId())) and not Config.AllowInWater then
|
|
|
|
-- cancel emote, destroy props and close menu
|
|
|
|
if IsInAnimation then
|
|
|
|
EmoteCancel()
|
|
|
|
end
|
|
|
|
_menuPool:CloseAllMenus()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end)
|