2025-04-07 01:41:12 +00:00

455 lines
16 KiB
Lua

local mainMenuOptions = {
{ label = locale('emote_options'), description = locale('open_emote_options'), icon = 'fa-solid fa-person', args = { id = 'emotemenu_submenu_emotes' } },
{ label = locale('walking_styles'), icon = 'fa-solid fa-person-walking', values = {}, args = { id = 'emotemenu_walks', walks = Walks }, close = false },
{ label = locale('scenarios'), icon = 'fa-solid fa-person-walking-with-cane', values = {}, args = { id = 'emotemenu_scenarios', scenarios = Scenarios }, close = false },
{ label = locale('facial_expressions'), icon = 'fa-solid fa-face-angry', values = {}, args = { id = 'emotemenu_expressions', expressions = Expressions }, close = false },
{ label = locale('cancel'), values = {
{ label = locale('emote'), description = locale('cancel_your_emote') },
{ label = locale('walk_style'), description = locale('reset_walk_style') },
{ label = locale('expression'), description = locale('reset_your_expression') },
{ label = locale('all'), description = locale('cancel_reset_everything') }
}, icon = 'fa-solid fa-ban', args = { id = 'emotemenu_cancel' }, close = false }
}
local preview = require 'client.modules.preview'
---Close the emote menu
function CloseMenu()
local currentMenu = lib.getOpenMenu()
if not currentMenu or not string.find(currentMenu, 'emotemenu_') then return end
lib.hideMenu()
end
exports('closeMenu', CloseMenu)
---Toggle the emote menu
function ToggleMenu()
if PlayerState.isLimited then return end
local currentMenu = lib.getOpenMenu()
if not currentMenu then
lib.showMenu('emotemenu_main_menu')
else
CloseMenu()
end
end
exports('toggleMenu', ToggleMenu)
---Register the emote menu
function RegisterMenu()
for i = 1, #mainMenuOptions do
local option = mainMenuOptions[i]
local data = option.args
if data.id == 'emotemenu_walks' then
local command = Config.walkCommands[1]
for k = 1, #data.walks do
local walk = data.walks[k]
option.values[k] = { label = walk.Label, description = ('/%s %s'):format(command, walk.Command) }
end
elseif data.id == 'emotemenu_scenarios' then
local command = Config.emoteCommands[1]
for k = 1, #data.scenarios do
local scenario = data.scenarios[k]
option.values[k] = { label = scenario.Label, description = ('/%s %s'):format(command, scenario.Command) }
end
elseif data.id == 'emotemenu_expressions' then
local command = Config.expressionCommands[1]
for k = 1, #data.expressions do
local expression = data.expressions[k]
option.values[k] = { label = expression.Label, description = ('/%s %s'):format(command, expression.Command) }
end
end
end
local emoteMenuOptions = {
{ label = locale('search'), description = locale('search_for_emotes'), icon = 'fa-solid fa-magnifying-glass', args = { id = 'emotemenu_search' } }
}
if Config.enableEmoteBinds then
emoteMenuOptions[2] = { label = locale('keybinds'), description = locale('create_delete_binds'), icon = 'fa-solid fa-keyboard', args = { id = 'emotemenu_submenu_binds' } }
end
Emotes = Utils.filterTable(Emotes, function(tbl, index)
local option = tbl[index]
local keepOption = true
if option.name == 'Consumable Emotes' and not Config.enableConsumableEmotes then
keepOption = false
elseif option.name == 'Synchronized Emotes' and not Config.enableSynchronizedEmotes then
keepOption = false
elseif option.name == 'Synchronized Dance Emotes' and not Config.enableSynchronizedEmotes then
keepOption = false
elseif option.name == 'Animal Emotes' and not Config.enableAnimalEmotes then
keepOption = false
end
return keepOption
end)
for i = 1, #Emotes do
local submenu = Emotes[i]
submenu.options = Utils.filterTable(submenu.options, function(tbl, index)
local emote = tbl[index]
local keepEmote = true
if not DoesAnimDictExist(emote.Dictionary) then
keepEmote = false
elseif emote?.Options?.Props then
local props = emote.Options.Props
for k = 1, #props do
if not IsModelValid(joaat(props[k].Name)) then
keepEmote = false
break
end
end
end
if emote.NSFW and Config.enableNSFWEmotes == 'false' then
keepEmote = false
elseif emote.Gang and not Config.enableGangEmotes then
keepEmote = false
elseif emote.SocialMovement and not Config.enableSocialMovementEmotes then
keepEmote = false
end
return keepEmote
end)
local emotes = {}
local emoteOptions = {}
for k = 1, #submenu.options do
local emote = submenu.options[k]
if not emote.Hide then
local index = #emotes + 1
local command = Config.emoteCommands[1]
emotes[index] = emote
emoteOptions[index] = { label = emote.Label, description = ('/%s %s - %s'):format(command, emote.Command, locale('hold_to_preview')) }
end
end
emoteMenuOptions[#emoteMenuOptions + 1] = { label = submenu.name, icon = submenu.icon, values = emoteOptions, args = { id = 'emotemenu_play_emote', emotes = emotes }, close = false }
end
lib.registerMenu({
id = 'emotemenu_submenu_emotes',
title = locale('emote_options'),
position = Config.menuPosition,
options = emoteMenuOptions,
onClose = function()
lib.showMenu('emotemenu_main_menu')
end,
}, function(_, scrollIndex, args)
if args.id == 'emotemenu_search' then
local query = lib.inputDialog(locale('search'), { locale('emote') })
if not query then
lib.showMenu('emotemenu_submenu_emotes')
return
end
query = string.lower(query[1])
local searchMenuOptions = {}
for i = 1, #Emotes do
local submenu = Emotes[i]
local emotes = {}
local foundEmotes = {}
for k = 1, #submenu.options do
local emote = submenu.options[k]
if not emote.Hide and (string.find(string.lower(emote.Label), query) or string.find(string.lower(emote.Command), query)) then
local index = #emotes + 1
local command = Config.emoteCommands[1]
emotes[index] = emote
foundEmotes[index] = { label = emote.Label, description = ('/%s %s - %s'):format(command, emote.Command, locale('hold_to_preview')) }
end
end
if #foundEmotes > 0 then
searchMenuOptions[#searchMenuOptions + 1] = { label = submenu.name, icon = submenu.icon, values = foundEmotes, args = { id = 'emotemenu_play_emote', emotes = emotes }, close = false }
end
end
if #searchMenuOptions == 0 then
lib.showMenu('emotemenu_submenu_emotes')
Utils.notify('error', locale('not_valid_emote'))
return
end
lib.registerMenu({
id = 'emotemenu_submenu_emotes_search',
title = locale('search_results'),
position = Config.menuPosition,
options = searchMenuOptions,
onClose = function()
lib.showMenu('emotemenu_submenu_emotes')
end,
}, function(_, scrollIndex, args)
if Config.enableEmotePreview and IsControlPressed(0, 38) then
preview.showEmote(args.emotes[scrollIndex])
return
end
PlayEmote(args.emotes[scrollIndex])
end)
lib.showMenu('emotemenu_submenu_emotes_search')
elseif args.id == 'emotemenu_submenu_binds' then
local bindMenuOptions = {
{ label = locale('none'), description = locale('new_bind'), icon = 'fa-solid fa-1', args = { id = 'emotemenu_submenu_binds_new' } },
{ label = locale('none'), description = locale('new_bind'), icon = 'fa-solid fa-2', args = { id = 'emotemenu_submenu_binds_new' } },
{ label = locale('none'), description = locale('new_bind'), icon = 'fa-solid fa-3', args = { id = 'emotemenu_submenu_binds_new' } },
{ label = locale('none'), description = locale('new_bind'), icon = 'fa-solid fa-4', args = { id = 'emotemenu_submenu_binds_new' } },
{ label = locale('none'), description = locale('new_bind'), icon = 'fa-solid fa-5', args = { id = 'emotemenu_submenu_binds_new' } }
}
for index, emote in pairs(EmoteBinds) do
if emote then
bindMenuOptions[tonumber(index)] = { label = emote.Label, description = locale('delete_bind'), icon = ('fa-solid fa-%s'):format(index), args = { id = 'emotemenu_submenu_binds_delete' } }
end
end
lib.registerMenu({
id = 'emotemenu_submenu_binds',
title = locale('keybinds'),
position = Config.menuPosition,
options = bindMenuOptions,
onClose = function()
lib.showMenu('emotemenu_submenu_emotes')
end,
}, function(selected, _, args)
if PlayerState.isLimited then return end
if args.id == 'emotemenu_submenu_binds_new' then
local query = lib.inputDialog(locale('new_bind'), { locale('emote_command_to_bind') })
if not query then
lib.showMenu('emotemenu_submenu_binds')
return
end
query = string.lower(query[1])
local bindEmote
for i = 1, #Emotes do
local emotes = Emotes[i]
for k = 1, #emotes.options do
local emote = emotes.options[k]
if emote.Command == query then
bindEmote = emote
break
end
end
if bindEmote then break end
end
if not bindEmote then
lib.showMenu('emotemenu_submenu_binds')
Utils.notify('error', locale('not_valid_emote'))
return
end
if bindEmote.BlockBinding then
Utils.notify('error', locale('bind_blocked'))
return
end
EmoteBinds[tostring(selected)] = bindEmote
KVP.update('keybinds', EmoteBinds)
Utils.notify('success', locale('bind_saved'))
else
EmoteBinds[tostring(selected)] = nil
KVP.update('keybinds', EmoteBinds)
Utils.notify('success', locale('bind_deleted'))
end
end)
lib.showMenu('emotemenu_submenu_binds')
else
if Config.enableEmotePreview and IsControlPressed(0, 38) then
preview.showEmote(args.emotes[scrollIndex])
return
end
PlayEmote(args.emotes[scrollIndex])
end
end)
lib.registerMenu({
id = 'emotemenu_main_menu',
title = locale('emote_menu'),
position = Config.menuPosition,
options = mainMenuOptions,
}, function(_, scrollIndex, args)
if args.id == 'emotemenu_submenu_emotes' then
lib.showMenu('emotemenu_submenu_emotes')
elseif args.id == 'emotemenu_walks' then
SetWalk(args.walks[scrollIndex].Walk)
elseif args.id == 'emotemenu_scenarios' then
PlayEmote(args.scenarios[scrollIndex])
elseif args.id == 'emotemenu_expressions' then
SetExpression(args.expressions[scrollIndex].Expression)
elseif args.id == 'emotemenu_cancel' then
if scrollIndex == 1 then
CancelEmote()
elseif scrollIndex == 2 then
ResetWalk()
elseif scrollIndex == 3 then
ResetExpression()
elseif scrollIndex == 4 then
CancelEmote()
ResetWalk()
ResetExpression()
end
end
end)
end
---Register the radial menu
function RegisterRadialMenu()
for i = 1, #mainMenuOptions do
local option = mainMenuOptions[i]
local isWalks = option.args.id == 'emotemenu_walks'
local isExpressions = option.args.id == 'emotemenu_expressions'
if isWalks or isExpressions then
local radialOptions = {
{
label = locale('view_list'),
icon = 'list',
onSelect = function()
CreateList(option.label, isWalks and Walks or Expressions, isWalks and Config.walkCommands[1] or Config.expressionCommands[1])
end
},
{
label = locale('cancel'),
icon = 'ban',
onSelect = isWalks and ResetWalk or ResetExpression
}
}
if isWalks then
for k = 1, #Walks do
local walk = Walks[k]
radialOptions[#radialOptions + 1] = {
label = walk.Label,
icon = 'person-walking',
onSelect = function()
SetWalk(walk.Walk)
end
}
end
elseif isExpressions then
for k = 1, #Expressions do
local expression = Expressions[k]
radialOptions[#radialOptions + 1] = {
label = expression.Label,
icon = 'face-angry',
onSelect = function()
SetExpression(expression.Expression)
end
}
end
end
lib.registerRadial({
id = option.args.id,
items = radialOptions
})
end
end
lib.registerRadial({
id = 'emotemenu_main',
items = {
{
id = 'emotemenu_open',
label = locale('open_radial_menu'),
icon = 'person-walking',
onSelect = ToggleMenu
},
{
id = 'emotemenu_walks_submenu',
label = locale('walking_styles'),
icon = 'person-walking',
menu = 'emotemenu_walks'
},
{
id = 'emotemenu_expressions_submenu',
label = locale('facial_expressions'),
icon = 'face-angry',
menu = 'emotemenu_expressions'
},
{
id = 'emotemenu_cancel',
label = locale('cancel'),
icon = 'ban',
onSelect = CancelEmote
}
}
})
lib.addRadialItem({{
id = 'emotemenu_open',
label = locale('emote_menu'),
icon = 'person-walking',
menu = 'emotemenu_main'
}})
end
---Add a new menu option to the emote menu
function AddEmoteMenuOption(data)
Emotes[#Emotes + 1] = data
RegisterMenu()
end
exports('addEmoteMenuOption', AddEmoteMenuOption)
for i = 1, #Config.menuCommands do
Utils.addCommand(Config.menuCommands[i], {
help = locale('open_emote_menu')
}, function(source, args, raw)
ToggleMenu()
end)
end
if Config.menuKeybind ~= '' then
if #Config.menuCommands > 0 then
RegisterKeyMapping(Config.menuCommands[1], locale('open_emote_menu'), 'keyboard', Config.menuKeybind)
end
end
CreateThread(function()
Wait(1000)
RegisterMenu()
if Config.enableRadialMenu then
RegisterRadialMenu()
end
end)