Main/resources/[standalone]/nordi_lookchanger/client.lua

439 lines
14 KiB
Lua
Raw Permalink Normal View History

2025-06-07 08:51:21 +02:00
local savedLooks = {}
local currentPed = PlayerPedId()
local menuPool = NativeUI.CreatePool()
local lookMenu = NativeUI.CreateMenu("Look-Menü", "Wähle deinen Style")
menuPool:Add(lookMenu)
local originalCamCoords = nil
local cam = nil
local loading = false
local isMenuOpen = false
local minimapLocked = false
-- HUD Funktionen
function hideHUD()
DisplayRadar(false)
TriggerEvent('codem-blackhudv2:SetForceHide', true, true)
for i = 0, 22 do
HideHudComponentThisFrame(i)
end
HideHudAndRadarThisFrame()
end
function showHUD()
DisplayRadar(true)
TriggerEvent('codem-blackhudv2:SetForceHide', false, false)
SetRadarBigmapEnabled(false, false)
end
function isAnyMenuVisible()
-- Prüfe Hauptmenü
if lookMenu:Visible() then
return true
end
-- Prüfe alle Untermenüs rekursiv
local function checkSubMenus(menu)
for _, item in pairs(menu.Items) do
if item.SubMenu then
if item.SubMenu:Visible() then
return true
end
if checkSubMenus(item.SubMenu) then
return true
end
end
end
return false
end
return checkSubMenus(lookMenu)
end
function updateMenuVisibility(menu, state)
menu:Visible(state)
for _, submenu in pairs(menu.Items) do
if submenu.SubMenu then
submenu.SubMenu:Visible(state)
end
end
end
RegisterNetEvent("lookchanger:setSavedLooks", function(data)
savedLooks = data
loading = false
populateLookMenu()
lookMenu:Visible(true)
focusCameraOnPedFront()
end)
function closeMenu()
lookMenu:Visible(false)
for _, item in pairs(lookMenu.Items) do
if item.SubMenu then
item.SubMenu:Visible(false)
end
end
clearCustomCamera()
isMenuOpen = false
-- Explizit alle Kontrollen wieder aktivieren
EnableAllControlActions(0)
-- Spieler entsperren
local ped = PlayerPedId()
FreezeEntityPosition(ped, false)
SetEntityCollision(ped, true, true)
-- Minimap-Rotation wieder freigeben
if minimapLocked then
minimapLocked = false
UnlockMinimapAngle()
end
-- HUD wieder einblenden
showHUD()
TriggerEvent('codem-blackhudv2:SetForceHide', false, false)
-- Kurzzeitig ESC-Taste blockieren
Citizen.CreateThread(function()
DisableControlAction(0, 200, true) -- ESC
DisableControlAction(0, 199, true) -- P (Pause Menu)
Wait(200) -- 200ms Verzögerung
EnableControlAction(0, 200, true)
EnableControlAction(0, 199, true)
end)
end
RegisterCommand("lookchanger_menu", function()
if not isMenuOpen and not loading then
loading = true
isMenuOpen = true
TriggerServerEvent("lookchanger:requestLooks")
elseif lookMenu:Visible() then
closeMenu()
end
end)
RegisterKeyMapping("lookchanger_menu", "Öffnet das Look-Menü", "keyboard", "F6")
-- Hauptthread für Menüsteuerung und HUD
Citizen.CreateThread(function()
local spinnerAngle = 0.0
while true do
Citizen.Wait(0)
menuPool:ProcessMenus()
if isAnyMenuVisible() then
hideHUD()
DisableAllControlActions(0)
EnableControlAction(0, 1, true) -- Maus
EnableControlAction(0, 2, true) -- Maus
EnableControlAction(0, 18, true) -- Enter
EnableControlAction(0, 172, true) -- Hoch
EnableControlAction(0, 173, true) -- Runter
EnableControlAction(0, 174, true) -- Links
EnableControlAction(0, 175, true) -- Rechts
EnableControlAction(0, 200, true) -- ESC
EnableControlAction(0, 194, true) -- Backslash
-- Minimap-Rotation verhindern
if not minimapLocked then
minimapLocked = true
SetRadarBigmapEnabled(false, false)
LockMinimapAngle(0)
end
if IsControlJustPressed(0, 200) or IsControlJustPressed(0, 194) then -- ESC oder Backslash
closeMenu()
end
drawHint("Drücke ESC, Backslash oder F6, um das Menü zu schließen")
elseif minimapLocked then
minimapLocked = false
UnlockMinimapAngle()
showHUD()
end
if loading then
drawLoadingSpinner("Daten werden geladen...", spinnerAngle)
spinnerAngle = (spinnerAngle + 5) % 360
end
end
end)
-- Kontinuierlicher Thread für HUD-Kontrolle
Citizen.CreateThread(function()
while true do
if isAnyMenuVisible() then
-- Aggressives HUD ausblenden
DisplayRadar(false)
TriggerEvent('codem-blackhudv2:SetForceHide', true, true)
for i = 0, 22 do
HideHudComponentThisFrame(i)
end
HideHudAndRadarThisFrame()
end
Citizen.Wait(0)
end
end)
function focusCameraOnPedFront()
local ped = PlayerPedId()
originalCamCoords = GetEntityCoords(ped)
local offset = GetOffsetFromEntityInWorldCoords(ped, 0.0, 1.5, 0.6)
cam = CreateCam("DEFAULT_SCRIPTED_CAMERA", true)
SetCamCoord(cam, offset.x, offset.y, offset.z)
PointCamAtEntity(cam, ped, 0.0, 0.0, 0.6, true)
SetCamActive(cam, true)
RenderScriptCams(true, false, 0, true, true)
local zoomStartTime = GetGameTimer()
Citizen.CreateThread(function()
while GetGameTimer() - zoomStartTime < 1000 do
local zoomAmount = (GetGameTimer() - zoomStartTime) / 1000
SetCamFov(cam, 50 + zoomAmount * 10)
Citizen.Wait(0)
end
end)
end
function clearCustomCamera()
if cam then
RenderScriptCams(false, false, 0, true, true)
DestroyCam(cam, false)
cam = nil
end
end
function drawHint(text)
SetTextFont(0)
SetTextProportional(1)
SetTextScale(0.35, 0.35)
SetTextColour(255, 255, 255, 215)
SetTextDropShadow()
SetTextEdge(1, 0, 0, 0, 255)
SetTextOutline()
SetTextEntry("STRING")
AddTextComponentString(text)
DrawText(0.015, 0.955)
end
function notify(msg)
SetNotificationTextEntry("STRING")
AddTextComponentSubstringPlayerName(msg)
DrawNotification(false, false)
end
function requestInput(prompt)
AddTextEntry('FMMC_KEY_TIP1', prompt)
DisplayOnscreenKeyboard(1, 'FMMC_KEY_TIP1', '', '', '', '', '', 30)
while UpdateOnscreenKeyboard() == 0 do
DisableAllControlActions(0)
DisplayRadar(false)
TriggerEvent('codem-blackhudv2:SetForceHide', true, true)
Citizen.Wait(0)
end
if GetOnscreenKeyboardResult() then
return GetOnscreenKeyboardResult()
end
return nil
end
function getCurrentLook(type)
local ped = PlayerPedId()
if type == "hair" then
return { GetPedDrawableVariation(ped, 2), GetPedTextureVariation(ped, 2) }
elseif type == "hat" then
return { GetPedPropIndex(ped, 0), GetPedPropTextureIndex(ped, 0) }
elseif type == "glasses" then
return { GetPedPropIndex(ped, 1), GetPedPropTextureIndex(ped, 1) }
elseif type == "bag" then
return { GetPedDrawableVariation(ped, 5), GetPedTextureVariation(ped, 5) }
elseif type == "shirt" then
return { GetPedDrawableVariation(ped, 11), GetPedTextureVariation(ped, 11) }
elseif type == "arms" then
return { GetPedDrawableVariation(ped, 3), GetPedTextureVariation(ped, 3) }
elseif type == "vest" then
return { GetPedDrawableVariation(ped, 9), GetPedTextureVariation(ped, 9) }
elseif type == "undershirt" then
return { GetPedDrawableVariation(ped, 8), GetPedTextureVariation(ped, 8) }
elseif type == "mask" then
return { GetPedDrawableVariation(ped, 1), GetPedTextureVariation(ped, 1) }
elseif type == "chain" then
return { GetPedDrawableVariation(ped, 7), GetPedTextureVariation(ped, 7) }
end
end
function applyLook(type, data)
local ped = PlayerPedId()
if type == "hair" then
SetPedComponentVariation(ped, 2, data[1], data[2], 0)
elseif type == "hat" then
SetPedPropIndex(ped, 0, data[1], data[2], true)
elseif type == "glasses" then
SetPedPropIndex(ped, 1, data[1], data[2], true)
elseif type == "bag" then
SetPedComponentVariation(ped, 5, data[1], data[2], 0)
elseif type == "shirt" then
SetPedComponentVariation(ped, 11, data[1], data[2], 0)
elseif type == "arms" then
SetPedComponentVariation(ped, 3, data[1], data[2], 0)
elseif type == "vest" then
SetPedComponentVariation(ped, 9, data[1], data[2], 0)
elseif type == "undershirt" then
SetPedComponentVariation(ped, 8, data[1], data[2], 0)
elseif type == "mask" then
SetPedComponentVariation(ped, 1, data[1], data[2], 0)
elseif type == "chain" then
SetPedComponentVariation(ped, 7, data[1], data[2], 0)
end
end
function createLoadButton(category, slot, menu)
local name = "Leer"
if savedLooks[category] and savedLooks[category][slot] then
name = savedLooks[category][slot].name or ("Slot " .. slot)
end
local btn = NativeUI.CreateItem("Slot " .. slot .. ": " .. name, "")
menu:AddItem(btn)
btn.Activated = function(_, item)
if savedLooks[category] and savedLooks[category][slot] then
applyLook(category, savedLooks[category][slot].look)
notify("Look geladen: " .. name)
else
notify("Kein Look in Slot " .. slot .. ".")
end
end
return btn
end
function createSaveButton(category, slot, menu)
local btn = NativeUI.CreateItem("Speichere Slot " .. slot, "")
menu:AddItem(btn)
btn.Activated = function(_, item)
local confirm = true
local name = nil
-- Temporär das Menü ausblenden während der Eingabe
menu:Visible(false)
DisplayRadar(false)
TriggerEvent('codem-blackhudv2:SetForceHide', true, true)
if savedLooks[category] and savedLooks[category][slot] then
name = requestInput("Slot ist belegt. Zum Überschreiben Namen eingeben, oder leer lassen zum Abbrechen:")
if name == nil or name == "" then
confirm = false
notify("Speichern abgebrochen.")
end
else
name = requestInput("Gib einen Namen für diesen Slot ein:")
if name == nil or name == "" then
confirm = false
notify("Speichern abgebrochen.")
end
end
-- Menü wieder anzeigen
menu:Visible(true)
if confirm and name then
local look = getCurrentLook(category)
savedLooks[category] = savedLooks[category] or {}
savedLooks[category][slot] = { name = name, look = look }
TriggerServerEvent("lookchanger:saveLook", category, slot, { name = name, look = look })
notify("Look gespeichert als " .. name)
-- Button Text aktualisieren
for i, item in pairs(menu.Items) do
if item:Text():find("Slot " .. slot .. ":") then
item:Text("Slot " .. slot .. ": " .. name)
break
end
end
end
end
end
function populateLookMenu()
lookMenu:Clear()
local categories = {
{ key = "hair", label = "Haare", slots = 2 },
{ key = "hat", label = "Hut", slots = 4 },
{ key = "glasses", label = "Brille", slots = 4 },
{ key = "mask", label = "Maske", slots = 4 },
{ key = "chain", label = "Kette", slots = 4 },
{ key = "bag", label = "Rucksack", slots = 4 },
{ key = "shirt", label = "Oberteil", slots = 4 },
{ key = "arms", label = "Arme", slots = 6 },
{ key = "vest", label = "Weste", slots = 4 },
{ key = "undershirt", label = "Unterhemd", slots = 4 }
}
for _, cat in ipairs(categories) do
local subMenu = NativeUI.CreateMenu(cat.label, "Slots für " .. cat.label)
menuPool:Add(subMenu)
-- Event-Handler für jedes Untermenü
subMenu.OnMenuOpened = function(menu)
TriggerEvent('codem-blackhudv2:SetForceHide', true, true)
DisplayRadar(false)
end
local btn = NativeUI.CreateItem(cat.label, "Öffne Slots für " .. cat.label)
lookMenu:AddItem(btn)
lookMenu:BindMenuToItem(subMenu, btn)
for i = 1, cat.slots do
createLoadButton(cat.key, i, subMenu)
createSaveButton(cat.key, i, subMenu)
end
end
end
function drawLoadingSpinner(text, angle)
local x, y = 0.5, 0.5
local radius = 0.03
local r = math.rad(angle)
local px = x + math.cos(r) * radius
local py = y + math.sin(r) * radius
DrawRect(x, y, 0.15, 0.07, 0, 0, 0, 180)
DrawLine(x, y, px, py, 255, 255, 255, 255)
SetTextFont(0)
SetTextScale(0.4, 0.4)
SetTextCentre(true)
SetTextEntry("STRING")
AddTextComponentString(text)
DrawText(x, y + 0.04)
end
AddEventHandler('onResourceStop', function(resourceName)
if (GetCurrentResourceName() ~= resourceName) then
return
end
if lookMenu:Visible() then
closeMenu()
end
-- Sicherstellen, dass der Spieler wirklich frei ist
local ped = PlayerPedId()
FreezeEntityPosition(ped, false)
SetEntityCollision(ped, true, true)
EnableAllControlActions(0)
TriggerEvent('codem-blackhudv2:SetForceHide', false, false)
end)