1
0
Fork 0
forked from Simnation/Main
Main/resources/[weapons]/[Scripts]/nordi_shootingrange/client.lua

438 lines
13 KiB
Lua
Raw Normal View History

2025-06-07 08:51:21 +02:00
-- qb-shootingrange client.lua
local QBCore = exports['qb-core']:GetCoreObject()
-- Variablen
local menuActive = false
local menuIndex = 1
local shooting = false
local score = 0
local targets = {}
local timerEnabled = false
local timeLeft = 0
local isTrainer = false
local currentRange = nil
local isInCompetition = false
local competitionHost = false
-- Gültige Target Models
local validTargetModels = {
`prop_target_backboard_b`,
`gr_prop_gr_target_05c`,
2025-08-06 08:27:08 +02:00
`gr_prop_gr_target_04c`,
`gr_prop_gr_target_02b`,
`gr_prop_gr_target_02a`,
`gr_prop_gr_target_w_02b`,
2025-06-07 08:51:21 +02:00
}
-- Menüoptionen
local menuOptions = {
"⏱️ Starte Schießstand mit Timer",
"🔫 Starte Schießstand ohne Timer",
"🏁 Starte Wettkampfmodus",
"👥 Trainingsmodus",
"🛑 Beende Schießstand",
"📋 Bestenliste"
}
-- Hilfsfunktionen
function DrawTxt(text, x, y, scale)
SetTextFont(4)
SetTextProportional(0)
SetTextScale(scale, scale)
SetTextColour(255, 255, 255, 255)
SetTextDropShadow()
SetTextCentre(true)
SetTextEntry("STRING")
AddTextComponentString(text)
DrawText(x, y)
end
function PlaySound(name)
SendNUIMessage({ action = "play", sound = name })
end
function GetNearbyPlayers()
local players = {}
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
for _, player in ipairs(GetActivePlayers()) do
if player ~= PlayerId() then
local targetPed = GetPlayerPed(player)
local targetCoords = GetEntityCoords(targetPed)
local distance = #(playerCoords - targetCoords)
if distance <= 20.0 then
local playerName = GetPlayerName(player)
local serverId = GetPlayerServerId(player)
table.insert(players, {
label = playerName,
serverId = serverId,
distance = math.floor(distance)
})
end
end
end
return players
end
function ShowPlayerSelectionMenu()
local nearbyPlayers = GetNearbyPlayers()
if #nearbyPlayers == 0 then
QBCore.Functions.Notify("Keine Spieler in der Nähe!", "error")
return
end
local elements = {
{
header = "Spieler zum Wettkampf einladen",
isMenuHeader = true
}
}
for _, player in ipairs(nearbyPlayers) do
table.insert(elements, {
header = player.label,
txt = string.format("Entfernung: %dm", player.distance),
params = {
event = "qb-shootingrange:invitePlayer",
args = {
playerId = player.serverId
}
}
})
end
exports['qb-menu']:openMenu(elements)
end
function ShowStartCompetitionMenu()
local elements = {
{
header = "Wettkampf Steuerung",
isMenuHeader = true
},
{
header = "🏁 Wettkampf starten",
txt = "Startet den Wettkampf für alle Teilnehmer",
params = {
event = "qb-shootingrange:hostStartCompetition",
args = {}
}
},
{
header = "❌ Abbrechen",
txt = "Bricht den Wettkampf ab",
params = {
event = "qb-shootingrange:cancelCompetition",
args = {}
}
}
}
exports['qb-menu']:openMenu(elements)
end
function FindNearbyTargets()
local foundTargets = {}
local playerCoords = GetEntityCoords(PlayerPedId())
local radius = 200.0
for _, model in ipairs(validTargetModels) do
local handle, object = FindFirstObject()
local success
repeat
if IsEntityAnObject(object) and GetEntityModel(object) == model then
local objCoords = GetEntityCoords(object)
if #(playerCoords - objCoords) < radius then
table.insert(foundTargets, object)
end
end
success, object = FindNextObject(handle)
until not success
EndFindObject(handle)
end
return foundTargets
end
function PromptPlayerName()
AddTextEntry('SHOOTING_NAME', 'Gib deinen Namen ein:')
DisplayOnscreenKeyboard(1, "SHOOTING_NAME", "", "", "", "", "", 20)
while UpdateOnscreenKeyboard() ~= 1 and UpdateOnscreenKeyboard() ~= 2 do Wait(0) end
if UpdateOnscreenKeyboard() ~= 2 then
return GetOnscreenKeyboardResult()
end
return "Unbekannt"
end
function DrawMenu()
DrawTxt("~b~" .. currentRange.label .. "~s~", 0.5, 0.3, 0.6)
for i, option in ipairs(menuOptions) do
local color = i == menuIndex and "~y~" or "~w~"
DrawTxt(color .. option, 0.5, 0.35 + (i * 0.05), 0.4)
end
DrawTxt("~c~↑/↓ Auswählen | ENTER bestätigen | BACKSPACE zurück", 0.5, 0.7, 0.3)
end
function StartShooting(useTimer, isComp)
if shooting then return end
if isComp then
competitionHost = true
ShowPlayerSelectionMenu()
return
end
targets = FindNearbyTargets()
if #targets == 0 then
QBCore.Functions.Notify("Keine Ziele im Umkreis gefunden!", "error")
return
end
shooting = true
score = 0
timerEnabled = useTimer
timeLeft = useTimer and 30 or 0
PlaySound("start")
QBCore.Functions.Notify("Schießstand gestartet!", "success")
if timerEnabled then
CreateThread(function()
while timeLeft > 0 and shooting do
Wait(1000)
timeLeft = timeLeft - 1
end
if shooting then StopShooting() end
end)
end
CreateThread(function()
while shooting do
Wait(0)
local hit, endCoords = GetPedLastWeaponImpactCoord(PlayerPedId())
if hit then
for _, target in ipairs(targets) do
if DoesEntityExist(target) then
local targetCoords = GetEntityCoords(target)
if #(endCoords - targetCoords) < 1.2 then
score = score + 10
QBCore.Functions.Notify("🎯 Treffer! Punkte: " .. score, "success")
if isInCompetition then
TriggerServerEvent("qb-shootingrange:updateCompetitionScore", score)
end
Wait(300)
break
end
end
end
end
end
end)
CreateThread(function()
while shooting do
Wait(0)
DrawTxt("Punkte: " .. score, 0.5, 0.05, 0.5)
if timerEnabled then
DrawTxt("Zeit: " .. timeLeft .. "s", 0.5, 0.09, 0.4)
end
end
end)
end
function StopShooting()
if not shooting then return end
shooting = false
targets = {}
QBCore.Functions.Notify("Beendet! Gesamtpunkte: " .. score, "success")
PlaySound("timeout")
if not isInCompetition then
local name = PromptPlayerName()
TriggerServerEvent("qb-shootingrange:saveScore", name, score)
end
isInCompetition = false
competitionHost = false
end
function ShowHighscores()
QBCore.Functions.TriggerCallback('qb-shootingrange:getHighscores', function(scores)
if scores and #scores > 0 then
local text = "~y~🏆 Bestenliste~s~\n\n"
for i, entry in ipairs(scores) do
text = text .. string.format("%d. %s - %d Punkte\n~c~%s~s~\n\n",
i,
entry.name,
entry.score,
entry.timestamp
)
end
SetNotificationTextEntry("STRING")
AddTextComponentString(text)
DrawNotification(false, true)
else
QBCore.Functions.Notify("Keine Einträge in der Bestenliste.", "error")
end
end)
end
-- Event Handler
RegisterNetEvent("qb-shootingrange:invitePlayer")
AddEventHandler("qb-shootingrange:invitePlayer", function(data)
TriggerServerEvent("qb-shootingrange:sendInvite", data.playerId)
QBCore.Functions.Notify("Einladung gesendet!", "success")
end)
RegisterNetEvent("qb-shootingrange:receiveInvite")
AddEventHandler("qb-shootingrange:receiveInvite", function(inviterName, inviterId)
local elements = {
{
header = "Schießstand Einladung",
txt = string.format("Von: %s", inviterName),
isMenuHeader = true
},
{
header = "✅ Annehmen",
txt = "Der Einladung folgen",
params = {
event = "qb-shootingrange:acceptInvite",
args = {
inviterId = inviterId
}
}
},
{
header = "❌ Ablehnen",
txt = "Einladung ablehnen",
params = {
event = "qb-shootingrange:declineInvite",
args = {
inviterId = inviterId
}
}
}
}
exports['qb-menu']:openMenu(elements)
end)
RegisterNetEvent("qb-shootingrange:acceptInvite")
AddEventHandler("qb-shootingrange:acceptInvite", function(data)
TriggerServerEvent("qb-shootingrange:acceptInvite", data.inviterId)
isInCompetition = true
QBCore.Functions.Notify("Du hast die Einladung angenommen!", "success")
end)
RegisterNetEvent("qb-shootingrange:declineInvite")
AddEventHandler("qb-shootingrange:declineInvite", function(data)
TriggerServerEvent("qb-shootingrange:declineInvite", data.inviterId)
QBCore.Functions.Notify("Du hast die Einladung abgelehnt.", "error")
end)
RegisterNetEvent("qb-shootingrange:hostStartCompetition")
AddEventHandler("qb-shootingrange:hostStartCompetition", function()
TriggerServerEvent("qb-shootingrange:startCompetition")
end)
RegisterNetEvent("qb-shootingrange:cancelCompetition")
AddEventHandler("qb-shootingrange:cancelCompetition", function()
TriggerServerEvent("qb-shootingrange:cancelCompetition")
isInCompetition = false
competitionHost = false
QBCore.Functions.Notify("Wettkampf abgebrochen", "error")
end)
RegisterNetEvent("qb-shootingrange:competitionStarted")
AddEventHandler("qb-shootingrange:competitionStarted", function()
StartShooting(true, false)
QBCore.Functions.Notify("Der Wettkampf beginnt!", "success")
end)
RegisterNetEvent("qb-shootingrange:playerJoinedCompetition")
AddEventHandler("qb-shootingrange:playerJoinedCompetition", function(playerName)
QBCore.Functions.Notify(playerName .. " ist dem Wettkampf beigetreten!", "success")
if competitionHost then
ShowStartCompetitionMenu()
end
end)
RegisterNetEvent("qb-shootingrange:updateCompetition")
AddEventHandler("qb-shootingrange:updateCompetition", function(scores)
if not isInCompetition then return end
local scoreText = "🏁 Wettkampf Punktestand:\n"
for name, playerScore in pairs(scores) do
scoreText = scoreText .. string.format("%s: %d\n", name, playerScore)
end
DrawTxt(scoreText, 0.5, 0.15, 0.4)
end)
-- Hauptthread
CreateThread(function()
while true do
Wait(0)
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
local closestRange = nil
local closestDist = 1000
for _, range in pairs(Config.ShootingRanges) do
local dist = #(playerCoords - range.coords)
if dist < closestDist then
closestDist = dist
closestRange = range
end
end
if closestRange and closestDist < 2.0 then
currentRange = closestRange
if not menuActive then
DrawTxt("Drücke ~g~E~s~ für den " .. closestRange.label, 0.5, 0.9, 0.4)
if IsControlJustPressed(0, 38) then -- E
menuActive = true
menuIndex = 1
end
else
DrawMenu()
if IsControlJustPressed(0, 172) then -- Hoch
menuIndex = menuIndex - 1
if menuIndex < 1 then menuIndex = #menuOptions end
elseif IsControlJustPressed(0, 173) then -- Runter
menuIndex = menuIndex + 1
if menuIndex > #menuOptions then menuIndex = 1 end
elseif IsControlJustPressed(0, 201) then -- Enter
if menuIndex == 1 then
StartShooting(true, false)
elseif menuIndex == 2 then
StartShooting(false, false)
elseif menuIndex == 3 then
StartShooting(true, true)
elseif menuIndex == 4 then
QBCore.Functions.Notify("Trainingsmodus wird bald verfügbar!", "primary")
elseif menuIndex == 5 then
StopShooting()
elseif menuIndex == 6 then
ShowHighscores()
end
menuActive = false
elseif IsControlJustPressed(0, 202) then -- Backspace
menuActive = false
end
end
else
menuActive = false
currentRange = nil
end
end
end)