This commit is contained in:
Nordi98 2025-08-06 15:36:50 +02:00
parent 6d22d5f77c
commit 63fbc60a00
86 changed files with 8352 additions and 3428 deletions

View file

@ -0,0 +1,5 @@
function Debug(text)
if Config.Debug then
print(text)
end
end

View file

@ -0,0 +1,180 @@
QBCore = exports['qb-core']:GetCoreObject()
Player = nil
npcHandle = nil
isNPCSpawned = false
CurrentZone = nil
CurrentActionData = {}
hasAlreadyEnteredMarker = false
Citizen.CreateThread(function()
while Player == nil do
Player = exports['qb-core']:GetPlayerData()
Wait(0)
end
end)
Citizen.CreateThread(function()
while true do
Wait(15000)
local ped = PlayerPedId()
if IsPedInAnyVehicle(ped, false) then
local veh = GetVehiclePedIsIn(ped, false)
local mods = QBCore.Functions.GetVehicleProperties(veh)
print("Triggert setMods: "..json.encode(mods))
TriggerServerEvent('mh_garage:setMods', mods)
end
end
end)
-- Funktion zum Spawnen des NPCs
function SpawnGuardNPC(npc)
-- Ped Model laden
RequestModel(npc.model)
local timeout = 0
while not HasModelLoaded(npc.model) and timeout < 100 do
timeout = timeout + 1
Wait(100)
end
if not HasModelLoaded(npc.model) then
return
end
-- NPC erstellen
npcHandle = CreatePed(4, npc.model, npc.spawn.x, npc.spawn.y, npc.spawn.z, npc.spawn.w, false, true)
if not DoesEntityExist(npcHandle) then
return
end
-- NPC Eigenschaften setzen
SetEntityAsMissionEntity(npcHandle, true, true)
SetBlockingOfNonTemporaryEvents(npcHandle, true)
SetPedDiesWhenInjured(npcHandle, false)
SetPedCanPlayAmbientAnims(npcHandle, true)
SetPedCanRagdollFromPlayerImpact(npcHandle, false)
SetEntityInvincible(npcHandle, true)
FreezeEntityPosition(npcHandle, true)
-- Optional: Animation für den NPC
TaskStartScenarioInPlace(npcHandle, "WORLD_HUMAN_GUARD_STAND", 0, true)
isNPCSpawned = true
end
-- Funktion zum Entfernen des NPCs
function RemoveGuardNPC()
if DoesEntityExist(npcHandle) then
DeleteEntity(npcHandle)
isNPCSpawned = false
end
end
-- Hauptthread zum Überprüfen der Spieler-Position
CreateThread(function()
while true do
Wait(0)
local ped = PlayerPedId()
local coords = GetEntityCoords(ped)
local isInMarker = false
for k, v in pairs(Config.Zonen) do
local dist = #(coords - vector3(v.NPC.spawn.x, v.NPC.spawn.y, v.NPC.spawn.z))
local spawnDistance = v.NPC.distance
if dist <= spawnDistance then
isInMarker = true
CurrentZone = v
end
end
if isInMarker and not hasAlreadyEnteredMarker then
hasAlreadyEnteredMarker = true
SpawnGuardNPC(CurrentZone.NPC)
AddTargetOptions()
end
if not isInMarker and hasAlreadyEnteredMarker then
hasAlreadyEnteredMarker = false
CurrentZone = nil
exports['qb-target']:RemoveTargetEntity(npcHandle)
RemoveGuardNPC()
end
end
end)
function AddTargetOptions()
local opt = {
{
type = "client",
event = "mh_garage:storeVehicle",
icon = "fas fa-parking",
label = "Fahrzeug einparken",
},
{
type = "client",
event = "mh_garage:retrieveOwnerVehicle",
icon = "fas fa-car",
label = "Eigene Fahrzeug ausparken",
},
{
type = "client",
event = "mh_garage:retrieveVehicle",
icon = "key",
label = "Schlüssel Fahrzeug ausparken",
}
}
if Config.Verwaltung.garage then
table.insert(opt, {
type = "client",
event = "mh_garage:verwaltungVeh",
icon = "hand",
label = "Fahrzeuge Verwalten",
})
end
exports['qb-target']:AddTargetEntity(npcHandle, {
options = opt,
distance = 2.5
})
end
function Notification(text, type)
lib.notify({
title = "Garage - "..CurrentZone.name,
description = text,
type = type,
position = 'top',
})
end
---------------------------- NetEvents
RegisterNetEvent('mh_jobgarage:notify')
AddEventHandler('mh_jobgarage:notify', function(title, text, type)
Notification(text, type)
end)
function GetVehicleDamagePercentage(vehicle)
if not vehicle then return 0 end
-- Hole die verschiedenen Gesundheitswerte
local engineHealth = GetVehicleEngineHealth(vehicle)
local bodyHealth = GetVehicleBodyHealth(vehicle)
local tankHealth = GetVehiclePetrolTankHealth(vehicle)
-- Normalisiere die Werte (Standard-Maximalwerte: 1000.0)
local enginePercent = (engineHealth / 1000.0) * 100
local bodyPercent = (bodyHealth / 1000.0) * 100
local tankPercent = (tankHealth / 1000.0) * 100
-- Berechne Durchschnitt als Gesamtzustand
local totalHealth = (enginePercent + bodyPercent + tankPercent) / 3
-- Runde auf ganze Zahlen
return math.floor(totalHealth)
end

View file

@ -0,0 +1,152 @@
RegisterNetEvent('mh_garage:retrieveOwnerVehicle')
AddEventHandler('mh_garage:retrieveOwnerVehicle', function()
local ped = PlayerPedId()
local coords = GetEntityCoords(ped)
local random = SelectName()
local opt = {}
QBCore.Functions.TriggerCallback('mh_garage:retrieveOwnerVehicle', function(cb)
if cb == false then
Notification("Es ist kein Fahrzeug hier!", "inform")
return
end
for i = 1, #cb, 1 do
local mods = json.decode(cb[i].mods)
table.insert(opt, {
title = cb[i].name,
description = "Kennzeichen: "..cb[i].plate, --[[ \nTankinhalt: "..math.round(mods.fuelLevel, 2).."%" ]]
icon = "car",
onSelect = function()
cb[i].mods = mods
SpawnThisVehicle(cb[i])
end
})
end
lib.registerContext({
id = "retrieveVehicle",
title = random.name,
options = opt
})
lib.showContext("retrieveVehicle")
end, CurrentZone.name)
end)
RegisterNetEvent('mh_garage:retrieveVehicle')
AddEventHandler('mh_garage:retrieveVehicle', function()
local ped = PlayerPedId()
local coords = GetEntityCoords(ped)
local random = SelectName()
local opt = {}
QBCore.Functions.TriggerCallback('mh_garage:retrieveKeyVehicle', function(cb)
if cb == false then
Notification("Es ist kein Fahrzeug hier!", "inform")
return
end
for i = 1, #cb, 1 do
if cb[i].garage ~= "OUT" then
local mods = json.decode(cb[i].mods)
table.insert(opt, {
title = cb[i].name,
description = "Kennzeichen: "..cb[i].plate, --[[ \nTankinhalt: "..math.round(mods.fuelLevel, 2).."%" ]]
icon = "car",
onSelect = function()
cb[i].mods = mods
SpawnThisVehicle(cb[i])
end
})
end
end
lib.registerContext({
id = "retrieveVehicle",
title = random.name,
options = opt
})
lib.showContext("retrieveVehicle")
end, CurrentZone.name)
end)
function SpawnThisVehicle(vehicle)
local spawnPoint = nil
-- Freien Spawnpunkt suchen
for _, spot in pairs(CurrentZone.vehicle_spawn) do
if not IsAnyVehicleNearPoint(spot.x, spot.y, spot.z, 3.0) then
spawnPoint = spot
break
end
end
if spawnPoint then
QBCore.Functions.SpawnVehicle(vehicle.vehicle, function(veh)
-- Fahrzeug ID für Server
local netId = NetworkGetNetworkIdFromEntity(veh)
-- Grundeinstellungen
SetVehicleNumberPlateText(veh, vehicle.plate)
SetVehicleDoorsLocked(veh, 0)
SetEntityHeading(veh, spawnPoint.w)
-- Motor aus
SetVehicleEngineOn(veh, false, true, true)
-- Fahrzeug Eigenschaften
local mods = type(vehicle.mods) == 'string' and json.decode(vehicle.mods) or vehicle.mods
-- Grundwerte setzen
SetVehicleFuelLevel(veh, mods.fuelLevel)
exports["lc_fuel"]:SetFuel(veh, mods.fuelLevel)
SetVehicleEngineHealth(veh, mods.engineHealth)
SetVehicleBodyHealth(veh, mods.bodyHealth)
SetVehicleDirtLevel(veh, mods.dirtLevel)
-- Türen Status
if mods.doorStatus then
for doorIndex = 0, 5 do
if mods.doorStatus[tostring(doorIndex)] then
SetVehicleDoorBroken(veh, doorIndex, true)
end
end
end
-- Fenster Status
if mods.windowStatus then
for windowIndex = 0, 7 do
if not mods.windowStatus[tostring(windowIndex)] then
SmashVehicleWindow(veh, windowIndex)
end
end
end
-- Alle Mods anwenden
QBCore.Functions.SetVehicleProperties(veh, mods)
-- Fahrzeug auf den Boden setzen
SetVehicleOnGroundProperly(veh)
-- Server über gespawntes Fahrzeug informieren
TriggerServerEvent('mh_garage:spawnedVehicle', netId, vehicle.plate)
-- Optional: Erfolgsmeldung
lib.notify({
title = "Fahrzeug geparkt...",
description = "Dein Fahrzeug steht auf Parkplatz "..math.random(1, 15),
type = "success"
})
end, vector3(spawnPoint.x, spawnPoint.y, spawnPoint.z), true)
else
QBCore.Functions.Notify('Alle Parkplätze sind belegt!', 'error')
lib.notify({
title = "Fahrzeug nicht gefunden",
description = "Alle Parkplätze sind belegt!",
type = "success"
})
end
end

View file

@ -0,0 +1,131 @@
RegisterNetEvent('mh_garage:storeVehicle')
AddEventHandler('mh_garage:storeVehicle', function()
local ped = PlayerPedId()
local coords = GetEntityCoords(ped)
local vehicles = GetGamePool('CVehicle')
local random = SelectName()
local opt = {}
for i = 1, #vehicles, 1 do
local veh_coords = GetEntityCoords(vehicles[i])
local distance = #(veh_coords - coords)
if distance < 15.0 then
local mods = QBCore.Functions.GetVehicleProperties(vehicles[i])
local lc_fuelLevel = exports["lc_fuel"]:GetFuel(vehicles[i]) -- Get the fuel level
mods.fuelLevel = lc_fuelLevel
table.insert(opt, {
title = "Kennzeichen: "..mods.plate,
description = GetRandomCarDescription(),
icon = "car",
onSelect = function()
print(CurrentZone.price)
if CurrentZone.price ~= nil then
lib.hideContext("StoredVehicles")
lib.registerContext({
id = "thisVehicle",
title = random.name,
options = {
{title = "Kosten: "..CurrentZone.price.."$"},
{title = "", disabled = true},
{
title = "Akzeptieren",
description = "Geld wird vom Bankkonto abgebucht!",
icon = "check",
onSelect = function()
lib.hideContext("thisVehicle")
QBCore.Functions.TriggerCallback('mh_garage:storedVehicle', function(cb)
if cb.status then
TriggerServerEvent('mh_Parking:deleteVehicle', mods.plate, NetworkGetNetworkIdFromEntity(vehicles[i]))
--DeleteVehicle(vehicles[i])
Notification(cb.text, cb.type, CurrentZone.name)
else
if cb.police and Config.EnabledPolice then
exports["roadphone"]:sendDispatch("Hier hat grade jemand versucht, ein Fahrzeug einzuparken.\nDas Zündschloss sah Beschädigt aus.\nKennzeichen: "..veh.plate, 'police', nil)
end
Notification(cb.text, cb.type)
end
end, mods, CurrentZone)
end
},
{
title = "Abbrechen",
description = "Das ist sehr Schade,",
icon = "close",
onSelect = function()
lib.hideContext("thisVehicle")
end
}
}
})
lib.showContext("thisVehicle")
else
QBCore.Functions.TriggerCallback('mh_garage:storedVehicle', function(cb)
if cb.status then
TriggerServerEvent('mh_Parking:deleteVehicle', mods.plate, NetworkGetNetworkIdFromEntity(vehicles[i]))
--DeleteVehicle(vehicles[i])
Notification(cb.text, cb.type, CurrentZone.name)
else
if cb.police and Config.EnabledPolice then
exports["roadphone"]:sendDispatch("Hier hat grade jemand versucht, ein Fahrzeug einzuparken.\nDas Zündschloss sah Beschädigt aus.\nKennzeichen: "..veh.plate, 'police', nil)
end
Notification(cb.text, cb.type)
end
end, mods, CurrentZone)
end
end
})
lib.registerContext({
id = "StoredVehicles",
title = random.name.."\n\n"..random.description,
options = opt
})
lib.showContext("StoredVehicles")
end
end
end)
function SelectName()
local names = {
{name = "Garagen-Guru",
description = "passt auf, dass keiner falsch parkt, Schranken nicht durchdrehen und Autos nicht fliegen!"},
{name = "Torflüsterer",
description = "Redet Schranken gut zu wenn diese wieder nicht funktionieren."},
{name = "Parkplatz-Papst",
description = "segnet jedes Auto, das diese heilige Halle betritt. Kein Ölverlust ohne dein Amen!"},
{name = "Schranken-Schamane",
description = "Elektronik und Technik? Kein Problem! Ich kontrolliere den Strom der Schranken mit reiner Willenskraft und Kabelbinder!"},
{name = "Chef vom Schuppen",
description = "Wer falsch parkt, kriegt nicht den Abschleppdienst, sondern eine Ansprache. Kurz. Hart. Legendär!"}
}
return names[math.random(1, #names)]
end
function GetRandomCarDescription()
local descriptions = {
"Das Auto für alle, die beim Beschleunigen mehr Spaß haben als beim Ankommen.",
"Wenn du ein Auto suchst, das schneller fährt als dein WiFi, bist du hier richtig.",
"Nicht das schnellste Auto, aber hey, es hat vier Räder und eine Hupe!",
"Das einzig wahre Fahren keine GPS-Fehler, nur pure Straßenmagie.",
"Mit diesem Auto wirst du die Straße genauso lieben wie das Benzin in deinem Tank.",
"Fahr einfach, und schau, wie viele Leute sich fragen, ob du gerade von der Rennstrecke kommst.",
"Dieses Auto bringt mehr Nervenkitzel als ein Achterbahn-Abenteuer!",
"Dieses Fahrzeug hat mehr Charakter als deine letzte Beziehung.",
"Es ist nicht das teuerste Auto, aber es fährt immer noch besser als deine Laune nach dem Montagmorgen!",
"Mit diesem Wagen wirst du zur Legende oder zumindest zum König des Parkhauses.",
"Schneller als dein Chefs Auto, langsamer als dein Instagram-Feed.",
"Wenn der Sound des Motors dich mehr motiviert als dein Wecker am Morgen!",
"Sicheres Fahren ist wichtig. Aber Spaß haben das ist die wahre Kunst!",
"Nicht der neueste Sportwagen, aber dafür ein echter Klassiker auf der Straße.",
"Weniger PS als dein Laptop, aber hey, er fährt!"
}
-- Zufällige Beschreibung auswählen
local randomIndex = math.random(1, #descriptions)
-- Beschreibung zurückgeben
return descriptions[randomIndex]
end

View file

@ -0,0 +1,44 @@
-- vehicleadmin.lua - Füge diese Datei in deinen client-Ordner ein
-- Füge einen Menüpunkt für das Fahrzeugadmin-System zum NPC-Menü hinzu
-- Diese Funktion wird aufgerufen, wenn der NPC-Target erstellt wird
local function AddVehicleAdminOption()
-- Prüfe, ob der Spieler die Berechtigung hat
QBCore.Functions.TriggerCallback('vehicleadmin:getPlayerJob', function(jobData)
if jobData and jobData.hasPermission then
-- Füge den Menüpunkt zum NPC hinzu, wenn der Spieler berechtigt ist
exports['qb-target']:AddTargetEntity(npcHandle, {
options = {
{
type = "client",
event = "vehicleadmin:openMenu",
icon = "fas fa-car-mechanic",
label = "Fahrzeugverwaltung",
}
},
distance = 2.5
})
end
end)
end
-- Registriere einen Event-Handler, der nach dem Hinzufügen der Standard-Target-Optionen ausgeführt wird
RegisterNetEvent('mh_garage:targetOptionsAdded')
AddEventHandler('mh_garage:targetOptionsAdded', function()
AddVehicleAdminOption()
end)
-- Füge einen Hook in die bestehende AddTargetOptions-Funktion ein
local originalAddTargetOptions = AddTargetOptions
AddTargetOptions = function()
originalAddTargetOptions()
TriggerEvent('mh_garage:targetOptionsAdded')
end
-- Registriere den Befehl für das Fahrzeugadmin-System
RegisterCommand('vehicleadmin', function()
TriggerEvent('vehicleadmin:openMenu')
end, false)
-- Registriere die Tastenbelegung (optional)
RegisterKeyMapping('vehicleadmin', 'Öffne Fahrzeug Admin Menu', 'keyboard', '')

View file

@ -0,0 +1,56 @@
-- vehicleadmin_integration.lua
-- Diese Datei integriert das Fahrzeugadmin-System mit dem Garagensystem
-- Füge einen Menüpunkt für das Fahrzeugadmin-System zum NPC-Menü hinzu
local function AddVehicleAdminOption()
-- Prüfe, ob der Spieler die Berechtigung hat
QBCore.Functions.TriggerCallback('vehicleadmin:getPlayerJob', function(jobData)
if jobData and jobData.hasPermission then
-- Füge den Menüpunkt zum NPC hinzu, wenn der Spieler berechtigt ist
if npcHandle and DoesEntityExist(npcHandle) then
exports['qb-target']:AddTargetEntity(npcHandle, {
options = {
{
type = "client",
event = "vehicleadmin:openMenu",
icon = "fas fa-car-mechanic",
label = "Fahrzeugverwaltung",
}
},
distance = 2.5
})
end
end
end)
end
-- Überschreibe die AddTargetOptions-Funktion, um unsere Option hinzuzufügen
local originalAddTargetOptions = AddTargetOptions
if originalAddTargetOptions then
AddTargetOptions = function()
originalAddTargetOptions()
AddVehicleAdminOption()
end
end
-- Registriere einen Event-Handler für das Hinzufügen der Target-Optionen
RegisterNetEvent('mh_garage:targetOptionsAdded')
AddEventHandler('mh_garage:targetOptionsAdded', function()
AddVehicleAdminOption()
end)
-- Füge einen Event-Handler hinzu, der nach dem Spawnen des NPCs ausgeführt wird
RegisterNetEvent('mh_garage:npcSpawned')
AddEventHandler('mh_garage:npcSpawned', function()
Wait(500) -- Warte kurz, damit der NPC vollständig gespawnt ist
AddVehicleAdminOption()
end)
-- Füge einen Hook in die SpawnGuardNPC-Funktion ein, um unseren Event auszulösen
local originalSpawnGuardNPC = SpawnGuardNPC
if originalSpawnGuardNPC then
SpawnGuardNPC = function(npc)
originalSpawnGuardNPC(npc)
TriggerEvent('mh_garage:npcSpawned')
end
end

View file

@ -0,0 +1,76 @@
RegisterNetEvent('mh_garage:verwaltungVeh')
AddEventHandler('mh_garage:verwaltungVeh', function()
QBCore.TriggerCallback('mh_garage:verwaltung', function(cb)
Debug("Verwaltung CB: "..json.encode(cb))
if cb[1] ~= nil then
local opt = {}
for i = 1, #cb, 1 do
local isingarage = cb[i].current_in_garage
local des = ""
if isingarage then
des = "Bearbeite das Fahrzeug\nKennzeichen: "..cb[i].current_plate.."\nGarage: "..cb[i].current_garage
else
des = "Bearbeite das Fahrzeug\nKennzeichen: "..cb[i].current_plate.."\nLetzte bekannte Garage: "..cb[i].current_garage
end
table.insert(opt, {
title = cb[i].current_name,
description = des,
icon = "car",
onSelect = function()
OpenVerwaltung(cb[i])
end
})
end
else
lib.notify({
title = "Fahrzeug Verwaltung",
description = "Du bist nicht im Besitz eines Fahrzeuges!",
type = "inform"
})
end
end)
end)
function OpenVerwaltung(vehicleInfos)
Debug("OpenVerwaltung: "..json.encode(vehicleInfos))
local garages = {}
for k, v in pairs(Config.Zonen) do
table.insert(garages, v.name)
end
lib.registerMenu({
id = 'some_menu_id',
title = 'Menu title',
position = 'top-right',
onSideScroll = function(selected, scrollIndex, args)
print("Scroll: ", selected, scrollIndex, args)
end,
onSelected = function(selected, secondary, args)
if not secondary then
print("Normal button")
else
if args.isCheck then
print("Check button")
end
if args.isScroll then
print("Scroll button")
end
end
print(selected, secondary, json.encode(args, {indent=true}))
end,
options = {
{label = "Name ändern", icon = "paper"},
{label = 'Transport to:', icon = 'arrows-up-down-left-right', values=garages},
}
}, function(selected, scrollIndex, args)
print(selected, scrollIndex, args)
end)
RegisterCommand('testmenu', function()
lib.showMenu('some_menu_id')
end)
end