ed
This commit is contained in:
parent
78e76690c3
commit
2fd4906414
579 changed files with 6943 additions and 6950 deletions
|
@ -0,0 +1,434 @@
|
|||
-- 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`,
|
||||
`gr_prop_gr_target_04c`
|
||||
}
|
||||
|
||||
-- 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)
|
Loading…
Add table
Add a link
Reference in a new issue