forked from Simnation/Main
439 lines
14 KiB
Lua
439 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)
|