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)
 |