438 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			438 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| 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)
 | 
